about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs24
-rw-r--r--tests/ui/sanitizer/cfi-supertraits.rs73
2 files changed, 87 insertions, 10 deletions
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index 04b92fbd33b..29305896188 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -1140,8 +1140,17 @@ pub fn typeid_for_instance<'tcx>(
         let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]);
         let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn);
         instance.args = tcx.mk_args_trait(self_ty, List::empty());
-    } else if matches!(instance.def, ty::InstanceDef::Virtual(..)) {
-        instance.args = strip_receiver_auto(tcx, instance.args);
+    } else if let ty::InstanceDef::Virtual(def_id, _) = instance.def {
+        let upcast_ty = match tcx.trait_of_item(def_id) {
+            Some(trait_id) => trait_object_ty(
+                tcx,
+                ty::Binder::dummy(ty::TraitRef::from_method(tcx, trait_id, instance.args)),
+            ),
+            // drop_in_place won't have a defining trait, skip the upcast
+            None => instance.args.type_at(0),
+        };
+        let stripped_ty = strip_receiver_auto(tcx, upcast_ty);
+        instance.args = tcx.mk_args_trait(stripped_ty, instance.args.into_iter().skip(1));
     }
 
     if let Some(impl_id) = tcx.impl_of_method(instance.def_id())
@@ -1190,15 +1199,11 @@ pub fn typeid_for_instance<'tcx>(
     typeid_for_fnabi(tcx, fn_abi, options)
 }
 
-fn strip_receiver_auto<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    args: ty::GenericArgsRef<'tcx>,
-) -> ty::GenericArgsRef<'tcx> {
-    let ty = args.type_at(0);
+fn strip_receiver_auto<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
     let ty::Dynamic(preds, lifetime, kind) = ty.kind() else {
         bug!("Tried to strip auto traits from non-dynamic type {ty}");
     };
-    let new_rcvr = if preds.principal().is_some() {
+    if preds.principal().is_some() {
         let filtered_preds =
             tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| {
                 !matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..))
@@ -1209,8 +1214,7 @@ fn strip_receiver_auto<'tcx>(
         // about it. This technically discards the knowledge that it was a type that was made
         // into a trait object at some point, but that's not a lot.
         tcx.types.unit
-    };
-    tcx.mk_args_trait(new_rcvr, args.into_iter().skip(1))
+    }
 }
 
 #[instrument(skip(tcx), ret)]
diff --git a/tests/ui/sanitizer/cfi-supertraits.rs b/tests/ui/sanitizer/cfi-supertraits.rs
new file mode 100644
index 00000000000..ed3d722ebb7
--- /dev/null
+++ b/tests/ui/sanitizer/cfi-supertraits.rs
@@ -0,0 +1,73 @@
+#![feature(trait_upcasting)]
+// Check that super-traits are callable.
+
+//@ revisions: cfi kcfi
+// FIXME(#122848) Remove only-linux once OSX CFI binaries work
+//@ only-linux
+//@ [cfi] needs-sanitizer-cfi
+//@ [kcfi] needs-sanitizer-kcfi
+//@ compile-flags: -C target-feature=-crt-static
+//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
+//@ [cfi] compile-flags: -Z sanitizer=cfi
+//@ [kcfi] compile-flags: -Z sanitizer=kcfi
+//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off
+//@ run-pass
+
+trait Parent1 {
+    type P1;
+    fn p1(&self) -> Self::P1;
+}
+
+trait Parent2 {
+    type P2;
+    fn p2(&self) -> Self::P2;
+}
+
+trait Child : Parent1 + Parent2 {
+    type C;
+    fn c(&self) -> Self::C;
+}
+
+struct Foo;
+
+impl Parent1 for Foo {
+    type P1 = u16;
+    fn p1(&self) -> Self::P1 {
+        println!("p1");
+        1
+    }
+}
+
+impl Parent2 for Foo {
+    type P2 = u32;
+    fn p2(&self) -> Self::P2 {
+        println!("p2");
+        2
+    }
+}
+
+impl Child for Foo {
+    type C = u8;
+    fn c(&self) -> Self::C {
+        println!("c");
+        0
+    }
+}
+
+fn main() {
+    // Child can access its own methods and super methods.
+    let x = &Foo as &dyn Child<C=u8,P1=u16,P2=u32>;
+    x.c();
+    x.p1();
+    x.p2();
+    // Parents can be created and access their methods.
+    let y = &Foo as &dyn Parent1<P1=u16>;
+    y.p1();
+    let z = &Foo as &dyn Parent2<P2=u32>;
+    z.p2();
+    // Trait upcasting works
+    let x1 = x as &dyn Parent1<P1=u16>;
+    x1.p1();
+    let x2 = x as &dyn Parent2<P2=u32>;
+    x2.p2();
+}