Skip to content

no_std: binary size blowup using Result::unwrap since 1.49.0 #83925

Open
@benma

Description

@benma

Needed toolchains and targets to run the examples (nightly instead of 1.49.0 also works, 1.49.0 is the first release with the regression):

rustup toolchain add 1.48.0
rustup toolchain add 1.49.0
rustup target add thumbv7em-none-eabi --toolchain=1.48.0
rustup target add thumbv7em-none-eabi --toolchain=1.49.0

Code

[package]
name = "foo"
version = "0.1.0"
edition = "2018"

[profile.release]
opt-level = 'z'
codegen-units = 1
panic = 'abort'
lto = true
#![no_std]
#![no_main]

#[no_mangle]
pub extern "C" fn _start() -> ! {
    let e: Result<(), ()> = Err(());
    e.unwrap();

    loop {}
}

#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
    loop {}
}

Compiled with:

cargo +1.49.0 build --release --target thumbv7em-none-eabi

I expected the all functions related to panics to be optimized away and the binary size to be relatively small:

Output with toolchain 1.48.0, everything is as expected:

$ nm target/thumbv7em-none-eabi/release/foo
000200e4 T _start
$ du -b  target/thumbv7em-none-eabi/release/foo
932	target/thumbv7em-none-eabi/release/foo

The same output when compiled with 1.49.0:

$ nm target/thumbv7em-none-eabi/release/foo
00020154 T _start
00020124 t _ZN45_$LT$$LP$$RP$$u20$as$u20$core..fmt..Debug$GT$3fmt17h83e1a6586aaeb498E
00020160 t _ZN4core3fmt9Formatter3pad17h81a3156a1ec5b453E
00020134 t _ZN4core3ptr13drop_in_place17h3eafc7c4aae35b40E
000204c4 t _ZN4core6option18expect_none_failed17h37d4a90aeed60e0cE
00020138 t _ZN4core6result19Result$LT$T$C$E$GT$6unwrap17hb9125050bd4dfd28E
0002015e t _ZN4core9panicking9panic_fmt17h49c6aff3292697f2E
$ du -b  target/thumbv7em-none-eabi/release/foo
11240	target/thumbv7em-none-eabi/release/foo

The binary size blew up by ~10kb. For my embedded program, this increase is too large and for my target and I cannot run the program anymore.

When I inline the code from unwrap() and call panic!() manually, the binary size reduces against drastically, though the symbols list still has a panic_fmt entry that is not optimized away since 1.49.0 (previous toolchains produce a minimal binary with no panic-related code in the binary, as expected):

#![no_std]
#![no_main]

#[no_mangle]
pub extern "C" fn _start() -> ! {
    let e: Result<(), ()> = Err(());
    match e {
        Ok(()) => {}
        Err(err) => panic!("error: {:?}", err),
    }
    loop {}
}

#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
    loop {}
}
$ nm target/thumbv7em-none-eabi/release/foo
000200e4 T _start
000200ee t _ZN4core9panicking9panic_fmt17h49c6aff3292697f2E
$ du -b  target/thumbv7em-none-eabi/release/foo
1892	target/thumbv7em-none-eabi/release/foo

Version it worked on

Toolchains below 1.49.0

Version with regression

Toolchains since 1.49.0, including today's nightly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-no_stdArea: `#![no_std]`C-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchI-heavyIssue: Problems and improvements with respect to binary size of generated code.P-mediumMedium priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions