Skip to content

Commit 1d2d867

Browse files
committed
CFI: Rewrite closure and coroutine instances to their trait method
1 parent eec30e9 commit 1d2d867

File tree

3 files changed

+66
-0
lines changed

3 files changed

+66
-0
lines changed

compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs

+34
Original file line numberDiff line numberDiff line change
@@ -1150,6 +1150,40 @@ pub fn typeid_for_instance<'tcx>(
11501150
tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
11511151
instance.args = instance.args.rebase_onto(tcx, impl_id, abstract_trait_args);
11521152
}
1153+
} else if tcx.is_closure_like(instance.def_id()) {
1154+
// We're either a closure or a coroutine. Our goal is to find the trait we're defined on,
1155+
// instantiate it, and take the type of its only method as our own.
1156+
let closure_ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
1157+
match closure_ty.kind() {
1158+
ty::Closure(_def_id, args) => {
1159+
let ca = ty::ClosureArgs { args };
1160+
let trait_id = tcx
1161+
.fn_trait_kind_to_def_id(ca.kind())
1162+
.expect("Resolving abstract closure typeid for undefined Fn trait?");
1163+
let tuple_args = ca
1164+
.sig()
1165+
.inputs()
1166+
.no_bound_vars()
1167+
.expect("We are at codegen, this instance should be fully instantiated.")[0];
1168+
let trait_ref = ty::TraitRef::new(tcx, trait_id, [closure_ty, tuple_args]);
1169+
let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
1170+
let abstract_args =
1171+
tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
1172+
// There should be exactly one method on this trait, and it should be the one we're
1173+
// defining.
1174+
let call = tcx
1175+
.associated_items(trait_id)
1176+
.in_definition_order()
1177+
.find(|it| it.kind == ty::AssocKind::Fn)
1178+
.expect("No call-family function on closure-like Fn trait?")
1179+
.def_id;
1180+
1181+
instance.def = ty::InstanceDef::Virtual(call, 0);
1182+
instance.args = abstract_args;
1183+
}
1184+
ty::CoroutineClosure(_def_id, _args) => unimplemented!(),
1185+
x => bug!("Unexpected type kind for closure-like: {x:?}"),
1186+
}
11531187
}
11541188

11551189
let fn_abi = tcx
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Verifies that casting a closure to a Fn trait object works.
2+
//
3+
// FIXME(#122848): Remove only-linux when fixed.
4+
//@ only-linux
5+
//@ needs-sanitizer-cfi
6+
//@ compile-flags: -Clto -Copt-level=0 -Cprefer-dynamic=off -Ctarget-feature=-crt-static -Zsanitizer=cfi
7+
//@ run-pass
8+
9+
#![feature(fn_traits)]
10+
fn main() {
11+
let f: &(dyn Fn()) = &(|| {}) as _;
12+
f.call(());
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Verifies that casting a closure to a Fn trait object works.
2+
//
3+
// FIXME(#122848): Remove only-linux when fixed.
4+
//@ only-linux
5+
//@ needs-sanitizer-cfi
6+
//@ compile-flags: -Clto -Copt-level=0 -Cprefer-dynamic=off -Ctarget-feature=-crt-static -Zsanitizer=cfi
7+
//@ run-pass
8+
9+
fn foo<'a, T>() -> Box<dyn Fn(&'a T) -> &'a T> {
10+
Box::new(|x| x)
11+
}
12+
13+
fn main() {
14+
let x = 3;
15+
let f = foo();
16+
f(&x);
17+
// FIXME remove once drops are working.
18+
std::mem::forget(f);
19+
}

0 commit comments

Comments
 (0)