Skip to content

Commit d9eed6a

Browse files
committed
CFI: Support non-general coroutines
Previously, we assumed all `ty::Coroutine` were general coroutines and attempted to generalize them through the `Coroutine` trait. Select appropriate traits for each kind of coroutine.
1 parent 6bb6b81 commit d9eed6a

File tree

2 files changed

+45
-8
lines changed

2 files changed

+45
-8
lines changed

compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs

+17-8
Original file line numberDiff line numberDiff line change
@@ -1218,22 +1218,31 @@ pub fn typeid_for_instance<'tcx>(
12181218
let trait_id = tcx.fn_trait_kind_to_def_id(closure_args.kind()).unwrap();
12191219
let tuple_args =
12201220
tcx.instantiate_bound_regions_with_erased(closure_args.sig()).inputs()[0];
1221-
(trait_id, tuple_args)
1221+
(trait_id, Some(tuple_args.into()))
12221222
}
1223-
ty::Coroutine(..) => (
1223+
// Implements coroutine, vtable entry could appear in `Coroutine`
1224+
ty::Coroutine(..) if tcx.is_general_coroutine(instance.def_id()) => (
12241225
tcx.require_lang_item(LangItem::Coroutine, None),
1225-
instance.args.as_coroutine().resume_ty(),
1226+
Some(instance.args.as_coroutine().resume_ty().into()),
12261227
),
1228+
// Async coroutines implement `Future`, which have no args
1229+
ty::Coroutine(..) if tcx.coroutine_is_async(instance.def_id()) => {
1230+
(tcx.require_lang_item(LangItem::Future, None), None)
1231+
}
12271232
ty::CoroutineClosure(..) => (
12281233
tcx.require_lang_item(LangItem::FnOnce, None),
1229-
tcx.instantiate_bound_regions_with_erased(
1230-
instance.args.as_coroutine_closure().coroutine_closure_sig(),
1231-
)
1232-
.tupled_inputs_ty,
1234+
Some(
1235+
tcx.instantiate_bound_regions_with_erased(
1236+
instance.args.as_coroutine_closure().coroutine_closure_sig(),
1237+
)
1238+
.tupled_inputs_ty
1239+
.into(),
1240+
),
12331241
),
12341242
x => bug!("Unexpected type kind for closure-like: {x:?}"),
12351243
};
1236-
let trait_ref = ty::TraitRef::new(tcx, trait_id, [closure_ty, inputs]);
1244+
let concrete_args = tcx.mk_args_trait(closure_ty, inputs);
1245+
let trait_ref = ty::TraitRef::new(tcx, trait_id, concrete_args);
12371246
let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
12381247
let abstract_args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
12391248
// There should be exactly one method on this trait, and it should be the one we're
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Check that async coroutines can be `dyn Future`
2+
3+
//@ edition: 2021
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 -Z panic-abort-tests -C prefer-dynamic=off
14+
//@ run-pass
15+
16+
#![feature(noop_waker)]
17+
18+
use std::future::Future;
19+
use std::pin::Pin;
20+
use std::task::{Context, Poll, Waker};
21+
22+
async fn async_fn() {}
23+
24+
fn main() {
25+
let f: fn() -> Pin<Box<dyn Future<Output = ()>>> = || Box::pin(async_fn());
26+
let _ = async { f().await; };
27+
assert_eq!(f().as_mut().poll(&mut Context::from_waker(Waker::noop())), Poll::Ready(()));
28+
}

0 commit comments

Comments
 (0)