Skip to content

Commit 9b75a43

Browse files
committed
Auto merge of #123865 - eholk:expr_2021, r=fmease
Update `expr` matcher for Edition 2024 and add `expr_2021` nonterminal This commit adds a new nonterminal `expr_2021` in macro patterns, and `expr_fragment_specifier_2024` feature flag. This change also updates `expr` so that on Edition 2024 it will also match `const { ... }` blocks, while `expr_2021` preserves the current behavior of `expr`, matching expressions without `const` blocks. Joint work with `@vincenzopalazzo.` Issue #123742
2 parents 1a73979 + 3986ea0 commit 9b75a43

13 files changed

+204
-24
lines changed

compiler/rustc_ast/src/token.rs

+4
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,8 @@ pub enum NonterminalKind {
881881
},
882882
PatWithOr,
883883
Expr,
884+
/// Matches an expression using the rules from edition 2021 and earlier.
885+
Expr2021,
884886
Ty,
885887
Ident,
886888
Lifetime,
@@ -910,6 +912,7 @@ impl NonterminalKind {
910912
},
911913
sym::pat_param => NonterminalKind::PatParam { inferred: false },
912914
sym::expr => NonterminalKind::Expr,
915+
sym::expr_2021 if edition().at_least_rust_2021() => NonterminalKind::Expr2021,
913916
sym::ty => NonterminalKind::Ty,
914917
sym::ident => NonterminalKind::Ident,
915918
sym::lifetime => NonterminalKind::Lifetime,
@@ -929,6 +932,7 @@ impl NonterminalKind {
929932
NonterminalKind::PatParam { inferred: false } => sym::pat_param,
930933
NonterminalKind::PatParam { inferred: true } | NonterminalKind::PatWithOr => sym::pat,
931934
NonterminalKind::Expr => sym::expr,
935+
NonterminalKind::Expr2021 => sym::expr_2021,
932936
NonterminalKind::Ty => sym::ty,
933937
NonterminalKind::Ident => sym::ident,
934938
NonterminalKind::Lifetime => sym::lifetime,

compiler/rustc_expand/src/mbe/macro_rules.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1290,7 +1290,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
12901290
// maintain
12911291
IsInFollow::Yes
12921292
}
1293-
NonterminalKind::Stmt | NonterminalKind::Expr => {
1293+
NonterminalKind::Stmt | NonterminalKind::Expr | NonterminalKind::Expr2021 => {
12941294
const TOKENS: &[&str] = &["`=>`", "`,`", "`;`"];
12951295
match tok {
12961296
TokenTree::Token(token) => match token.kind {

compiler/rustc_expand/src/mbe/quoted.rs

+50-21
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ use rustc_span::Span;
1616
const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
1717
`ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \
1818
`literal`, `path`, `meta`, `tt`, `item` and `vis`";
19+
const VALID_FRAGMENT_NAMES_MSG_2021: &str = "valid fragment specifiers are \
20+
`ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, \
21+
`ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, \
22+
`item` and `vis`";
1923

2024
/// Takes a `tokenstream::TokenStream` and returns a `Vec<self::TokenTree>`. Specifically, this
2125
/// takes a generic `TokenStream`, such as is used in the rest of the compiler, and returns a
@@ -63,35 +67,60 @@ pub(super) fn parse(
6367
Some(tokenstream::TokenTree::Token(token, _)) => match token.ident() {
6468
Some((fragment, _)) => {
6569
let span = token.span.with_lo(start_sp.lo());
66-
70+
let edition = || {
71+
// FIXME(#85708) - once we properly decode a foreign
72+
// crate's `SyntaxContext::root`, then we can replace
73+
// this with just `span.edition()`. A
74+
// `SyntaxContext::root()` from the current crate will
75+
// have the edition of the current crate, and a
76+
// `SyntaxContext::root()` from a foreign crate will
77+
// have the edition of that crate (which we manually
78+
// retrieve via the `edition` parameter).
79+
if !span.from_expansion() {
80+
edition
81+
} else {
82+
span.edition()
83+
}
84+
};
6785
let kind =
68-
token::NonterminalKind::from_symbol(fragment.name, || {
69-
// FIXME(#85708) - once we properly decode a foreign
70-
// crate's `SyntaxContext::root`, then we can replace
71-
// this with just `span.edition()`. A
72-
// `SyntaxContext::root()` from the current crate will
73-
// have the edition of the current crate, and a
74-
// `SyntaxContext::root()` from a foreign crate will
75-
// have the edition of that crate (which we manually
76-
// retrieve via the `edition` parameter).
77-
if !span.from_expansion() {
78-
edition
79-
} else {
80-
span.edition()
81-
}
82-
})
83-
.unwrap_or_else(
84-
|| {
86+
token::NonterminalKind::from_symbol(fragment.name, edition)
87+
.unwrap_or_else(|| {
88+
let help = match fragment.name {
89+
sym::expr_2021 => {
90+
format!(
91+
"fragment specifier `expr_2021` \
92+
requires Rust 2021 or later\n\
93+
{VALID_FRAGMENT_NAMES_MSG}"
94+
)
95+
}
96+
_ if edition().at_least_rust_2021()
97+
&& features
98+
.expr_fragment_specifier_2024 =>
99+
{
100+
VALID_FRAGMENT_NAMES_MSG_2021.into()
101+
}
102+
_ => VALID_FRAGMENT_NAMES_MSG.into(),
103+
};
85104
sess.dcx().emit_err(
86105
errors::InvalidFragmentSpecifier {
87106
span,
88107
fragment,
89-
help: VALID_FRAGMENT_NAMES_MSG.into(),
108+
help,
90109
},
91110
);
92111
token::NonterminalKind::Ident
93-
},
94-
);
112+
});
113+
if kind == token::NonterminalKind::Expr2021
114+
&& !features.expr_fragment_specifier_2024
115+
{
116+
rustc_session::parse::feature_err(
117+
sess,
118+
sym::expr_fragment_specifier_2024,
119+
span,
120+
"fragment specifier `expr_2021` is unstable",
121+
)
122+
.emit();
123+
}
95124
result.push(TokenTree::MetaVarDecl(span, ident, Some(kind)));
96125
continue;
97126
}

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,8 @@ declare_features! (
458458
(unstable, exhaustive_patterns, "1.13.0", Some(51085)),
459459
/// Allows explicit tail calls via `become` expression.
460460
(incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
461+
/// Uses 2024 rules for matching `expr` fragments in macros. Also enables `expr_2021` fragment.
462+
(incomplete, expr_fragment_specifier_2024, "CURRENT_RUSTC_VERSION", Some(123742)),
461463
/// Allows using `efiapi`, `sysv64` and `win64` as calling convention
462464
/// for functions with varargs.
463465
(unstable, extended_varargs_abi_support, "1.65.0", Some(100189)),

compiler/rustc_parse/src/parser/nonterminal.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,19 @@ impl<'a> Parser<'a> {
3636
}
3737

3838
match kind {
39-
NonterminalKind::Expr => {
39+
NonterminalKind::Expr2021 => {
4040
token.can_begin_expr()
4141
// This exception is here for backwards compatibility.
4242
&& !token.is_keyword(kw::Let)
4343
// This exception is here for backwards compatibility.
4444
&& !token.is_keyword(kw::Const)
4545
}
46+
NonterminalKind::Expr => {
47+
token.can_begin_expr()
48+
// This exception is here for backwards compatibility.
49+
&& !token.is_keyword(kw::Let)
50+
&& (token.span.edition().at_least_rust_2024() || !token.is_keyword(kw::Const))
51+
}
4652
NonterminalKind::Ty => token.can_begin_type(),
4753
NonterminalKind::Ident => get_macro_ident(token).is_some(),
4854
NonterminalKind::Literal => token.can_begin_literal_maybe_minus(),
@@ -143,7 +149,9 @@ impl<'a> Parser<'a> {
143149
})?)
144150
}
145151

146-
NonterminalKind::Expr => NtExpr(self.parse_expr_force_collect()?),
152+
NonterminalKind::Expr | NonterminalKind::Expr2021 => {
153+
NtExpr(self.parse_expr_force_collect()?)
154+
}
147155
NonterminalKind::Literal => {
148156
// The `:literal` matcher does not support attributes
149157
NtLiteral(self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?)

compiler/rustc_span/src/symbol.rs

+2
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,8 @@ symbols! {
782782
explicit_tail_calls,
783783
export_name,
784784
expr,
785+
expr_2021,
786+
expr_fragment_specifier_2024,
785787
extended_key_value_attributes,
786788
extended_varargs_abi_support,
787789
extern_absolute_paths,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
error: no rules expected the token `const`
2+
--> $DIR/expr_2021_inline_const.rs:21:12
3+
|
4+
LL | macro_rules! m2021 {
5+
| ------------------ when calling this macro
6+
...
7+
LL | m2021!(const { 1 });
8+
| ^^^^^ no rules expected this token in macro call
9+
|
10+
note: while trying to match meta-variable `$e:expr_2021`
11+
--> $DIR/expr_2021_inline_const.rs:10:6
12+
|
13+
LL | ($e:expr_2021) => {
14+
| ^^^^^^^^^^^^
15+
16+
error: no rules expected the token `const`
17+
--> $DIR/expr_2021_inline_const.rs:22:12
18+
|
19+
LL | macro_rules! m2024 {
20+
| ------------------ when calling this macro
21+
...
22+
LL | m2024!(const { 1 });
23+
| ^^^^^ no rules expected this token in macro call
24+
|
25+
note: while trying to match meta-variable `$e:expr`
26+
--> $DIR/expr_2021_inline_const.rs:16:6
27+
|
28+
LL | ($e:expr) => {
29+
| ^^^^^^^
30+
31+
error: aborting due to 2 previous errors
32+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error: no rules expected the token `const`
2+
--> $DIR/expr_2021_inline_const.rs:21:12
3+
|
4+
LL | macro_rules! m2021 {
5+
| ------------------ when calling this macro
6+
...
7+
LL | m2021!(const { 1 });
8+
| ^^^^^ no rules expected this token in macro call
9+
|
10+
note: while trying to match meta-variable `$e:expr_2021`
11+
--> $DIR/expr_2021_inline_const.rs:10:6
12+
|
13+
LL | ($e:expr_2021) => {
14+
| ^^^^^^^^^^^^
15+
16+
error: aborting due to 1 previous error
17+
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//@ revisions: edi2021 edi2024
2+
//@[edi2024]compile-flags: --edition=2024 -Z unstable-options
3+
//@[edi2021]compile-flags: --edition=2021
4+
5+
// This test ensures that the inline const match only on edition 2024
6+
#![feature(expr_fragment_specifier_2024)]
7+
#![allow(incomplete_features)]
8+
9+
macro_rules! m2021 {
10+
($e:expr_2021) => {
11+
$e
12+
};
13+
}
14+
15+
macro_rules! m2024 {
16+
($e:expr) => {
17+
$e
18+
};
19+
}
20+
fn main() {
21+
m2021!(const { 1 }); //~ ERROR: no rules expected the token `const`
22+
m2024!(const { 1 }); //[edi2021]~ ERROR: no rules expected the token `const`
23+
}
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//@ compile-flags: --edition=2018
2+
3+
// This test ensures that expr_2021 is not allowed on pre-2021 editions
4+
5+
macro_rules! m {
6+
($e:expr_2021) => { //~ ERROR: invalid fragment specifier `expr_2021`
7+
$e
8+
};
9+
}
10+
11+
fn main() {
12+
m!(()); //~ ERROR: no rules expected the token `(`
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error: invalid fragment specifier `expr_2021`
2+
--> $DIR/expr_2021_old_edition.rs:6:6
3+
|
4+
LL | ($e:expr_2021) => {
5+
| ^^^^^^^^^^^^
6+
|
7+
= help: fragment specifier `expr_2021` requires Rust 2021 or later
8+
valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
9+
10+
error: no rules expected the token `(`
11+
--> $DIR/expr_2021_old_edition.rs:12:8
12+
|
13+
LL | macro_rules! m {
14+
| -------------- when calling this macro
15+
...
16+
LL | m!(());
17+
| ^ no rules expected this token in macro call
18+
|
19+
note: while trying to match meta-variable `$e:ident`
20+
--> $DIR/expr_2021_old_edition.rs:6:6
21+
|
22+
LL | ($e:expr_2021) => {
23+
| ^^^^^^^^^^^^
24+
25+
error: aborting due to 2 previous errors
26+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@ compile-flags: --edition=2024 -Z unstable-options
2+
3+
macro_rules! m {
4+
($e:expr_2021) => { //~ ERROR: fragment specifier `expr_2021` is unstable
5+
$e
6+
};
7+
}
8+
9+
fn main() {
10+
m!(());
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error[E0658]: fragment specifier `expr_2021` is unstable
2+
--> $DIR/feature-gate-expr_fragment_specifier_2024.rs:4:6
3+
|
4+
LL | ($e:expr_2021) => {
5+
| ^^^^^^^^^^^^
6+
|
7+
= note: see issue #123742 <https://github.com/rust-lang/rust/issues/123742> for more information
8+
= help: add `#![feature(expr_fragment_specifier_2024)]` 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)