Skip to content

Commit 93edf9f

Browse files
committed
Auto merge of #137729 - jdonszelmann:fix-137687, r=fmease
Port `#[crate_name]` to the new attribute parsing infrastructure r? `@fmease` Closes #137687
2 parents 4eedad3 + 48a4e2d commit 93edf9f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+440
-228
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3791,7 +3791,6 @@ dependencies = [
37913791
"rustc_error_messages",
37923792
"rustc_fluent_macro",
37933793
"rustc_hashes",
3794-
"rustc_hir_id",
37953794
"rustc_index",
37963795
"rustc_lexer",
37973796
"rustc_lint_defs",
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use super::prelude::*;
2+
3+
pub(crate) struct CrateNameParser;
4+
5+
impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
6+
const PATH: &[Symbol] = &[sym::crate_name];
7+
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
8+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
9+
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
10+
11+
// FIXME: crate name is allowed on all targets and ignored,
12+
// even though it should only be valid on crates of course
13+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
14+
15+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
16+
let ArgParser::NameValue(n) = args else {
17+
cx.expected_name_value(cx.attr_span, None);
18+
return None;
19+
};
20+
21+
let Some(name) = n.value_as_str() else {
22+
cx.expected_string_literal(n.value_span, Some(n.value_as_lit()));
23+
return None;
24+
};
25+
26+
Some(AttributeKind::CrateName {
27+
name,
28+
name_span: n.value_span,
29+
attr_span: cx.attr_span,
30+
style: cx.attr_style,
31+
})
32+
}
33+
}

compiler/rustc_attr_parsing/src/attributes/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ pub(crate) mod cfg;
3535
pub(crate) mod cfg_old;
3636
pub(crate) mod codegen_attrs;
3737
pub(crate) mod confusables;
38+
pub(crate) mod crate_level;
3839
pub(crate) mod deprecation;
3940
pub(crate) mod dummy;
4041
pub(crate) mod inline;

compiler/rustc_attr_parsing/src/attributes/util.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rustc_ast::LitKind;
2-
use rustc_ast::attr::{AttributeExt, first_attr_value_str_by_name};
2+
use rustc_ast::attr::AttributeExt;
33
use rustc_feature::is_builtin_attr_name;
44
use rustc_hir::RustcVersion;
55
use rustc_span::{Symbol, sym};
@@ -27,10 +27,6 @@ pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool {
2727
attr.is_doc_comment() || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name))
2828
}
2929

30-
pub fn find_crate_name(attrs: &[impl AttributeExt]) -> Option<Symbol> {
31-
first_attr_value_str_by_name(attrs, sym::crate_name)
32-
}
33-
3430
pub fn is_doc_alias_attrs_contain_symbol<'tcx, T: AttributeExt + 'tcx>(
3531
attrs: impl Iterator<Item = &'tcx T>,
3632
symbol: Symbol,

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::sync::LazyLock;
55

66
use private::Sealed;
77
use rustc_ast::{AttrStyle, MetaItemLit, NodeId};
8-
use rustc_errors::Diagnostic;
8+
use rustc_errors::{Diag, Diagnostic, Level};
99
use rustc_feature::AttributeTemplate;
1010
use rustc_hir::attrs::AttributeKind;
1111
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
@@ -24,6 +24,7 @@ use crate::attributes::codegen_attrs::{
2424
UsedParser,
2525
};
2626
use crate::attributes::confusables::ConfusablesParser;
27+
use crate::attributes::crate_level::CrateNameParser;
2728
use crate::attributes::deprecation::DeprecationParser;
2829
use crate::attributes::dummy::DummyParser;
2930
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
@@ -166,6 +167,7 @@ attribute_parsers!(
166167

167168
// tidy-alphabetical-start
168169
Single<CoverageParser>,
170+
Single<CrateNameParser>,
169171
Single<CustomMirParser>,
170172
Single<DeprecationParser>,
171173
Single<DummyParser>,
@@ -263,11 +265,7 @@ impl Stage for Early {
263265
sess: &'sess Session,
264266
diag: impl for<'x> Diagnostic<'x>,
265267
) -> ErrorGuaranteed {
266-
if self.emit_errors.should_emit() {
267-
sess.dcx().emit_err(diag)
268-
} else {
269-
sess.dcx().create_err(diag).delay_as_bug()
270-
}
268+
self.should_emit().emit_err(sess.dcx().create_err(diag))
271269
}
272270

273271
fn should_emit(&self) -> ShouldEmit {
@@ -314,7 +312,9 @@ pub struct AcceptContext<'f, 'sess, S: Stage> {
314312
/// The span of the attribute currently being parsed
315313
pub(crate) attr_span: Span,
316314

315+
/// Whether it is an inner or outer attribute
317316
pub(crate) attr_style: AttrStyle,
317+
318318
/// The expected structure of the attribute.
319319
///
320320
/// Used in reporting errors to give a hint to users what the attribute *should* look like.
@@ -333,7 +333,7 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
333333
/// must be delayed until after HIR is built. This method will take care of the details of
334334
/// that.
335335
pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) {
336-
if !self.stage.should_emit().should_emit() {
336+
if matches!(self.stage.should_emit(), ShouldEmit::Nothing) {
337337
return;
338338
}
339339
let id = self.target_id;
@@ -651,8 +651,13 @@ pub enum OmitDoc {
651651
Skip,
652652
}
653653

654-
#[derive(Copy, Clone)]
654+
#[derive(Copy, Clone, Debug)]
655655
pub enum ShouldEmit {
656+
/// The operations will emit errors, and lints, and errors are fatal.
657+
///
658+
/// Only relevant when early parsing, in late parsing equivalent to `ErrorsAndLints`.
659+
/// Late parsing is never fatal, and instead tries to emit as many diagnostics as possible.
660+
EarlyFatal,
656661
/// The operation will emit errors and lints.
657662
/// This is usually what you need.
658663
ErrorsAndLints,
@@ -662,10 +667,12 @@ pub enum ShouldEmit {
662667
}
663668

664669
impl ShouldEmit {
665-
pub fn should_emit(&self) -> bool {
670+
pub(crate) fn emit_err(&self, diag: Diag<'_>) -> ErrorGuaranteed {
666671
match self {
667-
ShouldEmit::ErrorsAndLints => true,
668-
ShouldEmit::Nothing => false,
672+
ShouldEmit::EarlyFatal if diag.level() == Level::DelayedBug => diag.emit(),
673+
ShouldEmit::EarlyFatal => diag.upgrade_to_fatal().emit(),
674+
ShouldEmit::ErrorsAndLints => diag.emit(),
675+
ShouldEmit::Nothing => diag.delay_as_bug(),
669676
}
670677
}
671678
}

compiler/rustc_attr_parsing/src/interface.rs

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,27 @@ impl<'sess> AttributeParser<'sess, Early> {
5050
target_span: Span,
5151
target_node_id: NodeId,
5252
features: Option<&'sess Features>,
53+
) -> Option<Attribute> {
54+
Self::parse_limited_should_emit(
55+
sess,
56+
attrs,
57+
sym,
58+
target_span,
59+
target_node_id,
60+
features,
61+
ShouldEmit::Nothing,
62+
)
63+
}
64+
65+
/// Usually you want `parse_limited`, which defaults to no errors.
66+
pub fn parse_limited_should_emit(
67+
sess: &'sess Session,
68+
attrs: &[ast::Attribute],
69+
sym: Symbol,
70+
target_span: Span,
71+
target_node_id: NodeId,
72+
features: Option<&'sess Features>,
73+
should_emit: ShouldEmit,
5374
) -> Option<Attribute> {
5475
let mut parsed = Self::parse_limited_all(
5576
sess,
@@ -59,7 +80,7 @@ impl<'sess> AttributeParser<'sess, Early> {
5980
target_span,
6081
target_node_id,
6182
features,
62-
ShouldEmit::Nothing,
83+
should_emit,
6384
);
6485
assert!(parsed.len() <= 1);
6586
parsed.pop()
@@ -84,9 +105,8 @@ impl<'sess> AttributeParser<'sess, Early> {
84105
target,
85106
OmitDoc::Skip,
86107
std::convert::identity,
87-
|_lint| {
88-
// FIXME: Can't emit lints here for now
89-
// This branch can be hit when an attribute produces a warning during early parsing (such as attributes on macro calls)
108+
|lint| {
109+
crate::lints::emit_attribute_lint(&lint, sess);
90110
},
91111
)
92112
}
@@ -121,8 +141,8 @@ impl<'sess> AttributeParser<'sess, Early> {
121141
cx: &mut parser,
122142
target_span,
123143
target_id: target_node_id,
124-
emit_lint: &mut |_lint| {
125-
panic!("can't emit lints here for now (nothing uses this atm)");
144+
emit_lint: &mut |lint| {
145+
crate::lints::emit_attribute_lint(&lint, sess);
126146
},
127147
},
128148
attr_span: attr.span,
@@ -252,7 +272,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
252272

253273
(accept.accept_fn)(&mut cx, args);
254274

255-
if self.stage.should_emit().should_emit() {
275+
if !matches!(self.stage.should_emit(), ShouldEmit::Nothing) {
256276
self.check_target(
257277
path.get_attribute_path(),
258278
attr.span,

compiler/rustc_attr_parsing/src/lib.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,7 @@ pub mod validate_attr;
106106

107107
pub use attributes::cfg::{CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr};
108108
pub use attributes::cfg_old::*;
109-
pub use attributes::util::{
110-
find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version,
111-
};
109+
pub use attributes::util::{is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version};
112110
pub use context::{Early, Late, OmitDoc, ShouldEmit};
113111
pub use interface::AttributeParser;
114112
pub use lints::emit_attribute_lint;

compiler/rustc_attr_parsing/src/lints.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use std::borrow::Cow;
22

33
use rustc_errors::{DiagArgValue, LintEmitter};
4+
use rustc_hir::Target;
45
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
5-
use rustc_hir::{HirId, Target};
66
use rustc_span::sym;
77

88
use crate::session_diagnostics;
99

10-
pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emitter: L) {
10+
pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<L::Id>, lint_emitter: L) {
1111
let AttributeLint { id, span, kind } = lint;
1212

1313
match kind {
@@ -51,7 +51,7 @@ pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emi
5151
*id,
5252
*span,
5353
session_diagnostics::InvalidTargetLint {
54-
name,
54+
name: name.clone(),
5555
target: target.plural_name(),
5656
applied: DiagArgValue::StrListSepByAnd(
5757
applied.into_iter().map(|i| Cow::Owned(i.to_string())).collect(),

compiler/rustc_attr_parsing/src/parser.rs

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -328,15 +328,16 @@ fn expr_to_lit(
328328
match res {
329329
Ok(lit) => {
330330
if token_lit.suffix.is_some() {
331-
psess
332-
.dcx()
333-
.create_err(SuffixedLiteralInAttribute { span: lit.span })
334-
.emit_unless_delay(!should_emit.should_emit());
331+
should_emit.emit_err(
332+
psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
333+
);
335334
None
336335
} else {
337-
if should_emit.should_emit() && !lit.kind.is_unsuffixed() {
336+
if !lit.kind.is_unsuffixed() {
338337
// Emit error and continue, we can still parse the attribute as if the suffix isn't there
339-
psess.dcx().emit_err(SuffixedLiteralInAttribute { span: lit.span });
338+
should_emit.emit_err(
339+
psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
340+
);
340341
}
341342

342343
Some(lit)
@@ -354,19 +355,19 @@ fn expr_to_lit(
354355
}
355356
}
356357
} else {
358+
if matches!(should_emit, ShouldEmit::Nothing) {
359+
return None;
360+
}
361+
357362
// Example cases:
358363
// - `#[foo = 1+1]`: results in `ast::ExprKind::BinOp`.
359364
// - `#[foo = include_str!("nonexistent-file.rs")]`:
360365
// results in `ast::ExprKind::Err`. In that case we delay
361366
// the error because an earlier error will have already
362367
// been reported.
363368
let msg = "attribute value must be a literal";
364-
let mut err = psess.dcx().struct_span_err(span, msg);
365-
if let ExprKind::Err(_) = expr.kind {
366-
err.downgrade_to_delayed_bug();
367-
}
368-
369-
err.emit_unless_delay(!should_emit.should_emit());
369+
let err = psess.dcx().struct_span_err(span, msg);
370+
should_emit.emit_err(err);
370371
None
371372
}
372373
}
@@ -397,9 +398,11 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
397398
}
398399
};
399400

400-
if self.should_emit.should_emit() && !lit.kind.is_unsuffixed() {
401+
if !lit.kind.is_unsuffixed() {
401402
// Emit error and continue, we can still parse the attribute as if the suffix isn't there
402-
self.parser.dcx().emit_err(SuffixedLiteralInAttribute { span: lit.span });
403+
self.should_emit.emit_err(
404+
self.parser.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
405+
);
403406
}
404407

405408
Ok(lit)
@@ -539,7 +542,7 @@ impl<'a> MetaItemListParser<'a> {
539542
) {
540543
Ok(s) => Some(s),
541544
Err(e) => {
542-
e.emit_unless_delay(!should_emit.should_emit());
545+
should_emit.emit_err(e);
543546
None
544547
}
545548
}

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -484,9 +484,9 @@ pub(crate) struct EmptyAttributeList {
484484
#[diag(attr_parsing_invalid_target_lint)]
485485
#[warning]
486486
#[help]
487-
pub(crate) struct InvalidTargetLint<'a> {
488-
pub name: &'a AttrPath,
489-
pub target: &'a str,
487+
pub(crate) struct InvalidTargetLint {
488+
pub name: AttrPath,
489+
pub target: &'static str,
490490
pub applied: DiagArgValue,
491491
pub only: &'static str,
492492
#[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]

0 commit comments

Comments
 (0)