1
Fork 0

Remove NtTy.

Notes about tests:

- tests/ui/parser/macro/trait-object-macro-matcher.rs: the syntax error
  is duplicated, because it occurs now when parsing the decl macro
  input, and also when parsing the expanded decl macro. But this won't
  show up for normal users due to error de-duplication.

- tests/ui/associated-consts/issue-93835.rs: similar, plus there are
  some additional errors about this very broken code.

- The changes to metavariable descriptions in #132629 are now visible in
  error message for several tests.
This commit is contained in:
Nicholas Nethercote 2024-04-17 13:17:44 +10:00
parent c7981d6411
commit 76b04437be
19 changed files with 112 additions and 51 deletions

View file

@ -203,7 +203,6 @@ impl HasTokens for Nonterminal {
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::NtPat(pat) => pat.tokens(), Nonterminal::NtPat(pat) => pat.tokens(),
Nonterminal::NtTy(ty) => ty.tokens(),
Nonterminal::NtMeta(attr_item) => attr_item.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(),
@ -215,7 +214,6 @@ impl HasTokens for Nonterminal {
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::NtPat(pat) => pat.tokens_mut(), Nonterminal::NtPat(pat) => pat.tokens_mut(),
Nonterminal::NtTy(ty) => ty.tokens_mut(),
Nonterminal::NtMeta(attr_item) => attr_item.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

@ -907,7 +907,6 @@ fn visit_nonterminal<T: MutVisitor>(vis: &mut T, nt: &mut token::Nonterminal) {
}), }),
token::NtPat(pat) => vis.visit_pat(pat), token::NtPat(pat) => vis.visit_pat(pat),
token::NtExpr(expr) => vis.visit_expr(expr), token::NtExpr(expr) => vis.visit_expr(expr),
token::NtTy(ty) => vis.visit_ty(ty),
token::NtLiteral(expr) => vis.visit_expr(expr), token::NtLiteral(expr) => vis.visit_expr(expr),
token::NtMeta(item) => { token::NtMeta(item) => {
let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut(); let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut();

View file

@ -659,7 +659,6 @@ impl Token {
| NtMeta(..) | NtMeta(..)
| NtPat(..) | NtPat(..)
| NtPath(..) | NtPath(..)
| NtTy(..)
), ),
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
MetaVarKind::Expr { .. } | MetaVarKind::Expr { .. } |
@ -688,7 +687,7 @@ impl Token {
Lifetime(..) | // lifetime bound in trait object Lifetime(..) | // lifetime bound in trait object
Lt | BinOp(Shl) | // associated path Lt | BinOp(Shl) | // associated path
PathSep => true, // global path PathSep => true, // global path
Interpolated(ref nt) => matches!(&**nt, NtTy(..) | NtPath(..)), Interpolated(ref nt) => matches!(&**nt, NtPath(..)),
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
MetaVarKind::Ty | MetaVarKind::Ty |
MetaVarKind::Path MetaVarKind::Path
@ -1076,7 +1075,6 @@ pub enum Nonterminal {
NtStmt(P<ast::Stmt>), NtStmt(P<ast::Stmt>),
NtPat(P<ast::Pat>), NtPat(P<ast::Pat>),
NtExpr(P<ast::Expr>), NtExpr(P<ast::Expr>),
NtTy(P<ast::Ty>),
NtLiteral(P<ast::Expr>), NtLiteral(P<ast::Expr>),
/// Stuff inside brackets for attributes /// Stuff inside brackets for attributes
NtMeta(P<ast::AttrItem>), NtMeta(P<ast::AttrItem>),
@ -1174,7 +1172,6 @@ impl Nonterminal {
NtStmt(stmt) => stmt.span, NtStmt(stmt) => stmt.span,
NtPat(pat) => pat.span, NtPat(pat) => pat.span,
NtExpr(expr) | NtLiteral(expr) => expr.span, NtExpr(expr) | NtLiteral(expr) => expr.span,
NtTy(ty) => ty.span,
NtMeta(attr_item) => attr_item.span(), NtMeta(attr_item) => attr_item.span(),
NtPath(path) => path.span, NtPath(path) => path.span,
} }
@ -1188,7 +1185,6 @@ impl Nonterminal {
NtPat(..) => "pattern", NtPat(..) => "pattern",
NtExpr(..) => "expression", NtExpr(..) => "expression",
NtLiteral(..) => "literal", NtLiteral(..) => "literal",
NtTy(..) => "type",
NtMeta(..) => "attribute", NtMeta(..) => "attribute",
NtPath(..) => "path", NtPath(..) => "path",
} }
@ -1213,7 +1209,6 @@ impl fmt::Debug for Nonterminal {
NtStmt(..) => f.pad("NtStmt(..)"), NtStmt(..) => f.pad("NtStmt(..)"),
NtPat(..) => f.pad("NtPat(..)"), NtPat(..) => f.pad("NtPat(..)"),
NtExpr(..) => f.pad("NtExpr(..)"), NtExpr(..) => f.pad("NtExpr(..)"),
NtTy(..) => f.pad("NtTy(..)"),
NtLiteral(..) => f.pad("NtLiteral(..)"), NtLiteral(..) => f.pad("NtLiteral(..)"),
NtMeta(..) => f.pad("NtMeta(..)"), NtMeta(..) => f.pad("NtMeta(..)"),
NtPath(..) => f.pad("NtPath(..)"), NtPath(..) => f.pad("NtPath(..)"),

View file

@ -469,7 +469,6 @@ impl TokenStream {
} }
Nonterminal::NtStmt(stmt) => TokenStream::from_ast(stmt), Nonterminal::NtStmt(stmt) => TokenStream::from_ast(stmt),
Nonterminal::NtPat(pat) => TokenStream::from_ast(pat), Nonterminal::NtPat(pat) => TokenStream::from_ast(pat),
Nonterminal::NtTy(ty) => TokenStream::from_ast(ty),
Nonterminal::NtMeta(attr) => TokenStream::from_ast(attr), 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

@ -322,6 +322,9 @@ pub(super) fn transcribe<'a>(
let kind = token::NtLifetime(*ident, *is_raw); let kind = token::NtLifetime(*ident, *is_raw);
TokenTree::token_alone(kind, sp) TokenTree::token_alone(kind, sp)
} }
MatchedSingle(ParseNtResult::Ty(ty)) => {
mk_delimited(MetaVarKind::Ty, TokenStream::from_ast(ty))
}
MatchedSingle(ParseNtResult::Vis(vis)) => { MatchedSingle(ParseNtResult::Vis(vis)) => {
mk_delimited(MetaVarKind::Vis, TokenStream::from_ast(vis)) mk_delimited(MetaVarKind::Vis, TokenStream::from_ast(vis))
} }

View file

@ -117,12 +117,16 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath {
($self: expr, $allow_qpath_recovery: expr) => { ($self: expr, $allow_qpath_recovery: expr) => {
if $allow_qpath_recovery if $allow_qpath_recovery
&& $self.may_recover() && $self.may_recover()
&& $self.look_ahead(1, |t| t == &token::PathSep) && let Some(token::MetaVarKind::Ty) = $self.token.is_metavar_seq()
&& let token::Interpolated(nt) = &$self.token.kind && $self.check_noexpect_past_close_delim(&token::PathSep)
&& let token::NtTy(ty) = &**nt
{ {
let ty = ty.clone(); // Reparse the type, then move to recovery.
$self.bump(); let ty = $self
.eat_metavar_seq(token::MetaVarKind::Ty, |this| {
this.parse_ty_no_question_mark_recover()
})
.expect("metavar seq ty");
return $self.maybe_recover_from_bad_qpath_stage_2($self.prev_token.span, ty); return $self.maybe_recover_from_bad_qpath_stage_2($self.prev_token.span, ty);
} }
}; };
@ -614,6 +618,24 @@ impl<'a> Parser<'a> {
self.token == *tok self.token == *tok
} }
// Check the first token after the delimiter that closes the current
// delimited sequence. (Panics if used in the outermost token stream, which
// has no delimiters.) It uses a clone of the relevant tree cursor to skip
// past the entire `TokenTree::Delimited` in a single step, avoiding the
// need for unbounded token lookahead.
//
// Primarily used when `self.token` matches
// `OpenDelim(Delimiter::Invisible(_))`, to look ahead through the current
// metavar expansion.
fn check_noexpect_past_close_delim(&self, tok: &TokenKind) -> bool {
let mut tree_cursor = self.token_cursor.stack.last().unwrap().clone();
tree_cursor.bump();
matches!(
tree_cursor.curr(),
Some(TokenTree::Token(token::Token { kind, .. }, _)) if kind == tok
)
}
/// Consumes a token 'tok' if it exists. Returns whether the given token was present. /// Consumes a token 'tok' if it exists. Returns whether the given token was present.
/// ///
/// the main purpose of this function is to reduce the cluttering of the suggestions list /// the main purpose of this function is to reduce the cluttering of the suggestions list
@ -1724,6 +1746,7 @@ pub enum ParseNtResult {
Tt(TokenTree), Tt(TokenTree),
Ident(Ident, IdentIsRaw), Ident(Ident, IdentIsRaw),
Lifetime(Ident, IdentIsRaw), Lifetime(Ident, IdentIsRaw),
Ty(P<ast::Ty>),
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

@ -51,7 +51,6 @@ impl<'a> Parser<'a> {
NtStmt(_) NtStmt(_)
| NtPat(_) | NtPat(_)
| NtExpr(_) | NtExpr(_)
| NtTy(_)
| NtLiteral(_) // `true`, `false` | NtLiteral(_) // `true`, `false`
| NtMeta(_) | NtMeta(_)
| NtPath(_) => true, | NtPath(_) => true,
@ -100,7 +99,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(_) | NtPat(_) | NtTy(_) | NtMeta(_) | NtPath(_) => false, NtItem(_) | NtPat(_) | NtMeta(_) | NtPath(_) => false,
}, },
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k { token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k {
MetaVarKind::Block MetaVarKind::Block
@ -187,7 +186,9 @@ impl<'a> Parser<'a> {
NtLiteral(self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?) NtLiteral(self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?)
} }
NonterminalKind::Ty => { NonterminalKind::Ty => {
NtTy(self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?) return Ok(ParseNtResult::Ty(
self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?,
));
} }
// this could be handled like a token, since it is one // this could be handled like a token, since it is one
NonterminalKind::Ident => { NonterminalKind::Ident => {

View file

@ -2,7 +2,7 @@ use std::mem;
use ast::token::IdentIsRaw; use ast::token::IdentIsRaw;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::token::{self, Delimiter, MetaVarKind, Token, TokenKind};
use rustc_ast::{ use rustc_ast::{
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemConstraint, self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemConstraint,
AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs, AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
@ -196,15 +196,16 @@ impl<'a> Parser<'a> {
maybe_whole!(self, NtPath, |path| reject_generics_if_mod_style(self, path.into_inner())); maybe_whole!(self, NtPath, |path| reject_generics_if_mod_style(self, path.into_inner()));
if let token::Interpolated(nt) = &self.token.kind { if let Some(MetaVarKind::Ty) = self.token.is_metavar_seq() {
if let token::NtTy(ty) = &**nt { let mut snapshot = self.create_snapshot_for_diagnostic();
if let ast::TyKind::Path(None, path) = &ty.kind { let ty = snapshot
let path = path.clone(); .eat_metavar_seq(MetaVarKind::Ty, |this| this.parse_ty_no_question_mark_recover())
self.bump(); .expect("metavar seq ty");
if let ast::TyKind::Path(None, path) = ty.into_inner().kind {
self.restore_snapshot(snapshot);
return Ok(reject_generics_if_mod_style(self, path)); return Ok(reject_generics_if_mod_style(self, path));
} }
} }
}
let lo = self.token.span; let lo = self.token.span;
let mut segments = ThinVec::new(); let mut segments = ThinVec::new();

View file

@ -1,5 +1,5 @@
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token, TokenKind}; use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, MetaVarKind, Token, TokenKind};
use rustc_ast::util::case::Case; use rustc_ast::util::case::Case;
use rustc_ast::{ use rustc_ast::{
self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy, self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy,
@ -18,7 +18,7 @@ use crate::errors::{
HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
NestedCVariadicType, ReturnTypesUseThinArrow, NestedCVariadicType, ReturnTypesUseThinArrow,
}; };
use crate::{exp, maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use crate::{exp, maybe_recover_from_interpolated_ty_qpath};
/// Signals whether parsing a type should allow `+`. /// Signals whether parsing a type should allow `+`.
/// ///
@ -183,7 +183,8 @@ impl<'a> Parser<'a> {
) )
} }
/// Parse a type without recovering `:` as `->` to avoid breaking code such as `where fn() : for<'a>` /// Parse a type without recovering `:` as `->` to avoid breaking code such
/// as `where fn() : for<'a>`.
pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P<Ty>> { pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P<Ty>> {
self.parse_ty_common( self.parse_ty_common(
AllowPlus::Yes, AllowPlus::Yes,
@ -247,7 +248,12 @@ impl<'a> Parser<'a> {
) -> PResult<'a, P<Ty>> { ) -> PResult<'a, P<Ty>> {
let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes; let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery); maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
maybe_whole!(self, NtTy, |ty| ty);
if let Some(ty) =
self.eat_metavar_seq(MetaVarKind::Ty, |this| this.parse_ty_no_question_mark_recover())
{
return Ok(ty);
}
let lo = self.token.span; let lo = self.token.span;
let mut impl_dyn_multi = false; let mut impl_dyn_multi = false;

View file

@ -3,9 +3,11 @@
fn e() { fn e() {
type_ascribe!(p, a<p:p<e=6>>); type_ascribe!(p, a<p:p<e=6>>);
//~^ ERROR cannot find type `a` in this scope //~^ ERROR cannot find type `a` in this scope
//~| ERROR path separator must be a double colon
//~| ERROR cannot find value //~| ERROR cannot find value
//~| ERROR associated const equality //~| ERROR associated const equality
//~| ERROR cannot find trait `p` in this scope //~| ERROR associated const equality
//~| ERROR failed to resolve: use of unresolved module or unlinked crate `p`
} }
fn main() {} fn main() {}

View file

@ -1,3 +1,15 @@
error: path separator must be a double colon
--> $DIR/issue-93835.rs:4:25
|
LL | type_ascribe!(p, a<p:p<e=6>>);
| ^
|
= note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
help: use a double colon instead
|
LL | type_ascribe!(p, a<p::p<e=6>>);
| +
error[E0425]: cannot find value `p` in this scope error[E0425]: cannot find value `p` in this scope
--> $DIR/issue-93835.rs:4:19 --> $DIR/issue-93835.rs:4:19
| |
@ -10,12 +22,6 @@ error[E0412]: cannot find type `a` in this scope
LL | type_ascribe!(p, a<p:p<e=6>>); LL | type_ascribe!(p, a<p:p<e=6>>);
| ^ not found in this scope | ^ not found in this scope
error[E0405]: cannot find trait `p` in this scope
--> $DIR/issue-93835.rs:4:26
|
LL | type_ascribe!(p, a<p:p<e=6>>);
| ^ not found in this scope
error[E0658]: associated const equality is incomplete error[E0658]: associated const equality is incomplete
--> $DIR/issue-93835.rs:4:28 --> $DIR/issue-93835.rs:4:28
| |
@ -26,7 +32,26 @@ LL | type_ascribe!(p, a<p:p<e=6>>);
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 4 previous errors error[E0658]: associated const equality is incomplete
--> $DIR/issue-93835.rs:4:28
|
LL | type_ascribe!(p, a<p:p<e=6>>);
| ^^^
|
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
Some errors have detailed explanations: E0405, E0412, E0425, E0658. error[E0433]: failed to resolve: use of unresolved module or unlinked crate `p`
For more information about an error, try `rustc --explain E0405`. --> $DIR/issue-93835.rs:4:24
|
LL | type_ascribe!(p, a<p:p<e=6>>);
| ^ use of unresolved module or unlinked crate `p`
|
= help: you might be missing a crate named `p`
error: aborting due to 6 previous errors
Some errors have detailed explanations: E0412, E0425, E0433, E0658.
For more information about an error, try `rustc --explain E0412`.

View file

@ -19,7 +19,7 @@ macro_rules! qpath {
(ty, <$type:ty as $trait:ty>::$name:ident) => { (ty, <$type:ty as $trait:ty>::$name:ident) => {
<$type as $trait>::$name <$type as $trait>::$name
//~^ ERROR expected identifier, found `!` //~^ ERROR expected identifier, found metavariable
}; };
} }

View file

@ -1,8 +1,8 @@
error: expected identifier, found `!` error: expected identifier, found metavariable
--> $DIR/macro-interpolation.rs:21:19 --> $DIR/macro-interpolation.rs:21:19
| |
LL | <$type as $trait>::$name LL | <$type as $trait>::$name
| ^^^^^^ expected identifier | ^^^^^^ expected identifier, found metavariable
... ...
LL | let _: qpath!(ty, <str as !>::Owned); LL | let _: qpath!(ty, <str as !>::Owned);
| ----------------------------- | -----------------------------

View file

@ -9,8 +9,8 @@ macro_rules! values {
} }
}; };
} }
//~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found type `(String)` //~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `ty` metavariable
//~| ERROR macro expansion ignores type `(String)` and any tokens following //~| ERROR macro expansion ignores `ty` metavariable and any tokens following
values!(STRING(1) as (String) => cfg(test),); values!(STRING(1) as (String) => cfg(test),);
//~^ ERROR expected one of `!` or `::`, found `<eof>` //~^ ERROR expected one of `!` or `::`, found `<eof>`

View file

@ -1,4 +1,4 @@
error: expected one of `(`, `,`, `=`, `{`, or `}`, found type `(String)` error: expected one of `(`, `,`, `=`, `{`, or `}`, found `ty` metavariable
--> $DIR/syntax-error-recovery.rs:7:26 --> $DIR/syntax-error-recovery.rs:7:26
| |
LL | $token $($inner)? = $value, LL | $token $($inner)? = $value,
@ -10,7 +10,7 @@ LL | values!(STRING(1) as (String) => cfg(test),);
= help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
= note: this error originates in the macro `values` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `values` (in Nightly builds, run with -Z macro-backtrace for more info)
error: macro expansion ignores type `(String)` and any tokens following error: macro expansion ignores `ty` metavariable and any tokens following
--> $DIR/syntax-error-recovery.rs:7:26 --> $DIR/syntax-error-recovery.rs:7:26
| |
LL | $token $($inner)? = $value, LL | $token $($inner)? = $value,

View file

@ -1,7 +1,7 @@
macro_rules! test_macro { macro_rules! test_macro {
( $( $t:ty ),* $(),*) => { ( $( $t:ty ),* $(),*) => {
enum SomeEnum { enum SomeEnum {
$( $t, )* //~ ERROR expected identifier, found `String` $( $t, )* //~ ERROR expected identifier, found metavariable
}; };
}; };
} }

View file

@ -1,10 +1,10 @@
error: expected identifier, found `String` error: expected identifier, found metavariable
--> $DIR/issue-37113.rs:4:16 --> $DIR/issue-37113.rs:4:16
| |
LL | enum SomeEnum { LL | enum SomeEnum {
| -------- while parsing this enum | -------- while parsing this enum
LL | $( $t, )* LL | $( $t, )*
| ^^ expected identifier | ^^ expected identifier, found metavariable
... ...
LL | test_macro!(String,); LL | test_macro!(String,);
| -------------------- in this macro invocation | -------------------- in this macro invocation

View file

@ -10,5 +10,6 @@ macro_rules! m {
fn main() { fn main() {
m!('static); m!('static);
//~^ ERROR lifetime in trait object type must be followed by `+` //~^ ERROR lifetime in trait object type must be followed by `+`
//~| ERROR lifetime in trait object type must be followed by `+`
//~| ERROR at least one trait is required for an object type //~| ERROR at least one trait is required for an object type
} }

View file

@ -4,12 +4,20 @@ error: lifetime in trait object type must be followed by `+`
LL | m!('static); LL | m!('static);
| ^^^^^^^ | ^^^^^^^
error: lifetime in trait object type must be followed by `+`
--> $DIR/trait-object-macro-matcher.rs:11:8
|
LL | m!('static);
| ^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0224]: at least one trait is required for an object type error[E0224]: at least one trait is required for an object type
--> $DIR/trait-object-macro-matcher.rs:11:8 --> $DIR/trait-object-macro-matcher.rs:11:8
| |
LL | m!('static); LL | m!('static);
| ^^^^^^^ | ^^^^^^^
error: aborting due to 2 previous errors error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0224`. For more information about this error, try `rustc --explain E0224`.