-
Notifications
You must be signed in to change notification settings - Fork 13.7k
Port #[crate_name]
to the new attribute parsing infrastructure
#137729
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
097f40c
020b268
7f9f26b
9a7d66d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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, | ||
}) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -328,15 +328,16 @@ fn expr_to_lit( | |
match res { | ||
Ok(lit) => { | ||
if token_lit.suffix.is_some() { | ||
psess | ||
.dcx() | ||
.create_err(SuffixedLiteralInAttribute { span: lit.span }) | ||
.emit_unless_delay(!should_emit.should_emit()); | ||
should_emit.emit_err( | ||
psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }), | ||
); | ||
None | ||
} else { | ||
if should_emit.should_emit() && !lit.kind.is_unsuffixed() { | ||
if !lit.kind.is_unsuffixed() { | ||
// Emit error and continue, we can still parse the attribute as if the suffix isn't there | ||
psess.dcx().emit_err(SuffixedLiteralInAttribute { span: lit.span }); | ||
should_emit.emit_err( | ||
psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }), | ||
); | ||
} | ||
|
||
Some(lit) | ||
|
@@ -354,19 +355,19 @@ fn expr_to_lit( | |
} | ||
} | ||
} else { | ||
if matches!(should_emit, ShouldEmit::Nothing) { | ||
return None; | ||
} | ||
|
||
// Example cases: | ||
// - `#[foo = 1+1]`: results in `ast::ExprKind::BinOp`. | ||
// - `#[foo = include_str!("nonexistent-file.rs")]`: | ||
// results in `ast::ExprKind::Err`. In that case we delay | ||
// the error because an earlier error will have already | ||
// been reported. | ||
let msg = "attribute value must be a literal"; | ||
let mut err = psess.dcx().struct_span_err(span, msg); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there's a subtle bug in this version, fixed in my last commit. When an expression in an attribute is a macro, and the macro expands to a literal, and we parse an attribute with ShouldEmit::Nothing, we would delay that as a bug expecting a second parse to emit the error. However, when the macro then expands to a literal, we don't hit the same codepath and we never emit an error about this. The delayed bug turns into an ICE. A very similar problem was happening in February already (#137687) which was recognized and even a backport was made for it. However, in later versions it still made it to stable. The last commit of this PR adds tests for these cases and fixes this by, when we expect a literal, but have ShouldEmit::Nothing, we don't delay a bug, instead we do nothing. This is correct because if the macro indeed turns into a literal, the second parse might very well be correct. We shouldn't have delayed a bug at all. Specifically for crate_name, we parse with ShouldEmit::EarlyFatal so when it cares about this being a literal, it will error about it as it should. |
||
if let ExprKind::Err(_) = expr.kind { | ||
err.downgrade_to_delayed_bug(); | ||
} | ||
|
||
err.emit_unless_delay(!should_emit.should_emit()); | ||
let err = psess.dcx().struct_span_err(span, msg); | ||
should_emit.emit_err(err); | ||
None | ||
} | ||
} | ||
|
@@ -397,9 +398,11 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { | |
} | ||
}; | ||
|
||
if self.should_emit.should_emit() && !lit.kind.is_unsuffixed() { | ||
if !lit.kind.is_unsuffixed() { | ||
// Emit error and continue, we can still parse the attribute as if the suffix isn't there | ||
self.parser.dcx().emit_err(SuffixedLiteralInAttribute { span: lit.span }); | ||
self.should_emit.emit_err( | ||
self.parser.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }), | ||
); | ||
} | ||
|
||
Ok(lit) | ||
|
@@ -539,7 +542,7 @@ impl<'a> MetaItemListParser<'a> { | |
) { | ||
Ok(s) => Some(s), | ||
Err(e) => { | ||
e.emit_unless_delay(!should_emit.should_emit()); | ||
should_emit.emit_err(e); | ||
None | ||
} | ||
} | ||
|
Uh oh!
There was an error while loading. Please reload this page.