@@ -876,20 +876,14 @@ impl<'a, 'tcx> CastCheck<'tcx> {
876
876
// A<dyn Src<...> + SrcAuto> -> B<dyn Dst<...> + DstAuto>. need to make sure
877
877
// - `Src` and `Dst` traits are the same
878
878
// - traits have the same generic arguments
879
- // - `SrcAuto` is a superset of `DstAuto`
880
- ( Some ( src_principal) , Some ( dst_principal) ) => {
879
+ // - projections are the same
880
+ // - `SrcAuto` (+auto traits implied by `Src`) is a superset of `DstAuto`
881
+ //
882
+ // Note that trait upcasting goes through a different mechanism (`coerce_unsized`)
883
+ // and is unaffected by this check.
884
+ ( Some ( src_principal) , Some ( _) ) => {
881
885
let tcx = fcx. tcx ;
882
886
883
- // Check that the traits are actually the same.
884
- // The `dyn Src = dyn Dst` check below would suffice,
885
- // but this may produce a better diagnostic.
886
- //
887
- // Note that trait upcasting goes through a different mechanism (`coerce_unsized`)
888
- // and is unaffected by this check.
889
- if src_principal. def_id ( ) != dst_principal. def_id ( ) {
890
- return Err ( CastError :: DifferingKinds { src_kind, dst_kind } ) ;
891
- }
892
-
893
887
// We need to reconstruct trait object types.
894
888
// `m_src` and `m_dst` won't work for us here because they will potentially
895
889
// contain wrappers, which we do not care about.
@@ -912,8 +906,8 @@ impl<'a, 'tcx> CastCheck<'tcx> {
912
906
ty:: Dyn ,
913
907
) ) ;
914
908
915
- // `dyn Src = dyn Dst`, this checks for matching traits/generics
916
- // This is `demand_eqtype`, but inlined to give a better error.
909
+ // `dyn Src = dyn Dst`, this checks for matching traits/generics/projections
910
+ // This is `fcx. demand_eqtype`, but inlined to give a better error.
917
911
let cause = fcx. misc ( self . span ) ;
918
912
if fcx
919
913
. at ( & cause, fcx. param_env )
@@ -965,8 +959,35 @@ impl<'a, 'tcx> CastCheck<'tcx> {
965
959
// dyn Auto -> dyn Auto'? ok.
966
960
( None , None ) => Ok ( CastKind :: PtrPtrCast ) ,
967
961
968
- // dyn Trait -> dyn Auto? should be ok, but we used to not allow it.
969
- // FIXME: allow this
962
+ // dyn Trait -> dyn Auto? not ok (for now).
963
+ //
964
+ // Although dropping the principal is already allowed for unsizing coercions
965
+ // (e.g. `*const (dyn Trait + Auto)` to `*const dyn Auto`), dropping it is
966
+ // currently **NOT** allowed for (non-coercion) ptr-to-ptr casts (e.g
967
+ // `*const Foo` to `*const Bar` where `Foo` has a `dyn Trait + Auto` tail
968
+ // and `Bar` has a `dyn Auto` tail), because the underlying MIR operations
969
+ // currently work very differently:
970
+ //
971
+ // * A MIR unsizing coercion on raw pointers to trait objects (`*const dyn Src`
972
+ // to `*const dyn Dst`) is currently equivalent to downcasting the source to
973
+ // the concrete sized type that it was originally unsized from first (via a
974
+ // ptr-to-ptr cast from `*const Src` to `*const T` with `T: Sized`) and then
975
+ // unsizing this thin pointer to the target type (unsizing `*const T` to
976
+ // `*const Dst`). In particular, this means that the pointer's metadata
977
+ // (vtable) will semantically change, e.g. for const eval and miri, even
978
+ // though the vtables will always be merged for codegen.
979
+ //
980
+ // * A MIR ptr-to-ptr cast is currently equivalent to a transmute and does not
981
+ // change the pointer metadata (vtable) at all.
982
+ //
983
+ // In addition to this potentially surprising difference between coercion and
984
+ // non-coercion casts, casting away the principal with a MIR ptr-to-ptr cast
985
+ // is currently considered undefined behavior:
986
+ //
987
+ // As a validity invariant of pointers to trait objects, we currently require
988
+ // that the principal of the vtable in the pointer metadata exactly matches
989
+ // the principal of the pointee type, where "no principal" is also considered
990
+ // a kind of principal.
970
991
( Some ( _) , None ) => Err ( CastError :: DifferingKinds { src_kind, dst_kind } ) ,
971
992
972
993
// dyn Auto -> dyn Trait? not ok.
0 commit comments