Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ee5cb9e

Browse files
committedAug 18, 2023
Auto merge of #114915 - nnethercote:Nonterminal-cleanups, r=petrochenkov
`Nonterminal`-related cleanups In #114647 I am trying to remove `Nonterminal`. It has a number of preliminary cleanups that are worth merging even if #114647 doesn't merge, so let's do them in this PR. r? `@petrochenkov`
2 parents 2ceed0b + 9e22351 commit ee5cb9e

File tree

11 files changed

+120
-92
lines changed

11 files changed

+120
-92
lines changed
 

‎compiler/rustc_ast_pretty/src/pprust/state.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ pub fn print_crate<'a>(
150150
/// and also addresses some specific regressions described in #63896 and #73345.
151151
fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool {
152152
if let TokenTree::Token(token, _) = prev {
153+
// No space after these tokens, e.g. `x.y`, `$e`
154+
// (The carets point to `prev`.) ^ ^
153155
if matches!(token.kind, token::Dot | token::Dollar) {
154156
return false;
155157
}
@@ -158,10 +160,19 @@ fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool {
158160
}
159161
}
160162
match tt {
163+
// No space before these tokens, e.g. `foo,`, `println!`, `x.y`
164+
// (The carets point to `token`.) ^ ^ ^
165+
//
166+
// FIXME: having `Not` here works well for macro invocations like
167+
// `println!()`, but is bad when `!` means "logical not" or "the never
168+
// type", where the lack of space causes ugliness like this:
169+
// `Fn() ->!`, `x =! y`, `if! x { f(); }`.
161170
TokenTree::Token(token, _) => !matches!(token.kind, token::Comma | token::Not | token::Dot),
171+
// No space before parentheses if preceded by these tokens, e.g. `foo(...)`
162172
TokenTree::Delimited(_, Delimiter::Parenthesis, _) => {
163173
!matches!(prev, TokenTree::Token(Token { kind: token::Ident(..), .. }, _))
164174
}
175+
// No space before brackets if preceded by these tokens, e.g. `#[...]`
165176
TokenTree::Delimited(_, Delimiter::Bracket, _) => {
166177
!matches!(prev, TokenTree::Token(Token { kind: token::Pound, .. }, _))
167178
}

‎compiler/rustc_expand/src/mbe/macro_parser.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ use rustc_data_structures::fx::FxHashMap;
8181
use rustc_data_structures::sync::Lrc;
8282
use rustc_errors::ErrorGuaranteed;
8383
use rustc_lint_defs::pluralize;
84-
use rustc_parse::parser::{NtOrTt, Parser};
84+
use rustc_parse::parser::{ParseNtResult, Parser};
8585
use rustc_span::symbol::Ident;
8686
use rustc_span::symbol::MacroRulesNormalizedIdent;
8787
use rustc_span::Span;
@@ -692,8 +692,8 @@ impl TtParser {
692692
Ok(nt) => nt,
693693
};
694694
let m = match nt {
695-
NtOrTt::Nt(nt) => MatchedNonterminal(Lrc::new(nt)),
696-
NtOrTt::Tt(tt) => MatchedTokenTree(tt),
695+
ParseNtResult::Nt(nt) => MatchedNonterminal(Lrc::new(nt)),
696+
ParseNtResult::Tt(tt) => MatchedTokenTree(tt),
697697
};
698698
mp.push_match(next_metavar, seq_depth, m);
699699
mp.idx += 1;

‎compiler/rustc_expand/src/mbe/macro_rules.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1328,7 +1328,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
13281328
_ => IsInFollow::No(TOKENS),
13291329
}
13301330
}
1331-
NonterminalKind::PatWithOr { .. } => {
1331+
NonterminalKind::PatWithOr => {
13321332
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`if`", "`in`"];
13331333
match tok {
13341334
TokenTree::Token(token) => match token.kind {

‎compiler/rustc_expand/src/mbe/transcribe.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -220,16 +220,15 @@ pub(super) fn transcribe<'a>(
220220
MatchedTokenTree(tt) => {
221221
// `tt`s are emitted into the output stream directly as "raw tokens",
222222
// without wrapping them into groups.
223-
let token = tt.clone();
224-
result.push(token);
223+
result.push(tt.clone());
225224
}
226225
MatchedNonterminal(nt) => {
227226
// Other variables are emitted into the output stream as groups with
228227
// `Delimiter::Invisible` to maintain parsing priorities.
229228
// `Interpolated` is currently used for such groups in rustc parser.
230229
marker.visit_span(&mut sp);
231-
let token = TokenTree::token_alone(token::Interpolated(nt.clone()), sp);
232-
result.push(token);
230+
result
231+
.push(TokenTree::token_alone(token::Interpolated(nt.clone()), sp));
233232
}
234233
MatchedSeq(..) => {
235234
// We were unable to descend far enough. This is an error.

‎compiler/rustc_macros/src/serialize.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,14 @@ fn decodable_body(
5959
})
6060
.collect();
6161
let message = format!(
62-
"invalid enum variant tag while decoding `{}`, expected 0..{}",
62+
"invalid enum variant tag while decoding `{}`, expected 0..{}, actual {{}}",
6363
ty_name,
6464
variants.len()
6565
);
6666
quote! {
6767
match ::rustc_serialize::Decoder::read_usize(__decoder) {
6868
#match_inner
69-
_ => panic!(#message),
69+
n => panic!(#message, n),
7070
}
7171
}
7272
}

‎compiler/rustc_parse/src/parser/expr.rs

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -193,13 +193,7 @@ impl<'a> Parser<'a> {
193193

194194
self.expected_tokens.push(TokenType::Operator);
195195
while let Some(op) = self.check_assoc_op() {
196-
// Adjust the span for interpolated LHS to point to the `$lhs` token
197-
// and not to what it refers to.
198-
let lhs_span = match self.prev_token.kind {
199-
TokenKind::Interpolated(..) => self.prev_token.span,
200-
_ => lhs.span,
201-
};
202-
196+
let lhs_span = self.interpolated_or_expr_span(&lhs);
203197
let cur_op_span = self.token.span;
204198
let restrictions = if op.node.is_assign_like() {
205199
self.restrictions & Restrictions::NO_STRUCT_LITERAL
@@ -626,8 +620,8 @@ impl<'a> Parser<'a> {
626620

627621
fn parse_expr_prefix_common(&mut self, lo: Span) -> PResult<'a, (Span, P<Expr>)> {
628622
self.bump();
629-
let expr = self.parse_expr_prefix(None);
630-
let (span, expr) = self.interpolated_or_expr_span(expr)?;
623+
let expr = self.parse_expr_prefix(None)?;
624+
let span = self.interpolated_or_expr_span(&expr);
631625
Ok((lo.to(span), expr))
632626
}
633627

@@ -702,20 +696,12 @@ impl<'a> Parser<'a> {
702696
self.parse_expr_unary(lo, UnOp::Not)
703697
}
704698

705-
/// Returns the span of expr, if it was not interpolated or the span of the interpolated token.
706-
fn interpolated_or_expr_span(
707-
&self,
708-
expr: PResult<'a, P<Expr>>,
709-
) -> PResult<'a, (Span, P<Expr>)> {
710-
expr.map(|e| {
711-
(
712-
match self.prev_token.kind {
713-
TokenKind::Interpolated(..) => self.prev_token.span,
714-
_ => e.span,
715-
},
716-
e,
717-
)
718-
})
699+
/// Returns the span of expr if it was not interpolated, or the span of the interpolated token.
700+
fn interpolated_or_expr_span(&self, expr: &Expr) -> Span {
701+
match self.prev_token.kind {
702+
TokenKind::Interpolated(..) => self.prev_token.span,
703+
_ => expr.span,
704+
}
719705
}
720706

721707
fn parse_assoc_op_cast(
@@ -898,8 +884,8 @@ impl<'a> Parser<'a> {
898884
self.parse_expr_prefix_range(None)
899885
} else {
900886
self.parse_expr_prefix(None)
901-
};
902-
let (hi, expr) = self.interpolated_or_expr_span(expr)?;
887+
}?;
888+
let hi = self.interpolated_or_expr_span(&expr);
903889
let span = lo.to(hi);
904890
if let Some(lt) = lifetime {
905891
self.error_remove_borrow_lifetime(span, lt.ident.span);
@@ -930,8 +916,8 @@ impl<'a> Parser<'a> {
930916
fn parse_expr_dot_or_call(&mut self, attrs: Option<AttrWrapper>) -> PResult<'a, P<Expr>> {
931917
let attrs = self.parse_or_use_outer_attributes(attrs)?;
932918
self.collect_tokens_for_expr(attrs, |this, attrs| {
933-
let base = this.parse_expr_bottom();
934-
let (span, base) = this.interpolated_or_expr_span(base)?;
919+
let base = this.parse_expr_bottom()?;
920+
let span = this.interpolated_or_expr_span(&base);
935921
this.parse_expr_dot_or_call_with(base, span, attrs)
936922
})
937923
}

‎compiler/rustc_parse/src/parser/mod.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,33 +1052,48 @@ impl<'a> Parser<'a> {
10521052
}
10531053

10541054
/// Look-ahead `dist` tokens of `self.token` and get access to that token there.
1055-
/// When `dist == 0` then the current token is looked at.
1055+
/// When `dist == 0` then the current token is looked at. `Eof` will be
1056+
/// returned if the look-ahead is any distance past the end of the tokens.
10561057
pub fn look_ahead<R>(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R {
10571058
if dist == 0 {
10581059
return looker(&self.token);
10591060
}
10601061

1061-
let tree_cursor = &self.token_cursor.tree_cursor;
10621062
if let Some(&(_, delim, span)) = self.token_cursor.stack.last()
10631063
&& delim != Delimiter::Invisible
10641064
{
1065+
// We are not in the outermost token stream, and the token stream
1066+
// we are in has non-skipped delimiters. Look for skipped
1067+
// delimiters in the lookahead range.
1068+
let tree_cursor = &self.token_cursor.tree_cursor;
10651069
let all_normal = (0..dist).all(|i| {
10661070
let token = tree_cursor.look_ahead(i);
10671071
!matches!(token, Some(TokenTree::Delimited(_, Delimiter::Invisible, _)))
10681072
});
10691073
if all_normal {
1074+
// There were no skipped delimiters. Do lookahead by plain indexing.
10701075
return match tree_cursor.look_ahead(dist - 1) {
1071-
Some(tree) => match tree {
1072-
TokenTree::Token(token, _) => looker(token),
1073-
TokenTree::Delimited(dspan, delim, _) => {
1074-
looker(&Token::new(token::OpenDelim(*delim), dspan.open))
1076+
Some(tree) => {
1077+
// Indexing stayed within the current token stream.
1078+
match tree {
1079+
TokenTree::Token(token, _) => looker(token),
1080+
TokenTree::Delimited(dspan, delim, _) => {
1081+
looker(&Token::new(token::OpenDelim(*delim), dspan.open))
1082+
}
10751083
}
1076-
},
1077-
None => looker(&Token::new(token::CloseDelim(delim), span.close)),
1084+
}
1085+
None => {
1086+
// Indexing went past the end of the current token
1087+
// stream. Use the close delimiter, no matter how far
1088+
// ahead `dist` went.
1089+
looker(&Token::new(token::CloseDelim(delim), span.close))
1090+
}
10781091
};
10791092
}
10801093
}
10811094

1095+
// We are in a more complex case. Just clone the token cursor and use
1096+
// `next`, skipping delimiters as necessary. Slow but simple.
10821097
let mut cursor = self.token_cursor.clone();
10831098
let mut i = 0;
10841099
let mut token = Token::dummy();
@@ -1476,7 +1491,7 @@ pub enum FlatToken {
14761491
}
14771492

14781493
#[derive(Debug)]
1479-
pub enum NtOrTt {
1494+
pub enum ParseNtResult {
14801495
Nt(Nonterminal),
14811496
Tt(TokenTree),
14821497
}

‎compiler/rustc_parse/src/parser/nonterminal.rs

Lines changed: 44 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rustc_ast::ptr::P;
2-
use rustc_ast::token::{self, Delimiter, NonterminalKind, Token};
2+
use rustc_ast::token::{self, Delimiter, Nonterminal::*, NonterminalKind, Token};
33
use rustc_ast::HasTokens;
44
use rustc_ast_pretty::pprust;
55
use rustc_errors::IntoDiagnostic;
@@ -8,7 +8,7 @@ use rustc_span::symbol::{kw, Ident};
88

99
use crate::errors::UnexpectedNonterminal;
1010
use crate::parser::pat::{CommaRecoveryMode, RecoverColon, RecoverComma};
11-
use crate::parser::{FollowedByType, ForceCollect, NtOrTt, Parser, PathStyle};
11+
use crate::parser::{FollowedByType, ForceCollect, ParseNtResult, Parser, PathStyle};
1212

1313
impl<'a> Parser<'a> {
1414
/// Checks whether a non-terminal may begin with a particular token.
@@ -20,10 +20,21 @@ impl<'a> Parser<'a> {
2020
pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool {
2121
/// Checks whether the non-terminal may contain a single (non-keyword) identifier.
2222
fn may_be_ident(nt: &token::Nonterminal) -> bool {
23-
!matches!(
24-
*nt,
25-
token::NtItem(_) | token::NtBlock(_) | token::NtVis(_) | token::NtLifetime(_)
26-
)
23+
match nt {
24+
NtStmt(_)
25+
| NtPat(_)
26+
| NtExpr(_)
27+
| NtTy(_)
28+
| NtIdent(..)
29+
| NtLiteral(_) // `true`, `false`
30+
| NtMeta(_)
31+
| NtPath(_) => true,
32+
33+
NtItem(_)
34+
| NtBlock(_)
35+
| NtVis(_)
36+
| NtLifetime(_) => false,
37+
}
2738
}
2839

2940
match kind {
@@ -44,27 +55,19 @@ impl<'a> Parser<'a> {
4455
},
4556
NonterminalKind::Block => match &token.kind {
4657
token::OpenDelim(Delimiter::Brace) => true,
47-
token::Interpolated(nt) => !matches!(
48-
**nt,
49-
token::NtItem(_)
50-
| token::NtPat(_)
51-
| token::NtTy(_)
52-
| token::NtIdent(..)
53-
| token::NtMeta(_)
54-
| token::NtPath(_)
55-
| token::NtVis(_)
56-
),
58+
token::Interpolated(nt) => match **nt {
59+
NtBlock(_) | NtLifetime(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true,
60+
NtItem(_) | NtPat(_) | NtTy(_) | NtIdent(..) | NtMeta(_) | NtPath(_)
61+
| NtVis(_) => false,
62+
},
5763
_ => false,
5864
},
5965
NonterminalKind::Path | NonterminalKind::Meta => match &token.kind {
6066
token::ModSep | token::Ident(..) => true,
61-
token::Interpolated(nt) => match **nt {
62-
token::NtPath(_) | token::NtMeta(_) => true,
63-
_ => may_be_ident(&nt),
64-
},
67+
token::Interpolated(nt) => may_be_ident(nt),
6568
_ => false,
6669
},
67-
NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => {
70+
NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => {
6871
match &token.kind {
6972
token::Ident(..) | // box, ref, mut, and other identifiers (can stricten)
7073
token::OpenDelim(Delimiter::Parenthesis) | // tuple pattern
@@ -79,15 +82,15 @@ impl<'a> Parser<'a> {
7982
token::Lt | // path (UFCS constant)
8083
token::BinOp(token::Shl) => true, // path (double UFCS)
8184
// leading vert `|` or-pattern
82-
token::BinOp(token::Or) => matches!(kind, NonterminalKind::PatWithOr {..}),
85+
token::BinOp(token::Or) => matches!(kind, NonterminalKind::PatWithOr),
8386
token::Interpolated(nt) => may_be_ident(nt),
8487
_ => false,
8588
}
8689
}
8790
NonterminalKind::Lifetime => match &token.kind {
8891
token::Lifetime(_) => true,
8992
token::Interpolated(nt) => {
90-
matches!(**nt, token::NtLifetime(_))
93+
matches!(**nt, NtLifetime(_))
9194
}
9295
_ => false,
9396
},
@@ -100,18 +103,16 @@ impl<'a> Parser<'a> {
100103
/// Parse a non-terminal (e.g. MBE `:pat` or `:ident`). Inlined because there is only one call
101104
/// site.
102105
#[inline]
103-
pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, NtOrTt> {
104-
// Any `Nonterminal` which stores its tokens (currently `NtItem` and `NtExpr`)
105-
// needs to have them force-captured here.
106+
pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, ParseNtResult> {
106107
// A `macro_rules!` invocation may pass a captured item/expr to a proc-macro,
107108
// which requires having captured tokens available. Since we cannot determine
108109
// in advance whether or not a proc-macro will be (transitively) invoked,
109110
// we always capture tokens for any `Nonterminal` which needs them.
110111
let mut nt = match kind {
111112
// Note that TT is treated differently to all the others.
112-
NonterminalKind::TT => return Ok(NtOrTt::Tt(self.parse_token_tree())),
113+
NonterminalKind::TT => return Ok(ParseNtResult::Tt(self.parse_token_tree())),
113114
NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? {
114-
Some(item) => token::NtItem(item),
115+
Some(item) => NtItem(item),
115116
None => {
116117
return Err(UnexpectedNonterminal::Item(self.token.span)
117118
.into_diagnostic(&self.sess.span_diagnostic));
@@ -120,19 +121,19 @@ impl<'a> Parser<'a> {
120121
NonterminalKind::Block => {
121122
// While a block *expression* may have attributes (e.g. `#[my_attr] { ... }`),
122123
// the ':block' matcher does not support them
123-
token::NtBlock(self.collect_tokens_no_attrs(|this| this.parse_block())?)
124+
NtBlock(self.collect_tokens_no_attrs(|this| this.parse_block())?)
124125
}
125126
NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? {
126-
Some(s) => token::NtStmt(P(s)),
127+
Some(s) => NtStmt(P(s)),
127128
None => {
128129
return Err(UnexpectedNonterminal::Statement(self.token.span)
129130
.into_diagnostic(&self.sess.span_diagnostic));
130131
}
131132
},
132-
NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr { .. } => {
133-
token::NtPat(self.collect_tokens_no_attrs(|this| match kind {
133+
NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => {
134+
NtPat(self.collect_tokens_no_attrs(|this| match kind {
134135
NonterminalKind::PatParam { .. } => this.parse_pat_no_top_alt(None, None),
135-
NonterminalKind::PatWithOr { .. } => this.parse_pat_allow_top_alt(
136+
NonterminalKind::PatWithOr => this.parse_pat_allow_top_alt(
136137
None,
137138
RecoverComma::No,
138139
RecoverColon::No,
@@ -142,41 +143,41 @@ impl<'a> Parser<'a> {
142143
})?)
143144
}
144145

145-
NonterminalKind::Expr => token::NtExpr(self.parse_expr_force_collect()?),
146+
NonterminalKind::Expr => NtExpr(self.parse_expr_force_collect()?),
146147
NonterminalKind::Literal => {
147148
// The `:literal` matcher does not support attributes
148-
token::NtLiteral(
149+
NtLiteral(
149150
self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?,
150151
)
151152
}
152153

153-
NonterminalKind::Ty => token::NtTy(
154-
self.collect_tokens_no_attrs(|this| this.parse_no_question_mark_recover())?,
154+
NonterminalKind::Ty => NtTy(
155+
self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?,
155156
),
156157

157158
// this could be handled like a token, since it is one
158159
NonterminalKind::Ident
159160
if let Some((ident, is_raw)) = get_macro_ident(&self.token) =>
160161
{
161162
self.bump();
162-
token::NtIdent(ident, is_raw)
163+
NtIdent(ident, is_raw)
163164
}
164165
NonterminalKind::Ident => {
165166
return Err(UnexpectedNonterminal::Ident {
166167
span: self.token.span,
167168
token: self.token.clone(),
168169
}.into_diagnostic(&self.sess.span_diagnostic));
169170
}
170-
NonterminalKind::Path => token::NtPath(
171+
NonterminalKind::Path => NtPath(
171172
P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?),
172173
),
173-
NonterminalKind::Meta => token::NtMeta(P(self.parse_attr_item(true)?)),
174-
NonterminalKind::Vis => token::NtVis(
174+
NonterminalKind::Meta => NtMeta(P(self.parse_attr_item(true)?)),
175+
NonterminalKind::Vis => NtVis(
175176
P(self.collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?),
176177
),
177178
NonterminalKind::Lifetime => {
178179
if self.check_lifetime() {
179-
token::NtLifetime(self.expect_lifetime().ident)
180+
NtLifetime(self.expect_lifetime().ident)
180181
} else {
181182
return Err(UnexpectedNonterminal::Lifetime {
182183
span: self.token.span,
@@ -196,7 +197,7 @@ impl<'a> Parser<'a> {
196197
);
197198
}
198199

199-
Ok(NtOrTt::Nt(nt))
200+
Ok(ParseNtResult::Nt(nt))
200201
}
201202
}
202203

‎compiler/rustc_parse/src/parser/ty.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ impl<'a> Parser<'a> {
180180
)
181181
}
182182

183-
pub(super) fn parse_no_question_mark_recover(&mut self) -> PResult<'a, P<Ty>> {
183+
pub(super) fn parse_ty_no_question_mark_recover(&mut self) -> PResult<'a, P<Ty>> {
184184
self.parse_ty_common(
185185
AllowPlus::Yes,
186186
AllowCVariadic::No,

‎tests/ui/macros/macro-interpolation.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// run-pass
2-
31
macro_rules! overly_complicated {
42
($fnname:ident, $arg:ident, $ty:ty, $body:block, $val:expr, $pat:pat, $res:path) =>
53
({
@@ -21,12 +19,14 @@ macro_rules! qpath {
2119

2220
(ty, <$type:ty as $trait:ty>::$name:ident) => {
2321
<$type as $trait>::$name
22+
//~^ ERROR expected identifier, found `!`
2423
};
2524
}
2625

2726
pub fn main() {
2827
let _: qpath!(path, <str as ToOwned>::Owned);
2928
let _: qpath!(ty, <str as ToOwned>::Owned);
29+
let _: qpath!(ty, <str as !>::Owned);
3030

3131
assert!(overly_complicated!(f, x, Option<usize>, { return Some(x); },
3232
Some(8), Some(y), y) == 8)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: expected identifier, found `!`
2+
--> $DIR/macro-interpolation.rs:21:19
3+
|
4+
LL | <$type as $trait>::$name
5+
| ^^^^^^ expected identifier
6+
...
7+
LL | let _: qpath!(ty, <str as !>::Owned);
8+
| -----------------------------
9+
| |
10+
| this macro call doesn't expand to a type
11+
| in this macro invocation
12+
|
13+
= note: this error originates in the macro `qpath` (in Nightly builds, run with -Z macro-backtrace for more info)
14+
15+
error: aborting due to previous error
16+

0 commit comments

Comments
 (0)
Please sign in to comment.