Skip to content
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

Update expr matcher for Edition 2024 and add expr_2021 nonterminal #123865

Merged
merged 6 commits into from
May 18, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions compiler/rustc_ast/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,8 @@ pub enum NonterminalKind {
},
PatWithOr,
Expr,
/// Matches an expression using the rules from edition 2021 and earlier.
Expr2021,
Ty,
Ident,
Lifetime,
Expand Down Expand Up @@ -907,6 +909,7 @@ impl NonterminalKind {
},
sym::pat_param => NonterminalKind::PatParam { inferred: false },
sym::expr => NonterminalKind::Expr,
sym::expr_2021 if edition().at_least_rust_2021() => NonterminalKind::Expr2021,
sym::ty => NonterminalKind::Ty,
sym::ident => NonterminalKind::Ident,
sym::lifetime => NonterminalKind::Lifetime,
Expand All @@ -926,6 +929,7 @@ impl NonterminalKind {
NonterminalKind::PatParam { inferred: false } => sym::pat_param,
NonterminalKind::PatParam { inferred: true } | NonterminalKind::PatWithOr => sym::pat,
NonterminalKind::Expr => sym::expr,
NonterminalKind::Expr2021 => sym::expr_2021,
NonterminalKind::Ty => sym::ty,
NonterminalKind::Ident => sym::ident,
NonterminalKind::Lifetime => sym::lifetime,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_expand/src/mbe/macro_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1290,7 +1290,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
// maintain
IsInFollow::Yes
}
NonterminalKind::Stmt | NonterminalKind::Expr => {
NonterminalKind::Stmt | NonterminalKind::Expr | NonterminalKind::Expr2021 => {
const TOKENS: &[&str] = &["`=>`", "`,`", "`;`"];
match tok {
TokenTree::Token(token) => match token.kind {
Expand Down
71 changes: 50 additions & 21 deletions compiler/rustc_expand/src/mbe/quoted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ use rustc_span::Span;
const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
`ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \
`literal`, `path`, `meta`, `tt`, `item` and `vis`";
const VALID_FRAGMENT_NAMES_MSG_2021: &str = "valid fragment specifiers are \
`ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, \
`ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, \
`item` and `vis`";

/// Takes a `tokenstream::TokenStream` and returns a `Vec<self::TokenTree>`. Specifically, this
/// takes a generic `TokenStream`, such as is used in the rest of the compiler, and returns a
Expand Down Expand Up @@ -63,35 +67,60 @@ pub(super) fn parse(
Some(tokenstream::TokenTree::Token(token, _)) => match token.ident() {
Some((fragment, _)) => {
let span = token.span.with_lo(start_sp.lo());

let edition = || {
// FIXME(#85708) - once we properly decode a foreign
// crate's `SyntaxContext::root`, then we can replace
// this with just `span.edition()`. A
// `SyntaxContext::root()` from the current crate will
// have the edition of the current crate, and a
// `SyntaxContext::root()` from a foreign crate will
// have the edition of that crate (which we manually
// retrieve via the `edition` parameter).
if !span.from_expansion() {
edition
} else {
span.edition()
}
};
let kind =
token::NonterminalKind::from_symbol(fragment.name, || {
// FIXME(#85708) - once we properly decode a foreign
// crate's `SyntaxContext::root`, then we can replace
// this with just `span.edition()`. A
// `SyntaxContext::root()` from the current crate will
// have the edition of the current crate, and a
// `SyntaxContext::root()` from a foreign crate will
// have the edition of that crate (which we manually
// retrieve via the `edition` parameter).
if !span.from_expansion() {
edition
} else {
span.edition()
}
})
.unwrap_or_else(
|| {
token::NonterminalKind::from_symbol(fragment.name, edition)
.unwrap_or_else(|| {
let help = match fragment.name {
sym::expr_2021 => {
format!(
"fragment specifier `expr_2021` \
requires Rust 2021 or later\n\
{VALID_FRAGMENT_NAMES_MSG}"
)
}
_ if edition().at_least_rust_2021()
&& features
.expr_fragment_specifier_2024 =>
{
VALID_FRAGMENT_NAMES_MSG_2021.into()
}
_ => VALID_FRAGMENT_NAMES_MSG.into(),
};
sess.dcx().emit_err(
errors::InvalidFragmentSpecifier {
span,
fragment,
help: VALID_FRAGMENT_NAMES_MSG.into(),
help,
},
);
token::NonterminalKind::Ident
},
);
});
if kind == token::NonterminalKind::Expr2021
&& !features.expr_fragment_specifier_2024
{
rustc_session::parse::feature_err(
sess,
sym::expr_fragment_specifier_2024,
span,
"fragment specifier `expr_2021` is unstable",
)
.emit();
}
result.push(TokenTree::MetaVarDecl(span, ident, Some(kind)));
continue;
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,8 @@ declare_features! (
(unstable, exhaustive_patterns, "1.13.0", Some(51085)),
/// Allows explicit tail calls via `become` expression.
(incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
/// Uses 2024 rules for matching `expr` fragments in macros. Also enables `expr_2021` fragment.
(incomplete, expr_fragment_specifier_2024, "CURRENT_RUSTC_VERSION", Some(123742)),
/// Allows using `efiapi`, `sysv64` and `win64` as calling convention
/// for functions with varargs.
(unstable, extended_varargs_abi_support, "1.65.0", Some(100189)),
Expand Down
13 changes: 11 additions & 2 deletions compiler/rustc_parse/src/parser/nonterminal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use rustc_ast::token::{self, Delimiter, Nonterminal, Nonterminal::*, Nonterminal
use rustc_ast::HasTokens;
use rustc_ast_pretty::pprust;
use rustc_errors::PResult;
use rustc_span::edition::Edition;
use rustc_span::symbol::{kw, Ident};

use crate::errors::UnexpectedNonterminal;
Expand Down Expand Up @@ -37,13 +38,19 @@ impl<'a> Parser<'a> {
}

match kind {
NonterminalKind::Expr => {
NonterminalKind::Expr2021 => {
token.can_begin_expr()
// This exception is here for backwards compatibility.
&& !token.is_keyword(kw::Let)
// This exception is here for backwards compatibility.
&& !token.is_keyword(kw::Const)
}
NonterminalKind::Expr => {
token.can_begin_expr()
// This exception is here for backwards compatibility.
&& !token.is_keyword(kw::Let)
&& (token.span.edition() >= Edition::Edition2024 || !token.is_keyword(kw::Const))
eholk marked this conversation as resolved.
Show resolved Hide resolved
}
NonterminalKind::Ty => token.can_begin_type(),
NonterminalKind::Ident => get_macro_ident(token).is_some(),
NonterminalKind::Literal => token.can_begin_literal_maybe_minus(),
Expand Down Expand Up @@ -145,7 +152,9 @@ impl<'a> Parser<'a> {
})?)
}

NonterminalKind::Expr => NtExpr(self.parse_expr_force_collect()?),
NonterminalKind::Expr | NonterminalKind::Expr2021 => {
NtExpr(self.parse_expr_force_collect()?)
}
NonterminalKind::Literal => {
// The `:literal` matcher does not support attributes
NtLiteral(self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?)
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,8 @@ symbols! {
explicit_tail_calls,
export_name,
expr,
expr_2021,
expr_fragment_specifier_2024,
extended_key_value_attributes,
extended_varargs_abi_support,
extern_absolute_paths,
Expand Down
32 changes: 32 additions & 0 deletions tests/ui/macros/expr_2021_inline_const.edi2021.stderr
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This (intentional) behavior is a bit unfortunate but it makes sense. Well, it makes the most sense when edition-dependent keywords are involved.

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
error: no rules expected the token `const`
--> $DIR/expr_2021_inline_const.rs:21:12
|
LL | macro_rules! m2021 {
| ------------------ when calling this macro
...
LL | m2021!(const { 1 });
| ^^^^^ no rules expected this token in macro call
|
note: while trying to match meta-variable `$e:expr_2021`
--> $DIR/expr_2021_inline_const.rs:10:6
|
LL | ($e:expr_2021) => {
| ^^^^^^^^^^^^

error: no rules expected the token `const`
--> $DIR/expr_2021_inline_const.rs:22:12
|
LL | macro_rules! m2024 {
| ------------------ when calling this macro
...
LL | m2024!(const { 1 });
| ^^^^^ no rules expected this token in macro call
|
note: while trying to match meta-variable `$e:expr`
--> $DIR/expr_2021_inline_const.rs:16:6
|
LL | ($e:expr) => {
| ^^^^^^^

error: aborting due to 2 previous errors

17 changes: 17 additions & 0 deletions tests/ui/macros/expr_2021_inline_const.edi2024.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error: no rules expected the token `const`
--> $DIR/expr_2021_inline_const.rs:21:12
|
LL | macro_rules! m2021 {
| ------------------ when calling this macro
...
LL | m2021!(const { 1 });
| ^^^^^ no rules expected this token in macro call
|
note: while trying to match meta-variable `$e:expr_2021`
--> $DIR/expr_2021_inline_const.rs:10:6
|
LL | ($e:expr_2021) => {
| ^^^^^^^^^^^^

error: aborting due to 1 previous error

23 changes: 23 additions & 0 deletions tests/ui/macros/expr_2021_inline_const.rs
eholk marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//@ revisions: edi2021 edi2024
//@[edi2024]compile-flags: --edition=2024 -Z unstable-options
//@[edi2021]compile-flags: --edition=2021

// This test ensures that the inline const match only on edition 2024
#![feature(expr_fragment_specifier_2024)]
#![allow(incomplete_features)]

macro_rules! m2021 {
($e:expr_2021) => {
$e
};
}

macro_rules! m2024 {
($e:expr) => {
$e
};
}
fn main() {
m2021!(const { 1 }); //~ ERROR: no rules expected the token `const`
m2024!(const { 1 }); //[edi2021]~ ERROR: no rules expected the token `const`
}
13 changes: 13 additions & 0 deletions tests/ui/macros/expr_2021_old_edition.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//@ 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 `(`
}
26 changes: 26 additions & 0 deletions tests/ui/macros/expr_2021_old_edition.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
error: invalid fragment specifier `expr_2021`
eholk marked this conversation as resolved.
Show resolved Hide resolved
--> $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`
Comment on lines +7 to +8
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would probably split this into two separate help messages but er, doesn't matter

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think that'd be better. Let me poke around at it some more, I'm still getting the hang of the diagnostics system.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I'd rather save this for another PR so we can wrap this one up. I feel like otherwise I'll sit on this for another week or two, and I'd like to get this in as a foundation for similar edition-related changes.


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

11 changes: 11 additions & 0 deletions tests/ui/macros/feature-gate-expr_fragment_specifier_2024.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//@ compile-flags: --edition=2024 -Z unstable-options

macro_rules! m {
($e:expr_2021) => { //~ ERROR: fragment specifier `expr_2021` is unstable
$e
};
}

fn main() {
m!(());
}
13 changes: 13 additions & 0 deletions tests/ui/macros/feature-gate-expr_fragment_specifier_2024.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error[E0658]: fragment specifier `expr_2021` is unstable
--> $DIR/feature-gate-expr_fragment_specifier_2024.rs:4:6
|
LL | ($e:expr_2021) => {
| ^^^^^^^^^^^^
|
= note: see issue #123742 <https://github.com/rust-lang/rust/issues/123742> for more information
= help: add `#![feature(expr_fragment_specifier_2024)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0658`.
Loading