Skip to content

The definition of fragment specifier is inconsistent #2265

@xmh0511

Description

@xmh0511

Consider this example:

macro_rules! test{
    ($id:ident, $e:expr)=>{
        $id.$e
    }
}
fn main() {
  let a = (1,);
  test!(a,0);
}

The compiler reports an error

error: unexpected token: `expr` metavariable
 --> src/main.rs:3:13
  |
3 |         $id.$e
  |             ^^
...
8 |   test!(a,0);
  |   ---------- in this macro invocation
  |
  = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)

IIUC, the reason can be interpreted by the syntax

Valid fragment specifiers are:

$e is defined as an expr fragment specifier, which can match LiteralExpression; however, the valid syntax of Tuple indexing expressions is defined as

TupleIndexingExpressionExpression . TUPLE_INDEX

The component following . is TUPLE_INDEX in which an Expression cannot appear. So, this is the reason for the error, which is ruled by syntax.

However, see the definition of path

path: a TypePath

This is a fixed version by #2248

A TypePath is

TypePath → ::? TypePathSegment ( :: TypePathSegment )*

Instead, a path in an expression should be

PathExpression
PathInExpression
| QualifiedPathInExpression

The path that appears in an expression doesn't expect the syntax TypePath, that is, the following code should have had a similar error as the first example:

macro_rules! test2{
    ($id:ident,$p:path)=>{
        $id = $p;
    }
}
mod S{
    pub const I:i32 = 0;
}
fn main() {
  let mut i = 0;
  test2!(i,S::I);
}

However, this code is ok.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions