diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 460d54739a2..3c5cde4309b 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -1316,6 +1316,40 @@ impl<'tcx> LateContext<'tcx> { }) } + /// If the given expression is a local binding, find the initializer expression. + /// If that initializer expression is another local binding, find its initializer again. + /// + /// This process repeats as long as possible (but usually no more than once). + /// Type-check adjustments are not taken in account in this function. + /// + /// Examples: + /// ``` + /// let abc = 1; + /// let def = abc + 2; + /// // ^^^^^^^ output + /// let def = def; + /// dbg!(def); + /// // ^^^ input + /// ``` + pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> { + expr = expr.peel_blocks(); + + while let hir::ExprKind::Path(ref qpath) = expr.kind + && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) { + Res::Local(hir_id) => self.tcx.hir().find_parent(hir_id), + _ => None, + } + && let Some(init) = match parent_node { + hir::Node::Expr(expr) => Some(expr), + hir::Node::Local(hir::Local { init, .. }) => *init, + _ => None + } + { + expr = init.peel_blocks(); + } + expr + } + /// If the given expression is a local binding, find the initializer expression. /// If that initializer expression is another local or **outside** (`const`/`static`) /// binding, find its initializer again. @@ -1338,7 +1372,10 @@ impl<'tcx> LateContext<'tcx> { /// dbg!(def); /// // ^^^ input /// ``` - pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> { + pub fn expr_or_init_with_outside_body<'a>( + &self, + mut expr: &'a hir::Expr<'tcx>, + ) -> &'a hir::Expr<'tcx> { expr = expr.peel_blocks(); while let hir::ExprKind::Path(ref qpath) = expr.kind diff --git a/compiler/rustc_lint/src/invalid_from_utf8.rs b/compiler/rustc_lint/src/invalid_from_utf8.rs index 1841e7c85a8..e398059ade9 100644 --- a/compiler/rustc_lint/src/invalid_from_utf8.rs +++ b/compiler/rustc_lint/src/invalid_from_utf8.rs @@ -84,9 +84,9 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { ) }; - let mut init = cx.expr_or_init(arg); + let mut init = cx.expr_or_init_with_outside_body(arg); while let ExprKind::AddrOf(.., inner) = init.kind { - init = cx.expr_or_init(inner); + init = cx.expr_or_init_with_outside_body(inner); } match init.kind { ExprKind::Lit(Spanned { node: lit, .. }) => { diff --git a/tests/ui/lint/reference_casting.rs b/tests/ui/lint/reference_casting.rs index 3d73c261e55..fba8789e999 100644 --- a/tests/ui/lint/reference_casting.rs +++ b/tests/ui/lint/reference_casting.rs @@ -130,6 +130,7 @@ unsafe fn assign_to_ref() { } } +const RAW_PTR: *mut u8 = 1 as *mut u8; unsafe fn no_warn() { let num = &3i32; let mut_num = &mut 3i32; @@ -144,6 +145,9 @@ unsafe fn no_warn() { let mut value = 3; let value: *const i32 = &mut value; *(value as *const i16 as *mut i16) = 42; + *RAW_PTR = 42; // RAW_PTR is defined outside the function body, + // make sure we don't ICE on it when trying to + // determine if we should lint on it or not. fn safe_as_mut(x: &std::cell::UnsafeCell) -> &mut T { unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) }