Skip to content

Commit f4dcc1c

Browse files
authored
Rollup merge of rust-lang#137729 - jdonszelmann:fix-137687, r=fmease
Port `#[crate_name]` to the new attribute parsing infrastructure r? `@fmease` Closes rust-lang#137687
2 parents 69b76df + 9a7d66d commit f4dcc1c

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
@@ -3803,7 +3803,6 @@ dependencies = [
38033803
"rustc_error_messages",
38043804
"rustc_fluent_macro",
38053805
"rustc_hashes",
3806-
"rustc_hir_id",
38073806
"rustc_index",
38083807
"rustc_lexer",
38093808
"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};
@@ -23,6 +23,7 @@ use crate::attributes::codegen_attrs::{
2323
NoMangleParser, OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser,
2424
};
2525
use crate::attributes::confusables::ConfusablesParser;
26+
use crate::attributes::crate_level::CrateNameParser;
2627
use crate::attributes::deprecation::DeprecationParser;
2728
use crate::attributes::dummy::DummyParser;
2829
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
@@ -165,6 +166,7 @@ attribute_parsers!(
165166

166167
// tidy-alphabetical-start
167168
Single<CoverageParser>,
169+
Single<CrateNameParser>,
168170
Single<CustomMirParser>,
169171
Single<DeprecationParser>,
170172
Single<DummyParser>,
@@ -261,11 +263,7 @@ impl Stage for Early {
261263
sess: &'sess Session,
262264
diag: impl for<'x> Diagnostic<'x>,
263265
) -> ErrorGuaranteed {
264-
if self.emit_errors.should_emit() {
265-
sess.dcx().emit_err(diag)
266-
} else {
267-
sess.dcx().create_err(diag).delay_as_bug()
268-
}
266+
self.should_emit().emit_err(sess.dcx().create_err(diag))
269267
}
270268

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

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

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

662667
impl ShouldEmit {
663-
pub fn should_emit(&self) -> bool {
668+
pub(crate) fn emit_err(&self, diag: Diag<'_>) -> ErrorGuaranteed {
664669
match self {
665-
ShouldEmit::ErrorsAndLints => true,
666-
ShouldEmit::Nothing => false,
670+
ShouldEmit::EarlyFatal if diag.level() == Level::DelayedBug => diag.emit(),
671+
ShouldEmit::EarlyFatal => diag.upgrade_to_fatal().emit(),
672+
ShouldEmit::ErrorsAndLints => diag.emit(),
673+
ShouldEmit::Nothing => diag.delay_as_bug(),
667674
}
668675
}
669676
}

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)