Skip to content

Commit d1ee9c4

Browse files
committed
add test to reproduce #137687 and fix it
1 parent 96cfc75 commit d1ee9c4

35 files changed

+316
-151
lines changed

compiler/rustc_attr_data_structures/src/attributes.rs

+26
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,11 @@ pub enum AttributeKind {
175175
span: Span,
176176
},
177177
ConstStabilityIndirect,
178+
CrateName {
179+
name: Symbol,
180+
name_span: Span,
181+
style: AttrStyle,
182+
},
178183
Deprecation {
179184
deprecation: Deprecation,
180185
span: Span,
@@ -195,3 +200,24 @@ pub enum AttributeKind {
195200
},
196201
// tidy-alphabetical-end
197202
}
203+
204+
impl AttributeKind {
205+
pub fn crate_level(&self) -> Option<(AttrStyle, Span)> {
206+
match self {
207+
AttributeKind::AllowConstFnUnstable(..)
208+
| AttributeKind::AllowInternalUnstable(..)
209+
| AttributeKind::BodyStability { .. }
210+
| AttributeKind::Confusables { .. }
211+
| AttributeKind::ConstStability { .. }
212+
| AttributeKind::ConstStabilityIndirect
213+
| AttributeKind::Deprecation { .. }
214+
| AttributeKind::Diagnostic(..)
215+
| AttributeKind::DocComment { .. }
216+
| AttributeKind::MacroTransparency(..)
217+
| AttributeKind::Repr(..)
218+
| AttributeKind::Stability { .. } => None,
219+
220+
AttributeKind::CrateName { style, name_span, .. } => Some((*style, *name_span)),
221+
}
222+
}
223+
}

compiler/rustc_attr_parsing/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ attr_parsing_multiple_item =
8787
attr_parsing_multiple_stability_levels =
8888
multiple stability levels
8989
90+
attr_parsing_name_value = malformed `{$name}` attribute: expected to be of the form `#[{$name} = ...]`
91+
9092
attr_parsing_non_ident_feature =
9193
'feature' is not an identifier
9294
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use rustc_attr_data_structures::AttributeKind;
2+
use rustc_span::{Span, Symbol, sym};
3+
4+
use super::SingleAttributeParser;
5+
use crate::context::AcceptContext;
6+
use crate::parser::ArgParser;
7+
use crate::session_diagnostics::{ExpectedNameValue, IncorrectMetaItem, UnusedMultiple};
8+
9+
pub(crate) struct CratenameParser;
10+
11+
impl SingleAttributeParser for CratenameParser {
12+
const PATH: &'static [Symbol] = &[sym::crate_name];
13+
14+
fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span) {
15+
// FIXME(jdonszelmann): better duplicate reporting (WIP)
16+
cx.emit_err(UnusedMultiple {
17+
this: cx.attr_span,
18+
other: first_span,
19+
name: sym::crate_name,
20+
});
21+
}
22+
23+
fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
24+
if let ArgParser::NameValue(n) = args {
25+
if let Some(name) = n.value_as_str() {
26+
Some(AttributeKind::CrateName {
27+
name,
28+
name_span: n.value_span,
29+
style: cx.attr_style,
30+
})
31+
} else {
32+
cx.emit_err(IncorrectMetaItem { span: cx.attr_span, suggestion: None });
33+
34+
None
35+
}
36+
} else {
37+
cx.emit_err(ExpectedNameValue { span: cx.attr_span, name: sym::crate_name });
38+
39+
None
40+
}
41+
}
42+
}

compiler/rustc_attr_parsing/src/attributes/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use crate::parser::ArgParser;
2626
pub(crate) mod allow_unstable;
2727
pub(crate) mod cfg;
2828
pub(crate) mod confusables;
29+
pub(crate) mod crate_name;
2930
pub(crate) mod deprecation;
3031
pub(crate) mod repr;
3132
pub(crate) mod stability;

compiler/rustc_attr_parsing/src/attributes/util.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use rustc_ast::attr::{AttributeExt, first_attr_value_str_by_name};
1+
use rustc_ast::attr::AttributeExt;
22
use rustc_attr_data_structures::RustcVersion;
33
use rustc_feature::is_builtin_attr_name;
4-
use rustc_span::{Symbol, sym};
4+
use rustc_span::Symbol;
55

66
/// Parse a rustc version number written inside string literal in an attribute,
77
/// like appears in `since = "1.0.0"`. Suffixes like "-dev" and "-nightly" are
@@ -22,7 +22,3 @@ pub fn parse_version(s: Symbol) -> Option<RustcVersion> {
2222
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
}
25-
26-
pub fn find_crate_name(attrs: &[impl AttributeExt]) -> Option<Symbol> {
27-
first_attr_value_str_by_name(attrs, sym::crate_name)
28-
}

compiler/rustc_attr_parsing/src/context.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::collections::BTreeMap;
33
use std::ops::Deref;
44
use std::sync::LazyLock;
55

6-
use rustc_ast::{self as ast, DelimArgs};
6+
use rustc_ast::{self as ast, AttrStyle, DelimArgs};
77
use rustc_attr_data_structures::AttributeKind;
88
use rustc_errors::{DiagCtxtHandle, Diagnostic};
99
use rustc_feature::Features;
@@ -14,6 +14,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
1414

1515
use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
1616
use crate::attributes::confusables::ConfusablesParser;
17+
use crate::attributes::crate_name::CratenameParser;
1718
use crate::attributes::deprecation::DeprecationParser;
1819
use crate::attributes::repr::ReprParser;
1920
use crate::attributes::stability::{
@@ -76,6 +77,7 @@ attribute_groups!(
7677

7778
// tidy-alphabetical-start
7879
Single<ConstStabilityIndirectParser>,
80+
Single<CratenameParser>,
7981
Single<DeprecationParser>,
8082
Single<TransparencyParser>,
8183
// tidy-alphabetical-end
@@ -89,6 +91,7 @@ pub(crate) struct AcceptContext<'a> {
8991
pub(crate) group_cx: &'a FinalizeContext<'a>,
9092
/// The span of the attribute currently being parsed
9193
pub(crate) attr_span: Span,
94+
pub(crate) attr_style: AttrStyle,
9295
}
9396

9497
impl<'a> AcceptContext<'a> {
@@ -269,6 +272,7 @@ impl<'sess> AttributeParser<'sess> {
269272
let cx = AcceptContext {
270273
group_cx: &group_cx,
271274
attr_span: lower_span(attr.span),
275+
attr_style: attr.style,
272276
};
273277

274278
f(&cx, &args)

compiler/rustc_attr_parsing/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ pub mod parser;
9090
mod session_diagnostics;
9191

9292
pub use attributes::cfg::*;
93-
pub use attributes::util::{find_crate_name, is_builtin_attr, parse_version};
93+
pub use attributes::util::{is_builtin_attr, parse_version};
9494
pub use context::{AttributeParser, OmitDoc};
9595
pub use rustc_attr_data_structures::*;
9696

compiler/rustc_attr_parsing/src/session_diagnostics.rs

+8
Original file line numberDiff line numberDiff line change
@@ -479,3 +479,11 @@ pub(crate) struct UnrecognizedReprHint {
479479
#[primary_span]
480480
pub span: Span,
481481
}
482+
483+
#[derive(Diagnostic)]
484+
#[diag(attr_parsing_name_value, code = E0539)]
485+
pub(crate) struct ExpectedNameValue {
486+
#[primary_span]
487+
pub span: Span,
488+
pub name: Symbol,
489+
}

compiler/rustc_interface/src/passes.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::sync::{Arc, LazyLock};
66
use std::{env, fs, iter};
77

88
use rustc_ast as ast;
9+
use rustc_attr_parsing::{AttributeKind, AttributeParser};
910
use rustc_codegen_ssa::traits::CodegenBackend;
1011
use rustc_data_structures::parallel;
1112
use rustc_data_structures::steal::Steal;
@@ -32,7 +33,7 @@ use rustc_session::output::{collect_crate_types, filename_for_input};
3233
use rustc_session::search_paths::PathKind;
3334
use rustc_session::{Limit, Session};
3435
use rustc_span::{
35-
ErrorGuaranteed, FileName, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym,
36+
DUMMY_SP, ErrorGuaranteed, FileName, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym,
3637
};
3738
use rustc_target::spec::PanicStrategy;
3839
use rustc_trait_selection::traits;
@@ -1119,6 +1120,20 @@ pub(crate) fn start_codegen<'tcx>(
11191120
codegen
11201121
}
11211122

1123+
pub(crate) fn parse_crate_name(
1124+
sess: &Session,
1125+
attrs: &[ast::Attribute],
1126+
limit_diagnostics: bool,
1127+
) -> Option<(Symbol, Span)> {
1128+
let rustc_hir::Attribute::Parsed(AttributeKind::CrateName { name, name_span, .. }) =
1129+
AttributeParser::parse_limited(sess, &attrs, sym::crate_name, DUMMY_SP, limit_diagnostics)?
1130+
else {
1131+
unreachable!("crate_name is the only attr we could've parsed here");
1132+
};
1133+
1134+
Some((name, name_span))
1135+
}
1136+
11221137
/// Compute and validate the crate name.
11231138
pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol {
11241139
// We validate *all* occurrences of `#![crate_name]`, pick the first find and
@@ -1128,8 +1143,7 @@ pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol
11281143
// in all code paths that require the crate name very early on, namely before
11291144
// macro expansion.
11301145

1131-
let attr_crate_name =
1132-
validate_and_find_value_str_builtin_attr(sym::crate_name, sess, krate_attrs);
1146+
let attr_crate_name = parse_crate_name(sess, krate_attrs, false);
11331147

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

compiler/rustc_interface/src/util.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use rustc_target::spec::Target;
2323
use tracing::info;
2424

2525
use crate::errors;
26+
use crate::passes::parse_crate_name;
2627

2728
/// Function pointer type that constructs a new CodegenBackend.
2829
type MakeBackendFn = fn() -> Box<dyn CodegenBackend>;
@@ -485,7 +486,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu
485486
.opts
486487
.crate_name
487488
.clone()
488-
.or_else(|| rustc_attr_parsing::find_crate_name(attrs).map(|n| n.to_string()));
489+
.or_else(|| parse_crate_name(sess, attrs, true).map(|i| i.0.to_string()));
489490

490491
match sess.io.output_file {
491492
None => {

compiler/rustc_lint/src/nonstandard_style.rs

+23-31
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use rustc_abi::ExternAbi;
2-
use rustc_attr_parsing::{AttributeKind, AttributeParser, ReprAttr};
2+
use rustc_attr_parsing::{AttributeKind, AttributeParser, ReprAttr, find_attr};
33
use rustc_hir::def::{DefKind, Res};
44
use rustc_hir::intravisit::FnKind;
5-
use rustc_hir::{AttrArgs, AttrItem, Attribute, GenericParamKind, PatExprKind, PatKind};
5+
use rustc_hir::{Attribute, GenericParamKind, PatExprKind, PatKind};
66
use rustc_middle::ty;
77
use rustc_session::config::CrateType;
88
use rustc_session::{declare_lint, declare_lint_pass};
@@ -342,35 +342,27 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
342342
let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name {
343343
Some(Ident::from_str(name))
344344
} else {
345-
ast::attr::find_by_name(cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name)
346-
.and_then(|attr| {
347-
if let Attribute::Unparsed(n) = attr
348-
&& let AttrItem { args: AttrArgs::Eq { eq_span: _, expr: lit }, .. } =
349-
n.as_ref()
350-
&& let ast::LitKind::Str(name, ..) = lit.kind
351-
{
352-
// Discard the double quotes surrounding the literal.
353-
let sp = cx
354-
.sess()
355-
.source_map()
356-
.span_to_snippet(lit.span)
357-
.ok()
358-
.and_then(|snippet| {
359-
let left = snippet.find('"')?;
360-
let right = snippet.rfind('"').map(|pos| snippet.len() - pos)?;
361-
362-
Some(
363-
lit.span
364-
.with_lo(lit.span.lo() + BytePos(left as u32 + 1))
365-
.with_hi(lit.span.hi() - BytePos(right as u32)),
366-
)
367-
})
368-
.unwrap_or(lit.span);
369-
370-
Some(Ident::new(name, sp))
371-
} else {
372-
None
373-
}
345+
find_attr!(cx.tcx.hir().attrs(hir::CRATE_HIR_ID), AttributeKind::CrateName{name, name_span,..} => (name, name_span))
346+
.and_then(|(&name, &span)| {
347+
// Discard the double quotes surrounding the literal.
348+
let sp = cx
349+
.sess()
350+
.source_map()
351+
.span_to_snippet(span)
352+
.ok()
353+
.and_then(|snippet| {
354+
let left = snippet.find('"')?;
355+
let right = snippet.rfind('"').map(|pos| snippet.len() - pos)?;
356+
357+
Some(
358+
span
359+
.with_lo(span.lo() + BytePos(left as u32 + 1))
360+
.with_hi(span.hi() - BytePos(right as u32)),
361+
)
362+
})
363+
.unwrap_or(span);
364+
365+
Some(Ident::new(name, sp))
374366
})
375367
};
376368

compiler/rustc_parse/src/validate_attr.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,9 @@ pub fn check_builtin_meta_item(
217217
) {
218218
// Some special attributes like `cfg` must be checked
219219
// before the generic check, so we skip them here.
220-
let should_skip = |name| name == sym::cfg;
220+
//
221+
// Also, attributes that have a new-style parser don't need to be checked here anymore
222+
let should_skip = |name| name == sym::cfg || name == sym::crate_name;
221223

222224
if !should_skip(name) && !is_attr_template_compatible(&template, &meta.kind) {
223225
emit_malformed_attribute(psess, style, meta.span, name, template);

compiler/rustc_passes/src/check_attr.rs

+37-16
Original file line numberDiff line numberDiff line change
@@ -315,22 +315,43 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
315315
let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
316316

317317
if hir_id != CRATE_HIR_ID {
318-
if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) =
319-
attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name))
320-
{
321-
match attr.style() {
322-
ast::AttrStyle::Outer => self.tcx.emit_node_span_lint(
323-
UNUSED_ATTRIBUTES,
324-
hir_id,
325-
attr.span(),
326-
errors::OuterCrateLevelAttr,
327-
),
328-
ast::AttrStyle::Inner => self.tcx.emit_node_span_lint(
329-
UNUSED_ATTRIBUTES,
330-
hir_id,
331-
attr.span(),
332-
errors::InnerCrateLevelAttr,
333-
),
318+
if let Attribute::Parsed(attr) = attr {
319+
if let Some((style, span)) = attr.crate_level() {
320+
match style {
321+
ast::AttrStyle::Outer => self.tcx.emit_node_span_lint(
322+
UNUSED_ATTRIBUTES,
323+
hir_id,
324+
span,
325+
errors::OuterCrateLevelAttr,
326+
),
327+
ast::AttrStyle::Inner => self.tcx.emit_node_span_lint(
328+
UNUSED_ATTRIBUTES,
329+
hir_id,
330+
span,
331+
errors::InnerCrateLevelAttr,
332+
),
333+
}
334+
}
335+
} else {
336+
// FIXME(jdonszelmann): remove once all crate-level attrs are parsed and caught by
337+
// the above
338+
if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) =
339+
attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name))
340+
{
341+
match attr.style() {
342+
ast::AttrStyle::Outer => self.tcx.emit_node_span_lint(
343+
UNUSED_ATTRIBUTES,
344+
hir_id,
345+
attr.span(),
346+
errors::OuterCrateLevelAttr,
347+
),
348+
ast::AttrStyle::Inner => self.tcx.emit_node_span_lint(
349+
UNUSED_ATTRIBUTES,
350+
hir_id,
351+
attr.span(),
352+
errors::InnerCrateLevelAttr,
353+
),
354+
}
334355
}
335356
}
336357
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// issue: rust-lang/rust#122001
22
// Ensure we reject macro calls inside `#![crate_name]` as their result wouldn't get honored anyway.
33

4-
#![crate_name = concat!("my", "crate")] //~ ERROR malformed `crate_name` attribute input
4+
#![crate_name = concat!("my", "crate")] //~ ERROR expected a quoted string literal
55

66
fn main() {}

0 commit comments

Comments
 (0)