@@ -14,12 +14,43 @@ use rustc::hir;
1414use rustc:: ty:: TyCtxt ;
1515use rustc:: ty:: query:: Providers ;
1616use syntax:: ast:: Mutability ;
17+ use syntax:: feature_gate:: { emit_feature_err, Features , GateIssue } ;
1718use syntax:: span_err;
18- use syntax_pos:: Span ;
19+ use syntax_pos:: { sym , Span } ;
1920use rustc_error_codes:: * ;
2021
2122use std:: fmt;
2223
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+
2354#[ derive( Copy , Clone ) ]
2455enum ConstKind {
2556 Static ,
@@ -87,16 +118,38 @@ impl<'tcx> CheckConstVisitor<'tcx> {
87118 }
88119
89120 /// 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+ _ => { }
94133 }
95134
96135 let const_kind = self . const_kind
97136 . expect ( "`const_check_violated` may only be called inside a const context" ) ;
98137
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+ }
100153 }
101154
102155 /// Saves the parent `const_kind` before calling `f` and restores it afterwards.
@@ -129,24 +182,22 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
129182 _ if self . const_kind . is_none ( ) => { }
130183
131184 hir:: ExprKind :: Loop ( _, _, source) => {
132- self . const_check_violated ( source . name ( ) , e. span ) ;
185+ self . const_check_violated ( NonConstExpr :: Loop ( * source ) , e. span ) ;
133186 }
134187
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 {
144190 // 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) ) ,
146197 } ;
147198
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 ) ;
150201 }
151202 }
152203
0 commit comments