Rollup merge of #153532 - jdonszelmann:attributes-containing-rustc, r=petrochenkov

Attributes containing rustc

r? @petrochenkov

I noticed that attributes *containing* the word rustc as a segment also error with a message referring to "starting with rustc". The first commit shows this going wrong by re-exporting `#[test]`, a built-in macro, from a module called rustc.

The 2nd commit addresses this by changing the diagnostic. However, given the wording I wonder if the real solution shouldn't be to allow attributes containing a `rustc` segment and only disallow them when they start. In other words, actually implement the behavior that the original diagnostic pointed out.
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index c9dad4d..9684d3a 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -1199,6 +1199,15 @@ pub(crate) struct AttributesStartingWithRustcAreReserved {
 }
 
 #[derive(Diagnostic)]
+#[diag(
+    "attributes containing a segment starting with `rustc` are reserved for use by the `rustc` compiler"
+)]
+pub(crate) struct AttributesContainingRustcAreReserved {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag("cannot use {$article} {$descr} through an import")]
 pub(crate) struct CannotUseThroughAnImport {
     #[primary_span]
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 6ae9d3a..619e612 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -618,14 +618,20 @@ fn smart_resolve_macro_path(
         }
 
         // Report errors for the resolved macro.
-        for segment in &path.segments {
+        for (idx, segment) in path.segments.iter().enumerate() {
             if let Some(args) = &segment.args {
                 self.dcx().emit_err(errors::GenericArgumentsInMacroPath { span: args.span() });
             }
             if kind == MacroKind::Attr && segment.ident.as_str().starts_with("rustc") {
-                self.dcx().emit_err(errors::AttributesStartingWithRustcAreReserved {
-                    span: segment.ident.span,
-                });
+                if idx == 0 {
+                    self.dcx().emit_err(errors::AttributesStartingWithRustcAreReserved {
+                        span: segment.ident.span,
+                    });
+                } else {
+                    self.dcx().emit_err(errors::AttributesContainingRustcAreReserved {
+                        span: segment.ident.span,
+                    });
+                }
             }
         }
 
diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs.rs b/tests/ui/feature-gates/feature-gate-rustc-attrs.rs
index e7b2eca..6382af3 100644
--- a/tests/ui/feature-gates/feature-gate-rustc-attrs.rs
+++ b/tests/ui/feature-gates/feature-gate-rustc-attrs.rs
@@ -12,7 +12,7 @@ mod unknown { pub macro rustc() {} }
 fn f() {}
 
 #[unknown::rustc]
-//~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
+//~^ ERROR attributes containing a segment starting with `rustc` are reserved for use by the `rustc` compiler
 //~| ERROR expected attribute, found macro `unknown::rustc`
 //~| NOTE not an attribute
 fn g() {}
diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs.stderr b/tests/ui/feature-gates/feature-gate-rustc-attrs.stderr
index d586038..bc0db8b 100644
--- a/tests/ui/feature-gates/feature-gate-rustc-attrs.stderr
+++ b/tests/ui/feature-gates/feature-gate-rustc-attrs.stderr
@@ -10,7 +10,7 @@
 LL | #[rustc::unknown]
    |   ^^^^^^^^^^^^^^ not an attribute
 
-error: attributes starting with `rustc` are reserved for use by the `rustc` compiler
+error: attributes containing a segment starting with `rustc` are reserved for use by the `rustc` compiler
   --> $DIR/feature-gate-rustc-attrs.rs:14:12
    |
 LL | #[unknown::rustc]