Skip to content

Commit d4bc9e6

Browse files
committed
handle paren in macro expand for let-init-else expr
1 parent 728f2da commit d4bc9e6

6 files changed

+165
-13
lines changed

compiler/rustc_ast/src/mut_visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -807,7 +807,7 @@ fn visit_lazy_tts_opt_mut<T: MutVisitor>(vis: &mut T, lazy_tts: Option<&mut Lazy
807807
}
808808
}
809809

810-
fn visit_lazy_tts<T: MutVisitor>(vis: &mut T, lazy_tts: &mut Option<LazyAttrTokenStream>) {
810+
pub fn visit_lazy_tts<T: MutVisitor>(vis: &mut T, lazy_tts: &mut Option<LazyAttrTokenStream>) {
811811
visit_lazy_tts_opt_mut(vis, lazy_tts.as_mut());
812812
}
813813

compiler/rustc_expand/src/expand.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ macro_rules! ast_fragments {
100100
match self {
101101
$($(AstFragment::$Kind(ast) => ast.extend(placeholders.iter().flat_map(|id| {
102102
${ignore($flat_map_ast_elt)}
103-
placeholder(AstFragmentKind::$Kind, *id, None).$make_ast()
103+
placeholder(false, AstFragmentKind::$Kind, *id, None).$make_ast()
104104
})),)?)*
105105
_ => panic!("unexpected AST fragment kind")
106106
}
@@ -1783,17 +1783,26 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
17831783
}
17841784
}
17851785

1786-
fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment {
1786+
fn collect(
1787+
&mut self,
1788+
fragment_kind: AstFragmentKind,
1789+
invoke_kind: InvocationKind,
1790+
) -> AstFragment {
17871791
let expn_id = LocalExpnId::fresh_empty();
1788-
if matches!(kind, InvocationKind::GlobDelegation { .. }) {
1792+
if matches!(invoke_kind, InvocationKind::GlobDelegation { .. }) {
17891793
// In resolver we need to know which invocation ids are delegations early,
17901794
// before their `ExpnData` is filled.
17911795
self.cx.resolver.register_glob_delegation(expn_id);
17921796
}
1793-
let vis = kind.placeholder_visibility();
1797+
let vis = invoke_kind.placeholder_visibility();
1798+
let is_bang_brace = if let InvocationKind::Bang { mac, .. } = &invoke_kind {
1799+
mac.args.delim == Delimiter::Brace
1800+
} else {
1801+
false
1802+
};
17941803
self.invocations.push((
17951804
Invocation {
1796-
kind,
1805+
kind: invoke_kind,
17971806
fragment_kind,
17981807
expansion_data: ExpansionData {
17991808
id: expn_id,
@@ -1803,7 +1812,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
18031812
},
18041813
None,
18051814
));
1806-
placeholder(fragment_kind, NodeId::placeholder_from_expn_id(expn_id), vis)
1815+
placeholder(is_bang_brace, fragment_kind, NodeId::placeholder_from_expn_id(expn_id), vis)
18071816
}
18081817

18091818
fn collect_bang(&mut self, mac: P<ast::MacCall>, kind: AstFragmentKind) -> AstFragment {

compiler/rustc_expand/src/placeholders.rs

+50-6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::ops::DerefMut;
2+
13
use rustc_ast::mut_visit::*;
24
use rustc_ast::ptr::P;
35
use rustc_ast::token::Delimiter;
@@ -12,20 +14,21 @@ use thin_vec::ThinVec;
1214
use crate::expand::{AstFragment, AstFragmentKind};
1315

1416
pub(crate) fn placeholder(
15-
kind: AstFragmentKind,
17+
is_bang_brace: bool,
18+
fragment_kind: AstFragmentKind,
1619
id: ast::NodeId,
1720
vis: Option<ast::Visibility>,
1821
) -> AstFragment {
19-
fn mac_placeholder() -> P<ast::MacCall> {
22+
let mac_placeholder = || -> P<ast::MacCall> {
2023
P(ast::MacCall {
2124
path: ast::Path { span: DUMMY_SP, segments: ThinVec::new(), tokens: None },
2225
args: P(ast::DelimArgs {
2326
dspan: ast::tokenstream::DelimSpan::dummy(),
24-
delim: Delimiter::Parenthesis,
27+
delim: if is_bang_brace { Delimiter::Brace } else { Delimiter::Parenthesis },
2528
tokens: ast::tokenstream::TokenStream::new(Vec::new()),
2629
}),
2730
})
28-
}
31+
};
2932

3033
let ident = Ident::empty();
3134
let attrs = ast::AttrVec::new();
@@ -49,7 +52,7 @@ pub(crate) fn placeholder(
4952
let pat =
5053
|| P(ast::Pat { id, kind: ast::PatKind::MacCall(mac_placeholder()), span, tokens: None });
5154

52-
match kind {
55+
match fragment_kind {
5356
AstFragmentKind::Crate => AstFragment::Crate(ast::Crate {
5457
attrs: Default::default(),
5558
items: Default::default(),
@@ -194,6 +197,7 @@ pub(crate) fn placeholder(
194197
#[derive(Default)]
195198
pub(crate) struct PlaceholderExpander {
196199
expanded_fragments: FxHashMap<ast::NodeId, AstFragment>,
200+
expr_under_let_init_else: bool,
197201
}
198202

199203
impl PlaceholderExpander {
@@ -301,8 +305,48 @@ impl MutVisitor for PlaceholderExpander {
301305
}
302306
}
303307

308+
fn visit_local(&mut self, local: &mut P<ast::Local>) {
309+
let ast::Local { id, pat, ty, kind, span, colon_sp, attrs, tokens } = local.deref_mut();
310+
self.visit_id(id);
311+
for attr in attrs.iter_mut() {
312+
self.visit_attribute(attr);
313+
}
314+
self.visit_pat(pat);
315+
if let Some(ty) = ty {
316+
self.visit_ty(ty);
317+
}
318+
match kind {
319+
ast::LocalKind::Decl => {}
320+
ast::LocalKind::Init(init) => {
321+
self.visit_expr(init);
322+
}
323+
ast::LocalKind::InitElse(init, els) => {
324+
self.expr_under_let_init_else = true;
325+
self.visit_expr(init);
326+
self.expr_under_let_init_else = false;
327+
self.visit_block(els);
328+
}
329+
}
330+
visit_lazy_tts(self, tokens);
331+
if let Some(sp) = colon_sp {
332+
self.visit_span(sp);
333+
}
334+
self.visit_span(span);
335+
}
336+
304337
fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
305-
match expr.kind {
338+
tracing::debug!("visit: {:?}", expr);
339+
match &mut expr.kind {
340+
ast::ExprKind::Paren(paren) => {
341+
if self.expr_under_let_init_else
342+
&& let ast::ExprKind::MacCall(mac) = &paren.kind
343+
&& matches!(mac.args.delim, Delimiter::Brace)
344+
{
345+
*expr = self.remove(paren.id).make_expr();
346+
} else {
347+
walk_expr(self, expr);
348+
}
349+
}
306350
ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_expr(),
307351
_ => walk_expr(self, expr),
308352
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//@ run-rustfix
2+
3+
#![deny(unused_parens)]
4+
5+
fn main() {
6+
macro_rules! x {
7+
() => { None::<i32> };
8+
}
9+
10+
let Some(_) = (x!{}) else { return }; // no error
11+
let Some(_) = (x!{}) else { return };
12+
//~^ ERROR: unnecessary parentheses around pattern
13+
let _ = x!{};
14+
let _ = x!{};
15+
//~^ ERROR: unnecessary parentheses around assigned value
16+
if let Some(_) = x!{} {};
17+
if let Some(_) = x!{} {};
18+
//~^ ERROR: unnecessary parentheses around `let` scrutinee expression
19+
while let Some(_) = x!{} {};
20+
while let Some(_) = x!{} {};
21+
//~^ ERROR: unnecessary parentheses around `let` scrutinee expression
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//@ run-rustfix
2+
3+
#![deny(unused_parens)]
4+
5+
fn main() {
6+
macro_rules! x {
7+
() => { None::<i32> };
8+
}
9+
10+
let Some(_) = (x!{}) else { return }; // no error
11+
let Some((_)) = (x!{}) else { return };
12+
//~^ ERROR: unnecessary parentheses around pattern
13+
let _ = x!{};
14+
let _ = (x!{});
15+
//~^ ERROR: unnecessary parentheses around assigned value
16+
if let Some(_) = x!{} {};
17+
if let Some(_) = (x!{}) {};
18+
//~^ ERROR: unnecessary parentheses around `let` scrutinee expression
19+
while let Some(_) = x!{} {};
20+
while let Some(_) = (x!{}) {};
21+
//~^ ERROR: unnecessary parentheses around `let` scrutinee expression
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
error: unnecessary parentheses around pattern
2+
--> $DIR/unused-parens-for-macro-call-with-brace.rs:11:14
3+
|
4+
LL | let Some((_)) = (x!{}) else { return };
5+
| ^ ^
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/unused-parens-for-macro-call-with-brace.rs:3:9
9+
|
10+
LL | #![deny(unused_parens)]
11+
| ^^^^^^^^^^^^^
12+
help: remove these parentheses
13+
|
14+
LL - let Some((_)) = (x!{}) else { return };
15+
LL + let Some(_) = (x!{}) else { return };
16+
|
17+
18+
error: unnecessary parentheses around assigned value
19+
--> $DIR/unused-parens-for-macro-call-with-brace.rs:14:13
20+
|
21+
LL | let _ = (x!{});
22+
| ^ ^
23+
|
24+
help: remove these parentheses
25+
|
26+
LL - let _ = (x!{});
27+
LL + let _ = x!{};
28+
|
29+
30+
error: unnecessary parentheses around `let` scrutinee expression
31+
--> $DIR/unused-parens-for-macro-call-with-brace.rs:17:22
32+
|
33+
LL | if let Some(_) = (x!{}) {};
34+
| ^ ^
35+
|
36+
help: remove these parentheses
37+
|
38+
LL - if let Some(_) = (x!{}) {};
39+
LL + if let Some(_) = x!{} {};
40+
|
41+
42+
error: unnecessary parentheses around `let` scrutinee expression
43+
--> $DIR/unused-parens-for-macro-call-with-brace.rs:20:25
44+
|
45+
LL | while let Some(_) = (x!{}) {};
46+
| ^ ^
47+
|
48+
help: remove these parentheses
49+
|
50+
LL - while let Some(_) = (x!{}) {};
51+
LL + while let Some(_) = x!{} {};
52+
|
53+
54+
error: aborting due to 4 previous errors
55+

0 commit comments

Comments
 (0)