Skip to content

Get rid of the fake stack frame for reading from constants #57606

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/librustc_codegen_ssa/mir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let field = const_field(
bx.tcx(),
ty::ParamEnv::reveal_all(),
self.instance,
None,
mir::Field::new(field as usize),
c,
Expand Down
80 changes: 13 additions & 67 deletions src/librustc_mir/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@ use rustc::hir::{self, def_id::DefId};
use rustc::hir::def::Def;
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled};
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::subst::Subst;
use rustc::traits::Reveal;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::fx::FxHashMap;
use rustc::util::common::ErrorReported;

Expand All @@ -35,72 +34,20 @@ const STEPS_UNTIL_DETECTOR_ENABLED: isize = 1_000_000;
/// Should be a power of two for performance reasons.
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
/// `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<'a, 'tcx>(
pub(crate) fn mk_eval_cx<'a, 'mir, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
instance: Instance<'tcx>,
span: Span,
param_env: ty::ParamEnv<'tcx>,
) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'tcx, 'tcx>> {
debug!("mk_eval_cx: {:?}, {:?}", instance, param_env);
let span = tcx.def_span(instance.def_id());
let mir = tcx.optimized_mir(instance.def.def_id());
mk_eval_cx_inner(tcx, instance, mir, span, param_env)
) -> CompileTimeEvalContext<'a, 'mir, 'tcx> {
debug!("mk_eval_cx: {:?}", param_env);
EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new())
}

pub(crate) fn eval_promoted<'a, 'mir, 'tcx>(
Expand All @@ -109,7 +56,8 @@ pub(crate) fn eval_promoted<'a, 'mir, 'tcx>(
mir: &'mir mir::Mir<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
let mut ecx = mk_borrowck_eval_cx(tcx, cid.instance, mir, DUMMY_SP).unwrap();
let span = tcx.def_span(cid.instance.def_id());
let mut ecx = mk_eval_cx(tcx, span, param_env);
eval_body_using_ecx(&mut ecx, cid, Some(mir), param_env)
}

Expand Down Expand Up @@ -530,13 +478,12 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
pub fn const_field<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
instance: ty::Instance<'tcx>,
variant: Option<VariantIdx>,
field: mir::Field,
value: ty::Const<'tcx>,
) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
trace!("const_field: {:?}, {:?}, {:?}", instance, field, value);
let ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
trace!("const_field: {:?}, {:?}", field, value);
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env);
let result = (|| {
// get the operand again
let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(value), value.ty)?;
Expand All @@ -561,11 +508,10 @@ pub fn const_field<'a, 'tcx>(
pub fn const_variant_index<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
instance: ty::Instance<'tcx>,
val: ty::Const<'tcx>,
) -> EvalResult<'tcx, VariantIdx> {
trace!("const_variant_index: {:?}, {:?}", instance, val);
let ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
trace!("const_variant_index: {:?}", val);
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env);
let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(val), val.ty)?;
Ok(ecx.read_discriminant(op)?.1)
}
Expand All @@ -585,7 +531,7 @@ fn validate_and_turn_into_const<'a, 'tcx>(
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
let cid = key.value;
let ecx = mk_eval_cx(tcx, cid.instance, key.param_env).unwrap();
let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env);
let val = (|| {
let op = ecx.raw_const_to_mplace(constant)?.into();
// FIXME: Once the visitor infrastructure landed, change validation to
Expand Down
23 changes: 17 additions & 6 deletions src/librustc_mir/hair/pattern/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,13 +427,24 @@ pub enum 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 {
&Variant(vid) => adt.variant_index_with_id(vid),
&Single => {
assert!(!adt.is_enum());
VariantIdx::new(0)
}
&ConstantValue(c) => {
::const_eval::const_variant_index(
cx.tcx,
cx.param_env,
c,
).unwrap()
},
_ => bug!("bad constructor {:?} for adt {:?}", self, adt)
}
}
Expand Down Expand Up @@ -567,7 +578,7 @@ impl<'tcx> Witness<'tcx> {
PatternKind::Variant {
adt_def: adt,
substs,
variant_index: ctor.variant_index_for_adt(adt),
variant_index: ctor.variant_index_for_adt(cx, adt),
subpatterns: pats
}
} else {
Expand Down Expand Up @@ -1329,7 +1340,7 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>,
///
/// 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.
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);
match ty.sty {
ty::Tuple(ref fs) => fs.len() as u64,
Expand All @@ -1340,7 +1351,7 @@ fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 {
},
ty::Ref(..) => 1,
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
}
Expand All @@ -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].
fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
ctor: &Constructor,
ctor: &Constructor<'tcx>,
ty: Ty<'tcx>) -> Vec<Ty<'tcx>>
{
debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty);
Expand All @@ -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>.
vec![substs.type_at(0)]
} 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()
|| field.vis.is_accessible_from(cx.module, cx.tcx);
if is_visible {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir/hair/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -885,7 +885,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
let adt_subpattern = |i, variant_opt| {
let field = Field::new(i);
let val = const_field(
self.tcx, self.param_env, instance,
self.tcx, self.param_env,
variant_opt, field, cv,
).expect("field access failed");
self.const_to_pat(instance, val, id, span)
Expand Down Expand Up @@ -928,7 +928,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
},
ty::Adt(adt_def, substs) if adt_def.is_enum() => {
let variant_index = const_variant_index(
self.tcx, self.param_env, instance, cv
self.tcx, self.param_env, cv
).expect("const_variant_index failed");
let subpatterns = adt_subpatterns(
adt_def.variants[variant_index].fields.len(),
Expand Down
6 changes: 1 addition & 5 deletions src/librustc_mir/interpret/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
// The src operand does not matter, just its type
match src.layout.ty.sty {
ty::Closure(def_id, substs) => {
let substs = self.tcx.subst_and_normalize_erasing_regions(
self.substs(),
ty::ParamEnv::reveal_all(),
&substs,
);
let substs = self.subst_and_normalize_erasing_regions(substs)?;
let instance = ty::Instance::resolve_closure(
*self.tcx,
def_id,
Expand Down
46 changes: 33 additions & 13 deletions src/librustc_mir/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,11 +216,21 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
self.frame().mir
}

pub fn substs(&self) -> &'tcx Substs<'tcx> {
if let Some(frame) = self.stack.last() {
frame.instance.substs
} else {
Substs::empty()
pub(super) fn subst_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
&self,
substs: T,
) -> EvalResult<'tcx, T> {
match self.stack.last() {
Some(frame) => Ok(self.tcx.subst_and_normalize_erasing_regions(
frame.instance.substs,
self.param_env,
&substs,
)),
None => if substs.needs_subst() {
err!(TooGeneric).into()
} else {
Ok(substs)
},
}
}

Expand All @@ -230,13 +240,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
substs: &'tcx Substs<'tcx>
) -> EvalResult<'tcx, ty::Instance<'tcx>> {
trace!("resolve: {:?}, {:#?}", def_id, substs);
trace!("substs: {:#?}", self.substs());
trace!("param_env: {:#?}", self.param_env);
let substs = self.tcx.subst_and_normalize_erasing_regions(
self.substs(),
self.param_env,
&substs,
);
let substs = self.subst_and_normalize_erasing_regions(substs)?;
trace!("substs: {:#?}", substs);
ty::Instance::resolve(
*self.tcx,
self.param_env,
Expand Down Expand Up @@ -276,7 +282,21 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
}
}

pub fn monomorphize<T: TypeFoldable<'tcx> + Subst<'tcx>>(
pub(super) fn monomorphize<T: TypeFoldable<'tcx> + Subst<'tcx>>(
&self,
t: T,
) -> EvalResult<'tcx, T> {
match self.stack.last() {
Some(frame) => Ok(self.monomorphize_with_substs(t, frame.instance.substs)),
None => if t.needs_subst() {
err!(TooGeneric).into()
} else {
Ok(t)
},
}
}

fn monomorphize_with_substs<T: TypeFoldable<'tcx> + Subst<'tcx>>(
&self,
t: T,
substs: &'tcx Substs<'tcx>
Expand All @@ -295,7 +315,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
let cell = &frame.local_layouts[local];
if cell.get().is_none() {
let local_ty = frame.mir.local_decls[local].ty;
let local_ty = self.monomorphize(local_ty, frame.instance.substs);
let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs);
let layout = self.layout_of(local_ty)?;
cell.set(Some(layout));
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/interpret/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>

Constant(ref constant) => {
let layout = from_known_layout(layout, || {
let ty = self.monomorphize(mir_op.ty(self.mir(), *self.tcx), self.substs());
let ty = self.monomorphize(mir_op.ty(self.mir(), *self.tcx))?;
self.layout_of(ty)
})?;
let op = self.const_value_to_op(*constant.literal)?;
Expand Down
5 changes: 3 additions & 2 deletions src/librustc_mir/interpret/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use rustc::hir;
use rustc::mir;
use rustc::ty::{self, Ty};
use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx};
use rustc::ty::TypeFoldable;

use super::{
GlobalId, AllocId, Allocation, Scalar, EvalResult, Pointer, PointerArithmetic,
Expand Down Expand Up @@ -583,8 +584,8 @@ where
}

Static(ref static_) => {
let ty = self.monomorphize(static_.ty, self.substs());
let layout = self.layout_of(ty)?;
assert!(!static_.ty.needs_subst());
let layout = self.layout_of(static_.ty)?;
let instance = ty::Instance::mono(*self.tcx, static_.def_id);
let cid = GlobalId {
instance,
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir/interpret/step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
}

NullaryOp(mir::NullOp::SizeOf, ty) => {
let ty = self.monomorphize(ty, self.substs());
let ty = self.monomorphize(ty)?;
let layout = self.layout_of(ty)?;
assert!(!layout.is_unsized(),
"SizeOf nullary MIR operator called for unsized type");
Expand All @@ -260,7 +260,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
}

Cast(kind, ref operand, cast_ty) => {
debug_assert_eq!(self.monomorphize(cast_ty, self.substs()), dest.layout.ty);
debug_assert_eq!(self.monomorphize(cast_ty)?, dest.layout.ty);
let src = self.eval_operand(operand, None)?;
self.cast(src, kind, dest)?;
}
Expand Down
6 changes: 2 additions & 4 deletions src/librustc_mir/transform/const_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use rustc::ty::layout::{

use interpret::{self, EvalContext, ScalarMaybeUndef, Immediate, OpTy, MemoryKind};
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,
};
use transform::{MirPass, MirSource};
Expand Down Expand Up @@ -110,9 +110,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
source: MirSource,
) -> ConstPropagator<'a, 'mir, 'tcx> {
let param_env = tcx.param_env(source.def_id);
let substs = Substs::identity_for_item(tcx, source.def_id);
let instance = Instance::new(source.def_id, substs);
let ecx = mk_borrowck_eval_cx(tcx, instance, mir, DUMMY_SP).unwrap();
let ecx = mk_eval_cx(tcx, tcx.def_span(source.def_id), param_env);
ConstPropagator {
ecx,
mir,
Expand Down
Loading