Rollup merge of #153702 - SpriteOvO:guard-matcher, r=davidtwco

Add macro matcher for `guard` fragment specifier

Tracking issue #153104

This PR implements a new `guard` macro matcher to match `if-let` guards (specifically [`MatchArmGuard`](https://github.com/rust-lang/reference/blob/50a1075e879be75aeec436252c84eef0fad489f4/src/expressions/match-expr.md#match-guards)). In the upcoming PR, we can use this new matcher in the `matches!` and `assert_matches!` macros to support their use with `if-let` guards. (see #152313)

The original `Expr` used to represent a guard has been wrapped in a new `Guard` type, allowing us to carry the span information of the leading `if` keyword. However, it might be even better to include the `if` keyword in the `Guard` type as well? I've left a FIXME comment in the code.
This commit is contained in:
Jonathan Brouwer
2026-03-25 19:52:50 +01:00
committed by GitHub
29 changed files with 441 additions and 196 deletions
+14 -2
View File
@@ -938,7 +938,7 @@ pub enum PatKind {
Never,
/// A guard pattern (e.g., `x if guard(x)`).
Guard(Box<Pat>, Box<Expr>),
Guard(Box<Pat>, Box<Guard>),
/// Parentheses in patterns used for grouping (i.e., `(PAT)`).
Paren(Box<Pat>),
@@ -1346,7 +1346,7 @@ pub struct Arm {
/// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }`.
pub pat: Box<Pat>,
/// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }`.
pub guard: Option<Box<Expr>>,
pub guard: Option<Box<Guard>>,
/// Match arm body. Omitted if the pattern is a never pattern.
pub body: Option<Box<Expr>>,
pub span: Span,
@@ -3954,6 +3954,18 @@ impl ConstBlockItem {
pub const IDENT: Ident = Ident { name: kw::Underscore, span: DUMMY_SP };
}
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub struct Guard {
pub cond: Expr,
pub span_with_leading_if: Span,
}
impl Guard {
pub fn span(&self) -> Span {
self.cond.span
}
}
// Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`.
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum ItemKind {
+5
View File
@@ -94,6 +94,7 @@ pub enum MetaVarKind {
},
Path,
Vis,
Guard,
TT,
}
@@ -114,6 +115,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
MetaVarKind::Meta { .. } => sym::meta,
MetaVarKind::Path => sym::path,
MetaVarKind::Vis => sym::vis,
MetaVarKind::Guard => sym::guard,
MetaVarKind::TT => sym::tt,
};
write!(f, "{sym}")
@@ -1124,6 +1126,7 @@ pub enum NonterminalKind {
Meta,
Path,
Vis,
Guard,
TT,
}
@@ -1161,6 +1164,7 @@ pub fn from_symbol(
sym::meta => NonterminalKind::Meta,
sym::path => NonterminalKind::Path,
sym::vis => NonterminalKind::Vis,
sym::guard => NonterminalKind::Guard,
sym::tt => NonterminalKind::TT,
_ => return None,
})
@@ -1182,6 +1186,7 @@ fn symbol(self) -> Symbol {
NonterminalKind::Meta => sym::meta,
NonterminalKind::Path => sym::path,
NonterminalKind::Vis => sym::vis,
NonterminalKind::Guard => sym::guard,
NonterminalKind::TT => sym::tt,
}
}
+1
View File
@@ -442,6 +442,7 @@ pub fn ctxt(&self) -> Option<FnCtxt> {
FormatArguments,
FormatPlaceholder,
GenericParamKind,
Guard,
Impl,
ImplPolarity,
Inline,
+2 -2
View File
@@ -640,7 +640,7 @@ fn wrap_in_try_constructor(
fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
let pat = self.lower_pat(&arm.pat);
let guard = arm.guard.as_ref().map(|cond| self.lower_expr(cond));
let guard = arm.guard.as_ref().map(|guard| self.lower_expr(&guard.cond));
let hir_id = self.next_id();
let span = self.lower_span(arm.span);
self.lower_attrs(hir_id, &arm.attrs, arm.span, Target::Arm);
@@ -663,7 +663,7 @@ fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
} else if let Some(body) = &arm.body {
self.dcx().emit_err(NeverPatternWithBody { span: body.span });
} else if let Some(g) = &arm.guard {
self.dcx().emit_err(NeverPatternWithGuard { span: g.span });
self.dcx().emit_err(NeverPatternWithGuard { span: g.span() });
}
// We add a fake `loop {}` arm body so that it typecks to `!`. The mir lowering of never
+5 -2
View File
@@ -133,8 +133,11 @@ fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> {
self.lower_range_end(end, e2.is_some()),
);
}
PatKind::Guard(inner, cond) => {
break hir::PatKind::Guard(self.lower_pat(inner), self.lower_expr(cond));
PatKind::Guard(inner, guard) => {
break hir::PatKind::Guard(
self.lower_pat(inner),
self.lower_expr(&guard.cond),
);
}
PatKind::Slice(pats) => break self.lower_pat_slice(pats),
PatKind::Rest => {
@@ -1943,12 +1943,12 @@ fn print_pat(&mut self, pat: &ast::Pat) {
self.print_expr(e, FixupContext::default());
}
}
PatKind::Guard(subpat, condition) => {
PatKind::Guard(subpat, guard) => {
self.popen();
self.print_pat(subpat);
self.space();
self.word_space("if");
self.print_expr(condition, FixupContext::default());
self.print_expr(&guard.cond, FixupContext::default());
self.pclose();
}
PatKind::Slice(elts) => {
@@ -891,9 +891,9 @@ fn print_arm(&mut self, arm: &ast::Arm) {
self.print_outer_attributes(&arm.attrs);
self.print_pat(&arm.pat);
self.space();
if let Some(e) = &arm.guard {
if let Some(guard) = &arm.guard {
self.word_space("if");
self.print_expr(e, FixupContext::default());
self.print_expr(&guard.cond, FixupContext::default());
self.space();
}
+48 -10
View File
@@ -724,7 +724,7 @@ pub fn compile_declarative_macro(
let args = p.parse_token_tree();
check_args_parens(sess, sym::attr, &args);
let args = parse_one_tt(args, RulePart::Pattern, sess, node_id, features, edition);
check_emission(check_lhs(sess, node_id, &args));
check_emission(check_lhs(sess, features, node_id, &args));
if let Some(guar) = check_no_eof(sess, &p, "expected macro attr body") {
return dummy_syn_ext(guar);
}
@@ -773,7 +773,7 @@ pub fn compile_declarative_macro(
};
let lhs_tt = p.parse_token_tree();
let lhs_tt = parse_one_tt(lhs_tt, RulePart::Pattern, sess, node_id, features, edition);
check_emission(check_lhs(sess, node_id, &lhs_tt));
check_emission(check_lhs(sess, features, node_id, &lhs_tt));
if let Err(e) = p.expect(exp!(FatArrow)) {
return dummy_syn_ext(e.emit());
}
@@ -870,21 +870,27 @@ fn check_args_empty(sess: &Session, args: &tokenstream::TokenTree) -> Result<(),
}
}
fn check_lhs(sess: &Session, node_id: NodeId, lhs: &mbe::TokenTree) -> Result<(), ErrorGuaranteed> {
let e1 = check_lhs_nt_follows(sess, node_id, lhs);
fn check_lhs(
sess: &Session,
features: &Features,
node_id: NodeId,
lhs: &mbe::TokenTree,
) -> Result<(), ErrorGuaranteed> {
let e1 = check_lhs_nt_follows(sess, features, node_id, lhs);
let e2 = check_lhs_no_empty_seq(sess, slice::from_ref(lhs));
e1.and(e2)
}
fn check_lhs_nt_follows(
sess: &Session,
features: &Features,
node_id: NodeId,
lhs: &mbe::TokenTree,
) -> Result<(), ErrorGuaranteed> {
// lhs is going to be like TokenTree::Delimited(...), where the
// entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
if let mbe::TokenTree::Delimited(.., delimited) = lhs {
check_matcher(sess, node_id, &delimited.tts)
check_matcher(sess, features, node_id, &delimited.tts)
} else {
let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
Err(sess.dcx().span_err(lhs.span(), msg))
@@ -989,12 +995,13 @@ fn check_rhs(sess: &Session, rhs: &mbe::TokenTree) -> Result<(), ErrorGuaranteed
fn check_matcher(
sess: &Session,
features: &Features,
node_id: NodeId,
matcher: &[mbe::TokenTree],
) -> Result<(), ErrorGuaranteed> {
let first_sets = FirstSets::new(matcher);
let empty_suffix = TokenSet::empty();
check_matcher_core(sess, node_id, &first_sets, matcher, &empty_suffix)?;
check_matcher_core(sess, features, node_id, &first_sets, matcher, &empty_suffix)?;
Ok(())
}
@@ -1331,6 +1338,7 @@ fn add_all(&mut self, other: &Self) {
// see `FirstSets::new`.
fn check_matcher_core<'tt>(
sess: &Session,
features: &Features,
node_id: NodeId,
first_sets: &FirstSets<'tt>,
matcher: &'tt [mbe::TokenTree],
@@ -1369,6 +1377,17 @@ fn check_matcher_core<'tt>(
| TokenTree::MetaVar(..)
| TokenTree::MetaVarDecl { .. }
| TokenTree::MetaVarExpr(..) => {
if let TokenTree::MetaVarDecl { kind: NonterminalKind::Guard, .. } = token
&& !features.macro_guard_matcher()
{
feature_err(
sess,
sym::macro_guard_matcher,
token.span(),
"`guard` fragments in macro are unstable",
)
.emit();
}
if token_can_be_followed_by_any(token) {
// don't need to track tokens that work with any,
last.replace_with_irrelevant();
@@ -1385,7 +1404,7 @@ fn check_matcher_core<'tt>(
d.delim.as_close_token_kind(),
span.close,
));
check_matcher_core(sess, node_id, first_sets, &d.tts, &my_suffix)?;
check_matcher_core(sess, features, node_id, first_sets, &d.tts, &my_suffix)?;
// don't track non NT tokens
last.replace_with_irrelevant();
@@ -1417,7 +1436,14 @@ fn check_matcher_core<'tt>(
// At this point, `suffix_first` is built, and
// `my_suffix` is some TokenSet that we can use
// for checking the interior of `seq_rep`.
let next = check_matcher_core(sess, node_id, first_sets, &seq_rep.tts, my_suffix)?;
let next = check_matcher_core(
sess,
features,
node_id,
first_sets,
&seq_rep.tts,
my_suffix,
)?;
if next.maybe_empty {
last.add_all(&next);
} else {
@@ -1609,7 +1635,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
}
}
NonterminalKind::Pat(PatParam { .. }) => {
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"];
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`if let`", "`in`"];
match tok {
TokenTree::Token(token) => match token.kind {
FatArrow | Comma | Eq | Or => IsInFollow::Yes,
@@ -1618,11 +1644,12 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
}
_ => IsInFollow::No(TOKENS),
},
TokenTree::MetaVarDecl { kind: NonterminalKind::Guard, .. } => IsInFollow::Yes,
_ => IsInFollow::No(TOKENS),
}
}
NonterminalKind::Pat(PatWithOr) => {
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`if`", "`in`"];
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`if`", "`if let`", "`in`"];
match tok {
TokenTree::Token(token) => match token.kind {
FatArrow | Comma | Eq => IsInFollow::Yes,
@@ -1631,6 +1658,17 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
}
_ => IsInFollow::No(TOKENS),
},
TokenTree::MetaVarDecl { kind: NonterminalKind::Guard, .. } => IsInFollow::Yes,
_ => IsInFollow::No(TOKENS),
}
}
NonterminalKind::Guard => {
const TOKENS: &[&str] = &["`=>`", "`,`", "`{`"];
match tok {
TokenTree::Token(token) => match token.kind {
FatArrow | Comma | OpenBrace => IsInFollow::Yes,
_ => IsInFollow::No(TOKENS),
},
_ => IsInFollow::No(TOKENS),
}
}
+15 -1
View File
@@ -12,7 +12,8 @@
use rustc_session::parse::ParseSess;
use rustc_span::hygiene::{LocalExpnId, Transparency};
use rustc_span::{
Ident, MacroRulesNormalizedIdent, Span, Symbol, SyntaxContext, sym, with_metavar_spans,
BytePos, Ident, MacroRulesNormalizedIdent, Span, Symbol, SyntaxContext, kw, sym,
with_metavar_spans,
};
use smallvec::{SmallVec, smallvec};
@@ -556,6 +557,19 @@ fn transcribe_pnr<'tx>(
ParseNtResult::Vis(vis) => {
mk_delimited(vis.span, MetaVarKind::Vis, TokenStream::from_ast(vis))
}
ParseNtResult::Guard(guard) => {
// FIXME(macro_guard_matcher):
// Perhaps it would be better to treat the leading `if` as part of `ast::Guard` during parsing?
// Currently they are separate, but in macros we match and emit the leading `if` for `:guard` matchers, which creates some inconsistency.
let leading_if_span =
guard.span_with_leading_if.with_hi(guard.span_with_leading_if.lo() + BytePos(2));
let mut ts =
TokenStream::token_alone(token::Ident(kw::If, IdentIsRaw::No), leading_if_span);
ts.push_stream(TokenStream::from_ast(&guard.cond));
mk_delimited(guard.span_with_leading_if, MetaVarKind::Guard, ts)
}
};
tscx.result.push(tt);
+2
View File
@@ -569,6 +569,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
(unstable, macro_attr, "1.91.0", Some(143547)),
/// Allow `macro_rules!` derive rules
(unstable, macro_derive, "1.91.0", Some(143549)),
/// Allow `$x:guard` matcher in macros
(unstable, macro_guard_matcher, "CURRENT_RUSTC_VERSION", Some(153104)),
/// Give access to additional metadata about declarative macro meta-variables.
(unstable, macro_metavar_expr, "1.61.0", Some(83527)),
/// Provides a way to concatenate identifiers using metavariable expressions.
+86 -42
View File
@@ -15,8 +15,8 @@
use rustc_ast::{
self as ast, AnonConst, Arm, AssignOp, AssignOpKind, AttrStyle, AttrVec, BinOp, BinOpKind,
BlockCheckMode, CaptureBy, ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl,
FnRetTy, Label, MacCall, MetaItemLit, MgcaDisambiguation, Movability, Param, RangeLimits,
StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind,
FnRetTy, Guard, Label, MacCall, MetaItemLit, MgcaDisambiguation, Movability, Param,
RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind,
};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic};
@@ -2767,7 +2767,7 @@ pub fn parse_expr_cond(
/// Parses a `let $pat = $expr` pseudo-expression.
fn parse_expr_let(&mut self, restrictions: Restrictions) -> PResult<'a, Box<Expr>> {
let recovered = if !restrictions.contains(Restrictions::ALLOW_LET) {
let recovered: Recovered = if !restrictions.contains(Restrictions::ALLOW_LET) {
let err = errors::ExpectedExpressionFoundLet {
span: self.token.span,
reason: errors::ForbiddenLetReason::OtherForbidden,
@@ -3463,20 +3463,54 @@ pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
})
}
fn parse_match_arm_guard(&mut self) -> PResult<'a, Option<Box<Expr>>> {
pub(crate) fn eat_metavar_guard(&mut self) -> Option<Box<Guard>> {
self.eat_metavar_seq_with_matcher(
|mv_kind| matches!(mv_kind, MetaVarKind::Guard),
|this| this.parse_match_arm_guard(),
)
.flatten()
}
fn parse_match_arm_guard(&mut self) -> PResult<'a, Option<Box<Guard>>> {
if let Some(guard) = self.eat_metavar_guard() {
return Ok(Some(guard));
}
if !self.eat_keyword(exp!(If)) {
// No match arm guard present.
return Ok(None);
}
self.expect_match_arm_guard_cond(ForceCollect::No).map(Some)
}
let mut cond = self.parse_match_guard_condition()?;
pub(crate) fn expect_match_arm_guard(
&mut self,
force_collect: ForceCollect,
) -> PResult<'a, Box<Guard>> {
if let Some(guard) = self.eat_metavar_guard() {
return Ok(guard);
}
self.expect_keyword(exp!(If))?;
self.expect_match_arm_guard_cond(force_collect)
}
fn expect_match_arm_guard_cond(
&mut self,
force_collect: ForceCollect,
) -> PResult<'a, Box<Guard>> {
let leading_if_span = self.prev_token.span;
let mut cond = self.parse_match_guard_condition(force_collect)?;
let cond_span = cond.span;
CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
Ok(Some(cond))
let guard = Guard { cond: *cond, span_with_leading_if: leading_if_span.to(cond_span) };
Ok(Box::new(guard))
}
fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option<Box<Expr>>)> {
fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option<Box<Guard>>)> {
if self.token == token::OpenParen {
let left = self.token.span;
let pat = self.parse_pat_no_top_guard(
@@ -3492,10 +3526,10 @@ fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option<Box<Expr
// FIXME(guard_patterns): convert this to a normal guard instead
let span = pat.span;
let ast::PatKind::Paren(subpat) = pat.kind else { unreachable!() };
let ast::PatKind::Guard(_, mut cond) = subpat.kind else { unreachable!() };
self.psess.gated_spans.ungate_last(sym::guard_patterns, cond.span);
let ast::PatKind::Guard(_, mut guard) = subpat.kind else { unreachable!() };
self.psess.gated_spans.ungate_last(sym::guard_patterns, guard.span());
let mut checker = CondChecker::new(self, LetChainsPolicy::AlwaysAllowed);
checker.visit_expr(&mut cond);
checker.visit_expr(&mut guard.cond);
let right = self.prev_token.span;
self.dcx().emit_err(errors::ParenthesesInMatchPat {
@@ -3503,14 +3537,10 @@ fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option<Box<Expr
sugg: errors::ParenthesesInMatchPatSugg { left, right },
});
Ok((
self.mk_pat(span, ast::PatKind::Wild),
(if let Some(guar) = checker.found_incorrect_let_chain {
Some(self.mk_expr_err(cond.span, guar))
} else {
Some(cond)
}),
))
if let Some(guar) = checker.found_incorrect_let_chain {
guard.cond = *self.mk_expr_err(guard.span(), guar);
}
Ok((self.mk_pat(span, ast::PatKind::Wild), Some(guard)))
} else {
Ok((pat, self.parse_match_arm_guard()?))
}
@@ -3526,33 +3556,47 @@ fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option<Box<Expr
}
}
fn parse_match_guard_condition(&mut self) -> PResult<'a, Box<Expr>> {
fn parse_match_guard_condition(
&mut self,
force_collect: ForceCollect,
) -> PResult<'a, Box<Expr>> {
let attrs = self.parse_outer_attributes()?;
match self.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, attrs) {
Ok((expr, _)) => Ok(expr),
Err(mut err) => {
if self.prev_token == token::OpenBrace {
let sugg_sp = self.prev_token.span.shrink_to_lo();
// Consume everything within the braces, let's avoid further parse
// errors.
self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
let msg = "you might have meant to start a match arm after the match guard";
if self.eat(exp!(CloseBrace)) {
let applicability = if self.token != token::FatArrow {
// We have high confidence that we indeed didn't have a struct
// literal in the match guard, but rather we had some operation
// that ended in a path, immediately followed by a block that was
// meant to be the match arm.
Applicability::MachineApplicable
} else {
Applicability::MaybeIncorrect
};
err.span_suggestion_verbose(sugg_sp, msg, "=> ", applicability);
let expr = self.collect_tokens(
None,
AttrWrapper::empty(),
force_collect,
|this, _empty_attrs| {
match this
.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, attrs)
{
Ok((expr, _)) => Ok((expr, Trailing::No, UsePreAttrPos::No)),
Err(mut err) => {
if this.prev_token == token::OpenBrace {
let sugg_sp = this.prev_token.span.shrink_to_lo();
// Consume everything within the braces, let's avoid further parse
// errors.
this.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
let msg =
"you might have meant to start a match arm after the match guard";
if this.eat(exp!(CloseBrace)) {
let applicability = if this.token != token::FatArrow {
// We have high confidence that we indeed didn't have a struct
// literal in the match guard, but rather we had some operation
// that ended in a path, immediately followed by a block that was
// meant to be the match arm.
Applicability::MachineApplicable
} else {
Applicability::MaybeIncorrect
};
err.span_suggestion_verbose(sugg_sp, msg, "=> ", applicability);
}
}
Err(err)
}
}
Err(err)
}
}
},
)?;
Ok(expr)
}
pub(crate) fn is_builtin(&self) -> bool {
+1
View File
@@ -1788,4 +1788,5 @@ pub enum ParseNtResult {
Meta(Box<ast::AttrItem>),
Path(Box<ast::Path>),
Vis(Box<ast::Visibility>),
Guard(Box<ast::Guard>),
}
@@ -31,7 +31,8 @@ fn may_be_ident(kind: MetaVarKind) -> bool {
MetaVarKind::Item
| MetaVarKind::Block
| MetaVarKind::Vis => false,
| MetaVarKind::Vis
| MetaVarKind::Guard => false,
MetaVarKind::Ident
| MetaVarKind::Lifetime
@@ -86,7 +87,8 @@ fn may_be_ident(kind: MetaVarKind) -> bool {
| MetaVarKind::Ty { .. }
| MetaVarKind::Meta { .. }
| MetaVarKind::Path
| MetaVarKind::Vis => false,
| MetaVarKind::Vis
| MetaVarKind::Guard => false,
MetaVarKind::Lifetime | MetaVarKind::Ident | MetaVarKind::TT => {
unreachable!()
}
@@ -103,6 +105,7 @@ fn may_be_ident(kind: MetaVarKind) -> bool {
token::Lifetime(..) | token::NtLifetime(..) => true,
_ => false,
},
NonterminalKind::Guard => token.is_keyword(kw::If),
NonterminalKind::TT | NonterminalKind::Item | NonterminalKind::Stmt => {
token.kind.close_delim().is_none()
}
@@ -196,6 +199,9 @@ pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, ParseN
}))
}
}
NonterminalKind::Guard => {
Ok(ParseNtResult::Guard(self.expect_match_arm_guard(ForceCollect::Yes)?))
}
}
}
}
+19 -9
View File
@@ -6,8 +6,9 @@
use rustc_ast::util::parser::ExprPrecedence;
use rustc_ast::visit::{self, Visitor};
use rustc_ast::{
self as ast, Arm, AttrVec, BindingMode, ByRef, Expr, ExprKind, LocalKind, MacCall, Mutability,
Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, Stmt, StmtKind,
self as ast, Arm, AttrVec, BindingMode, ByRef, Expr, ExprKind, Guard, LocalKind, MacCall,
Mutability, Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, Stmt,
StmtKind,
};
use rustc_ast_pretty::pprust;
use rustc_errors::{Applicability, Diag, DiagArgValue, PResult, StashKey};
@@ -110,11 +111,19 @@ pub fn parse_pat_allow_top_guard(
let pat = self.parse_pat_no_top_guard(expected, rc, ra, rt)?;
if self.eat_keyword(exp!(If)) {
let cond = self.parse_expr()?;
let guard = if let Some(guard) = self.eat_metavar_guard() {
guard
} else {
let leading_if_span = self.prev_token.span;
let cond = self.parse_expr()?;
let cond_span = cond.span;
Box::new(Guard { cond: *cond, span_with_leading_if: leading_if_span.to(cond_span) })
};
// Feature-gate guard patterns
self.psess.gated_spans.gate(sym::guard_patterns, cond.span);
let span = pat.span.to(cond.span);
Ok(self.mk_pat(span, PatKind::Guard(Box::new(pat), cond)))
self.psess.gated_spans.gate(sym::guard_patterns, guard.span());
let span = pat.span.to(guard.span());
Ok(self.mk_pat(span, PatKind::Guard(Box::new(pat), guard)))
} else {
Ok(pat)
}
@@ -601,17 +610,18 @@ fn maybe_add_suggestions_then_emit(
}
Some(guard) => {
// Are parentheses required around the old guard?
let wrap_guard = guard.precedence() <= ExprPrecedence::LAnd;
let wrap_guard =
guard.cond.precedence() <= ExprPrecedence::LAnd;
err.subdiagnostic(
UnexpectedExpressionInPatternSugg::UpdateGuard {
ident_span,
guard_lo: if wrap_guard {
Some(guard.span.shrink_to_lo())
Some(guard.span().shrink_to_lo())
} else {
None
},
guard_hi: guard.span.shrink_to_hi(),
guard_hi: guard.span().shrink_to_hi(),
guard_hi_paren: if wrap_guard { ")" } else { "" },
ident,
expr,
+2 -2
View File
@@ -4073,7 +4073,7 @@ fn check_consistent_bindings(&mut self, pat: &'ast Pat) {
fn resolve_arm(&mut self, arm: &'ast Arm) {
self.with_rib(ValueNS, RibKind::Normal, |this| {
this.resolve_pattern_top(&arm.pat, PatternSource::Match);
visit_opt!(this, visit_expr, &arm.guard);
visit_opt!(this, visit_expr, arm.guard.as_ref().map(|g| &g.cond));
visit_opt!(this, visit_expr, &arm.body);
});
}
@@ -4215,7 +4215,7 @@ fn resolve_pattern_inner(
let subpat_bindings = bindings.pop().unwrap().1;
self.with_rib(ValueNS, RibKind::Normal, |this| {
*this.innermost_rib_bindings(ValueNS) = subpat_bindings.clone();
this.resolve_expr(guard, None);
this.resolve_expr(&guard.cond, None);
});
// Propagate the subpattern's bindings upwards.
// FIXME(guard_patterns): For `if let` guards, we'll also need to get the
+2
View File
@@ -1028,6 +1028,7 @@
global_registration,
globs,
gt,
guard,
guard_patterns,
half_open_range_patterns,
half_open_range_patterns_in_slices,
@@ -1193,6 +1194,7 @@
macro_derive,
macro_escape,
macro_export,
macro_guard_matcher,
macro_lifetime_matcher,
macro_literal_matcher,
macro_metavar_expr,
@@ -280,7 +280,7 @@ pub fn eq_arm(l: &Arm, r: &Arm) -> bool {
l.is_placeholder == r.is_placeholder
&& eq_pat(&l.pat, &r.pat)
&& eq_expr_opt(l.body.as_deref(), r.body.as_deref())
&& eq_expr_opt(l.guard.as_deref(), r.guard.as_deref())
&& eq_expr_opt(l.guard.as_deref().map(|g| &g.cond), r.guard.as_deref().map(|g| &g.cond))
&& over(&l.attrs, &r.attrs, eq_attr)
}
+5 -5
View File
@@ -571,7 +571,7 @@ fn rewrite_match_body(
// The `if ...` guard on a match arm.
fn rewrite_guard(
context: &RewriteContext<'_>,
guard: &Option<Box<ast::Expr>>,
guard: &Option<Box<ast::Guard>>,
shape: Shape,
// The amount of space used up on this line for the pattern in
// the arm (excludes offset).
@@ -586,7 +586,7 @@ fn rewrite_guard(
.and_then(|s| s.sub_width_opt(5));
if !multiline_pattern {
if let Some(cond_shape) = cond_shape {
if let Ok(cond_str) = guard.rewrite_result(context, cond_shape) {
if let Ok(cond_str) = guard.cond.rewrite_result(context, cond_shape) {
if !cond_str.contains('\n') || pattern_width <= context.config.tab_spaces() {
return Ok(format!(" if {cond_str}"));
}
@@ -597,9 +597,9 @@ fn rewrite_guard(
// Not enough space to put the guard after the pattern, try a newline.
// 3 = `if `, 5 = ` => {`
let cond_shape = Shape::indented(shape.indent.block_indent(context.config), context.config)
.offset_left(3, guard.span)?
.sub_width(5, guard.span)?;
let cond_str = guard.rewrite_result(context, cond_shape)?;
.offset_left(3, guard.span())?
.sub_width(5, guard.span())?;
let cond_str = guard.cond.rewrite_result(context, cond_shape)?;
Ok(format!(
"{}if {}",
cond_shape.indent.to_string_with_newline(context.config),
@@ -0,0 +1,5 @@
fn main() {
macro_rules! m {
($x:guard) => {}; //~ ERROR `guard` fragments in macro are unstable
}
}
@@ -0,0 +1,13 @@
error[E0658]: `guard` fragments in macro are unstable
--> $DIR/feature-gate-macro-guard-matcher.rs:3:10
|
LL | ($x:guard) => {};
| ^^^^^^^^
|
= note: see issue #153104 <https://github.com/rust-lang/rust/issues/153104> for more information
= help: add `#![feature(macro_guard_matcher)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0658`.
+2 -1
View File
@@ -3,13 +3,14 @@
#![allow(unused_macros)]
// Check the macro follow sets (see corresponding cfail test).
// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), Ident(in)}
// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), MetaVarDecl(Guard), Ident(in)}
macro_rules! follow_pat {
($p:pat =>) => {};
($p:pat ,) => {};
($p:pat =) => {};
($p:pat |) => {};
($p:pat if) => {};
($p:pat if let) => {};
($p:pat in) => {};
}
// FOLLOW(expr) = {FatArrow, Comma, Semicolon}
+6 -1
View File
@@ -2,9 +2,10 @@
//
// Check the macro follow sets (see corresponding rpass test).
#![feature(macro_guard_matcher)]
#![allow(unused_macros)]
// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), Ident(in)}
// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), MetaVarDecl(Guard), Ident(in)}
macro_rules! follow_pat {
($p:pat ()) => {}; //~ERROR `$p:pat` is followed by `(`
($p:pat []) => {}; //~ERROR `$p:pat` is followed by `[`
@@ -47,6 +48,7 @@ macro_rules! follow_expr {
($e:expr $t:tt) => {}; //~ERROR `$e:expr` is followed by `$t:tt`
($e:expr $i:item) => {}; //~ERROR `$e:expr` is followed by `$i:item`
($e:expr $m:meta) => {}; //~ERROR `$e:expr` is followed by `$m:meta`
($e:expr $g:guard) => {}; //~ERROR `$e:expr` is followed by `$g:guard`
}
// FOLLOW(ty) = {OpenDelim(Brace), Comma, FatArrow, Colon, Eq, Gt, Semi, Or,
// Ident(as), Ident(where), OpenDelim(Bracket), Nonterminal(Block)}
@@ -66,6 +68,7 @@ macro_rules! follow_ty {
($t:ty $r:tt) => {}; //~ERROR `$t:ty` is followed by `$r:tt`
($t:ty $i:item) => {}; //~ERROR `$t:ty` is followed by `$i:item`
($t:ty $m:meta) => {}; //~ERROR `$t:ty` is followed by `$m:meta`
($t:ty $g:guard) => {}; //~ERROR `$t:ty` is followed by `$g:guard`
}
// FOLLOW(stmt) = FOLLOW(expr)
macro_rules! follow_stmt {
@@ -90,6 +93,7 @@ macro_rules! follow_stmt {
($s:stmt $t:tt) => {}; //~ERROR `$s:stmt` is followed by `$t:tt`
($s:stmt $i:item) => {}; //~ERROR `$s:stmt` is followed by `$i:item`
($s:stmt $m:meta) => {}; //~ERROR `$s:stmt` is followed by `$m:meta`
($s:stmt $g:guard) => {}; //~ERROR `$s:stmt` is followed by `$g:guard`
}
// FOLLOW(path) = FOLLOW(ty)
macro_rules! follow_path {
@@ -108,6 +112,7 @@ macro_rules! follow_path {
($p:path $t:tt) => {}; //~ERROR `$p:path` is followed by `$t:tt`
($p:path $i:item) => {}; //~ERROR `$p:path` is followed by `$i:item`
($p:path $m:meta) => {}; //~ERROR `$p:path` is followed by `$m:meta`
($p:path $g:guard) => {}; //~ERROR `$p:path` is followed by `$g:guard`
}
// FOLLOW(block) = any token
// FOLLOW(ident) = any token
+135 -103
View File
@@ -1,141 +1,141 @@
error: `$p:pat` is followed by `(`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:9:13
--> $DIR/macro-follow.rs:10:13
|
LL | ($p:pat ()) => {};
| ^ not allowed after `pat` fragments
|
= note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in`
error: `$p:pat` is followed by `[`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:10:13
--> $DIR/macro-follow.rs:11:13
|
LL | ($p:pat []) => {};
| ^ not allowed after `pat` fragments
|
= note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in`
error: `$p:pat` is followed by `{`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:11:13
--> $DIR/macro-follow.rs:12:13
|
LL | ($p:pat {}) => {};
| ^ not allowed after `pat` fragments
|
= note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in`
error: `$p:pat` is followed by `:`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:12:13
--> $DIR/macro-follow.rs:13:13
|
LL | ($p:pat :) => {};
| ^ not allowed after `pat` fragments
|
= note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in`
error: `$p:pat` is followed by `>`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:13:13
--> $DIR/macro-follow.rs:14:13
|
LL | ($p:pat >) => {};
| ^ not allowed after `pat` fragments
|
= note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in`
error: `$p:pat` is followed by `+`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:14:13
--> $DIR/macro-follow.rs:15:13
|
LL | ($p:pat +) => {};
| ^ not allowed after `pat` fragments
|
= note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in`
error: `$p:pat` is followed by `ident`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:15:13
--> $DIR/macro-follow.rs:16:13
|
LL | ($p:pat ident) => {};
| ^^^^^ not allowed after `pat` fragments
|
= note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in`
error: `$p:pat` is followed by `$q:pat`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:16:13
--> $DIR/macro-follow.rs:17:13
|
LL | ($p:pat $q:pat) => {};
| ^^^^^^ not allowed after `pat` fragments
|
= note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in`
error: `$p:pat` is followed by `$e:expr`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:17:13
--> $DIR/macro-follow.rs:18:13
|
LL | ($p:pat $e:expr) => {};
| ^^^^^^^ not allowed after `pat` fragments
|
= note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in`
error: `$p:pat` is followed by `$t:ty`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:18:13
--> $DIR/macro-follow.rs:19:13
|
LL | ($p:pat $t:ty) => {};
| ^^^^^ not allowed after `pat` fragments
|
= note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in`
error: `$p:pat` is followed by `$s:stmt`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:19:13
--> $DIR/macro-follow.rs:20:13
|
LL | ($p:pat $s:stmt) => {};
| ^^^^^^^ not allowed after `pat` fragments
|
= note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in`
error: `$p:pat` is followed by `$q:path`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:20:13
--> $DIR/macro-follow.rs:21:13
|
LL | ($p:pat $q:path) => {};
| ^^^^^^^ not allowed after `pat` fragments
|
= note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in`
error: `$p:pat` is followed by `$b:block`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:21:13
--> $DIR/macro-follow.rs:22:13
|
LL | ($p:pat $b:block) => {};
| ^^^^^^^^ not allowed after `pat` fragments
|
= note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in`
error: `$p:pat` is followed by `$i:ident`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:22:13
--> $DIR/macro-follow.rs:23:13
|
LL | ($p:pat $i:ident) => {};
| ^^^^^^^^ not allowed after `pat` fragments
|
= note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in`
error: `$p:pat` is followed by `$t:tt`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:23:13
--> $DIR/macro-follow.rs:24:13
|
LL | ($p:pat $t:tt) => {};
| ^^^^^ not allowed after `pat` fragments
|
= note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in`
error: `$p:pat` is followed by `$i:item`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:24:13
--> $DIR/macro-follow.rs:25:13
|
LL | ($p:pat $i:item) => {};
| ^^^^^^^ not allowed after `pat` fragments
|
= note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in`
error: `$p:pat` is followed by `$m:meta`, which is not allowed for `pat` fragments
--> $DIR/macro-follow.rs:25:13
--> $DIR/macro-follow.rs:26:13
|
LL | ($p:pat $m:meta) => {};
| ^^^^^^^ not allowed after `pat` fragments
|
= note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in`
error: `$e:expr` is followed by `(`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:29:14
--> $DIR/macro-follow.rs:30:14
|
LL | ($e:expr ()) => {};
| ^ not allowed after `expr` fragments
@@ -143,7 +143,7 @@ LL | ($e:expr ()) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `[`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:30:14
--> $DIR/macro-follow.rs:31:14
|
LL | ($e:expr []) => {};
| ^ not allowed after `expr` fragments
@@ -151,7 +151,7 @@ LL | ($e:expr []) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `{`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:31:14
--> $DIR/macro-follow.rs:32:14
|
LL | ($e:expr {}) => {};
| ^ not allowed after `expr` fragments
@@ -159,7 +159,7 @@ LL | ($e:expr {}) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `=`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:32:14
--> $DIR/macro-follow.rs:33:14
|
LL | ($e:expr =) => {};
| ^ not allowed after `expr` fragments
@@ -167,7 +167,7 @@ LL | ($e:expr =) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `|`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:33:14
--> $DIR/macro-follow.rs:34:14
|
LL | ($e:expr |) => {};
| ^ not allowed after `expr` fragments
@@ -175,7 +175,7 @@ LL | ($e:expr |) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `:`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:34:14
--> $DIR/macro-follow.rs:35:14
|
LL | ($e:expr :) => {};
| ^ not allowed after `expr` fragments
@@ -183,7 +183,7 @@ LL | ($e:expr :) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `>`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:35:14
--> $DIR/macro-follow.rs:36:14
|
LL | ($e:expr >) => {};
| ^ not allowed after `expr` fragments
@@ -191,7 +191,7 @@ LL | ($e:expr >) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `+`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:36:14
--> $DIR/macro-follow.rs:37:14
|
LL | ($e:expr +) => {};
| ^ not allowed after `expr` fragments
@@ -199,7 +199,7 @@ LL | ($e:expr +) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `ident`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:37:14
--> $DIR/macro-follow.rs:38:14
|
LL | ($e:expr ident) => {};
| ^^^^^ not allowed after `expr` fragments
@@ -207,7 +207,7 @@ LL | ($e:expr ident) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `if`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:38:14
--> $DIR/macro-follow.rs:39:14
|
LL | ($e:expr if) => {};
| ^^ not allowed after `expr` fragments
@@ -215,7 +215,7 @@ LL | ($e:expr if) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `in`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:39:14
--> $DIR/macro-follow.rs:40:14
|
LL | ($e:expr in) => {};
| ^^ not allowed after `expr` fragments
@@ -223,7 +223,7 @@ LL | ($e:expr in) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$p:pat`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:40:14
--> $DIR/macro-follow.rs:41:14
|
LL | ($e:expr $p:pat) => {};
| ^^^^^^ not allowed after `expr` fragments
@@ -231,7 +231,7 @@ LL | ($e:expr $p:pat) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$f:expr`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:41:14
--> $DIR/macro-follow.rs:42:14
|
LL | ($e:expr $f:expr) => {};
| ^^^^^^^ not allowed after `expr` fragments
@@ -239,7 +239,7 @@ LL | ($e:expr $f:expr) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$t:ty`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:42:14
--> $DIR/macro-follow.rs:43:14
|
LL | ($e:expr $t:ty) => {};
| ^^^^^ not allowed after `expr` fragments
@@ -247,7 +247,7 @@ LL | ($e:expr $t:ty) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$s:stmt`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:43:14
--> $DIR/macro-follow.rs:44:14
|
LL | ($e:expr $s:stmt) => {};
| ^^^^^^^ not allowed after `expr` fragments
@@ -255,7 +255,7 @@ LL | ($e:expr $s:stmt) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$p:path`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:44:14
--> $DIR/macro-follow.rs:45:14
|
LL | ($e:expr $p:path) => {};
| ^^^^^^^ not allowed after `expr` fragments
@@ -263,7 +263,7 @@ LL | ($e:expr $p:path) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$b:block`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:45:14
--> $DIR/macro-follow.rs:46:14
|
LL | ($e:expr $b:block) => {};
| ^^^^^^^^ not allowed after `expr` fragments
@@ -271,7 +271,7 @@ LL | ($e:expr $b:block) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$i:ident`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:46:14
--> $DIR/macro-follow.rs:47:14
|
LL | ($e:expr $i:ident) => {};
| ^^^^^^^^ not allowed after `expr` fragments
@@ -279,7 +279,7 @@ LL | ($e:expr $i:ident) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$t:tt`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:47:14
--> $DIR/macro-follow.rs:48:14
|
LL | ($e:expr $t:tt) => {};
| ^^^^^ not allowed after `expr` fragments
@@ -287,7 +287,7 @@ LL | ($e:expr $t:tt) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$i:item`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:48:14
--> $DIR/macro-follow.rs:49:14
|
LL | ($e:expr $i:item) => {};
| ^^^^^^^ not allowed after `expr` fragments
@@ -295,15 +295,23 @@ LL | ($e:expr $i:item) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$m:meta`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:49:14
--> $DIR/macro-follow.rs:50:14
|
LL | ($e:expr $m:meta) => {};
| ^^^^^^^ not allowed after `expr` fragments
|
= note: allowed there are: `=>`, `,` or `;`
error: `$e:expr` is followed by `$g:guard`, which is not allowed for `expr` fragments
--> $DIR/macro-follow.rs:51:14
|
LL | ($e:expr $g:guard) => {};
| ^^^^^^^^ not allowed after `expr` fragments
|
= note: allowed there are: `=>`, `,` or `;`
error: `$t:ty` is followed by `(`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:54:12
--> $DIR/macro-follow.rs:56:12
|
LL | ($t:ty ()) => {};
| ^ not allowed after `ty` fragments
@@ -311,7 +319,7 @@ LL | ($t:ty ()) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `+`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:56:12
--> $DIR/macro-follow.rs:58:12
|
LL | ($t:ty +) => {};
| ^ not allowed after `ty` fragments
@@ -319,7 +327,7 @@ LL | ($t:ty +) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `ident`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:57:12
--> $DIR/macro-follow.rs:59:12
|
LL | ($t:ty ident) => {};
| ^^^^^ not allowed after `ty` fragments
@@ -327,7 +335,7 @@ LL | ($t:ty ident) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `if`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:58:12
--> $DIR/macro-follow.rs:60:12
|
LL | ($t:ty if) => {};
| ^^ not allowed after `ty` fragments
@@ -335,7 +343,7 @@ LL | ($t:ty if) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `$p:pat`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:59:12
--> $DIR/macro-follow.rs:61:12
|
LL | ($t:ty $p:pat) => {};
| ^^^^^^ not allowed after `ty` fragments
@@ -343,7 +351,7 @@ LL | ($t:ty $p:pat) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `$e:expr`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:60:12
--> $DIR/macro-follow.rs:62:12
|
LL | ($t:ty $e:expr) => {};
| ^^^^^^^ not allowed after `ty` fragments
@@ -351,7 +359,7 @@ LL | ($t:ty $e:expr) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `$r:ty`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:61:12
--> $DIR/macro-follow.rs:63:12
|
LL | ($t:ty $r:ty) => {};
| ^^^^^ not allowed after `ty` fragments
@@ -359,7 +367,7 @@ LL | ($t:ty $r:ty) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `$s:stmt`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:62:12
--> $DIR/macro-follow.rs:64:12
|
LL | ($t:ty $s:stmt) => {};
| ^^^^^^^ not allowed after `ty` fragments
@@ -367,7 +375,7 @@ LL | ($t:ty $s:stmt) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `$p:path`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:63:12
--> $DIR/macro-follow.rs:65:12
|
LL | ($t:ty $p:path) => {};
| ^^^^^^^ not allowed after `ty` fragments
@@ -375,7 +383,7 @@ LL | ($t:ty $p:path) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `$i:ident`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:65:12
--> $DIR/macro-follow.rs:67:12
|
LL | ($t:ty $i:ident) => {};
| ^^^^^^^^ not allowed after `ty` fragments
@@ -383,7 +391,7 @@ LL | ($t:ty $i:ident) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `$r:tt`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:66:12
--> $DIR/macro-follow.rs:68:12
|
LL | ($t:ty $r:tt) => {};
| ^^^^^ not allowed after `ty` fragments
@@ -391,7 +399,7 @@ LL | ($t:ty $r:tt) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `$i:item`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:67:12
--> $DIR/macro-follow.rs:69:12
|
LL | ($t:ty $i:item) => {};
| ^^^^^^^ not allowed after `ty` fragments
@@ -399,15 +407,23 @@ LL | ($t:ty $i:item) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `$m:meta`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:68:12
--> $DIR/macro-follow.rs:70:12
|
LL | ($t:ty $m:meta) => {};
| ^^^^^^^ not allowed after `ty` fragments
|
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$t:ty` is followed by `$g:guard`, which is not allowed for `ty` fragments
--> $DIR/macro-follow.rs:71:12
|
LL | ($t:ty $g:guard) => {};
| ^^^^^^^^ not allowed after `ty` fragments
|
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$s:stmt` is followed by `(`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:72:14
--> $DIR/macro-follow.rs:75:14
|
LL | ($s:stmt ()) => {};
| ^ not allowed after `stmt` fragments
@@ -415,7 +431,7 @@ LL | ($s:stmt ()) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `[`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:73:14
--> $DIR/macro-follow.rs:76:14
|
LL | ($s:stmt []) => {};
| ^ not allowed after `stmt` fragments
@@ -423,7 +439,7 @@ LL | ($s:stmt []) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `{`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:74:14
--> $DIR/macro-follow.rs:77:14
|
LL | ($s:stmt {}) => {};
| ^ not allowed after `stmt` fragments
@@ -431,7 +447,7 @@ LL | ($s:stmt {}) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `=`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:75:14
--> $DIR/macro-follow.rs:78:14
|
LL | ($s:stmt =) => {};
| ^ not allowed after `stmt` fragments
@@ -439,7 +455,7 @@ LL | ($s:stmt =) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `|`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:76:14
--> $DIR/macro-follow.rs:79:14
|
LL | ($s:stmt |) => {};
| ^ not allowed after `stmt` fragments
@@ -447,7 +463,7 @@ LL | ($s:stmt |) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `:`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:77:14
--> $DIR/macro-follow.rs:80:14
|
LL | ($s:stmt :) => {};
| ^ not allowed after `stmt` fragments
@@ -455,7 +471,7 @@ LL | ($s:stmt :) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `>`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:78:14
--> $DIR/macro-follow.rs:81:14
|
LL | ($s:stmt >) => {};
| ^ not allowed after `stmt` fragments
@@ -463,7 +479,7 @@ LL | ($s:stmt >) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `+`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:79:14
--> $DIR/macro-follow.rs:82:14
|
LL | ($s:stmt +) => {};
| ^ not allowed after `stmt` fragments
@@ -471,7 +487,7 @@ LL | ($s:stmt +) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `ident`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:80:14
--> $DIR/macro-follow.rs:83:14
|
LL | ($s:stmt ident) => {};
| ^^^^^ not allowed after `stmt` fragments
@@ -479,7 +495,7 @@ LL | ($s:stmt ident) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `if`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:81:14
--> $DIR/macro-follow.rs:84:14
|
LL | ($s:stmt if) => {};
| ^^ not allowed after `stmt` fragments
@@ -487,7 +503,7 @@ LL | ($s:stmt if) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `in`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:82:14
--> $DIR/macro-follow.rs:85:14
|
LL | ($s:stmt in) => {};
| ^^ not allowed after `stmt` fragments
@@ -495,7 +511,7 @@ LL | ($s:stmt in) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `$p:pat`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:83:14
--> $DIR/macro-follow.rs:86:14
|
LL | ($s:stmt $p:pat) => {};
| ^^^^^^ not allowed after `stmt` fragments
@@ -503,7 +519,7 @@ LL | ($s:stmt $p:pat) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `$e:expr`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:84:14
--> $DIR/macro-follow.rs:87:14
|
LL | ($s:stmt $e:expr) => {};
| ^^^^^^^ not allowed after `stmt` fragments
@@ -511,7 +527,7 @@ LL | ($s:stmt $e:expr) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `$t:ty`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:85:14
--> $DIR/macro-follow.rs:88:14
|
LL | ($s:stmt $t:ty) => {};
| ^^^^^ not allowed after `stmt` fragments
@@ -519,7 +535,7 @@ LL | ($s:stmt $t:ty) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `$t:stmt`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:86:14
--> $DIR/macro-follow.rs:89:14
|
LL | ($s:stmt $t:stmt) => {};
| ^^^^^^^ not allowed after `stmt` fragments
@@ -527,7 +543,7 @@ LL | ($s:stmt $t:stmt) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `$p:path`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:87:14
--> $DIR/macro-follow.rs:90:14
|
LL | ($s:stmt $p:path) => {};
| ^^^^^^^ not allowed after `stmt` fragments
@@ -535,7 +551,7 @@ LL | ($s:stmt $p:path) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `$b:block`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:88:14
--> $DIR/macro-follow.rs:91:14
|
LL | ($s:stmt $b:block) => {};
| ^^^^^^^^ not allowed after `stmt` fragments
@@ -543,7 +559,7 @@ LL | ($s:stmt $b:block) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `$i:ident`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:89:14
--> $DIR/macro-follow.rs:92:14
|
LL | ($s:stmt $i:ident) => {};
| ^^^^^^^^ not allowed after `stmt` fragments
@@ -551,7 +567,7 @@ LL | ($s:stmt $i:ident) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `$t:tt`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:90:14
--> $DIR/macro-follow.rs:93:14
|
LL | ($s:stmt $t:tt) => {};
| ^^^^^ not allowed after `stmt` fragments
@@ -559,7 +575,7 @@ LL | ($s:stmt $t:tt) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `$i:item`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:91:14
--> $DIR/macro-follow.rs:94:14
|
LL | ($s:stmt $i:item) => {};
| ^^^^^^^ not allowed after `stmt` fragments
@@ -567,23 +583,31 @@ LL | ($s:stmt $i:item) => {};
= note: allowed there are: `=>`, `,` or `;`
error: `$s:stmt` is followed by `$m:meta`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:92:14
--> $DIR/macro-follow.rs:95:14
|
LL | ($s:stmt $m:meta) => {};
| ^^^^^^^ not allowed after `stmt` fragments
|
= note: allowed there are: `=>`, `,` or `;`
error: `$p:path` is followed by `(`, which is not allowed for `path` fragments
error: `$s:stmt` is followed by `$g:guard`, which is not allowed for `stmt` fragments
--> $DIR/macro-follow.rs:96:14
|
LL | ($s:stmt $g:guard) => {};
| ^^^^^^^^ not allowed after `stmt` fragments
|
= note: allowed there are: `=>`, `,` or `;`
error: `$p:path` is followed by `(`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:100:14
|
LL | ($p:path ()) => {};
| ^ not allowed after `path` fragments
|
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `+`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:98:14
--> $DIR/macro-follow.rs:102:14
|
LL | ($p:path +) => {};
| ^ not allowed after `path` fragments
@@ -591,7 +615,7 @@ LL | ($p:path +) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `ident`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:99:14
--> $DIR/macro-follow.rs:103:14
|
LL | ($p:path ident) => {};
| ^^^^^ not allowed after `path` fragments
@@ -599,7 +623,7 @@ LL | ($p:path ident) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `if`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:100:14
--> $DIR/macro-follow.rs:104:14
|
LL | ($p:path if) => {};
| ^^ not allowed after `path` fragments
@@ -607,7 +631,7 @@ LL | ($p:path if) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `$q:pat`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:101:14
--> $DIR/macro-follow.rs:105:14
|
LL | ($p:path $q:pat) => {};
| ^^^^^^ not allowed after `path` fragments
@@ -615,7 +639,7 @@ LL | ($p:path $q:pat) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `$e:expr`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:102:14
--> $DIR/macro-follow.rs:106:14
|
LL | ($p:path $e:expr) => {};
| ^^^^^^^ not allowed after `path` fragments
@@ -623,7 +647,7 @@ LL | ($p:path $e:expr) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `$t:ty`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:103:14
--> $DIR/macro-follow.rs:107:14
|
LL | ($p:path $t:ty) => {};
| ^^^^^ not allowed after `path` fragments
@@ -631,7 +655,7 @@ LL | ($p:path $t:ty) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `$s:stmt`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:104:14
--> $DIR/macro-follow.rs:108:14
|
LL | ($p:path $s:stmt) => {};
| ^^^^^^^ not allowed after `path` fragments
@@ -639,7 +663,7 @@ LL | ($p:path $s:stmt) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `$q:path`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:105:14
--> $DIR/macro-follow.rs:109:14
|
LL | ($p:path $q:path) => {};
| ^^^^^^^ not allowed after `path` fragments
@@ -647,7 +671,7 @@ LL | ($p:path $q:path) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `$i:ident`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:107:14
--> $DIR/macro-follow.rs:111:14
|
LL | ($p:path $i:ident) => {};
| ^^^^^^^^ not allowed after `path` fragments
@@ -655,7 +679,7 @@ LL | ($p:path $i:ident) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `$t:tt`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:108:14
--> $DIR/macro-follow.rs:112:14
|
LL | ($p:path $t:tt) => {};
| ^^^^^ not allowed after `path` fragments
@@ -663,7 +687,7 @@ LL | ($p:path $t:tt) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `$i:item`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:109:14
--> $DIR/macro-follow.rs:113:14
|
LL | ($p:path $i:item) => {};
| ^^^^^^^ not allowed after `path` fragments
@@ -671,12 +695,20 @@ LL | ($p:path $i:item) => {};
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: `$p:path` is followed by `$m:meta`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:110:14
--> $DIR/macro-follow.rs:114:14
|
LL | ($p:path $m:meta) => {};
| ^^^^^^^ not allowed after `path` fragments
|
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: aborting due to 85 previous errors
error: `$p:path` is followed by `$g:guard`, which is not allowed for `path` fragments
--> $DIR/macro-follow.rs:115:14
|
LL | ($p:path $g:guard) => {};
| ^^^^^^^^ not allowed after `path` fragments
|
= note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
error: aborting due to 89 previous errors
+17
View File
@@ -0,0 +1,17 @@
#![feature(macro_guard_matcher)]
fn main() {
macro_rules! m {
($x:guard) => {};
}
// Accepts
m!(if true);
m!(if let Some(x) = Some(1));
m!(if let Some(x) = Some(1) && x == 1);
m!(if let Some(x) = Some(Some(1)) && let Some(1) = x);
m!(if let Some(x) = Some(Some(1)) && let Some(y) = x && y == 1);
// Rejects
m!(let Some(x) = Some(1)); //~ERROR no rules expected keyword `let`
}
@@ -0,0 +1,17 @@
error: no rules expected keyword `let`
--> $DIR/macro-guard-matcher.rs:16:8
|
LL | macro_rules! m {
| -------------- when calling this macro
...
LL | m!(let Some(x) = Some(1));
| ^^^ no rules expected this token in macro call
|
note: while trying to match meta-variable `$x:guard`
--> $DIR/macro-guard-matcher.rs:5:10
|
LL | ($x:guard) => {};
| ^^^^^^^^
error: aborting due to 1 previous error
@@ -20,7 +20,7 @@ error: `$pa:pat` is followed by `>`, which is not allowed for `pat` fragments
LL | ($pa:pat >) => ();
| ^ not allowed after `pat` fragments
|
= note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in`
error: `$pa:pat` is followed by `$pb:pat`, which is not allowed for `pat` fragments
--> $DIR/macro-input-future-proofing.rs:14:14
@@ -28,7 +28,7 @@ error: `$pa:pat` is followed by `$pb:pat`, which is not allowed for `pat` fragme
LL | ($pa:pat $pb:pat $ty:ty ,) => ();
| ^^^^^^^ not allowed after `pat` fragments
|
= note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in`
error: `$pb:pat` is followed by `$ty:ty`, which is not allowed for `pat` fragments
--> $DIR/macro-input-future-proofing.rs:14:22
@@ -36,7 +36,7 @@ error: `$pb:pat` is followed by `$ty:ty`, which is not allowed for `pat` fragmen
LL | ($pa:pat $pb:pat $ty:ty ,) => ();
| ^^^^^^ not allowed after `pat` fragments
|
= note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `|`, `if`, `if let` or `in`
error: `$ty:ty` is followed by `-`, which is not allowed for `ty` fragments
--> $DIR/macro-input-future-proofing.rs:17:17
@@ -6,7 +6,7 @@ LL | macro_rules! foo { ($x:pat | $y:pat) => {} }
| |
| help: try a `pat_param` fragment specifier instead: `$x:pat_param`
|
= note: allowed there are: `=>`, `,`, `=`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in`
error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
--> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:4:32
@@ -16,7 +16,7 @@ LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} }
| |
| help: try a `pat_param` fragment specifier instead: `$x:pat_param`
|
= note: allowed there are: `=>`, `,`, `=`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in`
error: `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments
--> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:7:36
@@ -26,7 +26,7 @@ LL | ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => {
| |
| help: try a `pat_param` fragment specifier instead: `$pat:pat_param`
|
= note: allowed there are: `=>`, `,`, `=`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in`
error: aborting due to 3 previous errors
@@ -6,7 +6,7 @@ LL | macro_rules! foo { ($x:pat | $y:pat) => {} }
| |
| help: try a `pat_param` fragment specifier instead: `$x:pat_param`
|
= note: allowed there are: `=>`, `,`, `=`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in`
error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
--> $DIR/macro-pat2021-pattern-followed-by-or.rs:7:28
@@ -16,7 +16,7 @@ LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} }
| |
| help: try a `pat_param` fragment specifier instead: `$x:pat_param`
|
= note: allowed there are: `=>`, `,`, `=`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in`
error: `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments
--> $DIR/macro-pat2021-pattern-followed-by-or.rs:9:35
@@ -26,7 +26,7 @@ LL | ( $expr:expr , $( $( $pat:pat)|+ => $expr_arm:pat),+ ) => {
| |
| help: try a `pat_param` fragment specifier instead: `$pat:pat_param`
|
= note: allowed there are: `=>`, `,`, `=`, `if` or `in`
= note: allowed there are: `=>`, `,`, `=`, `if`, `if let` or `in`
error: aborting due to 3 previous errors
+17
View File
@@ -14,6 +14,7 @@
#![feature(trait_alias)]
#![feature(try_blocks)]
#![feature(yeet_expr)]
#![feature(macro_guard_matcher)]
#![deny(unused_macros)]
// These macros force the use of AST pretty-printing by converting the input to
@@ -27,6 +28,7 @@
macro_rules! stmt { ($stmt:stmt) => { stringify!($stmt) }; }
macro_rules! ty { ($ty:ty) => { stringify!($ty) }; }
macro_rules! vis { ($vis:vis) => { stringify!($vis) }; }
macro_rules! guard { ($guard:guard) => { stringify!($guard) }; }
macro_rules! c1 {
($frag:ident, [$($tt:tt)*], $s:literal) => {
@@ -792,6 +794,21 @@ fn test_vis() {
// Attributes are not allowed on visibilities.
}
#[test]
fn test_guard() {
c1!(guard, [ if true ], "if true");
c1!(guard, [ if let Some(x) = Some(1) ], "if let Some(x) = Some(1)");
c1!(guard, [ if let Some(x) = Some(1) && x == 1 ], "if let Some(x) = Some(1) && x == 1");
c1!(guard,
[ if let Some(x) = Some(Some(1)) && let Some(1) = x ],
"if let Some(x) = Some(Some(1)) && let Some(1) = x"
);
c1!(guard,
[ if let Some(x) = Some(Some(1)) && let Some(y) = x && y == 1 ],
"if let Some(x) = Some(Some(1)) && let Some(y) = x && y == 1"
);
}
macro_rules! p {
([$($tt:tt)*], $s:literal) => {
assert_eq!(stringify!($($tt)*), $s);