diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 40857e0066ee5..b514c4f89fbff 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -896,6 +896,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::Yes, "#[rustc_never_returns_null_ptr] is used to mark functions returning non-null pointers." ), + rustc_attr!( + rustc_no_implicit_autorefs, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, + "#[rustc_no_implicit_autorefs] is used to mark functions that should not autorefs in raw pointers context." + ), rustc_attr!( rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No, "#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`." diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index d51865810b9a8..53838995f182f 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -360,6 +360,10 @@ lint_impl_trait_overcaptures = `{$self_ty}` will capture more lifetimes than pos lint_impl_trait_redundant_captures = all possible in-scope parameters are already captured, so `use<...>` syntax is redundant .suggestion = remove the `use<...>` syntax +lint_implicit_unsafe_autorefs = implicit auto-ref creates a reference to a dereference of a raw pointer + .note = creating a reference requires the pointer to be valid and imposes aliasing requirements + .suggestion = try using a raw pointer method instead; or if this reference is intentional, make it explicit + lint_improper_ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe .label = not FFI-safe .note = the type is defined here diff --git a/compiler/rustc_lint/src/autorefs.rs b/compiler/rustc_lint/src/autorefs.rs new file mode 100644 index 0000000000000..46748534f213b --- /dev/null +++ b/compiler/rustc_lint/src/autorefs.rs @@ -0,0 +1,157 @@ +use rustc_ast::{BorrowKind, UnOp}; +use rustc_hir::{Expr, ExprKind, Mutability}; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref}; +use rustc_session::{declare_lint, declare_lint_pass}; +use rustc_span::sym; + +use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion}; +use crate::{LateContext, LateLintPass, LintContext}; + +declare_lint! { + /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references + /// to dereferences of raw pointers. + /// + /// ### Example + /// + /// ```rust + /// use std::ptr::addr_of_mut; + /// + /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] { + /// addr_of_mut!((*ptr)[..16]) + /// // ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`, + /// // implicitly creating a reference + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// When working with raw pointers it's usually undesirable to create references, + /// since they inflict a lot of safety requirement. Unfortunately, it's possible + /// to take a reference to a dereference of a raw pointer implicitly, which inflicts + /// the usual reference requirements potentially without realizing that. + /// + /// If you are sure, you can soundly take a reference, then you can take it explicitly: + /// ```rust + /// # use std::ptr::addr_of_mut; + /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] { + /// addr_of_mut!((&mut *ptr)[..16]) + /// } + /// ``` + /// + /// Otherwise try to find an alternative way to achive your goals that work only with + /// raw pointers: + /// ```rust + /// #![feature(slice_ptr_get)] + /// + /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] { + /// ptr.get_unchecked_mut(..16) + /// } + /// ``` + pub DANGEROUS_IMPLICIT_AUTOREFS, + Warn, + "implicit reference to a dereference of a raw pointer", + report_in_external_macro +} + +declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]); + +impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + // This logic has mostly been taken from + // https://github.com/rust-lang/rust/pull/103735#issuecomment-1370420305 + + // 5. Either of the following: + // a. A deref followed by any non-deref place projection (that intermediate + // deref will typically be auto-inserted) + // b. A method call annotated with `#[rustc_no_implicit_refs]`. + // c. A deref followed by a `addr_of!` or `addr_of_mut!`. + let mut is_coming_from_deref = false; + let inner = match expr.kind { + ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind { + ExprKind::Unary(UnOp::Deref, inner) => { + is_coming_from_deref = true; + inner + } + _ => return, + }, + ExprKind::Index(base, _, _) => base, + ExprKind::MethodCall(_, inner, _, _) + if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) => + { + inner + } + ExprKind::Field(inner, _) => inner, + _ => return, + }; + + let typeck = cx.typeck_results(); + let adjustments_table = typeck.adjustments(); + + if let Some(adjustments) = adjustments_table.get(inner.hir_id) + // 4. Any number of automatically inserted deref/derefmut calls + && let adjustments = peel_derefs_adjustments(&**adjustments) + // 3. An automatically inserted reference (might come from a deref). + && let [adjustment] = adjustments + && let Some(borrow_mutbl) = has_implicit_borrow(adjustment) + && let ExprKind::Unary(UnOp::Deref, dereferenced) = + // 2. Any number of place projections + peel_place_mappers(inner).kind + // 1. Deref of a raw pointer + && typeck.expr_ty(dereferenced).is_raw_ptr() + { + cx.emit_span_lint( + DANGEROUS_IMPLICIT_AUTOREFS, + expr.span.source_callsite(), + ImplicitUnsafeAutorefsDiag { + suggestion: ImplicitUnsafeAutorefsSuggestion { + mutbl: borrow_mutbl.ref_prefix_str(), + deref: if is_coming_from_deref { "*" } else { "" }, + start_span: inner.span.shrink_to_lo(), + end_span: inner.span.shrink_to_hi(), + }, + }, + ) + } + } +} + +/// Peels expressions from `expr` that can map a place. +fn peel_place_mappers<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { + loop { + match expr.kind { + ExprKind::Index(base, _idx, _) => { + expr = &base; + } + ExprKind::Field(e, _) => expr = &e, + _ => break expr, + } + } +} + +/// Peel derefs adjustments until the last last element. +fn peel_derefs_adjustments<'a>(mut adjs: &'a [Adjustment<'a>]) -> &'a [Adjustment<'a>] { + while let [Adjustment { kind: Adjust::Deref(_), .. }, end @ ..] = adjs + && !end.is_empty() + { + adjs = end; + } + adjs +} + +/// Test if some adjustment has some implicit borrow +/// +/// Returns `Some(mutability)` if the argument adjustment has implicit borrow in it. +fn has_implicit_borrow(Adjustment { kind, .. }: &Adjustment<'_>) -> Option { + match kind { + &Adjust::Deref(Some(OverloadedDeref { mutbl, .. })) => Some(mutbl), + &Adjust::Borrow(AutoBorrow::Ref(mutbl)) => Some(mutbl.into()), + Adjust::NeverToAny + | Adjust::Pointer(..) + | Adjust::ReborrowPin(..) + | Adjust::Deref(None) + | Adjust::Borrow(AutoBorrow::RawPtr(..)) => None, + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 35867d8c9efef..fd3a0ef8a3b96 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -36,6 +36,7 @@ mod async_closures; mod async_fn_in_trait; +mod autorefs; pub mod builtin; mod context; mod dangling; @@ -82,6 +83,7 @@ mod unused; use async_closures::AsyncClosureUsage; use async_fn_in_trait::AsyncFnInTrait; +use autorefs::*; use builtin::*; use dangling::*; use default_could_be_derived::DefaultCouldBeDerived; @@ -200,6 +202,7 @@ late_lint_methods!( PathStatements: PathStatements, LetUnderscore: LetUnderscore, InvalidReferenceCasting: InvalidReferenceCasting, + ImplicitAutorefs: ImplicitAutorefs, // Depends on referenced function signatures in expressions UnusedResults: UnusedResults, UnitBindings: UnitBindings, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 0058630957291..39b7e09ba04dc 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -55,6 +55,26 @@ pub(crate) enum ShadowedIntoIterDiagSub { }, } +// autorefs.rs +#[derive(LintDiagnostic)] +#[diag(lint_implicit_unsafe_autorefs)] +#[note] +pub(crate) struct ImplicitUnsafeAutorefsDiag { + #[subdiagnostic] + pub suggestion: ImplicitUnsafeAutorefsSuggestion, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(lint_suggestion, applicability = "maybe-incorrect")] +pub(crate) struct ImplicitUnsafeAutorefsSuggestion { + pub mutbl: &'static str, + pub deref: &'static str, + #[suggestion_part(code = "({mutbl}{deref}")] + pub start_span: Span, + #[suggestion_part(code = ")")] + pub end_span: Span, +} + // builtin.rs #[derive(LintDiagnostic)] #[diag(lint_builtin_while_true)] diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c6ae2c0fb9bfd..1c53f1e56753b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -179,6 +179,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::rustc_as_ptr, ..] => { self.check_applied_to_fn_or_method(hir_id, attr, span, target) } + [sym::rustc_no_implicit_autorefs, ..] => { + self.check_applied_to_fn_or_method(hir_id, attr, span, target) + } [sym::rustc_never_returns_null_ptr, ..] => { self.check_applied_to_fn_or_method(hir_id, attr, span, target) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9e7f5047eb30c..658b10a9ceacc 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1787,6 +1787,7 @@ symbols! { rustc_must_implement_one_of, rustc_never_returns_null_ptr, rustc_never_type_options, + rustc_no_implicit_autorefs, rustc_no_mir_inline, rustc_nonnull_optimization_guaranteed, rustc_nounwind, diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 9236f5cb8d1f0..01f09e120d7b6 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1803,6 +1803,7 @@ impl String { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] #[rustc_confusables("length", "size")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] pub const fn len(&self) -> usize { self.vec.len() } @@ -1822,6 +1823,7 @@ impl String { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] pub const fn is_empty(&self) -> bool { self.len() == 0 } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index da9a77154f9b5..09fa8103124f1 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2575,7 +2575,7 @@ impl Vec { #[inline] #[track_caller] unsafe fn append_elements(&mut self, other: *const [T]) { - let count = unsafe { (*other).len() }; + let count = other.len(); self.reserve(count); let len = self.len(); unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) }; diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs index 37d9a28fb99c0..8106c088f0ba2 100644 --- a/library/core/src/ops/index.rs +++ b/library/core/src/ops/index.rs @@ -67,6 +67,7 @@ pub trait Index { /// /// May panic if the index is out of bounds. #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] #[track_caller] fn index(&self, index: Idx) -> &Self::Output; } @@ -171,6 +172,7 @@ pub trait IndexMut: Index { /// /// May panic if the index is out of bounds. #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] #[track_caller] fn index_mut(&mut self, index: Idx) -> &mut Self::Output; } diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 7fcd19f67ee2d..d82e2a24bccda 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -676,7 +676,7 @@ //! let data_ptr = unpinned_src.data.as_ptr() as *const u8; //! let slice_ptr = unpinned_src.slice.as_ptr() as *const u8; //! let offset = slice_ptr.offset_from(data_ptr) as usize; -//! let len = (*unpinned_src.slice.as_ptr()).len(); +//! let len = unpinned_src.slice.as_ptr().len(); //! //! unpinned_self.slice = NonNull::from(&mut unpinned_self.data[offset..offset+len]); //! } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 3570d8d087660..676c4ec22c549 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -110,6 +110,7 @@ impl [T] { #[lang = "slice_len_fn"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_len", since = "1.39.0")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] #[inline] #[must_use] pub const fn len(&self) -> usize { @@ -129,6 +130,7 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_is_empty", since = "1.39.0")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] #[inline] #[must_use] pub const fn is_empty(&self) -> bool { @@ -589,6 +591,7 @@ impl [T] { /// assert_eq!(None, v.get(0..4)); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] #[inline] #[must_use] pub fn get(&self, index: I) -> Option<&I::Output> @@ -614,6 +617,7 @@ impl [T] { /// assert_eq!(x, &[0, 42, 2]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] #[inline] #[must_use] pub fn get_mut(&mut self, index: I) -> Option<&mut I::Output> @@ -651,6 +655,7 @@ impl [T] { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] #[inline] #[must_use] pub unsafe fn get_unchecked(&self, index: I) -> &I::Output @@ -693,6 +698,7 @@ impl [T] { /// assert_eq!(x, &[1, 13, 4]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] #[inline] #[must_use] pub unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 83ad10db2da45..c3da5fca6a506 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -135,6 +135,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_len", since = "1.39.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "str_len")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] #[must_use] #[inline] pub const fn len(&self) -> usize { @@ -154,6 +155,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_is_empty", since = "1.39.0")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] #[must_use] #[inline] pub const fn is_empty(&self) -> bool { diff --git a/src/tools/miri/tests/pass/dst-raw.rs b/src/tools/miri/tests/pass/dst-raw.rs index f26191a1d5998..3d0b843b3da22 100644 --- a/src/tools/miri/tests/pass/dst-raw.rs +++ b/src/tools/miri/tests/pass/dst-raw.rs @@ -1,5 +1,7 @@ // Test DST raw pointers +#![allow(dangerous_implicit_autorefs)] + trait Trait { fn foo(&self) -> isize; } diff --git a/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs b/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs index 830e9c33847cf..e86cb3711acb0 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs +++ b/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs @@ -1,3 +1,5 @@ +#![allow(dangerous_implicit_autorefs)] + use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell}; use std::mem::{self, MaybeUninit}; diff --git a/tests/ui/dynamically-sized-types/dst-raw.rs b/tests/ui/dynamically-sized-types/dst-raw.rs index 111848c5a7f05..935f0f11ca61f 100644 --- a/tests/ui/dynamically-sized-types/dst-raw.rs +++ b/tests/ui/dynamically-sized-types/dst-raw.rs @@ -1,6 +1,8 @@ //@ run-pass // Test DST raw pointers +#![allow(dangerous_implicit_autorefs)] + trait Trait { fn foo(&self) -> isize; } diff --git a/tests/ui/lint/implicit_autorefs.fixed b/tests/ui/lint/implicit_autorefs.fixed new file mode 100644 index 0000000000000..4a659b8df1b2e --- /dev/null +++ b/tests/ui/lint/implicit_autorefs.fixed @@ -0,0 +1,88 @@ +//@ check-pass +//@ run-rustfix + +#![allow(dead_code)] // for the rustfix-ed code + +use std::mem::ManuallyDrop; +use std::ptr::addr_of_mut; +use std::ptr::addr_of; +use std::ops::Deref; + +unsafe fn test_const(ptr: *const [u8]) -> *const [u8] { + addr_of!((&(*ptr))[..16]) + //~^ WARN implicit auto-ref +} + +struct Test { + field: [u8], +} + +unsafe fn test_field(ptr: *const Test) -> *const [u8] { + let l = (&(*ptr).field).len(); + //~^ WARN implicit auto-ref + + addr_of!((&(*ptr).field)[..l - 1]) + //~^ WARN implicit auto-ref +} + +unsafe fn test_builtin_index(a: *mut [String]) { + _ = (&(*a)[0]).len(); + //~^ WARN implicit auto-ref + + _ = (&(&(*a))[..1][0]).len(); + //~^ WARN implicit auto-ref + //~^^ WARN implicit auto-ref +} + +unsafe fn test_overloaded_deref_const(ptr: *const ManuallyDrop) { + let _ = (&(*ptr)).field; + //~^ WARN implicit auto-ref + let _ = addr_of!((&(*ptr)).field); + //~^ WARN implicit auto-ref +} + +unsafe fn test_overloaded_deref_mut(ptr: *mut ManuallyDrop) { + let _ = addr_of_mut!((&mut (*ptr)).field); + //~^ WARN implicit auto-ref +} + +unsafe fn test_double_overloaded_deref_const(ptr: *const ManuallyDrop>) { + let _ = addr_of!((&(*ptr)).field); + //~^ WARN implicit auto-ref +} + +unsafe fn test_manually_overloaded_deref() { + struct W(T); + + impl Deref for W { + type Target = T; + fn deref(&self) -> &T { &self.0 } + } + + let w: W = W(5); + let w = addr_of!(w); + let _p: *const i32 = addr_of!(*(&**w)); + //~^ WARN implicit auto-ref +} + +struct Test2 { + // derefs to [u8] + field: &'static [u8] +} + +fn test_more_manual_deref(ptr: *const Test2) -> usize { + unsafe { (&(*ptr).field).len() } + //~^ WARN implicit auto-ref +} + +unsafe fn test_no_attr(ptr: *mut ManuallyDrop) { + ptr.write(ManuallyDrop::new(1)); // should not warn, as `ManuallyDrop::write` is not + // annotated with `#[rustc_no_implicit_auto_ref]` +} + +unsafe fn test_vec_get(ptr: *const Vec) { + let _ = (&(*ptr)).get(0); + //~^ WARN implicit auto-ref +} + +fn main() {} diff --git a/tests/ui/lint/implicit_autorefs.rs b/tests/ui/lint/implicit_autorefs.rs new file mode 100644 index 0000000000000..4a3732497b1dd --- /dev/null +++ b/tests/ui/lint/implicit_autorefs.rs @@ -0,0 +1,88 @@ +//@ check-pass +//@ run-rustfix + +#![allow(dead_code)] // for the rustfix-ed code + +use std::mem::ManuallyDrop; +use std::ptr::addr_of_mut; +use std::ptr::addr_of; +use std::ops::Deref; + +unsafe fn test_const(ptr: *const [u8]) -> *const [u8] { + addr_of!((*ptr)[..16]) + //~^ WARN implicit auto-ref +} + +struct Test { + field: [u8], +} + +unsafe fn test_field(ptr: *const Test) -> *const [u8] { + let l = (*ptr).field.len(); + //~^ WARN implicit auto-ref + + addr_of!((*ptr).field[..l - 1]) + //~^ WARN implicit auto-ref +} + +unsafe fn test_builtin_index(a: *mut [String]) { + _ = (*a)[0].len(); + //~^ WARN implicit auto-ref + + _ = (*a)[..1][0].len(); + //~^ WARN implicit auto-ref + //~^^ WARN implicit auto-ref +} + +unsafe fn test_overloaded_deref_const(ptr: *const ManuallyDrop) { + let _ = (*ptr).field; + //~^ WARN implicit auto-ref + let _ = addr_of!((*ptr).field); + //~^ WARN implicit auto-ref +} + +unsafe fn test_overloaded_deref_mut(ptr: *mut ManuallyDrop) { + let _ = addr_of_mut!((*ptr).field); + //~^ WARN implicit auto-ref +} + +unsafe fn test_double_overloaded_deref_const(ptr: *const ManuallyDrop>) { + let _ = addr_of!((*ptr).field); + //~^ WARN implicit auto-ref +} + +unsafe fn test_manually_overloaded_deref() { + struct W(T); + + impl Deref for W { + type Target = T; + fn deref(&self) -> &T { &self.0 } + } + + let w: W = W(5); + let w = addr_of!(w); + let _p: *const i32 = addr_of!(**w); + //~^ WARN implicit auto-ref +} + +struct Test2 { + // derefs to [u8] + field: &'static [u8] +} + +fn test_more_manual_deref(ptr: *const Test2) -> usize { + unsafe { (*ptr).field.len() } + //~^ WARN implicit auto-ref +} + +unsafe fn test_no_attr(ptr: *mut ManuallyDrop) { + ptr.write(ManuallyDrop::new(1)); // should not warn, as `ManuallyDrop::write` is not + // annotated with `#[rustc_no_implicit_auto_ref]` +} + +unsafe fn test_vec_get(ptr: *const Vec) { + let _ = (*ptr).get(0); + //~^ WARN implicit auto-ref +} + +fn main() {} diff --git a/tests/ui/lint/implicit_autorefs.stderr b/tests/ui/lint/implicit_autorefs.stderr new file mode 100644 index 0000000000000..2ccacd8202a30 --- /dev/null +++ b/tests/ui/lint/implicit_autorefs.stderr @@ -0,0 +1,159 @@ +warning: implicit auto-ref creates a reference to a dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:12:14 + | +LL | addr_of!((*ptr)[..16]) + | ^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer to be valid and imposes aliasing requirements + = note: `#[warn(dangerous_implicit_autorefs)]` on by default +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | addr_of!((&(*ptr))[..16]) + | ++ + + +warning: implicit auto-ref creates a reference to a dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:21:13 + | +LL | let l = (*ptr).field.len(); + | ^^^^^^^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let l = (&(*ptr).field).len(); + | ++ + + +warning: implicit auto-ref creates a reference to a dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:24:14 + | +LL | addr_of!((*ptr).field[..l - 1]) + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | addr_of!((&(*ptr).field)[..l - 1]) + | ++ + + +warning: implicit auto-ref creates a reference to a dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:29:9 + | +LL | _ = (*a)[0].len(); + | ^^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | _ = (&(*a)[0]).len(); + | ++ + + +warning: implicit auto-ref creates a reference to a dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:32:9 + | +LL | _ = (*a)[..1][0].len(); + | ^^^^^^^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | _ = (&(*a)[..1][0]).len(); + | ++ + + +warning: implicit auto-ref creates a reference to a dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:32:9 + | +LL | _ = (*a)[..1][0].len(); + | ^^^^^^^^^ + | + = note: creating a reference requires the pointer to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | _ = (&(*a))[..1][0].len(); + | ++ + + +warning: implicit auto-ref creates a reference to a dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:38:13 + | +LL | let _ = (*ptr).field; + | ^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let _ = (&(*ptr)).field; + | ++ + + +warning: implicit auto-ref creates a reference to a dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:40:22 + | +LL | let _ = addr_of!((*ptr).field); + | ^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let _ = addr_of!((&(*ptr)).field); + | ++ + + +warning: implicit auto-ref creates a reference to a dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:45:26 + | +LL | let _ = addr_of_mut!((*ptr).field); + | ^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let _ = addr_of_mut!((&mut (*ptr)).field); + | +++++ + + +warning: implicit auto-ref creates a reference to a dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:50:22 + | +LL | let _ = addr_of!((*ptr).field); + | ^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let _ = addr_of!((&(*ptr)).field); + | ++ + + +warning: implicit auto-ref creates a reference to a dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:64:26 + | +LL | let _p: *const i32 = addr_of!(**w); + | ^^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let _p: *const i32 = addr_of!(*(&**w)); + | +++ + + +warning: implicit auto-ref creates a reference to a dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:74:14 + | +LL | unsafe { (*ptr).field.len() } + | ^^^^^^^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | unsafe { (&(*ptr).field).len() } + | ++ + + +warning: implicit auto-ref creates a reference to a dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:84:13 + | +LL | let _ = (*ptr).get(0); + | ^^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let _ = (&(*ptr)).get(0); + | ++ + + +warning: 13 warnings emitted +