Repository: rust-lang/rust
Pull request: 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.

Changed files:
filename: compiler/rustc_resolve/src/errors.rs
patch: @@ -1198,6 +1198,15 @@ pub(crate) struct AttributesStartingWithRustcAreReserved {
     pub(crate) span: Span,
 }
 
+#[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 {

filename: compiler/rustc_resolve/src/macros.rs
patch: @@ -618,14 +618,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         }
 
         // 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,
+                    });
+                }
             }
         }
 

filename: tests/ui/feature-gates/feature-gate-rustc-attrs.rs
patch: @@ -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() {}

filename: tests/ui/feature-gates/feature-gate-rustc-attrs.stderr
patch: @@ -10,7 +10,7 @@ error: expected attribute, found macro `rustc::unknown`
 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]