@@ -14,12 +14,43 @@ use rustc::hir;
14
14
use rustc:: ty:: TyCtxt ;
15
15
use rustc:: ty:: query:: Providers ;
16
16
use syntax:: ast:: Mutability ;
17
+ use syntax:: feature_gate:: { emit_feature_err, Features , GateIssue } ;
17
18
use syntax:: span_err;
18
- use syntax_pos:: Span ;
19
+ use syntax_pos:: { sym , Span } ;
19
20
use rustc_error_codes:: * ;
20
21
21
22
use std:: fmt;
22
23
24
+ /// An expression that is not *always* legal in a const context.
25
+ #[ derive( Clone , Copy ) ]
26
+ enum NonConstExpr {
27
+ Loop ( hir:: LoopSource ) ,
28
+ Match ( hir:: MatchSource ) ,
29
+ }
30
+
31
+ impl NonConstExpr {
32
+ fn name ( self ) -> & ' static str {
33
+ match self {
34
+ Self :: Loop ( src) => src. name ( ) ,
35
+ Self :: Match ( src) => src. name ( ) ,
36
+ }
37
+ }
38
+
39
+ /// Returns `true` if all feature gates required to enable this expression are turned on, or
40
+ /// `None` if there is no feature gate corresponding to this expression.
41
+ fn is_feature_gate_enabled ( self , features : & Features ) -> Option < bool > {
42
+ use hir:: MatchSource :: * ;
43
+ match self {
44
+ | Self :: Match ( Normal )
45
+ | Self :: Match ( IfDesugar { .. } )
46
+ | Self :: Match ( IfLetDesugar { .. } )
47
+ => Some ( features. const_if_match ) ,
48
+
49
+ _ => None ,
50
+ }
51
+ }
52
+ }
53
+
23
54
#[ derive( Copy , Clone ) ]
24
55
enum ConstKind {
25
56
Static ,
@@ -87,16 +118,38 @@ impl<'tcx> CheckConstVisitor<'tcx> {
87
118
}
88
119
89
120
/// Emits an error when an unsupported expression is found in a const context.
90
- fn const_check_violated ( & self , bad_op : & str , span : Span ) {
91
- if self . tcx . sess . opts . debugging_opts . unleash_the_miri_inside_of_you {
92
- self . tcx . sess . span_warn ( span, "skipping const checks" ) ;
93
- return ;
121
+ fn const_check_violated ( & self , expr : NonConstExpr , span : Span ) {
122
+ match expr. is_feature_gate_enabled ( self . tcx . features ( ) ) {
123
+ // Don't emit an error if the user has enabled the requisite feature gates.
124
+ Some ( true ) => return ,
125
+
126
+ // Users of `-Zunleash-the-miri-inside-of-you` must use feature gates when possible.
127
+ None if self . tcx . sess . opts . debugging_opts . unleash_the_miri_inside_of_you => {
128
+ self . tcx . sess . span_warn ( span, "skipping const checks" ) ;
129
+ return ;
130
+ }
131
+
132
+ _ => { }
94
133
}
95
134
96
135
let const_kind = self . const_kind
97
136
. expect ( "`const_check_violated` may only be called inside a const context" ) ;
98
137
99
- span_err ! ( self . tcx. sess, span, E0744 , "`{}` is not allowed in a `{}`" , bad_op, const_kind) ;
138
+ let msg = format ! ( "`{}` is not allowed in a `{}`" , expr. name( ) , const_kind) ;
139
+ match expr {
140
+ | NonConstExpr :: Match ( hir:: MatchSource :: Normal )
141
+ | NonConstExpr :: Match ( hir:: MatchSource :: IfDesugar { .. } )
142
+ | NonConstExpr :: Match ( hir:: MatchSource :: IfLetDesugar { .. } )
143
+ => emit_feature_err (
144
+ & self . tcx . sess . parse_sess ,
145
+ sym:: const_if_match,
146
+ span,
147
+ GateIssue :: Language ,
148
+ & msg
149
+ ) ,
150
+
151
+ _ => span_err ! ( self . tcx. sess, span, E0744 , "{}" , msg) ,
152
+ }
100
153
}
101
154
102
155
/// Saves the parent `const_kind` before calling `f` and restores it afterwards.
@@ -129,24 +182,22 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
129
182
_ if self . const_kind . is_none ( ) => { }
130
183
131
184
hir:: ExprKind :: Loop ( _, _, source) => {
132
- self . const_check_violated ( source . name ( ) , e. span ) ;
185
+ self . const_check_violated ( NonConstExpr :: Loop ( * source ) , e. span ) ;
133
186
}
134
187
135
- hir:: ExprKind :: Match ( _, _, source) if !self . tcx . features ( ) . const_if_match => {
136
- use hir:: MatchSource :: * ;
137
-
138
- let op = match source {
139
- Normal => Some ( "match" ) ,
140
- IfDesugar { .. } | IfLetDesugar { .. } => Some ( "if" ) ,
141
- TryDesugar => Some ( "?" ) ,
142
- AwaitDesugar => Some ( ".await" ) ,
143
-
188
+ hir:: ExprKind :: Match ( _, _, source) => {
189
+ let non_const_expr = match source {
144
190
// These are handled by `ExprKind::Loop` above.
145
- WhileDesugar | WhileLetDesugar | ForLoopDesugar => None ,
191
+ | hir:: MatchSource :: WhileDesugar
192
+ | hir:: MatchSource :: WhileLetDesugar
193
+ | hir:: MatchSource :: ForLoopDesugar
194
+ => None ,
195
+
196
+ _ => Some ( NonConstExpr :: Match ( * source) ) ,
146
197
} ;
147
198
148
- if let Some ( op ) = op {
149
- self . const_check_violated ( op , e. span ) ;
199
+ if let Some ( expr ) = non_const_expr {
200
+ self . const_check_violated ( expr , e. span ) ;
150
201
}
151
202
}
152
203
0 commit comments