Skip to content

Commit 2a58411

Browse files
JonathanBrouwerjdonszelmann
andcommitted
Port #[feature] to the new attribute parsing infrastructure
Co-authored-by: jdonszelmann <janabent@gmail.com>
1 parent d8b2222 commit 2a58411

8 files changed

Lines changed: 129 additions & 67 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3515,6 +3515,7 @@ dependencies = [
35153515
"rustc_data_structures",
35163516
"rustc_errors",
35173517
"rustc_feature",
3518+
"rustc_hir",
35183519
"rustc_macros",
35193520
"rustc_session",
35203521
"rustc_span",

compiler/rustc_attr_parsing/src/attributes/crate_level.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,3 +301,49 @@ impl<S: Stage> NoArgsAttributeParser<S> for DefaultLibAllocatorParser {
301301
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
302302
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::DefaultLibAllocator;
303303
}
304+
305+
pub(crate) struct FeatureParser;
306+
307+
impl<S: Stage> CombineAttributeParser<S> for FeatureParser {
308+
const PATH: &[Symbol] = &[sym::feature];
309+
type Item = Ident;
310+
const CONVERT: ConvertFn<Self::Item> = AttributeKind::Feature;
311+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
312+
const TEMPLATE: AttributeTemplate = template!(List: &["feature1, feature2, ..."]);
313+
314+
fn extend(
315+
cx: &mut AcceptContext<'_, '_, S>,
316+
args: &ArgParser,
317+
) -> impl IntoIterator<Item = Self::Item> {
318+
let ArgParser::List(list) = args else {
319+
cx.expected_list(cx.attr_span, args);
320+
return Vec::new();
321+
};
322+
323+
if list.is_empty() {
324+
cx.warn_empty_attribute(cx.attr_span);
325+
}
326+
327+
let mut res = Vec::new();
328+
329+
for elem in list.mixed() {
330+
let Some(elem) = elem.meta_item() else {
331+
cx.expected_identifier(elem.span());
332+
continue;
333+
};
334+
if let Err(arg_span) = elem.args().no_args() {
335+
cx.expected_no_args(arg_span);
336+
continue;
337+
}
338+
339+
let path = elem.path();
340+
let Some(ident) = path.word() else {
341+
cx.expected_identifier(path.span());
342+
continue;
343+
};
344+
res.push(ident);
345+
}
346+
347+
res
348+
}
349+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ attribute_parsers!(
157157
Combine<AllowInternalUnstableParser>,
158158
Combine<CrateTypeParser>,
159159
Combine<DebuggerViualizerParser>,
160+
Combine<FeatureParser>,
160161
Combine<ForceTargetFeatureParser>,
161162
Combine<LinkParser>,
162163
Combine<ReprParser>,

compiler/rustc_error_codes/src/error_codes/E0556.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
#### Note: this error code is no longer emitted by the compiler.
2+
13
The `feature` attribute was badly formed.
24

35
Erroneous code example:
46

5-
```compile_fail,E0556
7+
```compile_fail
68
#![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] // error!
79
#![feature] // error!
810
#![feature = "foo"] // error!

compiler/rustc_error_codes/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ macro_rules! error_codes {
334334
0551,
335335
0552,
336336
0554,
337-
0556,
337+
0556, // REMOVED: merged with other attribute error codes
338338
0557,
339339
0559,
340340
0560,

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,9 @@ pub enum AttributeKind {
954954
/// Represents `#[export_stable]`.
955955
ExportStable,
956956

957+
/// Represents `#[feature(...)]`
958+
Feature(ThinVec<Ident>, Span),
959+
957960
/// Represents `#[ffi_const]`.
958961
FfiConst(Span),
959962

compiler/rustc_hir/src/attrs/encode_cross_crate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ impl AttributeKind {
4545
EiiImpls(..) => No,
4646
ExportName { .. } => Yes,
4747
ExportStable => No,
48+
Feature(..) => No,
4849
FfiConst(..) => No,
4950
FfiPure(..) => No,
5051
Fundamental { .. } => Yes,

compiler/rustc_passes/src/check_attr.rs

Lines changed: 73 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
253253
| AttributeKind::EiiForeignItem
254254
| AttributeKind::ExportName { .. }
255255
| AttributeKind::ExportStable
256+
| AttributeKind::Feature(..)
256257
| AttributeKind::FfiConst(..)
257258
| AttributeKind::Fundamental
258259
| AttributeKind::Ignore { .. }
@@ -1564,75 +1565,82 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
15641565
fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute, style: Option<AttrStyle>) {
15651566
// Warn on useless empty attributes.
15661567
// FIXME(jdonszelmann): this lint should be moved to attribute parsing, see `AcceptContext::warn_empty_attribute`
1567-
let note = if attr.has_any_name(&[
1568-
sym::allow,
1569-
sym::expect,
1570-
sym::warn,
1571-
sym::deny,
1572-
sym::forbid,
1573-
sym::feature,
1574-
]) && attr.meta_item_list().is_some_and(|list| list.is_empty())
1575-
{
1576-
errors::UnusedNote::EmptyList { name: attr.name().unwrap() }
1577-
} else if attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect])
1578-
&& let Some(meta) = attr.meta_item_list()
1579-
&& let [meta] = meta.as_slice()
1580-
&& let Some(item) = meta.meta_item()
1581-
&& let MetaItemKind::NameValue(_) = &item.kind
1582-
&& item.path == sym::reason
1583-
{
1584-
errors::UnusedNote::NoLints { name: attr.name().unwrap() }
1585-
} else if attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect])
1586-
&& let Some(meta) = attr.meta_item_list()
1587-
&& meta.iter().any(|meta| {
1588-
meta.meta_item().map_or(false, |item| item.path == sym::linker_messages)
1589-
})
1590-
{
1591-
if hir_id != CRATE_HIR_ID {
1592-
match style {
1593-
Some(ast::AttrStyle::Outer) => {
1594-
let attr_span = attr.span();
1595-
let bang_position = self
1596-
.tcx
1597-
.sess
1598-
.source_map()
1599-
.span_until_char(attr_span, '[')
1600-
.shrink_to_hi();
1601-
1602-
self.tcx.emit_node_span_lint(
1568+
let note =
1569+
if attr.has_any_name(&[sym::allow, sym::expect, sym::warn, sym::deny, sym::forbid])
1570+
&& attr.meta_item_list().is_some_and(|list| list.is_empty())
1571+
{
1572+
errors::UnusedNote::EmptyList { name: attr.name().unwrap() }
1573+
} else if attr.has_any_name(&[
1574+
sym::allow,
1575+
sym::warn,
1576+
sym::deny,
1577+
sym::forbid,
1578+
sym::expect,
1579+
]) && let Some(meta) = attr.meta_item_list()
1580+
&& let [meta] = meta.as_slice()
1581+
&& let Some(item) = meta.meta_item()
1582+
&& let MetaItemKind::NameValue(_) = &item.kind
1583+
&& item.path == sym::reason
1584+
{
1585+
errors::UnusedNote::NoLints { name: attr.name().unwrap() }
1586+
} else if attr.has_any_name(&[
1587+
sym::allow,
1588+
sym::warn,
1589+
sym::deny,
1590+
sym::forbid,
1591+
sym::expect,
1592+
]) && let Some(meta) = attr.meta_item_list()
1593+
&& meta.iter().any(|meta| {
1594+
meta.meta_item().map_or(false, |item| item.path == sym::linker_messages)
1595+
})
1596+
{
1597+
if hir_id != CRATE_HIR_ID {
1598+
match style {
1599+
Some(ast::AttrStyle::Outer) => {
1600+
let attr_span = attr.span();
1601+
let bang_position = self
1602+
.tcx
1603+
.sess
1604+
.source_map()
1605+
.span_until_char(attr_span, '[')
1606+
.shrink_to_hi();
1607+
1608+
self.tcx.emit_node_span_lint(
1609+
UNUSED_ATTRIBUTES,
1610+
hir_id,
1611+
attr_span,
1612+
errors::OuterCrateLevelAttr {
1613+
suggestion: errors::OuterCrateLevelAttrSuggestion {
1614+
bang_position,
1615+
},
1616+
},
1617+
)
1618+
}
1619+
Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint(
16031620
UNUSED_ATTRIBUTES,
16041621
hir_id,
1605-
attr_span,
1606-
errors::OuterCrateLevelAttr {
1607-
suggestion: errors::OuterCrateLevelAttrSuggestion { bang_position },
1608-
},
1609-
)
1610-
}
1611-
Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint(
1612-
UNUSED_ATTRIBUTES,
1613-
hir_id,
1614-
attr.span(),
1615-
errors::InnerCrateLevelAttr,
1616-
),
1617-
};
1618-
return;
1619-
} else {
1620-
let never_needs_link = self
1621-
.tcx
1622-
.crate_types()
1623-
.iter()
1624-
.all(|kind| matches!(kind, CrateType::Rlib | CrateType::StaticLib));
1625-
if never_needs_link {
1626-
errors::UnusedNote::LinkerMessagesBinaryCrateOnly
1627-
} else {
1622+
attr.span(),
1623+
errors::InnerCrateLevelAttr,
1624+
),
1625+
};
16281626
return;
1627+
} else {
1628+
let never_needs_link = self
1629+
.tcx
1630+
.crate_types()
1631+
.iter()
1632+
.all(|kind| matches!(kind, CrateType::Rlib | CrateType::StaticLib));
1633+
if never_needs_link {
1634+
errors::UnusedNote::LinkerMessagesBinaryCrateOnly
1635+
} else {
1636+
return;
1637+
}
16291638
}
1630-
}
1631-
} else if attr.has_name(sym::default_method_body_is_const) {
1632-
errors::UnusedNote::DefaultMethodBodyConst
1633-
} else {
1634-
return;
1635-
};
1639+
} else if attr.has_name(sym::default_method_body_is_const) {
1640+
errors::UnusedNote::DefaultMethodBodyConst
1641+
} else {
1642+
return;
1643+
};
16361644

16371645
self.tcx.emit_node_span_lint(
16381646
UNUSED_ATTRIBUTES,

0 commit comments

Comments
 (0)