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 04b92fbd33bf2..29305896188df 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 0000000000000..016395c880f3e --- /dev/null +++ b/tests/ui/sanitizer/cfi-supertraits.rs @@ -0,0 +1,72 @@ +#![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 +//@ 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; + x.c(); + x.p1(); + x.p2(); + // Parents can be created and access their methods. + let y = &Foo as &dyn Parent1; + y.p1(); + let z = &Foo as &dyn Parent2; + z.p2(); + // Trait upcasting works + let x1 = x as &dyn Parent1; + x1.p1(); + let x2 = x as &dyn Parent2; + x2.p2(); +}