Skip to content

Commit b520c78

Browse files
committed
pub async fn implementation coroutine (func::{closure#0}) is monomorphized, when func itself is monomorphized
1 parent 922958c commit b520c78

File tree

13 files changed

+237
-15
lines changed

13 files changed

+237
-15
lines changed

compiler/rustc_monomorphize/src/collector.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1535,7 +1535,20 @@ impl<'v> RootCollector<'_, 'v> {
15351535
fn process_nested_body(&mut self, def_id: LocalDefId) {
15361536
match self.tcx.def_kind(def_id) {
15371537
DefKind::Closure => {
1538-
if self.strategy == MonoItemCollectionStrategy::Eager
1538+
// for 'pub async fn foo(..)' also trying to monomorphize foo::{closure}
1539+
let is_pub_fn_coroutine =
1540+
match *self.tcx.type_of(def_id).instantiate_identity().kind() {
1541+
ty::Coroutine(cor_id, _args) => {
1542+
let tcx = self.tcx;
1543+
let parent_id = tcx.parent(cor_id);
1544+
tcx.def_kind(parent_id) == DefKind::Fn
1545+
&& tcx.asyncness(parent_id).is_async()
1546+
&& tcx.visibility(parent_id).is_public()
1547+
}
1548+
ty::Closure(..) | ty::CoroutineClosure(..) => false,
1549+
_ => unreachable!(),
1550+
};
1551+
if (self.strategy == MonoItemCollectionStrategy::Eager || is_pub_fn_coroutine)
15391552
&& !self
15401553
.tcx
15411554
.generics_of(self.tcx.typeck_root_def_id(def_id.to_def_id()))

tests/codegen-llvm/async-fn-debug-awaitee-field.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ pub async fn async_fn_test() {
1818

1919
pub async fn foo() {}
2020

21+
// NONMSVC: [[AWAITEE_TYPE:![0-9]*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[AWAITEE_SCOPE:![0-9]*]],
22+
// MSVC: [[AWAITEE_TYPE:![0-9]*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<async_fn_debug_awaitee_field::foo::async_fn_env$0>",
23+
// NONMSVC: [[AWAITEE_SCOPE]] = !DINamespace(name: "foo",
2124
// NONMSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[GEN_SCOPE:![0-9]*]],
2225
// MSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<async_fn_debug_awaitee_field::async_fn_test::async_fn_env$0>",
2326
// NONMSVC: [[GEN_SCOPE:!.*]] = !DINamespace(name: "async_fn_test",
2427
// CHECK: [[SUSPEND_STRUCT:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend0", scope: [[GEN]],
25-
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__awaitee", scope: [[SUSPEND_STRUCT]], {{.*}}, baseType: [[AWAITEE_TYPE:![0-9]*]],
26-
// NONMSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[AWAITEE_SCOPE:![0-9]*]],
27-
// MSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<async_fn_debug_awaitee_field::foo::async_fn_env$0>",
28-
// NONMSVC: [[AWAITEE_SCOPE]] = !DINamespace(name: "foo",
28+
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__awaitee", scope: [[SUSPEND_STRUCT]], {{.*}}, baseType: [[AWAITEE_TYPE]],
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//@ edition: 2024
2+
// When pub async fn is monomorphized, its implementation coroutine is also monomorphized
3+
//@ compile-flags: --crate-type=lib
4+
5+
//~ MONO_ITEM fn async_fn @@
6+
//~ MONO_ITEM fn async_fn::{closure#0} @@
7+
#[unsafe(no_mangle)]
8+
pub async fn async_fn(x: u64) -> bool {
9+
true
10+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//@ compile-flags: -C panic=abort
2+
//@ no-prefer-dynamic
3+
//@ edition:2024
4+
#![crate_type = "lib"]
5+
6+
trait TestTrait {
7+
fn test_func(&self);
8+
}
9+
10+
struct TestStruct {}
11+
12+
impl TestTrait for TestStruct {
13+
fn test_func(&self) {
14+
println!("TestStruct::test_func");
15+
}
16+
}
17+
18+
#[inline(never)]
19+
pub fn foo() -> impl TestTrait {
20+
TestStruct {}
21+
}
22+
23+
//~ MONO_ITEM fn foo
24+
//~ MONO_ITEM fn <TestStruct as TestTrait>::test_func
25+
26+
trait TestTrait2 {
27+
fn test_func2(&self);
28+
}
29+
30+
struct TestStruct2 {}
31+
32+
impl TestTrait2 for TestStruct2 {
33+
fn test_func2(&self) {
34+
println!("TestStruct2::test_func2");
35+
}
36+
}
37+
38+
#[inline(never)]
39+
pub fn foo2() -> Box<dyn TestTrait2> {
40+
Box::new(TestStruct2 {})
41+
}
42+
43+
//~ MONO_ITEM fn <TestStruct2 as TestTrait2>::test_func2
44+
//~ MONO_ITEM fn alloc::alloc::exchange_malloc
45+
//~ MONO_ITEM fn foo2
46+
//~ MONO_ITEM fn std::alloc::Global::alloc_impl
47+
//~ MONO_ITEM fn std::boxed::Box::<TestStruct2>::new
48+
49+
struct Counter {
50+
count: usize,
51+
}
52+
53+
impl Counter {
54+
fn new() -> Counter {
55+
Counter { count: 0 }
56+
}
57+
}
58+
59+
impl Iterator for Counter {
60+
type Item = usize;
61+
62+
fn next(&mut self) -> Option<Self::Item> {
63+
self.count += 1;
64+
if self.count < 6 { Some(self.count) } else { None }
65+
}
66+
}
67+
68+
#[inline(never)]
69+
pub fn foo3() -> Box<dyn Iterator<Item = usize>> {
70+
Box::new(Counter::new())
71+
}
72+
73+
//~ MONO_ITEM fn <Counter as std::iter::Iterator::advance_by::SpecAdvanceBy>::spec_advance_by
74+
//~ MONO_ITEM fn <Counter as std::iter::Iterator::advance_by::SpecAdvanceBy>::spec_advance_by::{closure#0}
75+
//~ MONO_ITEM fn <Counter as std::iter::Iterator>::advance_by
76+
//~ MONO_ITEM fn <Counter as std::iter::Iterator>::next
77+
//~ MONO_ITEM fn <Counter as std::iter::Iterator>::nth
78+
//~ MONO_ITEM fn <Counter as std::iter::Iterator>::size_hint
79+
//~ MONO_ITEM fn <Counter as std::iter::Iterator>::try_fold::<std::num::NonZero<usize>, {closure@<Counter as std::iter::Iterator::advance_by::SpecAdvanceBy>::spec_advance_by::{closure#0}}, std::option::Option<std::num::NonZero<usize>>>
80+
//~ MONO_ITEM fn <std::option::Option<std::num::NonZero<usize>> as std::ops::FromResidual<std::option::Option<std::convert::Infallible>>>::from_residual
81+
//~ MONO_ITEM fn <std::option::Option<std::num::NonZero<usize>> as std::ops::Try>::branch
82+
//~ MONO_ITEM fn <std::option::Option<std::num::NonZero<usize>> as std::ops::Try>::from_output
83+
//~ MONO_ITEM fn foo3
84+
//~ MONO_ITEM fn std::boxed::Box::<Counter>::new

tests/coverage/async.cov-map

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,21 +103,21 @@ Number of file 0 mappings: 3
103103
Highest counter ID seen: (none)
104104

105105
Function name: async::g
106-
Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 01, 00, 16]
106+
Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 01, 00, 12]
107107
Number of files: 1
108108
- file 0 => $DIR/async.rs
109109
Number of expressions: 0
110110
Number of file 0 mappings: 1
111-
- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 22)
111+
- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 18)
112112
Highest counter ID seen: c0
113113

114114
Function name: async::g::{closure#0} (unused)
115-
Raw bytes (64): 0x[01, 01, 00, 0c, 00, 1b, 17, 00, 18, 00, 01, 0b, 00, 0c, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02]
115+
Raw bytes (64): 0x[01, 01, 00, 0c, 00, 1b, 13, 00, 14, 00, 01, 0b, 00, 0c, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02]
116116
Number of files: 1
117117
- file 0 => $DIR/async.rs
118118
Number of expressions: 0
119119
Number of file 0 mappings: 12
120-
- Code(Zero) at (prev + 27, 23) to (start + 0, 24)
120+
- Code(Zero) at (prev + 27, 19) to (start + 0, 20)
121121
- Code(Zero) at (prev + 1, 11) to (start + 0, 12)
122122
- Code(Zero) at (prev + 1, 9) to (start + 0, 10)
123123
- Code(Zero) at (prev + 0, 14) to (start + 0, 23)

tests/coverage/async.coverage

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
LL| |
2525
LL| 0|async fn foo() -> [bool; 10] { [false; 10] } // unused function; executor does not block on `h()`
2626
LL| |
27-
LL| 1|pub async fn g(x: u8) {
28-
^0
27+
LL| 1|async fn g(x: u8) {
28+
^0
2929
LL| 0| match x {
3030
LL| 0| y if e().await == y => (),
3131
LL| 0| y if f().await == y => (),

tests/coverage/async.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ async fn f() -> u8 { 1 }
2424

2525
async fn foo() -> [bool; 10] { [false; 10] } // unused function; executor does not block on `h()`
2626

27-
pub async fn g(x: u8) {
27+
async fn g(x: u8) {
2828
match x {
2929
y if e().await == y => (),
3030
y if f().await == y => (),

tests/ui/async-await/future-sizes/async-awaiting-fut.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
//@ compile-flags: -Z print-type-sizes --crate-type lib
1+
//@ compile-flags: -C panic=abort -Z print-type-sizes --crate-type lib -Z randomize-layout=no
22
//@ edition:2021
33
//@ build-pass
44
//@ ignore-pass
5+
//@ only-x86_64
56

67
async fn wait() {}
78

tests/ui/async-await/future-sizes/async-awaiting-fut.stdout

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,39 @@ print-type-size variant `Returned`: 1024 bytes
4848
print-type-size upvar `.arg`: 1024 bytes
4949
print-type-size variant `Panicked`: 1024 bytes
5050
print-type-size upvar `.arg`: 1024 bytes
51+
print-type-size type: `std::task::Context<'_>`: 32 bytes, alignment: 8 bytes
52+
print-type-size field `.waker`: 8 bytes
53+
print-type-size field `.local_waker`: 8 bytes
54+
print-type-size field `.ext`: 16 bytes
55+
print-type-size field `._marker`: 0 bytes
56+
print-type-size field `._marker2`: 0 bytes
57+
print-type-size type: `std::panic::Location<'_>`: 24 bytes, alignment: 8 bytes
58+
print-type-size field `.filename`: 16 bytes
59+
print-type-size field `.line`: 4 bytes
60+
print-type-size field `.col`: 4 bytes
61+
print-type-size field `._filename`: 0 bytes
62+
print-type-size type: `core::task::wake::ExtData<'_>`: 16 bytes, alignment: 8 bytes
63+
print-type-size variant `Some`: 16 bytes
64+
print-type-size field `.0`: 16 bytes
65+
print-type-size variant `None`: 0 bytes
66+
print-type-size field `.0`: 0 bytes
67+
print-type-size type: `std::panic::AssertUnwindSafe<core::task::wake::ExtData<'_>>`: 16 bytes, alignment: 8 bytes
68+
print-type-size field `.0`: 16 bytes
69+
print-type-size type: `std::ptr::NonNull<str>`: 16 bytes, alignment: 8 bytes
70+
print-type-size field `.pointer`: 16 bytes
71+
print-type-size type: `std::pin::Pin<&mut {async fn body of big_fut()}>`: 8 bytes, alignment: 8 bytes
72+
print-type-size field `.pointer`: 8 bytes
73+
print-type-size type: `std::pin::Pin<&mut {async fn body of calls_fut<{async fn body of big_fut()}>()}>`: 8 bytes, alignment: 8 bytes
74+
print-type-size field `.pointer`: 8 bytes
75+
print-type-size type: `std::pin::Pin<&mut {async fn body of test()}>`: 8 bytes, alignment: 8 bytes
76+
print-type-size field `.pointer`: 8 bytes
77+
print-type-size type: `std::pin::Pin<&mut {async fn body of wait()}>`: 8 bytes, alignment: 8 bytes
78+
print-type-size field `.pointer`: 8 bytes
79+
print-type-size type: `std::ptr::DynMetadata<dyn std::any::Any>`: 8 bytes, alignment: 8 bytes
80+
print-type-size field `._vtable_ptr`: 8 bytes
81+
print-type-size field `._phantom`: 0 bytes
82+
print-type-size type: `std::ptr::NonNull<std::ptr::metadata::VTable>`: 8 bytes, alignment: 8 bytes
83+
print-type-size field `.pointer`: 8 bytes
5184
print-type-size type: `std::mem::ManuallyDrop<bool>`: 1 bytes, alignment: 1 bytes
5285
print-type-size field `.value`: 1 bytes
5386
print-type-size type: `std::mem::ManuallyDrop<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes
@@ -70,3 +103,7 @@ print-type-size discriminant: 1 bytes
70103
print-type-size variant `Unresumed`: 0 bytes
71104
print-type-size variant `Returned`: 0 bytes
72105
print-type-size variant `Panicked`: 0 bytes
106+
print-type-size type: `std::marker::PhantomData<&str>`: 0 bytes, alignment: 1 bytes
107+
print-type-size type: `std::marker::PhantomData<*mut ()>`: 0 bytes, alignment: 1 bytes
108+
print-type-size type: `std::marker::PhantomData<dyn std::any::Any>`: 0 bytes, alignment: 1 bytes
109+
print-type-size type: `std::marker::PhantomData<fn(&()) -> &()>`: 0 bytes, alignment: 1 bytes

tests/ui/async-await/future-sizes/large-arg.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
//@ compile-flags: -Z print-type-sizes --crate-type=lib
1+
//@ compile-flags: -C panic=abort -Z print-type-sizes --crate-type=lib -Z randomize-layout=no
22
//@ edition: 2021
33
//@ build-pass
44
//@ ignore-pass
5+
//@ only-x86_64
56

67
pub async fn test() {
78
let _ = a([0u8; 1024]).await;

0 commit comments

Comments
 (0)