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
This commit is contained in:
commit
21b473334f
12 changed files with 109 additions and 112 deletions
41
compiler/rustc_error_codes/src/error_codes/E0804.md
Normal file
41
compiler/rustc_error_codes/src/error_codes/E0804.md
Normal file
|
@ -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.
|
|
@ -547,6 +547,7 @@ E0800: 0800,
|
||||||
E0801: 0801,
|
E0801: 0801,
|
||||||
E0802: 0802,
|
E0802: 0802,
|
||||||
E0803: 0803,
|
E0803: 0803,
|
||||||
|
E0804: 0804,
|
||||||
);
|
);
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,10 +171,13 @@ hir_typeck_pass_to_variadic_function = can't pass `{$ty}` to variadic function
|
||||||
.suggestion = cast the value to `{$cast_ty}`
|
.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
|
.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 ->
|
hir_typeck_ptr_cast_add_auto_to_object = cannot add {$traits_len ->
|
||||||
[1] an auto trait {$traits}
|
[1] auto trait {$traits}
|
||||||
*[other] auto traits {$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 = 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
|
hir_typeck_remove_semi_for_coerce_expr = this could be implicitly returned but it is a statement, not a tail expression
|
||||||
|
|
|
@ -940,23 +940,19 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if !added.is_empty() {
|
if !added.is_empty() {
|
||||||
tcx.emit_node_span_lint(
|
tcx.dcx().emit_err(errors::PtrCastAddAutoToObject {
|
||||||
lint::builtin::PTR_CAST_ADD_AUTO_TO_OBJECT,
|
span: self.span,
|
||||||
self.expr.hir_id,
|
traits_len: added.len(),
|
||||||
self.span,
|
traits: {
|
||||||
errors::PtrCastAddAutoToObject {
|
let mut traits: Vec<_> = added
|
||||||
traits_len: added.len(),
|
.into_iter()
|
||||||
traits: {
|
.map(|trait_did| tcx.def_path_str(trait_did))
|
||||||
let mut traits: Vec<_> = added
|
.collect();
|
||||||
.into_iter()
|
|
||||||
.map(|trait_did| tcx.def_path_str(trait_did))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
traits.sort();
|
traits.sort();
|
||||||
traits.into()
|
traits.into()
|
||||||
},
|
|
||||||
},
|
},
|
||||||
)
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(CastKind::PtrPtrCast)
|
Ok(CastKind::PtrPtrCast)
|
||||||
|
|
|
@ -373,9 +373,14 @@ pub(crate) struct LossyProvenanceInt2Ptr<'tcx> {
|
||||||
pub sugg: LossyProvenanceInt2PtrSuggestion,
|
pub sugg: LossyProvenanceInt2PtrSuggestion,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(hir_typeck_ptr_cast_add_auto_to_object)]
|
#[diag(hir_typeck_ptr_cast_add_auto_to_object, code = E0804)]
|
||||||
|
#[note]
|
||||||
|
#[help]
|
||||||
pub(crate) struct PtrCastAddAutoToObject {
|
pub(crate) struct PtrCastAddAutoToObject {
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
pub traits_len: usize,
|
pub traits_len: usize,
|
||||||
pub traits: DiagSymbolList<String>,
|
pub traits: DiagSymbolList<String>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -599,6 +599,11 @@ fn register_builtins(store: &mut LintStore) {
|
||||||
"converted into hard error, \
|
"converted into hard error, \
|
||||||
see <https://github.com/rust-lang/rust/issues/73333> for more information",
|
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) {
|
fn register_internals(store: &mut LintStore) {
|
||||||
|
|
|
@ -80,7 +80,6 @@ declare_lint_pass! {
|
||||||
PRIVATE_BOUNDS,
|
PRIVATE_BOUNDS,
|
||||||
PRIVATE_INTERFACES,
|
PRIVATE_INTERFACES,
|
||||||
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
|
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
|
||||||
PTR_CAST_ADD_AUTO_TO_OBJECT,
|
|
||||||
PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS,
|
PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS,
|
||||||
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
|
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
|
||||||
REDUNDANT_IMPORTS,
|
REDUNDANT_IMPORTS,
|
||||||
|
@ -4827,58 +4826,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! {
|
declare_lint! {
|
||||||
/// The `out_of_scope_macro_calls` lint detects `macro_rules` called when they are not in scope,
|
/// 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.
|
/// above their definition, which may happen in key-value attributes.
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
//@ check-pass
|
|
||||||
|
|
||||||
trait Trait<'a> {}
|
trait Trait<'a> {}
|
||||||
|
|
||||||
fn add_auto<'a>(x: *mut dyn Trait<'a>) -> *mut (dyn Trait<'a> + Send) {
|
fn add_auto<'a>(x: *mut dyn Trait<'a>) -> *mut (dyn Trait<'a> + Send) {
|
||||||
x as _
|
x as _
|
||||||
//~^ warning: adding an auto trait `Send` to a trait object in a pointer cast may cause UB later on
|
//~^ ERROR cannot add auto trait `Send` to dyn bound via pointer cast
|
||||||
//~| warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
//~| NOTE unsupported cast
|
||||||
|
//~| NOTE this could allow UB elsewhere
|
||||||
|
//~| HELP use `transmute` if you're sure this is sound
|
||||||
}
|
}
|
||||||
|
|
||||||
// (to test diagnostic list formatting)
|
// (to test diagnostic list formatting)
|
||||||
fn add_multiple_auto<'a>(x: *mut dyn Trait<'a>) -> *mut (dyn Trait<'a> + Send + Sync + Unpin) {
|
fn add_multiple_auto<'a>(x: *mut dyn Trait<'a>) -> *mut (dyn Trait<'a> + Send + Sync + Unpin) {
|
||||||
x as _
|
x as _
|
||||||
//~^ warning: adding auto traits `Send`, `Sync`, and `Unpin` to a trait object in a pointer cast may cause UB later on
|
//~^ ERROR cannot add auto traits `Send`, `Sync`, and `Unpin` to dyn bound via pointer cast
|
||||||
//~| warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
//~| NOTE unsupported cast
|
||||||
|
//~| NOTE this could allow UB elsewhere
|
||||||
|
//~| HELP use `transmute` if you're sure this is sound
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,43 +1,21 @@
|
||||||
warning: adding an auto trait `Send` to a trait object in a pointer cast may cause UB later on
|
error[E0804]: cannot add auto trait `Send` to dyn bound via pointer cast
|
||||||
--> $DIR/ptr-to-trait-obj-add-auto.rs:6:5
|
--> $DIR/ptr-to-trait-obj-add-auto.rs:4:5
|
||||||
|
|
|
|
||||||
LL | x as _
|
LL | x as _
|
||||||
| ^^^^^^
|
| ^^^^^^ unsupported cast
|
||||||
|
|
|
|
||||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
= note: this could allow UB elsewhere
|
||||||
= note: for more information, see issue #127323 <https://github.com/rust-lang/rust/issues/127323>
|
= help: use `transmute` if you're sure this is sound
|
||||||
= note: `#[warn(ptr_cast_add_auto_to_object)]` on by default
|
|
||||||
|
|
||||||
warning: adding auto traits `Send`, `Sync`, and `Unpin` to a trait object in a pointer cast may cause UB later on
|
error[E0804]: cannot add auto traits `Send`, `Sync`, and `Unpin` to dyn bound via pointer cast
|
||||||
--> $DIR/ptr-to-trait-obj-add-auto.rs:13:5
|
--> $DIR/ptr-to-trait-obj-add-auto.rs:13:5
|
||||||
|
|
|
|
||||||
LL | x as _
|
LL | x as _
|
||||||
| ^^^^^^
|
| ^^^^^^ unsupported cast
|
||||||
|
|
|
|
||||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
= note: this could allow UB elsewhere
|
||||||
= note: for more information, see issue #127323 <https://github.com/rust-lang/rust/issues/127323>
|
= help: use `transmute` if you're sure this is sound
|
||||||
|
|
||||||
warning: 2 warnings emitted
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
Future incompatibility report: Future breakage diagnostic:
|
|
||||||
warning: adding an auto trait `Send` to a trait object in a pointer cast may cause UB later on
|
|
||||||
--> $DIR/ptr-to-trait-obj-add-auto.rs:6:5
|
|
||||||
|
|
|
||||||
LL | x as _
|
|
||||||
| ^^^^^^
|
|
||||||
|
|
|
||||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
|
||||||
= note: for more information, see issue #127323 <https://github.com/rust-lang/rust/issues/127323>
|
|
||||||
= note: `#[warn(ptr_cast_add_auto_to_object)]` on by default
|
|
||||||
|
|
||||||
Future breakage diagnostic:
|
|
||||||
warning: adding auto traits `Send`, `Sync`, and `Unpin` to a trait object in a pointer cast may cause UB later on
|
|
||||||
--> $DIR/ptr-to-trait-obj-add-auto.rs:13:5
|
|
||||||
|
|
|
||||||
LL | x as _
|
|
||||||
| ^^^^^^
|
|
||||||
|
|
|
||||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
|
||||||
= note: for more information, see issue #127323 <https://github.com/rust-lang/rust/issues/127323>
|
|
||||||
= note: `#[warn(ptr_cast_add_auto_to_object)]` on by default
|
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0804`.
|
||||||
|
|
4
tests/ui/lint/removed-lints/README.md
Normal file
4
tests/ui/lint/removed-lints/README.md
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# Removed lints
|
||||||
|
|
||||||
|
This directory contains tests to confirm that lints that have been
|
||||||
|
removed do not cause errors and produce the appropriate warnings.
|
|
@ -0,0 +1,5 @@
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
#![deny(ptr_cast_add_auto_to_object)]
|
||||||
|
//~^ WARN lint `ptr_cast_add_auto_to_object` has been removed
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,10 @@
|
||||||
|
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
|
||||||
|
--> $DIR/ptr_cast_add_auto_to_object.rs:3:9
|
||||||
|
|
|
||||||
|
LL | #![deny(ptr_cast_add_auto_to_object)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(renamed_and_removed_lints)]` on by default
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue