Skip to content

Commit 961e96a

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

File tree

13 files changed

+243
-15
lines changed

13 files changed

+243
-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: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//@ only-x86_64-unknown-linux-gnu
2+
//@ compile-flags: -C panic=abort -Zinline-mir=no
3+
//@ no-prefer-dynamic
4+
//@ edition:2024
5+
#![crate_type = "lib"]
6+
7+
trait TestTrait {
8+
fn test_func(&self);
9+
}
10+
11+
struct TestStruct {}
12+
13+
impl TestTrait for TestStruct {
14+
fn test_func(&self) {
15+
println!("TestStruct::test_func");
16+
}
17+
}
18+
19+
#[inline(never)]
20+
pub fn foo() -> impl TestTrait {
21+
TestStruct {}
22+
}
23+
24+
//~ MONO_ITEM fn foo
25+
//~ MONO_ITEM fn <TestStruct as TestTrait>::test_func
26+
27+
trait TestTrait2 {
28+
fn test_func2(&self);
29+
}
30+
31+
struct TestStruct2 {}
32+
33+
impl TestTrait2 for TestStruct2 {
34+
fn test_func2(&self) {
35+
println!("TestStruct2::test_func2");
36+
}
37+
}
38+
39+
#[inline(never)]
40+
pub fn foo2() -> Box<dyn TestTrait2> {
41+
Box::new(TestStruct2 {})
42+
}
43+
44+
//~ MONO_ITEM fn <TestStruct2 as TestTrait2>::test_func2
45+
//~ MONO_ITEM fn alloc::alloc::exchange_malloc
46+
//~ MONO_ITEM fn foo2
47+
//~ MONO_ITEM fn std::alloc::Global::alloc_impl
48+
//~ MONO_ITEM fn std::boxed::Box::<TestStruct2>::new
49+
50+
struct Counter {
51+
count: usize,
52+
}
53+
54+
impl Counter {
55+
fn new() -> Counter {
56+
Counter { count: 0 }
57+
}
58+
}
59+
60+
impl Iterator for Counter {
61+
type Item = usize;
62+
63+
fn next(&mut self) -> Option<Self::Item> {
64+
self.count += 1;
65+
if self.count < 6 { Some(self.count) } else { None }
66+
}
67+
}
68+
69+
#[inline(never)]
70+
pub fn foo3() -> Box<dyn Iterator<Item = usize>> {
71+
Box::new(Counter::new())
72+
}
73+
74+
//~ MONO_ITEM fn <Counter as std::iter::Iterator::advance_by::SpecAdvanceBy>::spec_advance_by
75+
//~ MONO_ITEM fn <Counter as std::iter::Iterator::advance_by::SpecAdvanceBy>::spec_advance_by::{closure#0}
76+
//~ MONO_ITEM fn <Counter as std::iter::Iterator>::advance_by
77+
//~ MONO_ITEM fn <Counter as std::iter::Iterator>::next
78+
//~ MONO_ITEM fn <Counter as std::iter::Iterator>::nth
79+
//~ MONO_ITEM fn <Counter as std::iter::Iterator>::size_hint
80+
//~ 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>>>
81+
//~ MONO_ITEM fn <std::option::Option<std::num::NonZero<usize>> as std::ops::FromResidual<std::option::Option<std::convert::Infallible>>>::from_residual
82+
//~ MONO_ITEM fn <std::option::Option<std::num::NonZero<usize>> as std::ops::Try>::branch
83+
//~ MONO_ITEM fn <std::option::Option<std::num::NonZero<usize>> as std::ops::Try>::from_output
84+
//~ MONO_ITEM fn foo3
85+
//~ MONO_ITEM fn std::boxed::Box::<Counter>::new
86+
//~ MONO_ITEM fn Counter::new
87+
//~ MONO_ITEM fn core::fmt::rt::<impl std::fmt::Arguments<'_>>::new_const::<1>

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: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
//@ compile-flags: -Z print-type-sizes --crate-type lib
1+
//@ compile-flags: -C panic=abort -Z print-type-sizes --crate-type lib
2+
//@ needs-deterministic-layouts
23
//@ edition:2021
34
//@ build-pass
45
//@ ignore-pass
6+
//@ only-x86_64
57

68
async fn wait() {}
79

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: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
//@ compile-flags: -Z print-type-sizes --crate-type=lib
1+
//@ compile-flags: -C panic=abort -Z print-type-sizes --crate-type=lib
2+
//@ needs-deterministic-layouts
23
//@ edition: 2021
34
//@ build-pass
45
//@ ignore-pass
6+
//@ only-x86_64
57

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

0 commit comments

Comments
 (0)