about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
author许杰友 Jieyou Xu (Joe) <39484203+jieyouxu@users.noreply.github.com>2025-03-05 21:46:34 +0800
committerGitHub <noreply@github.com>2025-03-05 21:46:34 +0800
commit21b473334fb3c96d41149655b730c5c8b3c19a8e (patch)
treefee0a285534a5daa96aa0e6ccedac06eddc8d7a9 /compiler
parent1b9b515674c46c8a59371b55ef857cbac8b985ae (diff)
parentef337a6599145766fc73b2896c6ff3e0fef65b0b (diff)
Rollup merge of #136764 - traviscross:TC/make-ptr_cast_add_auto_to_object-hard-error, r=oli-obk
Make `ptr_cast_add_auto_to_object` lint into hard error

In Rust 1.81, we added a FCW lint (including linting in dependencies) against pointer casts that add an auto trait to dyn bounds.  This was part of work making casts of pointers involving trait objects stricter, and was part of the work needed to restabilize trait upcasting.

We considered just making this a hard error, but opted against it at that time due to breakage found by crater.  This breakage was mostly due to the `anymap` crate which has been a persistent problem for us.

It's now a year later, and the fact that this is not yet a hard error is giving us pause about stabilizing arbitrary self types and `derive(CoercePointee)`.  So let's see about making a hard error of this.

r? ghost

cc ```@adetaylor``` ```@Darksonn``` ```@BoxyUwU``` ```@RalfJung``` ```@compiler-errors``` ```@oli-obk``` ```@WaffleLapkin```

Related:

- https://github.com/rust-lang/rust/pull/135881
- https://github.com/rust-lang/rust/issues/136702
- https://github.com/rust-lang/rust/pull/136776

Tracking:

- https://github.com/rust-lang/rust/issues/127323
- https://github.com/rust-lang/rust/issues/44874
- https://github.com/rust-lang/rust/issues/123430
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0804.md41
-rw-r--r--compiler/rustc_error_codes/src/lib.rs1
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl9
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs28
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs9
-rw-r--r--compiler/rustc_lint/src/lib.rs5
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs53
7 files changed, 72 insertions, 74 deletions
diff --git a/compiler/rustc_error_codes/src/error_codes/E0804.md b/compiler/rustc_error_codes/src/error_codes/E0804.md
new file mode 100644
index 00000000000..9a6937c0b52
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0804.md
@@ -0,0 +1,41 @@
+An auto trait cannot be added to the bounds of a `dyn Trait` type via
+a pointer cast.
+
+Erroneous code example:
+
+```rust,edition2021,compile_fail,E0804
+let ptr: *const dyn core::any::Any = &();
+_ = ptr as *const (dyn core::any::Any + Send);
+```
+
+Adding an auto trait can make the vtable invalid, potentially causing
+UB in safe code afterwards. For example:
+
+```rust,edition2021,no_run
+use core::{mem::transmute, ptr::NonNull};
+
+trait Trait {
+    fn f(&self)
+    where
+        Self: Send;
+}
+
+impl Trait for NonNull<()> {
+    fn f(&self) {
+        unreachable!()
+    }
+}
+
+fn main() {
+    let unsend: &dyn Trait = &NonNull::dangling();
+    let bad: &(dyn Trait + Send) = unsafe { transmute(unsend) };
+    // This crashes, since the vtable for `NonNull as dyn Trait` does
+    // not have an entry for `Trait::f`.
+    bad.f();
+}
+```
+
+To fix this error, you can use `transmute` rather than pointer casts,
+but you must ensure that the vtable is valid for the pointer's type
+before calling a method on the trait object or allowing other code to
+do so.
diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs
index 098ca42be2b..d53d5678832 100644
--- a/compiler/rustc_error_codes/src/lib.rs
+++ b/compiler/rustc_error_codes/src/lib.rs
@@ -547,6 +547,7 @@ E0800: 0800,
 E0801: 0801,
 E0802: 0802,
 E0803: 0803,
+E0804: 0804,
         );
     )
 }
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index ed80bc3e7be..872861d6289 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -171,10 +171,13 @@ hir_typeck_pass_to_variadic_function = can't pass `{$ty}` to variadic function
     .suggestion = cast the value to `{$cast_ty}`
     .teach_help = certain types, like `{$ty}`, must be casted before passing them to a variadic function, because of arcane ABI rules dictated by the C standard
 
-hir_typeck_ptr_cast_add_auto_to_object = adding {$traits_len ->
-    [1] an auto trait {$traits}
+hir_typeck_ptr_cast_add_auto_to_object = cannot add {$traits_len ->
+    [1] auto trait {$traits}
     *[other] auto traits {$traits}
-} to a trait object in a pointer cast may cause UB later on
+} to dyn bound via pointer cast
+    .note = this could allow UB elsewhere
+    .help = use `transmute` if you're sure this is sound
+    .label = unsupported cast
 
 hir_typeck_remove_semi_for_coerce = you might have meant to return the `match` expression
 hir_typeck_remove_semi_for_coerce_expr = this could be implicitly returned but it is a statement, not a tail expression
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index ea4ec345ad0..70b49fea34f 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -940,23 +940,19 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                             .collect::<Vec<_>>();
 
                         if !added.is_empty() {
-                            tcx.emit_node_span_lint(
-                                lint::builtin::PTR_CAST_ADD_AUTO_TO_OBJECT,
-                                self.expr.hir_id,
-                                self.span,
-                                errors::PtrCastAddAutoToObject {
-                                    traits_len: added.len(),
-                                    traits: {
-                                        let mut traits: Vec<_> = added
-                                            .into_iter()
-                                            .map(|trait_did| tcx.def_path_str(trait_did))
-                                            .collect();
-
-                                        traits.sort();
-                                        traits.into()
-                                    },
+                            tcx.dcx().emit_err(errors::PtrCastAddAutoToObject {
+                                span: self.span,
+                                traits_len: added.len(),
+                                traits: {
+                                    let mut traits: Vec<_> = added
+                                        .into_iter()
+                                        .map(|trait_did| tcx.def_path_str(trait_did))
+                                        .collect();
+
+                                    traits.sort();
+                                    traits.into()
                                 },
-                            )
+                            });
                         }
 
                         Ok(CastKind::PtrPtrCast)
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 20688a5b949..b73cd26927a 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -373,9 +373,14 @@ pub(crate) struct LossyProvenanceInt2Ptr<'tcx> {
     pub sugg: LossyProvenanceInt2PtrSuggestion,
 }
 
-#[derive(LintDiagnostic)]
-#[diag(hir_typeck_ptr_cast_add_auto_to_object)]
+#[derive(Diagnostic)]
+#[diag(hir_typeck_ptr_cast_add_auto_to_object, code = E0804)]
+#[note]
+#[help]
 pub(crate) struct PtrCastAddAutoToObject {
+    #[primary_span]
+    #[label]
+    pub span: Span,
     pub traits_len: usize,
     pub traits: DiagSymbolList<String>,
 }
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 5c5b3b350dd..7018774e5c6 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -599,6 +599,11 @@ fn register_builtins(store: &mut LintStore) {
         "converted into hard error, \
          see <https://github.com/rust-lang/rust/issues/73333> for more information",
     );
+    store.register_removed(
+        "ptr_cast_add_auto_to_object",
+        "converted into hard error, see issue #127323 \
+         <https://github.com/rust-lang/rust/issues/127323> for more information",
+    );
 }
 
 fn register_internals(store: &mut LintStore) {
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 3d63ea82053..10b85be2cfb 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -80,7 +80,6 @@ declare_lint_pass! {
         PRIVATE_BOUNDS,
         PRIVATE_INTERFACES,
         PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
-        PTR_CAST_ADD_AUTO_TO_OBJECT,
         PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS,
         PUB_USE_OF_PRIVATE_EXTERN_CRATE,
         REDUNDANT_IMPORTS,
@@ -4828,58 +4827,6 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `ptr_cast_add_auto_to_object` lint detects casts of raw pointers to trait
-    /// objects, which add auto traits.
-    ///
-    /// ### Example
-    ///
-    /// ```rust,edition2021,compile_fail
-    /// let ptr: *const dyn core::any::Any = &();
-    /// _ = ptr as *const dyn core::any::Any + Send;
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// Adding an auto trait can make the vtable invalid, potentially causing
-    /// UB in safe code afterwards. For example:
-    ///
-    /// ```ignore (causes a warning)
-    /// #![feature(arbitrary_self_types)]
-    ///
-    /// trait Trait {
-    ///     fn f(self: *const Self)
-    ///     where
-    ///         Self: Send;
-    /// }
-    ///
-    /// impl Trait for *const () {
-    ///     fn f(self: *const Self) {
-    ///         unreachable!()
-    ///     }
-    /// }
-    ///
-    /// fn main() {
-    ///     let unsend: *const () = &();
-    ///     let unsend: *const dyn Trait = &unsend;
-    ///     let send_bad: *const (dyn Trait + Send) = unsend as _;
-    ///     send_bad.f(); // this crashes, since vtable for `*const ()` does not have an entry for `f`
-    /// }
-    /// ```
-    ///
-    /// Generally you must ensure that vtable is right for the pointer's type,
-    /// before passing the pointer to safe code.
-    pub PTR_CAST_ADD_AUTO_TO_OBJECT,
-    Warn,
-    "detects `as` casts from pointers to `dyn Trait` to pointers to `dyn Trait + Auto`",
-    @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
-        reference: "issue #127323 <https://github.com/rust-lang/rust/issues/127323>",
-    };
-}
-
-declare_lint! {
     /// The `out_of_scope_macro_calls` lint detects `macro_rules` called when they are not in scope,
     /// above their definition, which may happen in key-value attributes.
     ///