diff options
| author | Stuart Cook <Zalathar@users.noreply.github.com> | 2024-10-24 14:19:55 +1100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-24 14:19:55 +1100 |
| commit | 4c0bab319260bacde18386f7e2504758b71eb97d (patch) | |
| tree | 121188611710c092557f3e218dc23b4813010430 | |
| parent | ad43be310f8b90f80c1d6b83806517b375ac224a (diff) | |
| parent | 46cc5e9e962fda2f99d4956ef539bf4b79fead26 (diff) | |
| download | rust-4c0bab319260bacde18386f7e2504758b71eb97d.tar.gz rust-4c0bab319260bacde18386f7e2504758b71eb97d.zip | |
Rollup merge of #131898 - lukas-code:ptr-cast-cleanup, r=compiler-errors
minor `*dyn` cast cleanup Small follow-up to https://github.com/rust-lang/rust/pull/130234 to remove a redundant check and clean up comments. No functional changes. Also, explain why casts cannot drop the principal even though coercions can, and add a test because apparently we didn't have one already. r? `@WaffleLapkin` or `@compiler-errors`
| -rw-r--r-- | compiler/rustc_hir_typeck/src/cast.rs | 53 | ||||
| -rw-r--r-- | tests/ui/cast/ptr-to-trait-obj-drop-principal.rs | 21 | ||||
| -rw-r--r-- | tests/ui/cast/ptr-to-trait-obj-drop-principal.stderr | 11 |
3 files changed, 69 insertions, 16 deletions
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index f7306063c16..483a8d1d9a9 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -876,20 +876,14 @@ impl<'a, 'tcx> CastCheck<'tcx> { // A<dyn Src<...> + SrcAuto> -> B<dyn Dst<...> + DstAuto>. need to make sure // - `Src` and `Dst` traits are the same // - traits have the same generic arguments - // - `SrcAuto` is a superset of `DstAuto` - (Some(src_principal), Some(dst_principal)) => { + // - projections are the same + // - `SrcAuto` (+auto traits implied by `Src`) is a superset of `DstAuto` + // + // Note that trait upcasting goes through a different mechanism (`coerce_unsized`) + // and is unaffected by this check. + (Some(src_principal), Some(_)) => { let tcx = fcx.tcx; - // Check that the traits are actually the same. - // The `dyn Src = dyn Dst` check below would suffice, - // but this may produce a better diagnostic. - // - // Note that trait upcasting goes through a different mechanism (`coerce_unsized`) - // and is unaffected by this check. - if src_principal.def_id() != dst_principal.def_id() { - return Err(CastError::DifferingKinds { src_kind, dst_kind }); - } - // We need to reconstruct trait object types. // `m_src` and `m_dst` won't work for us here because they will potentially // contain wrappers, which we do not care about. @@ -912,8 +906,8 @@ impl<'a, 'tcx> CastCheck<'tcx> { ty::Dyn, )); - // `dyn Src = dyn Dst`, this checks for matching traits/generics - // This is `demand_eqtype`, but inlined to give a better error. + // `dyn Src = dyn Dst`, this checks for matching traits/generics/projections + // This is `fcx.demand_eqtype`, but inlined to give a better error. let cause = fcx.misc(self.span); if fcx .at(&cause, fcx.param_env) @@ -965,8 +959,35 @@ impl<'a, 'tcx> CastCheck<'tcx> { // dyn Auto -> dyn Auto'? ok. (None, None) => Ok(CastKind::PtrPtrCast), - // dyn Trait -> dyn Auto? should be ok, but we used to not allow it. - // FIXME: allow this + // dyn Trait -> dyn Auto? not ok (for now). + // + // Although dropping the principal is already allowed for unsizing coercions + // (e.g. `*const (dyn Trait + Auto)` to `*const dyn Auto`), dropping it is + // currently **NOT** allowed for (non-coercion) ptr-to-ptr casts (e.g + // `*const Foo` to `*const Bar` where `Foo` has a `dyn Trait + Auto` tail + // and `Bar` has a `dyn Auto` tail), because the underlying MIR operations + // currently work very differently: + // + // * A MIR unsizing coercion on raw pointers to trait objects (`*const dyn Src` + // to `*const dyn Dst`) is currently equivalent to downcasting the source to + // the concrete sized type that it was originally unsized from first (via a + // ptr-to-ptr cast from `*const Src` to `*const T` with `T: Sized`) and then + // unsizing this thin pointer to the target type (unsizing `*const T` to + // `*const Dst`). In particular, this means that the pointer's metadata + // (vtable) will semantically change, e.g. for const eval and miri, even + // though the vtables will always be merged for codegen. + // + // * A MIR ptr-to-ptr cast is currently equivalent to a transmute and does not + // change the pointer metadata (vtable) at all. + // + // In addition to this potentially surprising difference between coercion and + // non-coercion casts, casting away the principal with a MIR ptr-to-ptr cast + // is currently considered undefined behavior: + // + // As a validity invariant of pointers to trait objects, we currently require + // that the principal of the vtable in the pointer metadata exactly matches + // the principal of the pointee type, where "no principal" is also considered + // a kind of principal. (Some(_), None) => Err(CastError::DifferingKinds { src_kind, dst_kind }), // dyn Auto -> dyn Trait? not ok. diff --git a/tests/ui/cast/ptr-to-trait-obj-drop-principal.rs b/tests/ui/cast/ptr-to-trait-obj-drop-principal.rs new file mode 100644 index 00000000000..01dd91fc77d --- /dev/null +++ b/tests/ui/cast/ptr-to-trait-obj-drop-principal.rs @@ -0,0 +1,21 @@ +//! Test that non-coercion casts aren't allowed to drop the principal, +//! because they cannot modify the pointer metadata. +//! +//! We test this in a const context to guard against UB if this is allowed +//! in the future. + +trait Trait {} +impl Trait for () {} + +struct Wrapper<T: ?Sized>(T); + +const OBJECT: *const (dyn Trait + Send) = &(); + +// coercions are allowed +const _: *const dyn Send = OBJECT as _; + +// casts are **not** allowed +const _: *const Wrapper<dyn Send> = OBJECT as _; +//~^ ERROR casting `*const (dyn Trait + Send + 'static)` as `*const Wrapper<dyn Send>` is invalid + +fn main() {} diff --git a/tests/ui/cast/ptr-to-trait-obj-drop-principal.stderr b/tests/ui/cast/ptr-to-trait-obj-drop-principal.stderr new file mode 100644 index 00000000000..719e0711f5b --- /dev/null +++ b/tests/ui/cast/ptr-to-trait-obj-drop-principal.stderr @@ -0,0 +1,11 @@ +error[E0606]: casting `*const (dyn Trait + Send + 'static)` as `*const Wrapper<dyn Send>` is invalid + --> $DIR/ptr-to-trait-obj-drop-principal.rs:18:37 + | +LL | const _: *const Wrapper<dyn Send> = OBJECT as _; + | ^^^^^^^^^^^ + | + = note: the trait objects may have different vtables + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0606`. |
