@@ -385,57 +385,68 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
385385 }
386386}
387387
388+ fn parse_tf_attribute < ' c , S : Stage > (
389+ cx : & ' c mut AcceptContext < ' _ , ' _ , S > ,
390+ args : & ' c ArgParser < ' _ > ,
391+ ) -> impl IntoIterator < Item = ( Symbol , Span ) > + ' c {
392+ let mut features = Vec :: new ( ) ;
393+ let ArgParser :: List ( list) = args else {
394+ cx. expected_list ( cx. attr_span ) ;
395+ return features;
396+ } ;
397+ if list. is_empty ( ) {
398+ cx. warn_empty_attribute ( cx. attr_span ) ;
399+ return features;
400+ }
401+ for item in list. mixed ( ) {
402+ let Some ( name_value) = item. meta_item ( ) else {
403+ cx. expected_name_value ( item. span ( ) , Some ( sym:: enable) ) ;
404+ return features;
405+ } ;
406+
407+ // Validate name
408+ let Some ( name) = name_value. path ( ) . word_sym ( ) else {
409+ cx. expected_name_value ( name_value. path ( ) . span ( ) , Some ( sym:: enable) ) ;
410+ return features;
411+ } ;
412+ if name != sym:: enable {
413+ cx. expected_name_value ( name_value. path ( ) . span ( ) , Some ( sym:: enable) ) ;
414+ return features;
415+ }
416+
417+ // Use value
418+ let Some ( name_value) = name_value. args ( ) . name_value ( ) else {
419+ cx. expected_name_value ( item. span ( ) , Some ( sym:: enable) ) ;
420+ return features;
421+ } ;
422+ let Some ( value_str) = name_value. value_as_str ( ) else {
423+ cx. expected_string_literal ( name_value. value_span , Some ( name_value. value_as_lit ( ) ) ) ;
424+ return features;
425+ } ;
426+ for feature in value_str. as_str ( ) . split ( "," ) {
427+ features. push ( ( Symbol :: intern ( feature) , item. span ( ) ) ) ;
428+ }
429+ }
430+ features
431+ }
432+
388433pub ( crate ) struct TargetFeatureParser ;
389434
390435impl < S : Stage > CombineAttributeParser < S > for TargetFeatureParser {
391436 type Item = ( Symbol , Span ) ;
392437 const PATH : & [ Symbol ] = & [ sym:: target_feature] ;
393- const CONVERT : ConvertFn < Self :: Item > = |items, span| AttributeKind :: TargetFeature ( items, span) ;
438+ const CONVERT : ConvertFn < Self :: Item > = |items, span| AttributeKind :: TargetFeature {
439+ features : items,
440+ attr_span : span,
441+ was_forced : false ,
442+ } ;
394443 const TEMPLATE : AttributeTemplate = template ! ( List : & [ "enable = \" feat1, feat2\" " ] ) ;
395444
396445 fn extend < ' c > (
397446 cx : & ' c mut AcceptContext < ' _ , ' _ , S > ,
398447 args : & ' c ArgParser < ' _ > ,
399448 ) -> impl IntoIterator < Item = Self :: Item > + ' c {
400- let mut features = Vec :: new ( ) ;
401- let ArgParser :: List ( list) = args else {
402- cx. expected_list ( cx. attr_span ) ;
403- return features;
404- } ;
405- if list. is_empty ( ) {
406- cx. warn_empty_attribute ( cx. attr_span ) ;
407- return features;
408- }
409- for item in list. mixed ( ) {
410- let Some ( name_value) = item. meta_item ( ) else {
411- cx. expected_name_value ( item. span ( ) , Some ( sym:: enable) ) ;
412- return features;
413- } ;
414-
415- // Validate name
416- let Some ( name) = name_value. path ( ) . word_sym ( ) else {
417- cx. expected_name_value ( name_value. path ( ) . span ( ) , Some ( sym:: enable) ) ;
418- return features;
419- } ;
420- if name != sym:: enable {
421- cx. expected_name_value ( name_value. path ( ) . span ( ) , Some ( sym:: enable) ) ;
422- return features;
423- }
424-
425- // Use value
426- let Some ( name_value) = name_value. args ( ) . name_value ( ) else {
427- cx. expected_name_value ( item. span ( ) , Some ( sym:: enable) ) ;
428- return features;
429- } ;
430- let Some ( value_str) = name_value. value_as_str ( ) else {
431- cx. expected_string_literal ( name_value. value_span , Some ( name_value. value_as_lit ( ) ) ) ;
432- return features;
433- } ;
434- for feature in value_str. as_str ( ) . split ( "," ) {
435- features. push ( ( Symbol :: intern ( feature) , item. span ( ) ) ) ;
436- }
437- }
438- features
449+ parse_tf_attribute ( cx, args)
439450 }
440451
441452 const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: AllowList ( & [
@@ -449,3 +460,30 @@ impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
449460 Warn ( Target :: MacroDef ) ,
450461 ] ) ;
451462}
463+
464+ pub ( crate ) struct ForceTargetFeatureParser ;
465+
466+ impl < S : Stage > CombineAttributeParser < S > for ForceTargetFeatureParser {
467+ type Item = ( Symbol , Span ) ;
468+ const PATH : & [ Symbol ] = & [ sym:: force_target_feature] ;
469+ const CONVERT : ConvertFn < Self :: Item > = |items, span| AttributeKind :: TargetFeature {
470+ features : items,
471+ attr_span : span,
472+ was_forced : true ,
473+ } ;
474+ const TEMPLATE : AttributeTemplate = template ! ( List : & [ "enable = \" feat1, feat2\" " ] ) ;
475+
476+ fn extend < ' c > (
477+ cx : & ' c mut AcceptContext < ' _ , ' _ , S > ,
478+ args : & ' c ArgParser < ' _ > ,
479+ ) -> impl IntoIterator < Item = Self :: Item > + ' c {
480+ parse_tf_attribute ( cx, args)
481+ }
482+
483+ const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: AllowList ( & [
484+ Allow ( Target :: Fn ) ,
485+ Allow ( Target :: Method ( MethodKind :: Inherent ) ) ,
486+ Allow ( Target :: Method ( MethodKind :: Trait { body : true } ) ) ,
487+ Allow ( Target :: Method ( MethodKind :: TraitImpl ) ) ,
488+ ] ) ;
489+ }
0 commit comments