Rollup merge of #142876 - JonathanBrouwer:target_feature_parser, r=oli-obk

Port `#[target_feature]` to new attribute parsing infrastructure

Ports `target_feature` to the new attribute parsing infrastructure for https://github.com/rust-lang/rust/issues/131229#issuecomment-2971353197

r? ``@jdonszelmann``
This commit is contained in:
Jana Dönszelmann
2025-07-03 13:29:36 +02:00
committed by GitHub
25 changed files with 438 additions and 310 deletions

View File

@@ -13,7 +13,8 @@ pub(crate) struct AllowInternalUnstableParser;
impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
const PATH: &[Symbol] = &[sym::allow_internal_unstable];
type Item = (Symbol, Span);
const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowInternalUnstable;
const CONVERT: ConvertFn<Self::Item> =
|items, span| AttributeKind::AllowInternalUnstable(items, span);
const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
fn extend<'c>(
@@ -30,7 +31,8 @@ pub(crate) struct AllowConstFnUnstableParser;
impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];
type Item = Symbol;
const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowConstFnUnstable;
const CONVERT: ConvertFn<Self::Item> =
|items, first_span| AttributeKind::AllowConstFnUnstable(items, first_span);
const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
fn extend<'c>(

View File

@@ -4,8 +4,8 @@ use rustc_session::parse::feature_err;
use rustc_span::{Span, Symbol, sym};
use super::{
AcceptMapping, AttributeOrder, AttributeParser, NoArgsAttributeParser, OnDuplicate,
SingleAttributeParser,
AcceptMapping, AttributeOrder, AttributeParser, CombineAttributeParser, ConvertFn,
NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
};
use crate::context::{AcceptContext, FinalizeContext, Stage};
use crate::parser::ArgParser;
@@ -280,3 +280,53 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
})
}
}
pub(crate) struct TargetFeatureParser;
impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
type Item = (Symbol, Span);
const PATH: &[Symbol] = &[sym::target_feature];
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature(items, span);
const TEMPLATE: AttributeTemplate = template!(List: "enable = \"feat1, feat2\"");
fn extend<'c>(
cx: &'c mut AcceptContext<'_, '_, S>,
args: &'c ArgParser<'_>,
) -> impl IntoIterator<Item = Self::Item> + 'c {
let mut features = Vec::new();
let ArgParser::List(list) = args else {
cx.expected_list(cx.attr_span);
return features;
};
for item in list.mixed() {
let Some(name_value) = item.meta_item() else {
cx.expected_name_value(item.span(), Some(sym::enable));
return features;
};
// Validate name
let Some(name) = name_value.path().word_sym() else {
cx.expected_name_value(name_value.path().span(), Some(sym::enable));
return features;
};
if name != sym::enable {
cx.expected_name_value(name_value.path().span(), Some(sym::enable));
return features;
}
// Use value
let Some(name_value) = name_value.args().name_value() else {
cx.expected_name_value(item.span(), Some(sym::enable));
return features;
};
let Some(value_str) = name_value.value_as_str() else {
cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit()));
return features;
};
for feature in value_str.as_str().split(",") {
features.push((Symbol::intern(feature), item.span()));
}
}
features
}
}

View File

@@ -264,7 +264,7 @@ impl<T: NoArgsAttributeParser<S>, S: Stage> SingleAttributeParser<S> for Without
}
}
type ConvertFn<E> = fn(ThinVec<E>) -> AttributeKind;
type ConvertFn<E> = fn(ThinVec<E>, Span) -> AttributeKind;
/// Alternative to [`AttributeParser`] that automatically handles state management.
/// If multiple attributes appear on an element, combines the values of each into a
@@ -295,14 +295,21 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
/// Use in combination with [`CombineAttributeParser`].
/// `Combine<T: CombineAttributeParser>` implements [`AttributeParser`].
pub(crate) struct Combine<T: CombineAttributeParser<S>, S: Stage>(
PhantomData<(S, T)>,
ThinVec<<T as CombineAttributeParser<S>>::Item>,
);
pub(crate) struct Combine<T: CombineAttributeParser<S>, S: Stage> {
phantom: PhantomData<(S, T)>,
/// A list of all items produced by parsing attributes so far. One attribute can produce any amount of items.
items: ThinVec<<T as CombineAttributeParser<S>>::Item>,
/// The full span of the first attribute that was encountered.
first_span: Option<Span>,
}
impl<T: CombineAttributeParser<S>, S: Stage> Default for Combine<T, S> {
fn default() -> Self {
Self(Default::default(), Default::default())
Self {
phantom: Default::default(),
items: Default::default(),
first_span: Default::default(),
}
}
}
@@ -310,10 +317,18 @@ impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
T::PATH,
<T as CombineAttributeParser<S>>::TEMPLATE,
|group: &mut Combine<T, S>, cx, args| group.1.extend(T::extend(cx, args)),
|group: &mut Combine<T, S>, cx, args| {
// Keep track of the span of the first attribute, for diagnostics
group.first_span.get_or_insert(cx.attr_span);
group.items.extend(T::extend(cx, args))
},
)];
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) }
if let Some(first_span) = self.first_span {
Some(T::CONVERT(self.items, first_span))
} else {
None
}
}
}

View File

@@ -23,7 +23,7 @@ pub(crate) struct ReprParser;
impl<S: Stage> CombineAttributeParser<S> for ReprParser {
type Item = (ReprAttr, Span);
const PATH: &[Symbol] = &[sym::repr];
const CONVERT: ConvertFn<Self::Item> = AttributeKind::Repr;
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::Repr(items);
// FIXME(jdonszelmann): never used
const TEMPLATE: AttributeTemplate =
template!(List: "C | Rust | align(...) | packed(...) | <integer type> | transparent");

View File

@@ -16,8 +16,8 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
use crate::attributes::codegen_attrs::{
ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TrackCallerParser,
UsedParser,
ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TargetFeatureParser,
TrackCallerParser, UsedParser,
};
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::deprecation::DeprecationParser;
@@ -118,6 +118,7 @@ attribute_parsers!(
Combine<AllowConstFnUnstableParser>,
Combine<AllowInternalUnstableParser>,
Combine<ReprParser>,
Combine<TargetFeatureParser>,
// tidy-alphabetical-end
// tidy-alphabetical-start