| 
1 | 1 | use rustc_attr_data_structures::{AttributeKind, OptimizeAttr};  | 
2 | 2 | use rustc_feature::{AttributeTemplate, template};  | 
3 |  | -use rustc_span::sym;  | 
 | 3 | +use rustc_span::{Span, Symbol, sym};  | 
4 | 4 | 
 
  | 
5 |  | -use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};  | 
 | 5 | +use super::{  | 
 | 6 | +    AttributeOrder, CombineAttributeParser, ConvertFn, OnDuplicate, SingleAttributeParser,  | 
 | 7 | +};  | 
6 | 8 | use crate::context::{AcceptContext, Stage};  | 
7 | 9 | use crate::parser::ArgParser;  | 
8 | 10 | 
 
  | 
@@ -56,3 +58,54 @@ impl<S: Stage> SingleAttributeParser<S> for ColdParser {  | 
56 | 58 |         Some(AttributeKind::Cold(cx.attr_span))  | 
57 | 59 |     }  | 
58 | 60 | }  | 
 | 61 | + | 
 | 62 | +pub(crate) struct TargetFeatureParser;  | 
 | 63 | + | 
 | 64 | +impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {  | 
 | 65 | +    type Item = (Symbol, Span);  | 
 | 66 | +    const PATH: &[Symbol] = &[sym::target_feature];  | 
 | 67 | +    const CONVERT: ConvertFn<Self::Item> =  | 
 | 68 | +        ConvertFn::WithFirstAttributeSpan(AttributeKind::TargetFeature);  | 
 | 69 | +    const TEMPLATE: AttributeTemplate = template!(List: "enable = \"feat1, feat2\"");  | 
 | 70 | + | 
 | 71 | +    fn extend<'c>(  | 
 | 72 | +        cx: &'c mut AcceptContext<'_, '_, S>,  | 
 | 73 | +        args: &'c ArgParser<'_>,  | 
 | 74 | +    ) -> impl IntoIterator<Item = Self::Item> + 'c {  | 
 | 75 | +        let mut features = Vec::new();  | 
 | 76 | +        let ArgParser::List(list) = args else {  | 
 | 77 | +            cx.expected_list(cx.attr_span);  | 
 | 78 | +            return features;  | 
 | 79 | +        };  | 
 | 80 | +        for item in list.mixed() {  | 
 | 81 | +            let Some(name_value) = item.meta_item() else {  | 
 | 82 | +                cx.expected_name_value(item.span(), Some(sym::enable));  | 
 | 83 | +                return features;  | 
 | 84 | +            };  | 
 | 85 | + | 
 | 86 | +            // Validate name  | 
 | 87 | +            let Some(name) = name_value.path().word_sym() else {  | 
 | 88 | +                cx.expected_name_value(name_value.path().span(), Some(sym::enable));  | 
 | 89 | +                return features;  | 
 | 90 | +            };  | 
 | 91 | +            if name != sym::enable {  | 
 | 92 | +                cx.expected_name_value(name_value.path().span(), Some(sym::enable));  | 
 | 93 | +                return features;  | 
 | 94 | +            }  | 
 | 95 | + | 
 | 96 | +            // Use value  | 
 | 97 | +            let Some(name_value) = name_value.args().name_value() else {  | 
 | 98 | +                cx.expected_name_value(item.span(), Some(sym::enable));  | 
 | 99 | +                return features;  | 
 | 100 | +            };  | 
 | 101 | +            let Some(value_str) = name_value.value_as_str() else {  | 
 | 102 | +                cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit()));  | 
 | 103 | +                return features;  | 
 | 104 | +            };  | 
 | 105 | +            for feature in value_str.as_str().split(",") {  | 
 | 106 | +                features.push((Symbol::intern(feature), item.span()));  | 
 | 107 | +            }  | 
 | 108 | +        }  | 
 | 109 | +        features  | 
 | 110 | +    }  | 
 | 111 | +}  | 
0 commit comments