@@ -5,12 +5,8 @@ use std::error::Error;
55use std:: fmt;
66use std:: hash:: Hash ;
77
8- use crate :: interpret:: eval_nullary_intrinsic;
9- use crate :: interpret:: eval_nullary_intrinsic;
10- use rustc:: hir:: def:: DefKind ;
118use rustc:: mir;
12- use rustc:: mir:: interpret:: { ConstEvalErr , ErrorHandled , ScalarMaybeUndef } ;
13- use rustc:: traits:: Reveal ;
9+ use rustc:: mir:: interpret:: ScalarMaybeUndef ;
1410use rustc:: ty:: layout:: { self , LayoutOf , VariantIdx } ;
1511use rustc:: ty:: { self , subst:: Subst , TyCtxt } ;
1612
@@ -21,15 +17,14 @@ use syntax::{
2117
2218use crate :: interpret:: {
2319 intern_const_alloc_recursive, Allocation , ConstValue , GlobalId , ImmTy , Immediate , InterpCx ,
24- InterpErrorInfo , InterpResult , MPlaceTy , Machine , MemoryKind , OpTy , RawConst , RefTracking ,
25- Scalar , StackPopCleanup ,
20+ InterpResult , MPlaceTy , MemoryKind , OpTy , Scalar , StackPopCleanup ,
2621} ;
2722
2823mod error;
29- mod machine ;
24+ mod query ;
3025
3126pub use error:: * ;
32- pub use machine :: * ;
27+ pub use query :: * ;
3328
3429/// The `InterpCx` is only meant to be used to do field and index projections into constants for
3530/// `simd_shuffle` and const patterns in match arms.
@@ -225,220 +220,3 @@ pub fn const_variant_index<'tcx>(
225220 let op = ecx. eval_const_to_op ( val, None ) . unwrap ( ) ;
226221 ecx. read_discriminant ( op) . unwrap ( ) . 1
227222}
228-
229- /// Turn an interpreter error into something to report to the user.
230- /// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace.
231- /// Should be called only if the error is actually going to to be reported!
232- pub fn error_to_const_error < ' mir , ' tcx , M : Machine < ' mir , ' tcx > > (
233- ecx : & InterpCx < ' mir , ' tcx , M > ,
234- mut error : InterpErrorInfo < ' tcx > ,
235- ) -> ConstEvalErr < ' tcx > {
236- error. print_backtrace ( ) ;
237- let stacktrace = ecx. generate_stacktrace ( None ) ;
238- ConstEvalErr { error : error. kind , stacktrace, span : ecx. tcx . span }
239- }
240-
241- pub fn note_on_undefined_behavior_error ( ) -> & ' static str {
242- "The rules on what exactly is undefined behavior aren't clear, \
243- so this check might be overzealous. Please open an issue on the rustc \
244- repository if you believe it should not be considered undefined behavior."
245- }
246-
247- fn validate_and_turn_into_const < ' tcx > (
248- tcx : TyCtxt < ' tcx > ,
249- constant : RawConst < ' tcx > ,
250- key : ty:: ParamEnvAnd < ' tcx , GlobalId < ' tcx > > ,
251- ) -> :: rustc:: mir:: interpret:: ConstEvalResult < ' tcx > {
252- let cid = key. value ;
253- let def_id = cid. instance . def . def_id ( ) ;
254- let is_static = tcx. is_static ( def_id) ;
255- let ecx = mk_eval_cx ( tcx, tcx. def_span ( key. value . instance . def_id ( ) ) , key. param_env , is_static) ;
256- let val = ( || {
257- let mplace = ecx. raw_const_to_mplace ( constant) ?;
258- let mut ref_tracking = RefTracking :: new ( mplace) ;
259- while let Some ( ( mplace, path) ) = ref_tracking. todo . pop ( ) {
260- ecx. validate_operand ( mplace. into ( ) , path, Some ( & mut ref_tracking) ) ?;
261- }
262- // Now that we validated, turn this into a proper constant.
263- // Statics/promoteds are always `ByRef`, for the rest `op_to_const` decides
264- // whether they become immediates.
265- if is_static || cid. promoted . is_some ( ) {
266- let ptr = mplace. ptr . to_ptr ( ) ?;
267- Ok ( tcx. mk_const ( ty:: Const {
268- val : ty:: ConstKind :: Value ( ConstValue :: ByRef {
269- alloc : ecx. tcx . alloc_map . lock ( ) . unwrap_memory ( ptr. alloc_id ) ,
270- offset : ptr. offset ,
271- } ) ,
272- ty : mplace. layout . ty ,
273- } ) )
274- } else {
275- Ok ( op_to_const ( & ecx, mplace. into ( ) ) )
276- }
277- } ) ( ) ;
278-
279- val. map_err ( |error| {
280- let err = error_to_const_error ( & ecx, error) ;
281- match err. struct_error ( ecx. tcx , "it is undefined behavior to use this value" ) {
282- Ok ( mut diag) => {
283- diag. note ( note_on_undefined_behavior_error ( ) ) ;
284- diag. emit ( ) ;
285- ErrorHandled :: Reported
286- }
287- Err ( err) => err,
288- }
289- } )
290- }
291-
292- pub fn const_eval_validated_provider < ' tcx > (
293- tcx : TyCtxt < ' tcx > ,
294- key : ty:: ParamEnvAnd < ' tcx , GlobalId < ' tcx > > ,
295- ) -> :: rustc:: mir:: interpret:: ConstEvalResult < ' tcx > {
296- // see comment in const_eval_raw_provider for what we're doing here
297- if key. param_env . reveal == Reveal :: All {
298- let mut key = key. clone ( ) ;
299- key. param_env . reveal = Reveal :: UserFacing ;
300- match tcx. const_eval_validated ( key) {
301- // try again with reveal all as requested
302- Err ( ErrorHandled :: TooGeneric ) => {
303- // Promoteds should never be "too generic" when getting evaluated.
304- // They either don't get evaluated, or we are in a monomorphic context
305- assert ! ( key. value. promoted. is_none( ) ) ;
306- }
307- // dedupliate calls
308- other => return other,
309- }
310- }
311-
312- // We call `const_eval` for zero arg intrinsics, too, in order to cache their value.
313- // Catch such calls and evaluate them instead of trying to load a constant's MIR.
314- if let ty:: InstanceDef :: Intrinsic ( def_id) = key. value . instance . def {
315- let ty = key. value . instance . ty ( tcx) ;
316- let substs = match ty. kind {
317- ty:: FnDef ( _, substs) => substs,
318- _ => bug ! ( "intrinsic with type {:?}" , ty) ,
319- } ;
320- return eval_nullary_intrinsic ( tcx, key. param_env , def_id, substs) . map_err ( |error| {
321- let span = tcx. def_span ( def_id) ;
322- let error = ConstEvalErr { error : error. kind , stacktrace : vec ! [ ] , span } ;
323- error. report_as_error ( tcx. at ( span) , "could not evaluate nullary intrinsic" )
324- } ) ;
325- }
326-
327- tcx. const_eval_raw ( key) . and_then ( |val| validate_and_turn_into_const ( tcx, val, key) )
328- }
329-
330- pub fn const_eval_raw_provider < ' tcx > (
331- tcx : TyCtxt < ' tcx > ,
332- key : ty:: ParamEnvAnd < ' tcx , GlobalId < ' tcx > > ,
333- ) -> :: rustc:: mir:: interpret:: ConstEvalRawResult < ' tcx > {
334- // Because the constant is computed twice (once per value of `Reveal`), we are at risk of
335- // reporting the same error twice here. To resolve this, we check whether we can evaluate the
336- // constant in the more restrictive `Reveal::UserFacing`, which most likely already was
337- // computed. For a large percentage of constants that will already have succeeded. Only
338- // associated constants of generic functions will fail due to not enough monomorphization
339- // information being available.
340-
341- // In case we fail in the `UserFacing` variant, we just do the real computation.
342- if key. param_env . reveal == Reveal :: All {
343- let mut key = key. clone ( ) ;
344- key. param_env . reveal = Reveal :: UserFacing ;
345- match tcx. const_eval_raw ( key) {
346- // try again with reveal all as requested
347- Err ( ErrorHandled :: TooGeneric ) => { }
348- // dedupliate calls
349- other => return other,
350- }
351- }
352- if cfg ! ( debug_assertions) {
353- // Make sure we format the instance even if we do not print it.
354- // This serves as a regression test against an ICE on printing.
355- // The next two lines concatenated contain some discussion:
356- // https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/
357- // subject/anon_const_instance_printing/near/135980032
358- let instance = key. value . instance . to_string ( ) ;
359- trace ! ( "const eval: {:?} ({})" , key, instance) ;
360- }
361-
362- let cid = key. value ;
363- let def_id = cid. instance . def . def_id ( ) ;
364-
365- if def_id. is_local ( ) && tcx. typeck_tables_of ( def_id) . tainted_by_errors {
366- return Err ( ErrorHandled :: Reported ) ;
367- }
368-
369- let is_static = tcx. is_static ( def_id) ;
370-
371- let span = tcx. def_span ( cid. instance . def_id ( ) ) ;
372- let mut ecx = InterpCx :: new (
373- tcx. at ( span) ,
374- key. param_env ,
375- CompileTimeInterpreter :: new ( ) ,
376- MemoryExtra { can_access_statics : is_static } ,
377- ) ;
378-
379- let res = ecx. load_mir ( cid. instance . def , cid. promoted ) ;
380- res. and_then ( |body| eval_body_using_ecx ( & mut ecx, cid, * body) )
381- . and_then ( |place| {
382- Ok ( RawConst { alloc_id : place. ptr . assert_ptr ( ) . alloc_id , ty : place. layout . ty } )
383- } )
384- . map_err ( |error| {
385- let err = error_to_const_error ( & ecx, error) ;
386- // errors in statics are always emitted as fatal errors
387- if is_static {
388- // Ensure that if the above error was either `TooGeneric` or `Reported`
389- // an error must be reported.
390- let v = err. report_as_error ( ecx. tcx , "could not evaluate static initializer" ) ;
391- tcx. sess . delay_span_bug (
392- err. span ,
393- & format ! ( "static eval failure did not emit an error: {:#?}" , v) ,
394- ) ;
395- v
396- } else if def_id. is_local ( ) {
397- // constant defined in this crate, we can figure out a lint level!
398- match tcx. def_kind ( def_id) {
399- // constants never produce a hard error at the definition site. Anything else is
400- // a backwards compatibility hazard (and will break old versions of winapi for sure)
401- //
402- // note that validation may still cause a hard error on this very same constant,
403- // because any code that existed before validation could not have failed validation
404- // thus preventing such a hard error from being a backwards compatibility hazard
405- Some ( DefKind :: Const ) | Some ( DefKind :: AssocConst ) => {
406- let hir_id = tcx. hir ( ) . as_local_hir_id ( def_id) . unwrap ( ) ;
407- err. report_as_lint (
408- tcx. at ( tcx. def_span ( def_id) ) ,
409- "any use of this value will cause an error" ,
410- hir_id,
411- Some ( err. span ) ,
412- )
413- }
414- // promoting runtime code is only allowed to error if it references broken constants
415- // any other kind of error will be reported to the user as a deny-by-default lint
416- _ => {
417- if let Some ( p) = cid. promoted {
418- let span = tcx. promoted_mir ( def_id) [ p] . span ;
419- if let err_inval ! ( ReferencedConstant ) = err. error {
420- err. report_as_error (
421- tcx. at ( span) ,
422- "evaluation of constant expression failed" ,
423- )
424- } else {
425- err. report_as_lint (
426- tcx. at ( span) ,
427- "reaching this expression at runtime will panic or abort" ,
428- tcx. hir ( ) . as_local_hir_id ( def_id) . unwrap ( ) ,
429- Some ( err. span ) ,
430- )
431- }
432- // anything else (array lengths, enum initializers, constant patterns) are reported
433- // as hard errors
434- } else {
435- err. report_as_error ( ecx. tcx , "evaluation of constant value failed" )
436- }
437- }
438- }
439- } else {
440- // use of broken constant from other crate
441- err. report_as_error ( ecx. tcx , "could not evaluate constant" )
442- }
443- } )
444- }
0 commit comments