Skip to content

Commit 56fd2c6

Browse files
committed
Port crate name to the new attribute system
1 parent ecb3fd4 commit 56fd2c6

31 files changed

+400
-221
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: 35 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};
@@ -65,6 +67,7 @@ use crate::attributes::traits::{
6567
use crate::attributes::transparency::TransparencyParser;
6668
use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
6769
use crate::context::MaybeWarn::{Allow, Error, Warn};
70+
use crate::lints::lint_name;
6871
use crate::parser::{ArgParser, MetaItemParser, PathParser};
6972
use crate::session_diagnostics::{
7073
AttributeParseError, AttributeParseErrorReason, InvalidTarget, UnknownMetaItem,
@@ -167,6 +170,7 @@ attribute_parsers!(
167170

168171
// tidy-alphabetical-start
169172
Single<CoverageParser>,
173+
Single<CrateNameParser>,
170174
Single<DeprecationParser>,
171175
Single<DummyParser>,
172176
Single<ExportNameParser>,
@@ -313,7 +317,9 @@ pub struct AcceptContext<'f, 'sess, S: Stage> {
313317
/// The span of the attribute currently being parsed
314318
pub(crate) attr_span: Span,
315319

320+
/// Whether it is an inner or outer attribute
316321
pub(crate) attr_style: AttrStyle,
322+
317323
/// The expected structure of the attribute.
318324
///
319325
/// Used in reporting errors to give a hint to users what the attribute *should* look like.
@@ -759,13 +765,34 @@ impl<'sess> AttributeParser<'sess, Early> {
759765
target_span: Span,
760766
target_node_id: NodeId,
761767
features: Option<&'sess Features>,
768+
) -> Option<Attribute> {
769+
Self::parse_limited_should_emit(
770+
sess,
771+
attrs,
772+
sym,
773+
target_span,
774+
target_node_id,
775+
features,
776+
ShouldEmit::Nothing,
777+
)
778+
}
779+
780+
/// Usually you want `parse_limited`, which defaults to no errors.
781+
pub fn parse_limited_should_emit(
782+
sess: &'sess Session,
783+
attrs: &[ast::Attribute],
784+
sym: Symbol,
785+
target_span: Span,
786+
target_node_id: NodeId,
787+
features: Option<&'sess Features>,
788+
should_emit: ShouldEmit,
762789
) -> Option<Attribute> {
763790
let mut p = Self {
764791
features,
765792
tools: Vec::new(),
766793
parse_only: Some(sym),
767794
sess,
768-
stage: Early { emit_errors: ShouldEmit::Nothing },
795+
stage: Early { emit_errors: should_emit },
769796
};
770797
let mut parsed = p.parse_attribute_list(
771798
attrs,
@@ -774,8 +801,13 @@ impl<'sess> AttributeParser<'sess, Early> {
774801
Target::Crate, // Does not matter, we're not going to emit errors anyways
775802
OmitDoc::Skip,
776803
std::convert::identity,
777-
|_lint| {
778-
panic!("can't emit lints here for now (nothing uses this atm)");
804+
|AttributeLint { id, span, kind }| {
805+
sess.psess.buffer_lint(
806+
lint_name(&kind),
807+
span,
808+
id,
809+
BuiltinLintDiag::AttributeLint(kind),
810+
);
779811
},
780812
);
781813
assert!(parsed.len() <= 1);

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: 55 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,68 @@
1-
use rustc_errors::{DiagArgValue, LintEmitter};
1+
use rustc_errors::{AttributeLintDecorator, DeferedAttributeLintDecorator, 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-
),
45+
46+
AttributeLintKind::EmptyAttribute { first_span } => lint_emitter
47+
.decorate(session_diagnostics::EmptyAttributeList { attr_span: *first_span }),
3848
&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-
},
57-
),
49+
.decorate(session_diagnostics::InvalidTargetLint {
50+
name,
51+
target: target.plural_name(),
52+
applied: applied.clone(),
53+
only,
54+
}),
5855
}
5956
}
57+
58+
pub fn emit_attribute_lint<L: DeferedAttributeLintDecorator<ID = HirId>>(
59+
lint: &AttributeLint<HirId>,
60+
lint_emitter: L,
61+
) {
62+
let AttributeLint { id, span, kind } = lint;
63+
64+
let lint_name = lint_name(&lint.kind);
65+
66+
let emit = lint_emitter.prepare(lint_name, *id, *span);
67+
decorate_attribute_lint_kind(kind, emit);
68+
}

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 DeferedAttributeLintDecorator: 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
@@ -324,6 +324,9 @@ pub enum AttributeKind {
324324
/// Represents `#[coverage(..)]`.
325325
Coverage(Span, CoverageAttrKind),
326326

327+
/// Represents `#[crate_name = ...]`
328+
CrateName { name: Symbol, name_span: Span, style: AttrStyle },
329+
327330
///Represents `#[rustc_deny_explicit_impl]`.
328331
DenyExplicitImpl(Span),
329332

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
DenyExplicitImpl(..) => No,
3541
Deprecation { .. } => Yes,
3642
DoNotImplementViaObject(..) => No,

0 commit comments

Comments
 (0)