Get rid of the fake stack frame
This commit is contained in:
parent
ad30e9a681
commit
a59eabbc36
6 changed files with 44 additions and 81 deletions
|
@ -59,7 +59,6 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
let field = const_field(
|
let field = const_field(
|
||||||
bx.tcx(),
|
bx.tcx(),
|
||||||
ty::ParamEnv::reveal_all(),
|
ty::ParamEnv::reveal_all(),
|
||||||
self.instance,
|
|
||||||
None,
|
None,
|
||||||
mir::Field::new(field as usize),
|
mir::Field::new(field as usize),
|
||||||
c,
|
c,
|
||||||
|
|
|
@ -10,16 +10,15 @@ use rustc::hir::{self, def_id::DefId};
|
||||||
use rustc::hir::def::Def;
|
use rustc::hir::def::Def;
|
||||||
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled};
|
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled};
|
||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
use rustc::ty::{self, TyCtxt, Instance, query::TyCtxtAt};
|
use rustc::ty::{self, TyCtxt, query::TyCtxtAt};
|
||||||
use rustc::ty::layout::{self, LayoutOf, TyLayout, VariantIdx};
|
use rustc::ty::layout::{self, LayoutOf, TyLayout, VariantIdx};
|
||||||
use rustc::ty::subst::Subst;
|
use rustc::ty::subst::Subst;
|
||||||
use rustc::traits::Reveal;
|
use rustc::traits::Reveal;
|
||||||
use rustc_data_structures::indexed_vec::IndexVec;
|
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc::util::common::ErrorReported;
|
use rustc::util::common::ErrorReported;
|
||||||
|
|
||||||
use syntax::ast::Mutability;
|
use syntax::ast::Mutability;
|
||||||
use syntax::source_map::{Span, DUMMY_SP};
|
use syntax::source_map::DUMMY_SP;
|
||||||
|
|
||||||
use crate::interpret::{self,
|
use crate::interpret::{self,
|
||||||
PlaceTy, MPlaceTy, MemPlace, OpTy, Operand, Immediate, Scalar, RawConst, ConstValue, Pointer,
|
PlaceTy, MPlaceTy, MemPlace, OpTy, Operand, Immediate, Scalar, RawConst, ConstValue, Pointer,
|
||||||
|
@ -35,56 +34,6 @@ const STEPS_UNTIL_DETECTOR_ENABLED: isize = 1_000_000;
|
||||||
/// Should be a power of two for performance reasons.
|
/// Should be a power of two for performance reasons.
|
||||||
const DETECTOR_SNAPSHOT_PERIOD: isize = 256;
|
const DETECTOR_SNAPSHOT_PERIOD: isize = 256;
|
||||||
|
|
||||||
/// Warning: do not use this function if you expect to start interpreting the given `Mir`.
|
|
||||||
/// The `EvalContext` is only meant to be used to query values from constants and statics.
|
|
||||||
///
|
|
||||||
/// This function is used during const propagation. We cannot use `mk_eval_cx`, because copy
|
|
||||||
/// propagation happens *during* the computation of the MIR of the current function. So if we
|
|
||||||
/// tried to call the `optimized_mir` query, we'd get a cycle error because we are (transitively)
|
|
||||||
/// inside the `optimized_mir` query of the `Instance` given.
|
|
||||||
///
|
|
||||||
/// Since we are looking at the MIR of the function in an abstract manner, we don't have a
|
|
||||||
/// `ParamEnv` available to us. This function creates a `ParamEnv` for the given instance.
|
|
||||||
pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>(
|
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|
||||||
instance: Instance<'tcx>,
|
|
||||||
mir: &'mir mir::Mir<'tcx>,
|
|
||||||
span: Span,
|
|
||||||
) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'mir, 'tcx>> {
|
|
||||||
debug!("mk_borrowck_eval_cx: {:?}", instance);
|
|
||||||
let param_env = tcx.param_env(instance.def_id());
|
|
||||||
mk_eval_cx_inner(tcx, instance, mir, span, param_env)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This is just a helper function to reduce code duplication between `mk_borrowck_eval_cx` and
|
|
||||||
/// `mk_eval_cx`. Do not call this function directly.
|
|
||||||
fn mk_eval_cx_inner<'a, 'mir, 'tcx>(
|
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|
||||||
instance: Instance<'tcx>,
|
|
||||||
mir: &'mir mir::Mir<'tcx>,
|
|
||||||
span: Span,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'mir, 'tcx>> {
|
|
||||||
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new());
|
|
||||||
// Insert a stack frame so any queries have the correct substs.
|
|
||||||
// We also avoid all the extra work performed by push_stack_frame,
|
|
||||||
// like initializing local variables
|
|
||||||
ecx.stack.push(interpret::Frame {
|
|
||||||
block: mir::START_BLOCK,
|
|
||||||
locals: IndexVec::new(),
|
|
||||||
local_layouts: IndexVec::new(),
|
|
||||||
instance,
|
|
||||||
span,
|
|
||||||
mir,
|
|
||||||
return_place: None,
|
|
||||||
return_to_block: StackPopCleanup::Goto(None), // never pop
|
|
||||||
stmt: 0,
|
|
||||||
extra: (),
|
|
||||||
});
|
|
||||||
Ok(ecx)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Warning: do not use this function if you expect to start interpreting the given `Mir`.
|
|
||||||
/// The `EvalContext` is only meant to be used to do field and index projections into constants for
|
/// The `EvalContext` is only meant to be used to do field and index projections into constants for
|
||||||
/// `simd_shuffle` and const patterns in match arms.
|
/// `simd_shuffle` and const patterns in match arms.
|
||||||
///
|
///
|
||||||
|
@ -92,15 +41,12 @@ fn mk_eval_cx_inner<'a, 'mir, 'tcx>(
|
||||||
/// that inform us about the generic bounds of the constant. E.g. using an associated constant
|
/// 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
|
/// 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.
|
/// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument.
|
||||||
fn mk_eval_cx<'a, 'tcx>(
|
pub(crate) fn mk_eval_cx<'a, 'mir, 'tcx>(
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
instance: Instance<'tcx>,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'tcx, 'tcx>> {
|
) -> CompileTimeEvalContext<'a, 'mir, 'tcx> {
|
||||||
debug!("mk_eval_cx: {:?}, {:?}", instance, param_env);
|
debug!("mk_eval_cx: {:?}", param_env);
|
||||||
let span = tcx.def_span(instance.def_id());
|
EvalContext::new(tcx.at(DUMMY_SP), param_env, CompileTimeInterpreter::new())
|
||||||
let mir = tcx.optimized_mir(instance.def.def_id());
|
|
||||||
mk_eval_cx_inner(tcx, instance, mir, span, param_env)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn eval_promoted<'a, 'mir, 'tcx>(
|
pub(crate) fn eval_promoted<'a, 'mir, 'tcx>(
|
||||||
|
@ -109,7 +55,7 @@ pub(crate) fn eval_promoted<'a, 'mir, 'tcx>(
|
||||||
mir: &'mir mir::Mir<'tcx>,
|
mir: &'mir mir::Mir<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
|
) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
|
||||||
let mut ecx = mk_borrowck_eval_cx(tcx, cid.instance, mir, DUMMY_SP).unwrap();
|
let mut ecx = mk_eval_cx(tcx, param_env);
|
||||||
eval_body_using_ecx(&mut ecx, cid, Some(mir), param_env)
|
eval_body_using_ecx(&mut ecx, cid, Some(mir), param_env)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,13 +476,12 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
|
||||||
pub fn const_field<'a, 'tcx>(
|
pub fn const_field<'a, 'tcx>(
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
instance: ty::Instance<'tcx>,
|
|
||||||
variant: Option<VariantIdx>,
|
variant: Option<VariantIdx>,
|
||||||
field: mir::Field,
|
field: mir::Field,
|
||||||
value: ty::Const<'tcx>,
|
value: ty::Const<'tcx>,
|
||||||
) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
|
) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
|
||||||
trace!("const_field: {:?}, {:?}, {:?}", instance, field, value);
|
trace!("const_field: {:?}, {:?}", field, value);
|
||||||
let ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
|
let ecx = mk_eval_cx(tcx, param_env);
|
||||||
let result = (|| {
|
let result = (|| {
|
||||||
// get the operand again
|
// get the operand again
|
||||||
let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(value), value.ty)?;
|
let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(value), value.ty)?;
|
||||||
|
@ -561,11 +506,10 @@ pub fn const_field<'a, 'tcx>(
|
||||||
pub fn const_variant_index<'a, 'tcx>(
|
pub fn const_variant_index<'a, 'tcx>(
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
instance: ty::Instance<'tcx>,
|
|
||||||
val: ty::Const<'tcx>,
|
val: ty::Const<'tcx>,
|
||||||
) -> EvalResult<'tcx, VariantIdx> {
|
) -> EvalResult<'tcx, VariantIdx> {
|
||||||
trace!("const_variant_index: {:?}, {:?}", instance, val);
|
trace!("const_variant_index: {:?}", val);
|
||||||
let ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
|
let ecx = mk_eval_cx(tcx, param_env);
|
||||||
let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(val), val.ty)?;
|
let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(val), val.ty)?;
|
||||||
Ok(ecx.read_discriminant(op)?.1)
|
Ok(ecx.read_discriminant(op)?.1)
|
||||||
}
|
}
|
||||||
|
@ -585,7 +529,7 @@ fn validate_and_turn_into_const<'a, 'tcx>(
|
||||||
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
|
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
|
||||||
) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
|
) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
|
||||||
let cid = key.value;
|
let cid = key.value;
|
||||||
let ecx = mk_eval_cx(tcx, cid.instance, key.param_env).unwrap();
|
let ecx = mk_eval_cx(tcx, key.param_env);
|
||||||
let val = (|| {
|
let val = (|| {
|
||||||
let op = ecx.raw_const_to_mplace(constant)?.into();
|
let op = ecx.raw_const_to_mplace(constant)?.into();
|
||||||
// FIXME: Once the visitor infrastructure landed, change validation to
|
// FIXME: Once the visitor infrastructure landed, change validation to
|
||||||
|
|
|
@ -427,13 +427,24 @@ pub enum Constructor<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Constructor<'tcx> {
|
impl<'tcx> Constructor<'tcx> {
|
||||||
fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> VariantIdx {
|
fn variant_index_for_adt<'a>(
|
||||||
|
&self,
|
||||||
|
cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||||
|
adt: &'tcx ty::AdtDef,
|
||||||
|
) -> VariantIdx {
|
||||||
match self {
|
match self {
|
||||||
&Variant(vid) => adt.variant_index_with_id(vid),
|
&Variant(vid) => adt.variant_index_with_id(vid),
|
||||||
&Single => {
|
&Single => {
|
||||||
assert!(!adt.is_enum());
|
assert!(!adt.is_enum());
|
||||||
VariantIdx::new(0)
|
VariantIdx::new(0)
|
||||||
}
|
}
|
||||||
|
&ConstantValue(c) => {
|
||||||
|
::const_eval::const_variant_index(
|
||||||
|
cx.tcx,
|
||||||
|
cx.param_env,
|
||||||
|
c,
|
||||||
|
).unwrap()
|
||||||
|
},
|
||||||
_ => bug!("bad constructor {:?} for adt {:?}", self, adt)
|
_ => bug!("bad constructor {:?} for adt {:?}", self, adt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -567,7 +578,7 @@ impl<'tcx> Witness<'tcx> {
|
||||||
PatternKind::Variant {
|
PatternKind::Variant {
|
||||||
adt_def: adt,
|
adt_def: adt,
|
||||||
substs,
|
substs,
|
||||||
variant_index: ctor.variant_index_for_adt(adt),
|
variant_index: ctor.variant_index_for_adt(cx, adt),
|
||||||
subpatterns: pats
|
subpatterns: pats
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1329,7 +1340,7 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>,
|
||||||
///
|
///
|
||||||
/// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3.
|
/// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3.
|
||||||
/// A struct pattern's arity is the number of fields it contains, etc.
|
/// A struct pattern's arity is the number of fields it contains, etc.
|
||||||
fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 {
|
fn constructor_arity(cx: &MatchCheckCtxt<'a, 'tcx>, ctor: &Constructor<'tcx>, ty: Ty<'tcx>) -> u64 {
|
||||||
debug!("constructor_arity({:#?}, {:?})", ctor, ty);
|
debug!("constructor_arity({:#?}, {:?})", ctor, ty);
|
||||||
match ty.sty {
|
match ty.sty {
|
||||||
ty::Tuple(ref fs) => fs.len() as u64,
|
ty::Tuple(ref fs) => fs.len() as u64,
|
||||||
|
@ -1340,7 +1351,7 @@ fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 {
|
||||||
},
|
},
|
||||||
ty::Ref(..) => 1,
|
ty::Ref(..) => 1,
|
||||||
ty::Adt(adt, _) => {
|
ty::Adt(adt, _) => {
|
||||||
adt.variants[ctor.variant_index_for_adt(adt)].fields.len() as u64
|
adt.variants[ctor.variant_index_for_adt(cx, adt)].fields.len() as u64
|
||||||
}
|
}
|
||||||
_ => 0
|
_ => 0
|
||||||
}
|
}
|
||||||
|
@ -1351,7 +1362,7 @@ fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 {
|
||||||
///
|
///
|
||||||
/// For instance, a tuple pattern (43u32, 'a') has sub pattern types [u32, char].
|
/// For instance, a tuple pattern (43u32, 'a') has sub pattern types [u32, char].
|
||||||
fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||||
ctor: &Constructor,
|
ctor: &Constructor<'tcx>,
|
||||||
ty: Ty<'tcx>) -> Vec<Ty<'tcx>>
|
ty: Ty<'tcx>) -> Vec<Ty<'tcx>>
|
||||||
{
|
{
|
||||||
debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty);
|
debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty);
|
||||||
|
@ -1368,7 +1379,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||||
// Use T as the sub pattern type of Box<T>.
|
// Use T as the sub pattern type of Box<T>.
|
||||||
vec![substs.type_at(0)]
|
vec![substs.type_at(0)]
|
||||||
} else {
|
} else {
|
||||||
adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| {
|
adt.variants[ctor.variant_index_for_adt(cx, adt)].fields.iter().map(|field| {
|
||||||
let is_visible = adt.is_enum()
|
let is_visible = adt.is_enum()
|
||||||
|| field.vis.is_accessible_from(cx.module, cx.tcx);
|
|| field.vis.is_accessible_from(cx.module, cx.tcx);
|
||||||
if is_visible {
|
if is_visible {
|
||||||
|
|
|
@ -885,7 +885,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||||
let adt_subpattern = |i, variant_opt| {
|
let adt_subpattern = |i, variant_opt| {
|
||||||
let field = Field::new(i);
|
let field = Field::new(i);
|
||||||
let val = const_field(
|
let val = const_field(
|
||||||
self.tcx, self.param_env, instance,
|
self.tcx, self.param_env,
|
||||||
variant_opt, field, cv,
|
variant_opt, field, cv,
|
||||||
).expect("field access failed");
|
).expect("field access failed");
|
||||||
self.const_to_pat(instance, val, id, span)
|
self.const_to_pat(instance, val, id, span)
|
||||||
|
@ -928,7 +928,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||||
},
|
},
|
||||||
ty::Adt(adt_def, substs) if adt_def.is_enum() => {
|
ty::Adt(adt_def, substs) if adt_def.is_enum() => {
|
||||||
let variant_index = const_variant_index(
|
let variant_index = const_variant_index(
|
||||||
self.tcx, self.param_env, instance, cv
|
self.tcx, self.param_env, cv
|
||||||
).expect("const_variant_index failed");
|
).expect("const_variant_index failed");
|
||||||
let subpatterns = adt_subpatterns(
|
let subpatterns = adt_subpatterns(
|
||||||
adt_def.variants[variant_index].fields.len(),
|
adt_def.variants[variant_index].fields.len(),
|
||||||
|
|
|
@ -20,7 +20,7 @@ use rustc::ty::layout::{
|
||||||
|
|
||||||
use interpret::{self, EvalContext, ScalarMaybeUndef, Immediate, OpTy, MemoryKind};
|
use interpret::{self, EvalContext, ScalarMaybeUndef, Immediate, OpTy, MemoryKind};
|
||||||
use const_eval::{
|
use const_eval::{
|
||||||
CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_borrowck_eval_cx,
|
CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_eval_cx,
|
||||||
lazy_const_to_op,
|
lazy_const_to_op,
|
||||||
};
|
};
|
||||||
use transform::{MirPass, MirSource};
|
use transform::{MirPass, MirSource};
|
||||||
|
@ -110,9 +110,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
|
||||||
source: MirSource,
|
source: MirSource,
|
||||||
) -> ConstPropagator<'a, 'mir, 'tcx> {
|
) -> ConstPropagator<'a, 'mir, 'tcx> {
|
||||||
let param_env = tcx.param_env(source.def_id);
|
let param_env = tcx.param_env(source.def_id);
|
||||||
let substs = Substs::identity_for_item(tcx, source.def_id);
|
let ecx = mk_eval_cx(tcx, param_env);
|
||||||
let instance = Instance::new(source.def_id, substs);
|
|
||||||
let ecx = mk_borrowck_eval_cx(tcx, instance, mir, DUMMY_SP).unwrap();
|
|
||||||
ConstPropagator {
|
ConstPropagator {
|
||||||
ecx,
|
ecx,
|
||||||
mir,
|
mir,
|
||||||
|
|
11
src/test/ui/consts/match_ice.rs
Normal file
11
src/test/ui/consts/match_ice.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
// compile-pass
|
||||||
|
// https://github.com/rust-lang/rust/issues/53708
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
const C: &S = &S;
|
||||||
|
match C {
|
||||||
|
C => {}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue