@@ -376,57 +376,68 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
376376 }
377377}
378378
379+ fn parse_tf_attribute < ' c , S : Stage > (
380+ cx : & ' c mut AcceptContext < ' _ , ' _ , S > ,
381+ args : & ' c ArgParser < ' _ > ,
382+ ) -> impl IntoIterator < Item = ( Symbol , Span ) > + ' c {
383+ let mut features = Vec :: new ( ) ;
384+ let ArgParser :: List ( list) = args else {
385+ cx. expected_list ( cx. attr_span ) ;
386+ return features;
387+ } ;
388+ if list. is_empty ( ) {
389+ cx. warn_empty_attribute ( cx. attr_span ) ;
390+ return features;
391+ }
392+ for item in list. mixed ( ) {
393+ let Some ( name_value) = item. meta_item ( ) else {
394+ cx. expected_name_value ( item. span ( ) , Some ( sym:: enable) ) ;
395+ return features;
396+ } ;
397+
398+ // Validate name
399+ let Some ( name) = name_value. path ( ) . word_sym ( ) else {
400+ cx. expected_name_value ( name_value. path ( ) . span ( ) , Some ( sym:: enable) ) ;
401+ return features;
402+ } ;
403+ if name != sym:: enable {
404+ cx. expected_name_value ( name_value. path ( ) . span ( ) , Some ( sym:: enable) ) ;
405+ return features;
406+ }
407+
408+ // Use value
409+ let Some ( name_value) = name_value. args ( ) . name_value ( ) else {
410+ cx. expected_name_value ( item. span ( ) , Some ( sym:: enable) ) ;
411+ return features;
412+ } ;
413+ let Some ( value_str) = name_value. value_as_str ( ) else {
414+ cx. expected_string_literal ( name_value. value_span , Some ( name_value. value_as_lit ( ) ) ) ;
415+ return features;
416+ } ;
417+ for feature in value_str. as_str ( ) . split ( "," ) {
418+ features. push ( ( Symbol :: intern ( feature) , item. span ( ) ) ) ;
419+ }
420+ }
421+ features
422+ }
423+
379424pub ( crate ) struct TargetFeatureParser ;
380425
381426impl < S : Stage > CombineAttributeParser < S > for TargetFeatureParser {
382427 type Item = ( Symbol , Span ) ;
383428 const PATH : & [ Symbol ] = & [ sym:: target_feature] ;
384- const CONVERT : ConvertFn < Self :: Item > = |items, span| AttributeKind :: TargetFeature ( items, span) ;
429+ const CONVERT : ConvertFn < Self :: Item > = |items, span| AttributeKind :: TargetFeature {
430+ features : items,
431+ attr_span : span,
432+ was_forced : false ,
433+ } ;
385434 const TEMPLATE : AttributeTemplate = template ! ( List : & [ "enable = \" feat1, feat2\" " ] ) ;
386435
387436 fn extend < ' c > (
388437 cx : & ' c mut AcceptContext < ' _ , ' _ , S > ,
389438 args : & ' c ArgParser < ' _ > ,
390439 ) -> impl IntoIterator < Item = Self :: Item > + ' c {
391- let mut features = Vec :: new ( ) ;
392- let ArgParser :: List ( list) = args else {
393- cx. expected_list ( cx. attr_span ) ;
394- return features;
395- } ;
396- if list. is_empty ( ) {
397- cx. warn_empty_attribute ( cx. attr_span ) ;
398- return features;
399- }
400- for item in list. mixed ( ) {
401- let Some ( name_value) = item. meta_item ( ) else {
402- cx. expected_name_value ( item. span ( ) , Some ( sym:: enable) ) ;
403- return features;
404- } ;
405-
406- // Validate name
407- let Some ( name) = name_value. path ( ) . word_sym ( ) else {
408- cx. expected_name_value ( name_value. path ( ) . span ( ) , Some ( sym:: enable) ) ;
409- return features;
410- } ;
411- if name != sym:: enable {
412- cx. expected_name_value ( name_value. path ( ) . span ( ) , Some ( sym:: enable) ) ;
413- return features;
414- }
415-
416- // Use value
417- let Some ( name_value) = name_value. args ( ) . name_value ( ) else {
418- cx. expected_name_value ( item. span ( ) , Some ( sym:: enable) ) ;
419- return features;
420- } ;
421- let Some ( value_str) = name_value. value_as_str ( ) else {
422- cx. expected_string_literal ( name_value. value_span , Some ( name_value. value_as_lit ( ) ) ) ;
423- return features;
424- } ;
425- for feature in value_str. as_str ( ) . split ( "," ) {
426- features. push ( ( Symbol :: intern ( feature) , item. span ( ) ) ) ;
427- }
428- }
429- features
440+ parse_tf_attribute ( cx, args)
430441 }
431442
432443 const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: AllowList ( & [
@@ -440,3 +451,30 @@ impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
440451 Warn ( Target :: MacroDef ) ,
441452 ] ) ;
442453}
454+
455+ pub ( crate ) struct ForceTargetFeatureParser ;
456+
457+ impl < S : Stage > CombineAttributeParser < S > for ForceTargetFeatureParser {
458+ type Item = ( Symbol , Span ) ;
459+ const PATH : & [ Symbol ] = & [ sym:: force_target_feature] ;
460+ const CONVERT : ConvertFn < Self :: Item > = |items, span| AttributeKind :: TargetFeature {
461+ features : items,
462+ attr_span : span,
463+ was_forced : true ,
464+ } ;
465+ const TEMPLATE : AttributeTemplate = template ! ( List : & [ "enable = \" feat1, feat2\" " ] ) ;
466+
467+ fn extend < ' c > (
468+ cx : & ' c mut AcceptContext < ' _ , ' _ , S > ,
469+ args : & ' c ArgParser < ' _ > ,
470+ ) -> impl IntoIterator < Item = Self :: Item > + ' c {
471+ parse_tf_attribute ( cx, args)
472+ }
473+
474+ const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: AllowList ( & [
475+ Allow ( Target :: Fn ) ,
476+ Allow ( Target :: Method ( MethodKind :: Inherent ) ) ,
477+ Allow ( Target :: Method ( MethodKind :: Trait { body : true } ) ) ,
478+ Allow ( Target :: Method ( MethodKind :: TraitImpl ) ) ,
479+ ] ) ;
480+ }
0 commit comments