@@ -9,6 +9,7 @@ fn main() {
99 drop_principal ( ) ;
1010 modulo_binder ( ) ;
1111 modulo_assoc ( ) ;
12+ bidirectional_subtyping ( ) ;
1213}
1314
1415fn vtable_nop_cast ( ) {
@@ -531,3 +532,32 @@ fn modulo_assoc() {
531532
532533 ( & ( ) as & dyn Trait as & dyn Middle < ( ) > ) . say_hello ( & 0 ) ;
533534}
535+
536+ fn bidirectional_subtyping ( ) {
537+ // Test that transmuting between subtypes of dyn traits is fine, even in the
538+ // "wrong direction", i.e. going from a lower-ranked to a higher-ranked dyn trait.
539+ // Note that compared to the `dyn-transmute-inner-binder` test, the `for` is on the
540+ // *outside* here!
541+
542+ trait Trait < U : ?Sized > { }
543+ impl < T , U : ?Sized > Trait < U > for T { }
544+
545+ struct Wrapper < T : ?Sized > ( T ) ;
546+
547+ let x: & dyn Trait < fn ( & ' static ( ) ) > = & ( ) ;
548+ let _y: & dyn for < ' a > Trait < fn ( & ' a ( ) ) > = unsafe { std:: mem:: transmute ( x) } ;
549+
550+ let x: & dyn for < ' a > Trait < fn ( & ' a ( ) ) > = & ( ) ;
551+ let _y: & dyn Trait < fn ( & ' static ( ) ) > = unsafe { std:: mem:: transmute ( x) } ;
552+
553+ let x: & dyn Trait < dyn Trait < fn ( & ' static ( ) ) > > = & ( ) ;
554+ let _y: & dyn for < ' a > Trait < dyn Trait < fn ( & ' a ( ) ) > > = unsafe { std:: mem:: transmute ( x) } ;
555+
556+ let x: & dyn for < ' a > Trait < dyn Trait < fn ( & ' a ( ) ) > > = & ( ) ;
557+ let _y: & dyn Trait < dyn Trait < fn ( & ' static ( ) ) > > = unsafe { std:: mem:: transmute ( x) } ;
558+
559+ // This lowers to a ptr-to-ptr cast (which behaves like a transmute)
560+ // and not an unsizing coercion:
561+ let x: * const dyn for < ' a > Trait < & ' a ( ) > = & ( ) ;
562+ let _y: * const Wrapper < dyn Trait < & ' static ( ) > > = x as _ ;
563+ }
0 commit comments