about summary refs log tree commit diff
path: root/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs')
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs54
1 files changed, 52 insertions, 2 deletions
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
+    }
+}