Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 50e3d62

Browse files
committed
Auto merge of rust-lang#123012 - maurer:cfi-supertraits, r=compiler-errors
CFI: Support calling methods on supertraits Automatically adjust `Virtual` calls to supertrait functions to use the supertrait's trait object type as the receiver rather than the child trait. cc `@compiler-errors` - this is the next usage of `trait_object_ty` I intend to have, so I thought it might be relevant while reviewing the existing one.
2 parents 174d07b + d301f40 commit 50e3d62

File tree

2 files changed

+87
-10
lines changed

2 files changed

+87
-10
lines changed

‎compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs‎

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,8 +1140,17 @@ pub fn typeid_for_instance<'tcx>(
11401140
let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]);
11411141
let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn);
11421142
instance.args = tcx.mk_args_trait(self_ty, List::empty());
1143-
} else if matches!(instance.def, ty::InstanceDef::Virtual(..)) {
1144-
instance.args = strip_receiver_auto(tcx, instance.args);
1143+
} else if let ty::InstanceDef::Virtual(def_id, _) = instance.def {
1144+
let upcast_ty = match tcx.trait_of_item(def_id) {
1145+
Some(trait_id) => trait_object_ty(
1146+
tcx,
1147+
ty::Binder::dummy(ty::TraitRef::from_method(tcx, trait_id, instance.args)),
1148+
),
1149+
// drop_in_place won't have a defining trait, skip the upcast
1150+
None => instance.args.type_at(0),
1151+
};
1152+
let stripped_ty = strip_receiver_auto(tcx, upcast_ty);
1153+
instance.args = tcx.mk_args_trait(stripped_ty, instance.args.into_iter().skip(1));
11451154
}
11461155

11471156
if !options.contains(EncodeTyOptions::NO_SELF_TYPE_ERASURE)
@@ -1191,15 +1200,11 @@ pub fn typeid_for_instance<'tcx>(
11911200
typeid_for_fnabi(tcx, fn_abi, options)
11921201
}
11931202

1194-
fn strip_receiver_auto<'tcx>(
1195-
tcx: TyCtxt<'tcx>,
1196-
args: ty::GenericArgsRef<'tcx>,
1197-
) -> ty::GenericArgsRef<'tcx> {
1198-
let ty = args.type_at(0);
1203+
fn strip_receiver_auto<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
11991204
let ty::Dynamic(preds, lifetime, kind) = ty.kind() else {
12001205
bug!("Tried to strip auto traits from non-dynamic type {ty}");
12011206
};
1202-
let new_rcvr = if preds.principal().is_some() {
1207+
if preds.principal().is_some() {
12031208
let filtered_preds =
12041209
tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| {
12051210
!matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..))
@@ -1210,8 +1215,7 @@ fn strip_receiver_auto<'tcx>(
12101215
// about it. This technically discards the knowledge that it was a type that was made
12111216
// into a trait object at some point, but that's not a lot.
12121217
tcx.types.unit
1213-
};
1214-
tcx.mk_args_trait(new_rcvr, args.into_iter().skip(1))
1218+
}
12151219
}
12161220

12171221
#[instrument(skip(tcx), ret)]
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#![feature(trait_upcasting)]
2+
// Check that super-traits are callable.
3+
4+
//@ revisions: cfi kcfi
5+
// FIXME(#122848) Remove only-linux once OSX CFI binaries work
6+
//@ only-linux
7+
//@ [cfi] needs-sanitizer-cfi
8+
//@ [kcfi] needs-sanitizer-kcfi
9+
//@ compile-flags: -C target-feature=-crt-static
10+
//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
11+
//@ [cfi] compile-flags: -Z sanitizer=cfi
12+
//@ [kcfi] compile-flags: -Z sanitizer=kcfi
13+
//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off
14+
//@ run-pass
15+
16+
trait Parent1 {
17+
type P1;
18+
fn p1(&self) -> Self::P1;
19+
}
20+
21+
trait Parent2 {
22+
type P2;
23+
fn p2(&self) -> Self::P2;
24+
}
25+
26+
trait Child : Parent1 + Parent2 {
27+
type C;
28+
fn c(&self) -> Self::C;
29+
}
30+
31+
struct Foo;
32+
33+
impl Parent1 for Foo {
34+
type P1 = u16;
35+
fn p1(&self) -> Self::P1 {
36+
println!("p1");
37+
1
38+
}
39+
}
40+
41+
impl Parent2 for Foo {
42+
type P2 = u32;
43+
fn p2(&self) -> Self::P2 {
44+
println!("p2");
45+
2
46+
}
47+
}
48+
49+
impl Child for Foo {
50+
type C = u8;
51+
fn c(&self) -> Self::C {
52+
println!("c");
53+
0
54+
}
55+
}
56+
57+
fn main() {
58+
// Child can access its own methods and super methods.
59+
let x = &Foo as &dyn Child<C=u8,P1=u16,P2=u32>;
60+
x.c();
61+
x.p1();
62+
x.p2();
63+
// Parents can be created and access their methods.
64+
let y = &Foo as &dyn Parent1<P1=u16>;
65+
y.p1();
66+
let z = &Foo as &dyn Parent2<P2=u32>;
67+
z.p2();
68+
// Trait upcasting works
69+
let x1 = x as &dyn Parent1<P1=u16>;
70+
x1.p1();
71+
let x2 = x as &dyn Parent2<P2=u32>;
72+
x2.p2();
73+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /