Skip to content

Commit 287db04

Browse files
committed
Specify macro is invalid in certain contexts
1 parent 8771282 commit 287db04

13 files changed

+209
-26
lines changed

compiler/rustc_parse/messages.ftl

+6
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,12 @@ parse_loop_else = `{$loop_kind}...else` loops are not supported
457457
.note = consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
458458
.loop_keyword = `else` is attached to this loop
459459
460+
parse_macro_expands_to_adt_field = macros cannot expand to {$adt_ty} fields
461+
462+
parse_macro_expands_to_enum_variant = macros cannot expand to enum variants
463+
464+
parse_macro_expands_to_match_arm = macros cannot expand to match arms
465+
460466
parse_macro_invocation_visibility = can't qualify macro invocation with `pub`
461467
.suggestion = remove the visibility
462468
.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
@@ -1800,6 +1800,12 @@ pub struct UnknownPrefix<'a> {
18001800
pub sugg: Option<UnknownPrefixSugg>,
18011801
}
18021802

1803+
#[derive(Subdiagnostic)]
1804+
#[note(parse_macro_expands_to_adt_field)]
1805+
pub struct MacroExpandsToAdtField<'a> {
1806+
pub adt_ty: &'a str,
1807+
}
1808+
18031809
#[derive(Subdiagnostic)]
18041810
pub enum UnknownPrefixSugg {
18051811
#[suggestion(

compiler/rustc_parse/src/parser/diagnostics.rs

+21-16
Original file line numberDiff line numberDiff line change
@@ -2591,6 +2591,7 @@ impl<'a> Parser<'a> {
25912591
pub(crate) fn maybe_recover_unexpected_comma(
25922592
&mut self,
25932593
lo: Span,
2594+
is_mac_invoc: bool,
25942595
rt: CommaRecoveryMode,
25952596
) -> PResult<'a, ()> {
25962597
if self.token != token::Comma {
@@ -2611,24 +2612,28 @@ impl<'a> Parser<'a> {
26112612
let seq_span = lo.to(self.prev_token.span);
26122613
let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern");
26132614
if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
2614-
err.multipart_suggestion(
2615-
format!(
2616-
"try adding parentheses to match on a tuple{}",
2617-
if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." },
2618-
),
2619-
vec![
2620-
(seq_span.shrink_to_lo(), "(".to_string()),
2621-
(seq_span.shrink_to_hi(), ")".to_string()),
2622-
],
2623-
Applicability::MachineApplicable,
2624-
);
2625-
if let CommaRecoveryMode::EitherTupleOrPipe = rt {
2626-
err.span_suggestion(
2627-
seq_span,
2628-
"...or a vertical bar to match on multiple alternatives",
2629-
seq_snippet.replace(',', " |"),
2615+
if is_mac_invoc {
2616+
err.note(fluent::parse_macro_expands_to_match_arm);
2617+
} else {
2618+
err.multipart_suggestion(
2619+
format!(
2620+
"try adding parentheses to match on a tuple{}",
2621+
if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." },
2622+
),
2623+
vec![
2624+
(seq_span.shrink_to_lo(), "(".to_string()),
2625+
(seq_span.shrink_to_hi(), ")".to_string()),
2626+
],
26302627
Applicability::MachineApplicable,
26312628
);
2629+
if let CommaRecoveryMode::EitherTupleOrPipe = rt {
2630+
err.span_suggestion(
2631+
seq_span,
2632+
"...or a vertical bar to match on multiple alternatives",
2633+
seq_snippet.replace(',', " |"),
2634+
Applicability::MachineApplicable,
2635+
);
2636+
}
26322637
}
26332638
}
26342639
Err(err)

compiler/rustc_parse/src/parser/item.rs

+18-8
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;
@@ -1342,6 +1342,13 @@ impl<'a> Parser<'a> {
13421342
}
13431343
let ident = this.parse_field_ident("enum", vlo)?;
13441344

1345+
if this.token == token::Not {
1346+
return this.unexpected().map_err(|mut err| {
1347+
err.note(fluent::parse_macro_expands_to_enum_variant);
1348+
err
1349+
});
1350+
}
1351+
13451352
let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) {
13461353
// Parse a struct variant.
13471354
let (fields, recovered) =
@@ -1369,7 +1376,7 @@ impl<'a> Parser<'a> {
13691376

13701377
Ok((Some(vr), TrailingToken::MaybeComma))
13711378
},
1372-
).map_err(|mut err|{
1379+
).map_err(|mut err| {
13731380
err.help("enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`");
13741381
err
13751382
})
@@ -1691,9 +1698,10 @@ impl<'a> Parser<'a> {
16911698
Ok(a_var)
16921699
}
16931700

1694-
fn expect_field_ty_separator(&mut self) -> PResult<'a, ()> {
1701+
fn expect_field_ty_separator(&mut self, adt_ty: &str) -> PResult<'a, ()> {
16951702
if let Err(mut err) = self.expect(&token::Colon) {
16961703
let sm = self.sess.source_map();
1704+
let mac_invoc = self.token.kind == token::Not;
16971705
let eq_typo = self.token.kind == token::Eq && self.look_ahead(1, |t| t.is_path_start());
16981706
let semi_typo = self.token.kind == token::Semi
16991707
&& self.look_ahead(1, |t| {
@@ -1705,16 +1713,18 @@ impl<'a> Parser<'a> {
17051713
_ => true,
17061714
}
17071715
});
1708-
if eq_typo || semi_typo {
1716+
if mac_invoc {
1717+
err.subdiagnostic(MacroExpandsToAdtField { adt_ty }).emit();
1718+
} else if eq_typo || semi_typo {
17091719
self.bump();
17101720
// Gracefully handle small typos.
17111721
err.span_suggestion_short(
17121722
self.prev_token.span,
17131723
"field names and their types are separated with `:`",
17141724
":",
17151725
Applicability::MachineApplicable,
1716-
);
1717-
err.emit();
1726+
)
1727+
.emit();
17181728
} else {
17191729
return Err(err);
17201730
}
@@ -1731,7 +1741,7 @@ impl<'a> Parser<'a> {
17311741
attrs: AttrVec,
17321742
) -> PResult<'a, FieldDef> {
17331743
let name = self.parse_field_ident(adt_ty, lo)?;
1734-
self.expect_field_ty_separator()?;
1744+
self.expect_field_ty_separator(adt_ty)?;
17351745
let ty = self.parse_ty()?;
17361746
if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) {
17371747
self.sess.emit_err(errors::SingleColonStructType { span: self.token.span });

compiler/rustc_parse/src/parser/pat.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,11 @@ impl<'a> Parser<'a> {
135135
// Parse the first pattern (`p_0`).
136136
let mut first_pat = self.parse_pat_no_top_alt(expected)?;
137137
if rc == RecoverComma::Yes {
138-
self.maybe_recover_unexpected_comma(first_pat.span, rt)?;
138+
self.maybe_recover_unexpected_comma(
139+
first_pat.span,
140+
matches!(first_pat.kind, PatKind::MacCall(_)),
141+
rt,
142+
)?;
139143
}
140144

141145
// If the next token is not a `|`,
@@ -177,7 +181,11 @@ impl<'a> Parser<'a> {
177181
err
178182
})?;
179183
if rc == RecoverComma::Yes {
180-
self.maybe_recover_unexpected_comma(pat.span, rt)?;
184+
self.maybe_recover_unexpected_comma(
185+
pat.span,
186+
matches!(pat.kind, PatKind::MacCall(_)),
187+
rt,
188+
)?;
181189
}
182190
pats.push(pat);
183191
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![no_main]
2+
3+
macro_rules! field {
4+
($name:ident:$type:ty) => {
5+
$name:$type
6+
};
7+
}
8+
9+
enum EnumVariantField {
10+
Named { //~ NOTE while parsing this struct
11+
field!(oopsies:()), //~ NOTE macros cannot expand to struct fields
12+
//~^ ERROR expected `:`, found `!`
13+
//~^^ ERROR expected `,`, or `}`, found `(`
14+
//~^^^ NOTE expected `:`
15+
},
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error: expected `:`, found `!`
2+
--> $DIR/macro-expand-to-field-2.rs:11:14
3+
|
4+
LL | field!(oopsies:()),
5+
| ^ expected `:`
6+
|
7+
= note: macros cannot expand to struct fields
8+
9+
error: expected `,`, or `}`, found `(`
10+
--> $DIR/macro-expand-to-field-2.rs:11:15
11+
|
12+
LL | Named {
13+
| ----- while parsing this struct
14+
LL | field!(oopsies:()),
15+
| ^
16+
17+
error: aborting due to 2 previous errors
18+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![no_main]
2+
3+
macro_rules! field {
4+
($name:ident:$type:ty) => {
5+
$name:$type
6+
};
7+
}
8+
9+
union EnumVariantField { //~ NOTE while parsing this union
10+
A: u32,
11+
field!(oopsies:()), //~ NOTE macros cannot expand to union fields
12+
//~^ ERROR expected `:`, found `!`
13+
//~^^ ERROR expected `,`, or `}`, found `(`
14+
//~^^^ NOTE expected `:`
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error: expected `:`, found `!`
2+
--> $DIR/macro-expand-to-field-3.rs:11:10
3+
|
4+
LL | field!(oopsies:()),
5+
| ^ expected `:`
6+
|
7+
= note: macros cannot expand to union fields
8+
9+
error: expected `,`, or `}`, found `(`
10+
--> $DIR/macro-expand-to-field-3.rs:11:11
11+
|
12+
LL | union EnumVariantField {
13+
| ---------------- while parsing this union
14+
LL | A: u32,
15+
LL | field!(oopsies:()),
16+
| ^
17+
18+
error: aborting due to 2 previous errors
19+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#![no_main]
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 { //~ NOTE while parsing this struct
16+
field!(bar:u128), //~ NOTE macros cannot expand to struct fields
17+
//~^ ERROR expected `:`, found `!`
18+
//~^^ NOTE expected `:`
19+
//~^^^ ERROR expected `,`, or `}`, found `(`
20+
}
21+
22+
enum EnumVariant { //~ NOTE while parsing this enum
23+
variant!(whoops), //~ NOTE macros cannot expand to enum variants
24+
//~^ ERROR unexpected token: `!`
25+
//~^^ NOTE unexpected token after this
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error: expected `:`, found `!`
2+
--> $DIR/macro-expand-to-field.rs:16:10
3+
|
4+
LL | field!(bar:u128),
5+
| ^ expected `:`
6+
|
7+
= note: macros cannot expand to struct fields
8+
9+
error: expected `,`, or `}`, found `(`
10+
--> $DIR/macro-expand-to-field.rs:16:11
11+
|
12+
LL | struct Struct {
13+
| ------ while parsing this struct
14+
LL | field!(bar:u128),
15+
| ^
16+
17+
error: unexpected token: `!`
18+
--> $DIR/macro-expand-to-field.rs:23:12
19+
|
20+
LL | enum EnumVariant {
21+
| ----------- while parsing this enum
22+
LL | variant!(whoops),
23+
| ^ unexpected token after this
24+
|
25+
= note: macros cannot expand to enum variants
26+
= help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
27+
28+
error: aborting due to 3 previous errors
29+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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 => {}), //~ NOTE macros cannot expand to match arms
12+
//~^ ERROR unexpected `,` in pattern
13+
_ => {},
14+
};
15+
}
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)