-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Temporary lifetime extension through tuple struct and tuple variant constructors #140593
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
Conversation
r? @Nadrieril rustbot has assigned @Nadrieril. Use |
Does this count as 'I-lang-easy-decision'? I think it might be an easy decision. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add an explicit test for
let indir = Some;
let x = indir(&temp);
53924ca
to
a9544f2
Compare
This seems great to me. As you said, we already do this for struct constructors in general, except tuple struct constructors. This is a consistency improvement and a usability improvement. @rfcbot merge |
Team member @joshtriplett has proposed to merge this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns. |
☔ The latest upstream changes (presumably #142438) made this pull request unmergeable. Please resolve the merge conflicts. |
rust-lang/reference#1813 is ready. (Just waiting for this PR to be merged, so the code test passes.) |
I have removed the S-waiting-on-documentation label. I think this should be ready to merge per #140593 (comment). |
@bors r=Nadrieril |
As just a note for our possible later analysis, it's interesting to analyze, actually, why this is (conjecturally) not a new SemVer hazard. I'd mostly expect for this, pub struct W<T>(pub T); and this, mod outer {
#[allow(dead_code, hidden_glob_reexports, non_snake_case)]
fn W() {} //~ For namespace masking.
pub use self::inner::*;
mod inner {
pub struct W<T>(pub T);
}
}
pub use outer::W;
#[allow(non_snake_case)]
pub fn W<T>(x: T) -> W<T> {
W { 0: x }
} to be equivalent and indistinguishable today. If they were, then this PR would mean that you newly couldn't switch from the first to the second, e.g. to do additional work in the constructor, without a breaking change. As it is, though, it'd already be breaking, as we disallow using the tuple form in patterns when the constructor (in the value namespace) isn't in scope. So with the first form, Probably, actually, I find that a bit surprising. In pattern position, I think of the tuple struct syntax |
Temporary lifetime extension through tuple struct and tuple variant constructors This makes temporary lifetime extension work for tuple struct and tuple variant constructors, such as `Some()`. Before: ```rust let a = &temp(); // Extended let a = Some(&temp()); // Not extended :( let a = Some { 0: &temp() }; // Extended ``` After: ```rust let a = &temp(); // Extended let a = Some(&temp()); // Extended let a = Some { 0: &temp() }; // Extended ``` So, with this change, this works: ```rust let a = Some(&String::from("hello")); // New: String lifetime now extended! println!("{a:?}"); ``` Until now, we did not extend through tuple struct/variant constructors (like `Some`), because they are function calls syntactically, and we do not want to extend the String lifetime in: ```rust let a = some_function(&String::from("hello")); // String not extended! ``` However, it turns out to be very easy to distinguish between regular functions and constructors at the point where we do lifetime extension. In practice, constructors nearly always use UpperCamelCase while regular functions use lower_snake_case, so it should still be easy to for a human programmer at the call site to see whether something qualifies for lifetime extension or not. This needs a lang fcp. --- More examples of what will work after this change: ```rust let x = Person { name: "Ferris", job: Some(&Job { // `Job` now extended! title: "Chief Rustacean", organisation: "Acme Ltd.", }), }; dbg!(x); ``` ```rust let file = if use_stdout { None } else { Some(&File::create("asdf")?) // `File` now extended! }; set_logger(file); ``` ```rust use std::path::Component; let c = Component::Normal(&OsString::from(format!("test-{num}"))); // OsString now extended! assert_eq!(path.components.first().unwrap(), c); ```
Rollup of 9 pull requests Successful merges: - #140593 (Temporary lifetime extension through tuple struct and tuple variant constructors) - #141399 ([rustdoc] Give more information into extracted doctest information) - #141493 (Delegate `<SocketAddr as Debug>` to `ByteStr`) - #141811 (Unimplement unsized_locals) - #142243 (float tests: deduplicate min, max, and rounding tests) - #142464 (variadic functions: remove list of supported ABIs from error) - #142477 (Fix incorrect suggestion when calling an associated type with a type anchor) - #142484 (Remove unneeded lifetime bound from signature of BTreeSet::extract_if) - #142489 (Update the `compiler-builtins` subtree) r? `@ghost` `@rustbot` modify labels: rollup
Rollup merge of #140593 - m-ou-se:some-temp, r=Nadrieril Temporary lifetime extension through tuple struct and tuple variant constructors This makes temporary lifetime extension work for tuple struct and tuple variant constructors, such as `Some()`. Before: ```rust let a = &temp(); // Extended let a = Some(&temp()); // Not extended :( let a = Some { 0: &temp() }; // Extended ``` After: ```rust let a = &temp(); // Extended let a = Some(&temp()); // Extended let a = Some { 0: &temp() }; // Extended ``` So, with this change, this works: ```rust let a = Some(&String::from("hello")); // New: String lifetime now extended! println!("{a:?}"); ``` Until now, we did not extend through tuple struct/variant constructors (like `Some`), because they are function calls syntactically, and we do not want to extend the String lifetime in: ```rust let a = some_function(&String::from("hello")); // String not extended! ``` However, it turns out to be very easy to distinguish between regular functions and constructors at the point where we do lifetime extension. In practice, constructors nearly always use UpperCamelCase while regular functions use lower_snake_case, so it should still be easy to for a human programmer at the call site to see whether something qualifies for lifetime extension or not. This needs a lang fcp. --- More examples of what will work after this change: ```rust let x = Person { name: "Ferris", job: Some(&Job { // `Job` now extended! title: "Chief Rustacean", organisation: "Acme Ltd.", }), }; dbg!(x); ``` ```rust let file = if use_stdout { None } else { Some(&File::create("asdf")?) // `File` now extended! }; set_logger(file); ``` ```rust use std::path::Component; let c = Component::Normal(&OsString::from(format!("test-{num}"))); // OsString now extended! assert_eq!(path.components.first().unwrap(), c); ```
This makes temporary lifetime extension work for tuple struct and tuple variant constructors, such as
Some()
.Before:
After:
So, with this change, this works:
Until now, we did not extend through tuple struct/variant constructors (like
Some
), because they are function calls syntactically, and we do not want to extend the String lifetime in:However, it turns out to be very easy to distinguish between regular functions and constructors at the point where we do lifetime extension.
In practice, constructors nearly always use UpperCamelCase while regular functions use lower_snake_case, so it should still be easy to for a human programmer at the call site to see whether something qualifies for lifetime extension or not.
This needs a lang fcp.
More examples of what will work after this change: