diff options
| author | Jana Dönszelmann <jana@donsz.nl> | 2025-08-11 11:46:30 +0200 |
|---|---|---|
| committer | Jana Dönszelmann <jana@donsz.nl> | 2025-08-24 09:20:57 +0200 |
| commit | 59ceb02d65f13a20d29422f4d923ecde429d4c0c (patch) | |
| tree | 5de1da32932e192b400b383f38d1a70e09ed0d97 /compiler | |
| parent | 4b35cde904c1015df42b2c63244c1db1ed51fff9 (diff) | |
| download | rust-59ceb02d65f13a20d29422f4d923ecde429d4c0c.tar.gz rust-59ceb02d65f13a20d29422f4d923ecde429d4c0c.zip | |
Port crate name to the new attribute system
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_attr_parsing/src/attributes/crate_level.rs | 33 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/attributes/mod.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/attributes/util.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/context.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_attr_parsing/src/lib.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/attrs/data_structures.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/attrs/encode_cross_crate.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/passes.rs | 28 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/util.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/nonstandard_style.rs | 52 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/check_attr.rs | 46 |
11 files changed, 142 insertions, 57 deletions
diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs new file mode 100644 index 00000000000..9175d7479e1 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -0,0 +1,33 @@ +use super::prelude::*; + +pub(crate) struct CrateNameParser; + +impl<S: Stage> SingleAttributeParser<S> for CrateNameParser { + const PATH: &[Symbol] = &[sym::crate_name]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); + + // FIXME: crate name is allowed on all targets and ignored, + // even though it should only be valid on crates of course + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let ArgParser::NameValue(n) = args else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + + let Some(name) = n.value_as_str() else { + cx.expected_string_literal(n.value_span, Some(n.value_as_lit())); + return None; + }; + + Some(AttributeKind::CrateName { + name, + name_span: n.value_span, + attr_span: cx.attr_span, + style: cx.attr_style, + }) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index b98678041d7..9dad9c893f0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -35,6 +35,7 @@ pub(crate) mod cfg; pub(crate) mod cfg_old; pub(crate) mod codegen_attrs; pub(crate) mod confusables; +pub(crate) mod crate_level; pub(crate) mod deprecation; pub(crate) mod dummy; pub(crate) mod inline; diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index ef9701cb7cb..77e8c32e59d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -1,5 +1,5 @@ use rustc_ast::LitKind; -use rustc_ast::attr::{AttributeExt, first_attr_value_str_by_name}; +use rustc_ast::attr::AttributeExt; use rustc_feature::is_builtin_attr_name; use rustc_hir::RustcVersion; use rustc_span::{Symbol, sym}; @@ -27,10 +27,6 @@ pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool { attr.is_doc_comment() || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name)) } -pub fn find_crate_name(attrs: &[impl AttributeExt]) -> Option<Symbol> { - first_attr_value_str_by_name(attrs, sym::crate_name) -} - pub fn is_doc_alias_attrs_contain_symbol<'tcx, T: AttributeExt + 'tcx>( attrs: impl Iterator<Item = &'tcx T>, symbol: Symbol, diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index f30edbfaaa1..128ecd67d2a 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -24,6 +24,7 @@ use crate::attributes::codegen_attrs::{ UsedParser, }; use crate::attributes::confusables::ConfusablesParser; +use crate::attributes::crate_level::CrateNameParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::dummy::DummyParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; @@ -166,6 +167,7 @@ attribute_parsers!( // tidy-alphabetical-start Single<CoverageParser>, + Single<CrateNameParser>, Single<CustomMirParser>, Single<DeprecationParser>, Single<DummyParser>, @@ -310,7 +312,9 @@ pub struct AcceptContext<'f, 'sess, S: Stage> { /// The span of the attribute currently being parsed pub(crate) attr_span: Span, + /// Whether it is an inner or outer attribute pub(crate) attr_style: AttrStyle, + /// The expected structure of the attribute. /// /// Used in reporting errors to give a hint to users what the attribute *should* look like. @@ -683,7 +687,9 @@ impl ShouldEmit { ShouldEmit::ErrorsAndLints => { diag.emit(); } - ShouldEmit::Nothing => {} + ShouldEmit::Nothing => { + diag.cancel(); + } } } } diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 969c24a4f89..4dd908cdc40 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -106,9 +106,7 @@ pub mod validate_attr; pub use attributes::cfg::{CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr}; pub use attributes::cfg_old::*; -pub use attributes::util::{ - find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version, -}; +pub use attributes::util::{is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version}; pub use context::{Early, Late, OmitDoc, ShouldEmit}; pub use interface::AttributeParser; pub use lints::emit_attribute_lint; diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 1e73bb6f5fd..09da5772d23 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -367,6 +367,9 @@ pub enum AttributeKind { /// Represents `#[coverage(..)]`. Coverage(Span, CoverageAttrKind), + /// Represents `#[crate_name = ...]` + CrateName { name: Symbol, name_span: Span, attr_span: Span, style: AttrStyle }, + /// Represents `#[custom_mir]`. CustomMir(Option<(MirDialect, Span)>, Option<(MirPhase, Span)>, Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 77c6faa7acd..e5329c104bb 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -7,6 +7,11 @@ pub enum EncodeCrossCrate { } impl AttributeKind { + /// Whether this attribute should be encoded in metadata files. + /// + /// If this is "Yes", then another crate can do `tcx.get_all_attrs(did)` for a did in this crate, and get the attribute. + /// When this is No, the attribute is filtered out while encoding and other crate won't be able to observe it. + /// This can be unexpectedly good for performance, so unless necessary for cross-crate compilation, prefer No. pub fn encode_cross_crate(&self) -> EncodeCrossCrate { use AttributeKind::*; use EncodeCrossCrate::*; @@ -31,6 +36,7 @@ impl AttributeKind { ConstTrait(..) => No, Coroutine(..) => No, Coverage(..) => No, + CrateName { .. } => No, CustomMir(_, _, _) => Yes, DenyExplicitImpl(..) => No, Deprecation { .. } => Yes, diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 90f7ae76387..bc5ef04079e 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -6,7 +6,7 @@ use std::sync::{Arc, LazyLock, OnceLock}; use std::{env, fs, iter}; use rustc_ast as ast; -use rustc_attr_parsing::validate_attr; +use rustc_attr_parsing::{AttributeParser, ShouldEmit, validate_attr}; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::steal::Steal; @@ -16,6 +16,7 @@ use rustc_errors::timings::TimingSection; use rustc_expand::base::{ExtCtxt, LintStoreExpand}; use rustc_feature::Features; use rustc_fs_util::try_canonicalize; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap}; use rustc_hir::definitions::Definitions; use rustc_incremental::setup_dep_graph; @@ -1244,8 +1245,7 @@ pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol // in all code paths that require the crate name very early on, namely before // macro expansion. - let attr_crate_name = - validate_and_find_value_str_builtin_attr(sym::crate_name, sess, krate_attrs); + let attr_crate_name = parse_crate_name(sess, krate_attrs, ShouldEmit::EarlyFatal); let validate = |name, span| { rustc_session::output::validate_crate_name(sess, name, span); @@ -1283,6 +1283,28 @@ pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol sym::rust_out } +pub(crate) fn parse_crate_name( + sess: &Session, + attrs: &[ast::Attribute], + emit_errors: ShouldEmit, +) -> Option<(Symbol, Span)> { + let rustc_hir::Attribute::Parsed(AttributeKind::CrateName { name, name_span, .. }) = + AttributeParser::parse_limited_should_emit( + sess, + &attrs, + sym::crate_name, + DUMMY_SP, + rustc_ast::node_id::CRATE_NODE_ID, + None, + emit_errors, + )? + else { + unreachable!("crate_name is the only attr we could've parsed here"); + }; + + Some((name, name_span)) +} + fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit { // We don't permit macro calls inside of the attribute (e.g., #![recursion_limit = `expand!()`]) // because that would require expanding this while in the middle of expansion, which needs to diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 9a432a60819..04006f3e446 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -5,7 +5,7 @@ use std::sync::{Arc, OnceLock}; use std::{env, thread}; use rustc_ast as ast; -use rustc_attr_parsing::validate_attr; +use rustc_attr_parsing::{ShouldEmit, validate_attr}; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::sync; @@ -24,6 +24,7 @@ use rustc_target::spec::Target; use tracing::info; use crate::errors; +use crate::passes::parse_crate_name; /// Function pointer type that constructs a new CodegenBackend. type MakeBackendFn = fn() -> Box<dyn CodegenBackend>; @@ -520,11 +521,10 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu sess.dcx().emit_fatal(errors::MultipleOutputTypesToStdout); } - let crate_name = sess - .opts - .crate_name - .clone() - .or_else(|| rustc_attr_parsing::find_crate_name(attrs).map(|n| n.to_string())); + let crate_name = + sess.opts.crate_name.clone().or_else(|| { + parse_crate_name(sess, attrs, ShouldEmit::Nothing).map(|i| i.0.to_string()) + }); match sess.io.output_file { None => { diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 8fafaa33d0c..65075cfecfa 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -5,7 +5,7 @@ use rustc_hir::attrs::{AttributeKind, ReprAttr}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{FnKind, Visitor}; -use rustc_hir::{AttrArgs, AttrItem, Attribute, GenericParamKind, PatExprKind, PatKind, find_attr}; +use rustc_hir::{Attribute, GenericParamKind, PatExprKind, PatKind, find_attr}; use rustc_middle::hir::nested_filter::All; use rustc_middle::ty; use rustc_session::config::CrateType; @@ -343,35 +343,27 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name { Some(Ident::from_str(name)) } else { - ast::attr::find_by_name(cx.tcx.hir_attrs(hir::CRATE_HIR_ID), sym::crate_name).and_then( - |attr| { - if let Attribute::Unparsed(n) = attr - && let AttrItem { args: AttrArgs::Eq { eq_span: _, expr: lit }, .. } = - n.as_ref() - && let ast::LitKind::Str(name, ..) = lit.kind - { - // Discard the double quotes surrounding the literal. - let sp = cx - .sess() - .source_map() - .span_to_snippet(lit.span) - .ok() - .and_then(|snippet| { - let left = snippet.find('"')?; - let right = snippet.rfind('"').map(|pos| snippet.len() - pos)?; - - Some( - lit.span - .with_lo(lit.span.lo() + BytePos(left as u32 + 1)) - .with_hi(lit.span.hi() - BytePos(right as u32)), - ) - }) - .unwrap_or(lit.span); - - Some(Ident::new(name, sp)) - } else { - None - } + find_attr!(cx.tcx.hir_attrs(hir::CRATE_HIR_ID), AttributeKind::CrateName{name, name_span,..} => (name, name_span)).map( + |(&name, &span)| { + // Discard the double quotes surrounding the literal. + let sp = cx + .sess() + .source_map() + .span_to_snippet(span) + .ok() + .and_then(|snippet| { + let left = snippet.find('"')?; + let right = snippet.rfind('"').map(|pos| snippet.len() - pos)?; + + Some( + span + .with_lo(span.lo() + BytePos(left as u32 + 1)) + .with_hi(span.hi() - BytePos(right as u32)), + ) + }) + .unwrap_or(span); + + Ident::new(name, sp) }, ) }; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c610ce4fc85..7aef60b7b91 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -250,7 +250,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::ShouldPanic { .. } | AttributeKind::Coroutine(..) | AttributeKind::Linkage(..) - | AttributeKind::MustUse { .. }, + | AttributeKind::MustUse { .. } + | AttributeKind::CrateName { .. } ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -367,22 +368,49 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); if hir_id != CRATE_HIR_ID { - if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) = - attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) - { - match style { - Some(ast::AttrStyle::Outer) => self.tcx.emit_node_span_lint( + match attr { + // FIXME(jdonszelmann) move to attribute parsing when validation gets better there + &Attribute::Parsed(AttributeKind::CrateName { + attr_span: span, style, .. + }) => match style { + ast::AttrStyle::Outer => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + span, errors::OuterCrateLevelAttr, ), - Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint( + ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + span, errors::InnerCrateLevelAttr, ), + }, + Attribute::Parsed(_) => { /* not crate-level */ } + Attribute::Unparsed(attr) => { + // FIXME(jdonszelmann): remove once all crate-level attrs are parsed and caught by + // the above + if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) = + attr.path + .segments + .first() + .and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) + { + match attr.style { + ast::AttrStyle::Outer => self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::OuterCrateLevelAttr, + ), + ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::InnerCrateLevelAttr, + ), + } + } } } } |
