99//! [#64197]: https://github.com/rust-lang/rust/issues/64197
1010
1111use crate :: { parse_in, validate_attr} ;
12- use rustc_errors:: Applicability ;
13- use rustc_feature:: Features ;
14- use rustc_span:: edition:: Edition ;
15- use rustc_span:: symbol:: sym;
16- use rustc_span:: Span ;
12+ use rustc_data_structures:: fx:: FxHashMap ;
13+ use rustc_error_codes:: * ;
14+ use rustc_errors:: { error_code, struct_span_err, Applicability , Handler } ;
15+ use rustc_feature:: { Feature , Features , State as FeatureState } ;
16+ use rustc_feature:: {
17+ ACCEPTED_FEATURES , ACTIVE_FEATURES , REMOVED_FEATURES , STABLE_REMOVED_FEATURES ,
18+ } ;
19+ use rustc_span:: edition:: { Edition , ALL_EDITIONS } ;
20+ use rustc_span:: symbol:: { sym, Symbol } ;
21+ use rustc_span:: { Span , DUMMY_SP } ;
1722use syntax:: ast:: { self , AttrItem , Attribute , MetaItem } ;
1823use syntax:: attr;
1924use syntax:: attr:: HasAttrs ;
20- use syntax:: feature_gate:: { feature_err, get_features } ;
25+ use syntax:: feature_gate:: feature_err;
2126use syntax:: mut_visit:: * ;
2227use syntax:: ptr:: P ;
2328use syntax:: sess:: ParseSess ;
@@ -31,6 +36,172 @@ pub struct StripUnconfigured<'a> {
3136 pub features : Option < & ' a Features > ,
3237}
3338
39+ fn get_features (
40+ span_handler : & Handler ,
41+ krate_attrs : & [ ast:: Attribute ] ,
42+ crate_edition : Edition ,
43+ allow_features : & Option < Vec < String > > ,
44+ ) -> Features {
45+ fn feature_removed ( span_handler : & Handler , span : Span , reason : Option < & str > ) {
46+ let mut err = struct_span_err ! ( span_handler, span, E0557 , "feature has been removed" ) ;
47+ err. span_label ( span, "feature has been removed" ) ;
48+ if let Some ( reason) = reason {
49+ err. note ( reason) ;
50+ }
51+ err. emit ( ) ;
52+ }
53+
54+ fn active_features_up_to ( edition : Edition ) -> impl Iterator < Item = & ' static Feature > {
55+ ACTIVE_FEATURES . iter ( ) . filter ( move |feature| {
56+ if let Some ( feature_edition) = feature. edition {
57+ feature_edition <= edition
58+ } else {
59+ false
60+ }
61+ } )
62+ }
63+
64+ let mut features = Features :: default ( ) ;
65+ let mut edition_enabled_features = FxHashMap :: default ( ) ;
66+
67+ for & edition in ALL_EDITIONS {
68+ if edition <= crate_edition {
69+ // The `crate_edition` implies its respective umbrella feature-gate
70+ // (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX).
71+ edition_enabled_features. insert ( edition. feature_name ( ) , edition) ;
72+ }
73+ }
74+
75+ for feature in active_features_up_to ( crate_edition) {
76+ feature. set ( & mut features, DUMMY_SP ) ;
77+ edition_enabled_features. insert ( feature. name , crate_edition) ;
78+ }
79+
80+ // Process the edition umbrella feature-gates first, to ensure
81+ // `edition_enabled_features` is completed before it's queried.
82+ for attr in krate_attrs {
83+ if !attr. check_name ( sym:: feature) {
84+ continue ;
85+ }
86+
87+ let list = match attr. meta_item_list ( ) {
88+ Some ( list) => list,
89+ None => continue ,
90+ } ;
91+
92+ for mi in list {
93+ if !mi. is_word ( ) {
94+ continue ;
95+ }
96+
97+ let name = mi. name_or_empty ( ) ;
98+
99+ let edition = ALL_EDITIONS . iter ( ) . find ( |e| name == e. feature_name ( ) ) . copied ( ) ;
100+ if let Some ( edition) = edition {
101+ if edition <= crate_edition {
102+ continue ;
103+ }
104+
105+ for feature in active_features_up_to ( edition) {
106+ // FIXME(Manishearth) there is currently no way to set
107+ // lib features by edition
108+ feature. set ( & mut features, DUMMY_SP ) ;
109+ edition_enabled_features. insert ( feature. name , edition) ;
110+ }
111+ }
112+ }
113+ }
114+
115+ for attr in krate_attrs {
116+ if !attr. check_name ( sym:: feature) {
117+ continue ;
118+ }
119+
120+ let list = match attr. meta_item_list ( ) {
121+ Some ( list) => list,
122+ None => continue ,
123+ } ;
124+
125+ let bad_input = |span| {
126+ struct_span_err ! ( span_handler, span, E0556 , "malformed `feature` attribute input" )
127+ } ;
128+
129+ for mi in list {
130+ let name = match mi. ident ( ) {
131+ Some ( ident) if mi. is_word ( ) => ident. name ,
132+ Some ( ident) => {
133+ bad_input ( mi. span ( ) )
134+ . span_suggestion (
135+ mi. span ( ) ,
136+ "expected just one word" ,
137+ format ! ( "{}" , ident. name) ,
138+ Applicability :: MaybeIncorrect ,
139+ )
140+ . emit ( ) ;
141+ continue ;
142+ }
143+ None => {
144+ bad_input ( mi. span ( ) ) . span_label ( mi. span ( ) , "expected just one word" ) . emit ( ) ;
145+ continue ;
146+ }
147+ } ;
148+
149+ if let Some ( edition) = edition_enabled_features. get ( & name) {
150+ let msg =
151+ & format ! ( "the feature `{}` is included in the Rust {} edition" , name, edition) ;
152+ span_handler. struct_span_warn_with_code ( mi. span ( ) , msg, error_code ! ( E0705 ) ) . emit ( ) ;
153+ continue ;
154+ }
155+
156+ if ALL_EDITIONS . iter ( ) . any ( |e| name == e. feature_name ( ) ) {
157+ // Handled in the separate loop above.
158+ continue ;
159+ }
160+
161+ let removed = REMOVED_FEATURES . iter ( ) . find ( |f| name == f. name ) ;
162+ let stable_removed = STABLE_REMOVED_FEATURES . iter ( ) . find ( |f| name == f. name ) ;
163+ if let Some ( Feature { state, .. } ) = removed. or ( stable_removed) {
164+ if let FeatureState :: Removed { reason } | FeatureState :: Stabilized { reason } =
165+ state
166+ {
167+ feature_removed ( span_handler, mi. span ( ) , * reason) ;
168+ continue ;
169+ }
170+ }
171+
172+ if let Some ( Feature { since, .. } ) = ACCEPTED_FEATURES . iter ( ) . find ( |f| name == f. name ) {
173+ let since = Some ( Symbol :: intern ( since) ) ;
174+ features. declared_lang_features . push ( ( name, mi. span ( ) , since) ) ;
175+ continue ;
176+ }
177+
178+ if let Some ( allowed) = allow_features. as_ref ( ) {
179+ if allowed. iter ( ) . find ( |& f| name. as_str ( ) == * f) . is_none ( ) {
180+ struct_span_err ! (
181+ span_handler,
182+ mi. span( ) ,
183+ E0725 ,
184+ "the feature `{}` is not in the list of allowed features" ,
185+ name
186+ )
187+ . emit ( ) ;
188+ continue ;
189+ }
190+ }
191+
192+ if let Some ( f) = ACTIVE_FEATURES . iter ( ) . find ( |f| name == f. name ) {
193+ f. set ( & mut features, mi. span ( ) ) ;
194+ features. declared_lang_features . push ( ( name, mi. span ( ) , None ) ) ;
195+ continue ;
196+ }
197+
198+ features. declared_lib_features . push ( ( name, mi. span ( ) ) ) ;
199+ }
200+ }
201+
202+ features
203+ }
204+
34205// `cfg_attr`-process the crate's attributes and compute the crate's features.
35206pub fn features (
36207 mut krate : ast:: Crate ,
0 commit comments