@@ -13,11 +13,11 @@ use rustc::hir::map::Map;
1313use  rustc:: hir; 
1414use  rustc:: ty:: TyCtxt ; 
1515use  rustc:: ty:: query:: Providers ; 
16- use  rustc_feature :: Features ; 
16+ use  rustc :: session :: config :: nightly_options ; 
1717use  syntax:: ast:: Mutability ; 
1818use  syntax:: feature_gate:: feature_err; 
1919use  syntax:: span_err; 
20- use  syntax_pos:: { sym,  Span } ; 
20+ use  syntax_pos:: { sym,  Span ,   Symbol } ; 
2121use  rustc_error_codes:: * ; 
2222
2323use  std:: fmt; 
@@ -37,18 +37,31 @@ impl NonConstExpr {
3737        } 
3838    } 
3939
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 ] >  { 
4341        use  hir:: MatchSource :: * ; 
44-         match  self  { 
42+         use  hir:: LoopSource :: * ; 
43+ 
44+         let  gates:  & [ _ ]  = match  self  { 
4545            | Self :: Match ( Normal ) 
4646            | Self :: Match ( IfDesugar  {  .. } ) 
4747            | Self :: Match ( IfLetDesugar  {  .. } ) 
48-             => Some ( features . const_if_match ) , 
48+             => & [ sym :: const_if_match] , 
4949
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) 
5265    } 
5366} 
5467
@@ -120,11 +133,15 @@ impl<'tcx> CheckConstVisitor<'tcx> {
120133
121134    /// Emits an error when an unsupported expression is found in a const context. 
122135fn  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 { 
124139            // 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 , 
126141
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. 
128145            None  if  self . tcx . sess . opts . debugging_opts . unleash_the_miri_inside_of_you  => { 
129146                self . tcx . sess . span_warn ( span,  "skipping const checks" ) ; 
130147                return ; 
@@ -135,15 +152,47 @@ impl<'tcx> CheckConstVisitor<'tcx> {
135152
136153        let  const_kind = self . const_kind 
137154            . expect ( "`const_check_violated` may only be called inside a const context" ) ; 
138- 
139155        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 ( ) , 
145156
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+ ) 
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+             } 
147196        } 
148197    } 
149198
0 commit comments