mirror of https://github.com/rust-lang/rust.git
Rollup merge of #126700 - compiler-errors:fragment, r=fmease
Make edition dependent `:expr` macro fragment act like the edition-dependent `:pat` fragment does Parse the `:expr` fragment as `:expr_2021` in editions <=2021, and as `:expr` in edition 2024. This is similar to how we parse `:pat` as `:pat_param` in edition <=2018 and `:pat_with_or` in >=2021, and means we can get rid of a span dependency from `nonterminal_may_begin_with`. Specifically, this fixes a theoretical regression since the `expr_2021` macro fragment previously would allow `const {}` if the *caller* is edition 2024. This is inconsistent with the way that the `pat` macro fragment was upgraded, and also leads to surprising behavior when a macro *caller* crate upgrades to edtion 2024, since they may have parsing changes that they never asked for (with no way of opting out of it). This PR also allows using `expr_2021` in all editions. Why was this was disallowed in the first place? It's purely additive, and also it's still feature gated? r? ```@fmease``` ```@eholk``` cc ```@vincenzopalazzo``` cc #123865 Tracking: - https://github.com/rust-lang/rust/issues/123742
This commit is contained in:
commit
3bd84f18bc
|
@ -900,7 +900,11 @@ pub enum NonterminalKind {
|
||||||
PatWithOr,
|
PatWithOr,
|
||||||
Expr,
|
Expr,
|
||||||
/// Matches an expression using the rules from edition 2021 and earlier.
|
/// Matches an expression using the rules from edition 2021 and earlier.
|
||||||
Expr2021,
|
Expr2021 {
|
||||||
|
/// Keep track of whether the user used `:expr` or `:expr_2021` and we inferred it from the
|
||||||
|
/// edition of the span. This is used for diagnostics AND feature gating.
|
||||||
|
inferred: bool,
|
||||||
|
},
|
||||||
Ty,
|
Ty,
|
||||||
Ident,
|
Ident,
|
||||||
Lifetime,
|
Lifetime,
|
||||||
|
@ -929,8 +933,13 @@ impl NonterminalKind {
|
||||||
Edition::Edition2021 | Edition::Edition2024 => NonterminalKind::PatWithOr,
|
Edition::Edition2021 | Edition::Edition2024 => NonterminalKind::PatWithOr,
|
||||||
},
|
},
|
||||||
sym::pat_param => NonterminalKind::PatParam { inferred: false },
|
sym::pat_param => NonterminalKind::PatParam { inferred: false },
|
||||||
sym::expr => NonterminalKind::Expr,
|
sym::expr => match edition() {
|
||||||
sym::expr_2021 if edition().at_least_rust_2021() => NonterminalKind::Expr2021,
|
Edition::Edition2015 | Edition::Edition2018 | Edition::Edition2021 => {
|
||||||
|
NonterminalKind::Expr2021 { inferred: true }
|
||||||
|
}
|
||||||
|
Edition::Edition2024 => NonterminalKind::Expr,
|
||||||
|
},
|
||||||
|
sym::expr_2021 => NonterminalKind::Expr2021 { inferred: false },
|
||||||
sym::ty => NonterminalKind::Ty,
|
sym::ty => NonterminalKind::Ty,
|
||||||
sym::ident => NonterminalKind::Ident,
|
sym::ident => NonterminalKind::Ident,
|
||||||
sym::lifetime => NonterminalKind::Lifetime,
|
sym::lifetime => NonterminalKind::Lifetime,
|
||||||
|
@ -949,8 +958,8 @@ impl NonterminalKind {
|
||||||
NonterminalKind::Stmt => sym::stmt,
|
NonterminalKind::Stmt => sym::stmt,
|
||||||
NonterminalKind::PatParam { inferred: false } => sym::pat_param,
|
NonterminalKind::PatParam { inferred: false } => sym::pat_param,
|
||||||
NonterminalKind::PatParam { inferred: true } | NonterminalKind::PatWithOr => sym::pat,
|
NonterminalKind::PatParam { inferred: true } | NonterminalKind::PatWithOr => sym::pat,
|
||||||
NonterminalKind::Expr => sym::expr,
|
NonterminalKind::Expr | NonterminalKind::Expr2021 { inferred: true } => sym::expr,
|
||||||
NonterminalKind::Expr2021 => sym::expr_2021,
|
NonterminalKind::Expr2021 { inferred: false } => sym::expr_2021,
|
||||||
NonterminalKind::Ty => sym::ty,
|
NonterminalKind::Ty => sym::ty,
|
||||||
NonterminalKind::Ident => sym::ident,
|
NonterminalKind::Ident => sym::ident,
|
||||||
NonterminalKind::Lifetime => sym::lifetime,
|
NonterminalKind::Lifetime => sym::lifetime,
|
||||||
|
|
|
@ -1292,7 +1292,9 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
|
||||||
// maintain
|
// maintain
|
||||||
IsInFollow::Yes
|
IsInFollow::Yes
|
||||||
}
|
}
|
||||||
NonterminalKind::Stmt | NonterminalKind::Expr | NonterminalKind::Expr2021 => {
|
NonterminalKind::Stmt
|
||||||
|
| NonterminalKind::Expr
|
||||||
|
| NonterminalKind::Expr2021 { inferred: _ } => {
|
||||||
const TOKENS: &[&str] = &["`=>`", "`,`", "`;`"];
|
const TOKENS: &[&str] = &["`=>`", "`,`", "`;`"];
|
||||||
match tok {
|
match tok {
|
||||||
TokenTree::Token(token) => match token.kind {
|
TokenTree::Token(token) => match token.kind {
|
||||||
|
|
|
@ -113,7 +113,8 @@ pub(super) fn parse(
|
||||||
);
|
);
|
||||||
token::NonterminalKind::Ident
|
token::NonterminalKind::Ident
|
||||||
});
|
});
|
||||||
if kind == token::NonterminalKind::Expr2021
|
if kind
|
||||||
|
== (token::NonterminalKind::Expr2021 { inferred: false })
|
||||||
&& !features.expr_fragment_specifier_2024
|
&& !features.expr_fragment_specifier_2024
|
||||||
{
|
{
|
||||||
rustc_session::parse::feature_err(
|
rustc_session::parse::feature_err(
|
||||||
|
|
|
@ -36,7 +36,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
NonterminalKind::Expr2021 => {
|
NonterminalKind::Expr2021 { inferred: _ } => {
|
||||||
token.can_begin_expr()
|
token.can_begin_expr()
|
||||||
// This exception is here for backwards compatibility.
|
// This exception is here for backwards compatibility.
|
||||||
&& !token.is_keyword(kw::Let)
|
&& !token.is_keyword(kw::Let)
|
||||||
|
@ -47,7 +47,6 @@ impl<'a> Parser<'a> {
|
||||||
token.can_begin_expr()
|
token.can_begin_expr()
|
||||||
// This exception is here for backwards compatibility.
|
// This exception is here for backwards compatibility.
|
||||||
&& !token.is_keyword(kw::Let)
|
&& !token.is_keyword(kw::Let)
|
||||||
&& (!token.is_keyword(kw::Const) || token.span.edition().at_least_rust_2024())
|
|
||||||
}
|
}
|
||||||
NonterminalKind::Ty => token.can_begin_type(),
|
NonterminalKind::Ty => token.can_begin_type(),
|
||||||
NonterminalKind::Ident => get_macro_ident(token).is_some(),
|
NonterminalKind::Ident => get_macro_ident(token).is_some(),
|
||||||
|
@ -149,7 +148,7 @@ impl<'a> Parser<'a> {
|
||||||
})?)
|
})?)
|
||||||
}
|
}
|
||||||
|
|
||||||
NonterminalKind::Expr | NonterminalKind::Expr2021 => {
|
NonterminalKind::Expr | NonterminalKind::Expr2021 { inferred: _ } => {
|
||||||
NtExpr(self.parse_expr_force_collect()?)
|
NtExpr(self.parse_expr_force_collect()?)
|
||||||
}
|
}
|
||||||
NonterminalKind::Literal => {
|
NonterminalKind::Literal => {
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
//@ edition:2021
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! m {
|
||||||
|
($expr:expr) => {
|
||||||
|
compile_error!("did not expect an expression to be parsed");
|
||||||
|
};
|
||||||
|
(const { }) => {};
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
//@ compile-flags: --edition=2024 -Zunstable-options
|
||||||
|
//@ aux-build:expr_2021_implicit.rs
|
||||||
|
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
extern crate expr_2021_implicit;
|
||||||
|
|
||||||
|
// Makes sure that a `:expr` fragment matcher defined in a edition 2021 crate
|
||||||
|
// still parses like an `expr_2021` fragment matcher in a 2024 user crate.
|
||||||
|
expr_2021_implicit::m!(const {});
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -1,13 +0,0 @@
|
||||||
//@ compile-flags: --edition=2018
|
|
||||||
|
|
||||||
// This test ensures that expr_2021 is not allowed on pre-2021 editions
|
|
||||||
|
|
||||||
macro_rules! m {
|
|
||||||
($e:expr_2021) => { //~ ERROR: invalid fragment specifier `expr_2021`
|
|
||||||
$e
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
m!(()); //~ ERROR: no rules expected the token `(`
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
error: invalid fragment specifier `expr_2021`
|
|
||||||
--> $DIR/expr_2021_old_edition.rs:6:6
|
|
||||||
|
|
|
||||||
LL | ($e:expr_2021) => {
|
|
||||||
| ^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= help: fragment specifier `expr_2021` requires Rust 2021 or later
|
|
||||||
valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
|
|
||||||
|
|
||||||
error: no rules expected the token `(`
|
|
||||||
--> $DIR/expr_2021_old_edition.rs:12:8
|
|
||||||
|
|
|
||||||
LL | macro_rules! m {
|
|
||||||
| -------------- when calling this macro
|
|
||||||
...
|
|
||||||
LL | m!(());
|
|
||||||
| ^ no rules expected this token in macro call
|
|
||||||
|
|
|
||||||
note: while trying to match meta-variable `$e:ident`
|
|
||||||
--> $DIR/expr_2021_old_edition.rs:6:6
|
|
||||||
|
|
|
||||||
LL | ($e:expr_2021) => {
|
|
||||||
| ^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
|
||||||
|
|
Loading…
Reference in New Issue