1
1
//! Concrete error types for all operations which may be invalid in a certain const context.
2
2
3
- use rustc_errors:: struct_span_err;
3
+ use rustc_errors:: { struct_span_err, Applicability } ;
4
4
use rustc_hir as hir;
5
5
use rustc_hir:: def_id:: DefId ;
6
6
use rustc_session:: config:: nightly_options;
@@ -14,35 +14,54 @@ use super::ConstCx;
14
14
pub fn non_const < O : NonConstOp > ( ccx : & ConstCx < ' _ , ' _ > , op : O , span : Span ) {
15
15
debug ! ( "illegal_op: op={:?}" , op) ;
16
16
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
+ } ;
20
45
21
46
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 ) ;
23
48
return ;
24
49
}
25
50
26
51
op. emit_error ( ccx, span) ;
27
52
}
28
53
54
+ pub enum Status {
55
+ Allowed ,
56
+ Unstable ( Symbol ) ,
57
+ Forbidden ,
58
+ }
59
+
29
60
/// An operation that is not *always* allowed in a const context.
30
61
pub 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
46
65
}
47
66
48
67
fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -53,9 +72,13 @@ pub trait NonConstOp: std::fmt::Debug {
53
72
"{} contains unimplemented expression type" ,
54
73
ccx. const_kind( )
55
74
) ;
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
+ }
58
80
}
81
+
59
82
if ccx. tcx . sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
60
83
err. note (
61
84
"A function call isn't allowed in the const's initialization expression \
@@ -147,7 +170,9 @@ pub struct InlineAsm;
147
170
impl NonConstOp for InlineAsm { }
148
171
149
172
#[ derive( Debug ) ]
150
- pub struct LiveDrop ( pub Option < Span > ) ;
173
+ pub struct LiveDrop {
174
+ pub dropped_at : Option < Span > ,
175
+ }
151
176
impl NonConstOp for LiveDrop {
152
177
fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
153
178
let mut diagnostic = struct_span_err ! (
@@ -157,7 +182,7 @@ impl NonConstOp for LiveDrop {
157
182
"destructors cannot be evaluated at compile-time"
158
183
) ;
159
184
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 {
161
186
diagnostic. span_label ( span, "value is dropped here" ) ;
162
187
}
163
188
diagnostic. emit ( ) ;
@@ -182,14 +207,13 @@ impl NonConstOp for CellBorrow {
182
207
#[ derive( Debug ) ]
183
208
pub struct MutBorrow ;
184
209
impl 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
+ }
193
217
}
194
218
195
219
fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -201,15 +225,16 @@ impl NonConstOp for MutBorrow {
201
225
& format ! ( "mutable references are not allowed in {}s" , ccx. const_kind( ) ) ,
202
226
)
203
227
} else {
204
- struct_span_err ! (
228
+ let mut err = struct_span_err ! (
205
229
ccx. tcx. sess,
206
230
span,
207
231
E0764 ,
208
232
"mutable references are not allowed in {}s" ,
209
233
ccx. const_kind( ) ,
210
- )
234
+ ) ;
235
+ err. span_label ( span, format ! ( "`&mut` is only allowed in `const fn`" ) ) ;
236
+ err
211
237
} ;
212
- err. span_label ( span, "`&mut` is only allowed in `const fn`" . to_string ( ) ) ;
213
238
if ccx. tcx . sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
214
239
err. note (
215
240
"References in statics and constants may only refer \
@@ -226,11 +251,17 @@ impl NonConstOp for MutBorrow {
226
251
}
227
252
}
228
253
254
+ // FIXME(ecstaticmorse): Unify this with `MutBorrow`. It has basically the same issues.
229
255
#[ derive( Debug ) ]
230
256
pub struct MutAddressOf ;
231
257
impl 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
+ }
234
265
}
235
266
236
267
fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -247,16 +278,16 @@ impl NonConstOp for MutAddressOf {
247
278
#[ derive( Debug ) ]
248
279
pub struct MutDeref ;
249
280
impl 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)
252
283
}
253
284
}
254
285
255
286
#[ derive( Debug ) ]
256
287
pub struct Panic ;
257
288
impl 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)
260
291
}
261
292
262
293
fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -289,8 +320,8 @@ impl NonConstOp for RawPtrComparison {
289
320
#[ derive( Debug ) ]
290
321
pub struct RawPtrDeref ;
291
322
impl 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)
294
325
}
295
326
296
327
fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -307,8 +338,8 @@ impl NonConstOp for RawPtrDeref {
307
338
#[ derive( Debug ) ]
308
339
pub struct RawPtrToIntCast ;
309
340
impl 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)
312
343
}
313
344
314
345
fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -326,8 +357,12 @@ impl NonConstOp for RawPtrToIntCast {
326
357
#[ derive( Debug ) ]
327
358
pub struct StaticAccess ;
328
359
impl 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
+ }
331
366
}
332
367
333
368
fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
@@ -371,14 +406,13 @@ impl NonConstOp for ThreadLocalAccess {
371
406
#[ derive( Debug ) ]
372
407
pub struct UnionAccess ;
373
408
impl NonConstOp for UnionAccess {
374
- fn is_allowed_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> bool {
409
+ fn status_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> Status {
375
410
// 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
+ }
382
416
}
383
417
384
418
fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
0 commit comments