diff options
| author | bors <bors@rust-lang.org> | 2023-08-12 03:05:01 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-08-12 03:05:01 +0000 |
| commit | d1fa3e4de38d117c94e1cf0807ed629f679e0cab (patch) | |
| tree | 3559e983bf46807f9e245684d15b160155c08ae1 /compiler/rustc_lint/src/reference_casting.rs | |
| parent | d8fd588afa24f6fa5259a01b815912710713d62f (diff) | |
| parent | 4d0501412a3216ee4a495e071f4b5fdf43f56c4e (diff) | |
Auto merge of #114748 - cuviper:beta-next, r=cuviper
[beta] backport * Restrict linker version script of proc-macro crates to just its two symbols #114470 * bootstrap: config: fix version comparison bug #114440 * lint/ctypes: only try normalize #113921 * Avoid tls access while iterating through mpsc thread entries #113861 * Substitute types before checking inlining compatibility. #113802 * Revert "fix: bug etc/bash_complettion -> src/etc/... to avoid copy error" #113579 * lint/ctypes: fix () return type checks #113457 * Rename and allow cast_ref_to_mut lint #113422 * Ignore flaky clippy tests. #113621 r? cuviper
Diffstat (limited to 'compiler/rustc_lint/src/reference_casting.rs')
| -rw-r--r-- | compiler/rustc_lint/src/reference_casting.rs | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs new file mode 100644 index 00000000000..db8d7302a25 --- /dev/null +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -0,0 +1,73 @@ +use rustc_ast::Mutability; +use rustc_hir::{Expr, ExprKind, MutTy, TyKind, UnOp}; +use rustc_middle::ty; +use rustc_span::sym; + +use crate::{lints::InvalidReferenceCastingDiag, LateContext, LateLintPass, LintContext}; + +declare_lint! { + /// The `invalid_reference_casting` lint checks for casts of `&T` to `&mut T` + /// without using interior mutability. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #![deny(invalid_reference_casting)] + /// fn x(r: &i32) { + /// unsafe { + /// *(r as *const i32 as *mut i32) += 1; + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Casting `&T` to `&mut T` without using interior mutability is undefined behavior, + /// as it's a violation of Rust reference aliasing requirements. + /// + /// `UnsafeCell` is the only way to obtain aliasable data that is considered + /// mutable. + INVALID_REFERENCE_CASTING, + Allow, + "casts of `&T` to `&mut T` without interior mutability" +} + +declare_lint_pass!(InvalidReferenceCasting => [INVALID_REFERENCE_CASTING]); + +impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + let ExprKind::Unary(UnOp::Deref, e) = &expr.kind else { return; }; + + let e = e.peel_blocks(); + let e = if let ExprKind::Cast(e, t) = e.kind + && let TyKind::Ptr(MutTy { mutbl: Mutability::Mut, .. }) = t.kind { + e + } else if let ExprKind::MethodCall(_, expr, [], _) = e.kind + && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) + && cx.tcx.is_diagnostic_item(sym::ptr_cast_mut, def_id) { + expr + } else { + return; + }; + + let e = e.peel_blocks(); + let e = if let ExprKind::Cast(e, t) = e.kind + && let TyKind::Ptr(MutTy { mutbl: Mutability::Not, .. }) = t.kind { + e + } else if let ExprKind::Call(path, [arg]) = e.kind + && let ExprKind::Path(ref qpath) = path.kind + && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() + && cx.tcx.is_diagnostic_item(sym::ptr_from_ref, def_id) { + arg + } else { + return; + }; + + let e = e.peel_blocks(); + if let ty::Ref(..) = cx.typeck_results().node_type(e.hir_id).kind() { + cx.emit_spanned_lint(INVALID_REFERENCE_CASTING, expr.span, InvalidReferenceCastingDiag); + } + } +} |
