Skip to content

The definition of fragment specifier is inconsistent #2265

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions