11//! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
22
3- use rustc_errors:: struct_span_err;
3+ use rustc_errors:: { Applicability , struct_span_err} ;
44use rustc_hir:: { self as hir, LangItem } ;
55use rustc_hir:: { def_id:: DefId , HirId } ;
66use rustc_infer:: infer:: TyCtxtInferExt ;
@@ -11,13 +11,13 @@ use rustc_middle::ty::subst::GenericArgKind;
1111use rustc_middle:: ty:: {
1212 self , adjustment:: PointerCast , Instance , InstanceDef , Ty , TyCtxt , TypeAndMut ,
1313} ;
14- use rustc_span:: { sym, Span } ;
14+ use rustc_span:: { sym, Span , Symbol } ;
1515use rustc_trait_selection:: traits:: error_reporting:: InferCtxtExt ;
1616use rustc_trait_selection:: traits:: { self , TraitEngine } ;
1717
1818use std:: ops:: Deref ;
1919
20- use super :: ops:: { self , NonConstOp } ;
20+ use super :: ops:: { self , NonConstOp , Status } ;
2121use super :: qualifs:: { self , CustomEq , HasMutInterior , NeedsDrop } ;
2222use super :: resolver:: FlowSensitiveAnalysis ;
2323use super :: { is_lang_panic_fn, ConstCx , Qualif } ;
@@ -179,7 +179,12 @@ pub struct Validator<'mir, 'tcx> {
179179 /// The span of the current statement.
180180 span : Span ,
181181
182- const_checking_stopped : bool ,
182+ /// True if we shouldn't emit errors when we find them.
183+ ///
184+ /// This allows items to be speculatively const-checked.
185+ silence_errors : bool ,
186+
187+ passes_checks_without_unstable_features : bool ,
183188}
184189
185190impl Deref for Validator < ' mir , ' tcx > {
@@ -196,7 +201,8 @@ impl Validator<'mir, 'tcx> {
196201 span : ccx. body . span ,
197202 ccx,
198203 qualifs : Default :: default ( ) ,
199- const_checking_stopped : false ,
204+ passes_checks_without_unstable_features : true ,
205+ silence_errors : false ,
200206 }
201207 }
202208
@@ -266,15 +272,48 @@ impl Validator<'mir, 'tcx> {
266272 /// Emits an error at the given `span` if an expression cannot be evaluated in the current
267273 /// context.
268274 pub fn check_op_spanned < O : NonConstOp > ( & mut self , op : O , span : Span ) {
269- // HACK: This is for strict equivalence with the old `qualify_min_const_fn` pass, which
270- // only emitted one error per function. It should be removed and the test output updated.
271- if self . const_checking_stopped {
275+ debug ! ( "illegal_op: op={:?}" , op) ;
276+
277+ let ccx = self . ccx ;
278+
279+ let gate = match op. status_in_item ( ccx) {
280+ Status :: Allowed => return ,
281+ Status :: Unstable ( gate) => Some ( gate) ,
282+ Status :: Forbidden => None ,
283+ } ;
284+
285+ self . passes_checks_without_unstable_features = false ;
286+
287+ if self . silence_errors {
272288 return ;
273289 }
274290
275- let err_emitted = ops:: non_const ( self . ccx , op, span) ;
276- if err_emitted && O :: STOPS_CONST_CHECKING {
277- self . const_checking_stopped = true ;
291+ // Unless we are const-checking a const-stable function, return before emitting an error if
292+ // the user has enabled the requisite feature gate.
293+ if let Some ( gate) = gate {
294+ if ccx. tcx . features ( ) . enabled ( gate) {
295+ let unstable_in_stable = ccx. is_const_stable_const_fn ( )
296+ && !super :: allow_internal_unstable ( ccx. tcx , ccx. def_id . to_def_id ( ) , gate) ;
297+
298+ if unstable_in_stable {
299+ error_unstable_in_stable ( ccx, gate, span) ;
300+ }
301+
302+ return ;
303+ }
304+ }
305+
306+ if ccx. tcx . sess . opts . debugging_opts . unleash_the_miri_inside_of_you {
307+ ccx. tcx . sess . miri_unleashed_feature ( span, gate) ;
308+ return ;
309+ }
310+
311+ op. emit_error ( ccx, span) ;
312+
313+ // HACK: This is for strict equivalence with the old `qualify_min_const_fn` pass, which
314+ // only emitted one error per function. It should be removed and the test output updated.
315+ if O :: STOPS_CONST_CHECKING {
316+ self . silence_errors = true ;
278317 }
279318 }
280319
@@ -866,3 +905,20 @@ fn place_as_reborrow(
866905 }
867906 } )
868907}
908+
909+ fn error_unstable_in_stable ( ccx : & ConstCx < ' _ , ' _ > , gate : Symbol , span : Span ) {
910+ ccx. tcx
911+ . sess
912+ . struct_span_err (
913+ span,
914+ & format ! ( "const-stable function cannot use `#[feature({})]`" , gate. as_str( ) ) ,
915+ )
916+ . span_suggestion (
917+ ccx. body . span ,
918+ "if it is not part of the public API, make this function unstably const" ,
919+ concat ! ( r#"#[rustc_const_unstable(feature = "...", issue = "...")]"# , '\n' ) . to_owned ( ) ,
920+ Applicability :: HasPlaceholders ,
921+ )
922+ . note ( "otherwise `#[allow_internal_unstable]` can be used to bypass stability checks" )
923+ . emit ( ) ;
924+ }
0 commit comments