@@ -13,17 +13,16 @@ use rustc_ast::NodeId;
1313use rustc_ast:: { self as ast, AttrStyle , Attribute , HasAttrs , HasTokens , MetaItem } ;
1414use rustc_attr as attr;
1515use rustc_data_structures:: flat_map_in_place:: FlatMapInPlace ;
16- use rustc_data_structures:: fx:: FxHashMap ;
16+ use rustc_data_structures:: fx:: FxHashSet ;
1717use rustc_feature:: { Feature , Features , State as FeatureState } ;
18- use rustc_feature:: {
19- ACCEPTED_FEATURES , ACTIVE_FEATURES , REMOVED_FEATURES , STABLE_REMOVED_FEATURES ,
20- } ;
18+ use rustc_feature:: { ACCEPTED_FEATURES , ACTIVE_FEATURES , REMOVED_FEATURES } ;
2119use rustc_parse:: validate_attr;
2220use rustc_session:: parse:: feature_err;
2321use rustc_session:: Session ;
2422use rustc_span:: edition:: { Edition , ALL_EDITIONS } ;
2523use rustc_span:: symbol:: { sym, Symbol } ;
26- use rustc_span:: { Span , DUMMY_SP } ;
24+ use rustc_span:: Span ;
25+ use thin_vec:: ThinVec ;
2726
2827/// A folder that strips out items that do not belong in the current configuration.
2928pub struct StripUnconfigured < ' a > {
@@ -37,13 +36,6 @@ pub struct StripUnconfigured<'a> {
3736}
3837
3938pub fn features ( sess : & Session , krate_attrs : & [ Attribute ] ) -> Features {
40- fn feature_removed ( sess : & Session , span : Span , reason : Option < & str > ) {
41- sess. emit_err ( FeatureRemoved {
42- span,
43- reason : reason. map ( |reason| FeatureRemovedReason { reason } ) ,
44- } ) ;
45- }
46-
4739 fn active_features_up_to ( edition : Edition ) -> impl Iterator < Item = & ' static Feature > {
4840 ACTIVE_FEATURES . iter ( ) . filter ( move |feature| {
4941 if let Some ( feature_edition) = feature. edition {
@@ -54,67 +46,49 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
5446 } )
5547 }
5648
57- let mut features = Features :: default ( ) ;
58- let mut edition_enabled_features = FxHashMap :: default ( ) ;
59- let crate_edition = sess. edition ( ) ;
60-
61- for & edition in ALL_EDITIONS {
62- if edition <= crate_edition {
63- // The `crate_edition` implies its respective umbrella feature-gate
64- // (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX).
65- edition_enabled_features. insert ( edition. feature_name ( ) , edition) ;
49+ fn feature_list ( attr : & Attribute ) -> ThinVec < ast:: NestedMetaItem > {
50+ if attr. has_name ( sym:: feature) && let Some ( list) = attr. meta_item_list ( ) {
51+ list
52+ } else {
53+ ThinVec :: new ( )
6654 }
6755 }
6856
69- for feature in active_features_up_to ( crate_edition) {
70- feature. set ( & mut features, DUMMY_SP ) ;
71- edition_enabled_features. insert ( feature. name , crate_edition) ;
72- }
73-
74- // Process the edition umbrella feature-gates first, to ensure
75- // `edition_enabled_features` is completed before it's queried.
76- for attr in krate_attrs {
77- if !attr. has_name ( sym:: feature) {
78- continue ;
79- }
80-
81- let Some ( list) = attr. meta_item_list ( ) else {
82- continue ;
83- } ;
84-
85- for mi in list {
86- if !mi. is_word ( ) {
87- continue ;
88- }
89-
90- let name = mi. name_or_empty ( ) ;
57+ let mut features = Features :: default ( ) ;
9158
92- let edition = ALL_EDITIONS . iter ( ) . find ( |e| name == e. feature_name ( ) ) . copied ( ) ;
93- if let Some ( edition) = edition {
94- if edition <= crate_edition {
95- continue ;
96- }
59+ // The edition from `--edition`.
60+ let crate_edition = sess. edition ( ) ;
9761
98- for feature in active_features_up_to ( edition) {
99- // FIXME(Manishearth) there is currently no way to set
100- // lib features by edition
101- feature. set ( & mut features, DUMMY_SP ) ;
102- edition_enabled_features. insert ( feature. name , edition) ;
62+ // The maximum of (a) the edition from `--edition` and (b) any edition
63+ // umbrella feature-gates declared in the code.
64+ // - E.g. if `crate_edition` is 2015 but `rust_2018_preview` is present,
65+ // `feature_edition` is 2018
66+ let mut features_edition = crate_edition;
67+ for attr in krate_attrs {
68+ for mi in feature_list ( attr) {
69+ if mi. is_word ( ) {
70+ let name = mi. name_or_empty ( ) ;
71+ let edition = ALL_EDITIONS . iter ( ) . find ( |e| name == e. feature_name ( ) ) . copied ( ) ;
72+ if let Some ( edition) = edition && edition > features_edition {
73+ features_edition = edition;
10374 }
10475 }
10576 }
10677 }
10778
108- for attr in krate_attrs {
109- if !attr. has_name ( sym:: feature) {
110- continue ;
111- }
112-
113- let Some ( list) = attr. meta_item_list ( ) else {
114- continue ;
115- } ;
79+ // Enable edition-dependent features based on `features_edition`.
80+ // - E.g. enable `test_2018_feature` if `features_edition` is 2018 or higher
81+ let mut edition_enabled_features = FxHashSet :: default ( ) ;
82+ for feature in active_features_up_to ( features_edition) {
83+ // FIXME(Manishearth) there is currently no way to set lib features by
84+ // edition.
85+ edition_enabled_features. insert ( feature. name ) ;
86+ feature. set ( & mut features) ;
87+ }
11688
117- for mi in list {
89+ // Process all features declared in the code.
90+ for attr in krate_attrs {
91+ for mi in feature_list ( attr) {
11892 let name = match mi. ident ( ) {
11993 Some ( ident) if mi. is_word ( ) => ident. name ,
12094 Some ( ident) => {
@@ -136,54 +110,76 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
136110 }
137111 } ;
138112
139- if let Some ( & edition) = edition_enabled_features. get ( & name) {
113+ // If the declared feature is an edition umbrella feature-gate,
114+ // warn if it was redundant w.r.t. `crate_edition`.
115+ // - E.g. warn if `rust_2018_preview` is declared when
116+ // `crate_edition` is 2018
117+ // - E.g. don't warn if `rust_2018_preview` is declared when
118+ // `crate_edition` is 2015.
119+ if let Some ( & edition) = ALL_EDITIONS . iter ( ) . find ( |e| name == e. feature_name ( ) ) {
120+ if edition <= crate_edition {
121+ sess. emit_warning ( FeatureIncludedInEdition {
122+ span : mi. span ( ) ,
123+ feature : name,
124+ edition,
125+ } ) ;
126+ }
127+ features. set_declared_lang_feature ( name, mi. span ( ) , None ) ;
128+ continue ;
129+ }
130+
131+ // If the declared feature is edition-dependent and was already
132+ // enabled due to `feature_edition`, give a warning.
133+ // - E.g. warn if `test_2018_feature` is declared when
134+ // `feature_edition` is 2018 or higher.
135+ if edition_enabled_features. contains ( & name) {
140136 sess. emit_warning ( FeatureIncludedInEdition {
141137 span : mi. span ( ) ,
142138 feature : name,
143- edition,
139+ edition : features_edition ,
144140 } ) ;
141+ features. set_declared_lang_feature ( name, mi. span ( ) , None ) ;
145142 continue ;
146143 }
147144
148- if ALL_EDITIONS . iter ( ) . any ( |e| name == e. feature_name ( ) ) {
149- // Handled in the separate loop above.
150- continue ;
151- }
152-
153- let removed = REMOVED_FEATURES . iter ( ) . find ( |f| name == f. name ) ;
154- let stable_removed = STABLE_REMOVED_FEATURES . iter ( ) . find ( |f| name == f. name ) ;
155- if let Some ( Feature { state, .. } ) = removed. or ( stable_removed) {
156- if let FeatureState :: Removed { reason } | FeatureState :: Stabilized { reason } =
157- state
158- {
159- feature_removed ( sess, mi. span ( ) , * reason) ;
145+ // If the declared feature has been removed, issue an error.
146+ if let Some ( Feature { state, .. } ) = REMOVED_FEATURES . iter ( ) . find ( |f| name == f. name ) {
147+ if let FeatureState :: Removed { reason } = state {
148+ sess. emit_err ( FeatureRemoved {
149+ span : mi. span ( ) ,
150+ reason : reason. map ( |reason| FeatureRemovedReason { reason } ) ,
151+ } ) ;
160152 continue ;
161153 }
162154 }
163155
156+ // If the declared feature is stable, record it.
164157 if let Some ( Feature { since, .. } ) = ACCEPTED_FEATURES . iter ( ) . find ( |f| name == f. name ) {
165158 let since = Some ( Symbol :: intern ( since) ) ;
166- features. declared_lang_features . push ( ( name, mi. span ( ) , since) ) ;
167- features. active_features . insert ( name) ;
159+ features. set_declared_lang_feature ( name, mi. span ( ) , since) ;
168160 continue ;
169161 }
170162
163+ // If `-Z allow-features` is used and the declared feature is
164+ // unstable and not also listed as one of the allowed features,
165+ // issue an error.
171166 if let Some ( allowed) = sess. opts . unstable_opts . allow_features . as_ref ( ) {
172167 if allowed. iter ( ) . all ( |f| name. as_str ( ) != f) {
173168 sess. emit_err ( FeatureNotAllowed { span : mi. span ( ) , name } ) ;
174169 continue ;
175170 }
176171 }
177172
173+ // If the declared feature is unstable, record it.
178174 if let Some ( f) = ACTIVE_FEATURES . iter ( ) . find ( |f| name == f. name ) {
179- f. set ( & mut features, mi. span ( ) ) ;
180- features. declared_lang_features . push ( ( name, mi. span ( ) , None ) ) ;
181- features. active_features . insert ( name) ;
175+ f. set ( & mut features) ;
176+ features. set_declared_lang_feature ( name, mi. span ( ) , None ) ;
182177 continue ;
183178 }
184179
185- features. declared_lib_features . push ( ( name, mi. span ( ) ) ) ;
186- features. active_features . insert ( name) ;
180+ // Otherwise, the feature is unknown. Record it as a lib feature.
181+ // It will be checked later.
182+ features. set_declared_lib_feature ( name, mi. span ( ) ) ;
187183 }
188184 }
189185
0 commit comments