about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-08-04 07:25:45 +0200
committerGitHub <noreply@github.com>2023-08-04 07:25:45 +0200
commit1f076fe1d8ffd13c3f339cf619dfed5da6dec3f6 (patch)
tree2dfbdf104dee8daf71bf2a0771ec01a5fabb6cce
parentf36a9b5e18cda84da1790db4c9fd0f85fb8c5ce2 (diff)
parentbbd69e4a4c27f2407326a71a4eb37de694a72b87 (diff)
downloadrust-1f076fe1d8ffd13c3f339cf619dfed5da6dec3f6.tar.gz
rust-1f076fe1d8ffd13c3f339cf619dfed5da6dec3f6.zip
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
-rw-r--r--compiler/rustc_parse/messages.ftl6
-rw-r--r--compiler/rustc_parse/src/errors.rs6
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs37
-rw-r--r--compiler/rustc_parse/src/parser/item.rs41
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs8
-rw-r--r--tests/ui/parser/macro/macro-expand-to-field.rs70
-rw-r--r--tests/ui/parser/macro/macro-expand-to-field.stderr74
-rw-r--r--tests/ui/parser/macro/macro-expand-to-match-arm.rs18
-rw-r--r--tests/ui/parser/macro/macro-expand-to-match-arm.stderr10
9 files changed, 246 insertions, 24 deletions
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index f5c4b13c5ed..6888127f36c 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -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
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 553ef4b51c8..26f38c9156a 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -1816,6 +1816,12 @@ pub struct UnknownPrefix<'a> {
 }
 
 #[derive(Subdiagnostic)]
+#[note(parse_macro_expands_to_adt_field)]
+pub struct MacroExpandsToAdtField<'a> {
+    pub adt_ty: &'a str,
+}
+
+#[derive(Subdiagnostic)]
 pub enum UnknownPrefixSugg {
     #[suggestion(
         parse_suggestion_br,
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 3f13937f72e..4e639a54cf7 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -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 {
@@ -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)
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index e9cc858c8c5..24c65d061f9 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -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;
@@ -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) =
@@ -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
         })
@@ -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))
         })
     }
 
@@ -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);
             }
@@ -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) {
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index c709a0fc9da..4aadb7d7ca5 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -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 `|`,
@@ -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);
         }
diff --git a/tests/ui/parser/macro/macro-expand-to-field.rs b/tests/ui/parser/macro/macro-expand-to-field.rs
new file mode 100644
index 00000000000..155872f7a5d
--- /dev/null
+++ b/tests/ui/parser/macro/macro-expand-to-field.rs
@@ -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
+}
diff --git a/tests/ui/parser/macro/macro-expand-to-field.stderr b/tests/ui/parser/macro/macro-expand-to-field.stderr
new file mode 100644
index 00000000000..adcd032f5c0
--- /dev/null
+++ b/tests/ui/parser/macro/macro-expand-to-field.stderr
@@ -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
+
diff --git a/tests/ui/parser/macro/macro-expand-to-match-arm.rs b/tests/ui/parser/macro/macro-expand-to-match-arm.rs
new file mode 100644
index 00000000000..39d1d065ed9
--- /dev/null
+++ b/tests/ui/parser/macro/macro-expand-to-match-arm.rs
@@ -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) => {},
+        _ => {},
+    };
+}
diff --git a/tests/ui/parser/macro/macro-expand-to-match-arm.stderr b/tests/ui/parser/macro/macro-expand-to-match-arm.stderr
new file mode 100644
index 00000000000..1a5f4696858
--- /dev/null
+++ b/tests/ui/parser/macro/macro-expand-to-match-arm.stderr
@@ -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
+