diff options
Diffstat (limited to 'compiler/rustc_attr_parsing/src')
5 files changed, 83 insertions, 15 deletions
diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index 21b01a8d071..1c51c3eee4e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -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>( diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 1132402ea00..13f560dff38 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -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 + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index f791d44e09a..0215504b52b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -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 + } } } diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 4aa27043e98..1c070dc2685 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -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"); diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index d21d49b08bd..8614b942a54 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -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 |
