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 d301f40

Browse files
committed
CFI: Encode Virtual calls as calls through the defining trait
For example, if `trait Foo: Bar`, and we try to call a method from `Bar` on `dyn Foo`, encode the callsite as passing a `dyn Bar`, not a `dyn Foo`.
1 parent d779a7a commit d301f40

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 let Some(impl_id) = tcx.impl_of_method(instance.def_id())
@@ -1190,15 +1199,11 @@ pub fn typeid_for_instance<'tcx>(
11901199
typeid_for_fnabi(tcx, fn_abi, options)
11911200
}
11921201

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

12161220
#[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 によって変換されたページ (->オリジナル) /