Skip to content

Commit 73250b9

Browse files
authored
Unrolled build for rust-lang#139080
Rollup merge of rust-lang#139080 - m-ou-se:super-let-gate, r=traviscross Experimental feature gate for `super let` This adds an experimental feature gate, `#![feature(super_let)]`, for the `super let` experiment. Tracking issue: rust-lang#139076 Liaison: ``@nikomatsakis`` ## Description There's a rough (inaccurate) description here: https://blog.m-ou.se/super-let/ In short, `super let` allows you to define something that lives long enough to be borrowed by the tail expression of the block. For example: ```rust let a = { super let b = temp(); &b }; ``` Here, `b` is extended to live as long as `a`, similar to how in `let a = &temp();`, the temporary will be extended to live as long as `a`. ## Properties During the temporary lifetimes work we did last year, we explored the properties of "super let" and concluded that the fundamental property should be that these two are always equivalent in any context: 1. `& $expr` 2. `{ super let a = & $expr; a }` And, additionally, that these are equivalent in any context when `$expr` is a temporary (aka rvalue): 1. `& $expr` 2. `{ super let a = $expr; & a }` This makes it possible to give a name to a temporary without affecting how temporary lifetimes work, such that a macro can transparently use a block in its expansion, without that having any effect on the outside. ## Implementing pin!() correctly With `super let`, we can properly implement the `pin!()` macro without hacks: ✨ ```rust pub macro pin($value:expr $(,)?) { { super let mut pinned = $value; unsafe { $crate::pin::Pin::new_unchecked(&mut pinned) } } } ``` This is important, as there is currently no way to express it without hacks in Rust 2021 and before (see [hacky definition](https://github.com/rust-lang/rust/blob/2a06022951893fe5b5384f8dbd75b4e6e3b5cee0/library/core/src/pin.rs#L1947)), and no way to express it at all in Rust 2024 (see [issue](rust-lang#138718)). ## Fixing format_args!() This will also allow us to express `format_args!()` in a way where one can assign the result to a variable, fixing a [long standing issue](rust-lang#92698): ```rust let f = format_args!("Hello {name}!"); // error today, but accepted in the future! (after separate FCP) ``` ## Experiment The precise definition of `super let`, what happens for `super let x;` (without initializer), and whether to accept `super let _ = _ else { .. }` are still open questions, to be answered by the experiment. Furthermore, once we have a more complete understanding of the feature, we might be able to come up with a better syntax. (Which could be just a different keywords, or an entirely different way of naming temporaries that doesn't involve a block and a (super) let statement.)
2 parents 946aea0 + 14e6a96 commit 73250b9

File tree

7 files changed

+39
-1
lines changed

7 files changed

+39
-1
lines changed

compiler/rustc_ast_passes/src/feature_gate.rs

+1
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
511511
gate_all!(contracts, "contracts are incomplete");
512512
gate_all!(contracts_internals, "contract internal machinery is for internal use only");
513513
gate_all!(where_clause_attrs, "attributes in `where` clause are unstable");
514+
gate_all!(super_let, "`super let` is experimental");
514515

515516
if !visitor.features.never_patterns() {
516517
if let Some(spans) = spans.get(&sym::never_patterns) {

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,8 @@ declare_features! (
629629
(unstable, strict_provenance_lints, "1.61.0", Some(130351)),
630630
/// Allows string patterns to dereference values to match them.
631631
(unstable, string_deref_patterns, "1.67.0", Some(87121)),
632+
/// Allows `super let` statements.
633+
(incomplete, super_let, "CURRENT_RUSTC_VERSION", Some(139076)),
632634
/// Allows subtrait items to shadow supertrait items.
633635
(unstable, supertrait_item_shadowing, "1.86.0", Some(89151)),
634636
/// Allows using `#[thread_local]` on `static` items.

compiler/rustc_parse/src/parser/stmt.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,20 @@ impl<'a> Parser<'a> {
7373
});
7474
}
7575

76-
let stmt = if self.token.is_keyword(kw::Let) {
76+
let stmt = if self.token.is_keyword(kw::Super) && self.is_keyword_ahead(1, &[kw::Let]) {
77+
self.collect_tokens(None, attrs, force_collect, |this, attrs| {
78+
this.expect_keyword(exp!(Super))?;
79+
this.psess.gated_spans.gate(sym::super_let, this.prev_token.span);
80+
this.expect_keyword(exp!(Let))?;
81+
let local = this.parse_local(attrs)?; // FIXME(mara): implement super let
82+
let trailing = Trailing::from(capture_semi && this.token == token::Semi);
83+
Ok((
84+
this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)),
85+
trailing,
86+
UsePreAttrPos::No,
87+
))
88+
})?
89+
} else if self.token.is_keyword(kw::Let) {
7790
self.collect_tokens(None, attrs, force_collect, |this, attrs| {
7891
this.expect_keyword(exp!(Let))?;
7992
let local = this.parse_local(attrs)?;

compiler/rustc_parse/src/parser/token_type.rs

+4
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ pub enum TokenType {
114114
KwSelfUpper,
115115
KwStatic,
116116
KwStruct,
117+
KwSuper,
117118
KwTrait,
118119
KwTry,
119120
KwType,
@@ -250,6 +251,7 @@ impl TokenType {
250251
KwSelfUpper,
251252
KwStatic,
252253
KwStruct,
254+
KwSuper,
253255
KwTrait,
254256
KwTry,
255257
KwType,
@@ -324,6 +326,7 @@ impl TokenType {
324326
TokenType::KwSelfUpper => Some(kw::SelfUpper),
325327
TokenType::KwStatic => Some(kw::Static),
326328
TokenType::KwStruct => Some(kw::Struct),
329+
TokenType::KwSuper => Some(kw::Super),
327330
TokenType::KwTrait => Some(kw::Trait),
328331
TokenType::KwTry => Some(kw::Try),
329332
TokenType::KwType => Some(kw::Type),
@@ -549,6 +552,7 @@ macro_rules! exp {
549552
(SelfUpper) => { exp!(@kw, SelfUpper, KwSelfUpper) };
550553
(Static) => { exp!(@kw, Static, KwStatic) };
551554
(Struct) => { exp!(@kw, Struct, KwStruct) };
555+
(Super) => { exp!(@kw, Super, KwSuper) };
552556
(Trait) => { exp!(@kw, Trait, KwTrait) };
553557
(Try) => { exp!(@kw, Try, KwTry) };
554558
(Type) => { exp!(@kw, Type, KwType) };

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2040,6 +2040,7 @@ symbols! {
20402040
sub_assign,
20412041
sub_with_overflow,
20422042
suggestion,
2043+
super_let,
20432044
supertrait_item_shadowing,
20442045
surface_async_drop_in_place,
20452046
sym,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fn main() {
2+
super let a = 1;
3+
//~^ ERROR `super let` is experimental
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error[E0658]: `super let` is experimental
2+
--> $DIR/feature-gate-super-let.rs:2:5
3+
|
4+
LL | super let a = 1;
5+
| ^^^^^
6+
|
7+
= note: see issue #139076 <https://github.com/rust-lang/rust/issues/139076> for more information
8+
= help: add `#![feature(super_let)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
11+
error: aborting due to 1 previous error
12+
13+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)