about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCatherine <catherine.3.flores@gmail.com>2023-07-24 04:55:47 +0000
committerCatherine Flores <catherine.3.flores@gmail.com>2023-07-24 00:25:17 -0500
commit287db04636ffefa3fdaa39fe0fdcc3cf75b60444 (patch)
tree745b89b10863c02ffe96a33220b12aea6fcfcca2
parent8771282d4e7a5c4569e49d1f878fb3ba90a974d0 (diff)
downloadrust-287db04636ffefa3fdaa39fe0fdcc3cf75b60444.tar.gz
rust-287db04636ffefa3fdaa39fe0fdcc3cf75b60444.zip
Specify macro is invalid in certain contexts
-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.rs26
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs12
-rw-r--r--tests/ui/parser/macro/macro-expand-to-field-2.rs16
-rw-r--r--tests/ui/parser/macro/macro-expand-to-field-2.stderr18
-rw-r--r--tests/ui/parser/macro/macro-expand-to-field-3.rs15
-rw-r--r--tests/ui/parser/macro/macro-expand-to-field-3.stderr19
-rw-r--r--tests/ui/parser/macro/macro-expand-to-field.rs26
-rw-r--r--tests/ui/parser/macro/macro-expand-to-field.stderr29
-rw-r--r--tests/ui/parser/macro/macro-expand-to-match-arm.rs15
-rw-r--r--tests/ui/parser/macro/macro-expand-to-match-arm.stderr10
13 files changed, 209 insertions, 26 deletions
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 9787d98c1a4..7d71449122f 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -457,6 +457,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 96e1c0e3c6d..7f209c63f42 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -1801,6 +1801,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 c3cf6437afa..3eed3ed9e1b 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -2591,6 +2591,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 {
@@ -2611,24 +2612,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 1470180dea7..6ec3a1ff1a5 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;
@@ -1342,6 +1342,13 @@ impl<'a> Parser<'a> {
                 }
                 let ident = this.parse_field_ident("enum", vlo)?;
 
+                if this.token == token::Not {
+                    return this.unexpected().map_err(|mut err| {
+                        err.note(fluent::parse_macro_expands_to_enum_variant);
+                        err
+                    });
+                }
+
                 let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) {
                     // Parse a struct variant.
                     let (fields, recovered) =
@@ -1369,7 +1376,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
         })
@@ -1691,9 +1698,10 @@ impl<'a> Parser<'a> {
         Ok(a_var)
     }
 
-    fn expect_field_ty_separator(&mut self) -> PResult<'a, ()> {
+    fn expect_field_ty_separator(&mut self, adt_ty: &str) -> PResult<'a, ()> {
         if let Err(mut err) = self.expect(&token::Colon) {
             let sm = self.sess.source_map();
+            let mac_invoc = self.token.kind == token::Not;
             let eq_typo = self.token.kind == token::Eq && self.look_ahead(1, |t| t.is_path_start());
             let semi_typo = self.token.kind == token::Semi
                 && self.look_ahead(1, |t| {
@@ -1705,7 +1713,9 @@ impl<'a> Parser<'a> {
                         _ => true,
                     }
                 });
-            if eq_typo || semi_typo {
+            if mac_invoc {
+                err.subdiagnostic(MacroExpandsToAdtField { adt_ty }).emit();
+            } else if eq_typo || semi_typo {
                 self.bump();
                 // Gracefully handle small typos.
                 err.span_suggestion_short(
@@ -1713,8 +1723,8 @@ impl<'a> Parser<'a> {
                     "field names and their types are separated with `:`",
                     ":",
                     Applicability::MachineApplicable,
-                );
-                err.emit();
+                )
+                .emit();
             } else {
                 return Err(err);
             }
@@ -1731,7 +1741,7 @@ impl<'a> Parser<'a> {
         attrs: AttrVec,
     ) -> PResult<'a, FieldDef> {
         let name = self.parse_field_ident(adt_ty, lo)?;
-        self.expect_field_ty_separator()?;
+        self.expect_field_ty_separator(adt_ty)?;
         let ty = self.parse_ty()?;
         if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) {
             self.sess.emit_err(errors::SingleColonStructType { span: self.token.span });
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 14891c45d81..b477453615d 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -135,7 +135,11 @@ impl<'a> Parser<'a> {
         // Parse the first pattern (`p_0`).
         let mut first_pat = self.parse_pat_no_top_alt(expected)?;
         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 `|`,
@@ -177,7 +181,11 @@ impl<'a> Parser<'a> {
                 err
             })?;
             if rc == RecoverComma::Yes {
-                self.maybe_recover_unexpected_comma(pat.span, rt)?;
+                self.maybe_recover_unexpected_comma(
+                    pat.span,
+                    matches!(pat.kind, PatKind::MacCall(_)),
+                    rt,
+                )?;
             }
             pats.push(pat);
         }
diff --git a/tests/ui/parser/macro/macro-expand-to-field-2.rs b/tests/ui/parser/macro/macro-expand-to-field-2.rs
new file mode 100644
index 00000000000..2f806bcea84
--- /dev/null
+++ b/tests/ui/parser/macro/macro-expand-to-field-2.rs
@@ -0,0 +1,16 @@
+#![no_main]
+
+macro_rules! field {
+    ($name:ident:$type:ty) => {
+        $name:$type
+    };
+}
+
+enum EnumVariantField {
+    Named { //~ NOTE while parsing this struct
+        field!(oopsies:()), //~ NOTE macros cannot expand to struct fields
+        //~^ ERROR expected `:`, found `!`
+        //~^^ ERROR expected `,`, or `}`, found `(`
+        //~^^^ NOTE expected `:`
+    },
+}
diff --git a/tests/ui/parser/macro/macro-expand-to-field-2.stderr b/tests/ui/parser/macro/macro-expand-to-field-2.stderr
new file mode 100644
index 00000000000..8c3758173fe
--- /dev/null
+++ b/tests/ui/parser/macro/macro-expand-to-field-2.stderr
@@ -0,0 +1,18 @@
+error: expected `:`, found `!`
+  --> $DIR/macro-expand-to-field-2.rs:11:14
+   |
+LL |         field!(oopsies:()),
+   |              ^ expected `:`
+   |
+   = note: macros cannot expand to struct fields
+
+error: expected `,`, or `}`, found `(`
+  --> $DIR/macro-expand-to-field-2.rs:11:15
+   |
+LL |     Named {
+   |     ----- while parsing this struct
+LL |         field!(oopsies:()),
+   |               ^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/parser/macro/macro-expand-to-field-3.rs b/tests/ui/parser/macro/macro-expand-to-field-3.rs
new file mode 100644
index 00000000000..0a8b655e0dc
--- /dev/null
+++ b/tests/ui/parser/macro/macro-expand-to-field-3.rs
@@ -0,0 +1,15 @@
+#![no_main]
+
+macro_rules! field {
+    ($name:ident:$type:ty) => {
+        $name:$type
+    };
+}
+
+union EnumVariantField { //~ NOTE while parsing this union
+    A: u32,
+    field!(oopsies:()), //~ NOTE macros cannot expand to union fields
+    //~^ ERROR expected `:`, found `!`
+    //~^^ ERROR expected `,`, or `}`, found `(`
+    //~^^^ NOTE expected `:`
+}
diff --git a/tests/ui/parser/macro/macro-expand-to-field-3.stderr b/tests/ui/parser/macro/macro-expand-to-field-3.stderr
new file mode 100644
index 00000000000..360b2bf793b
--- /dev/null
+++ b/tests/ui/parser/macro/macro-expand-to-field-3.stderr
@@ -0,0 +1,19 @@
+error: expected `:`, found `!`
+  --> $DIR/macro-expand-to-field-3.rs:11:10
+   |
+LL |     field!(oopsies:()),
+   |          ^ expected `:`
+   |
+   = note: macros cannot expand to union fields
+
+error: expected `,`, or `}`, found `(`
+  --> $DIR/macro-expand-to-field-3.rs:11:11
+   |
+LL | union EnumVariantField {
+   |       ---------------- while parsing this union
+LL |     A: u32,
+LL |     field!(oopsies:()),
+   |           ^
+
+error: aborting due to 2 previous errors
+
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..38055a3bbb2
--- /dev/null
+++ b/tests/ui/parser/macro/macro-expand-to-field.rs
@@ -0,0 +1,26 @@
+#![no_main]
+
+macro_rules! field {
+    ($name:ident:$type:ty) => {
+        $name:$type
+    };
+}
+
+macro_rules! variant {
+    ($name:ident) => {
+        $name
+    }
+}
+
+struct Struct { //~ NOTE while parsing this struct
+    field!(bar:u128), //~ NOTE macros cannot expand to struct fields
+    //~^ ERROR expected `:`, found `!`
+    //~^^ NOTE expected `:`
+    //~^^^ ERROR expected `,`, or `}`, found `(`
+}
+
+enum EnumVariant { //~ NOTE while parsing this enum
+    variant!(whoops), //~ NOTE macros cannot expand to enum variants
+    //~^ ERROR unexpected token: `!`
+    //~^^ NOTE 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..3f7fad334ec
--- /dev/null
+++ b/tests/ui/parser/macro/macro-expand-to-field.stderr
@@ -0,0 +1,29 @@
+error: expected `:`, found `!`
+  --> $DIR/macro-expand-to-field.rs:16:10
+   |
+LL |     field!(bar:u128),
+   |          ^ expected `:`
+   |
+   = note: macros cannot expand to struct fields
+
+error: expected `,`, or `}`, found `(`
+  --> $DIR/macro-expand-to-field.rs:16:11
+   |
+LL | struct Struct {
+   |        ------ while parsing this struct
+LL |     field!(bar:u128),
+   |           ^
+
+error: unexpected token: `!`
+  --> $DIR/macro-expand-to-field.rs:23:12
+   |
+LL | enum EnumVariant {
+   |      ----------- while parsing this enum
+LL |     variant!(whoops),
+   |            ^ unexpected token after this
+   |
+   = note: macros cannot expand to enum variants
+   = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
+
+error: aborting due to 3 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..043bf371902
--- /dev/null
+++ b/tests/ui/parser/macro/macro-expand-to-match-arm.rs
@@ -0,0 +1,15 @@
+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
+        _ => {},
+    };
+}
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
+