Skip to content

Commit 1f076fe

Browse files
authored
Rollup merge of #113999 - Centri3:macro-arm-expand, r=wesleywiser
Specify macro is invalid in certain contexts Adds a note when a macro is used where it really shouldn't be. Closes #113766
2 parents f36a9b5 + bbd69e4 commit 1f076fe

File tree

9 files changed

+246
-24
lines changed

9 files changed

+246
-24
lines changed

compiler/rustc_parse/messages.ftl

+6
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,12 @@ parse_loop_else = `{$loop_kind}...else` loops are not supported
461461
.note = consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
462462
.loop_keyword = `else` is attached to this loop
463463
464+
parse_macro_expands_to_adt_field = macros cannot expand to {$adt_ty} fields
465+
466+
parse_macro_expands_to_enum_variant = macros cannot expand to enum variants
467+
468+
parse_macro_expands_to_match_arm = macros cannot expand to match arms
469+
464470
parse_macro_invocation_visibility = can't qualify macro invocation with `pub`
465471
.suggestion = remove the visibility
466472
.help = try adjusting the macro to put `{$vis}` inside the invocation

compiler/rustc_parse/src/errors.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1815,6 +1815,12 @@ pub struct UnknownPrefix<'a> {
18151815
pub sugg: Option<UnknownPrefixSugg>,
18161816
}
18171817

1818+
#[derive(Subdiagnostic)]
1819+
#[note(parse_macro_expands_to_adt_field)]
1820+
pub struct MacroExpandsToAdtField<'a> {
1821+
pub adt_ty: &'a str,
1822+
}
1823+
18181824
#[derive(Subdiagnostic)]
18191825
pub enum UnknownPrefixSugg {
18201826
#[suggestion(

compiler/rustc_parse/src/parser/diagnostics.rs

+21-16
Original file line numberDiff line numberDiff line change
@@ -2641,6 +2641,7 @@ impl<'a> Parser<'a> {
26412641
pub(crate) fn maybe_recover_unexpected_comma(
26422642
&mut self,
26432643
lo: Span,
2644+
is_mac_invoc: bool,
26442645
rt: CommaRecoveryMode,
26452646
) -> PResult<'a, ()> {
26462647
if self.token != token::Comma {
@@ -2661,24 +2662,28 @@ impl<'a> Parser<'a> {
26612662
let seq_span = lo.to(self.prev_token.span);
26622663
let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern");
26632664
if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
2664-
err.multipart_suggestion(
2665-
format!(
2666-
"try adding parentheses to match on a tuple{}",
2667-
if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." },
2668-
),
2669-
vec![
2670-
(seq_span.shrink_to_lo(), "(".to_string()),
2671-
(seq_span.shrink_to_hi(), ")".to_string()),
2672-
],
2673-
Applicability::MachineApplicable,
2674-
);
2675-
if let CommaRecoveryMode::EitherTupleOrPipe = rt {
2676-
err.span_suggestion(
2677-
seq_span,
2678-
"...or a vertical bar to match on multiple alternatives",
2679-
seq_snippet.replace(',', " |"),
2665+
if is_mac_invoc {
2666+
err.note(fluent::parse_macro_expands_to_match_arm);
2667+
} else {
2668+
err.multipart_suggestion(
2669+
format!(
2670+
"try adding parentheses to match on a tuple{}",
2671+
if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." },
2672+
),
2673+
vec![
2674+
(seq_span.shrink_to_lo(), "(".to_string()),
2675+
(seq_span.shrink_to_hi(), ")".to_string()),
2676+
],
26802677
Applicability::MachineApplicable,
26812678
);
2679+
if let CommaRecoveryMode::EitherTupleOrPipe = rt {
2680+
err.span_suggestion(
2681+
seq_span,
2682+
"...or a vertical bar to match on multiple alternatives",
2683+
seq_snippet.replace(',', " |"),
2684+
Applicability::MachineApplicable,
2685+
);
2686+
}
26822687
}
26832688
}
26842689
Err(err)

compiler/rustc_parse/src/parser/item.rs

+35-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
use crate::errors;
2-
31
use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
42
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
53
use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
4+
use crate::errors::{self, MacroExpandsToAdtField};
5+
use crate::fluent_generated as fluent;
66
use ast::StaticItem;
77
use rustc_ast::ast::*;
88
use rustc_ast::ptr::P;
@@ -1450,6 +1450,17 @@ impl<'a> Parser<'a> {
14501450
}
14511451
let ident = this.parse_field_ident("enum", vlo)?;
14521452

1453+
if this.token == token::Not {
1454+
if let Err(mut err) = this.unexpected::<()>() {
1455+
err.note(fluent::parse_macro_expands_to_enum_variant).emit();
1456+
}
1457+
1458+
this.bump();
1459+
this.parse_delim_args()?;
1460+
1461+
return Ok((None, TrailingToken::MaybeComma));
1462+
}
1463+
14531464
let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) {
14541465
// Parse a struct variant.
14551466
let (fields, recovered) =
@@ -1477,7 +1488,7 @@ impl<'a> Parser<'a> {
14771488

14781489
Ok((Some(vr), TrailingToken::MaybeComma))
14791490
},
1480-
).map_err(|mut err|{
1491+
).map_err(|mut err| {
14811492
err.help("enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`");
14821493
err
14831494
})
@@ -1687,7 +1698,8 @@ impl<'a> Parser<'a> {
16871698
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
16881699
let lo = this.token.span;
16891700
let vis = this.parse_visibility(FollowedByType::No)?;
1690-
Ok((this.parse_single_struct_field(adt_ty, lo, vis, attrs)?, TrailingToken::None))
1701+
this.parse_single_struct_field(adt_ty, lo, vis, attrs)
1702+
.map(|field| (field, TrailingToken::None))
16911703
})
16921704
}
16931705

@@ -1821,8 +1833,8 @@ impl<'a> Parser<'a> {
18211833
"field names and their types are separated with `:`",
18221834
":",
18231835
Applicability::MachineApplicable,
1824-
);
1825-
err.emit();
1836+
)
1837+
.emit();
18261838
} else {
18271839
return Err(err);
18281840
}
@@ -1839,6 +1851,23 @@ impl<'a> Parser<'a> {
18391851
attrs: AttrVec,
18401852
) -> PResult<'a, FieldDef> {
18411853
let name = self.parse_field_ident(adt_ty, lo)?;
1854+
// Parse the macro invocation and recover
1855+
if self.token.kind == token::Not {
1856+
if let Err(mut err) = self.unexpected::<FieldDef>() {
1857+
err.subdiagnostic(MacroExpandsToAdtField { adt_ty }).emit();
1858+
self.bump();
1859+
self.parse_delim_args()?;
1860+
return Ok(FieldDef {
1861+
span: DUMMY_SP,
1862+
ident: None,
1863+
vis,
1864+
id: DUMMY_NODE_ID,
1865+
ty: self.mk_ty(DUMMY_SP, TyKind::Err),
1866+
attrs,
1867+
is_placeholder: false,
1868+
});
1869+
}
1870+
}
18421871
self.expect_field_ty_separator()?;
18431872
let ty = self.parse_ty()?;
18441873
if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) {

compiler/rustc_parse/src/parser/pat.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,11 @@ impl<'a> Parser<'a> {
142142
// Parse the first pattern (`p_0`).
143143
let mut first_pat = self.parse_pat_no_top_alt(expected, syntax_loc)?;
144144
if rc == RecoverComma::Yes {
145-
self.maybe_recover_unexpected_comma(first_pat.span, rt)?;
145+
self.maybe_recover_unexpected_comma(
146+
first_pat.span,
147+
matches!(first_pat.kind, PatKind::MacCall(_)),
148+
rt,
149+
)?;
146150
}
147151

148152
// If the next token is not a `|`,
@@ -184,7 +188,7 @@ impl<'a> Parser<'a> {
184188
err
185189
})?;
186190
if rc == RecoverComma::Yes {
187-
self.maybe_recover_unexpected_comma(pat.span, rt)?;
191+
self.maybe_recover_unexpected_comma(pat.span, false, rt)?;
188192
}
189193
pats.push(pat);
190194
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// compile-flags: --crate-type=lib
2+
3+
macro_rules! field {
4+
($name:ident:$type:ty) => {
5+
$name:$type
6+
};
7+
}
8+
9+
macro_rules! variant {
10+
($name:ident) => {
11+
$name
12+
}
13+
}
14+
15+
struct Struct {
16+
field!(bar:u128),
17+
//~^ NOTE macros cannot expand to struct fields
18+
//~| ERROR unexpected token: `!`
19+
//~| NOTE unexpected token after this
20+
a: u32,
21+
b: u32,
22+
field!(recovers:()), //~ NOTE macros cannot expand to struct fields
23+
//~^ ERROR unexpected token: `!`
24+
//~^^ NOTE unexpected token after this
25+
}
26+
27+
enum EnumVariant {
28+
variant!(whoops),
29+
//~^ NOTE macros cannot expand to enum variants
30+
//~| ERROR unexpected token: `!`
31+
//~| NOTE unexpected token after this
32+
U32,
33+
F64,
34+
variant!(recovers),
35+
//~^ NOTE macros cannot expand to enum variants
36+
//~| ERROR unexpected token: `!`
37+
//~| NOTE unexpected token after this
38+
Data {
39+
field!(x:u32),
40+
//~^ NOTE macros cannot expand to struct fields
41+
//~| ERROR unexpected token: `!`
42+
//~| NOTE unexpected token after this
43+
}
44+
}
45+
46+
enum EnumVariantField {
47+
Named {
48+
field!(oopsies:()),
49+
//~^ NOTE macros cannot expand to struct fields
50+
//~| ERROR unexpected token: `!`
51+
//~| unexpected token after this
52+
field!(oopsies2:()),
53+
//~^ NOTE macros cannot expand to struct fields
54+
//~| ERROR unexpected token: `!`
55+
//~| unexpected token after this
56+
},
57+
}
58+
59+
union Union {
60+
A: u32,
61+
field!(oopsies:()),
62+
//~^ NOTE macros cannot expand to union fields
63+
//~| ERROR unexpected token: `!`
64+
//~| unexpected token after this
65+
B: u32,
66+
field!(recovers:()),
67+
//~^ NOTE macros cannot expand to union fields
68+
//~| ERROR unexpected token: `!`
69+
//~| unexpected token after this
70+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
error: unexpected token: `!`
2+
--> $DIR/macro-expand-to-field.rs:16:10
3+
|
4+
LL | field!(bar:u128),
5+
| ^ unexpected token after this
6+
|
7+
= note: macros cannot expand to struct fields
8+
9+
error: unexpected token: `!`
10+
--> $DIR/macro-expand-to-field.rs:22:10
11+
|
12+
LL | field!(recovers:()),
13+
| ^ unexpected token after this
14+
|
15+
= note: macros cannot expand to struct fields
16+
17+
error: unexpected token: `!`
18+
--> $DIR/macro-expand-to-field.rs:28:12
19+
|
20+
LL | variant!(whoops),
21+
| ^ unexpected token after this
22+
|
23+
= note: macros cannot expand to enum variants
24+
25+
error: unexpected token: `!`
26+
--> $DIR/macro-expand-to-field.rs:34:12
27+
|
28+
LL | variant!(recovers),
29+
| ^ unexpected token after this
30+
|
31+
= note: macros cannot expand to enum variants
32+
33+
error: unexpected token: `!`
34+
--> $DIR/macro-expand-to-field.rs:39:14
35+
|
36+
LL | field!(x:u32),
37+
| ^ unexpected token after this
38+
|
39+
= note: macros cannot expand to struct fields
40+
41+
error: unexpected token: `!`
42+
--> $DIR/macro-expand-to-field.rs:48:14
43+
|
44+
LL | field!(oopsies:()),
45+
| ^ unexpected token after this
46+
|
47+
= note: macros cannot expand to struct fields
48+
49+
error: unexpected token: `!`
50+
--> $DIR/macro-expand-to-field.rs:52:14
51+
|
52+
LL | field!(oopsies2:()),
53+
| ^ unexpected token after this
54+
|
55+
= note: macros cannot expand to struct fields
56+
57+
error: unexpected token: `!`
58+
--> $DIR/macro-expand-to-field.rs:61:10
59+
|
60+
LL | field!(oopsies:()),
61+
| ^ unexpected token after this
62+
|
63+
= note: macros cannot expand to union fields
64+
65+
error: unexpected token: `!`
66+
--> $DIR/macro-expand-to-field.rs:66:10
67+
|
68+
LL | field!(recovers:()),
69+
| ^ unexpected token after this
70+
|
71+
= note: macros cannot expand to union fields
72+
73+
error: aborting due to 9 previous errors
74+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
macro_rules! arm {
2+
($pattern:pat => $block:block) => {
3+
$pattern => $block
4+
};
5+
}
6+
7+
fn main() {
8+
let x = Some(1);
9+
match x {
10+
Some(1) => {},
11+
arm!(None => {}),
12+
//~^ NOTE macros cannot expand to match arms
13+
//~| ERROR unexpected `,` in pattern
14+
// doesn't recover
15+
Some(2) => {},
16+
_ => {},
17+
};
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: unexpected `,` in pattern
2+
--> $DIR/macro-expand-to-match-arm.rs:11:25
3+
|
4+
LL | arm!(None => {}),
5+
| ^
6+
|
7+
= note: macros cannot expand to match arms
8+
9+
error: aborting due to previous error
10+

0 commit comments

Comments
 (0)