Skip to content

pub async fn impl is monomorphized when func itself is monomorphized #143290

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

azhogin
Copy link
Contributor

@azhogin azhogin commented Jul 1, 2025

Implentation coroutine (func::{closure#0}) is monomorphized, when func itself is monomorphized.

Currently, when pub async fn foo(..) is exported from lib and used in several dependent crates, only 'header' function is monomorphized in the defining crate. 'header' function, returning coroutine object, is monomorphized, but the coroutine's poll function (which actually implements all the logic for the function) is not. In such situation, func::{closure#0} will be monomorphized in every dependency.

This PR adds monomorphization for func::{closure#0} (coroutine poll function), when func itself is monomorphized.

Simple test with one lib async function and ten dependent crates (executable) that use the function, shows 5-7% compilation time improvement (single-threaded).

@rustbot
Copy link
Collaborator

rustbot commented Jul 1, 2025

r? @oli-obk

rustbot has assigned @oli-obk.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jul 1, 2025
@oli-obk
Copy link
Contributor

oli-obk commented Jul 2, 2025

I don't think this needs a -Z flag. It makes a lot of sense to just change this everywhere. We can then benchmark it in the benchmark suite, too.

A similar change could be done for iterator or closure returning functions.

On that note: instead of collecting nested bodies in general, wouldn't it be slightly more correct to collect types that are in the opaque (non-opque types must already have all their impls monomorphized, as they are publicly reachable) return type of monomorphized functions? For opaque types we'd only need to monomorphize the trait impls that the opaque type has in its bounds

cc @compiler-errors for thoughts as you wrote #135314

@azhogin azhogin force-pushed the azhogin/link-pub-async-impls branch from d6bb74b to a6b81d5 Compare July 2, 2025 11:54
@rustbot
Copy link
Collaborator

rustbot commented Jul 2, 2025

Some changes occurred in coverage tests.

cc @Zalathar

@azhogin azhogin force-pushed the azhogin/link-pub-async-impls branch from a6b81d5 to d6e2c24 Compare July 2, 2025 11:55
@azhogin azhogin changed the title -Zlink-pub-async-impls flag added to monomorphize pub async fn impl Jul 2, 2025
@azhogin
Copy link
Contributor Author

azhogin commented Jul 2, 2025

Flag removed, behaviour changed to be default.
"opaque return type of monomorphized functions" - not yet.

@rust-log-analyzer
Copy link
Collaborator

The job aarch64-gnu-llvm-19-1 failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
---- [ui] tests/ui/async-await/future-sizes/async-awaiting-fut.rs stdout ----
Saved the actual stdout to `/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/async-await/future-sizes/async-awaiting-fut/async-awaiting-fut.stdout`
diff of stdout:

50 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
+ print-type-size     field `._marker`: 0 bytes
53 print-type-size     field `.local_waker`: 8 bytes
54 print-type-size     field `.ext`: 16 bytes
- 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
- print-type-size     field `.file_bytes_with_nul`: 16 bytes
+ print-type-size     field `._filename`: 0 bytes
59 print-type-size     field `.line`: 4 bytes
60 print-type-size     field `.col`: 4 bytes
+ print-type-size     field `.filename`: 16 bytes
61 print-type-size type: `core::task::wake::ExtData<'_>`: 16 bytes, alignment: 8 bytes
62 print-type-size     variant `Some`: 16 bytes
63 print-type-size         field `.0`: 16 bytes

65 print-type-size         field `.0`: 0 bytes
66 print-type-size type: `std::panic::AssertUnwindSafe<core::task::wake::ExtData<'_>>`: 16 bytes, alignment: 8 bytes
67 print-type-size     field `.0`: 16 bytes
+ print-type-size type: `std::ptr::NonNull<str>`: 16 bytes, alignment: 8 bytes
+ print-type-size     field `.pointer`: 16 bytes
68 print-type-size type: `std::pin::Pin<&mut {async fn body of big_fut()}>`: 8 bytes, alignment: 8 bytes
69 print-type-size     field `.pointer`: 8 bytes
70 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

100 print-type-size     variant `Unresumed`: 0 bytes
101 print-type-size     variant `Returned`: 0 bytes
102 print-type-size     variant `Panicked`: 0 bytes
+ print-type-size type: `std::marker::PhantomData<&str>`: 0 bytes, alignment: 1 bytes
103 print-type-size type: `std::marker::PhantomData<*mut ()>`: 0 bytes, alignment: 1 bytes
104 print-type-size type: `std::marker::PhantomData<dyn std::any::Any>`: 0 bytes, alignment: 1 bytes
105 print-type-size type: `std::marker::PhantomData<fn(&()) -> &()>`: 0 bytes, alignment: 1 bytes


The actual stdout differed from the expected stdout
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args async-await/future-sizes/async-awaiting-fut.rs`

error: 1 errors occurred comparing output.
status: exit status: 0
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/async-await/future-sizes/async-awaiting-fut.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2" "--target=aarch64-unknown-linux-gnu" "--check-cfg" "cfg(test,FALSE)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/async-await/future-sizes/async-awaiting-fut" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/aarch64-unknown-linux-gnu/native/rust-test-helpers" "--edition=2021" "-C" "panic=abort" "-Z" "print-type-sizes" "--crate-type" "lib"
--- stdout -------------------------------
print-type-size type: `{async fn body of test()}`: 3078 bytes, alignment: 1 bytes
print-type-size     discriminant: 1 bytes
print-type-size     variant `Unresumed`: 0 bytes
print-type-size     variant `Suspend0`: 3077 bytes
print-type-size         local `.__awaitee`: 3077 bytes, type: {async fn body of calls_fut<{async fn body of big_fut()}>()}
print-type-size     variant `Returned`: 0 bytes
print-type-size     variant `Panicked`: 0 bytes
print-type-size type: `std::mem::ManuallyDrop<{async fn body of calls_fut<{async fn body of big_fut()}>()}>`: 3077 bytes, alignment: 1 bytes
print-type-size     field `.value`: 3077 bytes
print-type-size type: `std::mem::MaybeUninit<{async fn body of calls_fut<{async fn body of big_fut()}>()}>`: 3077 bytes, alignment: 1 bytes
print-type-size     variant `MaybeUninit`: 3077 bytes
print-type-size         field `.uninit`: 0 bytes
print-type-size         field `.value`: 3077 bytes
print-type-size type: `{async fn body of calls_fut<{async fn body of big_fut()}>()}`: 3077 bytes, alignment: 1 bytes
print-type-size     discriminant: 1 bytes
print-type-size     variant `Unresumed`: 1025 bytes
print-type-size         upvar `.fut`: 1025 bytes
print-type-size     variant `Suspend0`: 2052 bytes
print-type-size         upvar `.fut`: 1025 bytes
print-type-size         local `.fut`: 1025 bytes
print-type-size         local `..coroutine_field4`: 1 bytes, type: bool
print-type-size         local `.__awaitee`: 1 bytes, type: {async fn body of wait()}
print-type-size     variant `Suspend1`: 3076 bytes
print-type-size         upvar `.fut`: 1025 bytes
print-type-size         padding: 1025 bytes
print-type-size         local `..coroutine_field4`: 1 bytes, alignment: 1 bytes, type: bool
print-type-size         local `.__awaitee`: 1025 bytes, type: {async fn body of big_fut()}
print-type-size     variant `Suspend2`: 2052 bytes
print-type-size         upvar `.fut`: 1025 bytes
print-type-size         local `.fut`: 1025 bytes
print-type-size         local `..coroutine_field4`: 1 bytes, type: bool
print-type-size         local `.__awaitee`: 1 bytes, type: {async fn body of wait()}
print-type-size     variant `Returned`: 1025 bytes
print-type-size         upvar `.fut`: 1025 bytes
print-type-size     variant `Panicked`: 1025 bytes
print-type-size         upvar `.fut`: 1025 bytes
print-type-size type: `std::mem::ManuallyDrop<{async fn body of big_fut()}>`: 1025 bytes, alignment: 1 bytes
print-type-size     field `.value`: 1025 bytes
print-type-size type: `std::mem::MaybeUninit<{async fn body of big_fut()}>`: 1025 bytes, alignment: 1 bytes
print-type-size     variant `MaybeUninit`: 1025 bytes
print-type-size         field `.uninit`: 0 bytes
print-type-size         field `.value`: 1025 bytes
print-type-size type: `{async fn body of big_fut()}`: 1025 bytes, alignment: 1 bytes
print-type-size     discriminant: 1 bytes
print-type-size     variant `Unresumed`: 1024 bytes
print-type-size         upvar `.arg`: 1024 bytes
print-type-size     variant `Returned`: 1024 bytes
print-type-size         upvar `.arg`: 1024 bytes
print-type-size     variant `Panicked`: 1024 bytes
print-type-size         upvar `.arg`: 1024 bytes
print-type-size type: `std::task::Context<'_>`: 32 bytes, alignment: 8 bytes
print-type-size     field `.waker`: 8 bytes
print-type-size     field `._marker`: 0 bytes
print-type-size     field `.local_waker`: 8 bytes
print-type-size     field `.ext`: 16 bytes
print-type-size     field `._marker2`: 0 bytes
print-type-size type: `std::panic::Location<'_>`: 24 bytes, alignment: 8 bytes
print-type-size     field `._filename`: 0 bytes
print-type-size     field `.line`: 4 bytes
print-type-size     field `.col`: 4 bytes
print-type-size     field `.filename`: 16 bytes
print-type-size type: `core::task::wake::ExtData<'_>`: 16 bytes, alignment: 8 bytes
print-type-size     variant `Some`: 16 bytes
print-type-size         field `.0`: 16 bytes
print-type-size     variant `None`: 0 bytes
print-type-size         field `.0`: 0 bytes
print-type-size type: `std::panic::AssertUnwindSafe<core::task::wake::ExtData<'_>>`: 16 bytes, alignment: 8 bytes
print-type-size     field `.0`: 16 bytes
print-type-size type: `std::ptr::NonNull<str>`: 16 bytes, alignment: 8 bytes
print-type-size     field `.pointer`: 16 bytes
print-type-size type: `std::pin::Pin<&mut {async fn body of big_fut()}>`: 8 bytes, alignment: 8 bytes
print-type-size     field `.pointer`: 8 bytes
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
print-type-size     field `.pointer`: 8 bytes
print-type-size type: `std::pin::Pin<&mut {async fn body of test()}>`: 8 bytes, alignment: 8 bytes
print-type-size     field `.pointer`: 8 bytes
print-type-size type: `std::pin::Pin<&mut {async fn body of wait()}>`: 8 bytes, alignment: 8 bytes
print-type-size     field `.pointer`: 8 bytes
print-type-size type: `std::ptr::DynMetadata<dyn std::any::Any>`: 8 bytes, alignment: 8 bytes
print-type-size     field `._vtable_ptr`: 8 bytes
print-type-size     field `._phantom`: 0 bytes
print-type-size type: `std::ptr::NonNull<std::ptr::metadata::VTable>`: 8 bytes, alignment: 8 bytes
print-type-size     field `.pointer`: 8 bytes
print-type-size type: `std::mem::ManuallyDrop<bool>`: 1 bytes, alignment: 1 bytes
print-type-size     field `.value`: 1 bytes
print-type-size type: `std::mem::ManuallyDrop<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes
print-type-size     field `.value`: 1 bytes
print-type-size type: `std::mem::MaybeUninit<bool>`: 1 bytes, alignment: 1 bytes
print-type-size     variant `MaybeUninit`: 1 bytes
print-type-size         field `.uninit`: 0 bytes
print-type-size         field `.value`: 1 bytes
print-type-size type: `std::mem::MaybeUninit<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes
print-type-size     variant `MaybeUninit`: 1 bytes
print-type-size         field `.uninit`: 0 bytes
print-type-size         field `.value`: 1 bytes
print-type-size type: `std::task::Poll<()>`: 1 bytes, alignment: 1 bytes
print-type-size     discriminant: 1 bytes
print-type-size     variant `Ready`: 0 bytes
print-type-size         field `.0`: 0 bytes
print-type-size     variant `Pending`: 0 bytes
print-type-size type: `{async fn body of wait()}`: 1 bytes, alignment: 1 bytes
print-type-size     discriminant: 1 bytes
print-type-size     variant `Unresumed`: 0 bytes
print-type-size     variant `Returned`: 0 bytes
print-type-size     variant `Panicked`: 0 bytes
print-type-size type: `std::marker::PhantomData<&str>`: 0 bytes, alignment: 1 bytes
print-type-size type: `std::marker::PhantomData<*mut ()>`: 0 bytes, alignment: 1 bytes
print-type-size type: `std::marker::PhantomData<dyn std::any::Any>`: 0 bytes, alignment: 1 bytes
print-type-size type: `std::marker::PhantomData<fn(&()) -> &()>`: 0 bytes, alignment: 1 bytes
------------------------------------------
stderr: none


---- [ui] tests/ui/async-await/future-sizes/large-arg.rs stdout ----
Saved the actual stdout to `/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/async-await/future-sizes/large-arg/large-arg.stdout`
diff of stdout:

60 print-type-size         upvar `.t`: 1024 bytes
61 print-type-size type: `std::task::Context<'_>`: 32 bytes, alignment: 8 bytes
62 print-type-size     field `.waker`: 8 bytes
+ print-type-size     field `._marker`: 0 bytes
63 print-type-size     field `.local_waker`: 8 bytes
64 print-type-size     field `.ext`: 16 bytes
- print-type-size     field `._marker`: 0 bytes
66 print-type-size     field `._marker2`: 0 bytes
67 print-type-size type: `std::panic::Location<'_>`: 24 bytes, alignment: 8 bytes
- print-type-size     field `.file_bytes_with_nul`: 16 bytes
+ print-type-size     field `._filename`: 0 bytes
69 print-type-size     field `.line`: 4 bytes
70 print-type-size     field `.col`: 4 bytes
+ print-type-size     field `.filename`: 16 bytes
71 print-type-size type: `core::task::wake::ExtData<'_>`: 16 bytes, alignment: 8 bytes
72 print-type-size     variant `Some`: 16 bytes
73 print-type-size         field `.0`: 16 bytes

75 print-type-size         field `.0`: 0 bytes
76 print-type-size type: `std::panic::AssertUnwindSafe<core::task::wake::ExtData<'_>>`: 16 bytes, alignment: 8 bytes
77 print-type-size     field `.0`: 16 bytes
+ print-type-size type: `std::ptr::NonNull<str>`: 16 bytes, alignment: 8 bytes
+ print-type-size     field `.pointer`: 16 bytes
78 print-type-size type: `std::pin::Pin<&mut {async fn body of a<[u8; 1024]>()}>`: 8 bytes, alignment: 8 bytes
79 print-type-size     field `.pointer`: 8 bytes
80 print-type-size type: `std::pin::Pin<&mut {async fn body of b<[u8; 1024]>()}>`: 8 bytes, alignment: 8 bytes

93 print-type-size     variant `Ready`: 0 bytes
94 print-type-size         field `.0`: 0 bytes
95 print-type-size     variant `Pending`: 0 bytes
+ print-type-size type: `std::marker::PhantomData<&str>`: 0 bytes, alignment: 1 bytes
96 print-type-size type: `std::marker::PhantomData<*mut ()>`: 0 bytes, alignment: 1 bytes
97 print-type-size type: `std::marker::PhantomData<dyn std::any::Any>`: 0 bytes, alignment: 1 bytes
98 print-type-size type: `std::marker::PhantomData<fn(&()) -> &()>`: 0 bytes, alignment: 1 bytes


The actual stdout differed from the expected stdout
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args async-await/future-sizes/large-arg.rs`

error: 1 errors occurred comparing output.
status: exit status: 0
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/async-await/future-sizes/large-arg.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2" "--target=aarch64-unknown-linux-gnu" "--check-cfg" "cfg(test,FALSE)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/async-await/future-sizes/large-arg" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/aarch64-unknown-linux-gnu/native/rust-test-helpers" "--edition=2021" "-C" "panic=abort" "-Z" "print-type-sizes" "--crate-type=lib"
--- stdout -------------------------------
print-type-size type: `{async fn body of test()}`: 3076 bytes, alignment: 1 bytes
print-type-size     discriminant: 1 bytes
print-type-size     variant `Unresumed`: 0 bytes
print-type-size     variant `Suspend0`: 3075 bytes
print-type-size         local `.__awaitee`: 3075 bytes, type: {async fn body of a<[u8; 1024]>()}
print-type-size     variant `Returned`: 0 bytes
print-type-size     variant `Panicked`: 0 bytes
print-type-size type: `std::mem::ManuallyDrop<{async fn body of a<[u8; 1024]>()}>`: 3075 bytes, alignment: 1 bytes
print-type-size     field `.value`: 3075 bytes
print-type-size type: `std::mem::MaybeUninit<{async fn body of a<[u8; 1024]>()}>`: 3075 bytes, alignment: 1 bytes
print-type-size     variant `MaybeUninit`: 3075 bytes
print-type-size         field `.uninit`: 0 bytes
print-type-size         field `.value`: 3075 bytes
print-type-size type: `{async fn body of a<[u8; 1024]>()}`: 3075 bytes, alignment: 1 bytes
print-type-size     discriminant: 1 bytes
print-type-size     variant `Unresumed`: 1024 bytes
print-type-size         upvar `.t`: 1024 bytes
print-type-size     variant `Suspend0`: 3074 bytes
print-type-size         upvar `.t`: 1024 bytes
print-type-size         local `.__awaitee`: 2050 bytes, type: {async fn body of b<[u8; 1024]>()}
print-type-size     variant `Returned`: 1024 bytes
print-type-size         upvar `.t`: 1024 bytes
print-type-size     variant `Panicked`: 1024 bytes
print-type-size         upvar `.t`: 1024 bytes
print-type-size type: `std::mem::ManuallyDrop<{async fn body of b<[u8; 1024]>()}>`: 2050 bytes, alignment: 1 bytes
print-type-size     field `.value`: 2050 bytes
print-type-size type: `std::mem::MaybeUninit<{async fn body of b<[u8; 1024]>()}>`: 2050 bytes, alignment: 1 bytes
print-type-size     variant `MaybeUninit`: 2050 bytes
print-type-size         field `.uninit`: 0 bytes
print-type-size         field `.value`: 2050 bytes
print-type-size type: `{async fn body of b<[u8; 1024]>()}`: 2050 bytes, alignment: 1 bytes
print-type-size     discriminant: 1 bytes
print-type-size     variant `Unresumed`: 1024 bytes
print-type-size         upvar `.t`: 1024 bytes
print-type-size     variant `Suspend0`: 2049 bytes
print-type-size         upvar `.t`: 1024 bytes
print-type-size         local `.__awaitee`: 1025 bytes, type: {async fn body of c<[u8; 1024]>()}
print-type-size     variant `Returned`: 1024 bytes
print-type-size         upvar `.t`: 1024 bytes
print-type-size     variant `Panicked`: 1024 bytes
print-type-size         upvar `.t`: 1024 bytes
print-type-size type: `std::mem::ManuallyDrop<{async fn body of c<[u8; 1024]>()}>`: 1025 bytes, alignment: 1 bytes
print-type-size     field `.value`: 1025 bytes
print-type-size type: `std::mem::MaybeUninit<{async fn body of c<[u8; 1024]>()}>`: 1025 bytes, alignment: 1 bytes
print-type-size     variant `MaybeUninit`: 1025 bytes
print-type-size         field `.uninit`: 0 bytes
print-type-size         field `.value`: 1025 bytes
print-type-size type: `std::task::Poll<[u8; 1024]>`: 1025 bytes, alignment: 1 bytes
print-type-size     discriminant: 1 bytes
print-type-size     variant `Ready`: 1024 bytes
print-type-size         field `.0`: 1024 bytes
print-type-size     variant `Pending`: 0 bytes
print-type-size type: `{async fn body of c<[u8; 1024]>()}`: 1025 bytes, alignment: 1 bytes
print-type-size     discriminant: 1 bytes
print-type-size     variant `Unresumed`: 1024 bytes
print-type-size         upvar `.t`: 1024 bytes
print-type-size     variant `Returned`: 1024 bytes
print-type-size         upvar `.t`: 1024 bytes
print-type-size     variant `Panicked`: 1024 bytes
print-type-size         upvar `.t`: 1024 bytes
print-type-size type: `std::task::Context<'_>`: 32 bytes, alignment: 8 bytes
print-type-size     field `.waker`: 8 bytes
print-type-size     field `._marker`: 0 bytes
print-type-size     field `.local_waker`: 8 bytes
print-type-size     field `.ext`: 16 bytes
print-type-size     field `._marker2`: 0 bytes
print-type-size type: `std::panic::Location<'_>`: 24 bytes, alignment: 8 bytes
print-type-size     field `._filename`: 0 bytes
print-type-size     field `.line`: 4 bytes
print-type-size     field `.col`: 4 bytes
print-type-size     field `.filename`: 16 bytes
print-type-size type: `core::task::wake::ExtData<'_>`: 16 bytes, alignment: 8 bytes
print-type-size     variant `Some`: 16 bytes
print-type-size         field `.0`: 16 bytes
print-type-size     variant `None`: 0 bytes
print-type-size         field `.0`: 0 bytes
print-type-size type: `std::panic::AssertUnwindSafe<core::task::wake::ExtData<'_>>`: 16 bytes, alignment: 8 bytes
print-type-size     field `.0`: 16 bytes
print-type-size type: `std::ptr::NonNull<str>`: 16 bytes, alignment: 8 bytes
print-type-size     field `.pointer`: 16 bytes
print-type-size type: `std::pin::Pin<&mut {async fn body of a<[u8; 1024]>()}>`: 8 bytes, alignment: 8 bytes
print-type-size     field `.pointer`: 8 bytes
print-type-size type: `std::pin::Pin<&mut {async fn body of b<[u8; 1024]>()}>`: 8 bytes, alignment: 8 bytes
print-type-size     field `.pointer`: 8 bytes
print-type-size type: `std::pin::Pin<&mut {async fn body of c<[u8; 1024]>()}>`: 8 bytes, alignment: 8 bytes
print-type-size     field `.pointer`: 8 bytes
print-type-size type: `std::pin::Pin<&mut {async fn body of test()}>`: 8 bytes, alignment: 8 bytes
print-type-size     field `.pointer`: 8 bytes
print-type-size type: `std::ptr::DynMetadata<dyn std::any::Any>`: 8 bytes, alignment: 8 bytes
print-type-size     field `._vtable_ptr`: 8 bytes
print-type-size     field `._phantom`: 0 bytes
print-type-size type: `std::ptr::NonNull<std::ptr::metadata::VTable>`: 8 bytes, alignment: 8 bytes
print-type-size     field `.pointer`: 8 bytes
print-type-size type: `std::task::Poll<()>`: 1 bytes, alignment: 1 bytes
print-type-size     discriminant: 1 bytes
print-type-size     variant `Ready`: 0 bytes
print-type-size         field `.0`: 0 bytes
print-type-size     variant `Pending`: 0 bytes
print-type-size type: `std::marker::PhantomData<&str>`: 0 bytes, alignment: 1 bytes
print-type-size type: `std::marker::PhantomData<*mut ()>`: 0 bytes, alignment: 1 bytes
print-type-size type: `std::marker::PhantomData<dyn std::any::Any>`: 0 bytes, alignment: 1 bytes
print-type-size type: `std::marker::PhantomData<fn(&()) -> &()>`: 0 bytes, alignment: 1 bytes
------------------------------------------
stderr: none


---- [ui] tests/ui/print_type_sizes/async.rs stdout ----
Saved the actual stdout to `/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/print_type_sizes/async/async.stdout`
diff of stdout:

18 print-type-size         field `.value`: 8192 bytes
19 print-type-size type: `std::task::Context<'_>`: 32 bytes, alignment: 8 bytes
20 print-type-size     field `.waker`: 8 bytes
+ print-type-size     field `._marker`: 0 bytes
21 print-type-size     field `.local_waker`: 8 bytes
22 print-type-size     field `.ext`: 16 bytes
- print-type-size     field `._marker`: 0 bytes
24 print-type-size     field `._marker2`: 0 bytes
25 print-type-size type: `std::panic::Location<'_>`: 24 bytes, alignment: 8 bytes
- print-type-size     field `.file_bytes_with_nul`: 16 bytes
+ print-type-size     field `._filename`: 0 bytes
27 print-type-size     field `.line`: 4 bytes
28 print-type-size     field `.col`: 4 bytes
+ print-type-size     field `.filename`: 16 bytes
29 print-type-size type: `core::task::wake::ExtData<'_>`: 16 bytes, alignment: 8 bytes
30 print-type-size     variant `Some`: 16 bytes
31 print-type-size         field `.0`: 16 bytes

33 print-type-size         field `.0`: 0 bytes
34 print-type-size type: `std::panic::AssertUnwindSafe<core::task::wake::ExtData<'_>>`: 16 bytes, alignment: 8 bytes
35 print-type-size     field `.0`: 16 bytes
+ print-type-size type: `std::ptr::NonNull<str>`: 16 bytes, alignment: 8 bytes
+ print-type-size     field `.pointer`: 16 bytes
36 print-type-size type: `std::pin::Pin<&mut {async fn body of test()}>`: 8 bytes, alignment: 8 bytes
37 print-type-size     field `.pointer`: 8 bytes
38 print-type-size type: `std::pin::Pin<&mut {async fn body of wait()}>`: 8 bytes, alignment: 8 bytes

58 print-type-size     variant `Unresumed`: 0 bytes
59 print-type-size     variant `Returned`: 0 bytes
60 print-type-size     variant `Panicked`: 0 bytes
+ print-type-size type: `std::marker::PhantomData<&str>`: 0 bytes, alignment: 1 bytes
61 print-type-size type: `std::marker::PhantomData<*mut ()>`: 0 bytes, alignment: 1 bytes
62 print-type-size type: `std::marker::PhantomData<dyn std::any::Any>`: 0 bytes, alignment: 1 bytes
63 print-type-size type: `std::marker::PhantomData<fn(&()) -> &()>`: 0 bytes, alignment: 1 bytes


The actual stdout differed from the expected stdout
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args print_type_sizes/async.rs`

error: 1 errors occurred comparing output.
status: exit status: 0
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/print_type_sizes/async.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2" "--target=aarch64-unknown-linux-gnu" "--check-cfg" "cfg(test,FALSE)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/print_type_sizes/async" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/aarch64-unknown-linux-gnu/native/rust-test-helpers" "--edition=2021" "-C" "panic=abort" "-Z" "print-type-sizes" "--crate-type" "lib"
--- stdout -------------------------------
print-type-size type: `{async fn body of test()}`: 16386 bytes, alignment: 1 bytes
print-type-size     discriminant: 1 bytes
print-type-size     variant `Unresumed`: 8192 bytes
print-type-size         upvar `.arg`: 8192 bytes
print-type-size     variant `Suspend0`: 16385 bytes
print-type-size         upvar `.arg`: 8192 bytes
print-type-size         local `.arg`: 8192 bytes
print-type-size         local `.__awaitee`: 1 bytes, type: {async fn body of wait()}
print-type-size     variant `Returned`: 8192 bytes
print-type-size         upvar `.arg`: 8192 bytes
print-type-size     variant `Panicked`: 8192 bytes
print-type-size         upvar `.arg`: 8192 bytes
print-type-size type: `std::mem::ManuallyDrop<[u8; 8192]>`: 8192 bytes, alignment: 1 bytes
print-type-size     field `.value`: 8192 bytes
print-type-size type: `std::mem::MaybeUninit<[u8; 8192]>`: 8192 bytes, alignment: 1 bytes
print-type-size     variant `MaybeUninit`: 8192 bytes
print-type-size         field `.uninit`: 0 bytes
print-type-size         field `.value`: 8192 bytes
print-type-size type: `std::task::Context<'_>`: 32 bytes, alignment: 8 bytes
print-type-size     field `.waker`: 8 bytes
print-type-size     field `._marker`: 0 bytes
print-type-size     field `.local_waker`: 8 bytes
print-type-size     field `.ext`: 16 bytes
print-type-size     field `._marker2`: 0 bytes
print-type-size type: `std::panic::Location<'_>`: 24 bytes, alignment: 8 bytes
print-type-size     field `._filename`: 0 bytes
print-type-size     field `.line`: 4 bytes
print-type-size     field `.col`: 4 bytes
print-type-size     field `.filename`: 16 bytes
print-type-size type: `core::task::wake::ExtData<'_>`: 16 bytes, alignment: 8 bytes
print-type-size     variant `Some`: 16 bytes
print-type-size         field `.0`: 16 bytes
print-type-size     variant `None`: 0 bytes
print-type-size         field `.0`: 0 bytes
print-type-size type: `std::panic::AssertUnwindSafe<core::task::wake::ExtData<'_>>`: 16 bytes, alignment: 8 bytes
print-type-size     field `.0`: 16 bytes
print-type-size type: `std::ptr::NonNull<str>`: 16 bytes, alignment: 8 bytes
print-type-size     field `.pointer`: 16 bytes
print-type-size type: `std::pin::Pin<&mut {async fn body of test()}>`: 8 bytes, alignment: 8 bytes
print-type-size     field `.pointer`: 8 bytes
print-type-size type: `std::pin::Pin<&mut {async fn body of wait()}>`: 8 bytes, alignment: 8 bytes
print-type-size     field `.pointer`: 8 bytes
print-type-size type: `std::ptr::DynMetadata<dyn std::any::Any>`: 8 bytes, alignment: 8 bytes
print-type-size     field `._vtable_ptr`: 8 bytes
print-type-size     field `._phantom`: 0 bytes
print-type-size type: `std::ptr::NonNull<std::ptr::metadata::VTable>`: 8 bytes, alignment: 8 bytes
print-type-size     field `.pointer`: 8 bytes
print-type-size type: `std::mem::ManuallyDrop<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes
print-type-size     field `.value`: 1 bytes
print-type-size type: `std::mem::MaybeUninit<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes
print-type-size     variant `MaybeUninit`: 1 bytes
print-type-size         field `.uninit`: 0 bytes
print-type-size         field `.value`: 1 bytes
print-type-size type: `std::task::Poll<()>`: 1 bytes, alignment: 1 bytes
print-type-size     discriminant: 1 bytes
print-type-size     variant `Ready`: 0 bytes
print-type-size         field `.0`: 0 bytes
print-type-size     variant `Pending`: 0 bytes
print-type-size type: `{async fn body of wait()}`: 1 bytes, alignment: 1 bytes
print-type-size     discriminant: 1 bytes
print-type-size     variant `Unresumed`: 0 bytes
print-type-size     variant `Returned`: 0 bytes
print-type-size     variant `Panicked`: 0 bytes
print-type-size type: `std::marker::PhantomData<&str>`: 0 bytes, alignment: 1 bytes
print-type-size type: `std::marker::PhantomData<*mut ()>`: 0 bytes, alignment: 1 bytes
print-type-size type: `std::marker::PhantomData<dyn std::any::Any>`: 0 bytes, alignment: 1 bytes
print-type-size type: `std::marker::PhantomData<fn(&()) -> &()>`: 0 bytes, alignment: 1 bytes
------------------------------------------
stderr: none



@oli-obk
Copy link
Contributor

oli-obk commented Jul 2, 2025

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Jul 2, 2025
@bors
Copy link
Collaborator

bors commented Jul 2, 2025

⌛ Trying commit d6e2c24 with merge 9443527...

bors added a commit that referenced this pull request Jul 2, 2025
pub async fn impl is monomorphized when func itself is monomorphized

Implentation coroutine (`func::{closure#0}`) is monomorphized, when func itself is monomorphized.

Currently, when `pub async fn foo(..)` is exported from lib and used in several dependent crates, only 'header' function is monomorphized in the defining crate. 'header' function, returning coroutine object, is monomorphized, but the coroutine's poll function (which actually implements all the logic for the function) is not. In such situation, `func::{closure#0}` will be monomorphized in every dependency.

This PR adds monomorphization for `func::{closure#0}` (coroutine poll function), when func itself is monomorphized.

Simple test with one lib async function and ten dependent crates (executable) that use the function, shows 5-7% compilation time improvement (single-threaded).
@bors
Copy link
Collaborator

bors commented Jul 2, 2025

☀️ Try build successful - checks-actions
Build commit: 9443527 (9443527f3f94abad97e5cecc88f429e299eac1f0)

@rust-timer

This comment has been minimized.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (9443527): comparison URL.

Overall result: ❌ regressions - please read the text below

Benchmarking this pull request means it may be perf-sensitive – we'll automatically label it not fit for rolling up. You can override this, but we strongly advise not to, due to possible changes in compiler perf.

Next Steps: If you can justify the regressions found in this try perf run, please do so in sufficient writing along with @rustbot label: +perf-regression-triaged. If not, please fix the regressions and do another perf run. If its results are neutral or positive, the label will be automatically removed.

@bors rollup=never
@rustbot label: -S-waiting-on-perf +perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
6.0% [0.8%, 13.6%] 6
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) - - 0

Max RSS (memory usage)

Results (primary -3.1%, secondary 2.4%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
2.4% [0.4%, 5.0%] 4
Improvements ✅
(primary)
-3.1% [-3.8%, -2.5%] 2
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) -3.1% [-3.8%, -2.5%] 2

Cycles

Results (primary 2.5%, secondary 4.9%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
2.5% [2.0%, 3.7%] 11
Regressions ❌
(secondary)
5.6% [0.9%, 14.1%] 9
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-1.2% [-1.2%, -1.2%] 1
All ❌✅ (primary) 2.5% [2.0%, 3.7%] 11

Binary size

Results (secondary 9.4%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
9.4% [1.2%, 15.8%] 5
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) - - 0

Bootstrap: 462.08s -> 462.853s (0.17%)
Artifact size: 372.26 MiB -> 372.28 MiB (0.01%)

@rustbot rustbot added perf-regression Performance regression. and removed S-waiting-on-perf Status: Waiting on a perf run to be completed. labels Jul 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
perf-regression Performance regression. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
6 participants