@@ -10,33 +10,34 @@ use rustc_span::{Span, Symbol};
1010
1111use super :: ConstCx ;
1212
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 {
1515 debug ! ( "illegal_op: op={:?}" , op) ;
1616
1717 let gate = match op. status_in_item ( ccx) {
18- Status :: Allowed => return ,
18+ Status :: Allowed => return false ,
1919
2020 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 ( )
2422 && !super :: allow_internal_unstable ( ccx. tcx , ccx. def_id . to_def_id ( ) , gate) ;
2523
2624 if unstable_in_stable {
2725 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+ )
2930 . span_suggestion (
3031 ccx. body . span ,
3132 "if it is not part of the public API, make this function unstably const" ,
3233 concat ! ( r#"#[rustc_const_unstable(feature = "...", issue = "...")]"# , '\n' ) . to_owned ( ) ,
3334 Applicability :: HasPlaceholders ,
3435 )
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" )
3637 . emit ( ) ;
3738 }
3839
39- return ;
40+ return unstable_in_stable ;
4041 }
4142
4243 Status :: Unstable ( gate) => Some ( gate) ,
@@ -45,12 +46,14 @@ pub fn non_const<O: NonConstOp>(ccx: &ConstCx<'_, '_>, op: O, span: Span) {
4546
4647 if ccx. tcx . sess . opts . debugging_opts . unleash_the_miri_inside_of_you {
4748 ccx. tcx . sess . miri_unleashed_feature ( span, gate) ;
48- return ;
49+ return false ;
4950 }
5051
5152 op. emit_error ( ccx, span) ;
53+ true
5254}
5355
56+ #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
5457pub enum Status {
5558 Allowed ,
5659 Unstable ( Symbol ) ,
@@ -59,6 +62,8 @@ pub enum Status {
5962
6063/// An operation that is not *always* allowed in a const context.
6164pub trait NonConstOp : std:: fmt:: Debug {
65+ const STOPS_CONST_CHECKING : bool = false ;
66+
6267 /// Returns an enum indicating whether this operation is allowed within the given item.
6368 fn status_in_item ( & self , _ccx : & ConstCx < ' _ , ' _ > ) -> Status {
6469 Status :: Forbidden
@@ -93,6 +98,34 @@ pub trait NonConstOp: std::fmt::Debug {
9398 }
9499}
95100
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+
96129/// A function call where the callee is a pointer.
97130#[ derive( Debug ) ]
98131pub struct FnCallIndirect ;
@@ -125,7 +158,8 @@ impl NonConstOp for FnCallNonConst {
125158///
126159/// Contains the name of the feature that would allow the use of this function.
127160#[ derive( Debug ) ]
128- pub struct FnCallUnstable ( pub DefId , pub Symbol ) ;
161+ pub struct FnCallUnstable ( pub DefId , pub Option < Symbol > ) ;
162+
129163impl NonConstOp for FnCallUnstable {
130164 fn emit_error ( & self , ccx : & ConstCx < ' _ , ' _ > , span : Span ) {
131165 let FnCallUnstable ( def_id, feature) = * self ;
@@ -134,13 +168,51 @@ impl NonConstOp for FnCallUnstable {
134168 span,
135169 & format ! ( "`{}` is not yet stable as a const fn" , ccx. tcx. def_path_str( def_id) ) ,
136170 ) ;
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+ }
139181 }
140182 err. emit ( ) ;
141183 }
142184}
143185
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+
144216#[ derive( Debug ) ]
145217pub struct HeapAllocation ;
146218impl NonConstOp for HeapAllocation {
@@ -403,6 +475,24 @@ impl NonConstOp for ThreadLocalAccess {
403475 }
404476}
405477
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+
406496#[ derive( Debug ) ]
407497pub struct UnionAccess ;
408498impl NonConstOp for UnionAccess {
@@ -425,3 +515,131 @@ impl NonConstOp for UnionAccess {
425515 . emit ( ) ;
426516 }
427517}
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