about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDanuel <public.danuel@gmail.com>2021-02-01 23:35:53 +0900
committerDanuel <public.danuel@gmail.com>2021-02-01 23:36:19 +0900
commit8bbb2d057d1084368412f5236dfad8990ef98e49 (patch)
tree38f39c0380ddc2c01fb32703592c31918621d7c2
parente0d9f793990d20f8f640097e28556886ba5362f0 (diff)
downloadrust-8bbb2d057d1084368412f5236dfad8990ef98e49.tar.gz
rust-8bbb2d057d1084368412f5236dfad8990ef98e49.zip
Fixed #[inline] to be warned in fields, arms, macro defs
Add visitors for checking #[inline]

Add visitors for checking #[inline] with struct field

Fix test for #[inline]

Add visitors for checking #[inline] with #[macro_export] macro

Add visitors for checking #[inline] without #[macro_export] macro

Add use alias with Visitor

Fix lint error

Reduce unnecessary variable

Co-authored-by: LingMan <LingMan@users.noreply.github.com>

Change error to warning

Add warning for checking field, arm with #[allow_internal_unstable]

Add name resolver

Formatting

Formatting

Fix error fixture

Add checking field, arm, macro def
-rw-r--r--compiler/rustc_hir/src/target.rs6
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs18
-rw-r--r--compiler/rustc_passes/src/check_attr.rs308
-rw-r--r--src/test/ui/attr-usage-inline.rs16
-rw-r--r--src/test/ui/attr-usage-inline.stderr8
-rw-r--r--src/test/ui/internal/internal-unstable.rs13
-rw-r--r--src/test/ui/internal/internal-unstable.stderr10
-rw-r--r--src/test/ui/proc-macro/ambiguous-builtin-attrs.rs4
-rw-r--r--src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr11
9 files changed, 341 insertions, 53 deletions
diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs
index 2774cc9c08e..6dbcfb963ee 100644
--- a/compiler/rustc_hir/src/target.rs
+++ b/compiler/rustc_hir/src/target.rs
@@ -38,12 +38,14 @@ pub enum Target {
     Enum,
     Variant,
     Struct,
+    Field,
     Union,
     Trait,
     TraitAlias,
     Impl,
     Expression,
     Statement,
+    Arm,
     AssocConst,
     Method(MethodKind),
     AssocTy,
@@ -51,6 +53,7 @@ pub enum Target {
     ForeignStatic,
     ForeignTy,
     GenericParam(GenericParamKind),
+    MacroDef,
 }
 
 impl Display for Target {
@@ -73,12 +76,14 @@ impl Display for Target {
                 Target::Enum => "enum",
                 Target::Variant => "enum variant",
                 Target::Struct => "struct",
+                Target::Field => "struct field",
                 Target::Union => "union",
                 Target::Trait => "trait",
                 Target::TraitAlias => "trait alias",
                 Target::Impl => "item",
                 Target::Expression => "expression",
                 Target::Statement => "statement",
+                Target::Arm => "match arm",
                 Target::AssocConst => "associated const",
                 Target::Method(_) => "method",
                 Target::AssocTy => "associated type",
@@ -90,6 +95,7 @@ impl Display for Target {
                     GenericParamKind::Lifetime => "lifetime parameter",
                     GenericParamKind::Const => "const parameter",
                 },
+                Target::MacroDef => "macro def",
             }
         )
     }
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 26b35e87ac4..412d5b5082b 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -8,6 +8,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, Definitions};
 use rustc_hir::intravisit;
+use rustc_hir::intravisit::Visitor;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::*;
 use rustc_index::vec::IndexVec;
@@ -494,6 +495,15 @@ impl<'hir> Map<'hir> {
         }
     }
 
+    pub fn visit_exported_macros_in_krate<V>(&self, visitor: &mut V)
+    where
+        V: Visitor<'hir>,
+    {
+        for id in self.krate().exported_macros {
+            visitor.visit_macro_def(self.expect_macro_def(id.hir_id));
+        }
+    }
+
     /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
     pub fn get(&self, id: HirId) -> Node<'hir> {
         self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id))
@@ -802,6 +812,13 @@ impl<'hir> Map<'hir> {
         }
     }
 
+    pub fn expect_macro_def(&self, id: HirId) -> &'hir MacroDef<'hir> {
+        match self.find(id) {
+            Some(Node::MacroDef(macro_def)) => macro_def,
+            _ => bug!("expected macro def, found {}", self.node_to_string(id)),
+        }
+    }
+
     pub fn expect_expr(&self, id: HirId) -> &'hir Expr<'hir> {
         match self.find(id) {
             Some(Node::Expr(expr)) => expr,
@@ -821,6 +838,7 @@ impl<'hir> Map<'hir> {
             Node::GenericParam(param) => param.name.ident().name,
             Node::Binding(&Pat { kind: PatKind::Binding(_, _, l, _), .. }) => l.name,
             Node::Ctor(..) => self.name(self.get_parent_item(id)),
+            Node::MacroDef(md) => md.ident.name,
             _ => return None,
         })
     }
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index ac73ba7062e..0e3a722e082 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -70,27 +70,27 @@ impl CheckAttrVisitor<'tcx> {
             is_valid &= if self.tcx.sess.check_name(attr, sym::inline) {
                 self.check_inline(hir_id, attr, span, target)
             } else if self.tcx.sess.check_name(attr, sym::non_exhaustive) {
-                self.check_non_exhaustive(attr, span, target)
+                self.check_non_exhaustive(hir_id, attr, span, target)
             } else if self.tcx.sess.check_name(attr, sym::marker) {
-                self.check_marker(attr, span, target)
+                self.check_marker(hir_id, attr, span, target)
             } else if self.tcx.sess.check_name(attr, sym::target_feature) {
                 self.check_target_feature(hir_id, attr, span, target)
             } else if self.tcx.sess.check_name(attr, sym::track_caller) {
-                self.check_track_caller(&attr.span, attrs, span, target)
+                self.check_track_caller(hir_id, &attr.span, attrs, span, target)
             } else if self.tcx.sess.check_name(attr, sym::doc) {
                 self.check_doc_attrs(attr, hir_id, target)
             } else if self.tcx.sess.check_name(attr, sym::no_link) {
-                self.check_no_link(&attr, span, target)
+                self.check_no_link(hir_id, &attr, span, target)
             } else if self.tcx.sess.check_name(attr, sym::export_name) {
-                self.check_export_name(&attr, span, target)
+                self.check_export_name(hir_id, &attr, span, target)
             } else if self.tcx.sess.check_name(attr, sym::rustc_args_required_const) {
                 self.check_rustc_args_required_const(&attr, span, target, item)
             } else if self.tcx.sess.check_name(attr, sym::allow_internal_unstable) {
-                self.check_allow_internal_unstable(&attr, span, target, &attrs)
+                self.check_allow_internal_unstable(hir_id, &attr, span, target, &attrs)
             } else if self.tcx.sess.check_name(attr, sym::rustc_allow_const_fn_unstable) {
                 self.check_rustc_allow_const_fn_unstable(hir_id, &attr, span, target)
             } else if self.tcx.sess.check_name(attr, sym::naked) {
-                self.check_naked(attr, span, target)
+                self.check_naked(hir_id, attr, span, target)
             } else {
                 // lint-only checks
                 if self.tcx.sess.check_name(attr, sym::cold) {
@@ -118,6 +118,41 @@ impl CheckAttrVisitor<'tcx> {
         self.check_used(attrs, target);
     }
 
+    fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
+        self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+            lint.build(&format!(
+                "`#[{}]` is ignored on struct fields, match arms and macro defs",
+                sym,
+            ))
+            .warn(
+                "this was previously accepted by the compiler but is \
+                 being phased out; it will become a hard error in \
+                 a future release!",
+            )
+            .note(
+                "see issue #80564 <https://github.com/rust-lang/rust/issues/80564> \
+                 for more information",
+            )
+            .emit();
+        });
+    }
+
+    fn inline_attr_str_error_without_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
+        self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+            lint.build(&format!("`#[{}]` is ignored on struct fields and match arms", sym))
+                .warn(
+                    "this was previously accepted by the compiler but is \
+                 being phased out; it will become a hard error in \
+                 a future release!",
+                )
+                .note(
+                    "see issue #80564 <https://github.com/rust-lang/rust/issues/80564> \
+                 for more information",
+                )
+                .emit();
+        });
+    }
+
     /// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
     fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
         match target {
@@ -150,6 +185,11 @@ impl CheckAttrVisitor<'tcx> {
                 });
                 true
             }
+            // FIXME(#80564): Same for fields, arms, and macro defs
+            Target::Field | Target::Arm | Target::MacroDef => {
+                self.inline_attr_str_error_with_macro_def(hir_id, attr, "inline");
+                true
+            }
             _ => {
                 struct_span_err!(
                     self.tcx.sess,
@@ -165,10 +205,18 @@ impl CheckAttrVisitor<'tcx> {
     }
 
     /// Checks if `#[naked]` is applied to a function definition.
-    fn check_naked(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
+    fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
         match target {
             Target::Fn
             | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
+            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+            // `#[allow_internal_unstable]` attribute with just a lint, because we previously
+            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // with crates depending on them, we can't throw an error here.
+            Target::Field | Target::Arm | Target::MacroDef => {
+                self.inline_attr_str_error_with_macro_def(hir_id, attr, "naked");
+                true
+            }
             _ => {
                 self.tcx
                     .sess
@@ -186,6 +234,7 @@ impl CheckAttrVisitor<'tcx> {
     /// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
     fn check_track_caller(
         &self,
+        hir_id: HirId,
         attr_span: &Span,
         attrs: &'hir [Attribute],
         span: &Span,
@@ -203,6 +252,16 @@ impl CheckAttrVisitor<'tcx> {
                 false
             }
             Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true,
+            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+            // `#[track_caller]` attribute with just a lint, because we previously
+            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // with crates depending on them, we can't throw an error here.
+            Target::Field | Target::Arm | Target::MacroDef => {
+                for attr in attrs {
+                    self.inline_attr_str_error_with_macro_def(hir_id, attr, "track_caller");
+                }
+                true
+            }
             _ => {
                 struct_span_err!(
                     self.tcx.sess,
@@ -218,9 +277,23 @@ impl CheckAttrVisitor<'tcx> {
     }
 
     /// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. Returns `true` if valid.
-    fn check_non_exhaustive(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
+    fn check_non_exhaustive(
+        &self,
+        hir_id: HirId,
+        attr: &Attribute,
+        span: &Span,
+        target: Target,
+    ) -> bool {
         match target {
             Target::Struct | Target::Enum | Target::Variant => true,
+            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+            // `#[non_exhaustive]` attribute with just a lint, because we previously
+            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // with crates depending on them, we can't throw an error here.
+            Target::Field | Target::Arm | Target::MacroDef => {
+                self.inline_attr_str_error_with_macro_def(hir_id, attr, "non_exhaustive");
+                true
+            }
             _ => {
                 struct_span_err!(
                     self.tcx.sess,
@@ -236,9 +309,17 @@ impl CheckAttrVisitor<'tcx> {
     }
 
     /// Checks if the `#[marker]` attribute on an `item` is valid. Returns `true` if valid.
-    fn check_marker(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
+    fn check_marker(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
         match target {
             Target::Trait => true,
+            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+            // `#[marker]` attribute with just a lint, because we previously
+            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // with crates depending on them, we can't throw an error here.
+            Target::Field | Target::Arm | Target::MacroDef => {
+                self.inline_attr_str_error_with_macro_def(hir_id, attr, "marker");
+                true
+            }
             _ => {
                 self.tcx
                     .sess
@@ -276,6 +357,14 @@ impl CheckAttrVisitor<'tcx> {
                 });
                 true
             }
+            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+            // `#[target_feature]` attribute with just a lint, because we previously
+            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // with crates depending on them, we can't throw an error here.
+            Target::Field | Target::Arm | Target::MacroDef => {
+                self.inline_attr_str_error_with_macro_def(hir_id, attr, "target_feature");
+                true
+            }
             _ => {
                 self.tcx
                     .sess
@@ -464,6 +553,13 @@ impl CheckAttrVisitor<'tcx> {
     fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
         match target {
             Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {}
+            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+            // `#[cold]` attribute with just a lint, because we previously
+            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // with crates depending on them, we can't throw an error here.
+            Target::Field | Target::Arm | Target::MacroDef => {
+                self.inline_attr_str_error_with_macro_def(hir_id, attr, "cold");
+            }
             _ => {
                 // FIXME: #[cold] was previously allowed on non-functions and some crates used
                 // this, so only emit a warning.
@@ -485,6 +581,13 @@ impl CheckAttrVisitor<'tcx> {
     fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
         match target {
             Target::ForeignFn | Target::ForeignStatic => {}
+            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+            // `#[link_name]` attribute with just a lint, because we previously
+            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // with crates depending on them, we can't throw an error here.
+            Target::Field | Target::Arm | Target::MacroDef => {
+                self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_name");
+            }
             _ => {
                 // FIXME: #[cold] was previously allowed on non-functions/statics and some crates
                 // used this, so only emit a warning.
@@ -517,23 +620,49 @@ impl CheckAttrVisitor<'tcx> {
     }
 
     /// Checks if `#[no_link]` is applied to an `extern crate`. Returns `true` if valid.
-    fn check_no_link(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
-        if target == Target::ExternCrate {
-            true
-        } else {
-            self.tcx
-                .sess
-                .struct_span_err(attr.span, "attribute should be applied to an `extern crate` item")
-                .span_label(*span, "not an `extern crate` item")
-                .emit();
-            false
+    fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
+        match target {
+            Target::ExternCrate => true,
+            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+            // `#[no_link]` attribute with just a lint, because we previously
+            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // with crates depending on them, we can't throw an error here.
+            Target::Field | Target::Arm | Target::MacroDef => {
+                self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_link");
+                true
+            }
+            _ => {
+                self.tcx
+                    .sess
+                    .struct_span_err(
+                        attr.span,
+                        "attribute should be applied to an `extern crate` item",
+                    )
+                    .span_label(*span, "not an `extern crate` item")
+                    .emit();
+                false
+            }
         }
     }
 
     /// Checks if `#[export_name]` is applied to a function or static. Returns `true` if valid.
-    fn check_export_name(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
+    fn check_export_name(
+        &self,
+        hir_id: HirId,
+        attr: &Attribute,
+        span: &Span,
+        target: Target,
+    ) -> bool {
         match target {
             Target::Static | Target::Fn | Target::Method(..) => true,
+            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+            // `#[export_name]` attribute with just a lint, because we previously
+            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // with crates depending on them, we can't throw an error here.
+            Target::Field | Target::Arm | Target::MacroDef => {
+                self.inline_attr_str_error_with_macro_def(hir_id, attr, "export_name");
+                true
+            }
             _ => {
                 self.tcx
                     .sess
@@ -625,6 +754,13 @@ impl CheckAttrVisitor<'tcx> {
     fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
         match target {
             Target::Static | Target::Fn | Target::Method(..) => {}
+            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+            // `#[link_section]` attribute with just a lint, because we previously
+            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // with crates depending on them, we can't throw an error here.
+            Target::Field | Target::Arm | Target::MacroDef => {
+                self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_section");
+            }
             _ => {
                 // FIXME: #[link_section] was previously allowed on non-functions/statics and some
                 // crates used this, so only emit a warning.
@@ -646,6 +782,13 @@ impl CheckAttrVisitor<'tcx> {
     fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
         match target {
             Target::Static | Target::Fn | Target::Method(..) => {}
+            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+            // `#[no_mangle]` attribute with just a lint, because we previously
+            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // with crates depending on them, we can't throw an error here.
+            Target::Field | Target::Arm | Target::MacroDef => {
+                self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_mangle");
+            }
             _ => {
                 // FIXME: #[no_mangle] was previously allowed on non-functions/statics and some
                 // crates used this, so only emit a warning.
@@ -828,27 +971,46 @@ impl CheckAttrVisitor<'tcx> {
     /// (Allows proc_macro functions)
     fn check_allow_internal_unstable(
         &self,
+        hir_id: HirId,
         attr: &Attribute,
         span: &Span,
         target: Target,
         attrs: &[Attribute],
     ) -> bool {
         debug!("Checking target: {:?}", target);
-        if target == Target::Fn {
-            for attr in attrs {
-                if self.tcx.sess.is_proc_macro_attr(attr) {
-                    debug!("Is proc macro attr");
-                    return true;
+        match target {
+            Target::Fn => {
+                for attr in attrs {
+                    if self.tcx.sess.is_proc_macro_attr(attr) {
+                        debug!("Is proc macro attr");
+                        return true;
+                    }
                 }
+                debug!("Is not proc macro attr");
+                false
+            }
+            Target::MacroDef => true,
+            // FIXME(#80564): We permit struct fields and match arms to have an
+            // `#[allow_internal_unstable]` attribute with just a lint, because we previously
+            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // with crates depending on them, we can't throw an error here.
+            Target::Field | Target::Arm => {
+                self.inline_attr_str_error_without_macro_def(
+                    hir_id,
+                    attr,
+                    "allow_internal_unstable",
+                );
+                true
+            }
+            _ => {
+                self.tcx
+                    .sess
+                    .struct_span_err(attr.span, "attribute should be applied to a macro")
+                    .span_label(*span, "not a macro")
+                    .emit();
+                false
             }
-            debug!("Is not proc macro attr");
         }
-        self.tcx
-            .sess
-            .struct_span_err(attr.span, "attribute should be applied to a macro")
-            .span_label(*span, "not a macro")
-            .emit();
-        false
     }
 
     /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
@@ -860,17 +1022,29 @@ impl CheckAttrVisitor<'tcx> {
         span: &Span,
         target: Target,
     ) -> bool {
-        if let Target::Fn | Target::Method(_) = target {
-            if self.tcx.is_const_fn_raw(self.tcx.hir().local_def_id(hir_id)) {
-                return true;
+        match target {
+            Target::Fn | Target::Method(_)
+                if self.tcx.is_const_fn_raw(self.tcx.hir().local_def_id(hir_id)) =>
+            {
+                true
+            }
+            // FIXME(#80564): We permit struct fields and match arms to have an
+            // `#[allow_internal_unstable]` attribute with just a lint, because we previously
+            // erroneously allowed it and some crates used it accidentally, to to be compatible
+            // with crates depending on them, we can't throw an error here.
+            Target::Field | Target::Arm | Target::MacroDef => {
+                self.inline_attr_str_error_with_macro_def(hir_id, attr, "allow_internal_unstable");
+                true
+            }
+            _ => {
+                self.tcx
+                    .sess
+                    .struct_span_err(attr.span, "attribute should be applied to `const fn`")
+                    .span_label(*span, "not a `const fn`")
+                    .emit();
+                false
             }
         }
-        self.tcx
-            .sess
-            .struct_span_err(attr.span, "attribute should be applied to `const fn`")
-            .span_label(*span, "not a `const fn`")
-            .emit();
-        false
     }
 }
 
@@ -911,6 +1085,33 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
         intravisit::walk_trait_item(self, trait_item)
     }
 
+    fn visit_struct_field(&mut self, struct_field: &'tcx hir::StructField<'tcx>) {
+        self.check_attributes(
+            struct_field.hir_id,
+            &struct_field.attrs,
+            &struct_field.span,
+            Target::Field,
+            None,
+        );
+        intravisit::walk_struct_field(self, struct_field);
+    }
+
+    fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
+        self.check_attributes(arm.hir_id, &arm.attrs, &arm.span, Target::Arm, None);
+        intravisit::walk_arm(self, arm);
+    }
+
+    fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef<'tcx>) {
+        self.check_attributes(
+            macro_def.hir_id,
+            &macro_def.attrs,
+            &macro_def.span,
+            Target::MacroDef,
+            None,
+        );
+        intravisit::walk_macro_def(self, macro_def);
+    }
+
     fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) {
         let target = Target::from_foreign_item(f_item);
         self.check_attributes(
@@ -999,11 +1200,28 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
     }
 }
 
+fn check_invalid_macro_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
+    for attr in attrs {
+        if tcx.sess.check_name(attr, sym::inline) {
+            struct_span_err!(
+                tcx.sess,
+                attr.span,
+                E0518,
+                "attribute should be applied to function or closure",
+            )
+            .span_label(attr.span, "not a function or closure")
+            .emit();
+        }
+    }
+}
+
 fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir()
-        .visit_item_likes_in_module(module_def_id, &mut CheckAttrVisitor { tcx }.as_deep_visitor());
+    let check_attr_visitor = &mut CheckAttrVisitor { tcx };
+    tcx.hir().visit_item_likes_in_module(module_def_id, &mut check_attr_visitor.as_deep_visitor());
+    tcx.hir().visit_exported_macros_in_krate(check_attr_visitor);
+    check_invalid_macro_level_attr(tcx, tcx.hir().krate().non_exported_macro_attrs);
     if module_def_id.is_top_level_module() {
-        CheckAttrVisitor { tcx }.check_attributes(
+        check_attr_visitor.check_attributes(
             CRATE_HIR_ID,
             tcx.hir().krate_attrs(),
             &DUMMY_SP,
diff --git a/src/test/ui/attr-usage-inline.rs b/src/test/ui/attr-usage-inline.rs
index 1996f4a692c..674c12454cd 100644
--- a/src/test/ui/attr-usage-inline.rs
+++ b/src/test/ui/attr-usage-inline.rs
@@ -6,4 +6,20 @@ fn f() {}
 #[inline] //~ ERROR: attribute should be applied to function or closure
 struct S;
 
+struct I {
+    #[inline]
+    i: u8,
+}
+
+#[macro_export]
+#[inline]
+macro_rules! m_e {
+    () => {};
+}
+
+#[inline] //~ ERROR: attribute should be applied to function or closure
+macro_rules! m {
+    () => {};
+}
+
 fn main() {}
diff --git a/src/test/ui/attr-usage-inline.stderr b/src/test/ui/attr-usage-inline.stderr
index d8d7f6adb82..22a0bf47e20 100644
--- a/src/test/ui/attr-usage-inline.stderr
+++ b/src/test/ui/attr-usage-inline.stderr
@@ -6,6 +6,12 @@ LL | #[inline]
 LL | struct S;
    | --------- not a function or closure
 
-error: aborting due to previous error
+error[E0518]: attribute should be applied to function or closure
+  --> $DIR/attr-usage-inline.rs:20:1
+   |
+LL | #[inline]
+   | ^^^^^^^^^ not a function or closure
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0518`.
diff --git a/src/test/ui/internal/internal-unstable.rs b/src/test/ui/internal/internal-unstable.rs
index 94bd6aab23b..b8987d3e13c 100644
--- a/src/test/ui/internal/internal-unstable.rs
+++ b/src/test/ui/internal/internal-unstable.rs
@@ -1,10 +1,17 @@
 // aux-build:internal_unstable.rs
 
 #![feature(allow_internal_unstable)]
+#[allow(dead_code)]
 
 #[macro_use]
 extern crate internal_unstable;
 
+struct Baz {
+    #[allow_internal_unstable]
+    //^ WARN `#[allow_internal_unstable]` is ignored on struct fields and match arms
+    baz: u8,
+}
+
 macro_rules! foo {
     ($e: expr, $f: expr) => {{
         $e;
@@ -40,4 +47,10 @@ fn main() {
     println!("{:?}", internal_unstable::unstable()); //~ ERROR use of unstable
 
     bar!(internal_unstable::unstable()); //~ ERROR use of unstable
+
+    match true {
+        #[allow_internal_unstable]
+        //^ WARN `#[allow_internal_unstable]` is ignored on struct fields and match arms
+        _ => {}
+    }
 }
diff --git a/src/test/ui/internal/internal-unstable.stderr b/src/test/ui/internal/internal-unstable.stderr
index 2e6360c75c4..a92ca4957b5 100644
--- a/src/test/ui/internal/internal-unstable.stderr
+++ b/src/test/ui/internal/internal-unstable.stderr
@@ -1,5 +1,5 @@
 error[E0658]: use of unstable library feature 'function'
-  --> $DIR/internal-unstable.rs:34:25
+  --> $DIR/internal-unstable.rs:41:25
    |
 LL |     pass_through_allow!(internal_unstable::unstable());
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     pass_through_allow!(internal_unstable::unstable());
    = help: add `#![feature(function)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'function'
-  --> $DIR/internal-unstable.rs:36:27
+  --> $DIR/internal-unstable.rs:43:27
    |
 LL |     pass_through_noallow!(internal_unstable::unstable());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -15,7 +15,7 @@ LL |     pass_through_noallow!(internal_unstable::unstable());
    = help: add `#![feature(function)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'function'
-  --> $DIR/internal-unstable.rs:40:22
+  --> $DIR/internal-unstable.rs:47:22
    |
 LL |     println!("{:?}", internal_unstable::unstable());
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL |     println!("{:?}", internal_unstable::unstable());
    = help: add `#![feature(function)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'function'
-  --> $DIR/internal-unstable.rs:42:10
+  --> $DIR/internal-unstable.rs:49:10
    |
 LL |     bar!(internal_unstable::unstable());
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -31,7 +31,7 @@ LL |     bar!(internal_unstable::unstable());
    = help: add `#![feature(function)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'function'
-  --> $DIR/internal-unstable.rs:12:9
+  --> $DIR/internal-unstable.rs:19:9
    |
 LL |         internal_unstable::unstable();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs b/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs
index 5f45f6892d2..a6e9ed14ff1 100644
--- a/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs
+++ b/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs
@@ -21,7 +21,9 @@ fn non_macro_expanded_location<#[repr(C)] T>() {
     //~^ ERROR `repr` is ambiguous
     //~| ERROR attribute should be applied to a struct, enum, or union
     match 0u8 {
-        #[repr(C)] //~ ERROR `repr` is ambiguous
+        #[repr(C)]
+        //~^ ERROR `repr` is ambiguous
+        //~| ERROR attribute should be applied to a struct, enum, or union
         _ => {}
     }
 }
diff --git a/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr b/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr
index dfd60dc92cc..15935ebebeb 100644
--- a/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr
+++ b/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr
@@ -1,5 +1,5 @@
 error[E0425]: cannot find value `NonExistent` in this scope
-  --> $DIR/ambiguous-builtin-attrs.rs:32:5
+  --> $DIR/ambiguous-builtin-attrs.rs:34:5
    |
 LL |     NonExistent;
    |     ^^^^^^^^^^^ not found in this scope
@@ -94,6 +94,15 @@ error[E0517]: attribute should be applied to a struct, enum, or union
 LL | fn non_macro_expanded_location<#[repr(C)] T>() {
    |                                       ^   - not a struct, enum, or union
 
+error[E0517]: attribute should be applied to a struct, enum, or union
+  --> $DIR/ambiguous-builtin-attrs.rs:24:16
+   |
+LL |         #[repr(C)]
+   |                ^
+...
+LL |         _ => {}
+   |         ------- not a struct, enum, or union
+
 error: aborting due to 8 previous errors
 
 Some errors have detailed explanations: E0425, E0517, E0659.