Skip to content

Commit d563729

Browse files
authored
Rollup merge of rust-lang#123368 - maurer:cfi-non-general-coroutines, r=compiler-errors
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. I have this marked as a draft because it currently only fixes async coroutines, and I think it make sense to try to fix gen/async gen coroutines before this is merged. If the issue [mentioned](rust-lang#123106 (comment)) in the original PR is actually affecting someone, we can land this as is to remedy it.
2 parents 2536825 + a333b82 commit d563729

File tree

2 files changed

+62
-12
lines changed

2 files changed

+62
-12
lines changed

compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs

+23-10
Original file line numberDiff line numberDiff line change
@@ -1218,22 +1218,35 @@ 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))
12221222
}
1223-
ty::Coroutine(..) => (
1224-
tcx.require_lang_item(LangItem::Coroutine, None),
1225-
instance.args.as_coroutine().resume_ty(),
1226-
),
1223+
ty::Coroutine(..) => match tcx.coroutine_kind(instance.def_id()).unwrap() {
1224+
hir::CoroutineKind::Coroutine(..) => (
1225+
tcx.require_lang_item(LangItem::Coroutine, None),
1226+
Some(instance.args.as_coroutine().resume_ty()),
1227+
),
1228+
hir::CoroutineKind::Desugared(desugaring, _) => {
1229+
let lang_item = match desugaring {
1230+
hir::CoroutineDesugaring::Async => LangItem::Future,
1231+
hir::CoroutineDesugaring::AsyncGen => LangItem::AsyncIterator,
1232+
hir::CoroutineDesugaring::Gen => LangItem::Iterator,
1233+
};
1234+
(tcx.require_lang_item(lang_item, None), None)
1235+
}
1236+
},
12271237
ty::CoroutineClosure(..) => (
12281238
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,
1239+
Some(
1240+
tcx.instantiate_bound_regions_with_erased(
1241+
instance.args.as_coroutine_closure().coroutine_closure_sig(),
1242+
)
1243+
.tupled_inputs_ty,
1244+
),
12331245
),
12341246
x => bug!("Unexpected type kind for closure-like: {x:?}"),
12351247
};
1236-
let trait_ref = ty::TraitRef::new(tcx, trait_id, [closure_ty, inputs]);
1248+
let concrete_args = tcx.mk_args_trait(closure_ty, inputs.map(Into::into));
1249+
let trait_ref = ty::TraitRef::new(tcx, trait_id, concrete_args);
12371250
let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
12381251
let abstract_args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
12391252
// There should be exactly one method on this trait, and it should be the one we're

tests/ui/sanitizer/cfi-coroutine.rs

+39-2
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,30 @@
33
//@ revisions: cfi kcfi
44
// FIXME(#122848) Remove only-linux once OSX CFI binaries work
55
//@ only-linux
6+
//@ edition: 2024
67
//@ [cfi] needs-sanitizer-cfi
78
//@ [kcfi] needs-sanitizer-kcfi
89
//@ compile-flags: -C target-feature=-crt-static
910
//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
1011
//@ [cfi] compile-flags: -Z sanitizer=cfi
1112
//@ [kcfi] compile-flags: -Z sanitizer=kcfi
1213
//@ [kcfi] compile-flags: -C panic=abort -Z panic-abort-tests -C prefer-dynamic=off
13-
//@ compile-flags: --test
14+
//@ compile-flags: --test -Z unstable-options
1415
//@ run-pass
1516

1617
#![feature(coroutines)]
1718
#![feature(coroutine_trait)]
19+
#![feature(noop_waker)]
20+
#![feature(gen_blocks)]
21+
#![feature(async_iterator)]
1822

1923
use std::ops::{Coroutine, CoroutineState};
2024
use std::pin::{pin, Pin};
25+
use std::task::{Context, Poll, Waker};
26+
use std::async_iter::AsyncIterator;
2127

22-
fn main() {
28+
#[test]
29+
fn general_coroutine() {
2330
let mut coro = |x: i32| {
2431
yield x;
2532
"done"
@@ -28,3 +35,33 @@ fn main() {
2835
assert_eq!(abstract_coro.as_mut().resume(2), CoroutineState::Yielded(2));
2936
assert_eq!(abstract_coro.as_mut().resume(0), CoroutineState::Complete("done"));
3037
}
38+
39+
async fn async_fn() {}
40+
41+
#[test]
42+
fn async_coroutine() {
43+
let f: fn() -> Pin<Box<dyn Future<Output = ()>>> = || Box::pin(async_fn());
44+
let _ = async { f().await; };
45+
assert_eq!(f().as_mut().poll(&mut Context::from_waker(Waker::noop())), Poll::Ready(()));
46+
}
47+
48+
async gen fn async_gen_fn() -> u8 {
49+
yield 5;
50+
}
51+
52+
#[test]
53+
fn async_gen_coroutine() {
54+
let f: fn() -> Pin<Box<dyn AsyncIterator<Item = u8>>> = || Box::pin(async_gen_fn());
55+
assert_eq!(f().as_mut().poll_next(&mut Context::from_waker(Waker::noop())),
56+
Poll::Ready(Some(5)));
57+
}
58+
59+
gen fn gen_fn() -> u8 {
60+
yield 6;
61+
}
62+
63+
#[test]
64+
fn gen_coroutine() {
65+
let f: fn() -> Box<dyn Iterator<Item = u8>> = || Box::new(gen_fn());
66+
assert_eq!(f().next(), Some(6));
67+
}

0 commit comments

Comments
 (0)