Skip to content

Commit

Permalink
Add expr202x macro pattern
Browse files Browse the repository at this point in the history
This makes it possible to use `inline_const` (rust-lang#76001) and `let_chains`
(rust-lang#53667) inside macros' `expr` patterns in a future edition by
bifurcating the `expr` nonterminal in a similar way to `pat2021` to
remove some backwards compatibility exceptions that disallow
`const`/`let` at the beginning of an `expr` match.

Fixes rust-lang#84155 and relaxes the backward compat restriction from rust-lang#80135 for
a future edition. This is not intended to go into 2021 as it I don't
think it's simple to write an automatic fix, and certainly not now that
it's past the soft deadline for inclusion in 2021 by a long shot.

Here is a pathological case of rust-lang#79908 that forces this to be an edition
change:

```rust
macro_rules! evil {
    ($e:expr) => {
        // or something else
        const {$e-1}
    };
    (const $b:block) => {
        const {$b}
    }
}
fn main() {
    let x = 5;
    match x {
        evil!(const { 5 }) => panic!("oh no"),
        _ => (),
    };
}
```
  • Loading branch information
lf- committed Apr 26, 2021
1 parent f8f5968 commit dbb3841
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 17 deletions.
17 changes: 14 additions & 3 deletions compiler/rustc_ast/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,13 @@ pub enum NonterminalKind {
/// edition of the span. This is used for diagnostics.
inferred: bool,
},
Expr,
/// Expr202x with exceptions for const and let not being allowed at the start
Expr2015 {
inferred: bool,
},
Expr202x {
inferred: bool,
},
Ty,
Ident,
Lifetime,
Expand Down Expand Up @@ -728,7 +734,9 @@ impl NonterminalKind {
},
sym::pat2015 => NonterminalKind::Pat2015 { inferred: false },
sym::pat2021 => NonterminalKind::Pat2021 { inferred: false },
sym::expr => NonterminalKind::Expr,
sym::expr => NonterminalKind::Expr2015 { inferred: true },
sym::expr2015 => NonterminalKind::Expr2015 { inferred: false },
sym::expr202x => NonterminalKind::Expr202x { inferred: false },
sym::ty => NonterminalKind::Ty,
sym::ident => NonterminalKind::Ident,
sym::lifetime => NonterminalKind::Lifetime,
Expand All @@ -749,7 +757,10 @@ impl NonterminalKind {
NonterminalKind::Pat2021 { inferred: false } => sym::pat2021,
NonterminalKind::Pat2015 { inferred: true }
| NonterminalKind::Pat2021 { inferred: true } => sym::pat,
NonterminalKind::Expr => sym::expr,
NonterminalKind::Expr2015 { inferred: false } => sym::expr2015,
NonterminalKind::Expr202x { inferred: false } => sym::expr202x,
NonterminalKind::Expr2015 { inferred: true }
| NonterminalKind::Expr202x { inferred: true } => sym::expr,
NonterminalKind::Ty => sym::ty,
NonterminalKind::Ident => sym::ident,
NonterminalKind::Lifetime => sym::lifetime,
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_expand/src/mbe/macro_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1095,7 +1095,9 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
// maintain
IsInFollow::Yes
}
NonterminalKind::Stmt | NonterminalKind::Expr => {
NonterminalKind::Stmt
| NonterminalKind::Expr2015 { .. }
| NonterminalKind::Expr202x { .. } => {
const TOKENS: &[&str] = &["`=>`", "`,`", "`;`"];
match tok {
TokenTree::Token(token) => match token.kind {
Expand Down
31 changes: 21 additions & 10 deletions compiler/rustc_expand/src/mbe/quoted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,27 @@ pub(super) fn parse(
let span = token.span.with_lo(start_sp.lo());

match frag.name {
sym::pat2015 | sym::pat2021 => {
if !features.edition_macro_pats {
feature_err(
sess,
sym::edition_macro_pats,
frag.span,
"`pat2015` and `pat2021` are unstable.",
)
.emit();
}
sym::pat2015 | sym::pat2021
if !features.edition_macro_pats =>
{
feature_err(
sess,
sym::edition_macro_pats,
frag.span,
"`pat2015` and `pat2021` are unstable.",
)
.emit();
}
sym::expr2015 | sym::expr202x
if !features.edition_macro_expr =>
{
feature_err(
sess,
sym::edition_macro_expr,
frag.span,
"`expr2015` and `expr202x` are unstable.",
)
.emit();
}
_ => {}
}
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ declare_features! (
/// Allows the use of `no_sanitize` attribute.
(active, no_sanitize, "1.42.0", Some(39699), None),

// Allows limiting the evaluation steps of const expressions
/// Allows limiting the evaluation steps of const expressions
(active, const_eval_limit, "1.43.0", Some(67217), None),

/// Allow negative trait implementations.
Expand Down Expand Up @@ -655,6 +655,9 @@ declare_features! (
/// Allows unsizing coercions in `const fn`.
(active, const_fn_unsize, "1.53.0", Some(64992), None),

/// `:expr2015` and `:expr202x` macro matchers.
(active, edition_macro_expr, "1.53.0", None, None),

// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_parse/src/parser/nonterminal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@ impl<'a> Parser<'a> {
}

match kind {
NonterminalKind::Expr => {
NonterminalKind::Expr2015 { .. } => {
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::Expr202x { .. } => token.can_begin_expr(),
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 @@ -128,7 +129,9 @@ impl<'a> Parser<'a> {
})?)
}

NonterminalKind::Expr => token::NtExpr(self.parse_expr_force_collect()?),
NonterminalKind::Expr2015 { .. } | NonterminalKind::Expr202x { .. } => {
token::NtExpr(self.parse_expr_force_collect()?)
}
NonterminalKind::Literal => {
// The `:literal` matcher does not support attributes
token::NtLiteral(
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ symbols! {
dylib,
dyn_metadata,
dyn_trait,
edition_macro_expr,
edition_macro_pats,
eh_catch_typeinfo,
eh_personality,
Expand Down Expand Up @@ -526,6 +527,8 @@ symbols! {
expf64,
export_name,
expr,
expr2015,
expr202x,
extended_key_value_attributes,
extern_absolute_paths,
extern_crate_item_prelude,
Expand Down
8 changes: 8 additions & 0 deletions src/test/ui/feature-gates/feature-gate-edition_macro_expr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// feature gate test for edition_macro_expr

macro_rules! mac {
($x:expr2015) => {}; //~ERROR `expr2015` and `expr202x` are unstable
($x:expr202x) => {}; //~ERROR `expr2015` and `expr202x` are unstable
}

fn main() {}
19 changes: 19 additions & 0 deletions src/test/ui/feature-gates/feature-gate-edition_macro_expr.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
error[E0658]: `expr2015` and `expr202x` are unstable.
--> $DIR/feature-gate-edition_macro_expr.rs:4:9
|
LL | ($x:expr2015) => {};
| ^^^^^^^^
|
= help: add `#![feature(edition_macro_expr)]` to the crate attributes to enable

error[E0658]: `expr2015` and `expr202x` are unstable.
--> $DIR/feature-gate-edition_macro_expr.rs:5:9
|
LL | ($x:expr202x) => {};
| ^^^^^^^^
|
= help: add `#![feature(edition_macro_expr)]` to the crate attributes to enable

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0658`.
34 changes: 34 additions & 0 deletions src/test/ui/macros/macro-expr2015-matching.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// run-pass

#![feature(edition_macro_expr)]
#![feature(inline_const)]
#![allow(incomplete_features)]

macro_rules! new_const {
($e:expr202x) => {
$e
};
(const $e:block) => {
1
};
}

macro_rules! old_const {
($e:expr2015) => {
$e
};
(const $e:block) => {
1
};
}

fn main() {
match 1 {
old_const!(const { 2 }) => (),
_ => unreachable!(),
}
match 1 {
new_const!(const { 2 }) => unreachable!(),
_ => (),
}
}

0 comments on commit dbb3841

Please sign in to comment.