Repository navigation
Closed
Description
I tried this code:
https://godbolt.org/z/bonYfhhMv
#![allow(unused_variables)]
use std::ops::Deref;
pub fn main() {
let temp_bridge_990 = env_var("FOOBAR");
if temp_bridge_990.as_ref().map(Deref::deref).ok() == Some("yes") {
panic!()
}
let env_home: Option<Result<String, ()>> = Some(Ok("foo-bar-baz".to_string()));
let env_home = (*env_home.as_ref().unwrap())
.as_ref()
.map(Deref::deref)
.ok();
if env_home == Some("") {
panic!()
}
}
#[inline(never)]
#[no_mangle]
fn env_var(s: &str) -> Result<String, VarError> {
Err(VarError::NotPresent)
}
pub enum VarError {
NotPresent,
NotUnicode(String),
}and:
#![allow(unused_variables)]
use std::ops::Deref;
pub fn main() {
if env_var("FOOBAR").as_ref().map(Deref::deref).ok() == Some("yes") {
panic!()
}
let env_home: Option<Result<String, ()>> = Some(Ok("foo-bar-baz".to_string()));
let env_home = (*env_home.as_ref().unwrap())
.as_ref()
.map(Deref::deref)
.ok();
if env_home == Some("") {
panic!()
}
}
#[inline(never)]
#[no_mangle]
fn env_var(s: &str) -> Result<String, VarError> {
Err(VarError::NotPresent)
}
pub enum VarError {
NotPresent,
NotUnicode(String),
}I expected to see this happen:
Both code snippets have similar runtime performance, since they are logically equivalent(use temporary variables ).
Instead, this happened:
When benchmarked with hyperfine (the main function loop with 10,000,000 iterations), the second version runs about 11.75% slower:
Version A: ≈0.2664s
Version B: ≈0.2977s
One possible reason is the former version uses temporary variable temp_bridge_990 and brings performance improvement.
Meta
rustc --version --verbose:
rustc 1.92.0-nightly (7c275d09e 2025-09-18)
binary: rustc
commit-hash: 7c275d09ea6b953d2cca169667184a7214bd14c7
commit-date: 2025-09-18
host: x86_64-unknown-linux-gnu
release: 1.92.0-nightly
LLVM version: 21.1.1
Version A hyperfine.json
{
"results": [
{
"command": "./target/release/issue-36023_new",
"mean": 0.26642538039999997,
"stddev": 0.00551239745835572,
"median": 0.2647992951,
"user": 0.26089066,
"system": 0.0010413800000000002,
"min": 0.2603177821,
"max": 0.27670482009999997,
"times": [
0.27670482009999997,
0.2664608811,
0.2609985961,
0.2631627861,
0.2631257741,
0.2699005981,
0.2603177821,
0.2632137181,
0.2663848721,
0.27398397609999997
],
"exit_codes": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]
}
]
}Version B hyperfine.json
{
"results": [
{
"command": "./target/release/issue-36023_involved",
"mean": 0.29774036094,
"stddev": 0.008004246309255942,
"median": 0.29310984084,
"user": 0.28805685999999997,
"system": 0.00235702,
"min": 0.28915518784,
"max": 0.31272262584,
"times": [
0.29260377084,
0.29248871584,
0.29259467284,
0.31272262584,
0.30361505184,
0.29361591084,
0.28915518784,
0.29244038184,
0.30843728484,
0.29973000684
],
"exit_codes": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]
}
]
}Metadata
Metadata
Assignees
Labels
No labels
Activity
theemathas commentedon Sep 19, 2025
The two versions of the code are not equivalent. The first version deallocates the temp_bridge_990 String at the end of main(). The second version deallocates the String as soon as the env var is checked against "yes".
guoker2077 commentedon Sep 19, 2025
The variable temp_bridge_990 is only used inside a conditional branch. What prevents rustc from optimizing its deallocation from the end of main to the end of that branch?
mati865 commentedon Sep 19, 2025
The compiler cannot decide to extend the lifetime like that. You don't want your program to suddenly double your memory usage if that temporary allocation happens to be something big.
guoker2077 commentedon Sep 19, 2025
Thanks for your explanation, I've learned a lot. :)
theemathas commentedon Sep 19, 2025
The "drop things early if possible" semantics has been considered before, and rejected. See rust-lang/rfcs#210 and https://rust-lang.github.io/rfcs/0320-nonzeroing-dynamic-drop.html.
For the current rules for when things get dropped, see https://doc.rust-lang.org/stable/reference/destructors.html.
guoker2077 commentedon Sep 19, 2025
Thank you for your sharing, I will learn it :)