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:: { Applicability , struct_span_err} ;
4
4
use rustc_hir:: { self as hir, LangItem } ;
5
5
use rustc_hir:: { def_id:: DefId , HirId } ;
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 } ;
@@ -179,7 +179,12 @@ pub struct Validator<'mir, 'tcx> {
179
179
/// The span of the current statement.
180
180
span : Span ,
181
181
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 ,
183
188
}
184
189
185
190
impl Deref for Validator < ' mir , ' tcx > {
@@ -196,7 +201,8 @@ impl Validator<'mir, 'tcx> {
196
201
span : ccx. body . span ,
197
202
ccx,
198
203
qualifs : Default :: default ( ) ,
199
- const_checking_stopped : false ,
204
+ passes_checks_without_unstable_features : true ,
205
+ silence_errors : false ,
200
206
}
201
207
}
202
208
@@ -266,15 +272,48 @@ impl Validator<'mir, 'tcx> {
266
272
/// Emits an error at the given `span` if an expression cannot be evaluated in the current
267
273
/// context.
268
274
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 {
272
288
return ;
273
289
}
274
290
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 ;
278
317
}
279
318
}
280
319
@@ -866,3 +905,20 @@ fn place_as_reborrow(
866
905
}
867
906
} )
868
907
}
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