@@ -10,33 +10,34 @@ use rustc_span::{Span, Symbol};
10
10
11
11
use super :: ConstCx ;
12
12
13
- /// Emits an error if `op` is not allowed in the given const context.
14
- pub fn non_const < O : NonConstOp > ( ccx : & ConstCx < ' _ , ' _ > , op : O , span : Span ) {
13
+ /// Emits an error and returns `true` if `op` is not allowed in the given const context.
14
+ pub fn non_const < O : NonConstOp > ( ccx : & ConstCx < ' _ , ' _ > , op : O , span : Span ) -> bool {
15
15
debug ! ( "illegal_op: op={:?}" , op) ;
16
16
17
17
let gate = match op. status_in_item ( ccx) {
18
- Status :: Allowed => return ,
18
+ Status :: Allowed => return false ,
19
19
20
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)
21
+ let unstable_in_stable = ccx. is_const_stable_const_fn ( )
24
22
&& !super :: allow_internal_unstable ( ccx. tcx , ccx. def_id . to_def_id ( ) , gate) ;
25
23
26
24
if unstable_in_stable {
27
25
ccx. tcx . sess
28
- . struct_span_err ( span, & format ! ( "`#[feature({})]` cannot be depended on in a const-stable function" , gate. as_str( ) ) )
26
+ . struct_span_err (
27
+ span,
28
+ & format ! ( "const-stable function cannot use `#[feature({})]`" , gate. as_str( ) ) ,
29
+ )
29
30
. span_suggestion (
30
31
ccx. body . span ,
31
32
"if it is not part of the public API, make this function unstably const" ,
32
33
concat ! ( r#"#[rustc_const_unstable(feature = "...", issue = "...")]"# , '\n' ) . to_owned ( ) ,
33
34
Applicability :: HasPlaceholders ,
34
35
)
35
- . help ( "otherwise `#[allow_internal_unstable]` can be used to bypass stability checks" )
36
+ . note ( "otherwise `#[allow_internal_unstable]` can be used to bypass stability checks" )
36
37
. emit ( ) ;
37
38
}
38
39
39
- return ;
40
+ return unstable_in_stable ;
40
41
}
41
42
42
43
Status :: Unstable ( gate) => Some ( gate) ,
@@ -45,12 +46,14 @@ pub fn non_const<O: NonConstOp>(ccx: &ConstCx<'_, '_>, op: O, span: Span) {
45
46
46
47
if ccx. tcx . sess . opts . debugging_opts . unleash_the_miri_inside_of_you {
47
48
ccx. tcx . sess . miri_unleashed_feature ( span, gate) ;
48
- return ;
49
+ return false ;
49
50
}
50
51
51
52
op. emit_error ( ccx, span) ;
53
+ true
52
54
}
53
55
56
+ #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
54
57
pub enum Status {
55
58
Allowed ,
56
59
Unstable ( Symbol ) ,
@@ -59,6 +62,8 @@ pub enum Status {
59
62
60
63
/// An operation that is not *always* allowed in a const context.
61
64
pub trait NonConstOp : std:: fmt:: Debug {
65
+ const STOPS_CONST_CHECKING : bool = false ;
66
+
62
67
/// Returns an enum indicating whether this operation is allowed within the given item.
63
68
fn status_in_item ( & self , _ccx : & ConstCx < ' _ , ' _ > ) -> Status {
64
69
Status :: Forbidden
@@ -93,6 +98,34 @@ pub trait NonConstOp: std::fmt::Debug {
93
98
}
94
99
}
95
100
101
+ #[ derive( Debug ) ]
102
+ pub struct Abort ;
103
+ impl NonConstOp for Abort {
104
+ const STOPS_CONST_CHECKING : bool = true ;
105
+
106
+ fn status_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> Status {
107
+ mcf_status_in_item ( ccx)
108
+ }
109
+
110
+ fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
111
+ mcf_emit_error ( ccx, span, "abort is not stable in const fn" )
112
+ }
113
+ }
114
+
115
+ #[ derive( Debug ) ]
116
+ pub struct NonPrimitiveOp ;
117
+ impl NonConstOp for NonPrimitiveOp {
118
+ const STOPS_CONST_CHECKING : bool = true ;
119
+
120
+ fn status_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> Status {
121
+ mcf_status_in_item ( ccx)
122
+ }
123
+
124
+ fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
125
+ mcf_emit_error ( ccx, span, "only int, `bool` and `char` operations are stable in const fn" )
126
+ }
127
+ }
128
+
96
129
/// A function call where the callee is a pointer.
97
130
#[ derive( Debug ) ]
98
131
pub struct FnCallIndirect ;
@@ -125,7 +158,8 @@ impl NonConstOp for FnCallNonConst {
125
158
///
126
159
/// Contains the name of the feature that would allow the use of this function.
127
160
#[ derive( Debug ) ]
128
- pub struct FnCallUnstable ( pub DefId , pub Symbol ) ;
161
+ pub struct FnCallUnstable ( pub DefId , pub Option < Symbol > ) ;
162
+
129
163
impl NonConstOp for FnCallUnstable {
130
164
fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
131
165
let FnCallUnstable ( def_id, feature) = * self ;
@@ -134,13 +168,51 @@ impl NonConstOp for FnCallUnstable {
134
168
span,
135
169
& format ! ( "`{}` is not yet stable as a const fn" , ccx. tcx. def_path_str( def_id) ) ,
136
170
) ;
137
- if nightly_options:: is_nightly_build ( ) {
138
- err. help ( & format ! ( "add `#![feature({})]` to the crate attributes to enable" , feature) ) ;
171
+
172
+ if ccx. is_const_stable_const_fn ( ) {
173
+ err. help ( "Const-stable functions can only call other const-stable functions" ) ;
174
+ } else if nightly_options:: is_nightly_build ( ) {
175
+ if let Some ( feature) = feature {
176
+ err. help ( & format ! (
177
+ "add `#![feature({})]` to the crate attributes to enable" ,
178
+ feature
179
+ ) ) ;
180
+ }
139
181
}
140
182
err. emit ( ) ;
141
183
}
142
184
}
143
185
186
+ #[ derive( Debug ) ]
187
+ pub struct FnPtrCast ;
188
+ impl NonConstOp for FnPtrCast {
189
+ const STOPS_CONST_CHECKING : bool = true ;
190
+
191
+ fn status_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> Status {
192
+ mcf_status_in_item ( ccx)
193
+ }
194
+
195
+ fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
196
+ mcf_emit_error ( ccx, span, "function pointer casts are not allowed in const fn" ) ;
197
+ }
198
+ }
199
+
200
+ #[ derive( Debug ) ]
201
+ pub struct Generator ;
202
+ impl NonConstOp for Generator {
203
+ const STOPS_CONST_CHECKING : bool = true ;
204
+
205
+ fn status_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> Status {
206
+ // FIXME: This means generator-only MIR is only forbidden in const fn. This is for
207
+ // compatibility with the old code. Such MIR should be forbidden everywhere.
208
+ mcf_status_in_item ( ccx)
209
+ }
210
+
211
+ fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
212
+ mcf_emit_error ( ccx, span, "const fn generators are unstable" ) ;
213
+ }
214
+ }
215
+
144
216
#[ derive( Debug ) ]
145
217
pub struct HeapAllocation ;
146
218
impl NonConstOp for HeapAllocation {
@@ -403,6 +475,24 @@ impl NonConstOp for ThreadLocalAccess {
403
475
}
404
476
}
405
477
478
+ #[ derive( Debug ) ]
479
+ pub struct Transmute ;
480
+ impl NonConstOp for Transmute {
481
+ const STOPS_CONST_CHECKING : bool = true ;
482
+
483
+ fn status_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> Status {
484
+ if ccx. const_kind ( ) != hir:: ConstContext :: ConstFn {
485
+ Status :: Allowed
486
+ } else {
487
+ Status :: Unstable ( sym:: const_fn_transmute)
488
+ }
489
+ }
490
+
491
+ fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
492
+ mcf_emit_error ( ccx, span, "can only call `transmute` from const items, not `const fn`" ) ;
493
+ }
494
+ }
495
+
406
496
#[ derive( Debug ) ]
407
497
pub struct UnionAccess ;
408
498
impl NonConstOp for UnionAccess {
@@ -425,3 +515,131 @@ impl NonConstOp for UnionAccess {
425
515
. emit ( ) ;
426
516
}
427
517
}
518
+
519
+ /// See [#64992].
520
+ ///
521
+ /// [#64992]: https://github.com/rust-lang/rust/issues/64992
522
+ #[ derive( Debug ) ]
523
+ pub struct UnsizingCast ;
524
+ impl NonConstOp for UnsizingCast {
525
+ fn status_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> Status {
526
+ mcf_status_in_item ( ccx)
527
+ }
528
+
529
+ fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
530
+ mcf_emit_error (
531
+ ccx,
532
+ span,
533
+ "unsizing casts to types besides slices are not allowed in const fn" ,
534
+ ) ;
535
+ }
536
+ }
537
+
538
+ pub mod ty {
539
+ use super :: * ;
540
+
541
+ #[ derive( Debug ) ]
542
+ pub struct MutRef ;
543
+ impl NonConstOp for MutRef {
544
+ const STOPS_CONST_CHECKING : bool = true ;
545
+
546
+ fn status_in_item ( & self , _ccx : & ConstCx < ' _ , ' _ > ) -> Status {
547
+ Status :: Unstable ( sym:: const_mut_refs)
548
+ }
549
+
550
+ fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
551
+ mcf_emit_error ( ccx, span, "mutable references in const fn are unstable" ) ;
552
+ }
553
+ }
554
+
555
+ #[ derive( Debug ) ]
556
+ pub struct FnPtr ;
557
+ impl NonConstOp for FnPtr {
558
+ const STOPS_CONST_CHECKING : bool = true ;
559
+
560
+ fn status_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> Status {
561
+ // FIXME: This attribute a hack to allow the specialization of the `futures` API. See
562
+ // #59739. We should have a proper feature gate for this.
563
+ if ccx. tcx . has_attr ( ccx. def_id . to_def_id ( ) , sym:: rustc_allow_const_fn_ptr) {
564
+ Status :: Allowed
565
+ } else {
566
+ mcf_status_in_item ( ccx)
567
+ }
568
+ }
569
+
570
+ fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
571
+ mcf_emit_error ( ccx, span, "function pointers in const fn are unstable" ) ;
572
+ }
573
+ }
574
+
575
+ #[ derive( Debug ) ]
576
+ pub struct ImplTrait ;
577
+ impl NonConstOp for ImplTrait {
578
+ const STOPS_CONST_CHECKING : bool = true ;
579
+
580
+ fn status_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> Status {
581
+ mcf_status_in_item ( ccx)
582
+ }
583
+
584
+ fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
585
+ mcf_emit_error ( ccx, span, "`impl Trait` in const fn is unstable" ) ;
586
+ }
587
+ }
588
+
589
+ #[ derive( Debug ) ]
590
+ pub struct TraitBound ;
591
+ impl NonConstOp for TraitBound {
592
+ const STOPS_CONST_CHECKING : bool = true ;
593
+
594
+ fn status_in_item ( & self , ccx : & ConstCx < ' _ , ' _ > ) -> Status {
595
+ mcf_status_in_item ( ccx)
596
+ }
597
+
598
+ fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
599
+ mcf_emit_error (
600
+ ccx,
601
+ span,
602
+ "trait bounds other than `Sized` on const fn parameters are unstable" ,
603
+ ) ;
604
+ }
605
+ }
606
+
607
+ /// A trait bound with the `?const Trait` opt-out
608
+ #[ derive( Debug ) ]
609
+ pub struct TraitBoundNotConst ;
610
+ impl NonConstOp for TraitBoundNotConst {
611
+ const STOPS_CONST_CHECKING : bool = true ;
612
+
613
+ fn status_in_item ( & self , _: & ConstCx < ' _ , ' _ > ) -> Status {
614
+ Status :: Unstable ( sym:: const_trait_bound_opt_out)
615
+ }
616
+
617
+ fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
618
+ feature_err (
619
+ & ccx. tcx . sess . parse_sess ,
620
+ sym:: const_trait_bound_opt_out,
621
+ span,
622
+ "`?const Trait` syntax is unstable" ,
623
+ )
624
+ . emit ( )
625
+ }
626
+ }
627
+ }
628
+
629
+ fn mcf_status_in_item ( ccx : & ConstCx < ' _ , ' _ > ) -> Status {
630
+ if ccx. const_kind ( ) != hir:: ConstContext :: ConstFn {
631
+ Status :: Allowed
632
+ } else {
633
+ Status :: Unstable ( sym:: const_fn)
634
+ }
635
+ }
636
+
637
+ fn mcf_emit_error ( ccx : & ConstCx < ' _ , ' _ > , span : Span , msg : & str ) {
638
+ struct_span_err ! ( ccx. tcx. sess, span, E0723 , "{}" , msg)
639
+ . note (
640
+ "see issue #57563 <https://github.com/rust-lang/rust/issues/57563> \
641
+ for more information",
642
+ )
643
+ . help ( "add `#![feature(const_fn)]` to the crate attributes to enable" )
644
+ . emit ( ) ;
645
+ }
0 commit comments