Skip to content

Commit 1f5c49f

Browse files
committed
Port crate name to the new attribute system
1 parent 65316eb commit 1f5c49f

31 files changed

+377
-193
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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::{AcceptContext, 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+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
18+
let ArgParser::NameValue(n) = args else {
19+
cx.expected_name_value(cx.attr_span, None);
20+
return None;
21+
};
22+
23+
let Some(name) = n.value_as_str() else {
24+
cx.expected_string_literal(n.value_span, Some(n.value_as_lit()));
25+
return None;
26+
};
27+
28+
Some(AttributeKind::CrateName { name, name_span: n.value_span, style: cx.attr_style })
29+
}
30+
}

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
@@ -11,6 +11,7 @@ use rustc_hir::attrs::AttributeKind;
1111
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
1212
use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId};
1313
use rustc_session::Session;
14+
use rustc_session::lint::BuiltinLintDiag;
1415
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
1516

1617
use crate::attributes::allow_unstable::{
@@ -22,6 +23,7 @@ use crate::attributes::codegen_attrs::{
2223
TargetFeatureParser, TrackCallerParser, UsedParser,
2324
};
2425
use crate::attributes::confusables::ConfusablesParser;
26+
use crate::attributes::crate_level::CrateNameParser;
2527
use crate::attributes::deprecation::DeprecationParser;
2628
use crate::attributes::dummy::DummyParser;
2729
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
@@ -59,6 +61,7 @@ use crate::attributes::traits::{
5961
};
6062
use crate::attributes::transparency::TransparencyParser;
6163
use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
64+
use crate::lints::lint_name;
6265
use crate::parser::{ArgParser, MetaItemParser, PathParser};
6366
use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem};
6467

@@ -157,6 +160,7 @@ attribute_parsers!(
157160

158161
// tidy-alphabetical-start
159162
Single<CoverageParser>,
163+
Single<CrateNameParser>,
160164
Single<DeprecationParser>,
161165
Single<DummyParser>,
162166
Single<ExportNameParser>,
@@ -301,7 +305,9 @@ pub struct AcceptContext<'f, 'sess, S: Stage> {
301305
/// The span of the attribute currently being parsed
302306
pub(crate) attr_span: Span,
303307

308+
/// Whether it is an inner or outer attribute
304309
pub(crate) attr_style: AttrStyle,
310+
305311
/// The expected structure of the attribute.
306312
///
307313
/// Used in reporting errors to give a hint to users what the attribute *should* look like.
@@ -689,22 +695,48 @@ impl<'sess> AttributeParser<'sess, Early> {
689695
target_span: Span,
690696
target_node_id: NodeId,
691697
features: Option<&'sess Features>,
698+
) -> Option<Attribute> {
699+
Self::parse_limited_should_emit(
700+
sess,
701+
attrs,
702+
sym,
703+
target_span,
704+
target_node_id,
705+
features,
706+
ShouldEmit::Nothing,
707+
)
708+
}
709+
710+
/// Usually you want `parse_limited`, which defaults to no errors.
711+
pub fn parse_limited_should_emit(
712+
sess: &'sess Session,
713+
attrs: &[ast::Attribute],
714+
sym: Symbol,
715+
target_span: Span,
716+
target_node_id: NodeId,
717+
features: Option<&'sess Features>,
718+
should_emit: ShouldEmit,
692719
) -> Option<Attribute> {
693720
let mut p = Self {
694721
features,
695722
tools: Vec::new(),
696723
parse_only: Some(sym),
697724
sess,
698-
stage: Early { emit_errors: ShouldEmit::Nothing },
725+
stage: Early { emit_errors: should_emit },
699726
};
700727
let mut parsed = p.parse_attribute_list(
701728
attrs,
702729
target_span,
703730
target_node_id,
704731
OmitDoc::Skip,
705732
std::convert::identity,
706-
|_lint| {
707-
panic!("can't emit lints here for now (nothing uses this atm)");
733+
|AttributeLint { id, span, kind }| {
734+
sess.psess.buffer_lint(
735+
lint_name(&kind),
736+
span,
737+
id,
738+
BuiltinLintDiag::AttributeLint(kind),
739+
);
708740
},
709741
);
710742
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::{emit_attribute_lint, emit_attribute_lint_kind};
10098

10199
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,46 @@
1-
use rustc_errors::{DiagArgValue, LintEmitter};
1+
use rustc_errors::{DiagArgValue, LintEmitter, SimpleLintEmitter};
22
use rustc_hir::HirId;
33
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
4+
use rustc_session::lint::Lint;
45

56
use crate::session_diagnostics;
67

7-
pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emitter: L) {
8-
let AttributeLint { id, span, kind } = lint;
8+
pub(crate) fn lint_name(kind: &AttributeLintKind) -> &'static Lint {
9+
use rustc_session::lint::builtin::*;
10+
match kind {
11+
AttributeLintKind::UnusedDuplicate { .. } => UNUSED_ATTRIBUTES,
12+
AttributeLintKind::IllFormedAttributeInput { .. } => ILL_FORMED_ATTRIBUTE_INPUT,
13+
AttributeLintKind::EmptyAttribute { .. } => UNUSED_ATTRIBUTES,
14+
}
15+
}
916

17+
pub fn emit_attribute_lint_kind<L: SimpleLintEmitter>(kind: &AttributeLintKind, lint_emitter: L) {
1018
match kind {
11-
&AttributeLintKind::UnusedDuplicate { this, other, warning } => lint_emitter
12-
.emit_node_span_lint(
13-
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
14-
*id,
15-
*span,
16-
session_diagnostics::UnusedDuplicate { this, other, warning },
17-
),
19+
&AttributeLintKind::UnusedDuplicate { this, other, warning } => {
20+
lint_emitter.emit(session_diagnostics::UnusedDuplicate { this, other, warning })
21+
}
1822
AttributeLintKind::IllFormedAttributeInput { suggestions } => {
19-
lint_emitter.emit_node_span_lint(
20-
rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT,
21-
*id,
22-
*span,
23-
session_diagnostics::IllFormedAttributeInput {
24-
num_suggestions: suggestions.len(),
25-
suggestions: DiagArgValue::StrListSepByAnd(
26-
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
27-
),
28-
},
29-
);
23+
lint_emitter.emit(session_diagnostics::IllFormedAttributeInput {
24+
num_suggestions: suggestions.len(),
25+
suggestions: DiagArgValue::StrListSepByAnd(
26+
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
27+
),
28+
});
29+
}
30+
AttributeLintKind::EmptyAttribute { first_span } => {
31+
lint_emitter.emit(session_diagnostics::EmptyAttributeList { attr_span: *first_span })
3032
}
31-
AttributeLintKind::EmptyAttribute { first_span } => lint_emitter.emit_node_span_lint(
32-
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
33-
*id,
34-
*first_span,
35-
session_diagnostics::EmptyAttributeList { attr_span: *first_span },
36-
),
3733
}
3834
}
35+
36+
pub fn emit_attribute_lint<L: LintEmitter<ID = HirId>>(
37+
lint: &AttributeLint<HirId>,
38+
lint_emitter: L,
39+
) {
40+
let AttributeLint { id, span, kind } = lint;
41+
42+
let lint_name = lint_name(&lint.kind);
43+
44+
let emit = lint_emitter.prepare_node_span_lint(lint_name, *id, *span);
45+
emit_attribute_lint_kind(kind, emit);
46+
}

compiler/rustc_errors/src/lib.rs

Lines changed: 10 additions & 5 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 SimpleLintEmitter {
108+
fn emit(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`.
110113
pub trait LintEmitter: Copy {
114+
type ID: Copy;
115+
type Simple: SimpleLintEmitter;
116+
111117
#[track_caller]
112-
fn emit_node_span_lint(
118+
fn prepare_node_span_lint(
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::Simple;
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
@@ -303,6 +303,9 @@ pub enum AttributeKind {
303303
/// Represents `#[coverage(..)]`.
304304
Coverage(Span, CoverageAttrKind),
305305

306+
/// Represents `#[crate_name = ...]`
307+
CrateName { name: Symbol, name_span: Span, style: AttrStyle },
308+
306309
///Represents `#[rustc_deny_explicit_impl]`.
307310
DenyExplicitImpl(Span),
308311

compiler/rustc_hir/src/attrs/encode_cross_crate.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@ 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::*;
1318

1419
match self {
15-
// tidy-alphabetical-start
1620
Align { .. } => No,
1721
AllowConstFnUnstable(..) => No,
1822
AllowIncoherentImpl(..) => No,
@@ -30,6 +34,7 @@ impl AttributeKind {
3034
ConstTrait(..) => No,
3135
Coroutine(..) => No,
3236
Coverage(..) => No,
37+
CrateName { .. } => No,
3338
DenyExplicitImpl(..) => No,
3439
Deprecation { .. } => Yes,
3540
DoNotImplementViaObject(..) => No,
@@ -42,9 +47,9 @@ impl AttributeKind {
4247
Fundamental { .. } => Yes,
4348
Ignore { .. } => No,
4449
Inline(..) => No,
45-
LinkName { .. } => Yes, // Needed for rustdoc
50+
LinkName { .. } => Yes,
4651
LinkOrdinal { .. } => No,
47-
LinkSection { .. } => Yes, // Needed for rustdoc
52+
LinkSection { .. } => Yes,
4853
LoopMatch(..) => No,
4954
MacroEscape(..) => No,
5055
MacroTransparency(..) => Yes,
@@ -54,8 +59,8 @@ impl AttributeKind {
5459
MustUse { .. } => Yes,
5560
Naked(..) => No,
5661
NoImplicitPrelude(..) => No,
57-
NoMangle(..) => Yes, // Needed for rustdoc
58-
NonExhaustive(..) => Yes, // Needed for rustdoc
62+
NoMangle(..) => Yes,
63+
NonExhaustive(..) => Yes,
5964
Optimize(..) => No,
6065
ParenSugar(..) => No,
6166
PassByValue(..) => Yes,
@@ -81,7 +86,6 @@ impl AttributeKind {
8186
UnsafeSpecializationMarker(..) => No,
8287
UnstableFeatureBound(..) => No,
8388
Used { .. } => No,
84-
// tidy-alphabetical-end
8589
}
8690
}
8791
}

compiler/rustc_interface/src/passes.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use std::path::{Path, PathBuf};
55
use std::sync::{Arc, LazyLock, OnceLock};
66
use std::{env, fs, iter};
77

8-
use rustc_ast as ast;
8+
use rustc_ast::{self as ast};
9+
use rustc_attr_parsing::{AttributeParser, ShouldEmit};
910
use rustc_codegen_ssa::traits::CodegenBackend;
1011
use rustc_data_structures::jobserver::Proxy;
1112
use rustc_data_structures::steal::Steal;
@@ -15,6 +16,7 @@ use rustc_errors::timings::TimingSection;
1516
use rustc_expand::base::{ExtCtxt, LintStoreExpand};
1617
use rustc_feature::Features;
1718
use rustc_fs_util::try_canonicalize;
19+
use rustc_hir::attrs::AttributeKind;
1820
use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap};
1921
use rustc_hir::definitions::Definitions;
2022
use rustc_incremental::setup_dep_graph;
@@ -1125,6 +1127,28 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
11251127
}
11261128
}
11271129

1130+
pub(crate) fn parse_crate_name(
1131+
sess: &Session,
1132+
attrs: &[ast::Attribute],
1133+
emit_errors: ShouldEmit,
1134+
) -> Option<(Symbol, Span)> {
1135+
let rustc_hir::Attribute::Parsed(AttributeKind::CrateName { name, name_span, .. }) =
1136+
AttributeParser::parse_limited_should_emit(
1137+
sess,
1138+
&attrs,
1139+
sym::crate_name,
1140+
DUMMY_SP,
1141+
rustc_ast::node_id::CRATE_NODE_ID,
1142+
None,
1143+
emit_errors,
1144+
)?
1145+
else {
1146+
unreachable!("crate_name is the only attr we could've parsed here");
1147+
};
1148+
1149+
Some((name, name_span))
1150+
}
1151+
11281152
/// Runs the type-checking, region checking and other miscellaneous analysis
11291153
/// passes on the crate.
11301154
fn analysis(tcx: TyCtxt<'_>, (): ()) {
@@ -1244,8 +1268,7 @@ pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol
12441268
// in all code paths that require the crate name very early on, namely before
12451269
// macro expansion.
12461270

1247-
let attr_crate_name =
1248-
validate_and_find_value_str_builtin_attr(sym::crate_name, sess, krate_attrs);
1271+
let attr_crate_name = parse_crate_name(sess, krate_attrs, ShouldEmit::ErrorsAndLints);
12491272

12501273
let validate = |name, span| {
12511274
rustc_session::output::validate_crate_name(sess, name, span);

0 commit comments

Comments
 (0)