about summary refs log tree commit diff
diff options
context:
space:
mode:
authorjyn <github@jyn.dev>2025-03-11 00:24:08 -0400
committerjyn <github@jyn.dev>2025-04-13 16:46:02 -0400
commitd50a8d5fb3727277f82440524e20a67e29dead4c (patch)
tree78acdfd39a727bccd0be62d614758cf9d2e4005c
parent092a284ba0421695f2032c947765429fd7095796 (diff)
downloadrust-d50a8d5fb3727277f82440524e20a67e29dead4c.tar.gz
rust-d50a8d5fb3727277f82440524e20a67e29dead4c.zip
Improve `-Z crate-attr` diagnostics
- Show the `#![ ... ]` in the span (to make it clear that it should not
  be included in the CLI argument)
- Show more detailed errors when the crate has valid token trees but
  invalid syntax.
  Previously, `crate-attr=feature(foo),feature(bar)` would just say
  "invalid crate attribute" and point at the comma. Now, it explicitly
  says that the comma was unexpected, which is useful when using
  `--error-format=short`. It also fixes the column to show the correct
  span.
- Recover from parse errors. Previously we would abort immediately on
  syntax errors; now we go on to try and type-check the rest of the
  crate.

The new diagnostic code also happens to be slightly shorter.
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs2
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl2
-rw-r--r--compiler/rustc_builtin_macros/src/cmdline_attrs.rs57
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs7
-rw-r--r--tests/ui/attributes/z-crate-attr/garbage.stderr16
-rw-r--r--tests/ui/attributes/z-crate-attr/injection.rs6
-rw-r--r--tests/ui/attributes/z-crate-attr/injection.stderr17
-rw-r--r--tests/ui/attributes/z-crate-attr/injection2.rs3
-rw-r--r--tests/ui/attributes/z-crate-attr/injection2.stderr15
-rw-r--r--tests/ui/attributes/z-crate-attr/inner-attr.stderr6
-rw-r--r--tests/ui/attributes/z-crate-attr/multiple.rs4
-rw-r--r--tests/ui/attributes/z-crate-attr/multiple.stderr8
-rw-r--r--tests/ui/attributes/z-crate-attr/unbalanced-paren.rs4
-rw-r--r--tests/ui/attributes/z-crate-attr/unbalanced-paren.stderr13
14 files changed, 82 insertions, 78 deletions
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 0b65246693d..d656d9b0b8a 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -627,7 +627,7 @@ pub fn mk_doc_comment(
     Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
 }
 
-pub fn mk_attr(
+fn mk_attr(
     g: &AttrIdGenerator,
     style: AttrStyle,
     unsafety: Safety,
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 603dc90bafc..5316e90847a 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -231,8 +231,6 @@ builtin_macros_format_unused_args = multiple unused formatting arguments
 
 builtin_macros_format_use_positional = consider using a positional formatting argument instead
 
-builtin_macros_invalid_crate_attribute = invalid crate attribute
-
 builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
     .note = only one `#[default]` attribute is needed
     .label = `#[default]` used here
diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
index 6afd8c4b43b..423b6a15b64 100644
--- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
+++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
@@ -1,44 +1,37 @@
 //! Attributes injected into the crate root from command line using `-Z crate-attr`.
 
-use rustc_ast::attr::mk_attr;
-use rustc_ast::{self as ast, AttrItem, AttrStyle, token};
-use rustc_parse::parser::ForceCollect;
-use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal};
+use rustc_ast::{self as ast};
+use rustc_errors::Diag;
+use rustc_parse::parser::attr::InnerAttrPolicy;
+use rustc_parse::{parse_in, source_str_to_stream};
 use rustc_session::parse::ParseSess;
 use rustc_span::FileName;
 
-use crate::errors;
-
 pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
     for raw_attr in attrs {
-        let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str(
-            psess,
-            FileName::cli_crate_attr_source_code(raw_attr),
-            raw_attr.clone(),
-        ));
-
-        let start_span = parser.token.span;
-        let AttrItem { unsafety, path, args, tokens: _ } =
-            match parser.parse_attr_item(ForceCollect::No) {
-                Ok(ai) => ai,
-                Err(err) => {
+        let source = format!("#![{raw_attr}]");
+        let parse = || -> Result<ast::Attribute, Vec<Diag<'_>>> {
+            let tokens = source_str_to_stream(
+                psess,
+                FileName::cli_crate_attr_source_code(raw_attr),
+                source,
+                None,
+            )?;
+            parse_in(psess, tokens, "<crate attribute>", |p| {
+                p.parse_attribute(InnerAttrPolicy::Permitted)
+            })
+            .map_err(|e| vec![e])
+        };
+        let meta = match parse() {
+            Ok(meta) => meta,
+            Err(errs) => {
+                for err in errs {
                     err.emit();
-                    continue;
                 }
-            };
-        let end_span = parser.token.span;
-        if parser.token != token::Eof {
-            psess.dcx().emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) });
-            continue;
-        }
+                continue;
+            }
+        };
 
-        krate.attrs.push(mk_attr(
-            &psess.attr_id_generator,
-            AttrStyle::Inner,
-            unsafety,
-            path,
-            args,
-            start_span.to(end_span),
-        ));
+        krate.attrs.push(meta);
     }
 }
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index 4bbe212f429..c2b1dff4cf1 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -110,13 +110,6 @@ pub(crate) struct ProcMacro {
 }
 
 #[derive(Diagnostic)]
-#[diag(builtin_macros_invalid_crate_attribute)]
-pub(crate) struct InvalidCrateAttr {
-    #[primary_span]
-    pub(crate) span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(builtin_macros_non_abi)]
 pub(crate) struct NonABI {
     #[primary_span]
diff --git a/tests/ui/attributes/z-crate-attr/garbage.stderr b/tests/ui/attributes/z-crate-attr/garbage.stderr
index 082046e31f8..12d18b0845f 100644
--- a/tests/ui/attributes/z-crate-attr/garbage.stderr
+++ b/tests/ui/attributes/z-crate-attr/garbage.stderr
@@ -1,20 +1,20 @@
 error: unknown start of token: `
-  --> <crate attribute>:1:1
+  --> <crate attribute>:1:4
    |
-LL | `%~@$#
-   | ^
+LL | #![`%~@$#]
+   |    ^
    |
 help: Unicode character '`' (Grave Accent) looks like ''' (Single Quote), but it is not
    |
-LL - `%~@$#
-LL + '%~@$#
+LL - #![`%~@$#]
+LL + #!['%~@$#]
    |
 
 error: expected identifier, found `%`
-  --> <crate attribute>:1:2
+  --> <crate attribute>:1:5
    |
-LL | `%~@$#
-   |  ^ expected identifier
+LL | #![`%~@$#]
+   |     ^ expected identifier
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/attributes/z-crate-attr/injection.rs b/tests/ui/attributes/z-crate-attr/injection.rs
index a91f9d2886e..ee7a27c7490 100644
--- a/tests/ui/attributes/z-crate-attr/injection.rs
+++ b/tests/ui/attributes/z-crate-attr/injection.rs
@@ -1,5 +1,3 @@
 //@ compile-flags: '-Zcrate-attr=feature(yeet_expr)]fn main(){}#[inline'
-
-fn foo() {}
-
-//~? ERROR unexpected closing delimiter: `]`
+//~? ERROR unexpected token
+fn foo() {} //~ ERROR `main` function not found
diff --git a/tests/ui/attributes/z-crate-attr/injection.stderr b/tests/ui/attributes/z-crate-attr/injection.stderr
index 6fec98baf8d..899dad07e60 100644
--- a/tests/ui/attributes/z-crate-attr/injection.stderr
+++ b/tests/ui/attributes/z-crate-attr/injection.stderr
@@ -1,8 +1,15 @@
-error: unexpected closing delimiter: `]`
-  --> <crate attribute>:1:19
+error: unexpected token: keyword `fn`
+  --> <crate attribute>:1:23
    |
-LL | feature(yeet_expr)]fn main(){}#[inline
-   |                   ^ unexpected closing delimiter
+LL | #![feature(yeet_expr)]fn main(){}#[inline]
+   |                       ^^ unexpected token after this
 
-error: aborting due to 1 previous error
+error[E0601]: `main` function not found in crate `injection`
+  --> $DIR/injection.rs:3:12
+   |
+LL | fn foo() {}
+   |            ^ consider adding a `main` function to `$DIR/injection.rs`
+
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0601`.
diff --git a/tests/ui/attributes/z-crate-attr/injection2.rs b/tests/ui/attributes/z-crate-attr/injection2.rs
new file mode 100644
index 00000000000..67ae3d17f3e
--- /dev/null
+++ b/tests/ui/attributes/z-crate-attr/injection2.rs
@@ -0,0 +1,3 @@
+//@ compile-flags: -Zcrate-attr=feature(yeet_expr)]#![allow(warnings)
+//~? ERROR unexpected token
+fn foo() {} //~ ERROR `main` function not found
diff --git a/tests/ui/attributes/z-crate-attr/injection2.stderr b/tests/ui/attributes/z-crate-attr/injection2.stderr
new file mode 100644
index 00000000000..51f54f900a1
--- /dev/null
+++ b/tests/ui/attributes/z-crate-attr/injection2.stderr
@@ -0,0 +1,15 @@
+error: unexpected token: `#`
+  --> <crate attribute>:1:23
+   |
+LL | #![feature(yeet_expr)]#![allow(warnings)]
+   |                       ^ unexpected token after this
+
+error[E0601]: `main` function not found in crate `injection2`
+  --> $DIR/injection2.rs:3:12
+   |
+LL | fn foo() {}
+   |            ^ consider adding a `main` function to `$DIR/injection2.rs`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0601`.
diff --git a/tests/ui/attributes/z-crate-attr/inner-attr.stderr b/tests/ui/attributes/z-crate-attr/inner-attr.stderr
index 06a063d310b..1acb8c2e750 100644
--- a/tests/ui/attributes/z-crate-attr/inner-attr.stderr
+++ b/tests/ui/attributes/z-crate-attr/inner-attr.stderr
@@ -1,8 +1,8 @@
 error: expected identifier, found `#`
-  --> <crate attribute>:1:1
+  --> <crate attribute>:1:4
    |
-LL | #![feature(foo)]
-   | ^ expected identifier
+LL | #![#![feature(foo)]]
+   |    ^ expected identifier
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/attributes/z-crate-attr/multiple.rs b/tests/ui/attributes/z-crate-attr/multiple.rs
index 47d35d2c3fd..8c60ea64fec 100644
--- a/tests/ui/attributes/z-crate-attr/multiple.rs
+++ b/tests/ui/attributes/z-crate-attr/multiple.rs
@@ -1,5 +1,3 @@
 //@ compile-flags: -Zcrate-attr=feature(foo),feature(bar)
-
+//~? ERROR expected `]`
 fn main() {}
-
-//~? ERROR invalid crate attribute
diff --git a/tests/ui/attributes/z-crate-attr/multiple.stderr b/tests/ui/attributes/z-crate-attr/multiple.stderr
index 9f968a7e134..b95c95dcd73 100644
--- a/tests/ui/attributes/z-crate-attr/multiple.stderr
+++ b/tests/ui/attributes/z-crate-attr/multiple.stderr
@@ -1,8 +1,8 @@
-error: invalid crate attribute
-  --> <crate attribute>:1:1
+error: expected `]`, found `,`
+  --> <crate attribute>:1:16
    |
-LL | feature(foo),feature(bar)
-   | ^^^^^^^^^^^^^
+LL | #![feature(foo),feature(bar)]
+   |                ^ expected `]`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/attributes/z-crate-attr/unbalanced-paren.rs b/tests/ui/attributes/z-crate-attr/unbalanced-paren.rs
index 77d5d698f65..5ef0a75a3a8 100644
--- a/tests/ui/attributes/z-crate-attr/unbalanced-paren.rs
+++ b/tests/ui/attributes/z-crate-attr/unbalanced-paren.rs
@@ -1,6 +1,4 @@
 // Show diagnostics for unbalanced parens.
 //@ compile-flags: -Zcrate-attr=(
-
+//~? ERROR mismatched closing delimiter
 fn main() {}
-
-//~? ERROR this file contains an unclosed delimiter
diff --git a/tests/ui/attributes/z-crate-attr/unbalanced-paren.stderr b/tests/ui/attributes/z-crate-attr/unbalanced-paren.stderr
index 47b1b764ba9..f6545d1db8b 100644
--- a/tests/ui/attributes/z-crate-attr/unbalanced-paren.stderr
+++ b/tests/ui/attributes/z-crate-attr/unbalanced-paren.stderr
@@ -1,10 +1,11 @@
-error: this file contains an unclosed delimiter
-  --> <crate attribute>:1:2
+error: mismatched closing delimiter: `]`
+  --> <crate attribute>:1:4
    |
-LL | (
-   | -^
-   | |
-   | unclosed delimiter
+LL | #![(]
+   |   -^^ mismatched closing delimiter
+   |   ||
+   |   |unclosed delimiter
+   |   closing delimiter possibly meant for this
 
 error: aborting due to 1 previous error