dtolnay / syn

Parser for Rust source code
Apache License 2.0
2.79k stars 306 forks source link

Scope when parsing delimited group content does not necessarily belong to the right Group token #1678

Closed dtolnay closed 1 month ago

dtolnay commented 1 month ago

This code looks suspect:

https://github.com/dtolnay/syn/blob/1be870bd7d3378fe52903cefe43240f348810a27/src/group.rs#L84-L85

when considered in combination with the implementation of Cursor::group and close_span_of_group.

https://github.com/dtolnay/syn/blob/1be870bd7d3378fe52903cefe43240f348810a27/src/buffer.rs#L184-L190

https://github.com/dtolnay/syn/blob/1be870bd7d3378fe52903cefe43240f348810a27/src/buffer.rs#L429-L434

In the case of input like … «∅ [ … ] … ∅» …, while parsing the bracket's contents, the content in the first snippet would be the contents of the square bracket Group token, while the scope would be the one from the None-delimited Group token. Then if an error is triggered up on reaching the end of content, it would be spanned using the None-delimited group span rather than the span of ].

// src/main.rs

macro_rules! m {
    ($e:expr) => {
        repro::repro!(x $e z);
    };
}

m!([1] as T);

fn main() {}
// src/lib.rs

use proc_macro::TokenStream;
use syn::parse::{ParseStream, Result};
use syn::{bracketed, parse_macro_input, Ident, Lit};

fn parse(input: ParseStream) -> Result<()> {
    input.parse::<Ident>()?;

    let bracketed;
    bracketed!(bracketed in input);
    bracketed.parse::<Lit>()?;
    bracketed.parse::<Lit>()?;
    unreachable!()
}

#[proc_macro]
pub fn repro(input: TokenStream) -> TokenStream {
    parse_macro_input!(input with parse);
    TokenStream::new()
}

Diagnostic currently produced by syn:

error: unexpected end of input, expected literal
 --> src/main.rs:5:25
  |
5 |         repro::repro!(x $e z);
  |                         ^^
...
9 | m!([1] as T);
  | ------------ in this macro invocation
  |
  = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)

I believe the correct diagnostic would be this:

error: unexpected end of input, expected literal
 --> src/main.rs:9:6
  |
9 | m!([1] as T);
  |      ^