@@ -14,35 +14,32 @@ use super::ConstCx;
1414pub fn non_const < O : NonConstOp > ( ccx : & ConstCx < ' _ , ' _ > , op : O , span : Span ) {
1515 debug ! ( "illegal_op: op={:?}" , op) ;
1616
17- if op. is_allowed_in_item ( ccx) {
18- return ;
19- }
17+ let gate = match op. status_in_item ( ccx) {
18+ Status :: Allowed => return ,
19+ Status :: Unstable ( gate) if ccx. tcx . features ( ) . enabled ( gate) => return ,
20+ Status :: Unstable ( gate) => Some ( gate) ,
21+ Status :: Forbidden => None ,
22+ } ;
2023
2124 if ccx. tcx . sess . opts . debugging_opts . unleash_the_miri_inside_of_you {
22- ccx. tcx . sess . miri_unleashed_feature ( span, O :: feature_gate ( ) ) ;
25+ ccx. tcx . sess . miri_unleashed_feature ( span, gate ) ;
2326 return ;
2427 }
2528
2629 op. emit_error ( ccx, span) ;
2730}
2831
32+ pub enum Status {
33+ Allowed ,
34+ Unstable ( Symbol ) ,
35+ Forbidden ,
36+ }
37+
2938/// An operation that is not *always* allowed in a const context.
3039pub trait NonConstOp : std:: fmt:: Debug {
31- /// Returns the `Symbol` corresponding to the feature gate that would enable this operation,
32- /// or `None` if such a feature gate does not exist.
33- fn feature_gate ( ) -> Option < Symbol > {
34- None
35- }
36-
37- /// Returns `true` if this operation is allowed in the given item.
38- ///
39- /// This check should assume that we are not in a non-const `fn`, where all operations are
40- /// legal.
41- ///
42- /// By default, it returns `true` if and only if this operation has a corresponding feature
43- /// gate and that gate is enabled.
44- fn is_allowed_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> bool {
45- Self :: feature_gate ( ) . map_or ( false , |gate| ccx. tcx . features ( ) . enabled ( gate) )
40+ /// Returns an enum indicating whether this operation is allowed within the given item.
41+ fn status_in_item ( & self , _ccx : & ConstCx < ' _ , ' _ > ) -> Status {
42+ Status :: Forbidden
4643 }
4744
4845 fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -53,9 +50,13 @@ pub trait NonConstOp: std::fmt::Debug {
5350 "{} contains unimplemented expression type" ,
5451 ccx. const_kind( )
5552 ) ;
56- if let Some ( feat) = Self :: feature_gate ( ) {
57- err. help ( & format ! ( "add `#![feature({})]` to the crate attributes to enable" , feat) ) ;
53+
54+ if let Status :: Unstable ( gate) = self . status_in_item ( ccx) {
55+ if !ccx. tcx . features ( ) . enabled ( gate) && nightly_options:: is_nightly_build ( ) {
56+ err. help ( & format ! ( "add `#![feature({})]` to the crate attributes to enable" , gate) ) ;
57+ }
5858 }
59+
5960 if ccx. tcx . sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
6061 err. note (
6162 "A function call isn't allowed in the const's initialization expression \
@@ -182,14 +183,13 @@ impl NonConstOp for CellBorrow {
182183#[ derive( Debug ) ]
183184pub struct MutBorrow ;
184185impl NonConstOp for MutBorrow {
185- fn is_allowed_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> bool {
186- // Forbid everywhere except in const fn
187- ccx. const_kind ( ) == hir:: ConstContext :: ConstFn
188- && ccx. tcx . features ( ) . enabled ( Self :: feature_gate ( ) . unwrap ( ) )
189- }
190-
191- fn feature_gate ( ) -> Option < Symbol > {
192- Some ( sym:: const_mut_refs)
186+ fn status_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> Status {
187+ // Forbid everywhere except in const fn with a feature gate
188+ if ccx. const_kind ( ) == hir:: ConstContext :: ConstFn {
189+ Status :: Unstable ( sym:: const_mut_refs)
190+ } else {
191+ Status :: Forbidden
192+ }
193193 }
194194
195195 fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -201,15 +201,16 @@ impl NonConstOp for MutBorrow {
201201 & format ! ( "mutable references are not allowed in {}s" , ccx. const_kind( ) ) ,
202202 )
203203 } else {
204- struct_span_err ! (
204+ let mut err = struct_span_err ! (
205205 ccx. tcx. sess,
206206 span,
207207 E0764 ,
208208 "mutable references are not allowed in {}s" ,
209209 ccx. const_kind( ) ,
210- )
210+ ) ;
211+ err. span_label ( span, format ! ( "`&mut` is only allowed in `const fn`" ) ) ;
212+ err
211213 } ;
212- err. span_label ( span, "`&mut` is only allowed in `const fn`" . to_string ( ) ) ;
213214 if ccx. tcx . sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
214215 err. note (
215216 "References in statics and constants may only refer \
@@ -226,11 +227,17 @@ impl NonConstOp for MutBorrow {
226227 }
227228}
228229
230+ // FIXME(ecstaticmorse): Unify this with `MutBorrow`. It has basically the same issues.
229231#[ derive( Debug ) ]
230232pub struct MutAddressOf ;
231233impl NonConstOp for MutAddressOf {
232- fn feature_gate ( ) -> Option < Symbol > {
233- Some ( sym:: const_mut_refs)
234+ fn status_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> Status {
235+ // Forbid everywhere except in const fn with a feature gate
236+ if ccx. const_kind ( ) == hir:: ConstContext :: ConstFn {
237+ Status :: Unstable ( sym:: const_mut_refs)
238+ } else {
239+ Status :: Forbidden
240+ }
234241 }
235242
236243 fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -247,16 +254,16 @@ impl NonConstOp for MutAddressOf {
247254#[ derive( Debug ) ]
248255pub struct MutDeref ;
249256impl NonConstOp for MutDeref {
250- fn feature_gate ( ) -> Option < Symbol > {
251- Some ( sym:: const_mut_refs)
257+ fn status_in_item ( & self , _ : & ConstCx < ' _ , ' _ > ) -> Status {
258+ Status :: Unstable ( sym:: const_mut_refs)
252259 }
253260}
254261
255262#[ derive( Debug ) ]
256263pub struct Panic ;
257264impl NonConstOp for Panic {
258- fn feature_gate ( ) -> Option < Symbol > {
259- Some ( sym:: const_panic)
265+ fn status_in_item ( & self , _ : & ConstCx < ' _ , ' _ > ) -> Status {
266+ Status :: Unstable ( sym:: const_panic)
260267 }
261268
262269 fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -289,8 +296,8 @@ impl NonConstOp for RawPtrComparison {
289296#[ derive( Debug ) ]
290297pub struct RawPtrDeref ;
291298impl NonConstOp for RawPtrDeref {
292- fn feature_gate ( ) -> Option < Symbol > {
293- Some ( sym:: const_raw_ptr_deref)
299+ fn status_in_item ( & self , _ : & ConstCx < ' _ , ' _ > ) -> Status {
300+ Status :: Unstable ( sym:: const_raw_ptr_deref)
294301 }
295302
296303 fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -307,8 +314,8 @@ impl NonConstOp for RawPtrDeref {
307314#[ derive( Debug ) ]
308315pub struct RawPtrToIntCast ;
309316impl NonConstOp for RawPtrToIntCast {
310- fn feature_gate ( ) -> Option < Symbol > {
311- Some ( sym:: const_raw_ptr_to_usize_cast)
317+ fn status_in_item ( & self , _ : & ConstCx < ' _ , ' _ > ) -> Status {
318+ Status :: Unstable ( sym:: const_raw_ptr_to_usize_cast)
312319 }
313320
314321 fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -326,8 +333,12 @@ impl NonConstOp for RawPtrToIntCast {
326333#[ derive( Debug ) ]
327334pub struct StaticAccess ;
328335impl NonConstOp for StaticAccess {
329- fn is_allowed_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> bool {
330- matches ! ( ccx. const_kind( ) , hir:: ConstContext :: Static ( _) )
336+ fn status_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> Status {
337+ if let hir:: ConstContext :: Static ( _) = ccx. const_kind ( ) {
338+ Status :: Allowed
339+ } else {
340+ Status :: Forbidden
341+ }
331342 }
332343
333344 fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -371,14 +382,13 @@ impl NonConstOp for ThreadLocalAccess {
371382#[ derive( Debug ) ]
372383pub struct UnionAccess ;
373384impl NonConstOp for UnionAccess {
374- fn is_allowed_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> bool {
385+ fn status_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> Status {
375386 // Union accesses are stable in all contexts except `const fn`.
376- ccx. const_kind ( ) != hir:: ConstContext :: ConstFn
377- || ccx. tcx . features ( ) . enabled ( Self :: feature_gate ( ) . unwrap ( ) )
378- }
379-
380- fn feature_gate ( ) -> Option < Symbol > {
381- Some ( sym:: const_fn_union)
387+ if ccx. const_kind ( ) != hir:: ConstContext :: ConstFn {
388+ Status :: Allowed
389+ } else {
390+ Status :: Unstable ( sym:: const_fn_union)
391+ }
382392 }
383393
384394 fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
0 commit comments