Skip to content

Commit

Permalink
Auto merge of #57606 - oli-obk:shrink, r=<try>
Browse files Browse the repository at this point in the history
Get rid of the fake stack frame for reading from constants

r? @RalfJung

fixes the ice in #53708 but still keeps around the wrong "non-exhaustive match" error

cc @varkor
  • Loading branch information
bors committed Jan 15, 2019
2 parents 33e6df4 + b805232 commit c5b89bf
Show file tree
Hide file tree
Showing 12 changed files with 91 additions and 99 deletions.
1 change: 0 additions & 1 deletion src/librustc_codegen_ssa/mir/constant.rs
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
78 changes: 13 additions & 65 deletions src/librustc_mir/const_eval.rs
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,54 +34,6 @@ 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(),
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.
Expand All @@ -91,15 +42,13 @@ fn mk_eval_cx_inner<'a, 'mir, 'tcx>(
/// 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 @@ -108,7 +57,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 @@ -529,13 +479,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 @@ -560,11 +509,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 @@ -584,7 +532,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
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
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
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
42 changes: 31 additions & 11 deletions src/librustc_mir/interpret/eval_context.rs
Expand Up @@ -214,11 +214,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 @@ -228,13 +238,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 @@ -274,6 +280,20 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
}
}

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

pub fn monomorphize<T: TypeFoldable<'tcx> + Subst<'tcx>>(
&self,
t: T,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/interpret/operand.rs
Expand Up @@ -514,7 +514,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_in_frame(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
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
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_in_frame(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_in_frame(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
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
10 changes: 10 additions & 0 deletions src/test/ui/consts/match_ice.rs
@@ -0,0 +1,10 @@
// https://github.com/rust-lang/rust/issues/53708

struct S;

fn main() {
const C: &S = &S;
match C { //~ ERROR non-exhaustive
C => {} // this is a common bug around constants and references in patterns
}
}
9 changes: 9 additions & 0 deletions src/test/ui/consts/match_ice.stderr
@@ -0,0 +1,9 @@
error[E0004]: non-exhaustive patterns: `&S` not covered
--> $DIR/match_ice.rs:7:11
|
LL | match C { //~ ERROR non-exhaustive
| ^ pattern `&S` not covered

error: aborting due to previous error

For more information about this error, try `rustc --explain E0004`.

0 comments on commit c5b89bf

Please sign in to comment.