1
1
//! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
2
2
3
- use rustc_errors:: struct_span_err;
3
+ use rustc_errors:: { struct_span_err, Applicability } ;
4
4
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
5
5
use rustc_hir:: { self as hir, HirId , LangItem } ;
6
6
use rustc_infer:: infer:: TyCtxtInferExt ;
@@ -11,13 +11,13 @@ use rustc_middle::ty::subst::GenericArgKind;
11
11
use rustc_middle:: ty:: {
12
12
self , adjustment:: PointerCast , Instance , InstanceDef , Ty , TyCtxt , TypeAndMut ,
13
13
} ;
14
- use rustc_span:: { sym, Span } ;
14
+ use rustc_span:: { sym, Span , Symbol } ;
15
15
use rustc_trait_selection:: traits:: error_reporting:: InferCtxtExt ;
16
16
use rustc_trait_selection:: traits:: { self , TraitEngine } ;
17
17
18
18
use std:: ops:: Deref ;
19
19
20
- use super :: ops:: { self , NonConstOp } ;
20
+ use super :: ops:: { self , NonConstOp , Status } ;
21
21
use super :: qualifs:: { self , CustomEq , HasMutInterior , NeedsDrop } ;
22
22
use super :: resolver:: FlowSensitiveAnalysis ;
23
23
use super :: { is_lang_panic_fn, ConstCx , Qualif } ;
@@ -277,8 +277,33 @@ impl Validator<'mir, 'tcx> {
277
277
return ;
278
278
}
279
279
280
- let err_emitted = ops:: non_const ( self . ccx , op, span) ;
281
- if err_emitted && O :: STOPS_CONST_CHECKING {
280
+ let gate = match op. status_in_item ( self . ccx ) {
281
+ Status :: Allowed => return ,
282
+
283
+ Status :: Unstable ( gate) if self . tcx . features ( ) . enabled ( gate) => {
284
+ let unstable_in_stable = self . ccx . is_const_stable_const_fn ( )
285
+ && !super :: allow_internal_unstable ( self . tcx , self . def_id . to_def_id ( ) , gate) ;
286
+ if unstable_in_stable {
287
+ emit_unstable_in_stable_error ( self . ccx , span, gate) ;
288
+ }
289
+
290
+ return ;
291
+ }
292
+
293
+ Status :: Unstable ( gate) => Some ( gate) ,
294
+ Status :: Forbidden => None ,
295
+ } ;
296
+
297
+ if self . tcx . sess . opts . debugging_opts . unleash_the_miri_inside_of_you {
298
+ self . tcx . sess . miri_unleashed_feature ( span, gate) ;
299
+ return ;
300
+ }
301
+
302
+ let mut err = op. build_error ( self . ccx , span) ;
303
+ assert ! ( err. is_error( ) ) ;
304
+ err. emit ( ) ;
305
+
306
+ if O :: STOPS_CONST_CHECKING {
282
307
self . const_checking_stopped = true ;
283
308
}
284
309
}
@@ -892,3 +917,25 @@ fn is_async_fn(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
892
917
. fn_sig_by_hir_id ( hir_id)
893
918
. map_or ( false , |sig| sig. header . asyncness == hir:: IsAsync :: Async )
894
919
}
920
+
921
+ fn emit_unstable_in_stable_error ( ccx : & ConstCx < ' _ , ' _ > , span : Span , gate : Symbol ) {
922
+ ccx. tcx
923
+ . sess
924
+ . struct_span_err (
925
+ span,
926
+ & format ! ( "const-stable function cannot use `#[feature({})]`" , gate. as_str( ) ) ,
927
+ )
928
+ . span_suggestion (
929
+ ccx. body . span ,
930
+ "if it is not part of the public API, make this function unstably const" ,
931
+ concat ! ( r#"#[rustc_const_unstable(feature = "...", issue = "...")]"# , '\n' ) . to_owned ( ) ,
932
+ Applicability :: HasPlaceholders ,
933
+ )
934
+ . span_suggestion (
935
+ ccx. body . span ,
936
+ "otherwise `#[allow_internal_unstable]` can be used to bypass stability checks" ,
937
+ format ! ( "#[allow_internal_unstable({})]" , gate) ,
938
+ Applicability :: MaybeIncorrect ,
939
+ )
940
+ . emit ( ) ;
941
+ }
0 commit comments