@@ -13,11 +13,11 @@ use rustc::hir::map::Map;
13
13
use rustc:: hir;
14
14
use rustc:: ty:: TyCtxt ;
15
15
use rustc:: ty:: query:: Providers ;
16
- use rustc_feature :: Features ;
16
+ use rustc :: session :: config :: nightly_options ;
17
17
use syntax:: ast:: Mutability ;
18
18
use syntax:: feature_gate:: feature_err;
19
19
use syntax:: span_err;
20
- use syntax_pos:: { sym, Span } ;
20
+ use syntax_pos:: { sym, Span , Symbol } ;
21
21
use rustc_error_codes:: * ;
22
22
23
23
use std:: fmt;
@@ -37,18 +37,31 @@ impl NonConstExpr {
37
37
}
38
38
}
39
39
40
- /// Returns `true` if all feature gates required to enable this expression are turned on, or
41
- /// `None` if there is no feature gate corresponding to this expression.
42
- fn is_feature_gate_enabled ( self , features : & Features ) -> Option < bool > {
40
+ fn required_feature_gates ( self ) -> Option < & ' static [ Symbol ] > {
43
41
use hir:: MatchSource :: * ;
44
- match self {
42
+ use hir:: LoopSource :: * ;
43
+
44
+ let gates: & [ _ ] = match self {
45
45
| Self :: Match ( Normal )
46
46
| Self :: Match ( IfDesugar { .. } )
47
47
| Self :: Match ( IfLetDesugar { .. } )
48
- => Some ( features . const_if_match ) ,
48
+ => & [ sym :: const_if_match] ,
49
49
50
- _ => None ,
51
- }
50
+ | Self :: Loop ( Loop )
51
+ => & [ sym:: const_loop] ,
52
+
53
+ | Self :: Loop ( While )
54
+ | Self :: Loop ( WhileLet )
55
+ | Self :: Match ( WhileDesugar )
56
+ | Self :: Match ( WhileLetDesugar )
57
+ => & [ sym:: const_loop, sym:: const_if_match] ,
58
+
59
+ // A `for` loop's desugaring contains a call to `IntoIterator::into_iter`,
60
+ // so they are not yet allowed with `#![feature(const_loop)]`.
61
+ _ => return None ,
62
+ } ;
63
+
64
+ Some ( gates)
52
65
}
53
66
}
54
67
@@ -120,11 +133,15 @@ impl<'tcx> CheckConstVisitor<'tcx> {
120
133
121
134
/// Emits an error when an unsupported expression is found in a const context.
122
135
fn const_check_violated ( & self , expr : NonConstExpr , span : Span ) {
123
- match expr. is_feature_gate_enabled ( self . tcx . features ( ) ) {
136
+ let features = self . tcx . features ( ) ;
137
+ let required_gates = expr. required_feature_gates ( ) ;
138
+ match required_gates {
124
139
// Don't emit an error if the user has enabled the requisite feature gates.
125
- Some ( true ) => return ,
140
+ Some ( gates ) if gates . iter ( ) . all ( | & g| features . enabled ( g ) ) => return ,
126
141
127
- // Users of `-Zunleash-the-miri-inside-of-you` must use feature gates when possible.
142
+ // `-Zunleash-the-miri-inside-of-you` only works for expressions that don't have a
143
+ // corresponding feature gate. This encourages nightly users to use feature gates when
144
+ // possible.
128
145
None if self . tcx . sess . opts . debugging_opts . unleash_the_miri_inside_of_you => {
129
146
self . tcx . sess . span_warn ( span, "skipping const checks" ) ;
130
147
return ;
@@ -135,15 +152,47 @@ impl<'tcx> CheckConstVisitor<'tcx> {
135
152
136
153
let const_kind = self . const_kind
137
154
. expect ( "`const_check_violated` may only be called inside a const context" ) ;
138
-
139
155
let msg = format ! ( "`{}` is not allowed in a `{}`" , expr. name( ) , const_kind) ;
140
- match expr {
141
- | NonConstExpr :: Match ( hir:: MatchSource :: Normal )
142
- | NonConstExpr :: Match ( hir:: MatchSource :: IfDesugar { .. } )
143
- | NonConstExpr :: Match ( hir:: MatchSource :: IfLetDesugar { .. } )
144
- => feature_err ( & self . tcx . sess . parse_sess , sym:: const_if_match, span, & msg) . emit ( ) ,
145
156
146
- _ => span_err ! ( self . tcx. sess, span, E0744 , "{}" , msg) ,
157
+ let required_gates = required_gates. unwrap_or ( & [ ] ) ;
158
+ let missing_gates: Vec < _ > = required_gates
159
+ . iter ( )
160
+ . copied ( )
161
+ . filter ( |& g| !features. enabled ( g) )
162
+ . collect ( ) ;
163
+
164
+ match missing_gates. as_slice ( ) {
165
+ & [ ] => span_err ! ( self . tcx. sess, span, E0744 , "{}" , msg) ,
166
+
167
+ // If the user enabled `#![feature(const_loop)]` but not `#![feature(const_if_match)]`,
168
+ // explain why their `while` loop is being rejected.
169
+ & [ gate @ sym:: const_if_match] if required_gates. contains ( & sym:: const_loop) => {
170
+ feature_err ( & self . tcx . sess . parse_sess , gate, span, & msg)
171
+ . note ( "`#![feature(const_loop)]` alone is not sufficient, \
172
+ since this loop expression contains an implicit conditional")
173
+ . emit ( ) ;
174
+ }
175
+
176
+ & [ missing_primary, ref missing_secondary @ ..] => {
177
+ let mut err = feature_err ( & self . tcx . sess . parse_sess , missing_primary, span, & msg) ;
178
+
179
+ // If multiple feature gates would be required to enable this expression, include
180
+ // them as help messages. Don't emit a separate error for each missing feature gate.
181
+ //
182
+ // FIXME(ecstaticmorse): Maybe this could be incorporated into `feature_err`? This
183
+ // is a pretty narrow case, however.
184
+ if nightly_options:: is_nightly_build ( ) {
185
+ for gate in missing_secondary {
186
+ let note = format ! (
187
+ "add `#![feature({})]` to the crate attributes to enable" ,
188
+ gate,
189
+ ) ;
190
+ err. help ( & note) ;
191
+ }
192
+ }
193
+
194
+ err. emit ( ) ;
195
+ }
147
196
}
148
197
}
149
198
0 commit comments