about summary refs log tree commit diff
path: root/compiler/rustc_lint/src/reference_casting.rs
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-08-12 03:05:01 +0000
committerbors <bors@rust-lang.org>2023-08-12 03:05:01 +0000
commitd1fa3e4de38d117c94e1cf0807ed629f679e0cab (patch)
tree3559e983bf46807f9e245684d15b160155c08ae1 /compiler/rustc_lint/src/reference_casting.rs
parentd8fd588afa24f6fa5259a01b815912710713d62f (diff)
parent4d0501412a3216ee4a495e071f4b5fdf43f56c4e (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.rs73
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);
+        }
+    }
+}