@@ -3,7 +3,7 @@ use std::num::IntErrorKind;
33use rustc_hir:: limit:: Limit ;
44
55use super :: prelude:: * ;
6- use crate :: session_diagnostics:: LimitInvalid ;
6+ use crate :: session_diagnostics:: { FeatureExpectedSingleWord , LimitInvalid } ;
77
88impl < S : Stage > AcceptContext < ' _ , ' _ , S > {
99 fn parse_limit_int ( & self , nv : & NameValueParser ) -> Option < Limit > {
@@ -183,3 +183,55 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcCoherenceIsCoreParser {
183183 const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: CrateLevel ;
184184 const CREATE : fn ( Span ) -> AttributeKind = AttributeKind :: RustcCoherenceIsCore ;
185185}
186+
187+ pub ( crate ) struct FeatureParser ;
188+
189+ impl < S : Stage > CombineAttributeParser < S > for FeatureParser {
190+ const PATH : & [ Symbol ] = & [ sym:: feature] ;
191+ type Item = Ident ;
192+ const CONVERT : ConvertFn < Self :: Item > = AttributeKind :: Feature ;
193+ const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: CrateLevel ;
194+ const TEMPLATE : AttributeTemplate = template ! ( List : & [ "feature1, feature2, ..." ] ) ;
195+
196+ fn extend < ' c > (
197+ cx : & ' c mut AcceptContext < ' _ , ' _ , S > ,
198+ args : & ' c ArgParser < ' _ > ,
199+ ) -> impl IntoIterator < Item = Self :: Item > + ' c {
200+ let ArgParser :: List ( list) = args else {
201+ cx. expected_list ( cx. attr_span ) ;
202+ return Vec :: new ( ) ;
203+ } ;
204+
205+ if list. is_empty ( ) {
206+ cx. warn_empty_attribute ( cx. attr_span ) ;
207+ }
208+
209+ let mut res = Vec :: new ( ) ;
210+
211+ for elem in list. mixed ( ) {
212+ let Some ( elem) = elem. meta_item ( ) else {
213+ cx. expected_identifier ( elem. span ( ) ) ;
214+ continue ;
215+ } ;
216+ if let Err ( arg_span) = elem. args ( ) . no_args ( ) {
217+ cx. expected_no_args ( arg_span) ;
218+ continue ;
219+ }
220+
221+ let path = elem. path ( ) ;
222+ let Some ( ident) = path. word ( ) else {
223+ let first_segment = elem. path ( ) . segments ( ) . next ( ) . expect ( "at least one segment" ) ;
224+ cx. emit_err ( FeatureExpectedSingleWord {
225+ span : path. span ( ) ,
226+ first_segment_span : first_segment. span ,
227+ first_segment : first_segment. name ,
228+ } ) ;
229+ continue ;
230+ } ;
231+
232+ res. push ( ident) ;
233+ }
234+
235+ res
236+ }
237+ }
0 commit comments