1
Fork 0

Remove NtMeta.

Note: there was an existing code path involving `Interpolated` in
`MetaItem::from_tokens` that was dead. This commit transfers that to the
new form, but puts an `unreachable!` call inside it.
This commit is contained in:
Nicholas Nethercote 2024-04-18 16:22:02 +10:00
parent ef1114a964
commit 7ea59e053b
20 changed files with 67 additions and 64 deletions

View file

@ -202,7 +202,6 @@ impl HasTokens for Nonterminal {
Nonterminal::NtItem(item) => item.tokens(), Nonterminal::NtItem(item) => item.tokens(),
Nonterminal::NtStmt(stmt) => stmt.tokens(), Nonterminal::NtStmt(stmt) => stmt.tokens(),
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(),
Nonterminal::NtMeta(attr_item) => attr_item.tokens(),
Nonterminal::NtPath(path) => path.tokens(), Nonterminal::NtPath(path) => path.tokens(),
Nonterminal::NtBlock(block) => block.tokens(), Nonterminal::NtBlock(block) => block.tokens(),
} }
@ -212,7 +211,6 @@ impl HasTokens for Nonterminal {
Nonterminal::NtItem(item) => item.tokens_mut(), Nonterminal::NtItem(item) => item.tokens_mut(),
Nonterminal::NtStmt(stmt) => stmt.tokens_mut(), Nonterminal::NtStmt(stmt) => stmt.tokens_mut(),
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(),
Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(),
Nonterminal::NtPath(path) => path.tokens_mut(), Nonterminal::NtPath(path) => path.tokens_mut(),
Nonterminal::NtBlock(block) => block.tokens_mut(), Nonterminal::NtBlock(block) => block.tokens_mut(),
} }

View file

@ -14,7 +14,7 @@ use crate::ast::{
PathSegment, Safety, PathSegment, Safety,
}; };
use crate::ptr::P; use crate::ptr::P;
use crate::token::{self, CommentKind, Delimiter, Token}; use crate::token::{self, CommentKind, Delimiter, InvisibleOrigin, MetaVarKind, Token};
use crate::tokenstream::{ use crate::tokenstream::{
DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenStreamIter, TokenTree, DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenStreamIter, TokenTree,
}; };
@ -406,10 +406,18 @@ impl MetaItem {
Path { span, segments, tokens: None } 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 {
token::Nonterminal::NtMeta(item) => return item.meta(item.path.span),
token::Nonterminal::NtPath(path) => (**path).clone(), token::Nonterminal::NtPath(path) => (**path).clone(),
_ => return None, _ => return None,
}, },
Some(TokenTree::Delimited(
_span,
_spacing,
Delimiter::Invisible(InvisibleOrigin::MetaVar(MetaVarKind::Meta { .. })),
_stream,
)) => {
// This path is currently unreachable in the test suite.
unreachable!()
}
Some(TokenTree::Token( Some(TokenTree::Token(
Token { kind: token::OpenDelim(_) | token::CloseDelim(_), .. }, Token { kind: token::OpenDelim(_) | token::CloseDelim(_), .. },
_, _,

View file

@ -907,12 +907,6 @@ fn visit_nonterminal<T: MutVisitor>(vis: &mut T, nt: &mut token::Nonterminal) {
}), }),
token::NtExpr(expr) => vis.visit_expr(expr), token::NtExpr(expr) => vis.visit_expr(expr),
token::NtLiteral(expr) => vis.visit_expr(expr), token::NtLiteral(expr) => vis.visit_expr(expr),
token::NtMeta(item) => {
let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut();
vis.visit_path(path);
visit_attr_args(vis, args);
visit_lazy_tts(vis, tokens);
}
token::NtPath(path) => vis.visit_path(path), token::NtPath(path) => vis.visit_path(path),
} }
} }

View file

@ -90,7 +90,10 @@ pub enum MetaVarKind {
Ident, Ident,
Lifetime, Lifetime,
Literal, Literal,
Meta, Meta {
/// Will `AttrItem::meta` succeed on this, if reparsed?
has_meta_form: bool,
},
Path, Path,
Vis, Vis,
TT, TT,
@ -110,7 +113,7 @@ impl fmt::Display for MetaVarKind {
MetaVarKind::Ident => sym::ident, MetaVarKind::Ident => sym::ident,
MetaVarKind::Lifetime => sym::lifetime, MetaVarKind::Lifetime => sym::lifetime,
MetaVarKind::Literal => sym::literal, MetaVarKind::Literal => sym::literal,
MetaVarKind::Meta => sym::meta, MetaVarKind::Meta { .. } => sym::meta,
MetaVarKind::Path => sym::path, MetaVarKind::Path => sym::path,
MetaVarKind::Vis => sym::vis, MetaVarKind::Vis => sym::vis,
MetaVarKind::TT => sym::tt, MetaVarKind::TT => sym::tt,
@ -658,13 +661,12 @@ impl Token {
matches!(&**nt, matches!(&**nt,
| NtExpr(..) | NtExpr(..)
| NtLiteral(..) | NtLiteral(..)
| NtMeta(..)
| NtPath(..) | NtPath(..)
), ),
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
MetaVarKind::Expr { .. } | MetaVarKind::Expr { .. } |
MetaVarKind::Literal | MetaVarKind::Literal |
MetaVarKind::Meta | MetaVarKind::Meta { .. } |
MetaVarKind::Pat(_) | MetaVarKind::Pat(_) |
MetaVarKind::Path | MetaVarKind::Path |
MetaVarKind::Ty { .. } MetaVarKind::Ty { .. }
@ -1076,8 +1078,6 @@ pub enum Nonterminal {
NtStmt(P<ast::Stmt>), NtStmt(P<ast::Stmt>),
NtExpr(P<ast::Expr>), NtExpr(P<ast::Expr>),
NtLiteral(P<ast::Expr>), NtLiteral(P<ast::Expr>),
/// Stuff inside brackets for attributes
NtMeta(P<ast::AttrItem>),
NtPath(P<ast::Path>), NtPath(P<ast::Path>),
} }
@ -1171,7 +1171,6 @@ impl Nonterminal {
NtBlock(block) => block.span, NtBlock(block) => block.span,
NtStmt(stmt) => stmt.span, NtStmt(stmt) => stmt.span,
NtExpr(expr) | NtLiteral(expr) => expr.span, NtExpr(expr) | NtLiteral(expr) => expr.span,
NtMeta(attr_item) => attr_item.span(),
NtPath(path) => path.span, NtPath(path) => path.span,
} }
} }
@ -1183,7 +1182,6 @@ impl Nonterminal {
NtStmt(..) => "statement", NtStmt(..) => "statement",
NtExpr(..) => "expression", NtExpr(..) => "expression",
NtLiteral(..) => "literal", NtLiteral(..) => "literal",
NtMeta(..) => "attribute",
NtPath(..) => "path", NtPath(..) => "path",
} }
} }
@ -1207,7 +1205,6 @@ impl fmt::Debug for Nonterminal {
NtStmt(..) => f.pad("NtStmt(..)"), NtStmt(..) => f.pad("NtStmt(..)"),
NtExpr(..) => f.pad("NtExpr(..)"), NtExpr(..) => f.pad("NtExpr(..)"),
NtLiteral(..) => f.pad("NtLiteral(..)"), NtLiteral(..) => f.pad("NtLiteral(..)"),
NtMeta(..) => f.pad("NtMeta(..)"),
NtPath(..) => f.pad("NtPath(..)"), NtPath(..) => f.pad("NtPath(..)"),
} }
} }

View file

@ -468,7 +468,6 @@ impl TokenStream {
TokenStream::token_alone(token::Semi, stmt.span) TokenStream::token_alone(token::Semi, stmt.span)
} }
Nonterminal::NtStmt(stmt) => TokenStream::from_ast(stmt), Nonterminal::NtStmt(stmt) => TokenStream::from_ast(stmt),
Nonterminal::NtMeta(attr) => TokenStream::from_ast(attr),
Nonterminal::NtPath(path) => TokenStream::from_ast(path), Nonterminal::NtPath(path) => TokenStream::from_ast(path),
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr),
} }

View file

@ -481,15 +481,6 @@ impl<'a> MetaItemListParserContext<'a> {
self.inside_delimiters.peek() self.inside_delimiters.peek()
{ {
match &**nt { match &**nt {
// or maybe a full nt meta including the path but we return immediately
token::Nonterminal::NtMeta(item) => {
self.inside_delimiters.next();
return Some(MetaItemOrLitParser::MetaItemParser(MetaItemParser {
path: PathParser::Ast(&item.path),
args: ArgParser::from_attr_args(&item.args, self.dcx),
}));
}
// an already interpolated path from a macro expansion is a path, no need to parse // an already interpolated path from a macro expansion is a path, no need to parse
// one from tokens // one from tokens
token::Nonterminal::NtPath(path) => { token::Nonterminal::NtPath(path) => {

View file

@ -336,6 +336,14 @@ pub(super) fn transcribe<'a>(
TokenStream::from_ast(ty), TokenStream::from_ast(ty),
) )
} }
MatchedSingle(ParseNtResult::Meta(attr_item)) => {
let has_meta_form = attr_item.meta_kind().is_some();
mk_delimited(
attr_item.span(),
MetaVarKind::Meta { has_meta_form },
TokenStream::from_ast(attr_item),
)
}
MatchedSingle(ParseNtResult::Vis(vis)) => { MatchedSingle(ParseNtResult::Vis(vis)) => {
mk_delimited(vis.span, MetaVarKind::Vis, TokenStream::from_ast(vis)) mk_delimited(vis.span, MetaVarKind::Vis, TokenStream::from_ast(vis))
} }

View file

@ -424,7 +424,7 @@ parse_invalid_logical_operator = `{$incorrect}` is not a logical operator
.use_amp_amp_for_conjunction = use `&&` to perform logical conjunction .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction
.use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction .use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction
parse_invalid_meta_item = expected unsuffixed literal, found `{$token}` parse_invalid_meta_item = expected unsuffixed literal, found {$descr}
.quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal .quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal
parse_invalid_offset_of = offset_of expects dot-separated field and variant names parse_invalid_offset_of = offset_of expects dot-separated field and variant names

View file

@ -1024,7 +1024,7 @@ pub(crate) struct SuffixedLiteralInAttribute {
pub(crate) struct InvalidMetaItem { pub(crate) struct InvalidMetaItem {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
pub token: Token, pub descr: String,
#[subdiagnostic] #[subdiagnostic]
pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>, pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>,
} }

View file

@ -1,4 +1,6 @@
use rustc_ast::{self as ast, Attribute, attr, token}; use rustc_ast as ast;
use rustc_ast::token::{self, MetaVarKind};
use rustc_ast::{Attribute, attr};
use rustc_errors::codes::*; use rustc_errors::codes::*;
use rustc_errors::{Diag, PResult}; use rustc_errors::{Diag, PResult};
use rustc_span::{BytePos, Span}; use rustc_span::{BytePos, Span};
@ -9,7 +11,7 @@ use super::{
AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, ParserRange, PathStyle, Trailing, AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, ParserRange, PathStyle, Trailing,
UsePreAttrPos, UsePreAttrPos,
}; };
use crate::{errors, exp, fluent_generated as fluent, maybe_whole}; use crate::{errors, exp, fluent_generated as fluent};
// Public for rustfmt usage // Public for rustfmt usage
#[derive(Debug)] #[derive(Debug)]
@ -269,7 +271,12 @@ impl<'a> Parser<'a> {
/// PATH `=` UNSUFFIXED_LIT /// PATH `=` UNSUFFIXED_LIT
/// The delimiters or `=` are still put into the resulting token stream. /// The delimiters or `=` are still put into the resulting token stream.
pub fn parse_attr_item(&mut self, force_collect: ForceCollect) -> PResult<'a, ast::AttrItem> { pub fn parse_attr_item(&mut self, force_collect: ForceCollect) -> PResult<'a, ast::AttrItem> {
maybe_whole!(self, NtMeta, |attr| attr.into_inner()); if let Some(item) = self.eat_metavar_seq_with_matcher(
|mv_kind| matches!(mv_kind, MetaVarKind::Meta { .. }),
|this| this.parse_attr_item(force_collect),
) {
return Ok(item);
}
// Attr items don't have attributes. // Attr items don't have attributes.
self.collect_tokens(None, AttrWrapper::empty(), force_collect, |this, _empty_attrs| { self.collect_tokens(None, AttrWrapper::empty(), force_collect, |this, _empty_attrs| {
@ -396,18 +403,17 @@ impl<'a> Parser<'a> {
&mut self, &mut self,
unsafe_allowed: AllowLeadingUnsafe, unsafe_allowed: AllowLeadingUnsafe,
) -> PResult<'a, ast::MetaItem> { ) -> PResult<'a, ast::MetaItem> {
// We can't use `maybe_whole` here because it would bump in the `None` if let Some(MetaVarKind::Meta { has_meta_form }) = self.token.is_metavar_seq() {
// case, which we don't want. return if has_meta_form {
if let token::Interpolated(nt) = &self.token.kind let attr_item = self
&& let token::NtMeta(attr_item) = &**nt .eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| {
{ this.parse_attr_item(ForceCollect::No)
match attr_item.meta(attr_item.path.span) { })
Some(meta) => { .unwrap();
self.bump(); Ok(attr_item.meta(attr_item.path.span).unwrap())
return Ok(meta); } else {
} self.unexpected_any()
None => self.unexpected()?, };
}
} }
let lo = self.token.span; let lo = self.token.span;
@ -464,7 +470,7 @@ impl<'a> Parser<'a> {
let mut err = errors::InvalidMetaItem { let mut err = errors::InvalidMetaItem {
span: self.token.span, span: self.token.span,
token: self.token.clone(), descr: super::token_descr(&self.token),
quote_ident_sugg: None, quote_ident_sugg: None,
}; };

View file

@ -1748,6 +1748,7 @@ pub enum ParseNtResult {
Lifetime(Ident, IdentIsRaw), Lifetime(Ident, IdentIsRaw),
Pat(P<ast::Pat>, NtPatKind), Pat(P<ast::Pat>, NtPatKind),
Ty(P<ast::Ty>), Ty(P<ast::Ty>),
Meta(P<ast::AttrItem>),
Vis(P<ast::Visibility>), Vis(P<ast::Visibility>),
/// This variant will eventually be removed, along with `Token::Interpolate`. /// This variant will eventually be removed, along with `Token::Interpolate`.

View file

@ -32,7 +32,7 @@ impl<'a> Parser<'a> {
| MetaVarKind::Expr { .. } | MetaVarKind::Expr { .. }
| MetaVarKind::Ty { .. } | MetaVarKind::Ty { .. }
| MetaVarKind::Literal // `true`, `false` | MetaVarKind::Literal // `true`, `false`
| MetaVarKind::Meta | MetaVarKind::Meta { .. }
| MetaVarKind::Path => true, | MetaVarKind::Path => true,
MetaVarKind::Item MetaVarKind::Item
@ -51,7 +51,6 @@ impl<'a> Parser<'a> {
NtStmt(_) NtStmt(_)
| NtExpr(_) | NtExpr(_)
| NtLiteral(_) // `true`, `false` | NtLiteral(_) // `true`, `false`
| NtMeta(_)
| NtPath(_) => true, | NtPath(_) => true,
NtItem(_) | NtBlock(_) => false, NtItem(_) | NtBlock(_) => false,
@ -98,7 +97,7 @@ impl<'a> Parser<'a> {
token::NtLifetime(..) => true, token::NtLifetime(..) => true,
token::Interpolated(nt) => match &**nt { token::Interpolated(nt) => match &**nt {
NtBlock(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true, NtBlock(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true,
NtItem(_) | NtMeta(_) | NtPath(_) => false, NtItem(_) | NtPath(_) => false,
}, },
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k { token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k {
MetaVarKind::Block MetaVarKind::Block
@ -108,7 +107,7 @@ impl<'a> Parser<'a> {
MetaVarKind::Item MetaVarKind::Item
| MetaVarKind::Pat(_) | MetaVarKind::Pat(_)
| MetaVarKind::Ty { .. } | MetaVarKind::Ty { .. }
| MetaVarKind::Meta | MetaVarKind::Meta { .. }
| MetaVarKind::Path | MetaVarKind::Path
| MetaVarKind::Vis => false, | MetaVarKind::Vis => false,
MetaVarKind::Lifetime | MetaVarKind::Ident | MetaVarKind::TT => { MetaVarKind::Lifetime | MetaVarKind::Ident | MetaVarKind::TT => {
@ -207,7 +206,9 @@ impl<'a> Parser<'a> {
NonterminalKind::Path => { NonterminalKind::Path => {
NtPath(P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?)) NtPath(P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?))
} }
NonterminalKind::Meta => NtMeta(P(self.parse_attr_item(ForceCollect::Yes)?)), NonterminalKind::Meta => {
return Ok(ParseNtResult::Meta(P(self.parse_attr_item(ForceCollect::Yes)?)));
}
NonterminalKind::Vis => { NonterminalKind::Vis => {
return Ok(ParseNtResult::Vis(P(self.collect_tokens_no_attrs(|this| { return Ok(ParseNtResult::Vis(P(self.collect_tokens_no_attrs(|this| {
this.parse_visibility(FollowedByType::Yes) this.parse_visibility(FollowedByType::Yes)

View file

@ -5,7 +5,7 @@
macro_rules! pass_nonterminal { macro_rules! pass_nonterminal {
($n:expr) => { ($n:expr) => {
#[repr(align($n))] #[repr(align($n))]
//~^ ERROR expected unsuffixed literal, found `n!()` //~^ ERROR expected unsuffixed literal, found expression `n!()`
//~^^ ERROR incorrect `repr(align)` attribute format: `align` expects a literal integer as argument [E0693] //~^^ ERROR incorrect `repr(align)` attribute format: `align` expects a literal integer as argument [E0693]
struct S; struct S;
}; };

View file

@ -1,4 +1,4 @@
error: expected unsuffixed literal, found `n!()` error: expected unsuffixed literal, found expression `n!()`
--> $DIR/nonterminal-expansion.rs:7:22 --> $DIR/nonterminal-expansion.rs:7:22
| |
LL | #[repr(align($n))] LL | #[repr(align($n))]

View file

@ -28,8 +28,8 @@ struct S9;
macro_rules! generate_s10 { macro_rules! generate_s10 {
($expr: expr) => { ($expr: expr) => {
#[cfg(feature = $expr)] #[cfg(feature = $expr)]
//~^ ERROR expected unsuffixed literal, found `concat!("nonexistent")` //~^ ERROR expected unsuffixed literal, found expression `concat!("nonexistent")`
//~| ERROR expected unsuffixed literal, found `concat!("nonexistent")` //~| ERROR expected unsuffixed literal, found expression `concat!("nonexistent")`
struct S10; struct S10;
} }
} }

View file

@ -54,7 +54,7 @@ LL | #[cfg(a = b"hi")]
| | | |
| help: consider removing the prefix | help: consider removing the prefix
error: expected unsuffixed literal, found `concat!("nonexistent")` error: expected unsuffixed literal, found expression `concat!("nonexistent")`
--> $DIR/cfg-attr-syntax-validation.rs:30:25 --> $DIR/cfg-attr-syntax-validation.rs:30:25
| |
LL | #[cfg(feature = $expr)] LL | #[cfg(feature = $expr)]
@ -65,7 +65,7 @@ LL | generate_s10!(concat!("nonexistent"));
| |
= note: this error originates in the macro `generate_s10` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `generate_s10` (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected unsuffixed literal, found `concat!("nonexistent")` error: expected unsuffixed literal, found expression `concat!("nonexistent")`
--> $DIR/cfg-attr-syntax-validation.rs:30:25 --> $DIR/cfg-attr-syntax-validation.rs:30:25
| |
LL | #[cfg(feature = $expr)] LL | #[cfg(feature = $expr)]

View file

@ -1,8 +1,8 @@
macro_rules! mac { macro_rules! mac {
($attr_item: meta) => { ($attr_item: meta) => {
#[cfg($attr_item)] #[cfg($attr_item)]
//~^ ERROR expected unsuffixed literal, found `an(arbitrary token stream)` //~^ ERROR expected unsuffixed literal, found `meta` metavariable
//~| ERROR expected unsuffixed literal, found `an(arbitrary token stream)` //~| ERROR expected unsuffixed literal, found `meta` metavariable
struct S; struct S;
} }
} }

View file

@ -4,7 +4,7 @@ error: expected unsuffixed literal, found `-`
LL | #[cfg(feature = -1)] LL | #[cfg(feature = -1)]
| ^ | ^
error: expected unsuffixed literal, found `an(arbitrary token stream)` error: expected unsuffixed literal, found `meta` metavariable
--> $DIR/attr-bad-meta-4.rs:3:15 --> $DIR/attr-bad-meta-4.rs:3:15
| |
LL | #[cfg($attr_item)] LL | #[cfg($attr_item)]
@ -15,7 +15,7 @@ LL | mac!(an(arbitrary token stream));
| |
= note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected unsuffixed literal, found `an(arbitrary token stream)` error: expected unsuffixed literal, found `meta` metavariable
--> $DIR/attr-bad-meta-4.rs:3:15 --> $DIR/attr-bad-meta-4.rs:3:15
| |
LL | #[cfg($attr_item)] LL | #[cfg($attr_item)]

View file

@ -19,7 +19,7 @@ fn main() {
macro_rules! make { macro_rules! make {
($name:ident) => { #[doc(alias = $name)] pub struct S; } ($name:ident) => { #[doc(alias = $name)] pub struct S; }
//~^ ERROR expected unsuffixed literal, found `nickname` //~^ ERROR expected unsuffixed literal, found identifier `nickname`
} }
make!(nickname); //~ NOTE in this expansion make!(nickname); //~ NOTE in this expansion

View file

@ -20,7 +20,7 @@ help: surround the identifier with quotation marks to make it into a string lite
LL | #[cfg(key="foo bar baz")] LL | #[cfg(key="foo bar baz")]
| + + | + +
error: expected unsuffixed literal, found `nickname` error: expected unsuffixed literal, found identifier `nickname`
--> $DIR/attr-unquoted-ident.rs:21:38 --> $DIR/attr-unquoted-ident.rs:21:38
| |
LL | ($name:ident) => { #[doc(alias = $name)] pub struct S; } LL | ($name:ident) => { #[doc(alias = $name)] pub struct S; }