Skip to content

Commit 21b4733

Browse files
authored
Rollup merge of rust-lang#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: - rust-lang#135881 - rust-lang#136702 - rust-lang#136776 Tracking: - rust-lang#127323 - rust-lang#44874 - rust-lang#123430
2 parents 1b9b515 + ef337a6 commit 21b4733

File tree

12 files changed

+110
-113
lines changed

12 files changed

+110
-113
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
An auto trait cannot be added to the bounds of a `dyn Trait` type via
2+
a pointer cast.
3+
4+
Erroneous code example:
5+
6+
```rust,edition2021,compile_fail,E0804
7+
let ptr: *const dyn core::any::Any = &();
8+
_ = ptr as *const (dyn core::any::Any + Send);
9+
```
10+
11+
Adding an auto trait can make the vtable invalid, potentially causing
12+
UB in safe code afterwards. For example:
13+
14+
```rust,edition2021,no_run
15+
use core::{mem::transmute, ptr::NonNull};
16+
17+
trait Trait {
18+
fn f(&self)
19+
where
20+
Self: Send;
21+
}
22+
23+
impl Trait for NonNull<()> {
24+
fn f(&self) {
25+
unreachable!()
26+
}
27+
}
28+
29+
fn main() {
30+
let unsend: &dyn Trait = &NonNull::dangling();
31+
let bad: &(dyn Trait + Send) = unsafe { transmute(unsend) };
32+
// This crashes, since the vtable for `NonNull as dyn Trait` does
33+
// not have an entry for `Trait::f`.
34+
bad.f();
35+
}
36+
```
37+
38+
To fix this error, you can use `transmute` rather than pointer casts,
39+
but you must ensure that the vtable is valid for the pointer's type
40+
before calling a method on the trait object or allowing other code to
41+
do so.

compiler/rustc_error_codes/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,7 @@ E0800: 0800,
547547
E0801: 0801,
548548
E0802: 0802,
549549
E0803: 0803,
550+
E0804: 0804,
550551
);
551552
)
552553
}

compiler/rustc_hir_typeck/messages.ftl

+6-3
Original file line numberDiff line numberDiff line change
@@ -171,10 +171,13 @@ hir_typeck_pass_to_variadic_function = can't pass `{$ty}` to variadic function
171171
.suggestion = cast the value to `{$cast_ty}`
172172
.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
173173
174-
hir_typeck_ptr_cast_add_auto_to_object = adding {$traits_len ->
175-
[1] an auto trait {$traits}
174+
hir_typeck_ptr_cast_add_auto_to_object = cannot add {$traits_len ->
175+
[1] auto trait {$traits}
176176
*[other] auto traits {$traits}
177-
} to a trait object in a pointer cast may cause UB later on
177+
} to dyn bound via pointer cast
178+
.note = this could allow UB elsewhere
179+
.help = use `transmute` if you're sure this is sound
180+
.label = unsupported cast
178181
179182
hir_typeck_remove_semi_for_coerce = you might have meant to return the `match` expression
180183
hir_typeck_remove_semi_for_coerce_expr = this could be implicitly returned but it is a statement, not a tail expression

compiler/rustc_hir_typeck/src/cast.rs

+12-16
Original file line numberDiff line numberDiff line change
@@ -940,23 +940,19 @@ impl<'a, 'tcx> CastCheck<'tcx> {
940940
.collect::<Vec<_>>();
941941

942942
if !added.is_empty() {
943-
tcx.emit_node_span_lint(
944-
lint::builtin::PTR_CAST_ADD_AUTO_TO_OBJECT,
945-
self.expr.hir_id,
946-
self.span,
947-
errors::PtrCastAddAutoToObject {
948-
traits_len: added.len(),
949-
traits: {
950-
let mut traits: Vec<_> = added
951-
.into_iter()
952-
.map(|trait_did| tcx.def_path_str(trait_did))
953-
.collect();
954-
955-
traits.sort();
956-
traits.into()
957-
},
943+
tcx.dcx().emit_err(errors::PtrCastAddAutoToObject {
944+
span: self.span,
945+
traits_len: added.len(),
946+
traits: {
947+
let mut traits: Vec<_> = added
948+
.into_iter()
949+
.map(|trait_did| tcx.def_path_str(trait_did))
950+
.collect();
951+
952+
traits.sort();
953+
traits.into()
958954
},
959-
)
955+
});
960956
}
961957

962958
Ok(CastKind::PtrPtrCast)

compiler/rustc_hir_typeck/src/errors.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -373,9 +373,14 @@ pub(crate) struct LossyProvenanceInt2Ptr<'tcx> {
373373
pub sugg: LossyProvenanceInt2PtrSuggestion,
374374
}
375375

376-
#[derive(LintDiagnostic)]
377-
#[diag(hir_typeck_ptr_cast_add_auto_to_object)]
376+
#[derive(Diagnostic)]
377+
#[diag(hir_typeck_ptr_cast_add_auto_to_object, code = E0804)]
378+
#[note]
379+
#[help]
378380
pub(crate) struct PtrCastAddAutoToObject {
381+
#[primary_span]
382+
#[label]
383+
pub span: Span,
379384
pub traits_len: usize,
380385
pub traits: DiagSymbolList<String>,
381386
}

compiler/rustc_lint/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,11 @@ fn register_builtins(store: &mut LintStore) {
599599
"converted into hard error, \
600600
see <https://github.com/rust-lang/rust/issues/73333> for more information",
601601
);
602+
store.register_removed(
603+
"ptr_cast_add_auto_to_object",
604+
"converted into hard error, see issue #127323 \
605+
<https://github.com/rust-lang/rust/issues/127323> for more information",
606+
);
602607
}
603608

604609
fn register_internals(store: &mut LintStore) {

compiler/rustc_lint_defs/src/builtin.rs

-53
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ declare_lint_pass! {
8080
PRIVATE_BOUNDS,
8181
PRIVATE_INTERFACES,
8282
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
83-
PTR_CAST_ADD_AUTO_TO_OBJECT,
8483
PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS,
8584
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
8685
REDUNDANT_IMPORTS,
@@ -4827,58 +4826,6 @@ declare_lint! {
48274826
};
48284827
}
48294828

4830-
declare_lint! {
4831-
/// The `ptr_cast_add_auto_to_object` lint detects casts of raw pointers to trait
4832-
/// objects, which add auto traits.
4833-
///
4834-
/// ### Example
4835-
///
4836-
/// ```rust,edition2021,compile_fail
4837-
/// let ptr: *const dyn core::any::Any = &();
4838-
/// _ = ptr as *const dyn core::any::Any + Send;
4839-
/// ```
4840-
///
4841-
/// {{produces}}
4842-
///
4843-
/// ### Explanation
4844-
///
4845-
/// Adding an auto trait can make the vtable invalid, potentially causing
4846-
/// UB in safe code afterwards. For example:
4847-
///
4848-
/// ```ignore (causes a warning)
4849-
/// #![feature(arbitrary_self_types)]
4850-
///
4851-
/// trait Trait {
4852-
/// fn f(self: *const Self)
4853-
/// where
4854-
/// Self: Send;
4855-
/// }
4856-
///
4857-
/// impl Trait for *const () {
4858-
/// fn f(self: *const Self) {
4859-
/// unreachable!()
4860-
/// }
4861-
/// }
4862-
///
4863-
/// fn main() {
4864-
/// let unsend: *const () = &();
4865-
/// let unsend: *const dyn Trait = &unsend;
4866-
/// let send_bad: *const (dyn Trait + Send) = unsend as _;
4867-
/// send_bad.f(); // this crashes, since vtable for `*const ()` does not have an entry for `f`
4868-
/// }
4869-
/// ```
4870-
///
4871-
/// Generally you must ensure that vtable is right for the pointer's type,
4872-
/// before passing the pointer to safe code.
4873-
pub PTR_CAST_ADD_AUTO_TO_OBJECT,
4874-
Warn,
4875-
"detects `as` casts from pointers to `dyn Trait` to pointers to `dyn Trait + Auto`",
4876-
@future_incompatible = FutureIncompatibleInfo {
4877-
reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
4878-
reference: "issue #127323 <https://github.com/rust-lang/rust/issues/127323>",
4879-
};
4880-
}
4881-
48824829
declare_lint! {
48834830
/// The `out_of_scope_macro_calls` lint detects `macro_rules` called when they are not in scope,
48844831
/// above their definition, which may happen in key-value attributes.
+8-6
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
1-
//@ check-pass
2-
31
trait Trait<'a> {}
42

53
fn add_auto<'a>(x: *mut dyn Trait<'a>) -> *mut (dyn Trait<'a> + Send) {
64
x as _
7-
//~^ warning: adding an auto trait `Send` to a trait object in a pointer cast may cause UB later on
8-
//~| warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
5+
//~^ ERROR cannot add auto trait `Send` to dyn bound via pointer cast
6+
//~| NOTE unsupported cast
7+
//~| NOTE this could allow UB elsewhere
8+
//~| HELP use `transmute` if you're sure this is sound
99
}
1010

1111
// (to test diagnostic list formatting)
1212
fn add_multiple_auto<'a>(x: *mut dyn Trait<'a>) -> *mut (dyn Trait<'a> + Send + Sync + Unpin) {
1313
x as _
14-
//~^ warning: adding auto traits `Send`, `Sync`, and `Unpin` to a trait object in a pointer cast may cause UB later on
15-
//~| warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
14+
//~^ ERROR cannot add auto traits `Send`, `Sync`, and `Unpin` to dyn bound via pointer cast
15+
//~| NOTE unsupported cast
16+
//~| NOTE this could allow UB elsewhere
17+
//~| HELP use `transmute` if you're sure this is sound
1618
}
1719

1820
fn main() {}
+11-33
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,21 @@
1-
warning: adding an auto trait `Send` to a trait object in a pointer cast may cause UB later on
2-
--> $DIR/ptr-to-trait-obj-add-auto.rs:6:5
1+
error[E0804]: cannot add auto trait `Send` to dyn bound via pointer cast
2+
--> $DIR/ptr-to-trait-obj-add-auto.rs:4:5
33
|
44
LL | x as _
5-
| ^^^^^^
5+
| ^^^^^^ unsupported cast
66
|
7-
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
8-
= note: for more information, see issue #127323 <https://github.com/rust-lang/rust/issues/127323>
9-
= note: `#[warn(ptr_cast_add_auto_to_object)]` on by default
7+
= note: this could allow UB elsewhere
8+
= help: use `transmute` if you're sure this is sound
109

11-
warning: adding auto traits `Send`, `Sync`, and `Unpin` to a trait object in a pointer cast may cause UB later on
10+
error[E0804]: cannot add auto traits `Send`, `Sync`, and `Unpin` to dyn bound via pointer cast
1211
--> $DIR/ptr-to-trait-obj-add-auto.rs:13:5
1312
|
1413
LL | x as _
15-
| ^^^^^^
14+
| ^^^^^^ unsupported cast
1615
|
17-
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
18-
= note: for more information, see issue #127323 <https://github.com/rust-lang/rust/issues/127323>
16+
= note: this could allow UB elsewhere
17+
= help: use `transmute` if you're sure this is sound
1918

20-
warning: 2 warnings emitted
21-
22-
Future incompatibility report: Future breakage diagnostic:
23-
warning: adding an auto trait `Send` to a trait object in a pointer cast may cause UB later on
24-
--> $DIR/ptr-to-trait-obj-add-auto.rs:6:5
25-
|
26-
LL | x as _
27-
| ^^^^^^
28-
|
29-
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
30-
= note: for more information, see issue #127323 <https://github.com/rust-lang/rust/issues/127323>
31-
= note: `#[warn(ptr_cast_add_auto_to_object)]` on by default
32-
33-
Future breakage diagnostic:
34-
warning: adding auto traits `Send`, `Sync`, and `Unpin` to a trait object in a pointer cast may cause UB later on
35-
--> $DIR/ptr-to-trait-obj-add-auto.rs:13:5
36-
|
37-
LL | x as _
38-
| ^^^^^^
39-
|
40-
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
41-
= note: for more information, see issue #127323 <https://github.com/rust-lang/rust/issues/127323>
42-
= note: `#[warn(ptr_cast_add_auto_to_object)]` on by default
19+
error: aborting due to 2 previous errors
4320

21+
For more information about this error, try `rustc --explain E0804`.

tests/ui/lint/removed-lints/README.md

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Removed lints
2+
3+
This directory contains tests to confirm that lints that have been
4+
removed do not cause errors and produce the appropriate warnings.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
//@ check-pass
2+
3+
#![deny(ptr_cast_add_auto_to_object)]
4+
//~^ WARN lint `ptr_cast_add_auto_to_object` has been removed
5+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
warning: lint `ptr_cast_add_auto_to_object` has been removed: converted into hard error, see issue #127323 <https://github.com/rust-lang/rust/issues/127323> for more information
2+
--> $DIR/ptr_cast_add_auto_to_object.rs:3:9
3+
|
4+
LL | #![deny(ptr_cast_add_auto_to_object)]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(renamed_and_removed_lints)]` on by default
8+
9+
warning: 1 warning emitted
10+

0 commit comments

Comments
 (0)