1use rustc_ast::BorrowKind;
2use rustc_hir::{Expr, ExprKind, TyKind};
3use rustc_session::{declare_lint, declare_lint_pass};
45use crate::lints::{RawBorrowViaReference, RawBorrowViaReferenceSuggestion};
6use crate::{LateContext, LateLintPass, LintContext};
78#[doc =
r" The `raw_borrows_via_references` lint checks for references that decay immediately into raw borrows."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust"]
#[doc = r" #![warn(raw_borrows_via_references)]"]
#[doc = r""]
#[doc = r" fn via_ref(x: *const (i32, i32)) -> *const i32 {"]
#[doc = r" unsafe { &(*x).0 as *const i32 }"]
#[doc = r" }"]
#[doc = r""]
#[doc = r" fn main() {"]
#[doc = r" let x = (0, 1);"]
#[doc = r" let _r = via_ref(&x);"]
#[doc = r" }"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc =
r" Creating unnecessary references is discouraged because it makes code"]
#[doc =
r" less explicit and can lead to undefined behavior. Creating a reference"]
#[doc = r" induces aliasing assumptions that the compiler relies on, so an"]
#[doc =
r" otherwise-pointless reference can cause undefined behavior even when the"]
#[doc =
r" reference is never read through. Avoiding them keeps the code more"]
#[doc = r" explicit and easier to reason about."]
#[doc = r""]
#[doc =
r" See the [Reference] for the full set of validity requirements that"]
#[doc = r" references must uphold."]
#[doc = r""]
#[doc =
r" [Reference]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html"]
#[doc = r""]
#[doc =
r#" This lint is "allow" by default because it will trigger for a large"#]
#[doc = r" amount of existing Rust code."]
#[doc = r" Eventually it is desired for this to become warn-by-default."]
pub static RAW_BORROWS_VIA_REFERENCES: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: "RAW_BORROWS_VIA_REFERENCES",
default_level: ::rustc_lint_defs::Allow,
desc: "creating raw borrows via references is discouraged",
is_externally_loaded: false,
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_lint! {
9/// The `raw_borrows_via_references` lint checks for references that decay immediately into raw borrows.
10 ///
11 /// ### Example
12 ///
13 /// ```rust
14 /// #![warn(raw_borrows_via_references)]
15 ///
16 /// fn via_ref(x: *const (i32, i32)) -> *const i32 {
17 /// unsafe { &(*x).0 as *const i32 }
18 /// }
19 ///
20 /// fn main() {
21 /// let x = (0, 1);
22 /// let _r = via_ref(&x);
23 /// }
24 /// ```
25 ///
26 /// {{produces}}
27 ///
28 /// ### Explanation
29 ///
30 /// Creating unnecessary references is discouraged because it makes code
31 /// less explicit and can lead to undefined behavior. Creating a reference
32 /// induces aliasing assumptions that the compiler relies on, so an
33 /// otherwise-pointless reference can cause undefined behavior even when the
34 /// reference is never read through. Avoiding them keeps the code more
35 /// explicit and easier to reason about.
36 ///
37 /// See the [Reference] for the full set of validity requirements that
38 /// references must uphold.
39 ///
40 /// [Reference]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
41 ///
42 /// This lint is "allow" by default because it will trigger for a large
43 /// amount of existing Rust code.
44 /// Eventually it is desired for this to become warn-by-default.
45pub RAW_BORROWS_VIA_REFERENCES,
46// FIXME: This should eventually be `Warn`, see the "Explanation" above.
47Allow,
48"creating raw borrows via references is discouraged"
49}5051pub struct RawBorrowsViaReferences;
#[automatically_derived]
impl ::core::marker::Copy for RawBorrowsViaReferences { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for RawBorrowsViaReferences { }
#[automatically_derived]
impl ::core::clone::Clone for RawBorrowsViaReferences {
#[inline]
fn clone(&self) -> RawBorrowsViaReferences { *self }
}
impl ::rustc_lint_defs::LintPass for RawBorrowsViaReferences {
fn name(&self) -> &'static str { "RawBorrowsViaReferences" }
fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[RAW_BORROWS_VIA_REFERENCES]))
}
}
impl RawBorrowsViaReferences {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[RAW_BORROWS_VIA_REFERENCES]))
}
}declare_lint_pass!(RawBorrowsViaReferences => [RAW_BORROWS_VIA_REFERENCES]);
5253impl<'tcx> LateLintPass<'tcx> for RawBorrowsViaReferences {
54fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
55if let ExprKind::Cast(exp, ty) = expr.kind
56 && let ExprKind::AddrOf(BorrowKind::Ref, mutbl, addr_of_exp) = exp.kind
57 && let TyKind::Ptr(_) = ty.kind
58 && addr_of_exp.is_syntactic_place_expr()
59 {
60let suggestion = if let Some(addr_of_span) =
61addr_of_exp.span.find_ancestor_in_same_ctxt(expr.span)
62 && let Some(ty_span) = ty.span.find_ancestor_in_same_ctxt(expr.span)
63 && expr.span.can_be_used_for_suggestions()
64 && addr_of_span.can_be_used_for_suggestions()
65 && ty_span.can_be_used_for_suggestions()
66 {
67 RawBorrowViaReferenceSuggestion::Spanful {
68 left: expr.span.until(addr_of_span),
69 right: addr_of_span.shrink_to_hi().until(ty_span.shrink_to_hi()),
70 mutbl: mutbl.ptr_str(),
71 }
72 } else {
73 RawBorrowViaReferenceSuggestion::Spanless { mutbl: mutbl.ptr_str() }
74 };
7576cx.emit_span_lint(
77RAW_BORROWS_VIA_REFERENCES,
78expr.span,
79RawBorrowViaReference { suggestion },
80 );
81 }
82 }
83}