Skip to content

Commit

Permalink
Rollup merge of #113999 - Centri3:macro-arm-expand, r=wesleywiser
Browse files Browse the repository at this point in the history
Specify macro is invalid in certain contexts

Adds a note when a macro is used where it really shouldn't be.

Closes #113766
  • Loading branch information
matthiaskrgr committed Aug 4, 2023
2 parents f36a9b5 + bbd69e4 commit 1f076fe
Show file tree
Hide file tree
Showing 9 changed files with 246 additions and 24 deletions.
6 changes: 6 additions & 0 deletions compiler/rustc_parse/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,12 @@ parse_loop_else = `{$loop_kind}...else` loops are not supported
.note = consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
.loop_keyword = `else` is attached to this loop
parse_macro_expands_to_adt_field = macros cannot expand to {$adt_ty} fields
parse_macro_expands_to_enum_variant = macros cannot expand to enum variants
parse_macro_expands_to_match_arm = macros cannot expand to match arms
parse_macro_invocation_visibility = can't qualify macro invocation with `pub`
.suggestion = remove the visibility
.help = try adjusting the macro to put `{$vis}` inside the invocation
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1815,6 +1815,12 @@ pub struct UnknownPrefix<'a> {
pub sugg: Option<UnknownPrefixSugg>,
}

#[derive(Subdiagnostic)]
#[note(parse_macro_expands_to_adt_field)]
pub struct MacroExpandsToAdtField<'a> {
pub adt_ty: &'a str,
}

#[derive(Subdiagnostic)]
pub enum UnknownPrefixSugg {
#[suggestion(
Expand Down
37 changes: 21 additions & 16 deletions compiler/rustc_parse/src/parser/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2641,6 +2641,7 @@ impl<'a> Parser<'a> {
pub(crate) fn maybe_recover_unexpected_comma(
&mut self,
lo: Span,
is_mac_invoc: bool,
rt: CommaRecoveryMode,
) -> PResult<'a, ()> {
if self.token != token::Comma {
Expand All @@ -2661,24 +2662,28 @@ impl<'a> Parser<'a> {
let seq_span = lo.to(self.prev_token.span);
let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern");
if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
err.multipart_suggestion(
format!(
"try adding parentheses to match on a tuple{}",
if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." },
),
vec![
(seq_span.shrink_to_lo(), "(".to_string()),
(seq_span.shrink_to_hi(), ")".to_string()),
],
Applicability::MachineApplicable,
);
if let CommaRecoveryMode::EitherTupleOrPipe = rt {
err.span_suggestion(
seq_span,
"...or a vertical bar to match on multiple alternatives",
seq_snippet.replace(',', " |"),
if is_mac_invoc {
err.note(fluent::parse_macro_expands_to_match_arm);
} else {
err.multipart_suggestion(
format!(
"try adding parentheses to match on a tuple{}",
if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." },
),
vec![
(seq_span.shrink_to_lo(), "(".to_string()),
(seq_span.shrink_to_hi(), ")".to_string()),
],
Applicability::MachineApplicable,
);
if let CommaRecoveryMode::EitherTupleOrPipe = rt {
err.span_suggestion(
seq_span,
"...or a vertical bar to match on multiple alternatives",
seq_snippet.replace(',', " |"),
Applicability::MachineApplicable,
);
}
}
}
Err(err)
Expand Down
41 changes: 35 additions & 6 deletions compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::errors;

use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
use crate::errors::{self, MacroExpandsToAdtField};
use crate::fluent_generated as fluent;
use ast::StaticItem;
use rustc_ast::ast::*;
use rustc_ast::ptr::P;
Expand Down Expand Up @@ -1450,6 +1450,17 @@ impl<'a> Parser<'a> {
}
let ident = this.parse_field_ident("enum", vlo)?;

if this.token == token::Not {
if let Err(mut err) = this.unexpected::<()>() {
err.note(fluent::parse_macro_expands_to_enum_variant).emit();
}

this.bump();
this.parse_delim_args()?;

return Ok((None, TrailingToken::MaybeComma));
}

let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) {
// Parse a struct variant.
let (fields, recovered) =
Expand Down Expand Up @@ -1477,7 +1488,7 @@ impl<'a> Parser<'a> {

Ok((Some(vr), TrailingToken::MaybeComma))
},
).map_err(|mut err|{
).map_err(|mut err| {
err.help("enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`");
err
})
Expand Down Expand Up @@ -1687,7 +1698,8 @@ impl<'a> Parser<'a> {
self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
let lo = this.token.span;
let vis = this.parse_visibility(FollowedByType::No)?;
Ok((this.parse_single_struct_field(adt_ty, lo, vis, attrs)?, TrailingToken::None))
this.parse_single_struct_field(adt_ty, lo, vis, attrs)
.map(|field| (field, TrailingToken::None))
})
}

Expand Down Expand Up @@ -1821,8 +1833,8 @@ impl<'a> Parser<'a> {
"field names and their types are separated with `:`",
":",
Applicability::MachineApplicable,
);
err.emit();
)
.emit();
} else {
return Err(err);
}
Expand All @@ -1839,6 +1851,23 @@ impl<'a> Parser<'a> {
attrs: AttrVec,
) -> PResult<'a, FieldDef> {
let name = self.parse_field_ident(adt_ty, lo)?;
// Parse the macro invocation and recover
if self.token.kind == token::Not {
if let Err(mut err) = self.unexpected::<FieldDef>() {
err.subdiagnostic(MacroExpandsToAdtField { adt_ty }).emit();
self.bump();
self.parse_delim_args()?;
return Ok(FieldDef {
span: DUMMY_SP,
ident: None,
vis,
id: DUMMY_NODE_ID,
ty: self.mk_ty(DUMMY_SP, TyKind::Err),
attrs,
is_placeholder: false,
});
}
}
self.expect_field_ty_separator()?;
let ty = self.parse_ty()?;
if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) {
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_parse/src/parser/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,11 @@ impl<'a> Parser<'a> {
// Parse the first pattern (`p_0`).
let mut first_pat = self.parse_pat_no_top_alt(expected, syntax_loc)?;
if rc == RecoverComma::Yes {
self.maybe_recover_unexpected_comma(first_pat.span, rt)?;
self.maybe_recover_unexpected_comma(
first_pat.span,
matches!(first_pat.kind, PatKind::MacCall(_)),
rt,
)?;
}

// If the next token is not a `|`,
Expand Down Expand Up @@ -184,7 +188,7 @@ impl<'a> Parser<'a> {
err
})?;
if rc == RecoverComma::Yes {
self.maybe_recover_unexpected_comma(pat.span, rt)?;
self.maybe_recover_unexpected_comma(pat.span, false, rt)?;
}
pats.push(pat);
}
Expand Down
70 changes: 70 additions & 0 deletions tests/ui/parser/macro/macro-expand-to-field.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// compile-flags: --crate-type=lib

macro_rules! field {
($name:ident:$type:ty) => {
$name:$type
};
}

macro_rules! variant {
($name:ident) => {
$name
}
}

struct Struct {
field!(bar:u128),
//~^ NOTE macros cannot expand to struct fields
//~| ERROR unexpected token: `!`
//~| NOTE unexpected token after this
a: u32,
b: u32,
field!(recovers:()), //~ NOTE macros cannot expand to struct fields
//~^ ERROR unexpected token: `!`
//~^^ NOTE unexpected token after this
}

enum EnumVariant {
variant!(whoops),
//~^ NOTE macros cannot expand to enum variants
//~| ERROR unexpected token: `!`
//~| NOTE unexpected token after this
U32,
F64,
variant!(recovers),
//~^ NOTE macros cannot expand to enum variants
//~| ERROR unexpected token: `!`
//~| NOTE unexpected token after this
Data {
field!(x:u32),
//~^ NOTE macros cannot expand to struct fields
//~| ERROR unexpected token: `!`
//~| NOTE unexpected token after this
}
}

enum EnumVariantField {
Named {
field!(oopsies:()),
//~^ NOTE macros cannot expand to struct fields
//~| ERROR unexpected token: `!`
//~| unexpected token after this
field!(oopsies2:()),
//~^ NOTE macros cannot expand to struct fields
//~| ERROR unexpected token: `!`
//~| unexpected token after this
},
}

union Union {
A: u32,
field!(oopsies:()),
//~^ NOTE macros cannot expand to union fields
//~| ERROR unexpected token: `!`
//~| unexpected token after this
B: u32,
field!(recovers:()),
//~^ NOTE macros cannot expand to union fields
//~| ERROR unexpected token: `!`
//~| unexpected token after this
}
74 changes: 74 additions & 0 deletions tests/ui/parser/macro/macro-expand-to-field.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
error: unexpected token: `!`
--> $DIR/macro-expand-to-field.rs:16:10
|
LL | field!(bar:u128),
| ^ unexpected token after this
|
= note: macros cannot expand to struct fields

error: unexpected token: `!`
--> $DIR/macro-expand-to-field.rs:22:10
|
LL | field!(recovers:()),
| ^ unexpected token after this
|
= note: macros cannot expand to struct fields

error: unexpected token: `!`
--> $DIR/macro-expand-to-field.rs:28:12
|
LL | variant!(whoops),
| ^ unexpected token after this
|
= note: macros cannot expand to enum variants

error: unexpected token: `!`
--> $DIR/macro-expand-to-field.rs:34:12
|
LL | variant!(recovers),
| ^ unexpected token after this
|
= note: macros cannot expand to enum variants

error: unexpected token: `!`
--> $DIR/macro-expand-to-field.rs:39:14
|
LL | field!(x:u32),
| ^ unexpected token after this
|
= note: macros cannot expand to struct fields

error: unexpected token: `!`
--> $DIR/macro-expand-to-field.rs:48:14
|
LL | field!(oopsies:()),
| ^ unexpected token after this
|
= note: macros cannot expand to struct fields

error: unexpected token: `!`
--> $DIR/macro-expand-to-field.rs:52:14
|
LL | field!(oopsies2:()),
| ^ unexpected token after this
|
= note: macros cannot expand to struct fields

error: unexpected token: `!`
--> $DIR/macro-expand-to-field.rs:61:10
|
LL | field!(oopsies:()),
| ^ unexpected token after this
|
= note: macros cannot expand to union fields

error: unexpected token: `!`
--> $DIR/macro-expand-to-field.rs:66:10
|
LL | field!(recovers:()),
| ^ unexpected token after this
|
= note: macros cannot expand to union fields

error: aborting due to 9 previous errors

18 changes: 18 additions & 0 deletions tests/ui/parser/macro/macro-expand-to-match-arm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
macro_rules! arm {
($pattern:pat => $block:block) => {
$pattern => $block
};
}

fn main() {
let x = Some(1);
match x {
Some(1) => {},
arm!(None => {}),
//~^ NOTE macros cannot expand to match arms
//~| ERROR unexpected `,` in pattern
// doesn't recover
Some(2) => {},
_ => {},
};
}
10 changes: 10 additions & 0 deletions tests/ui/parser/macro/macro-expand-to-match-arm.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: unexpected `,` in pattern
--> $DIR/macro-expand-to-match-arm.rs:11:25
|
LL | arm!(None => {}),
| ^
|
= note: macros cannot expand to match arms

error: aborting due to previous error

0 comments on commit 1f076fe

Please sign in to comment.