11//! Concrete error types for all operations which may be invalid in a certain const context.
22
3- use rustc_errors:: struct_span_err;
3+ use rustc_errors:: { struct_span_err, Applicability } ;
44use rustc_hir as hir;
55use rustc_hir:: def_id:: DefId ;
66use rustc_session:: config:: nightly_options;
@@ -14,35 +14,54 @@ 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+
20+ Status :: Unstable ( gate) if ccx. tcx . features ( ) . enabled ( gate) => {
21+ let unstable_in_stable = ccx. const_kind ( ) == hir:: ConstContext :: ConstFn
22+ && ccx. tcx . features ( ) . enabled ( sym:: staged_api)
23+ && !ccx. tcx . has_attr ( ccx. def_id . to_def_id ( ) , sym:: rustc_const_unstable)
24+ && !super :: allow_internal_unstable ( ccx. tcx , ccx. def_id . to_def_id ( ) , gate) ;
25+
26+ if unstable_in_stable {
27+ ccx. tcx . sess
28+ . struct_span_err ( span, & format ! ( "`#[feature({})]` cannot be depended on in a const-stable function" , gate. as_str( ) ) )
29+ . span_suggestion (
30+ ccx. body . span ,
31+ "if it is not part of the public API, make this function unstably const" ,
32+ concat ! ( r#"#[rustc_const_unstable(feature = "...", issue = "...")]"# , '\n' ) . to_owned ( ) ,
33+ Applicability :: HasPlaceholders ,
34+ )
35+ . help ( "otherwise `#[allow_internal_unstable]` can be used to bypass stability checks" )
36+ . emit ( ) ;
37+ }
38+
39+ return ;
40+ }
41+
42+ Status :: Unstable ( gate) => Some ( gate) ,
43+ Status :: Forbidden => None ,
44+ } ;
2045
2146 if ccx. tcx . sess . opts . debugging_opts . unleash_the_miri_inside_of_you {
22- ccx. tcx . sess . miri_unleashed_feature ( span, O :: feature_gate ( ) ) ;
47+ ccx. tcx . sess . miri_unleashed_feature ( span, gate ) ;
2348 return ;
2449 }
2550
2651 op. emit_error ( ccx, span) ;
2752}
2853
54+ pub enum Status {
55+ Allowed ,
56+ Unstable ( Symbol ) ,
57+ Forbidden ,
58+ }
59+
2960/// An operation that is not *always* allowed in a const context.
3061pub 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) )
62+ /// Returns an enum indicating whether this operation is allowed within the given item.
63+ fn status_in_item ( & self , _ccx : & ConstCx < ' _ , ' _ > ) -> Status {
64+ Status :: Forbidden
4665 }
4766
4867 fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -53,9 +72,13 @@ pub trait NonConstOp: std::fmt::Debug {
5372 "{} contains unimplemented expression type" ,
5473 ccx. const_kind( )
5574 ) ;
56- if let Some ( feat) = Self :: feature_gate ( ) {
57- err. help ( & format ! ( "add `#![feature({})]` to the crate attributes to enable" , feat) ) ;
75+
76+ if let Status :: Unstable ( gate) = self . status_in_item ( ccx) {
77+ if !ccx. tcx . features ( ) . enabled ( gate) && nightly_options:: is_nightly_build ( ) {
78+ err. help ( & format ! ( "add `#![feature({})]` to the crate attributes to enable" , gate) ) ;
79+ }
5880 }
81+
5982 if ccx. tcx . sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
6083 err. note (
6184 "A function call isn't allowed in the const's initialization expression \
@@ -147,7 +170,9 @@ pub struct InlineAsm;
147170impl NonConstOp for InlineAsm { }
148171
149172#[ derive( Debug ) ]
150- pub struct LiveDrop ( pub Option < Span > ) ;
173+ pub struct LiveDrop {
174+ pub dropped_at : Option < Span > ,
175+ }
151176impl NonConstOp for LiveDrop {
152177 fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
153178 let mut diagnostic = struct_span_err ! (
@@ -157,7 +182,7 @@ impl NonConstOp for LiveDrop {
157182 "destructors cannot be evaluated at compile-time"
158183 ) ;
159184 diagnostic. span_label ( span, format ! ( "{}s cannot evaluate destructors" , ccx. const_kind( ) ) ) ;
160- if let Some ( span) = self . 0 {
185+ if let Some ( span) = self . dropped_at {
161186 diagnostic. span_label ( span, "value is dropped here" ) ;
162187 }
163188 diagnostic. emit ( ) ;
@@ -182,14 +207,13 @@ impl NonConstOp for CellBorrow {
182207#[ derive( Debug ) ]
183208pub struct MutBorrow ;
184209impl 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)
210+ fn status_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> Status {
211+ // Forbid everywhere except in const fn with a feature gate
212+ if ccx. const_kind ( ) == hir:: ConstContext :: ConstFn {
213+ Status :: Unstable ( sym:: const_mut_refs)
214+ } else {
215+ Status :: Forbidden
216+ }
193217 }
194218
195219 fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -201,15 +225,16 @@ impl NonConstOp for MutBorrow {
201225 & format ! ( "mutable references are not allowed in {}s" , ccx. const_kind( ) ) ,
202226 )
203227 } else {
204- struct_span_err ! (
228+ let mut err = struct_span_err ! (
205229 ccx. tcx. sess,
206230 span,
207231 E0764 ,
208232 "mutable references are not allowed in {}s" ,
209233 ccx. const_kind( ) ,
210- )
234+ ) ;
235+ err. span_label ( span, format ! ( "`&mut` is only allowed in `const fn`" ) ) ;
236+ err
211237 } ;
212- err. span_label ( span, "`&mut` is only allowed in `const fn`" . to_string ( ) ) ;
213238 if ccx. tcx . sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
214239 err. note (
215240 "References in statics and constants may only refer \
@@ -226,11 +251,17 @@ impl NonConstOp for MutBorrow {
226251 }
227252}
228253
254+ // FIXME(ecstaticmorse): Unify this with `MutBorrow`. It has basically the same issues.
229255#[ derive( Debug ) ]
230256pub struct MutAddressOf ;
231257impl NonConstOp for MutAddressOf {
232- fn feature_gate ( ) -> Option < Symbol > {
233- Some ( sym:: const_mut_refs)
258+ fn status_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> Status {
259+ // Forbid everywhere except in const fn with a feature gate
260+ if ccx. const_kind ( ) == hir:: ConstContext :: ConstFn {
261+ Status :: Unstable ( sym:: const_mut_refs)
262+ } else {
263+ Status :: Forbidden
264+ }
234265 }
235266
236267 fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -247,16 +278,16 @@ impl NonConstOp for MutAddressOf {
247278#[ derive( Debug ) ]
248279pub struct MutDeref ;
249280impl NonConstOp for MutDeref {
250- fn feature_gate ( ) -> Option < Symbol > {
251- Some ( sym:: const_mut_refs)
281+ fn status_in_item ( & self , _ : & ConstCx < ' _ , ' _ > ) -> Status {
282+ Status :: Unstable ( sym:: const_mut_refs)
252283 }
253284}
254285
255286#[ derive( Debug ) ]
256287pub struct Panic ;
257288impl NonConstOp for Panic {
258- fn feature_gate ( ) -> Option < Symbol > {
259- Some ( sym:: const_panic)
289+ fn status_in_item ( & self , _ : & ConstCx < ' _ , ' _ > ) -> Status {
290+ Status :: Unstable ( sym:: const_panic)
260291 }
261292
262293 fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -289,8 +320,8 @@ impl NonConstOp for RawPtrComparison {
289320#[ derive( Debug ) ]
290321pub struct RawPtrDeref ;
291322impl NonConstOp for RawPtrDeref {
292- fn feature_gate ( ) -> Option < Symbol > {
293- Some ( sym:: const_raw_ptr_deref)
323+ fn status_in_item ( & self , _ : & ConstCx < ' _ , ' _ > ) -> Status {
324+ Status :: Unstable ( sym:: const_raw_ptr_deref)
294325 }
295326
296327 fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -307,8 +338,8 @@ impl NonConstOp for RawPtrDeref {
307338#[ derive( Debug ) ]
308339pub struct RawPtrToIntCast ;
309340impl NonConstOp for RawPtrToIntCast {
310- fn feature_gate ( ) -> Option < Symbol > {
311- Some ( sym:: const_raw_ptr_to_usize_cast)
341+ fn status_in_item ( & self , _ : & ConstCx < ' _ , ' _ > ) -> Status {
342+ Status :: Unstable ( sym:: const_raw_ptr_to_usize_cast)
312343 }
313344
314345 fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -326,8 +357,12 @@ impl NonConstOp for RawPtrToIntCast {
326357#[ derive( Debug ) ]
327358pub struct StaticAccess ;
328359impl NonConstOp for StaticAccess {
329- fn is_allowed_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> bool {
330- matches ! ( ccx. const_kind( ) , hir:: ConstContext :: Static ( _) )
360+ fn status_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> Status {
361+ if let hir:: ConstContext :: Static ( _) = ccx. const_kind ( ) {
362+ Status :: Allowed
363+ } else {
364+ Status :: Forbidden
365+ }
331366 }
332367
333368 fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -371,14 +406,13 @@ impl NonConstOp for ThreadLocalAccess {
371406#[ derive( Debug ) ]
372407pub struct UnionAccess ;
373408impl NonConstOp for UnionAccess {
374- fn is_allowed_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> bool {
409+ fn status_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> Status {
375410 // 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)
411+ if ccx. const_kind ( ) != hir:: ConstContext :: ConstFn {
412+ Status :: Allowed
413+ } else {
414+ Status :: Unstable ( sym:: const_fn_union)
415+ }
382416 }
383417
384418 fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
0 commit comments