From 5a05b614bf3c837f0984ff3a1d6d3e357ac6d1bd Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 28 Apr 2022 16:15:18 +1000 Subject: [PATCH 1/6] Tweak `print_attr_item`. This commit rearranges the `match`. The new code avoids testing for `MacArgs::Eq` twice, at the cost of repeating the `self.print_path()` call. I think this is worthwhile because it puts the `match` in a more standard and readable form. --- compiler/rustc_ast_pretty/src/pprust/state.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index a2ebe3048ce..c41de17212d 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -469,14 +469,15 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere true, span, ), - MacArgs::Empty | MacArgs::Eq(..) => { + MacArgs::Empty => { self.print_path(&item.path, false, 0); - if let MacArgs::Eq(_, token) = &item.args { - self.space(); - self.word_space("="); - let token_str = self.token_to_string_ext(token, true); - self.word(token_str); - } + } + MacArgs::Eq(_, token) => { + self.print_path(&item.path, false, 0); + self.space(); + self.word_space("="); + let token_str = self.token_to_string_ext(token, true); + self.word(token_str); } } self.end(); From 481a4461ae709e4410af6ba495c725d673ba5c2d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 28 Apr 2022 16:19:06 +1000 Subject: [PATCH 2/6] Rename `visit_interpolated` as `visit_nonterminal`. Because `Nonterminal` is the type it visits. --- compiler/rustc_ast/src/mut_visit.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index cba49835f69..70e18a52c4c 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -738,7 +738,7 @@ pub fn visit_token(t: &mut Token, vis: &mut T) { } token::Interpolated(nt) => { let mut nt = Lrc::make_mut(nt); - visit_interpolated(&mut nt, vis); + visit_nonterminal(&mut nt, vis); } _ => {} } @@ -769,7 +769,7 @@ pub fn visit_token(t: &mut Token, vis: &mut T) { // contain multiple items, but decided against it when I looked at // `parse_item_or_view_item` and tried to figure out what I would do with // multiple items there.... -pub fn visit_interpolated(nt: &mut token::Nonterminal, vis: &mut T) { +pub fn visit_nonterminal(nt: &mut token::Nonterminal, vis: &mut T) { match nt { token::NtItem(item) => visit_clobber(item, |item| { // This is probably okay, because the only visitors likely to From cde25f8dbe86c34dc4774107018b18974d9a14ee Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 28 Apr 2022 14:12:40 +1000 Subject: [PATCH 3/6] Simplify `lower_mac_args`. The `token` is always an interpolated non-terminal expression, and always a literal in valid code. This commit simplifies the processing accordingly, by directly extracting and using the literal. --- compiler/rustc_ast_lowering/src/lib.rs | 42 +++++++++----------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index de4f8e04b16..526679e5315 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -38,8 +38,8 @@ #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] -use rustc_ast::token::{Delimiter, Token}; -use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree}; +use rustc_ast::token::{self, Token, TokenKind}; +use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream}; use rustc_ast::visit; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust; @@ -878,33 +878,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // spans to handle nonterminals in `#[doc]` (e.g. `#[doc = $e]`). MacArgs::Eq(eq_span, ref token) => { // In valid code the value is always representable as a single literal token. - fn unwrap_single_token(sess: &Session, tokens: TokenStream, span: Span) -> Token { - if tokens.len() != 1 { - sess.diagnostic() - .delay_span_bug(span, "multiple tokens in key-value attribute's value"); + // Otherwise, a dummy token suffices because the error is handled elsewhere. + let token = if let token::Interpolated(nt) = &token.kind + && let token::NtExpr(expr) = &**nt + { + if let ExprKind::Lit(Lit { token, span, .. }) = expr.kind { + Token::new(TokenKind::Literal(token), span) + } else { + Token::dummy() } - match tokens.into_trees().next() { - Some(TokenTree::Token(token)) => token, - Some(TokenTree::Delimited(_, delim, tokens)) => { - if delim != Delimiter::Invisible { - sess.diagnostic().delay_span_bug( - span, - "unexpected delimiter in key-value attribute's value", - ); - } - unwrap_single_token(sess, tokens, span) - } - None => Token::dummy(), - } - } - - let tokens = FlattenNonterminals { - parse_sess: &self.sess.parse_sess, - synthesize_tokens: CanSynthesizeMissingTokens::Yes, - nt_to_tokenstream: self.nt_to_tokenstream, - } - .process_token(token.clone()); - MacArgs::Eq(eq_span, unwrap_single_token(self.sess, tokens, token.span)) + } else { + unreachable!() + }; + MacArgs::Eq(eq_span, token) } } } From ae5f67f9e8a560c66d1c4afea1750d21f1d093e7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 28 Apr 2022 16:35:28 +1000 Subject: [PATCH 4/6] Remove the `T::VISIT_TOKENS` test in `visit_mac_args`. The two paths are equivalent -- they both end up calling `visit_expr()`. I have kept the more restrictive path, the one that requires that `token` be an expression nonterminal. (The next commit will simplify this function further.) --- compiler/rustc_ast/src/mut_visit.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 70e18a52c4c..c85b763a820 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -372,18 +372,14 @@ pub fn visit_mac_args(args: &mut MacArgs, vis: &mut T) { } MacArgs::Eq(eq_span, token) => { vis.visit_span(eq_span); - if T::VISIT_TOKENS { - visit_token(token, vis); - } else { - // The value in `#[key = VALUE]` must be visited as an expression for backward - // compatibility, so that macros can be expanded in that position. - match &mut token.kind { - token::Interpolated(nt) => match Lrc::make_mut(nt) { - token::NtExpr(expr) => vis.visit_expr(expr), - t => panic!("unexpected token in key-value attribute: {:?}", t), - }, + // The value in `#[key = VALUE]` must be visited as an expression for backward + // compatibility, so that macros can be expanded in that position. + match &mut token.kind { + token::Interpolated(nt) => match Lrc::make_mut(nt) { + 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), } } } From 99f5945f85342e1eff8d31507410ddd66ea94d64 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 29 Apr 2022 06:52:01 +1000 Subject: [PATCH 5/6] 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. --- compiler/rustc_ast/src/ast.rs | 64 +++++++++++++++++-- compiler/rustc_ast/src/attr/mod.rs | 23 +++++-- compiler/rustc_ast/src/mut_visit.rs | 15 ++--- compiler/rustc_ast/src/visit.rs | 14 ++-- compiler/rustc_ast_lowering/src/lib.rs | 32 +++++----- compiler/rustc_ast_pretty/src/pprust/state.rs | 17 ++++- compiler/rustc_parse/src/parser/mod.rs | 13 +--- compiler/rustc_parse/src/validate_attr.rs | 39 +++++++++-- .../ast-json/ast-json-noexpand-output.stdout | 2 +- src/test/ui/ast-json/ast-json-output.stdout | 2 +- src/test/ui/attributes/issue-90873.rs | 4 +- src/test/ui/attributes/issue-90873.stderr | 4 +- .../attributes/key-value-expansion-on-mac.rs | 4 +- .../key-value-expansion-on-mac.stderr | 2 +- src/test/ui/attributes/key-value-expansion.rs | 6 +- .../ui/attributes/key-value-expansion.stderr | 6 +- src/test/ui/consts/issue-90878-2.rs | 2 +- src/test/ui/consts/issue-90878-2.stderr | 2 +- .../ui/malformed/malformed-interpolated.rs | 4 +- .../malformed/malformed-interpolated.stderr | 4 +- .../clippy/clippy_utils/src/ast_utils.rs | 3 +- 21 files changed, 174 insertions(+), 88 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index a310828b9fb..bea0482bf73 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -23,7 +23,7 @@ pub use GenericArgs::*; pub use UnsafeSource::*; 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 rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -1526,7 +1526,7 @@ impl MacCall { } /// 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 { /// No arguments - `#[attr]`. Empty, @@ -1536,11 +1536,20 @@ pub enum MacArgs { Eq( /// Span of the `=` token. Span, - /// "value" as a nonterminal token. - Token, + /// The "value". + 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), + Hir(Lit), +} + impl MacArgs { pub fn delim(&self) -> Option { match self { @@ -1553,7 +1562,10 @@ impl MacArgs { match self { MacArgs::Empty => None, 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 { MacArgs::Empty => TokenStream::default(), 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 HashStable 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)] pub enum MacDelimiter { Parenthesis, diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index b14367aa1c2..84654a9f737 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -3,14 +3,16 @@ use crate::ast; use crate::ast::{AttrId, AttrItem, AttrKind, AttrStyle, Attribute}; 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::ptr::P; use crate::token::{self, CommentKind, Delimiter, Token}; use crate::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree}; use crate::tokenstream::{DelimSpan, Spacing, TokenTree, TreeAndSpacing}; use crate::tokenstream::{LazyTokenStream, TokenStream}; use crate::util::comments; +use rustc_data_structures::thin_vec::ThinVec; use rustc_index::bit_set::GrowableBitSet; use rustc_span::source_map::BytePos; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -475,7 +477,16 @@ impl MetaItemKind { pub fn mac_args(&self, span: Span) -> MacArgs { match self { 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) => { let mut tts = Vec::new(); for (i, item) in list.iter().enumerate() { @@ -552,12 +563,16 @@ impl MetaItemKind { fn from_mac_args(args: &MacArgs) -> Option { match args { + MacArgs::Empty => Some(MetaItemKind::Word), MacArgs::Delimited(_, MacDelimiter::Parenthesis, tokens) => { MetaItemKind::list_from_tokens(tokens.clone()) } MacArgs::Delimited(..) => None, - MacArgs::Eq(_, token) => Lit::from_token(token).ok().map(MetaItemKind::NameValue), - MacArgs::Empty => Some(MetaItemKind::Word), + MacArgs::Eq(_, MacArgsEq::Ast(expr)) => match &expr.kind { + ast::ExprKind::Lit(lit) => Some(MetaItemKind::NameValue(lit.clone())), + _ => None, + }, + MacArgs::Eq(_, MacArgsEq::Hir(lit)) => Some(MetaItemKind::NameValue(lit.clone())), } } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index c85b763a820..333ffce774d 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -370,17 +370,12 @@ pub fn visit_mac_args(args: &mut MacArgs, vis: &mut T) { visit_delim_span(dspan, vis); visit_tts(tokens, vis); } - MacArgs::Eq(eq_span, token) => { + MacArgs::Eq(eq_span, MacArgsEq::Ast(expr)) => { vis.visit_span(eq_span); - // The value in `#[key = VALUE]` must be visited as an expression for backward - // compatibility, so that macros can be expanded in that position. - match &mut token.kind { - token::Interpolated(nt) => match Lrc::make_mut(nt) { - 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), - } + vis.visit_expr(expr); + } + MacArgs::Eq(_, MacArgsEq::Hir(lit)) => { + unreachable!("in literal form when visiting mac args eq: {:?}", lit) } } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index e08ba73e0ae..3a2d957194c 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -14,7 +14,6 @@ //! those that are created by the expansion of a macro. use crate::ast::*; -use crate::token; use rustc_span::symbol::{Ident, Symbol}; 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 { MacArgs::Empty => {} MacArgs::Delimited(_dspan, _delim, _tokens) => {} - // The value in `#[key = VALUE]` must be visited as an expression for backward - // compatibility, so that macros can be expanded in that position. - MacArgs::Eq(_eq_span, token) => match &token.kind { - 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), - }, + MacArgs::Eq(_eq_span, MacArgsEq::Ast(expr)) => visitor.visit_expr(expr), + MacArgs::Eq(_, MacArgsEq::Hir(lit)) => { + unreachable!("in literal form when walking mac args eq: {:?}", lit) + } } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 526679e5315..d6bbd23cdce 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -38,7 +38,6 @@ #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] -use rustc_ast::token::{self, Token, TokenKind}; use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream}; use rustc_ast::visit; 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 - // after it gets lowered to HIR. Therefore, we can synthesize tokens with fake - // spans to handle nonterminals in `#[doc]` (e.g. `#[doc = $e]`). - MacArgs::Eq(eq_span, ref token) => { - // In valid code the value is always representable as a single literal token. - // Otherwise, a dummy token suffices because the error is handled elsewhere. - let token = if let token::Interpolated(nt) = &token.kind - && let token::NtExpr(expr) = &**nt - { - if let ExprKind::Lit(Lit { token, span, .. }) = expr.kind { - Token::new(TokenKind::Literal(token), span) - } else { - Token::dummy() - } + // after it gets lowered to HIR. Therefore, we can extract literals to handle + // nonterminals in `#[doc]` (e.g. `#[doc = $e]`). + MacArgs::Eq(eq_span, MacArgsEq::Ast(ref expr)) => { + // In valid code the value always ends up as a single literal. Otherwise, a dummy + // literal suffices because the error is handled elsewhere. + let lit = if let ExprKind::Lit(lit) = &expr.kind { + lit.clone() } 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) } } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index c41de17212d..e79f4f0a095 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -13,7 +13,7 @@ use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle}; use rustc_ast::util::parser; use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax}; 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::{InlineAsmOperand, InlineAsmRegOrRegClass}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; @@ -472,11 +472,18 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere MacArgs::Empty => { self.print_path(&item.path, false, 0); } - MacArgs::Eq(_, token) => { + MacArgs::Eq(_, MacArgsEq::Ast(expr)) => { self.print_path(&item.path, false, 0); self.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); } } @@ -818,6 +825,10 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere 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 { Self::to_string(|s| s.print_tt(tt, false)) } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 96cca68257e..c4a26359f51 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -26,11 +26,10 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::AttrId; use rustc_ast::DUMMY_NODE_ID; 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::{Visibility, VisibilityKind}; +use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacArgsEq, MacDelimiter, Mutability, StrLit}; +use rustc_ast::{Unsafe, Visibility, VisibilityKind}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::Lrc; use rustc_errors::PResult; use rustc_errors::{ struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, MultiSpan, @@ -1157,13 +1156,7 @@ impl<'a> Parser<'a> { } else if !delimited_only { if self.eat(&token::Eq) { let eq_span = self.prev_token.span; - - // 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)) + MacArgs::Eq(eq_span, MacArgsEq::Ast(self.parse_expr_force_collect()?)) } else { MacArgs::Empty } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 4781813ee8e..47477898b24 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -2,8 +2,9 @@ use crate::parse_in; -use rustc_ast::tokenstream::{DelimSpan, TokenTree}; -use rustc_ast::{self as ast, Attribute, MacArgs, MacDelimiter, MetaItem, MetaItemKind}; +use rustc_ast::tokenstream::DelimSpan; +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_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; 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(), kind: match &item.args { 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) => { 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())?; 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()), }, }) } diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout index 746ced689d4..6f6e9b38e94 100644 --- a/src/test/ui/ast-json/ast-json-noexpand-output.stdout +++ b/src/test/ui/ast-json/ast-json-noexpand-output.stdout @@ -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} diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout index b0aaa663f38..5637ce596b3 100644 --- a/src/test/ui/ast-json/ast-json-output.stdout +++ b/src/test/ui/ast-json/ast-json-output.stdout @@ -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} diff --git a/src/test/ui/attributes/issue-90873.rs b/src/test/ui/attributes/issue-90873.rs index 0f62d415308..1411f61744d 100644 --- a/src/test/ui/attributes/issue-90873.rs +++ b/src/test/ui/attributes/issue-90873.rs @@ -1,9 +1,9 @@ #![u=||{static d=||1;}] -//~^ unexpected token +//~^ unexpected expression //~| cannot find attribute `u` in this scope //~| missing type for `static` item #![a={impl std::ops::Neg for i8 {}}] -//~^ ERROR unexpected token +//~^ ERROR unexpected expression //~| ERROR cannot find attribute `a` in this scope //~| ERROR `main` function not found in crate `issue_90873` diff --git a/src/test/ui/attributes/issue-90873.stderr b/src/test/ui/attributes/issue-90873.stderr index fbdc05ef6f0..0852bb7ca8b 100644 --- a/src/test/ui/attributes/issue-90873.stderr +++ b/src/test/ui/attributes/issue-90873.stderr @@ -1,4 +1,4 @@ -error: unexpected token: `|| +error: unexpected expression: `|| { static d: _ = || 1; }` @@ -7,7 +7,7 @@ error: unexpected token: `|| LL | #![u=||{static d=||1;}] | ^^^^^^^^^^^^^^^^^ -error: unexpected token: `{ +error: unexpected expression: `{ impl std::ops::Neg for i8 {} }` --> $DIR/issue-90873.rs:6:6 diff --git a/src/test/ui/attributes/key-value-expansion-on-mac.rs b/src/test/ui/attributes/key-value-expansion-on-mac.rs index 95bc1c04961..c1d68d8cda9 100644 --- a/src/test/ui/attributes/key-value-expansion-on-mac.rs +++ b/src/test/ui/attributes/key-value-expansion-on-mac.rs @@ -7,8 +7,8 @@ macro_rules! bar { // FIXME?: `bar` here expands before `stringify` has a chance to expand. // `#[rustc_dummy = ...]` is validated and dropped during expansion of `bar`, -// the "unexpected token" errors comes from the validation. -#[rustc_dummy = stringify!(b)] //~ ERROR unexpected token: `stringify!(b)` +// the "unexpected expression" errors comes from the validation. +#[rustc_dummy = stringify!(b)] //~ ERROR unexpected expression: `stringify!(b)` bar!(); fn main() {} diff --git a/src/test/ui/attributes/key-value-expansion-on-mac.stderr b/src/test/ui/attributes/key-value-expansion-on-mac.stderr index fa9ea543765..64ab892d997 100644 --- a/src/test/ui/attributes/key-value-expansion-on-mac.stderr +++ b/src/test/ui/attributes/key-value-expansion-on-mac.stderr @@ -1,4 +1,4 @@ -error: unexpected token: `stringify!(b)` +error: unexpected expression: `stringify!(b)` --> $DIR/key-value-expansion-on-mac.rs:11:17 | LL | #[rustc_dummy = stringify!(b)] diff --git a/src/test/ui/attributes/key-value-expansion.rs b/src/test/ui/attributes/key-value-expansion.rs index 08121413ee9..83d601e5e3a 100644 --- a/src/test/ui/attributes/key-value-expansion.rs +++ b/src/test/ui/attributes/key-value-expansion.rs @@ -18,13 +18,13 @@ macro_rules! bug { // Any expressions containing macro call `X` that's more complex than `X` itself. // Parentheses will work. -bug!((column!())); //~ ERROR unexpected token: `(7u32)` +bug!((column!())); //~ ERROR unexpected expression: `(7u32)` // Original test case. macro_rules! bug { () => { - bug!("bug" + stringify!(found)); //~ ERROR unexpected token: `"bug" + "found"` + bug!("bug" + stringify!(found)); //~ ERROR unexpected expression: `"bug" + "found"` }; ($test:expr) => { #[doc = $test] @@ -46,7 +46,7 @@ macro_rules! doc_comment { macro_rules! some_macro { ($t1: ty) => { doc_comment! {format!("{coor}", coor = stringify!($t1)).as_str()} - //~^ ERROR unexpected token: `{ + //~^ ERROR unexpected expression: `{ }; } diff --git a/src/test/ui/attributes/key-value-expansion.stderr b/src/test/ui/attributes/key-value-expansion.stderr index 1b7cb76b553..1b776322aaa 100644 --- a/src/test/ui/attributes/key-value-expansion.stderr +++ b/src/test/ui/attributes/key-value-expansion.stderr @@ -1,10 +1,10 @@ -error: unexpected token: `(7u32)` +error: unexpected expression: `(7u32)` --> $DIR/key-value-expansion.rs:21:6 | LL | bug!((column!())); | ^^^^^^^^^^^ -error: unexpected token: `"bug" + "found"` +error: unexpected expression: `"bug" + "found"` --> $DIR/key-value-expansion.rs:27:14 | 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) -error: unexpected token: `{ +error: unexpected expression: `{ let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1(&[""], &[::core::fmt::ArgumentV1::new_display(&"u8")])); diff --git a/src/test/ui/consts/issue-90878-2.rs b/src/test/ui/consts/issue-90878-2.rs index ac5640646a8..e5bcecce6ee 100644 --- a/src/test/ui/consts/issue-90878-2.rs +++ b/src/test/ui/consts/issue-90878-2.rs @@ -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 // notice the space at the start, diff --git a/src/test/ui/consts/issue-90878-2.stderr b/src/test/ui/consts/issue-90878-2.stderr index 4ccce36eedf..71b8d21fb4d 100644 --- a/src/test/ui/consts/issue-90878-2.stderr +++ b/src/test/ui/consts/issue-90878-2.stderr @@ -1,4 +1,4 @@ -error: unexpected token: `|x| [b; x]` +error: unexpected expression: `|x| [b; x]` --> $DIR/issue-90878-2.rs:1:7 | LL | #![l=|x|[b;x ]] diff --git a/src/test/ui/malformed/malformed-interpolated.rs b/src/test/ui/malformed/malformed-interpolated.rs index b962447e7ed..0d84e723fc3 100644 --- a/src/test/ui/malformed/malformed-interpolated.rs +++ b/src/test/ui/malformed/malformed-interpolated.rs @@ -10,7 +10,7 @@ macro_rules! check { check!("0"); // OK check!(0); // OK check!(0u8); //~ ERROR suffixed literals are not allowed in attributes -check!(-0); //~ ERROR unexpected token: `-0` -check!(0 + 0); //~ ERROR unexpected token: `0 + 0` +check!(-0); //~ ERROR unexpected expression: `-0` +check!(0 + 0); //~ ERROR unexpected expression: `0 + 0` fn main() {} diff --git a/src/test/ui/malformed/malformed-interpolated.stderr b/src/test/ui/malformed/malformed-interpolated.stderr index 4b9332ddd01..c24d9f15388 100644 --- a/src/test/ui/malformed/malformed-interpolated.stderr +++ b/src/test/ui/malformed/malformed-interpolated.stderr @@ -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.) -error: unexpected token: `-0` +error: unexpected expression: `-0` --> $DIR/malformed-interpolated.rs:13:8 | LL | check!(-0); | ^^ -error: unexpected token: `0 + 0` +error: unexpected expression: `0 + 0` --> $DIR/malformed-interpolated.rs:14:8 | LL | check!(0 + 0); diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 3fce4987679..7919800483f 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -688,7 +688,8 @@ pub fn eq_mac_args(l: &MacArgs, r: &MacArgs) -> bool { match (l, r) { (Empty, Empty) => true, (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, } } From baa18c027a9f001a560d3b9537528cf8d9a53a05 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 4 May 2022 16:12:09 +1000 Subject: [PATCH 6/6] Add a comment on `TokenKind::Interpolated`. --- compiler/rustc_ast/src/token.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 1589a882f08..b335fc0e71f 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -237,6 +237,15 @@ pub enum TokenKind { /// treat regular and interpolated lifetime identifiers in the same way. Lifetime(Symbol), + /// An embedded AST node, as produced by a macro. This only exists for + /// historical reasons. We'd like to get rid of it, for multiple reasons. + /// - It's conceptually very strange. Saying a token can contain an AST + /// node is like saying, in natural language, that a word can contain a + /// sentence. + /// - It requires special handling in a bunch of places in the parser. + /// - 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), /// A doc comment token.