From fe60f19f7e98af78526364563fa6b40825fa97a8 Mon Sep 17 00:00:00 2001
From: Aaron Hill <aa1ronham@gmail.com>
Date: Mon, 1 Mar 2021 16:02:09 -0500
Subject: [PATCH] Ban custom inner attributes in expressions and statements

---
 compiler/rustc_expand/src/expand.rs       |  20 +-
 compiler/rustc_resolve/src/macros.rs      |  21 +-
 src/test/ui/proc-macro/inner-attrs.rs     |  21 +-
 src/test/ui/proc-macro/inner-attrs.stderr |  32 +++
 src/test/ui/proc-macro/inner-attrs.stdout | 314 ++++++++++++----------
 5 files changed, 246 insertions(+), 162 deletions(-)
 create mode 100644 src/test/ui/proc-macro/inner-attrs.stderr

diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 2674ccced6f..470788a972a 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -206,30 +206,36 @@ ast_fragments! {
     }
 }
 
+pub enum SupportsMacroExpansion {
+    No,
+    Yes { supports_inner_attrs: bool },
+}
+
 impl AstFragmentKind {
     crate fn dummy(self, span: Span) -> AstFragment {
         self.make_from(DummyResult::any(span)).expect("couldn't create a dummy AST fragment")
     }
 
-    /// Fragment supports macro expansion and not just inert attributes, `cfg` and `cfg_attr`.
-    pub fn supports_macro_expansion(self) -> bool {
+    pub fn supports_macro_expansion(self) -> SupportsMacroExpansion {
         match self {
             AstFragmentKind::OptExpr
             | AstFragmentKind::Expr
-            | AstFragmentKind::Pat
-            | AstFragmentKind::Ty
             | AstFragmentKind::Stmts
-            | AstFragmentKind::Items
+            | AstFragmentKind::Ty
+            | AstFragmentKind::Pat => SupportsMacroExpansion::Yes { supports_inner_attrs: false },
+            AstFragmentKind::Items
             | AstFragmentKind::TraitItems
             | AstFragmentKind::ImplItems
-            | AstFragmentKind::ForeignItems => true,
+            | AstFragmentKind::ForeignItems => {
+                SupportsMacroExpansion::Yes { supports_inner_attrs: true }
+            }
             AstFragmentKind::Arms
             | AstFragmentKind::Fields
             | AstFragmentKind::FieldPats
             | AstFragmentKind::GenericParams
             | AstFragmentKind::Params
             | AstFragmentKind::StructFields
-            | AstFragmentKind::Variants => false,
+            | AstFragmentKind::Variants => SupportsMacroExpansion::No,
         }
     }
 
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 2e47d4cecee..2efce1e1984 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -17,7 +17,7 @@ use rustc_errors::struct_span_err;
 use rustc_expand::base::Annotatable;
 use rustc_expand::base::{Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind};
 use rustc_expand::compile_declarative_macro;
-use rustc_expand::expand::{AstFragment, Invocation, InvocationKind};
+use rustc_expand::expand::{AstFragment, Invocation, InvocationKind, SupportsMacroExpansion};
 use rustc_feature::is_builtin_attr_name;
 use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
 use rustc_hir::def_id;
@@ -278,12 +278,12 @@ impl<'a> ResolverExpand for Resolver<'a> {
 
         // Derives are not included when `invocations` are collected, so we have to add them here.
         let parent_scope = &ParentScope { derives, ..parent_scope };
-        let require_inert = !invoc.fragment_kind.supports_macro_expansion();
+        let supports_macro_expansion = invoc.fragment_kind.supports_macro_expansion();
         let node_id = self.lint_node_id(eager_expansion_root);
         let (ext, res) = self.smart_resolve_macro_path(
             path,
             kind,
-            require_inert,
+            supports_macro_expansion,
             inner_attr,
             parent_scope,
             node_id,
@@ -457,7 +457,7 @@ impl<'a> Resolver<'a> {
         &mut self,
         path: &ast::Path,
         kind: MacroKind,
-        require_inert: bool,
+        supports_macro_expansion: SupportsMacroExpansion,
         inner_attr: bool,
         parent_scope: &ParentScope<'a>,
         node_id: NodeId,
@@ -505,8 +505,17 @@ impl<'a> Resolver<'a> {
 
         let unexpected_res = if ext.macro_kind() != kind {
             Some((kind.article(), kind.descr_expected()))
-        } else if require_inert && matches!(res, Res::Def(..)) {
-            Some(("a", "non-macro attribute"))
+        } else if matches!(res, Res::Def(..)) {
+            match supports_macro_expansion {
+                SupportsMacroExpansion::No => Some(("a", "non-macro attribute")),
+                SupportsMacroExpansion::Yes { supports_inner_attrs } => {
+                    if inner_attr && !supports_inner_attrs {
+                        Some(("a", "non-macro inner attribute"))
+                    } else {
+                        None
+                    }
+                }
+            }
         } else {
             None
         };
diff --git a/src/test/ui/proc-macro/inner-attrs.rs b/src/test/ui/proc-macro/inner-attrs.rs
index 6a353ca3263..5707621f80e 100644
--- a/src/test/ui/proc-macro/inner-attrs.rs
+++ b/src/test/ui/proc-macro/inner-attrs.rs
@@ -1,10 +1,10 @@
-// check-pass
 // compile-flags: -Z span-debug --error-format human
 // aux-build:test-macros.rs
 
 #![feature(custom_inner_attributes)]
 #![feature(proc_macro_hygiene)]
 #![feature(stmt_expr_attributes)]
+#![feature(rustc_attrs)]
 
 #![no_std] // Don't load unnecessary hygiene information from std
 extern crate std;
@@ -25,17 +25,34 @@ struct MyStruct {
 
 fn bar() {
     (#![print_target_and_args(fifth)] 1, 2);
+    //~^ ERROR expected non-macro inner attribute, found attribute macro
+
+    #[print_target_and_args(tuple_attrs)] (
+        #![cfg_attr(FALSE, rustc_dummy)]
+        3, 4, {
+            #![cfg_attr(not(FALSE), rustc_dummy(innermost))]
+            5
+        }
+    );
+
+    #[print_target_and_args(array_attrs)] [
+        #![rustc_dummy(inner)]
+        true; 0
+    ];
 
     [#![print_target_and_args(sixth)] 1 , 2];
+    //~^ ERROR expected non-macro inner attribute, found attribute macro
     [#![print_target_and_args(seventh)] true ; 5];
-
+    //~^ ERROR expected non-macro inner attribute, found attribute macro
 
     match 0 {
         #![print_target_and_args(eighth)]
+        //~^ ERROR expected non-macro inner attribute, found attribute macro
         _ => {}
     }
 
     MyStruct { #![print_target_and_args(ninth)] field: true };
+    //~^ ERROR expected non-macro inner attribute, found attribute macro
 }
 
 extern {
diff --git a/src/test/ui/proc-macro/inner-attrs.stderr b/src/test/ui/proc-macro/inner-attrs.stderr
new file mode 100644
index 00000000000..db774cbfb8f
--- /dev/null
+++ b/src/test/ui/proc-macro/inner-attrs.stderr
@@ -0,0 +1,32 @@
+error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
+  --> $DIR/inner-attrs.rs:27:9
+   |
+LL |     (#![print_target_and_args(fifth)] 1, 2);
+   |         ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
+
+error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
+  --> $DIR/inner-attrs.rs:43:9
+   |
+LL |     [#![print_target_and_args(sixth)] 1 , 2];
+   |         ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
+
+error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
+  --> $DIR/inner-attrs.rs:45:9
+   |
+LL |     [#![print_target_and_args(seventh)] true ; 5];
+   |         ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
+
+error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
+  --> $DIR/inner-attrs.rs:49:12
+   |
+LL |         #![print_target_and_args(eighth)]
+   |            ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
+
+error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
+  --> $DIR/inner-attrs.rs:54:19
+   |
+LL |     MyStruct { #![print_target_and_args(ninth)] field: true };
+   |                   ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/proc-macro/inner-attrs.stdout b/src/test/ui/proc-macro/inner-attrs.stdout
index 2fd8d8a242e..ae04544e533 100644
--- a/src/test/ui/proc-macro/inner-attrs.stdout
+++ b/src/test/ui/proc-macro/inner-attrs.stdout
@@ -290,231 +290,251 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
         span: $DIR/inner-attrs.rs:17:1: 20:2 (#0),
     },
 ]
-PRINT-ATTR_ARGS INPUT (DISPLAY): fifth
+PRINT-ATTR_ARGS INPUT (DISPLAY): tuple_attrs
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
-        ident: "fifth",
-        span: $DIR/inner-attrs.rs:27:31: 27:36 (#0),
+        ident: "tuple_attrs",
+        span: $DIR/inner-attrs.rs:30:29: 30:40 (#0),
     },
 ]
-PRINT-ATTR INPUT (DISPLAY): (1, 2) ;
+PRINT-ATTR INPUT (DISPLAY): (# ! [cfg_attr(FALSE, rustc_dummy)] 3, 4,
+ { # ! [cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }) ;
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [
+            Punct {
+                ch: '#',
+                spacing: Joint,
+                span: $DIR/inner-attrs.rs:31:9: 31:10 (#0),
+            },
+            Punct {
+                ch: '!',
+                spacing: Alone,
+                span: $DIR/inner-attrs.rs:31:10: 31:11 (#0),
+            },
+            Group {
+                delimiter: Bracket,
+                stream: TokenStream [
+                    Ident {
+                        ident: "cfg_attr",
+                        span: $DIR/inner-attrs.rs:31:12: 31:20 (#0),
+                    },
+                    Group {
+                        delimiter: Parenthesis,
+                        stream: TokenStream [
+                            Ident {
+                                ident: "FALSE",
+                                span: $DIR/inner-attrs.rs:31:21: 31:26 (#0),
+                            },
+                            Punct {
+                                ch: ',',
+                                spacing: Alone,
+                                span: $DIR/inner-attrs.rs:31:26: 31:27 (#0),
+                            },
+                            Ident {
+                                ident: "rustc_dummy",
+                                span: $DIR/inner-attrs.rs:31:28: 31:39 (#0),
+                            },
+                        ],
+                        span: $DIR/inner-attrs.rs:31:20: 31:40 (#0),
+                    },
+                ],
+                span: $DIR/inner-attrs.rs:31:11: 31:41 (#0),
+            },
             Literal {
                 kind: Integer,
-                symbol: "1",
+                symbol: "3",
                 suffix: None,
-                span: $DIR/inner-attrs.rs:27:5: 27:45 (#0),
+                span: $DIR/inner-attrs.rs:32:9: 32:10 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:27:5: 27:45 (#0),
+                span: $DIR/inner-attrs.rs:32:10: 32:11 (#0),
             },
             Literal {
                 kind: Integer,
-                symbol: "2",
+                symbol: "4",
                 suffix: None,
-                span: $DIR/inner-attrs.rs:27:5: 27:45 (#0),
-            },
-        ],
-        span: $DIR/inner-attrs.rs:27:5: 27:45 (#0),
-    },
-    Punct {
-        ch: ';',
-        spacing: Alone,
-        span: $DIR/inner-attrs.rs:27:5: 27:45 (#0),
-    },
-]
-PRINT-ATTR_ARGS INPUT (DISPLAY): sixth
-PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
-    Ident {
-        ident: "sixth",
-        span: $DIR/inner-attrs.rs:29:31: 29:36 (#0),
-    },
-]
-PRINT-ATTR INPUT (DISPLAY): [1, 2] ;
-PRINT-ATTR INPUT (DEBUG): TokenStream [
-    Group {
-        delimiter: Bracket,
-        stream: TokenStream [
-            Literal {
-                kind: Integer,
-                symbol: "1",
-                suffix: None,
-                span: $DIR/inner-attrs.rs:29:5: 29:46 (#0),
+                span: $DIR/inner-attrs.rs:32:12: 32:13 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:29:5: 29:46 (#0),
+                span: $DIR/inner-attrs.rs:32:13: 32:14 (#0),
             },
-            Literal {
-                kind: Integer,
-                symbol: "2",
-                suffix: None,
-                span: $DIR/inner-attrs.rs:29:5: 29:46 (#0),
+            Group {
+                delimiter: Brace,
+                stream: TokenStream [
+                    Punct {
+                        ch: '#',
+                        spacing: Joint,
+                        span: $DIR/inner-attrs.rs:33:13: 33:14 (#0),
+                    },
+                    Punct {
+                        ch: '!',
+                        spacing: Alone,
+                        span: $DIR/inner-attrs.rs:33:14: 33:15 (#0),
+                    },
+                    Group {
+                        delimiter: Bracket,
+                        stream: TokenStream [
+                            Ident {
+                                ident: "cfg_attr",
+                                span: $DIR/inner-attrs.rs:33:16: 33:24 (#0),
+                            },
+                            Group {
+                                delimiter: Parenthesis,
+                                stream: TokenStream [
+                                    Ident {
+                                        ident: "not",
+                                        span: $DIR/inner-attrs.rs:33:25: 33:28 (#0),
+                                    },
+                                    Group {
+                                        delimiter: Parenthesis,
+                                        stream: TokenStream [
+                                            Ident {
+                                                ident: "FALSE",
+                                                span: $DIR/inner-attrs.rs:33:29: 33:34 (#0),
+                                            },
+                                        ],
+                                        span: $DIR/inner-attrs.rs:33:28: 33:35 (#0),
+                                    },
+                                    Punct {
+                                        ch: ',',
+                                        spacing: Alone,
+                                        span: $DIR/inner-attrs.rs:33:35: 33:36 (#0),
+                                    },
+                                    Ident {
+                                        ident: "rustc_dummy",
+                                        span: $DIR/inner-attrs.rs:33:37: 33:48 (#0),
+                                    },
+                                    Group {
+                                        delimiter: Parenthesis,
+                                        stream: TokenStream [
+                                            Ident {
+                                                ident: "innermost",
+                                                span: $DIR/inner-attrs.rs:33:49: 33:58 (#0),
+                                            },
+                                        ],
+                                        span: $DIR/inner-attrs.rs:33:48: 33:59 (#0),
+                                    },
+                                ],
+                                span: $DIR/inner-attrs.rs:33:24: 33:60 (#0),
+                            },
+                        ],
+                        span: $DIR/inner-attrs.rs:33:15: 33:61 (#0),
+                    },
+                    Literal {
+                        kind: Integer,
+                        symbol: "5",
+                        suffix: None,
+                        span: $DIR/inner-attrs.rs:34:13: 34:14 (#0),
+                    },
+                ],
+                span: $DIR/inner-attrs.rs:32:15: 35:10 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:29:5: 29:46 (#0),
+        span: $DIR/inner-attrs.rs:30:43: 36:6 (#0),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: $DIR/inner-attrs.rs:29:5: 29:46 (#0),
+        span: $DIR/inner-attrs.rs:36:6: 36:7 (#0),
     },
 ]
-PRINT-ATTR_ARGS INPUT (DISPLAY): seventh
+PRINT-ATTR_ARGS INPUT (DISPLAY): array_attrs
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
-        ident: "seventh",
-        span: $DIR/inner-attrs.rs:30:31: 30:38 (#0),
+        ident: "array_attrs",
+        span: $DIR/inner-attrs.rs:38:29: 38:40 (#0),
     },
 ]
-PRINT-ATTR INPUT (DISPLAY): [true ; 5] ;
+PRINT-ATTR INPUT (DISPLAY): [# ! [rustc_dummy(inner)] true ; 0] ;
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Group {
         delimiter: Bracket,
         stream: TokenStream [
+            Punct {
+                ch: '#',
+                spacing: Joint,
+                span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
+            },
+            Punct {
+                ch: '!',
+                spacing: Alone,
+                span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
+            },
+            Group {
+                delimiter: Bracket,
+                stream: TokenStream [
+                    Ident {
+                        ident: "rustc_dummy",
+                        span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
+                    },
+                    Group {
+                        delimiter: Parenthesis,
+                        stream: TokenStream [
+                            Ident {
+                                ident: "inner",
+                                span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
+                            },
+                        ],
+                        span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
+                    },
+                ],
+                span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
+            },
             Ident {
                 ident: "true",
-                span: $DIR/inner-attrs.rs:30:5: 30:51 (#0),
+                span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
             },
             Punct {
                 ch: ';',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:30:5: 30:51 (#0),
+                span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
             },
             Literal {
                 kind: Integer,
-                symbol: "5",
+                symbol: "0",
                 suffix: None,
-                span: $DIR/inner-attrs.rs:30:5: 30:51 (#0),
+                span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:30:5: 30:51 (#0),
+        span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: $DIR/inner-attrs.rs:30:5: 30:51 (#0),
-    },
-]
-PRINT-ATTR_ARGS INPUT (DISPLAY): eighth
-PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
-    Ident {
-        ident: "eighth",
-        span: $DIR/inner-attrs.rs:34:34: 34:40 (#0),
-    },
-]
-PRINT-ATTR INPUT (DISPLAY): match 0 { _ => { } }
-PRINT-ATTR INPUT (DEBUG): TokenStream [
-    Ident {
-        ident: "match",
-        span: $DIR/inner-attrs.rs:33:5: 36:6 (#0),
-    },
-    Literal {
-        kind: Integer,
-        symbol: "0",
-        suffix: None,
-        span: $DIR/inner-attrs.rs:33:5: 36:6 (#0),
-    },
-    Group {
-        delimiter: Brace,
-        stream: TokenStream [
-            Ident {
-                ident: "_",
-                span: $DIR/inner-attrs.rs:33:5: 36:6 (#0),
-            },
-            Punct {
-                ch: '=',
-                spacing: Joint,
-                span: $DIR/inner-attrs.rs:33:5: 36:6 (#0),
-            },
-            Punct {
-                ch: '>',
-                spacing: Alone,
-                span: $DIR/inner-attrs.rs:33:5: 36:6 (#0),
-            },
-            Group {
-                delimiter: Brace,
-                stream: TokenStream [],
-                span: $DIR/inner-attrs.rs:33:5: 36:6 (#0),
-            },
-        ],
-        span: $DIR/inner-attrs.rs:33:5: 36:6 (#0),
-    },
-]
-PRINT-ATTR_ARGS INPUT (DISPLAY): ninth
-PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
-    Ident {
-        ident: "ninth",
-        span: $DIR/inner-attrs.rs:38:41: 38:46 (#0),
-    },
-]
-PRINT-ATTR INPUT (DISPLAY): MyStruct { field : true, } ;
-PRINT-ATTR INPUT (DEBUG): TokenStream [
-    Ident {
-        ident: "MyStruct",
-        span: $DIR/inner-attrs.rs:38:5: 38:63 (#0),
-    },
-    Group {
-        delimiter: Brace,
-        stream: TokenStream [
-            Ident {
-                ident: "field",
-                span: $DIR/inner-attrs.rs:38:5: 38:63 (#0),
-            },
-            Punct {
-                ch: ':',
-                spacing: Alone,
-                span: $DIR/inner-attrs.rs:38:5: 38:63 (#0),
-            },
-            Ident {
-                ident: "true",
-                span: $DIR/inner-attrs.rs:38:5: 38:63 (#0),
-            },
-            Punct {
-                ch: ',',
-                spacing: Alone,
-                span: $DIR/inner-attrs.rs:38:5: 38:63 (#0),
-            },
-        ],
-        span: $DIR/inner-attrs.rs:38:5: 38:63 (#0),
-    },
-    Punct {
-        ch: ';',
-        spacing: Alone,
-        span: $DIR/inner-attrs.rs:38:5: 38:63 (#0),
+        span: $DIR/inner-attrs.rs:38:43: 41:7 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): tenth
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "tenth",
-        span: $DIR/inner-attrs.rs:43:42: 43:47 (#0),
+        span: $DIR/inner-attrs.rs:60:42: 60:47 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): fn weird_extern() { }
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:42:5: 44:6 (#0),
+        span: $DIR/inner-attrs.rs:59:5: 61:6 (#0),
     },
     Ident {
         ident: "weird_extern",
-        span: $DIR/inner-attrs.rs:42:5: 44:6 (#0),
+        span: $DIR/inner-attrs.rs:59:5: 61:6 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:42:5: 44:6 (#0),
+        span: $DIR/inner-attrs.rs:59:5: 61:6 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:42:5: 44:6 (#0),
+        span: $DIR/inner-attrs.rs:59:5: 61:6 (#0),
     },
 ]