Skip to content

Commit c04570f

Browse files
committed
Port crate name to the new attribute system
1 parent bec7474 commit c04570f

32 files changed

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

compiler/rustc_attr_parsing/src/attributes/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub(crate) mod cfg;
3131
pub(crate) mod cfg_old;
3232
pub(crate) mod codegen_attrs;
3333
pub(crate) mod confusables;
34+
pub(crate) mod crate_level;
3435
pub(crate) mod deprecation;
3536
pub(crate) mod dummy;
3637
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,4 +1,4 @@
1-
use rustc_ast::attr::{AttributeExt, first_attr_value_str_by_name};
1+
use rustc_ast::attr::AttributeExt;
22
use rustc_feature::is_builtin_attr_name;
33
use rustc_hir::RustcVersion;
44
use rustc_span::{Symbol, sym};
@@ -23,10 +23,6 @@ pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool {
2323
attr.is_doc_comment() || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name))
2424
}
2525

26-
pub fn find_crate_name(attrs: &[impl AttributeExt]) -> Option<Symbol> {
27-
first_attr_value_str_by_name(attrs, sym::crate_name)
28-
}
29-
3026
pub fn is_doc_alias_attrs_contain_symbol<'tcx, T: AttributeExt + 'tcx>(
3127
attrs: impl Iterator<Item = &'tcx T>,
3228
symbol: Symbol,

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use rustc_hir::{
1414
AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId, MethodKind, Target,
1515
};
1616
use rustc_session::Session;
17+
use rustc_session::lint::BuiltinLintDiag;
1718
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
1819

1920
use crate::attributes::allow_unstable::{
@@ -25,6 +26,7 @@ use crate::attributes::codegen_attrs::{
2526
TargetFeatureParser, TrackCallerParser, UsedParser,
2627
};
2728
use crate::attributes::confusables::ConfusablesParser;
29+
use crate::attributes::crate_level::CrateNameParser;
2830
use crate::attributes::deprecation::DeprecationParser;
2931
use crate::attributes::dummy::DummyParser;
3032
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
@@ -66,6 +68,7 @@ use crate::attributes::traits::{
6668
use crate::attributes::transparency::TransparencyParser;
6769
use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
6870
use crate::context::MaybeWarn::{Allow, Error, Warn};
71+
use crate::lints::lint_name;
6972
use crate::parser::{ArgParser, MetaItemParser, PathParser};
7073
use crate::session_diagnostics::{
7174
AttributeParseError, AttributeParseErrorReason, InvalidTarget, UnknownMetaItem,
@@ -168,6 +171,7 @@ attribute_parsers!(
168171

169172
// tidy-alphabetical-start
170173
Single<CoverageParser>,
174+
Single<CrateNameParser>,
171175
Single<CustomMirParser>,
172176
Single<DeprecationParser>,
173177
Single<DummyParser>,
@@ -315,7 +319,9 @@ pub struct AcceptContext<'f, 'sess, S: Stage> {
315319
/// The span of the attribute currently being parsed
316320
pub(crate) attr_span: Span,
317321

322+
/// Whether it is an inner or outer attribute
318323
pub(crate) attr_style: AttrStyle,
324+
319325
/// The expected structure of the attribute.
320326
///
321327
/// Used in reporting errors to give a hint to users what the attribute *should* look like.
@@ -761,13 +767,34 @@ impl<'sess> AttributeParser<'sess, Early> {
761767
target_span: Span,
762768
target_node_id: NodeId,
763769
features: Option<&'sess Features>,
770+
) -> Option<Attribute> {
771+
Self::parse_limited_should_emit(
772+
sess,
773+
attrs,
774+
sym,
775+
target_span,
776+
target_node_id,
777+
features,
778+
ShouldEmit::Nothing,
779+
)
780+
}
781+
782+
/// Usually you want `parse_limited`, which defaults to no errors.
783+
pub fn parse_limited_should_emit(
784+
sess: &'sess Session,
785+
attrs: &[ast::Attribute],
786+
sym: Symbol,
787+
target_span: Span,
788+
target_node_id: NodeId,
789+
features: Option<&'sess Features>,
790+
should_emit: ShouldEmit,
764791
) -> Option<Attribute> {
765792
let mut p = Self {
766793
features,
767794
tools: Vec::new(),
768795
parse_only: Some(sym),
769796
sess,
770-
stage: Early { emit_errors: ShouldEmit::Nothing },
797+
stage: Early { emit_errors: should_emit },
771798
};
772799
let mut parsed = p.parse_attribute_list(
773800
attrs,
@@ -776,8 +803,13 @@ impl<'sess> AttributeParser<'sess, Early> {
776803
Target::Crate, // Does not matter, we're not going to emit errors anyways
777804
OmitDoc::Skip,
778805
std::convert::identity,
779-
|_lint| {
780-
panic!("can't emit lints here for now (nothing uses this atm)");
806+
|AttributeLint { id, span, kind }| {
807+
sess.psess.buffer_lint(
808+
lint_name(&kind),
809+
span,
810+
id,
811+
BuiltinLintDiag::AttributeLint(kind),
812+
);
781813
},
782814
);
783815
assert!(parsed.len() <= 1);
@@ -955,6 +987,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
955987
target,
956988
only: if only { "only " } else { "" },
957989
applied,
990+
span: attr.span,
958991
},
959992
});
960993
}

compiler/rustc_attr_parsing/src/lib.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,8 @@ mod session_diagnostics;
9292

9393
pub use attributes::cfg::{CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr};
9494
pub use attributes::cfg_old::*;
95-
pub use attributes::util::{
96-
find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version,
97-
};
95+
pub use attributes::util::{is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version};
9896
pub use context::{AttributeParser, Early, Late, OmitDoc, ShouldEmit};
99-
pub use lints::emit_attribute_lint;
97+
pub use lints::{decorate_attribute_lint_kind, emit_attribute_lint};
10098

10199
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
Lines changed: 57 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,69 @@
1-
use rustc_errors::{DiagArgValue, LintEmitter};
1+
use rustc_errors::{AttributeLintDecorator, DeferredAttributeLintDecorator, DiagArgValue};
22
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
33
use rustc_hir::{HirId, Target};
4+
use rustc_session::lint::Lint;
45
use rustc_span::sym;
56

67
use crate::session_diagnostics;
78

8-
pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emitter: L) {
9-
let AttributeLint { id, span, kind } = lint;
9+
pub(crate) fn lint_name(kind: &AttributeLintKind) -> &'static Lint {
10+
use rustc_session::lint::builtin::*;
11+
match kind {
12+
AttributeLintKind::UnusedDuplicate { .. } => UNUSED_ATTRIBUTES,
13+
AttributeLintKind::IllFormedAttributeInput { .. } => ILL_FORMED_ATTRIBUTE_INPUT,
14+
AttributeLintKind::EmptyAttribute { .. } => UNUSED_ATTRIBUTES,
15+
AttributeLintKind::InvalidTarget { name, target, .. } => {
16+
// This check is here because `deprecated` had its own lint group and removing this would be a breaking change
17+
if *name == sym::deprecated
18+
&& ![Target::Closure, Target::Expression, Target::Statement, Target::Arm]
19+
.contains(target)
20+
{
21+
rustc_session::lint::builtin::USELESS_DEPRECATED
22+
} else {
23+
rustc_session::lint::builtin::UNUSED_ATTRIBUTES
24+
}
25+
}
26+
}
27+
}
1028

29+
pub fn decorate_attribute_lint_kind<L: AttributeLintDecorator>(
30+
kind: &AttributeLintKind,
31+
lint_emitter: L,
32+
) {
1133
match kind {
12-
&AttributeLintKind::UnusedDuplicate { this, other, warning } => lint_emitter
13-
.emit_node_span_lint(
14-
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
15-
*id,
16-
*span,
17-
session_diagnostics::UnusedDuplicate { this, other, warning },
18-
),
34+
&AttributeLintKind::UnusedDuplicate { this, other, warning } => {
35+
lint_emitter.decorate(session_diagnostics::UnusedDuplicate { this, other, warning })
36+
}
1937
AttributeLintKind::IllFormedAttributeInput { suggestions } => {
20-
lint_emitter.emit_node_span_lint(
21-
rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT,
22-
*id,
23-
*span,
24-
session_diagnostics::IllFormedAttributeInput {
25-
num_suggestions: suggestions.len(),
26-
suggestions: DiagArgValue::StrListSepByAnd(
27-
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
28-
),
29-
},
30-
);
38+
lint_emitter.decorate(session_diagnostics::IllFormedAttributeInput {
39+
num_suggestions: suggestions.len(),
40+
suggestions: DiagArgValue::StrListSepByAnd(
41+
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
42+
),
43+
});
3144
}
32-
AttributeLintKind::EmptyAttribute { first_span } => lint_emitter.emit_node_span_lint(
33-
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
34-
*id,
35-
*first_span,
36-
session_diagnostics::EmptyAttributeList { attr_span: *first_span },
37-
),
38-
&AttributeLintKind::InvalidTarget { name, target, ref applied, only } => lint_emitter
39-
.emit_node_span_lint(
40-
// This check is here because `deprecated` had its own lint group and removing this would be a breaking change
41-
if name == sym::deprecated
42-
&& ![Target::Closure, Target::Expression, Target::Statement, Target::Arm]
43-
.contains(&target)
44-
{
45-
rustc_session::lint::builtin::USELESS_DEPRECATED
46-
} else {
47-
rustc_session::lint::builtin::UNUSED_ATTRIBUTES
48-
},
49-
*id,
50-
*span,
51-
session_diagnostics::InvalidTargetLint {
52-
name,
53-
target: target.plural_name(),
54-
applied: applied.clone(),
55-
only,
56-
attr_span: *span,
57-
},
58-
),
45+
46+
AttributeLintKind::EmptyAttribute { first_span } => lint_emitter
47+
.decorate(session_diagnostics::EmptyAttributeList { attr_span: *first_span }),
48+
&AttributeLintKind::InvalidTarget { name, target, ref applied, only, span } => lint_emitter
49+
.decorate(session_diagnostics::InvalidTargetLint {
50+
name,
51+
target: target.plural_name(),
52+
applied: applied.clone(),
53+
only,
54+
attr_span: span,
55+
}),
5956
}
6057
}
58+
59+
pub fn emit_attribute_lint<L: DeferredAttributeLintDecorator<ID = HirId>>(
60+
lint: &AttributeLint<HirId>,
61+
lint_emitter: L,
62+
) {
63+
let AttributeLint { id, span, kind } = lint;
64+
65+
let lint_name = lint_name(&lint.kind);
66+
67+
let emit = lint_emitter.prepare(lint_name, *id, *span);
68+
decorate_attribute_lint_kind(kind, emit);
69+
}

compiler/rustc_errors/src/lib.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ pub use rustc_error_messages::{
6060
SubdiagMessage, fallback_fluent_bundle, fluent_bundle,
6161
};
6262
use rustc_hashes::Hash128;
63-
use rustc_hir::HirId;
6463
pub use rustc_lint_defs::{Applicability, listify, pluralize};
6564
use rustc_lint_defs::{Lint, LintExpectationId};
6665
use rustc_macros::{Decodable, Encodable};
@@ -105,17 +104,23 @@ rustc_data_structures::static_assert_size!(PResult<'_, ()>, 24);
105104
#[cfg(target_pointer_width = "64")]
106105
rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24);
107106

107+
pub trait AttributeLintDecorator {
108+
fn decorate(self, diag: impl for<'a> LintDiagnostic<'a, ()>);
109+
}
110+
108111
/// Used to avoid depending on `rustc_middle` in `rustc_attr_parsing`.
109112
/// Always the `TyCtxt`.
110-
pub trait LintEmitter: Copy {
113+
pub trait DeferredAttributeLintDecorator: Copy {
114+
type ID: Copy;
115+
type Decorator: AttributeLintDecorator;
116+
111117
#[track_caller]
112-
fn emit_node_span_lint(
118+
fn prepare(
113119
self,
114120
lint: &'static Lint,
115-
hir_id: HirId,
121+
id: Self::ID,
116122
span: impl Into<MultiSpan>,
117-
decorator: impl for<'a> LintDiagnostic<'a, ()>,
118-
);
123+
) -> Self::Decorator;
119124
}
120125

121126
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,9 @@ pub enum AttributeKind {
340340
/// Represents `#[coverage(..)]`.
341341
Coverage(Span, CoverageAttrKind),
342342

343+
/// Represents `#[crate_name = ...]`
344+
CrateName { name: Symbol, name_span: Span, style: AttrStyle },
345+
343346
/// Represents `#[custom_mir]`.
344347
CustomMir(Option<(MirDialect, Span)>, Option<(MirPhase, Span)>, Span),
345348

compiler/rustc_hir/src/attrs/encode_cross_crate.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ pub enum EncodeCrossCrate {
77
}
88

99
impl AttributeKind {
10+
/// Whether this attribute should be encoded in metadata files.
11+
///
12+
/// If this is "Yes", then another crate can do `tcx.get_all_attrs(did)` for a did in this crate, and get the attribute.
13+
/// When this is No, the attribute is filtered out while encoding and other crate won't be able to observe it.
14+
/// This can be unexpectedly good for performance, so unless necessary for cross-crate compilation, prefer No.
1015
pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
1116
use AttributeKind::*;
1217
use EncodeCrossCrate::*;
@@ -31,6 +36,7 @@ impl AttributeKind {
3136
ConstTrait(..) => No,
3237
Coroutine(..) => No,
3338
Coverage(..) => No,
39+
CrateName { .. } => No,
3440
CustomMir(_, _, _) => Yes,
3541
DenyExplicitImpl(..) => No,
3642
Deprecation { .. } => Yes,

compiler/rustc_hir/src/lints.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,5 @@ pub enum AttributeLintKind {
3434
UnusedDuplicate { this: Span, other: Span, warning: bool },
3535
IllFormedAttributeInput { suggestions: Vec<String> },
3636
EmptyAttribute { first_span: Span },
37-
InvalidTarget { name: Symbol, target: Target, applied: String, only: &'static str },
37+
InvalidTarget { name: Symbol, target: Target, applied: String, only: &'static str, span: Span },
3838
}

0 commit comments

Comments
 (0)