9
9
//! [#64197]: https://github.com/rust-lang/rust/issues/64197
10
10
11
11
use 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 } ;
17
22
use syntax:: ast:: { self , AttrItem , Attribute , MetaItem } ;
18
23
use syntax:: attr;
19
24
use syntax:: attr:: HasAttrs ;
20
- use syntax:: feature_gate:: { feature_err, get_features } ;
25
+ use syntax:: feature_gate:: feature_err;
21
26
use syntax:: mut_visit:: * ;
22
27
use syntax:: ptr:: P ;
23
28
use syntax:: sess:: ParseSess ;
@@ -31,6 +36,172 @@ pub struct StripUnconfigured<'a> {
31
36
pub features : Option < & ' a Features > ,
32
37
}
33
38
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
+
34
205
// `cfg_attr`-process the crate's attributes and compute the crate's features.
35
206
pub fn features (
36
207
mut krate : ast:: Crate ,
0 commit comments