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:
@@ -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>(
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user