Overhaul `MacArgs::Eq`.

The value in `MacArgs::Eq` is currently represented as a `Token`.
Because of `TokenKind::Interpolated`, `Token` can be either a token or
an arbitrary AST fragment. In practice, a `MacArgs::Eq` starts out as a
literal or macro call AST fragment, and then is later lowered to a
literal token. But this is very non-obvious. `Token` is a much more
general type than what is needed.

This commit restricts things, by introducing a new type `MacArgsEqKind`
that is either an AST expression (pre-lowering) or an AST literal
(post-lowering). The downside is that the code is a bit more verbose in
a few places. The benefit is that makes it much clearer what the
possibilities are (though also shorter in some other places). Also, it
removes one use of `TokenKind::Interpolated`, taking us a step closer to
removing that variant, which will let us make `Token` impl `Copy` and
remove many "handle Interpolated" code paths in the parser.

Things to note:
- Error messages have improved. Messages like this:
  ```
  unexpected token: `"bug" + "found"`
  ```
  now say "unexpected expression", which makes more sense. Although
  arbitrary expressions can exist within tokens thanks to
  `TokenKind::Interpolated`, that's not obvious to anyone who doesn't
  know compiler internals.
- In `parse_mac_args_common`, we no longer need to collect tokens for
  the value expression.
This commit is contained in:
Nicholas Nethercote 2022-04-29 06:52:01 +10:00
parent ae5f67f9e8
commit 99f5945f85
21 changed files with 174 additions and 88 deletions

View File

@ -23,7 +23,7 @@ pub use GenericArgs::*;
pub use UnsafeSource::*; pub use UnsafeSource::*;
use crate::ptr::P; use crate::ptr::P;
use crate::token::{self, CommentKind, Delimiter, Token}; use crate::token::{self, CommentKind, Delimiter, Token, TokenKind};
use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream, TokenTree}; use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream, TokenTree};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@ -1526,7 +1526,7 @@ impl MacCall {
} }
/// Arguments passed to an attribute or a function-like macro. /// Arguments passed to an attribute or a function-like macro.
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] #[derive(Clone, Encodable, Decodable, Debug)]
pub enum MacArgs { pub enum MacArgs {
/// No arguments - `#[attr]`. /// No arguments - `#[attr]`.
Empty, Empty,
@ -1536,11 +1536,20 @@ pub enum MacArgs {
Eq( Eq(
/// Span of the `=` token. /// Span of the `=` token.
Span, Span,
/// "value" as a nonterminal token. /// The "value".
Token, MacArgsEq,
), ),
} }
// The RHS of a `MacArgs::Eq` starts out as an expression. Once macro expansion
// is completed, all cases end up either as a literal, which is the form used
// after lowering to HIR, or as an error.
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum MacArgsEq {
Ast(P<Expr>),
Hir(Lit),
}
impl MacArgs { impl MacArgs {
pub fn delim(&self) -> Option<Delimiter> { pub fn delim(&self) -> Option<Delimiter> {
match self { match self {
@ -1553,7 +1562,10 @@ impl MacArgs {
match self { match self {
MacArgs::Empty => None, MacArgs::Empty => None,
MacArgs::Delimited(dspan, ..) => Some(dspan.entire()), MacArgs::Delimited(dspan, ..) => Some(dspan.entire()),
MacArgs::Eq(eq_span, token) => Some(eq_span.to(token.span)), MacArgs::Eq(eq_span, MacArgsEq::Ast(expr)) => Some(eq_span.to(expr.span)),
MacArgs::Eq(_, MacArgsEq::Hir(lit)) => {
unreachable!("in literal form when getting span: {:?}", lit);
}
} }
} }
@ -1563,7 +1575,23 @@ impl MacArgs {
match self { match self {
MacArgs::Empty => TokenStream::default(), MacArgs::Empty => TokenStream::default(),
MacArgs::Delimited(.., tokens) => tokens.clone(), MacArgs::Delimited(.., tokens) => tokens.clone(),
MacArgs::Eq(.., token) => TokenTree::Token(token.clone()).into(), MacArgs::Eq(_, MacArgsEq::Ast(expr)) => {
// Currently only literals are allowed here. If more complex expression kinds are
// allowed in the future, then `nt_to_tokenstream` should be used to extract the
// token stream. This will require some cleverness, perhaps with a function
// pointer, because `nt_to_tokenstream` is not directly usable from this crate.
// It will also require changing the `parse_expr` call in `parse_mac_args_common`
// to `parse_expr_force_collect`.
if let ExprKind::Lit(lit) = &expr.kind {
let token = Token::new(TokenKind::Literal(lit.token), lit.span);
TokenTree::Token(token).into()
} else {
unreachable!("couldn't extract literal when getting inner tokens: {:?}", expr)
}
}
MacArgs::Eq(_, MacArgsEq::Hir(lit)) => {
unreachable!("in literal form when getting inner tokens: {:?}", lit)
}
} }
} }
@ -1574,6 +1602,30 @@ impl MacArgs {
} }
} }
impl<CTX> HashStable<CTX> for MacArgs
where
CTX: crate::HashStableContext,
{
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
mem::discriminant(self).hash_stable(ctx, hasher);
match self {
MacArgs::Empty => {}
MacArgs::Delimited(dspan, delim, tokens) => {
dspan.hash_stable(ctx, hasher);
delim.hash_stable(ctx, hasher);
tokens.hash_stable(ctx, hasher);
}
MacArgs::Eq(_eq_span, MacArgsEq::Ast(expr)) => {
unreachable!("hash_stable {:?}", expr);
}
MacArgs::Eq(eq_span, MacArgsEq::Hir(lit)) => {
eq_span.hash_stable(ctx, hasher);
lit.hash_stable(ctx, hasher);
}
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)] #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum MacDelimiter { pub enum MacDelimiter {
Parenthesis, Parenthesis,

View File

@ -3,14 +3,16 @@
use crate::ast; use crate::ast;
use crate::ast::{AttrId, AttrItem, AttrKind, AttrStyle, Attribute}; use crate::ast::{AttrId, AttrItem, AttrKind, AttrStyle, Attribute};
use crate::ast::{Lit, LitKind}; use crate::ast::{Lit, LitKind};
use crate::ast::{MacArgs, MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem}; use crate::ast::{MacArgs, MacArgsEq, MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem};
use crate::ast::{Path, PathSegment}; use crate::ast::{Path, PathSegment};
use crate::ptr::P;
use crate::token::{self, CommentKind, Delimiter, Token}; use crate::token::{self, CommentKind, Delimiter, Token};
use crate::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree}; use crate::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
use crate::tokenstream::{DelimSpan, Spacing, TokenTree, TreeAndSpacing}; use crate::tokenstream::{DelimSpan, Spacing, TokenTree, TreeAndSpacing};
use crate::tokenstream::{LazyTokenStream, TokenStream}; use crate::tokenstream::{LazyTokenStream, TokenStream};
use crate::util::comments; use crate::util::comments;
use rustc_data_structures::thin_vec::ThinVec;
use rustc_index::bit_set::GrowableBitSet; use rustc_index::bit_set::GrowableBitSet;
use rustc_span::source_map::BytePos; use rustc_span::source_map::BytePos;
use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::symbol::{sym, Ident, Symbol};
@ -475,7 +477,16 @@ impl MetaItemKind {
pub fn mac_args(&self, span: Span) -> MacArgs { pub fn mac_args(&self, span: Span) -> MacArgs {
match self { match self {
MetaItemKind::Word => MacArgs::Empty, MetaItemKind::Word => MacArgs::Empty,
MetaItemKind::NameValue(lit) => MacArgs::Eq(span, lit.to_token()), MetaItemKind::NameValue(lit) => {
let expr = P(ast::Expr {
id: ast::DUMMY_NODE_ID,
kind: ast::ExprKind::Lit(lit.clone()),
span: lit.span,
attrs: ThinVec::new(),
tokens: None,
});
MacArgs::Eq(span, MacArgsEq::Ast(expr))
}
MetaItemKind::List(list) => { MetaItemKind::List(list) => {
let mut tts = Vec::new(); let mut tts = Vec::new();
for (i, item) in list.iter().enumerate() { for (i, item) in list.iter().enumerate() {
@ -552,12 +563,16 @@ impl MetaItemKind {
fn from_mac_args(args: &MacArgs) -> Option<MetaItemKind> { fn from_mac_args(args: &MacArgs) -> Option<MetaItemKind> {
match args { match args {
MacArgs::Empty => Some(MetaItemKind::Word),
MacArgs::Delimited(_, MacDelimiter::Parenthesis, tokens) => { MacArgs::Delimited(_, MacDelimiter::Parenthesis, tokens) => {
MetaItemKind::list_from_tokens(tokens.clone()) MetaItemKind::list_from_tokens(tokens.clone())
} }
MacArgs::Delimited(..) => None, MacArgs::Delimited(..) => None,
MacArgs::Eq(_, token) => Lit::from_token(token).ok().map(MetaItemKind::NameValue), MacArgs::Eq(_, MacArgsEq::Ast(expr)) => match &expr.kind {
MacArgs::Empty => Some(MetaItemKind::Word), ast::ExprKind::Lit(lit) => Some(MetaItemKind::NameValue(lit.clone())),
_ => None,
},
MacArgs::Eq(_, MacArgsEq::Hir(lit)) => Some(MetaItemKind::NameValue(lit.clone())),
} }
} }

View File

@ -370,17 +370,12 @@ pub fn visit_mac_args<T: MutVisitor>(args: &mut MacArgs, vis: &mut T) {
visit_delim_span(dspan, vis); visit_delim_span(dspan, vis);
visit_tts(tokens, vis); visit_tts(tokens, vis);
} }
MacArgs::Eq(eq_span, token) => { MacArgs::Eq(eq_span, MacArgsEq::Ast(expr)) => {
vis.visit_span(eq_span); vis.visit_span(eq_span);
// The value in `#[key = VALUE]` must be visited as an expression for backward vis.visit_expr(expr);
// compatibility, so that macros can be expanded in that position. }
match &mut token.kind { MacArgs::Eq(_, MacArgsEq::Hir(lit)) => {
token::Interpolated(nt) => match Lrc::make_mut(nt) { unreachable!("in literal form when visiting mac args eq: {:?}", lit)
token::NtExpr(expr) => vis.visit_expr(expr),
t => panic!("unexpected token in key-value attribute: {:?}", t),
},
t => panic!("unexpected token in key-value attribute: {:?}", t),
}
} }
} }
} }

View File

@ -14,7 +14,6 @@
//! those that are created by the expansion of a macro. //! those that are created by the expansion of a macro.
use crate::ast::*; use crate::ast::*;
use crate::token;
use rustc_span::symbol::{Ident, Symbol}; use rustc_span::symbol::{Ident, Symbol};
use rustc_span::Span; use rustc_span::Span;
@ -937,14 +936,9 @@ pub fn walk_mac_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a MacArgs) {
match args { match args {
MacArgs::Empty => {} MacArgs::Empty => {}
MacArgs::Delimited(_dspan, _delim, _tokens) => {} MacArgs::Delimited(_dspan, _delim, _tokens) => {}
// The value in `#[key = VALUE]` must be visited as an expression for backward MacArgs::Eq(_eq_span, MacArgsEq::Ast(expr)) => visitor.visit_expr(expr),
// compatibility, so that macros can be expanded in that position. MacArgs::Eq(_, MacArgsEq::Hir(lit)) => {
MacArgs::Eq(_eq_span, token) => match &token.kind { unreachable!("in literal form when walking mac args eq: {:?}", lit)
token::Interpolated(nt) => match &**nt { }
token::NtExpr(expr) => visitor.visit_expr(expr),
t => panic!("unexpected token in key-value attribute: {:?}", t),
},
t => panic!("unexpected token in key-value attribute: {:?}", t),
},
} }
} }

View File

@ -38,7 +38,6 @@
#![recursion_limit = "256"] #![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)] #![allow(rustc::potential_query_instability)]
use rustc_ast::token::{self, Token, TokenKind};
use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream}; use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream};
use rustc_ast::visit; use rustc_ast::visit;
use rustc_ast::{self as ast, *}; use rustc_ast::{self as ast, *};
@ -874,23 +873,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
) )
} }
// This is an inert key-value attribute - it will never be visible to macros // This is an inert key-value attribute - it will never be visible to macros
// after it gets lowered to HIR. Therefore, we can synthesize tokens with fake // after it gets lowered to HIR. Therefore, we can extract literals to handle
// spans to handle nonterminals in `#[doc]` (e.g. `#[doc = $e]`). // nonterminals in `#[doc]` (e.g. `#[doc = $e]`).
MacArgs::Eq(eq_span, ref token) => { MacArgs::Eq(eq_span, MacArgsEq::Ast(ref expr)) => {
// In valid code the value is always representable as a single literal token. // In valid code the value always ends up as a single literal. Otherwise, a dummy
// Otherwise, a dummy token suffices because the error is handled elsewhere. // literal suffices because the error is handled elsewhere.
let token = if let token::Interpolated(nt) = &token.kind let lit = if let ExprKind::Lit(lit) = &expr.kind {
&& let token::NtExpr(expr) = &**nt lit.clone()
{
if let ExprKind::Lit(Lit { token, span, .. }) = expr.kind {
Token::new(TokenKind::Literal(token), span)
} else {
Token::dummy()
}
} else { } else {
unreachable!() Lit {
token: token::Lit::new(token::LitKind::Err, kw::Empty, None),
kind: LitKind::Err(kw::Empty),
span: DUMMY_SP,
}
}; };
MacArgs::Eq(eq_span, token) MacArgs::Eq(eq_span, MacArgsEq::Hir(lit))
}
MacArgs::Eq(_, MacArgsEq::Hir(ref lit)) => {
unreachable!("in literal form when lowering mac args eq: {:?}", lit)
} }
} }
} }

View File

@ -13,7 +13,7 @@ use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
use rustc_ast::util::parser; use rustc_ast::util::parser;
use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax}; use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
use rustc_ast::{attr, Term}; use rustc_ast::{attr, Term};
use rustc_ast::{GenericArg, MacArgs}; use rustc_ast::{GenericArg, MacArgs, MacArgsEq};
use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier}; use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier};
use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass}; use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
@ -472,11 +472,18 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
MacArgs::Empty => { MacArgs::Empty => {
self.print_path(&item.path, false, 0); self.print_path(&item.path, false, 0);
} }
MacArgs::Eq(_, token) => { MacArgs::Eq(_, MacArgsEq::Ast(expr)) => {
self.print_path(&item.path, false, 0); self.print_path(&item.path, false, 0);
self.space(); self.space();
self.word_space("="); self.word_space("=");
let token_str = self.token_to_string_ext(token, true); let token_str = self.expr_to_string(expr);
self.word(token_str);
}
MacArgs::Eq(_, MacArgsEq::Hir(lit)) => {
self.print_path(&item.path, false, 0);
self.space();
self.word_space("=");
let token_str = self.literal_to_string(lit);
self.word(token_str); self.word(token_str);
} }
} }
@ -818,6 +825,10 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
Self::to_string(|s| s.print_expr(e)) Self::to_string(|s| s.print_expr(e))
} }
fn literal_to_string(&self, lit: &ast::Lit) -> String {
Self::to_string(|s| s.print_literal(lit))
}
fn tt_to_string(&self, tt: &TokenTree) -> String { fn tt_to_string(&self, tt: &TokenTree) -> String {
Self::to_string(|s| s.print_tt(tt, false)) Self::to_string(|s| s.print_tt(tt, false))
} }

View File

@ -26,11 +26,10 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_ast::AttrId; use rustc_ast::AttrId;
use rustc_ast::DUMMY_NODE_ID; use rustc_ast::DUMMY_NODE_ID;
use rustc_ast::{self as ast, AnonConst, AstLike, AttrStyle, AttrVec, Const, CrateSugar, Extern}; use rustc_ast::{self as ast, AnonConst, AstLike, AttrStyle, AttrVec, Const, CrateSugar, Extern};
use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacDelimiter, Mutability, StrLit, Unsafe}; use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacArgsEq, MacDelimiter, Mutability, StrLit};
use rustc_ast::{Visibility, VisibilityKind}; use rustc_ast::{Unsafe, Visibility, VisibilityKind};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
use rustc_errors::PResult; use rustc_errors::PResult;
use rustc_errors::{ use rustc_errors::{
struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, MultiSpan, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, MultiSpan,
@ -1157,13 +1156,7 @@ impl<'a> Parser<'a> {
} else if !delimited_only { } else if !delimited_only {
if self.eat(&token::Eq) { if self.eat(&token::Eq) {
let eq_span = self.prev_token.span; let eq_span = self.prev_token.span;
MacArgs::Eq(eq_span, MacArgsEq::Ast(self.parse_expr_force_collect()?))
// Collect tokens because they are used during lowering to HIR.
let expr = self.parse_expr_force_collect()?;
let span = expr.span;
let token_kind = token::Interpolated(Lrc::new(token::NtExpr(expr)));
MacArgs::Eq(eq_span, Token::new(token_kind, span))
} else { } else {
MacArgs::Empty MacArgs::Empty
} }

View File

@ -2,8 +2,9 @@
use crate::parse_in; use crate::parse_in;
use rustc_ast::tokenstream::{DelimSpan, TokenTree}; use rustc_ast::tokenstream::DelimSpan;
use rustc_ast::{self as ast, Attribute, MacArgs, MacDelimiter, MetaItem, MetaItemKind}; use rustc_ast::{self as ast, Attribute, MacArgs, MacArgsEq, MacDelimiter, MetaItem, MetaItemKind};
use rustc_ast_pretty::pprust;
use rustc_errors::{Applicability, FatalError, PResult}; use rustc_errors::{Applicability, FatalError, PResult};
use rustc_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
@ -42,16 +43,40 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta
path: item.path.clone(), path: item.path.clone(),
kind: match &item.args { kind: match &item.args {
MacArgs::Empty => MetaItemKind::Word, MacArgs::Empty => MetaItemKind::Word,
MacArgs::Eq(_, t) => {
let t = TokenTree::Token(t.clone()).into();
let v = parse_in(sess, t, "name value", |p| p.parse_unsuffixed_lit())?;
MetaItemKind::NameValue(v)
}
MacArgs::Delimited(dspan, delim, t) => { MacArgs::Delimited(dspan, delim, t) => {
check_meta_bad_delim(sess, *dspan, *delim, "wrong meta list delimiters"); check_meta_bad_delim(sess, *dspan, *delim, "wrong meta list delimiters");
let nmis = parse_in(sess, t.clone(), "meta list", |p| p.parse_meta_seq_top())?; let nmis = parse_in(sess, t.clone(), "meta list", |p| p.parse_meta_seq_top())?;
MetaItemKind::List(nmis) MetaItemKind::List(nmis)
} }
MacArgs::Eq(_, MacArgsEq::Ast(expr)) => {
if let ast::ExprKind::Lit(lit) = &expr.kind {
if !lit.kind.is_unsuffixed() {
let mut err = sess.span_diagnostic.struct_span_err(
lit.span,
"suffixed literals are not allowed in attributes",
);
err.help(
"instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), \
use an unsuffixed version (`1`, `1.0`, etc.)",
);
return Err(err);
} else {
MetaItemKind::NameValue(lit.clone())
}
} else {
// The non-error case can happen with e.g. `#[foo = 1+1]`. The error case can
// happen with e.g. `#[foo = include_str!("non-existent-file.rs")]`; in that
// case we delay the error because an earlier error will have already been
// reported.
let msg = format!("unexpected expression: `{}`", pprust::expr_to_string(expr));
let mut err = sess.span_diagnostic.struct_span_err(expr.span, msg);
if let ast::ExprKind::Err = expr.kind {
err.downgrade_to_delayed_bug();
}
return Err(err);
}
}
MacArgs::Eq(_, MacArgsEq::Hir(lit)) => MetaItemKind::NameValue(lit.clone()),
}, },
}) })
} }

View File

@ -1 +1 @@
{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"spans":{"inner_span":{"lo":0,"hi":0},"inject_use_span":{"lo":0,"hi":0}},"id":0,"is_placeholder":false} {"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"variant":"Ast","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"spans":{"inner_span":{"lo":0,"hi":0},"inject_use_span":{"lo":0,"hi":0}},"id":0,"is_placeholder":false}

View File

@ -1 +1 @@
{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"spans":{"inner_span":{"lo":0,"hi":0},"inject_use_span":{"lo":0,"hi":0}},"id":0,"is_placeholder":false} {"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"variant":"Ast","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"spans":{"inner_span":{"lo":0,"hi":0},"inject_use_span":{"lo":0,"hi":0}},"id":0,"is_placeholder":false}

View File

@ -1,9 +1,9 @@
#![u=||{static d=||1;}] #![u=||{static d=||1;}]
//~^ unexpected token //~^ unexpected expression
//~| cannot find attribute `u` in this scope //~| cannot find attribute `u` in this scope
//~| missing type for `static` item //~| missing type for `static` item
#![a={impl std::ops::Neg for i8 {}}] #![a={impl std::ops::Neg for i8 {}}]
//~^ ERROR unexpected token //~^ ERROR unexpected expression
//~| ERROR cannot find attribute `a` in this scope //~| ERROR cannot find attribute `a` in this scope
//~| ERROR `main` function not found in crate `issue_90873` //~| ERROR `main` function not found in crate `issue_90873`

View File

@ -1,4 +1,4 @@
error: unexpected token: `|| error: unexpected expression: `||
{ {
static d: _ = || 1; static d: _ = || 1;
}` }`
@ -7,7 +7,7 @@ error: unexpected token: `||
LL | #![u=||{static d=||1;}] LL | #![u=||{static d=||1;}]
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
error: unexpected token: `{ error: unexpected expression: `{
impl std::ops::Neg for i8 {} impl std::ops::Neg for i8 {}
}` }`
--> $DIR/issue-90873.rs:6:6 --> $DIR/issue-90873.rs:6:6

View File

@ -7,8 +7,8 @@ macro_rules! bar {
// FIXME?: `bar` here expands before `stringify` has a chance to expand. // FIXME?: `bar` here expands before `stringify` has a chance to expand.
// `#[rustc_dummy = ...]` is validated and dropped during expansion of `bar`, // `#[rustc_dummy = ...]` is validated and dropped during expansion of `bar`,
// the "unexpected token" errors comes from the validation. // the "unexpected expression" errors comes from the validation.
#[rustc_dummy = stringify!(b)] //~ ERROR unexpected token: `stringify!(b)` #[rustc_dummy = stringify!(b)] //~ ERROR unexpected expression: `stringify!(b)`
bar!(); bar!();
fn main() {} fn main() {}

View File

@ -1,4 +1,4 @@
error: unexpected token: `stringify!(b)` error: unexpected expression: `stringify!(b)`
--> $DIR/key-value-expansion-on-mac.rs:11:17 --> $DIR/key-value-expansion-on-mac.rs:11:17
| |
LL | #[rustc_dummy = stringify!(b)] LL | #[rustc_dummy = stringify!(b)]

View File

@ -18,13 +18,13 @@ macro_rules! bug {
// Any expressions containing macro call `X` that's more complex than `X` itself. // Any expressions containing macro call `X` that's more complex than `X` itself.
// Parentheses will work. // Parentheses will work.
bug!((column!())); //~ ERROR unexpected token: `(7u32)` bug!((column!())); //~ ERROR unexpected expression: `(7u32)`
// Original test case. // Original test case.
macro_rules! bug { macro_rules! bug {
() => { () => {
bug!("bug" + stringify!(found)); //~ ERROR unexpected token: `"bug" + "found"` bug!("bug" + stringify!(found)); //~ ERROR unexpected expression: `"bug" + "found"`
}; };
($test:expr) => { ($test:expr) => {
#[doc = $test] #[doc = $test]
@ -46,7 +46,7 @@ macro_rules! doc_comment {
macro_rules! some_macro { macro_rules! some_macro {
($t1: ty) => { ($t1: ty) => {
doc_comment! {format!("{coor}", coor = stringify!($t1)).as_str()} doc_comment! {format!("{coor}", coor = stringify!($t1)).as_str()}
//~^ ERROR unexpected token: `{ //~^ ERROR unexpected expression: `{
}; };
} }

View File

@ -1,10 +1,10 @@
error: unexpected token: `(7u32)` error: unexpected expression: `(7u32)`
--> $DIR/key-value-expansion.rs:21:6 --> $DIR/key-value-expansion.rs:21:6
| |
LL | bug!((column!())); LL | bug!((column!()));
| ^^^^^^^^^^^ | ^^^^^^^^^^^
error: unexpected token: `"bug" + "found"` error: unexpected expression: `"bug" + "found"`
--> $DIR/key-value-expansion.rs:27:14 --> $DIR/key-value-expansion.rs:27:14
| |
LL | bug!("bug" + stringify!(found)); LL | bug!("bug" + stringify!(found));
@ -15,7 +15,7 @@ LL | bug!();
| |
= note: this error originates in the macro `bug` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `bug` (in Nightly builds, run with -Z macro-backtrace for more info)
error: unexpected token: `{ error: unexpected expression: `{
let res = let res =
::alloc::fmt::format(::core::fmt::Arguments::new_v1(&[""], ::alloc::fmt::format(::core::fmt::Arguments::new_v1(&[""],
&[::core::fmt::ArgumentV1::new_display(&"u8")])); &[::core::fmt::ArgumentV1::new_display(&"u8")]));

View File

@ -1,4 +1,4 @@
#![l=|x|[b;x ]] //~ ERROR unexpected token: `|x| [b; x]` #![l=|x|[b;x ]] //~ ERROR unexpected expression: `|x| [b; x]`
//~^ ERROR cannot find attribute `l` in this scope //~^ ERROR cannot find attribute `l` in this scope
// notice the space at the start, // notice the space at the start,

View File

@ -1,4 +1,4 @@
error: unexpected token: `|x| [b; x]` error: unexpected expression: `|x| [b; x]`
--> $DIR/issue-90878-2.rs:1:7 --> $DIR/issue-90878-2.rs:1:7
| |
LL | #![l=|x|[b;x ]] LL | #![l=|x|[b;x ]]

View File

@ -10,7 +10,7 @@ macro_rules! check {
check!("0"); // OK check!("0"); // OK
check!(0); // OK check!(0); // OK
check!(0u8); //~ ERROR suffixed literals are not allowed in attributes check!(0u8); //~ ERROR suffixed literals are not allowed in attributes
check!(-0); //~ ERROR unexpected token: `-0` check!(-0); //~ ERROR unexpected expression: `-0`
check!(0 + 0); //~ ERROR unexpected token: `0 + 0` check!(0 + 0); //~ ERROR unexpected expression: `0 + 0`
fn main() {} fn main() {}

View File

@ -6,13 +6,13 @@ LL | check!(0u8);
| |
= help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
error: unexpected token: `-0` error: unexpected expression: `-0`
--> $DIR/malformed-interpolated.rs:13:8 --> $DIR/malformed-interpolated.rs:13:8
| |
LL | check!(-0); LL | check!(-0);
| ^^ | ^^
error: unexpected token: `0 + 0` error: unexpected expression: `0 + 0`
--> $DIR/malformed-interpolated.rs:14:8 --> $DIR/malformed-interpolated.rs:14:8
| |
LL | check!(0 + 0); LL | check!(0 + 0);

View File

@ -688,7 +688,8 @@ pub fn eq_mac_args(l: &MacArgs, r: &MacArgs) -> bool {
match (l, r) { match (l, r) {
(Empty, Empty) => true, (Empty, Empty) => true,
(Delimited(_, ld, lts), Delimited(_, rd, rts)) => ld == rd && lts.eq_unspanned(rts), (Delimited(_, ld, lts), Delimited(_, rd, rts)) => ld == rd && lts.eq_unspanned(rts),
(Eq(_, lt), Eq(_, rt)) => lt.kind == rt.kind, (Eq(_, MacArgsEq::Ast(le)), Eq(_, MacArgsEq::Ast(re))) => eq_expr(le, re),
(Eq(_, MacArgsEq::Hir(ll)), Eq(_, MacArgsEq::Hir(rl))) => ll.kind == rl.kind,
_ => false, _ => false,
} }
} }