More detail when expecting expression but encountering bad macro argument
Partially address #71039.
This commit is contained in:
parent
1be1e84872
commit
4e418805da
@ -342,7 +342,7 @@ fn from_tokens<'a, I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
|
||||
let span = span.with_hi(segments.last().unwrap().ident.span.hi());
|
||||
Path { span, segments, tokens: None }
|
||||
}
|
||||
Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &**nt {
|
||||
Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &nt.0 {
|
||||
token::Nonterminal::NtMeta(item) => return item.meta(item.path.span),
|
||||
token::Nonterminal::NtPath(path) => (**path).clone(),
|
||||
_ => return None,
|
||||
|
@ -764,7 +764,10 @@ pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
|
||||
return; // Avoid visiting the span for the second time.
|
||||
}
|
||||
token::Interpolated(nt) => {
|
||||
visit_nonterminal(Lrc::make_mut(nt), vis);
|
||||
let nt = Lrc::make_mut(nt);
|
||||
let (nt, sp) = (&mut nt.0, &mut nt.1);
|
||||
vis.visit_span(sp);
|
||||
visit_nonterminal(nt, vis);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ pub fn from_token(token: &Token) -> Option<Lit> {
|
||||
Ident(name, false) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)),
|
||||
Literal(token_lit) => Some(token_lit),
|
||||
Interpolated(ref nt)
|
||||
if let NtExpr(expr) | NtLiteral(expr) = &**nt
|
||||
if let NtExpr(expr) | NtLiteral(expr) = &nt.0
|
||||
&& let ast::ExprKind::Lit(token_lit) = expr.kind =>
|
||||
{
|
||||
Some(token_lit)
|
||||
@ -314,7 +314,7 @@ pub enum TokenKind {
|
||||
/// - It prevents `Token` from implementing `Copy`.
|
||||
/// It adds complexity and likely slows things down. Please don't add new
|
||||
/// occurrences of this token kind!
|
||||
Interpolated(Lrc<Nonterminal>),
|
||||
Interpolated(Lrc<(Nonterminal, Span)>),
|
||||
|
||||
/// A doc comment token.
|
||||
/// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc)
|
||||
@ -421,7 +421,7 @@ pub fn from_ast_ident(ident: Ident) -> Self {
|
||||
/// if they keep spans or perform edition checks.
|
||||
pub fn uninterpolated_span(&self) -> Span {
|
||||
match &self.kind {
|
||||
Interpolated(nt) => nt.span(),
|
||||
Interpolated(nt) => nt.0.use_span(),
|
||||
_ => self.span,
|
||||
}
|
||||
}
|
||||
@ -464,7 +464,7 @@ pub fn can_begin_expr(&self) -> bool {
|
||||
ModSep | // global path
|
||||
Lifetime(..) | // labeled loop
|
||||
Pound => true, // expression attributes
|
||||
Interpolated(ref nt) => matches!(**nt, NtLiteral(..) |
|
||||
Interpolated(ref nt) => matches!(&nt.0, NtLiteral(..) |
|
||||
NtExpr(..) |
|
||||
NtBlock(..) |
|
||||
NtPath(..)),
|
||||
@ -488,7 +488,7 @@ pub fn can_begin_pattern(&self) -> bool {
|
||||
| DotDot | DotDotDot | DotDotEq // ranges
|
||||
| Lt | BinOp(Shl) // associated path
|
||||
| ModSep => true, // global path
|
||||
Interpolated(ref nt) => matches!(**nt, NtLiteral(..) |
|
||||
Interpolated(ref nt) => matches!(&nt.0, NtLiteral(..) |
|
||||
NtPat(..) |
|
||||
NtBlock(..) |
|
||||
NtPath(..)),
|
||||
@ -511,7 +511,7 @@ pub fn can_begin_type(&self) -> bool {
|
||||
Lifetime(..) | // lifetime bound in trait object
|
||||
Lt | BinOp(Shl) | // associated path
|
||||
ModSep => true, // global path
|
||||
Interpolated(ref nt) => matches!(**nt, NtTy(..) | NtPath(..)),
|
||||
Interpolated(ref nt) => matches!(&nt.0, NtTy(..) | NtPath(..)),
|
||||
// For anonymous structs or unions, which only appear in specific positions
|
||||
// (type of struct fields or union fields), we don't consider them as regular types
|
||||
_ => false,
|
||||
@ -522,7 +522,7 @@ pub fn can_begin_type(&self) -> bool {
|
||||
pub fn can_begin_const_arg(&self) -> bool {
|
||||
match self.kind {
|
||||
OpenDelim(Delimiter::Brace) => true,
|
||||
Interpolated(ref nt) => matches!(**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
|
||||
Interpolated(ref nt) => matches!(&nt.0, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
|
||||
_ => self.can_begin_literal_maybe_minus(),
|
||||
}
|
||||
}
|
||||
@ -576,7 +576,7 @@ pub fn can_begin_literal_maybe_minus(&self) -> bool {
|
||||
match self.uninterpolate().kind {
|
||||
Literal(..) | BinOp(Minus) => true,
|
||||
Ident(name, false) if name.is_bool_lit() => true,
|
||||
Interpolated(ref nt) => match &**nt {
|
||||
Interpolated(ref nt) => match &nt.0 {
|
||||
NtLiteral(_) => true,
|
||||
NtExpr(e) => match &e.kind {
|
||||
ast::ExprKind::Lit(_) => true,
|
||||
@ -597,9 +597,9 @@ pub fn can_begin_literal_maybe_minus(&self) -> bool {
|
||||
/// otherwise returns the original token.
|
||||
pub fn uninterpolate(&self) -> Cow<'_, Token> {
|
||||
match &self.kind {
|
||||
Interpolated(nt) => match **nt {
|
||||
Interpolated(nt) => match &nt.0 {
|
||||
NtIdent(ident, is_raw) => {
|
||||
Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span))
|
||||
Cow::Owned(Token::new(Ident(ident.name, *is_raw), ident.span))
|
||||
}
|
||||
NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
|
||||
_ => Cow::Borrowed(self),
|
||||
@ -614,8 +614,8 @@ pub fn ident(&self) -> Option<(Ident, /* is_raw */ bool)> {
|
||||
// We avoid using `Token::uninterpolate` here because it's slow.
|
||||
match &self.kind {
|
||||
&Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
|
||||
Interpolated(nt) => match **nt {
|
||||
NtIdent(ident, is_raw) => Some((ident, is_raw)),
|
||||
Interpolated(nt) => match &nt.0 {
|
||||
NtIdent(ident, is_raw) => Some((*ident, *is_raw)),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
@ -628,8 +628,8 @@ pub fn lifetime(&self) -> Option<Ident> {
|
||||
// We avoid using `Token::uninterpolate` here because it's slow.
|
||||
match &self.kind {
|
||||
&Lifetime(name) => Some(Ident::new(name, self.span)),
|
||||
Interpolated(nt) => match **nt {
|
||||
NtLifetime(ident) => Some(ident),
|
||||
Interpolated(nt) => match &nt.0 {
|
||||
NtLifetime(ident) => Some(*ident),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
@ -655,7 +655,7 @@ pub fn is_ident_named(&self, name: Symbol) -> bool {
|
||||
/// Returns `true` if the token is an interpolated path.
|
||||
fn is_path(&self) -> bool {
|
||||
if let Interpolated(nt) = &self.kind
|
||||
&& let NtPath(..) = **nt
|
||||
&& let NtPath(..) = &nt.0
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -668,7 +668,7 @@ fn is_path(&self) -> bool {
|
||||
/// (which happens while parsing the result of macro expansion)?
|
||||
pub fn is_whole_expr(&self) -> bool {
|
||||
if let Interpolated(nt) = &self.kind
|
||||
&& let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = **nt
|
||||
&& let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = &nt.0
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -679,7 +679,7 @@ pub fn is_whole_expr(&self) -> bool {
|
||||
/// Is the token an interpolated block (`$b:block`)?
|
||||
pub fn is_whole_block(&self) -> bool {
|
||||
if let Interpolated(nt) = &self.kind
|
||||
&& let NtBlock(..) = **nt
|
||||
&& let NtBlock(..) = &nt.0
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -927,7 +927,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
}
|
||||
|
||||
impl Nonterminal {
|
||||
pub fn span(&self) -> Span {
|
||||
pub fn use_span(&self) -> Span {
|
||||
match self {
|
||||
NtItem(item) => item.span,
|
||||
NtBlock(block) => block.span,
|
||||
@ -941,6 +941,23 @@ pub fn span(&self) -> Span {
|
||||
NtVis(vis) => vis.span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn descr(&self) -> &'static str {
|
||||
match self {
|
||||
NtItem(..) => "item",
|
||||
NtBlock(..) => "block",
|
||||
NtStmt(..) => "statement",
|
||||
NtPat(..) => "pattern",
|
||||
NtExpr(..) => "expression",
|
||||
NtLiteral(..) => "literal",
|
||||
NtTy(..) => "type",
|
||||
NtIdent(..) => "identifier",
|
||||
NtLifetime(..) => "lifetime",
|
||||
NtMeta(..) => "attribute",
|
||||
NtPath(..) => "path",
|
||||
NtVis(..) => "visibility",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Nonterminal {
|
||||
|
@ -477,13 +477,13 @@ pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {
|
||||
|
||||
fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree {
|
||||
match &token.kind {
|
||||
token::Interpolated(nt) if let token::NtIdent(ident, is_raw) = **nt => {
|
||||
token::Interpolated(nt) if let token::NtIdent(ident, is_raw) = nt.0 => {
|
||||
TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing)
|
||||
}
|
||||
token::Interpolated(nt) => TokenTree::Delimited(
|
||||
DelimSpan::from_single(token.span),
|
||||
Delimiter::Invisible,
|
||||
TokenStream::from_nonterminal_ast(nt).flattened(),
|
||||
TokenStream::from_nonterminal_ast(&nt.0).flattened(),
|
||||
),
|
||||
_ => TokenTree::Token(token.clone(), spacing),
|
||||
}
|
||||
|
@ -825,7 +825,7 @@ fn token_kind_to_string_ext(
|
||||
}
|
||||
token::Eof => "<eof>".into(),
|
||||
|
||||
token::Interpolated(ref nt) => self.nonterminal_to_string(nt).into(),
|
||||
token::Interpolated(ref nt) => self.nonterminal_to_string(&nt.0).into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,6 +67,12 @@ pub(super) fn failed_to_match_macro<'cx>(
|
||||
&& (matches!(expected_token.kind, TokenKind::Interpolated(_))
|
||||
|| matches!(token.kind, TokenKind::Interpolated(_)))
|
||||
{
|
||||
if let TokenKind::Interpolated(node) = &expected_token.kind {
|
||||
err.span_label(node.1, "");
|
||||
}
|
||||
if let TokenKind::Interpolated(node) = &token.kind {
|
||||
err.span_label(node.1, "");
|
||||
}
|
||||
err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
|
||||
err.note("see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information");
|
||||
|
||||
|
@ -397,7 +397,7 @@ pub(crate) enum NamedMatch {
|
||||
MatchedTokenTree(rustc_ast::tokenstream::TokenTree),
|
||||
|
||||
// A metavar match of any type other than `tt`.
|
||||
MatchedNonterminal(Lrc<Nonterminal>),
|
||||
MatchedNonterminal(Lrc<(Nonterminal, rustc_span::Span)>),
|
||||
}
|
||||
|
||||
/// Performs a token equality check, ignoring syntax context (that is, an unhygienic comparison)
|
||||
@ -692,7 +692,7 @@ pub(super) fn parse_tt<'matcher, T: Tracker<'matcher>>(
|
||||
Ok(nt) => nt,
|
||||
};
|
||||
let m = match nt {
|
||||
ParseNtResult::Nt(nt) => MatchedNonterminal(Lrc::new(nt)),
|
||||
ParseNtResult::Nt(nt) => MatchedNonterminal(Lrc::new((nt, span))),
|
||||
ParseNtResult::Tt(tt) => MatchedTokenTree(tt),
|
||||
};
|
||||
mp.push_match(next_metavar, seq_depth, m);
|
||||
|
@ -126,7 +126,7 @@ fn expand(
|
||||
Annotatable::Stmt(stmt) => token::NtStmt(stmt),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
TokenStream::token_alone(token::Interpolated(Lrc::new(nt)), DUMMY_SP)
|
||||
TokenStream::token_alone(token::Interpolated(Lrc::new((nt, span))), DUMMY_SP)
|
||||
} else {
|
||||
item.to_tokens()
|
||||
};
|
||||
|
@ -226,18 +226,23 @@ fn from_internal((stream, rustc): (TokenStream, &mut Rustc<'_, '_>)) -> Self {
|
||||
}));
|
||||
}
|
||||
|
||||
Interpolated(nt) if let NtIdent(ident, is_raw) = *nt => trees
|
||||
.push(TokenTree::Ident(Ident { sym: ident.name, is_raw, span: ident.span })),
|
||||
Interpolated(ref nt) if let NtIdent(ident, is_raw) = &nt.0 => {
|
||||
trees.push(TokenTree::Ident(Ident {
|
||||
sym: ident.name,
|
||||
is_raw: *is_raw,
|
||||
span: ident.span,
|
||||
}))
|
||||
}
|
||||
|
||||
Interpolated(nt) => {
|
||||
let stream = TokenStream::from_nonterminal_ast(&nt);
|
||||
let stream = TokenStream::from_nonterminal_ast(&nt.0);
|
||||
// A hack used to pass AST fragments to attribute and derive
|
||||
// macros as a single nonterminal token instead of a token
|
||||
// stream. Such token needs to be "unwrapped" and not
|
||||
// represented as a delimited group.
|
||||
// FIXME: It needs to be removed, but there are some
|
||||
// compatibility issues (see #73345).
|
||||
if crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.sess()) {
|
||||
if crate::base::nt_pretty_printing_compatibility_hack(&nt.0, rustc.sess()) {
|
||||
trees.extend(Self::from_internal((stream, rustc)));
|
||||
} else {
|
||||
trees.push(TokenTree::Group(Group {
|
||||
|
@ -249,7 +249,7 @@ pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerA
|
||||
/// The delimiters or `=` are still put into the resulting token stream.
|
||||
pub fn parse_attr_item(&mut self, capture_tokens: bool) -> PResult<'a, ast::AttrItem> {
|
||||
let item = match &self.token.kind {
|
||||
token::Interpolated(nt) => match &**nt {
|
||||
token::Interpolated(nt) => match &nt.0 {
|
||||
Nonterminal::NtMeta(item) => Some(item.clone().into_inner()),
|
||||
_ => None,
|
||||
},
|
||||
@ -369,7 +369,7 @@ pub(crate) fn parse_meta_seq_top(&mut self) -> PResult<'a, ThinVec<ast::NestedMe
|
||||
/// ```
|
||||
pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
|
||||
let nt_meta = match &self.token.kind {
|
||||
token::Interpolated(nt) => match &**nt {
|
||||
token::Interpolated(nt) => match &nt.0 {
|
||||
token::NtMeta(e) => Some(e.clone()),
|
||||
_ => None,
|
||||
},
|
||||
|
@ -24,11 +24,12 @@
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Delimiter, Lit, LitKind, TokenKind};
|
||||
use rustc_ast::tokenstream::AttrTokenTree;
|
||||
use rustc_ast::util::parser::AssocOp;
|
||||
use rustc_ast::{
|
||||
AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingAnnotation, Block,
|
||||
BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat, PatKind,
|
||||
Path, PathSegment, QSelf, Ty, TyKind,
|
||||
BlockCheckMode, Expr, ExprKind, GenericArg, Generics, HasTokens, Item, ItemKind, Param, Pat,
|
||||
PatKind, Path, PathSegment, QSelf, Ty, TyKind,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
@ -2252,6 +2253,59 @@ pub(super) fn expected_expression_found(&self) -> DiagnosticBuilder<'a, ErrorGua
|
||||
err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
|
||||
}
|
||||
err.span_label(span, "expected expression");
|
||||
|
||||
// Walk the chain of macro expansions for the current token to point at how the original
|
||||
// code was interpreted. This helps the user realize when a macro argument of one type is
|
||||
// later reinterpreted as a different type, like `$x:expr` being reinterpreted as `$x:pat`
|
||||
// in a subsequent macro invocation (#71039).
|
||||
let mut tok = self.token.clone();
|
||||
let mut labels = vec![];
|
||||
while let TokenKind::Interpolated(node) = &tok.kind {
|
||||
let tokens = node.0.tokens();
|
||||
labels.push(node.clone());
|
||||
if let Some(tokens) = tokens
|
||||
&& let tokens = tokens.to_attr_token_stream()
|
||||
&& let tokens = tokens.0.deref()
|
||||
&& let [AttrTokenTree::Token(token, _)] = &tokens[..]
|
||||
{
|
||||
tok = token.clone();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let mut iter = labels.into_iter().peekable();
|
||||
let mut show_link = false;
|
||||
while let Some(node) = iter.next() {
|
||||
let descr = node.0.descr();
|
||||
if let Some(next) = iter.peek() {
|
||||
let next_descr = next.0.descr();
|
||||
if next_descr != descr {
|
||||
err.span_label(next.1, format!("this macro fragment matcher is {next_descr}"));
|
||||
err.span_label(node.1, format!("this macro fragment matcher is {descr}"));
|
||||
err.span_label(
|
||||
next.0.use_span(),
|
||||
format!("this is expected to be {next_descr}"),
|
||||
);
|
||||
err.span_label(
|
||||
node.0.use_span(),
|
||||
format!(
|
||||
"this is interpreted as {}, but it is expected to be {}",
|
||||
next_descr, descr,
|
||||
),
|
||||
);
|
||||
show_link = true;
|
||||
} else {
|
||||
err.span_label(node.1, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
if show_link {
|
||||
err.note(
|
||||
"when forwarding a matched fragment to another macro-by-example, matchers in the \
|
||||
second macro will see an opaque AST of the fragment type, not the underlying \
|
||||
tokens",
|
||||
);
|
||||
}
|
||||
err
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@
|
||||
macro_rules! maybe_whole_expr {
|
||||
($p:expr) => {
|
||||
if let token::Interpolated(nt) = &$p.token.kind {
|
||||
match &**nt {
|
||||
match &nt.0 {
|
||||
token::NtExpr(e) | token::NtLiteral(e) => {
|
||||
let e = e.clone();
|
||||
$p.bump();
|
||||
@ -1952,7 +1952,7 @@ fn handle_missing_lit<L>(
|
||||
mk_lit_char: impl FnOnce(Symbol, Span) -> L,
|
||||
) -> PResult<'a, L> {
|
||||
if let token::Interpolated(nt) = &self.token.kind
|
||||
&& let token::NtExpr(e) | token::NtLiteral(e) = &**nt
|
||||
&& let token::NtExpr(e) | token::NtLiteral(e) = &nt.0
|
||||
&& matches!(e.kind, ExprKind::Err)
|
||||
{
|
||||
let mut err = errors::InvalidInterpolatedExpression { span: self.token.span }
|
||||
|
@ -123,7 +123,7 @@ pub(super) fn parse_item_common(
|
||||
// Don't use `maybe_whole` so that we have precise control
|
||||
// over when we bump the parser
|
||||
if let token::Interpolated(nt) = &self.token.kind
|
||||
&& let token::NtItem(item) = &**nt
|
||||
&& let token::NtItem(item) = &nt.0
|
||||
{
|
||||
let mut item = item.clone();
|
||||
self.bump();
|
||||
@ -2750,7 +2750,7 @@ fn parse_self_param(&mut self) -> PResult<'a, Option<Param>> {
|
||||
|
||||
fn is_named_param(&self) -> bool {
|
||||
let offset = match &self.token.kind {
|
||||
token::Interpolated(nt) => match **nt {
|
||||
token::Interpolated(nt) => match &nt.0 {
|
||||
token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
|
||||
_ => 0,
|
||||
},
|
||||
|
@ -93,7 +93,7 @@ pub enum TrailingToken {
|
||||
macro_rules! maybe_whole {
|
||||
($p:expr, $constructor:ident, |$x:ident| $e:expr) => {
|
||||
if let token::Interpolated(nt) = &$p.token.kind {
|
||||
if let token::$constructor(x) = &**nt {
|
||||
if let token::$constructor(x) = &nt.0 {
|
||||
let $x = x.clone();
|
||||
$p.bump();
|
||||
return Ok($e);
|
||||
@ -110,7 +110,7 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath {
|
||||
&& $self.may_recover()
|
||||
&& $self.look_ahead(1, |t| t == &token::ModSep)
|
||||
&& let token::Interpolated(nt) = &$self.token.kind
|
||||
&& let token::NtTy(ty) = &**nt
|
||||
&& let token::NtTy(ty) = &nt.0
|
||||
{
|
||||
let ty = ty.clone();
|
||||
$self.bump();
|
||||
@ -367,12 +367,14 @@ pub fn from_token(token: &Token) -> Option<Self> {
|
||||
pub(super) fn token_descr(token: &Token) -> String {
|
||||
let name = pprust::token_to_string(token).to_string();
|
||||
|
||||
let kind = TokenDescription::from_token(token).map(|kind| match kind {
|
||||
TokenDescription::ReservedIdentifier => "reserved identifier",
|
||||
TokenDescription::Keyword => "keyword",
|
||||
TokenDescription::ReservedKeyword => "reserved keyword",
|
||||
TokenDescription::DocComment => "doc comment",
|
||||
});
|
||||
let kind = match (TokenDescription::from_token(token), &token.kind) {
|
||||
(Some(TokenDescription::ReservedIdentifier), _) => Some("reserved identifier"),
|
||||
(Some(TokenDescription::Keyword), _) => Some("keyword"),
|
||||
(Some(TokenDescription::ReservedKeyword), _) => Some("reserved keyword"),
|
||||
(Some(TokenDescription::DocComment), _) => Some("doc comment"),
|
||||
(None, TokenKind::Interpolated(node)) => Some(node.0.descr()),
|
||||
(None, _) => None,
|
||||
};
|
||||
|
||||
if let Some(kind) = kind { format!("{kind} `{name}`") } else { format!("`{name}`") }
|
||||
}
|
||||
@ -662,7 +664,7 @@ fn check_const_closure(&self) -> bool {
|
||||
fn check_inline_const(&self, dist: usize) -> bool {
|
||||
self.is_keyword_ahead(dist, &[kw::Const])
|
||||
&& self.look_ahead(dist + 1, |t| match &t.kind {
|
||||
token::Interpolated(nt) => matches!(**nt, token::NtBlock(..)),
|
||||
token::Interpolated(nt) => matches!(&nt.0, token::NtBlock(..)),
|
||||
token::OpenDelim(Delimiter::Brace) => true,
|
||||
_ => false,
|
||||
})
|
||||
|
@ -50,12 +50,12 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
|
||||
NonterminalKind::Literal => token.can_begin_literal_maybe_minus(),
|
||||
NonterminalKind::Vis => match token.kind {
|
||||
// The follow-set of :vis + "priv" keyword + interpolated
|
||||
token::Comma | token::Ident(..) | token::Interpolated(..) => true,
|
||||
token::Comma | token::Ident(..) | token::Interpolated(_) => true,
|
||||
_ => token.can_begin_type(),
|
||||
},
|
||||
NonterminalKind::Block => match &token.kind {
|
||||
token::OpenDelim(Delimiter::Brace) => true,
|
||||
token::Interpolated(nt) => match **nt {
|
||||
token::Interpolated(nt) => match &nt.0 {
|
||||
NtBlock(_) | NtLifetime(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true,
|
||||
NtItem(_) | NtPat(_) | NtTy(_) | NtIdent(..) | NtMeta(_) | NtPath(_)
|
||||
| NtVis(_) => false,
|
||||
@ -64,7 +64,7 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
|
||||
},
|
||||
NonterminalKind::Path | NonterminalKind::Meta => match &token.kind {
|
||||
token::ModSep | token::Ident(..) => true,
|
||||
token::Interpolated(nt) => may_be_ident(nt),
|
||||
token::Interpolated(nt) => may_be_ident(&nt.0),
|
||||
_ => false,
|
||||
},
|
||||
NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => {
|
||||
@ -75,7 +75,7 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
|
||||
token::BinOp(token::And) | // reference
|
||||
token::BinOp(token::Minus) | // negative literal
|
||||
token::AndAnd | // double reference
|
||||
token::Literal(..) | // literal
|
||||
token::Literal(_) | // literal
|
||||
token::DotDot | // range pattern (future compat)
|
||||
token::DotDotDot | // range pattern (future compat)
|
||||
token::ModSep | // path
|
||||
@ -83,14 +83,14 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
|
||||
token::BinOp(token::Shl) => true, // path (double UFCS)
|
||||
// leading vert `|` or-pattern
|
||||
token::BinOp(token::Or) => matches!(kind, NonterminalKind::PatWithOr),
|
||||
token::Interpolated(nt) => may_be_ident(nt),
|
||||
token::Interpolated(nt) => may_be_ident(&nt.0),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
NonterminalKind::Lifetime => match &token.kind {
|
||||
token::Lifetime(_) => true,
|
||||
token::Interpolated(nt) => {
|
||||
matches!(**nt, NtLifetime(_))
|
||||
matches!(&nt.0, NtLifetime(_))
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
@ -191,7 +191,7 @@ pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, ParseN
|
||||
panic!(
|
||||
"Missing tokens for nt {:?} at {:?}: {:?}",
|
||||
nt,
|
||||
nt.span(),
|
||||
nt.use_span(),
|
||||
pprust::nonterminal_to_string(&nt)
|
||||
);
|
||||
}
|
||||
|
@ -592,7 +592,7 @@ fn parse_pat_ident_mut(&mut self, syntax_loc: Option<PatternLocation>) -> PResul
|
||||
|
||||
// Make sure we don't allow e.g. `let mut $p;` where `$p:pat`.
|
||||
if let token::Interpolated(nt) = &self.token.kind {
|
||||
if let token::NtPat(_) = **nt {
|
||||
if let token::NtPat(..) = &nt.0 {
|
||||
self.expected_ident_found_err().emit();
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ pub(super) fn parse_path_inner(
|
||||
});
|
||||
|
||||
if let token::Interpolated(nt) = &self.token.kind {
|
||||
if let token::NtTy(ty) = &**nt {
|
||||
if let token::NtTy(ty) = &nt.0 {
|
||||
if let ast::TyKind::Path(None, path) = &ty.kind {
|
||||
let path = path.clone();
|
||||
self.bump();
|
||||
|
@ -53,7 +53,7 @@ pub fn parse_stmt_without_recovery(
|
||||
// Don't use `maybe_whole` so that we have precise control
|
||||
// over when we bump the parser
|
||||
if let token::Interpolated(nt) = &self.token.kind
|
||||
&& let token::NtStmt(stmt) = &**nt
|
||||
&& let token::NtStmt(stmt) = &nt.0
|
||||
{
|
||||
let mut stmt = stmt.clone();
|
||||
self.bump();
|
||||
|
@ -1,6 +1,6 @@
|
||||
macro_rules! get_opt {
|
||||
($tgt:expr, $field:ident) => {
|
||||
if $tgt.has_$field() {} //~ ERROR expected `{`, found `foo`
|
||||
if $tgt.has_$field() {} //~ ERROR expected `{`, found identifier `foo`
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: expected `{`, found `foo`
|
||||
error: expected `{`, found identifier `foo`
|
||||
--> $DIR/issue-39848.rs:3:21
|
||||
|
|
||||
LL | if $tgt.has_$field() {}
|
||||
|
@ -1,6 +1,8 @@
|
||||
error: no rules expected the token `enum E {}`
|
||||
--> $DIR/nonterminal-matching.rs:19:10
|
||||
|
|
||||
LL | macro complex_nonterminal($nt_item: item) {
|
||||
| --------------
|
||||
LL | macro n(a $nt_item b) {
|
||||
| --------------------- when calling this macro
|
||||
...
|
||||
|
@ -9,7 +9,7 @@ pub enum TokenKind {
|
||||
}
|
||||
};
|
||||
}
|
||||
//~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `(String)`
|
||||
//~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found type `(String)`
|
||||
//~| ERROR macro expansion ignores token `(String)` and any following
|
||||
|
||||
values!(STRING(1) as (String) => cfg(test),);
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: expected one of `(`, `,`, `=`, `{`, or `}`, found `(String)`
|
||||
error: expected one of `(`, `,`, `=`, `{`, or `}`, found type `(String)`
|
||||
--> $DIR/syntax-error-recovery.rs:7:26
|
||||
|
|
||||
LL | $token $($inner)? = $value,
|
||||
|
@ -41,3 +41,14 @@ fn use_bang_macro_as_attr() {}
|
||||
|
||||
#[derive(Debug)] //~ ERROR `derive` may only be applied to `struct`s
|
||||
fn use_derive_macro_as_attr() {}
|
||||
|
||||
macro_rules! test {
|
||||
(let $p:pat = $e:expr) => {test!(($p,$e))};
|
||||
// this should be expr
|
||||
// vvv
|
||||
(($p:pat, $e:pat)) => {let $p = $e;}; //~ ERROR expected expression, found pattern `1 + 1`
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
test!(let x = 1+1);
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ LL | my_recursive_macro!();
|
||||
= note: expanding `my_recursive_macro! { }`
|
||||
= note: to `my_recursive_macro! () ;`
|
||||
|
||||
error: expected expression, found `A { a: a, b: 0, c: _, .. }`
|
||||
error: expected expression, found pattern `A { a: a, b: 0, c: _, .. }`
|
||||
--> $DIR/trace_faulty_macros.rs:16:9
|
||||
|
|
||||
LL | $a
|
||||
@ -69,6 +69,28 @@ LL | #[derive(Debug)]
|
||||
LL | fn use_derive_macro_as_attr() {}
|
||||
| -------------------------------- not a `struct`, `enum` or `union`
|
||||
|
||||
error: expected expression, found pattern `1 + 1`
|
||||
--> $DIR/trace_faulty_macros.rs:49:37
|
||||
|
|
||||
LL | (let $p:pat = $e:expr) => {test!(($p,$e))};
|
||||
| ------- -- this is interpreted as expression, but it is expected to be pattern
|
||||
| |
|
||||
| this macro fragment matcher is expression
|
||||
...
|
||||
LL | (($p:pat, $e:pat)) => {let $p = $e;};
|
||||
| ------ ^^ expected expression
|
||||
| |
|
||||
| this macro fragment matcher is pattern
|
||||
...
|
||||
LL | test!(let x = 1+1);
|
||||
| ------------------
|
||||
| | |
|
||||
| | this is expected to be expression
|
||||
| in this macro invocation
|
||||
|
|
||||
= note: when forwarding a matched fragment to another macro-by-example, matchers in the second macro will see an opaque AST of the fragment type, not the underlying tokens
|
||||
= note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
note: trace_macro
|
||||
--> $DIR/trace_faulty_macros.rs:36:13
|
||||
|
|
||||
@ -80,6 +102,17 @@ LL | let a = pat_macro!();
|
||||
= note: expanding `pat_macro! { A { a : a, b : 0, c : _, .. } }`
|
||||
= note: to `A { a: a, b: 0, c: _, .. }`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
note: trace_macro
|
||||
--> $DIR/trace_faulty_macros.rs:53:5
|
||||
|
|
||||
LL | test!(let x = 1+1);
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: expanding `test! { let x = 1 + 1 }`
|
||||
= note: to `test! ((x, 1 + 1))`
|
||||
= note: expanding `test! { (x, 1 + 1) }`
|
||||
= note: to `let x = 1 + 1 ;`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0774`.
|
||||
|
@ -6,9 +6,9 @@ macro_rules! generate_field_accesses {
|
||||
|
||||
s.$a; // OK
|
||||
{ s.$b; } //~ ERROR unexpected token: `1.1`
|
||||
//~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `1.1`
|
||||
//~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found literal `1.1`
|
||||
{ s.$c; } //~ ERROR unexpected token: `1.1`
|
||||
//~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `1.1`
|
||||
//~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found expression `1.1`
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ LL | generate_field_accesses!(1.1, 1.1, 1.1);
|
||||
|
|
||||
= note: this error originates in the macro `generate_field_accesses` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `1.1`
|
||||
error: expected one of `.`, `;`, `?`, `}`, or an operator, found literal `1.1`
|
||||
--> $DIR/float-field-interpolated.rs:8:13
|
||||
|
|
||||
LL | { s.$b; }
|
||||
@ -31,7 +31,7 @@ LL | generate_field_accesses!(1.1, 1.1, 1.1);
|
||||
|
|
||||
= note: this error originates in the macro `generate_field_accesses` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `1.1`
|
||||
error: expected one of `.`, `;`, `?`, `}`, or an operator, found expression `1.1`
|
||||
--> $DIR/float-field-interpolated.rs:10:13
|
||||
|
|
||||
LL | { s.$c; }
|
||||
|
Loading…
Reference in New Issue
Block a user