Rollup merge of #138336 - jyn514:crate-attr-diagnostics, r=compiler-errors

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.

r? diagnostics
This commit is contained in:
Jacob Pratt 2025-04-13 23:57:37 -04:00 committed by GitHub
commit 2b6835bf54
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 82 additions and 78 deletions

View file

@ -627,7 +627,7 @@ pub fn mk_doc_comment(
Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span } Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
} }
pub fn mk_attr( fn mk_attr(
g: &AttrIdGenerator, g: &AttrIdGenerator,
style: AttrStyle, style: AttrStyle,
unsafety: Safety, unsafety: Safety,

View file

@ -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_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 builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
.note = only one `#[default]` attribute is needed .note = only one `#[default]` attribute is needed
.label = `#[default]` used here .label = `#[default]` used here

View file

@ -1,44 +1,37 @@
//! Attributes injected into the crate root from command line using `-Z crate-attr`. //! 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};
use rustc_ast::{self as ast, AttrItem, AttrStyle, token}; use rustc_errors::Diag;
use rustc_parse::parser::ForceCollect; use rustc_parse::parser::attr::InnerAttrPolicy;
use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_parse::{parse_in, source_str_to_stream};
use rustc_session::parse::ParseSess; use rustc_session::parse::ParseSess;
use rustc_span::FileName; use rustc_span::FileName;
use crate::errors;
pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) { pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
for raw_attr in attrs { for raw_attr in attrs {
let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str( let source = format!("#![{raw_attr}]");
psess, let parse = || -> Result<ast::Attribute, Vec<Diag<'_>>> {
FileName::cli_crate_attr_source_code(raw_attr), let tokens = source_str_to_stream(
raw_attr.clone(), psess,
)); FileName::cli_crate_attr_source_code(raw_attr),
source,
let start_span = parser.token.span; None,
let AttrItem { unsafety, path, args, tokens: _ } = )?;
match parser.parse_attr_item(ForceCollect::No) { parse_in(psess, tokens, "<crate attribute>", |p| {
Ok(ai) => ai, p.parse_attribute(InnerAttrPolicy::Permitted)
Err(err) => { })
.map_err(|e| vec![e])
};
let meta = match parse() {
Ok(meta) => meta,
Err(errs) => {
for err in errs {
err.emit(); err.emit();
continue;
} }
}; 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;
}
krate.attrs.push(mk_attr( krate.attrs.push(meta);
&psess.attr_id_generator,
AttrStyle::Inner,
unsafety,
path,
args,
start_span.to(end_span),
));
} }
} }

View file

@ -109,13 +109,6 @@ pub(crate) struct ProcMacro {
pub(crate) span: Span, pub(crate) span: Span,
} }
#[derive(Diagnostic)]
#[diag(builtin_macros_invalid_crate_attribute)]
pub(crate) struct InvalidCrateAttr {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(builtin_macros_non_abi)] #[diag(builtin_macros_non_abi)]
pub(crate) struct NonABI { pub(crate) struct NonABI {

View file

@ -1,20 +1,20 @@
error: unknown start of token: ` 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 help: Unicode character '`' (Grave Accent) looks like ''' (Single Quote), but it is not
| |
LL - `%~@$# LL - #![`%~@$#]
LL + '%~@$# LL + #!['%~@$#]
| |
error: expected identifier, found `%` error: expected identifier, found `%`
--> <crate attribute>:1:2 --> <crate attribute>:1:5
| |
LL | `%~@$# LL | #![`%~@$#]
| ^ expected identifier | ^ expected identifier
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View file

@ -1,5 +1,3 @@
//@ compile-flags: '-Zcrate-attr=feature(yeet_expr)]fn main(){}#[inline' //@ compile-flags: '-Zcrate-attr=feature(yeet_expr)]fn main(){}#[inline'
//~? ERROR unexpected token
fn foo() {} fn foo() {} //~ ERROR `main` function not found
//~? ERROR unexpected closing delimiter: `]`

View file

@ -1,8 +1,15 @@
error: unexpected closing delimiter: `]` error: unexpected token: keyword `fn`
--> <crate attribute>:1:19 --> <crate attribute>:1:23
| |
LL | feature(yeet_expr)]fn main(){}#[inline LL | #![feature(yeet_expr)]fn main(){}#[inline]
| ^ unexpected closing delimiter | ^^ 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`.

View file

@ -0,0 +1,3 @@
//@ compile-flags: -Zcrate-attr=feature(yeet_expr)]#![allow(warnings)
//~? ERROR unexpected token
fn foo() {} //~ ERROR `main` function not found

View file

@ -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`.

View file

@ -1,8 +1,8 @@
error: expected identifier, found `#` error: expected identifier, found `#`
--> <crate attribute>:1:1 --> <crate attribute>:1:4
| |
LL | #![feature(foo)] LL | #![#![feature(foo)]]
| ^ expected identifier | ^ expected identifier
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -1,5 +1,3 @@
//@ compile-flags: -Zcrate-attr=feature(foo),feature(bar) //@ compile-flags: -Zcrate-attr=feature(foo),feature(bar)
//~? ERROR expected `]`
fn main() {} fn main() {}
//~? ERROR invalid crate attribute

View file

@ -1,8 +1,8 @@
error: invalid crate attribute error: expected `]`, found `,`
--> <crate attribute>:1:1 --> <crate attribute>:1:16
| |
LL | feature(foo),feature(bar) LL | #![feature(foo),feature(bar)]
| ^^^^^^^^^^^^^ | ^ expected `]`
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -1,6 +1,4 @@
// Show diagnostics for unbalanced parens. // Show diagnostics for unbalanced parens.
//@ compile-flags: -Zcrate-attr=( //@ compile-flags: -Zcrate-attr=(
//~? ERROR mismatched closing delimiter
fn main() {} fn main() {}
//~? ERROR this file contains an unclosed delimiter

View file

@ -1,10 +1,11 @@
error: this file contains an unclosed delimiter error: mismatched closing delimiter: `]`
--> <crate attribute>:1:2 --> <crate attribute>:1:4
| |
LL | ( LL | #![(]
| -^ | -^^ mismatched closing delimiter
| | | ||
| unclosed delimiter | |unclosed delimiter
| closing delimiter possibly meant for this
error: aborting due to 1 previous error error: aborting due to 1 previous error