Skip to main content

rustc_lint/
raw_borrows_via_references.rs

1use rustc_ast::BorrowKind;
2use rustc_hir::{Expr, ExprKind, TyKind};
3use rustc_session::{declare_lint, declare_lint_pass};
4
5use crate::lints::{RawBorrowViaReference, RawBorrowViaReferenceSuggestion};
6use crate::{LateContext, LateLintPass, LintContext};
7
8#[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.
45    pub RAW_BORROWS_VIA_REFERENCES,
46    // FIXME: This should eventually be `Warn`, see the "Explanation" above.
47    Allow,
48    "creating raw borrows via references is discouraged"
49}
50
51pub 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]);
52
53impl<'tcx> LateLintPass<'tcx> for RawBorrowsViaReferences {
54    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
55        if 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        {
60            let suggestion = if let Some(addr_of_span) =
61                addr_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            };
75
76            cx.emit_span_lint(
77                RAW_BORROWS_VIA_REFERENCES,
78                expr.span,
79                RawBorrowViaReference { suggestion },
80            );
81        }
82    }
83}