From e21d2c8f9b797a05a1eba0610e5dae0ba0ced4b9 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 25 Dec 2019 01:15:26 +0100 Subject: [PATCH] Move all functions used by the queries to query.rs --- src/librustc_mir/const_eval.rs | 111 +-------------------------- src/librustc_mir/const_eval/query.rs | 95 +++++++++++++++++++++++ 2 files changed, 98 insertions(+), 108 deletions(-) diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index e614ad8539e..579b79d92f8 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -1,22 +1,12 @@ // Not in interpret to make sure we do not use private implementation details -use std::convert::TryInto; -use std::error::Error; -use std::fmt; -use std::hash::Hash; - use rustc::mir; -use rustc::ty::layout::{self, VariantIdx}; +use rustc::ty::layout::VariantIdx; use rustc::ty::{self, TyCtxt}; -use syntax::{ - source_map::{Span, DUMMY_SP}, - symbol::Symbol, -}; +use syntax::{source_map::DUMMY_SP, symbol::Symbol}; -use crate::interpret::{ - intern_const_alloc_recursive, Allocation, ConstValue, ImmTy, Immediate, InterpCx, OpTy, Scalar, -}; +use crate::interpret::{intern_const_alloc_recursive, ConstValue, InterpCx}; mod error; mod query; @@ -24,101 +14,6 @@ mod query; pub use error::*; pub use query::*; -/// The `InterpCx` is only meant to be used to do field and index projections into constants for -/// `simd_shuffle` and const patterns in match arms. -/// -/// The function containing the `match` that is currently being analyzed may have generic bounds -/// that inform us about the generic bounds of the constant. E.g., using an associated constant -/// of a function's generic parameter will require knowledge about the bounds on the generic -/// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument. -fn mk_eval_cx<'mir, 'tcx>( - tcx: TyCtxt<'tcx>, - span: Span, - param_env: ty::ParamEnv<'tcx>, - can_access_statics: bool, -) -> CompileTimeEvalContext<'mir, 'tcx> { - debug!("mk_eval_cx: {:?}", param_env); - InterpCx::new( - tcx.at(span), - param_env, - CompileTimeInterpreter::new(), - MemoryExtra { can_access_statics }, - ) -} - -fn op_to_const<'tcx>( - ecx: &CompileTimeEvalContext<'_, 'tcx>, - op: OpTy<'tcx>, -) -> &'tcx ty::Const<'tcx> { - // We do not have value optimizations for everything. - // Only scalars and slices, since they are very common. - // Note that further down we turn scalars of undefined bits back to `ByRef`. These can result - // from scalar unions that are initialized with one of their zero sized variants. We could - // instead allow `ConstValue::Scalar` to store `ScalarMaybeUndef`, but that would affect all - // the usual cases of extracting e.g. a `usize`, without there being a real use case for the - // `Undef` situation. - let try_as_immediate = match op.layout.abi { - layout::Abi::Scalar(..) => true, - layout::Abi::ScalarPair(..) => match op.layout.ty.kind { - ty::Ref(_, inner, _) => match inner.kind { - ty::Slice(elem) => elem == ecx.tcx.types.u8, - ty::Str => true, - _ => false, - }, - _ => false, - }, - _ => false, - }; - let immediate = if try_as_immediate { - Err(ecx.read_immediate(op).expect("normalization works on validated constants")) - } else { - // It is guaranteed that any non-slice scalar pair is actually ByRef here. - // When we come back from raw const eval, we are always by-ref. The only way our op here is - // by-val is if we are in const_field, i.e., if this is (a field of) something that we - // "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or - // structs containing such. - op.try_as_mplace() - }; - let val = match immediate { - Ok(mplace) => { - let ptr = mplace.ptr.to_ptr().unwrap(); - let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); - ConstValue::ByRef { alloc, offset: ptr.offset } - } - // see comment on `let try_as_immediate` above - Err(ImmTy { imm: Immediate::Scalar(x), .. }) => match x { - ScalarMaybeUndef::Scalar(s) => ConstValue::Scalar(s), - ScalarMaybeUndef::Undef => { - // When coming out of "normal CTFE", we'll always have an `Indirect` operand as - // argument and we will not need this. The only way we can already have an - // `Immediate` is when we are called from `const_field`, and that `Immediate` - // comes from a constant so it can happen have `Undef`, because the indirect - // memory that was read had undefined bytes. - let mplace = op.assert_mem_place(); - let ptr = mplace.ptr.to_ptr().unwrap(); - let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); - ConstValue::ByRef { alloc, offset: ptr.offset } - } - }, - Err(ImmTy { imm: Immediate::ScalarPair(a, b), .. }) => { - let (data, start) = match a.not_undef().unwrap() { - Scalar::Ptr(ptr) => { - (ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), ptr.offset.bytes()) - } - Scalar::Raw { .. } => ( - ecx.tcx.intern_const_alloc(Allocation::from_byte_aligned_bytes(b"" as &[u8])), - 0, - ), - }; - let len = b.to_machine_usize(&ecx.tcx.tcx).unwrap(); - let start = start.try_into().unwrap(); - let len: usize = len.try_into().unwrap(); - ConstValue::Slice { data, start, end: start + len } - } - }; - ecx.tcx.mk_const(ty::Const { val: ty::ConstKind::Value(val), ty: op.layout.ty }) -} - /// Extracts a field of a (variant of a) const. // this function uses `unwrap` copiously, because an already validated constant must have valid // fields and can thus never fail outside of compiler bugs diff --git a/src/librustc_mir/const_eval/query.rs b/src/librustc_mir/const_eval/query.rs index 1ab8377c4b9..f92475e0375 100644 --- a/src/librustc_mir/const_eval/query.rs +++ b/src/librustc_mir/const_eval/query.rs @@ -262,3 +262,98 @@ fn eval_body_using_ecx<'mir, 'tcx>( debug!("eval_body_using_ecx done: {:?}", *ret); Ok(ret) } + +/// The `InterpCx` is only meant to be used to do field and index projections into constants for +/// `simd_shuffle` and const patterns in match arms. +/// +/// The function containing the `match` that is currently being analyzed may have generic bounds +/// that inform us about the generic bounds of the constant. E.g., using an associated constant +/// of a function's generic parameter will require knowledge about the bounds on the generic +/// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument. +pub(super) fn mk_eval_cx<'mir, 'tcx>( + tcx: TyCtxt<'tcx>, + span: Span, + param_env: ty::ParamEnv<'tcx>, + can_access_statics: bool, +) -> CompileTimeEvalContext<'mir, 'tcx> { + debug!("mk_eval_cx: {:?}", param_env); + InterpCx::new( + tcx.at(span), + param_env, + CompileTimeInterpreter::new(), + MemoryExtra { can_access_statics }, + ) +} + +pub(super) fn op_to_const<'tcx>( + ecx: &CompileTimeEvalContext<'_, 'tcx>, + op: OpTy<'tcx>, +) -> &'tcx ty::Const<'tcx> { + // We do not have value optimizations for everything. + // Only scalars and slices, since they are very common. + // Note that further down we turn scalars of undefined bits back to `ByRef`. These can result + // from scalar unions that are initialized with one of their zero sized variants. We could + // instead allow `ConstValue::Scalar` to store `ScalarMaybeUndef`, but that would affect all + // the usual cases of extracting e.g. a `usize`, without there being a real use case for the + // `Undef` situation. + let try_as_immediate = match op.layout.abi { + layout::Abi::Scalar(..) => true, + layout::Abi::ScalarPair(..) => match op.layout.ty.kind { + ty::Ref(_, inner, _) => match inner.kind { + ty::Slice(elem) => elem == ecx.tcx.types.u8, + ty::Str => true, + _ => false, + }, + _ => false, + }, + _ => false, + }; + let immediate = if try_as_immediate { + Err(ecx.read_immediate(op).expect("normalization works on validated constants")) + } else { + // It is guaranteed that any non-slice scalar pair is actually ByRef here. + // When we come back from raw const eval, we are always by-ref. The only way our op here is + // by-val is if we are in const_field, i.e., if this is (a field of) something that we + // "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or + // structs containing such. + op.try_as_mplace() + }; + let val = match immediate { + Ok(mplace) => { + let ptr = mplace.ptr.to_ptr().unwrap(); + let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); + ConstValue::ByRef { alloc, offset: ptr.offset } + } + // see comment on `let try_as_immediate` above + Err(ImmTy { imm: Immediate::Scalar(x), .. }) => match x { + ScalarMaybeUndef::Scalar(s) => ConstValue::Scalar(s), + ScalarMaybeUndef::Undef => { + // When coming out of "normal CTFE", we'll always have an `Indirect` operand as + // argument and we will not need this. The only way we can already have an + // `Immediate` is when we are called from `const_field`, and that `Immediate` + // comes from a constant so it can happen have `Undef`, because the indirect + // memory that was read had undefined bytes. + let mplace = op.assert_mem_place(); + let ptr = mplace.ptr.to_ptr().unwrap(); + let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); + ConstValue::ByRef { alloc, offset: ptr.offset } + } + }, + Err(ImmTy { imm: Immediate::ScalarPair(a, b), .. }) => { + let (data, start) = match a.not_undef().unwrap() { + Scalar::Ptr(ptr) => { + (ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), ptr.offset.bytes()) + } + Scalar::Raw { .. } => ( + ecx.tcx.intern_const_alloc(Allocation::from_byte_aligned_bytes(b"" as &[u8])), + 0, + ), + }; + let len = b.to_machine_usize(&ecx.tcx.tcx).unwrap(); + let start = start.try_into().unwrap(); + let len: usize = len.try_into().unwrap(); + ConstValue::Slice { data, start, end: start + len } + } + }; + ecx.tcx.mk_const(ty::Const { val: ty::ConstKind::Value(val), ty: op.layout.ty }) +}