Auto merge of #59369 - oli-obk:unwrap_usICE, r=eddyb,nikomatsakis

`unwrap_usize` should at least try to evaluate the underlying constant

r? @eddyb

fixes #59016

I know that I'm still using `ParamEnv` wrongly, but that's a preexisting issue not amplified by this PR.
This commit is contained in:
bors 2019-08-05 19:06:50 +00:00
commit c4715198b5
53 changed files with 298 additions and 142 deletions

View File

@ -340,6 +340,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
ambient_variance,
needs_wf: false,
root_ty: ty,
param_env: self.param_env,
};
let ty = match generalize.relate(&ty, &ty) {
@ -379,6 +380,8 @@ struct Generalizer<'cx, 'tcx> {
/// The root type that we are generalizing. Used when reporting cycles.
root_ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>,
}
/// Result from a generalization operation. This includes
@ -419,6 +422,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env }
fn tag(&self) -> &'static str {
"Generalizer"

View File

@ -30,6 +30,8 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> { self.fields.tcx() }
fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env }
fn a_is_expected(&self) -> bool { self.a_is_expected }
fn relate_item_substs(&mut self,

View File

@ -27,6 +27,8 @@ impl TypeRelation<'tcx> for Glb<'combine, 'infcx, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> { self.fields.tcx() }
fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env }
fn a_is_expected(&self) -> bool { self.a_is_expected }
fn relate_with_variance<T: Relate<'tcx>>(&mut self,

View File

@ -27,6 +27,8 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> { self.fields.tcx() }
fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env }
fn a_is_expected(&self) -> bool { self.a_is_expected }
fn relate_with_variance<T: Relate<'tcx>>(&mut self,

View File

@ -502,6 +502,9 @@ where
self.infcx.tcx
}
// FIXME(oli-obk): not sure how to get the correct ParamEnv
fn param_env(&self) -> ty::ParamEnv<'tcx> { ty::ParamEnv::empty() }
fn tag(&self) -> &'static str {
"nll::subtype"
}
@ -831,6 +834,9 @@ where
self.infcx.tcx
}
// FIXME(oli-obk): not sure how to get the correct ParamEnv
fn param_env(&self) -> ty::ParamEnv<'tcx> { ty::ParamEnv::empty() }
fn tag(&self) -> &'static str {
"nll::generalizer"
}

View File

@ -27,7 +27,7 @@ use crate::ty::{self, Ty};
/// interested in the `OutlivesEnvironment`. -nmatsakis
#[derive(Clone)]
pub struct OutlivesEnvironment<'tcx> {
param_env: ty::ParamEnv<'tcx>,
pub param_env: ty::ParamEnv<'tcx>,
free_region_map: FreeRegionMap<'tcx>,
// Contains, for each body B that we are checking (that is, the fn

View File

@ -35,6 +35,9 @@ impl<'combine, 'infcx, 'tcx> Sub<'combine, 'infcx, 'tcx> {
impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> {
fn tag(&self) -> &'static str { "Sub" }
fn tcx(&self) -> TyCtxt<'tcx> { self.fields.infcx.tcx }
fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env }
fn a_is_expected(&self) -> bool { self.a_is_expected }
fn with_cause<F,R>(&mut self, cause: Cause, f: F) -> R

View File

@ -277,6 +277,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
) -> Self {
ExprUseVisitor {
mc: mc::MemCategorizationContext::new(tcx,
param_env,
body_owner,
region_scope_tree,
tables,
@ -299,6 +300,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
ExprUseVisitor {
mc: mc::MemCategorizationContext::with_infer(
infcx,
param_env,
body_owner,
region_scope_tree,
tables,

View File

@ -214,6 +214,7 @@ impl HirNode for hir::Pat {
#[derive(Clone)]
pub struct MemCategorizationContext<'a, 'tcx> {
pub tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
pub body_owner: DefId,
pub upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
pub region_scope_tree: &'a region::ScopeTree,
@ -330,6 +331,7 @@ impl MutabilityCategory {
impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
pub fn new(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_owner: DefId,
region_scope_tree: &'a region::ScopeTree,
tables: &'a ty::TypeckTables<'tcx>,
@ -342,7 +344,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
region_scope_tree,
tables,
rvalue_promotable_map,
infcx: None
infcx: None,
param_env,
}
}
}
@ -359,6 +362,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
/// known, the results around upvar accesses may be incorrect.
pub fn with_infer(
infcx: &'a InferCtxt<'a, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_owner: DefId,
region_scope_tree: &'a region::ScopeTree,
tables: &'a ty::TypeckTables<'tcx>,
@ -379,6 +383,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
tables,
rvalue_promotable_map,
infcx: Some(infcx),
param_env,
}
}
@ -896,7 +901,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
// Always promote `[T; 0]` (even when e.g., borrowed mutably).
let promotable = match expr_ty.sty {
ty::Array(_, len) if len.assert_usize(self.tcx) == Some(0) => true,
ty::Array(_, len) if len.try_eval_usize(self.tcx, self.param_env) == Some(0) => true,
_ => promotable,
};

View File

@ -57,7 +57,7 @@ impl<'tcx> PlaceTy<'tcx> {
/// `PlaceElem`, where we can just use the `Ty` that is already
/// stored inline on field projection elems.
pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: &PlaceElem<'tcx>) -> PlaceTy<'tcx> {
self.projection_ty_core(tcx, elem, |_, _, ty| ty)
self.projection_ty_core(tcx, ty::ParamEnv::empty(), elem, |_, _, ty| ty)
}
/// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
@ -68,6 +68,7 @@ impl<'tcx> PlaceTy<'tcx> {
pub fn projection_ty_core<V, T>(
self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
elem: &ProjectionElem<V, T>,
mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>,
) -> PlaceTy<'tcx>
@ -90,7 +91,7 @@ impl<'tcx> PlaceTy<'tcx> {
ProjectionElem::Subslice { from, to } => {
PlaceTy::from_ty(match self.ty.sty {
ty::Array(inner, size) => {
let size = size.unwrap_usize(tcx);
let size = size.eval_usize(tcx, param_env);
let len = size - (from as u64) - (to as u64);
tcx.mk_array(inner, len)
}

View File

@ -417,7 +417,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
Some(format!("[{}]", self.tcx.type_of(def.did).to_string())),
));
let tcx = self.tcx;
if let Some(len) = len.assert_usize(tcx) {
if let Some(len) = len.try_eval_usize(tcx, ty::ParamEnv::empty()) {
flags.push((
sym::_Self,
Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),

View File

@ -1082,7 +1082,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
if unbound_input_types && stack.iter().skip(1).any(|prev| {
stack.obligation.param_env == prev.obligation.param_env
&& self.match_fresh_trait_refs(&stack.fresh_trait_ref, &prev.fresh_trait_ref)
&& self.match_fresh_trait_refs(
&stack.fresh_trait_ref, &prev.fresh_trait_ref, prev.obligation.param_env)
}) {
debug!(
"evaluate_stack({:?}) --> unbound argument, recursive --> giving up",
@ -3798,8 +3799,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&self,
previous: &ty::PolyTraitRef<'tcx>,
current: &ty::PolyTraitRef<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
let mut matcher = ty::_match::Match::new(self.tcx());
let mut matcher = ty::_match::Match::new(self.tcx(), param_env);
matcher.relate(previous, current).is_ok()
}

View File

@ -21,17 +21,19 @@ use crate::mir::interpret::ConstValue;
/// affects any type variables or unification state.
pub struct Match<'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
}
impl Match<'tcx> {
pub fn new(tcx: TyCtxt<'tcx>) -> Match<'tcx> {
Match { tcx }
pub fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Match<'tcx> {
Match { tcx, param_env }
}
}
impl TypeRelation<'tcx> for Match<'tcx> {
fn tag(&self) -> &'static str { "Match" }
fn tcx(&self) -> TyCtxt<'tcx> { self.tcx }
fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env }
fn a_is_expected(&self) -> bool { true } // irrelevant
fn relate_with_variance<T: Relate<'tcx>>(&mut self,

View File

@ -194,7 +194,7 @@ impl<'tcx> ty::TyS<'tcx> {
ty::Foreign(def_id) => format!("extern type `{}`", tcx.def_path_str(def_id)).into(),
ty::Array(_, n) => {
let n = tcx.lift_to_global(&n).unwrap();
match n.assert_usize(tcx) {
match n.try_eval_usize(tcx, ty::ParamEnv::empty()) {
Some(n) => format!("array of {} elements", n).into(),
None => "array".into(),
}

View File

@ -3,6 +3,7 @@ use crate::ty::{AdtDef, VariantDef, FieldDef, Ty, TyS};
use crate::ty::{DefId, SubstsRef};
use crate::ty::{AdtKind, Visibility};
use crate::ty::TyKind::*;
use crate::ty;
pub use self::def_id_forest::DefIdForest;
@ -190,7 +191,7 @@ impl<'tcx> TyS<'tcx> {
}))
}
Array(ty, len) => match len.assert_usize(tcx) {
Array(ty, len) => match len.try_eval_usize(tcx, ty::ParamEnv::empty()) {
// If the array is definitely non-empty, it's uninhabited if
// the type of its elements is uninhabited.
Some(n) if n != 0 => ty.uninhabited_from(tcx),

View File

@ -594,7 +594,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
}
}
let count = count.assert_usize(tcx).ok_or(LayoutError::Unknown(ty))?;
let count = count.try_eval_usize(tcx, param_env).ok_or(LayoutError::Unknown(ty))?;
let element = self.layout_of(element)?;
let size = element.size.checked_mul(count, dl)
.ok_or(LayoutError::SizeOverflow(ty))?;

View File

@ -2357,7 +2357,7 @@ impl<'tcx> AdtDef {
#[inline]
pub fn eval_explicit_discr(&self, tcx: TyCtxt<'tcx>, expr_did: DefId) -> Option<Discr<'tcx>> {
let param_env = ParamEnv::empty();
let param_env = tcx.param_env(expr_did);
let repr_type = self.repr.discr_type();
let substs = InternalSubsts::identity_for_item(tcx.global_tcx(), expr_did);
let instance = ty::Instance::new(expr_did, substs);
@ -2368,7 +2368,7 @@ impl<'tcx> AdtDef {
match tcx.const_eval(param_env.and(cid)) {
Ok(val) => {
// FIXME: Find the right type and use it instead of `val.ty` here
if let Some(b) = val.assert_bits(tcx.global_tcx(), param_env.and(val.ty)) {
if let Some(b) = val.try_eval_bits(tcx.global_tcx(), param_env, val.ty) {
trace!("discriminants: {} ({:?})", b, repr_type);
Some(Discr {
val: b,

View File

@ -89,7 +89,8 @@ impl DefPathBasedNames<'tcx> {
ty::Array(inner_type, len) => {
output.push('[');
self.push_type_name(inner_type, output, debug);
write!(output, "; {}", len.unwrap_usize(self.tcx)).unwrap();
let len = len.eval_usize(self.tcx, ty::ParamEnv::reveal_all());
write!(output, "; {}", len).unwrap();
output.push(']');
}
ty::Slice(inner_type) => {

View File

@ -696,7 +696,12 @@ pub trait PrettyPrinter<'tcx>:
},
ty::Array(ty, sz) => {
p!(write("["), print(ty), write("; "));
if let Some(n) = sz.assert_usize(self.tcx()) {
if let ConstValue::Unevaluated(..) = sz.val {
// do not try to evalute unevaluated constants. If we are const evaluating an
// array length anon const, rustc will (with debug assertions) print the
// constant's path. Which will end up here again.
p!(write("_"));
} else if let Some(n) = sz.try_eval_usize(self.tcx(), ty::ParamEnv::empty()) {
p!(write("{}", n));
} else {
p!(write("_"));
@ -915,7 +920,7 @@ pub trait PrettyPrinter<'tcx>:
if let ty::Ref(_, ref_ty, _) = ct.ty.sty {
let byte_str = match (ct.val, &ref_ty.sty) {
(ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => {
let n = n.unwrap_usize(self.tcx());
let n = n.eval_usize(self.tcx(), ty::ParamEnv::empty());
Some(self.tcx()
.alloc_map.lock()
.unwrap_memory(ptr.alloc_id)

View File

@ -25,6 +25,8 @@ pub enum Cause {
pub trait TypeRelation<'tcx>: Sized {
fn tcx(&self) -> TyCtxt<'tcx>;
fn param_env(&self) -> ty::ParamEnv<'tcx>;
/// Returns a static string we can use for printouts.
fn tag(&self) -> &'static str;
@ -466,7 +468,9 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>(
Err(err) => {
// Check whether the lengths are both concrete/known values,
// but are unequal, for better diagnostics.
match (sz_a.assert_usize(tcx), sz_b.assert_usize(tcx)) {
let sz_a = sz_a.try_eval_usize(tcx, relation.param_env());
let sz_b = sz_b.try_eval_usize(tcx, relation.param_env());
match (sz_a, sz_b) {
(Some(sz_a_val), Some(sz_b_val)) => {
Err(TypeError::FixedArraySize(
expected_found(relation, &sz_a_val, &sz_b_val)

View File

@ -15,7 +15,7 @@ use crate::ty::{self, AdtDef, Discr, DefIdTree, TypeFlags, Ty, TyCtxt, TypeFolda
use crate::ty::{List, TyS, ParamEnvAnd, ParamEnv};
use crate::ty::layout::VariantIdx;
use crate::util::captures::Captures;
use crate::mir::interpret::{Scalar, Pointer};
use crate::mir::interpret::{Scalar, GlobalId};
use smallvec::SmallVec;
use std::borrow::Cow;
@ -1726,7 +1726,7 @@ impl<'tcx> TyS<'tcx> {
ty.expect_ty().conservative_is_privately_uninhabited(tcx)
}),
ty::Array(ty, len) => {
match len.assert_usize(tcx) {
match len.try_eval_usize(tcx, ParamEnv::empty()) {
// If the array is definitely non-empty, it's uninhabited if
// the type of its elements is uninhabited.
Some(n) if n != 0 => ty.conservative_is_privately_uninhabited(tcx),
@ -2291,29 +2291,38 @@ impl<'tcx> Const<'tcx> {
}
#[inline]
pub fn to_bits(&self, tcx: TyCtxt<'tcx>, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> Option<u128> {
if self.ty != ty.value {
return None;
pub fn try_eval_bits(
&self,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
ty: Ty<'tcx>,
) -> Option<u128> {
assert_eq!(self.ty, ty);
// if `ty` does not depend on generic parameters, use an empty param_env
let size = tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size;
match self.val {
// FIXME(const_generics): this doesn't work right now,
// because it tries to relate an `Infer` to a `Param`.
ConstValue::Unevaluated(did, substs) => {
// if `substs` has no unresolved components, use and empty param_env
let (param_env, substs) = param_env.with_reveal_all().and(substs).into_parts();
// try to resolve e.g. associated constants to their definition on an impl
let instance = ty::Instance::resolve(tcx, param_env, did, substs)?;
let gid = GlobalId {
instance,
promoted: None,
};
let evaluated = tcx.const_eval(param_env.and(gid)).ok()?;
evaluated.val.try_to_bits(size)
},
// otherwise just extract a `ConstValue`'s bits if possible
_ => self.val.try_to_bits(size),
}
let size = tcx.layout_of(ty).ok()?.size;
self.val.try_to_bits(size)
}
#[inline]
pub fn to_ptr(&self) -> Option<Pointer> {
self.val.try_to_ptr()
}
#[inline]
pub fn assert_bits(&self, tcx: TyCtxt<'tcx>, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> Option<u128> {
assert_eq!(self.ty, ty.value);
let size = tcx.layout_of(ty).ok()?.size;
self.val.try_to_bits(size)
}
#[inline]
pub fn assert_bool(&self, tcx: TyCtxt<'tcx>) -> Option<bool> {
self.assert_bits(tcx, ParamEnv::empty().and(tcx.types.bool)).and_then(|v| match v {
pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
self.try_eval_bits(tcx, param_env, tcx.types.bool).and_then(|v| match v {
0 => Some(false),
1 => Some(true),
_ => None,
@ -2321,20 +2330,19 @@ impl<'tcx> Const<'tcx> {
}
#[inline]
pub fn assert_usize(&self, tcx: TyCtxt<'tcx>) -> Option<u64> {
self.assert_bits(tcx, ParamEnv::empty().and(tcx.types.usize)).map(|v| v as u64)
pub fn try_eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u64> {
self.try_eval_bits(tcx, param_env, tcx.types.usize).map(|v| v as u64)
}
#[inline]
pub fn unwrap_bits(&self, tcx: TyCtxt<'tcx>, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> u128 {
self.assert_bits(tcx, ty).unwrap_or_else(||
bug!("expected bits of {}, got {:#?}", ty.value, self))
pub fn eval_bits(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
self.try_eval_bits(tcx, param_env, ty).unwrap_or_else(||
bug!("expected bits of {:#?}, got {:#?}", ty, self))
}
#[inline]
pub fn unwrap_usize(&self, tcx: TyCtxt<'tcx>) -> u64 {
self.assert_usize(tcx).unwrap_or_else(||
bug!("expected constant usize, got {:#?}", self))
pub fn eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 {
self.eval_bits(tcx, param_env, tcx.types.usize) as u64
}
}

View File

@ -341,7 +341,7 @@ fn fixed_vec_metadata(
let (size, align) = cx.size_and_align_of(array_or_slice_type);
let upper_bound = match array_or_slice_type.sty {
ty::Array(_, len) => len.unwrap_usize(cx.tcx) as c_longlong,
ty::Array(_, len) => len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong,
_ => -1
};

View File

@ -132,7 +132,7 @@ pub fn unsized_info<'tcx, Cx: CodegenMethods<'tcx>>(
cx.tcx().struct_lockstep_tails_erasing_lifetimes(source, target, cx.param_env());
match (&source.sty, &target.sty) {
(&ty::Array(_, len), &ty::Slice(_)) => {
cx.const_usize(len.unwrap_usize(cx.tcx()))
cx.const_usize(len.eval_usize(cx.tcx(), ty::ParamEnv::reveal_all()))
}
(&ty::Dynamic(..), &ty::Dynamic(..)) => {
// For now, upcasts are limited to changes in marker

View File

@ -89,7 +89,7 @@ pub fn push_debuginfo_type_name<'tcx>(
ty::Array(inner_type, len) => {
output.push('[');
push_debuginfo_type_name(tcx, inner_type, true, output, visited);
output.push_str(&format!("; {}", len.unwrap_usize(tcx)));
output.push_str(&format!("; {}", len.eval_usize(tcx, ty::ParamEnv::reveal_all())));
output.push(']');
},
ty::Slice(inner_type) => {

View File

@ -41,7 +41,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
.map(|c| {
let field_ty = c.ty.builtin_index().unwrap();
let fields = match c.ty.sty {
ty::Array(_, n) => n.unwrap_usize(bx.tcx()),
ty::Array(_, n) => n.eval_usize(bx.tcx(), ty::ParamEnv::reveal_all()),
_ => bug!("invalid simd shuffle type: {}", c.ty),
};
let values: Vec<_> = (0..fields).map(|field| {

View File

@ -521,7 +521,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} = *place {
if let LocalRef::Operand(Some(op)) = self.locals[index] {
if let ty::Array(_, n) = op.layout.ty.sty {
let n = n.unwrap_usize(bx.cx().tcx());
let n = n.eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all());
return bx.cx().const_usize(n);
}
}

View File

@ -512,7 +512,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
}
self = ct.ty.print(self)?;
if let Some(bits) = ct.assert_bits(self.tcx, ty::ParamEnv::empty().and(ct.ty)) {
if let Some(bits) = ct.try_eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty) {
let _ = write!(self.out, "{:x}_", bits);
} else {
// NOTE(eddyb) despite having the path, we need to

View File

@ -208,7 +208,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
}
has_emitted
}
ty::Array(ty, len) => match len.assert_usize(cx.tcx) {
ty::Array(ty, len) => match len.try_eval_usize(cx.tcx, cx.param_env) {
// If the array is definitely non-empty, we can do `#[must_use]` checking.
Some(n) if n != 0 => {
let descr_pre = &format!(

View File

@ -206,7 +206,7 @@ fn do_mir_borrowck<'a, 'tcx>(
def_id,
&attributes,
&dead_unwinds,
Borrows::new(tcx, body, regioncx.clone(), &borrow_set),
Borrows::new(tcx, body, param_env, regioncx.clone(), &borrow_set),
|rs, i| DebugFormatted::new(&rs.location(i)),
));
let flow_uninits = FlowAtLocation::new(do_dataflow(
@ -242,6 +242,7 @@ fn do_mir_borrowck<'a, 'tcx>(
infcx,
body,
mir_def_id: def_id,
param_env,
move_data: &mdpe.move_data,
location_table,
movable_generator,
@ -424,6 +425,7 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> {
crate infcx: &'cx InferCtxt<'cx, 'tcx>,
body: &'cx Body<'tcx>,
mir_def_id: DefId,
param_env: ty::ParamEnv<'tcx>,
move_data: &'cx MoveData<'tcx>,
/// Map from MIR `Location` to `LocationIndex`; created
@ -1004,11 +1006,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let mut error_reported = false;
let tcx = self.infcx.tcx;
let body = self.body;
let param_env = self.param_env;
let location_table = self.location_table.start_index(location);
let borrow_set = self.borrow_set.clone();
each_borrow_involving_path(
self,
tcx,
param_env,
body,
location,
(sd, place_span.0),
@ -1480,6 +1484,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if places_conflict::borrow_conflicts_with_place(
self.infcx.tcx,
self.param_env,
self.body,
place,
borrow.kind,

View File

@ -18,6 +18,7 @@ use rustc::ty::subst::SubstsRef;
pub(super) fn generate_constraints<'cx, 'tcx>(
infcx: &InferCtxt<'cx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
liveness_constraints: &mut LivenessValues<RegionVid>,
all_facts: &mut Option<AllFacts>,
location_table: &LocationTable,
@ -31,6 +32,7 @@ pub(super) fn generate_constraints<'cx, 'tcx>(
location_table,
all_facts,
body,
param_env,
};
for (bb, data) in body.basic_blocks().iter_enumerated() {
@ -41,6 +43,7 @@ pub(super) fn generate_constraints<'cx, 'tcx>(
/// 'cg = the duration of the constraint generation process itself.
struct ConstraintGeneration<'cg, 'cx, 'tcx> {
infcx: &'cg InferCtxt<'cx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
all_facts: &'cg mut Option<AllFacts>,
location_table: &'cg LocationTable,
liveness_constraints: &'cg mut LivenessValues<RegionVid>,
@ -271,6 +274,7 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
for &borrow_index in borrow_indices {
let places_conflict = places_conflict::places_conflict(
self.infcx.tcx,
self.param_env,
self.body,
&self.borrow_set.borrows[borrow_index].borrowed_place,
place,

View File

@ -9,7 +9,7 @@ use crate::borrow_check::{ReadKind, WriteKind};
use crate::borrow_check::nll::facts::AllFacts;
use crate::borrow_check::path_utils::*;
use crate::dataflow::indexes::BorrowIndex;
use rustc::ty::TyCtxt;
use rustc::ty::{self, TyCtxt};
use rustc::mir::visit::Visitor;
use rustc::mir::{BasicBlock, Location, Body, Place, Rvalue};
use rustc::mir::{Statement, StatementKind};
@ -19,6 +19,7 @@ use rustc_data_structures::graph::dominators::Dominators;
pub(super) fn generate_invalidates<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
all_facts: &mut Option<AllFacts>,
location_table: &LocationTable,
body: &Body<'tcx>,
@ -34,6 +35,7 @@ pub(super) fn generate_invalidates<'tcx>(
let mut ig = InvalidationGenerator {
all_facts,
borrow_set,
param_env,
tcx,
location_table,
body,
@ -45,6 +47,7 @@ pub(super) fn generate_invalidates<'tcx>(
struct InvalidationGenerator<'cx, 'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
all_facts: &'cx mut AllFacts,
location_table: &'cx LocationTable,
body: &'cx Body<'tcx>,
@ -401,11 +404,13 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
);
let tcx = self.tcx;
let body = self.body;
let param_env = self.param_env;
let borrow_set = self.borrow_set.clone();
let indices = self.borrow_set.borrows.indices();
each_borrow_involving_path(
self,
tcx,
param_env,
body,
location,
(sd, place),

View File

@ -138,6 +138,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
constraint_generation::generate_constraints(
infcx,
param_env,
&mut liveness_constraints,
&mut all_facts,
location_table,
@ -162,6 +163,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
// Generate various additional constraints.
invalidation::generate_invalidates(
infcx.tcx,
param_env,
&mut all_facts,
location_table,
&body,

View File

@ -669,7 +669,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
ProjectionElem::Subslice { from, to } => PlaceTy::from_ty(
match base_ty.sty {
ty::Array(inner, size) => {
let size = size.unwrap_usize(tcx);
let size = size.eval_usize(tcx, self.cx.param_env);
let min_size = (from as u64) + (to as u64);
if let Some(rest_size) = size.checked_sub(min_size) {
tcx.mk_array(inner, rest_size)
@ -1214,10 +1214,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let tcx = self.infcx.tcx;
for proj in &user_ty.projs {
let projected_ty = curr_projected_ty.projection_ty_core(tcx, proj, |this, field, &()| {
let ty = this.field_ty(tcx, field);
self.normalize(ty, locations)
});
let projected_ty = curr_projected_ty.projection_ty_core(
tcx,
self.param_env,
proj,
|this, field, &()| {
let ty = this.field_ty(tcx, field);
self.normalize(ty, locations)
},
);
curr_projected_ty = projected_ty;
}
debug!("user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}",

View File

@ -4,7 +4,7 @@ use crate::borrow_check::AccessDepth;
use crate::dataflow::indexes::BorrowIndex;
use rustc::mir::{BasicBlock, Location, Body, Place, PlaceBase};
use rustc::mir::{ProjectionElem, BorrowKind};
use rustc::ty::TyCtxt;
use rustc::ty::{self, TyCtxt};
use rustc_data_structures::graph::dominators::Dominators;
/// Returns `true` if the borrow represented by `kind` is
@ -25,6 +25,7 @@ pub(super) enum Control {
pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
s: &mut S,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
_location: Location,
access_place: (AccessDepth, &Place<'tcx>),
@ -47,6 +48,7 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
if places_conflict::borrow_conflicts_with_place(
tcx,
param_env,
body,
&borrowed.borrowed_place,
borrowed.kind,

View File

@ -26,6 +26,7 @@ crate enum PlaceConflictBias {
/// dataflow).
crate fn places_conflict<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
borrow_place: &Place<'tcx>,
access_place: &Place<'tcx>,
@ -33,6 +34,7 @@ crate fn places_conflict<'tcx>(
) -> bool {
borrow_conflicts_with_place(
tcx,
param_env,
body,
borrow_place,
BorrowKind::Mut { allow_two_phase_borrow: true },
@ -48,6 +50,7 @@ crate fn places_conflict<'tcx>(
/// order to make the conservative choice and preserve soundness.
pub(super) fn borrow_conflicts_with_place<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
borrow_place: &Place<'tcx>,
borrow_kind: BorrowKind,
@ -78,6 +81,7 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
access_place.iterate(|access_base, access_projections| {
place_components_conflict(
tcx,
param_env,
body,
(borrow_base, borrow_projections),
borrow_kind,
@ -91,6 +95,7 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
fn place_components_conflict<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body: &Body<'tcx>,
borrow_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>),
borrow_kind: BorrowKind,
@ -143,7 +148,7 @@ fn place_components_conflict<'tcx>(
let borrow_base = borrow_projections.0;
let access_base = access_projections.0;
match place_base_conflict(tcx, borrow_base, access_base) {
match place_base_conflict(tcx, param_env, borrow_base, access_base) {
Overlap::Arbitrary => {
bug!("Two base can't return Arbitrary");
}
@ -306,6 +311,7 @@ fn place_components_conflict<'tcx>(
// between `elem1` and `elem2`.
fn place_base_conflict<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
elem1: &PlaceBase<'tcx>,
elem2: &PlaceBase<'tcx>,
) -> Overlap {
@ -339,7 +345,7 @@ fn place_base_conflict<'tcx>(
(StaticKind::Promoted(promoted_1), StaticKind::Promoted(promoted_2)) => {
if promoted_1 == promoted_2 {
if let ty::Array(_, len) = s1.ty.sty {
if let Some(0) = len.assert_usize(tcx) {
if let Some(0) = len.try_eval_usize(tcx, param_env) {
// Ignore conflicts with promoted [T; 0].
debug!("place_element_conflict: IGNORE-LEN-0-PROMOTED");
return Overlap::Disjoint;

View File

@ -109,10 +109,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
match *match_pair.pattern.kind {
PatternKind::Constant { value } => {
let switch_ty = ty::ParamEnv::empty().and(switch_ty);
indices.entry(value)
.or_insert_with(|| {
options.push(value.unwrap_bits(self.hir.tcx(), switch_ty));
options.push(value.eval_bits(
self.hir.tcx(), self.hir.param_env, switch_ty,
));
options.len() - 1
});
true
@ -653,11 +654,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
use std::cmp::Ordering::*;
use rustc::hir::RangeEnd::*;
let param_env = ty::ParamEnv::empty().and(test.ty);
let tcx = self.hir.tcx();
let lo = compare_const_vals(tcx, test.lo, pat.hi, param_env)?;
let hi = compare_const_vals(tcx, test.hi, pat.lo, param_env)?;
let lo = compare_const_vals(tcx, test.lo, pat.hi, self.hir.param_env, test.ty)?;
let hi = compare_const_vals(tcx, test.hi, pat.lo, self.hir.param_env, test.ty)?;
match (test.end, pat.end, lo, hi) {
// pat < test
@ -772,11 +772,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
) -> Option<bool> {
use std::cmp::Ordering::*;
let param_env = ty::ParamEnv::empty().and(range.ty);
let tcx = self.hir.tcx();
let a = compare_const_vals(tcx, range.lo, value, param_env)?;
let b = compare_const_vals(tcx, value, range.hi, param_env)?;
let a = compare_const_vals(tcx, range.lo, value, self.hir.param_env, range.ty)?;
let b = compare_const_vals(tcx, value, range.hi, self.hir.param_env, range.ty)?;
match (b, range.end) {
(Less, _) |

View File

@ -2,7 +2,7 @@ use crate::borrow_check::borrow_set::{BorrowSet, BorrowData};
use crate::borrow_check::place_ext::PlaceExt;
use rustc::mir::{self, Location, Place, PlaceBase, Body};
use rustc::ty::TyCtxt;
use rustc::ty::{self, TyCtxt};
use rustc::ty::RegionVid;
use rustc_data_structures::bit_set::BitSet;
@ -32,6 +32,7 @@ newtype_index! {
pub struct Borrows<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
body: &'a Body<'tcx>,
param_env: ty::ParamEnv<'tcx>,
borrow_set: Rc<BorrowSet<'tcx>>,
borrows_out_of_scope_at_location: FxHashMap<Location, Vec<BorrowIndex>>,
@ -137,6 +138,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
crate fn new(
tcx: TyCtxt<'tcx>,
body: &'a Body<'tcx>,
param_env: ty::ParamEnv<'tcx>,
nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
borrow_set: &Rc<BorrowSet<'tcx>>,
) -> Self {
@ -153,6 +155,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
Borrows {
tcx: tcx,
body: body,
param_env,
borrow_set: borrow_set.clone(),
borrows_out_of_scope_at_location,
_nonlexical_regioncx: nonlexical_regioncx,
@ -218,6 +221,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
.filter(|&&i| {
places_conflict::places_conflict(
self.tcx,
self.param_env,
self.body,
&self.borrow_set.borrows[i].borrowed_place,
place,

View File

@ -556,7 +556,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
};
let span = cx.tcx.def_span(def_id);
let count = match cx.tcx.at(span).const_eval(cx.param_env.and(global_id)) {
Ok(cv) => cv.unwrap_usize(cx.tcx),
Ok(cv) => cv.eval_usize(cx.tcx, cx.param_env),
Err(ErrorHandled::Reported) => 0,
Err(ErrorHandled::TooGeneric) => {
cx.tcx.sess.span_err(span, "array lengths can't depend on generic parameters");

View File

@ -228,7 +228,7 @@ impl LiteralExpander<'tcx> {
ConstValue::Slice {
data: self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id),
start: p.offset.bytes().try_into().unwrap(),
end: n.unwrap_usize(self.tcx).try_into().unwrap(),
end: n.eval_usize(self.tcx, ty::ParamEnv::empty()).try_into().unwrap(),
}
},
// fat pointers stay the same
@ -646,8 +646,8 @@ fn all_constructors<'a, 'tcx>(
ConstantValue(ty::Const::from_bool(cx.tcx, b))
}).collect()
}
ty::Array(ref sub_ty, len) if len.assert_usize(cx.tcx).is_some() => {
let len = len.unwrap_usize(cx.tcx);
ty::Array(ref sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => {
let len = len.eval_usize(cx.tcx, cx.param_env);
if len != 0 && cx.is_uninhabited(sub_ty) {
vec![]
} else {
@ -789,7 +789,7 @@ where
match (value.val, &value.ty.sty) {
(_, ty::Array(_, n)) => max_fixed_len = cmp::max(
max_fixed_len,
n.unwrap_usize(cx.tcx),
n.eval_usize(cx.tcx, cx.param_env),
),
(ConstValue::Slice{ start, end, .. }, ty::Slice(_)) => max_fixed_len = cmp::max(
max_fixed_len,
@ -830,7 +830,11 @@ struct IntRange<'tcx> {
}
impl<'tcx> IntRange<'tcx> {
fn from_ctor(tcx: TyCtxt<'tcx>, ctor: &Constructor<'tcx>) -> Option<IntRange<'tcx>> {
fn from_ctor(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ctor: &Constructor<'tcx>,
) -> Option<IntRange<'tcx>> {
// Floating-point ranges are permitted and we don't want
// to consider them when constructing integer ranges.
fn is_integral(ty: Ty<'_>) -> bool {
@ -856,7 +860,7 @@ impl<'tcx> IntRange<'tcx> {
}
ConstantValue(val) if is_integral(val.ty) => {
let ty = val.ty;
if let Some(val) = val.assert_bits(tcx, ty::ParamEnv::empty().and(ty)) {
if let Some(val) = val.try_eval_bits(tcx, param_env, ty) {
let bias = IntRange::signed_bias(tcx, ty);
let val = val ^ bias;
Some(IntRange { range: val..=val, ty })
@ -868,13 +872,17 @@ impl<'tcx> IntRange<'tcx> {
}
}
fn from_pat(tcx: TyCtxt<'tcx>, mut pat: &Pattern<'tcx>) -> Option<IntRange<'tcx>> {
fn from_pat(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
mut pat: &Pattern<'tcx>,
) -> Option<IntRange<'tcx>> {
let range = loop {
match pat.kind {
box PatternKind::Constant { value } => break ConstantValue(value),
box PatternKind::Range(PatternRange { lo, hi, ty, end }) => break ConstantRange(
lo.to_bits(tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
hi.to_bits(tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
lo.eval_bits(tcx, param_env, ty),
hi.eval_bits(tcx, param_env, ty),
ty,
end,
),
@ -884,7 +892,7 @@ impl<'tcx> IntRange<'tcx> {
_ => return None,
}
};
Self::from_ctor(tcx, &range)
Self::from_ctor(tcx, param_env, &range)
}
// The return value of `signed_bias` should be XORed with an endpoint to encode/decode it.
@ -919,10 +927,11 @@ impl<'tcx> IntRange<'tcx> {
fn subtract_from(
self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ranges: Vec<Constructor<'tcx>>,
) -> Vec<Constructor<'tcx>> {
let ranges = ranges.into_iter().filter_map(|r| {
IntRange::from_ctor(tcx, &r).map(|i| i.range)
IntRange::from_ctor(tcx, param_env, &r).map(|i| i.range)
});
let mut remaining_ranges = vec![];
let ty = self.ty;
@ -989,6 +998,7 @@ enum MissingCtors<'tcx> {
fn compute_missing_ctors<'tcx>(
info: MissingCtorsInfo,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
all_ctors: &Vec<Constructor<'tcx>>,
used_ctors: &Vec<Constructor<'tcx>>,
) -> MissingCtors<'tcx> {
@ -1001,10 +1011,10 @@ fn compute_missing_ctors<'tcx>(
// If a constructor appears in a `match` arm, we can
// eliminate it straight away.
refined_ctors = vec![]
} else if let Some(interval) = IntRange::from_ctor(tcx, used_ctor) {
} else if let Some(interval) = IntRange::from_ctor(tcx, param_env, used_ctor) {
// Refine the required constructors for the type by subtracting
// the range defined by the current constructor pattern.
refined_ctors = interval.subtract_from(tcx, refined_ctors);
refined_ctors = interval.subtract_from(tcx, param_env, refined_ctors);
}
// If the constructor patterns that have been considered so far
@ -1119,7 +1129,9 @@ pub fn is_useful<'p, 'a, 'tcx>(
if is_declared_nonexhaustive {
Useful
} else {
split_grouped_constructors(cx.tcx, constructors, matrix, pcx.ty).into_iter().map(|c|
split_grouped_constructors(
cx.tcx, cx.param_env, constructors, matrix, pcx.ty,
).into_iter().map(|c|
is_useful_specialized(cx, matrix, v, c, pcx.ty, witness)
).find(|result| result.is_useful()).unwrap_or(NotUseful)
}
@ -1158,8 +1170,9 @@ pub fn is_useful<'p, 'a, 'tcx>(
// non-wildcard patterns in the current column. We always determine if
// the set is empty, but we only fully construct them on-demand,
// because they're rarely used and can be big.
let cheap_missing_ctors =
compute_missing_ctors(MissingCtorsInfo::Emptiness, cx.tcx, &all_ctors, &used_ctors);
let cheap_missing_ctors = compute_missing_ctors(
MissingCtorsInfo::Emptiness, cx.tcx, cx.param_env, &all_ctors, &used_ctors,
);
let is_privately_empty = all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
let is_declared_nonexhaustive = cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty);
@ -1172,9 +1185,10 @@ pub fn is_useful<'p, 'a, 'tcx>(
(pcx.ty.is_ptr_sized_integral() && !cx.tcx.features().precise_pointer_size_matching);
if cheap_missing_ctors == MissingCtors::Empty && !is_non_exhaustive {
split_grouped_constructors(cx.tcx, all_ctors, matrix, pcx.ty).into_iter().map(|c| {
is_useful_specialized(cx, matrix, v, c, pcx.ty, witness)
}).find(|result| result.is_useful()).unwrap_or(NotUseful)
split_grouped_constructors(cx.tcx, cx.param_env, all_ctors, matrix, pcx.ty)
.into_iter().map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness))
.find(|result| result.is_useful())
.unwrap_or(NotUseful)
} else {
let matrix = rows.iter().filter_map(|r| {
if r[0].is_wildcard() {
@ -1242,9 +1256,9 @@ pub fn is_useful<'p, 'a, 'tcx>(
witness
}).collect()
} else {
let expensive_missing_ctors =
compute_missing_ctors(MissingCtorsInfo::Ctors, cx.tcx, &all_ctors,
&used_ctors);
let expensive_missing_ctors = compute_missing_ctors(
MissingCtorsInfo::Ctors, cx.tcx, cx.param_env, &all_ctors, &used_ctors,
);
if let MissingCtors::Ctors(missing_ctors) = expensive_missing_ctors {
pats.into_iter().flat_map(|witness| {
missing_ctors.iter().map(move |ctor| {
@ -1327,14 +1341,14 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>,
PatternKind::Constant { value } => Some(vec![ConstantValue(value)]),
PatternKind::Range(PatternRange { lo, hi, ty, end }) =>
Some(vec![ConstantRange(
lo.to_bits(cx.tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
hi.to_bits(cx.tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
lo.eval_bits(cx.tcx, cx.param_env, ty),
hi.eval_bits(cx.tcx, cx.param_env, ty),
ty,
end,
)]),
PatternKind::Array { .. } => match pcx.ty.sty {
ty::Array(_, length) => Some(vec![
Slice(length.unwrap_usize(cx.tcx))
Slice(length.eval_usize(cx.tcx, cx.param_env))
]),
_ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty)
},
@ -1402,7 +1416,8 @@ fn constructor_sub_pattern_tys<'a, 'tcx>(
match ty.sty {
// If the field type returned is an array of an unknown
// size return an TyErr.
ty::Array(_, len) if len.assert_usize(cx.tcx).is_none() =>
ty::Array(_, len)
if len.try_eval_usize(cx.tcx, cx.param_env).is_none() =>
cx.tcx.types.err,
_ => ty,
}
@ -1432,11 +1447,12 @@ fn slice_pat_covered_by_const<'tcx>(
prefix: &[Pattern<'tcx>],
slice: &Option<Pattern<'tcx>>,
suffix: &[Pattern<'tcx>],
param_env: ty::ParamEnv<'tcx>,
) -> Result<bool, ErrorReported> {
let data: &[u8] = match (const_val.val, &const_val.ty.sty) {
(ConstValue::ByRef { offset, alloc, .. }, ty::Array(t, n)) => {
assert_eq!(*t, tcx.types.u8);
let n = n.assert_usize(tcx).unwrap();
let n = n.eval_usize(tcx, param_env);
let ptr = Pointer::new(AllocId(0), offset);
alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
},
@ -1464,7 +1480,7 @@ fn slice_pat_covered_by_const<'tcx>(
{
match pat.kind {
box PatternKind::Constant { value } => {
let b = value.unwrap_bits(tcx, ty::ParamEnv::empty().and(pat.ty));
let b = value.eval_bits(tcx, param_env, pat.ty);
assert_eq!(b as u8 as u128, b);
if b as u8 != *ch {
return Ok(false);
@ -1526,6 +1542,7 @@ fn should_treat_range_exhaustively(tcx: TyCtxt<'tcx>, ctor: &Constructor<'tcx>)
/// merging operation depicted above.)
fn split_grouped_constructors<'p, 'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ctors: Vec<Constructor<'tcx>>,
&Matrix(ref m): &Matrix<'p, 'tcx>,
ty: Ty<'tcx>,
@ -1540,7 +1557,7 @@ fn split_grouped_constructors<'p, 'tcx>(
// We only care about finding all the subranges within the range of the constructor
// range. Anything else is irrelevant, because it is guaranteed to result in
// `NotUseful`, which is the default case anyway, and can be ignored.
let ctor_range = IntRange::from_ctor(tcx, &ctor).unwrap();
let ctor_range = IntRange::from_ctor(tcx, param_env, &ctor).unwrap();
/// Represents a border between 2 integers. Because the intervals spanning borders
/// must be able to cover every integer, we need to be able to represent
@ -1565,7 +1582,7 @@ fn split_grouped_constructors<'p, 'tcx>(
// `borders` is the set of borders between equivalence classes: each equivalence
// class lies between 2 borders.
let row_borders = m.iter()
.flat_map(|row| IntRange::from_pat(tcx, row[0]))
.flat_map(|row| IntRange::from_pat(tcx, param_env, row[0]))
.flat_map(|range| ctor_range.intersection(&range))
.flat_map(|range| range_borders(range));
let ctor_borders = range_borders(ctor_range.clone());
@ -1604,11 +1621,12 @@ fn split_grouped_constructors<'p, 'tcx>(
/// Checks whether there exists any shared value in either `ctor` or `pat` by intersecting them.
fn constructor_intersects_pattern<'p, 'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ctor: &Constructor<'tcx>,
pat: &'p Pattern<'tcx>,
) -> Option<SmallVec<[&'p Pattern<'tcx>; 2]>> {
if should_treat_range_exhaustively(tcx, ctor) {
match (IntRange::from_ctor(tcx, ctor), IntRange::from_pat(tcx, pat)) {
match (IntRange::from_ctor(tcx, param_env, ctor), IntRange::from_pat(tcx, param_env, pat)) {
(Some(ctor), Some(pat)) => {
ctor.intersection(&pat).map(|_| {
let (pat_lo, pat_hi) = pat.range.into_inner();
@ -1623,7 +1641,7 @@ fn constructor_intersects_pattern<'p, 'tcx>(
// Fallback for non-ranges and ranges that involve floating-point numbers, which are not
// conveniently handled by `IntRange`. For these cases, the constructor may not be a range
// so intersection actually devolves into being covered by the pattern.
match constructor_covered_by_range(tcx, ctor, pat) {
match constructor_covered_by_range(tcx, param_env, ctor, pat) {
Ok(true) => Some(smallvec![]),
Ok(false) | Err(ErrorReported) => None,
}
@ -1632,6 +1650,7 @@ fn constructor_intersects_pattern<'p, 'tcx>(
fn constructor_covered_by_range<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ctor: &Constructor<'tcx>,
pat: &Pattern<'tcx>,
) -> Result<bool, ErrorReported> {
@ -1641,9 +1660,9 @@ fn constructor_covered_by_range<'tcx>(
_ => bug!("`constructor_covered_by_range` called with {:?}", pat),
};
trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty);
let cmp_from = |c_from| compare_const_vals(tcx, c_from, from, ty::ParamEnv::empty().and(ty))
let cmp_from = |c_from| compare_const_vals(tcx, c_from, from, param_env, ty)
.map(|res| res != Ordering::Less);
let cmp_to = |c_to| compare_const_vals(tcx, c_to, to, ty::ParamEnv::empty().and(ty));
let cmp_to = |c_to| compare_const_vals(tcx, c_to, to, param_env, ty);
macro_rules! some_or_ok {
($e:expr) => {
match $e {
@ -1760,7 +1779,7 @@ fn specialize<'p, 'a: 'p, 'tcx>(
ConstValue::ByRef { offset, alloc, .. } => (
alloc,
offset,
n.unwrap_usize(cx.tcx),
n.eval_usize(cx.tcx, cx.param_env),
t,
),
_ => span_bug!(
@ -1821,7 +1840,7 @@ fn specialize<'p, 'a: 'p, 'tcx>(
// If the constructor is a:
// Single value: add a row if the constructor equals the pattern.
// Range: add a row if the constructor contains the pattern.
constructor_intersects_pattern(cx.tcx, constructor, pat)
constructor_intersects_pattern(cx.tcx, cx.param_env, constructor, pat)
}
}
}
@ -1830,7 +1849,7 @@ fn specialize<'p, 'a: 'p, 'tcx>(
// If the constructor is a:
// Single value: add a row if the pattern contains the constructor.
// Range: add a row if the constructor intersects the pattern.
constructor_intersects_pattern(cx.tcx, constructor, pat)
constructor_intersects_pattern(cx.tcx, cx.param_env, constructor, pat)
}
PatternKind::Array { ref prefix, ref slice, ref suffix } |
@ -1854,7 +1873,9 @@ fn specialize<'p, 'a: 'p, 'tcx>(
}
}
ConstantValue(cv) => {
match slice_pat_covered_by_const(cx.tcx, pat.span, cv, prefix, slice, suffix) {
match slice_pat_covered_by_const(
cx.tcx, pat.span, cv, prefix, slice, suffix, cx.param_env,
) {
Ok(true) => Some(smallvec![]),
Ok(false) => None,
Err(ErrorReported) => None

View File

@ -446,7 +446,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
self.tcx,
lo,
hi,
self.param_env.and(ty),
self.param_env,
ty,
);
match (end, cmp) {
(RangeEnd::Excluded, Some(Ordering::Less)) =>
@ -728,7 +729,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
ty::Array(_, len) => {
// fixed-length array
let len = len.unwrap_usize(self.tcx);
let len = len.eval_usize(self.tcx, self.param_env);
assert!(len >= prefix.len() as u64 + suffix.len() as u64);
PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix }
}
@ -1123,7 +1124,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
}
ty::Array(_, n) => {
PatternKind::Array {
prefix: (0..n.unwrap_usize(self.tcx))
prefix: (0..n.eval_usize(self.tcx, self.param_env))
.map(|i| adt_subpattern(i as usize, None))
.collect(),
slice: None,
@ -1206,7 +1207,8 @@ fn search_for_adt_without_structural_match<'tcx>(tcx: TyCtxt<'tcx>,
// (But still tell caller to continue search.)
return false;
}
ty::Array(_, n) if n.assert_usize(self.tcx) == Some(0) => {
ty::Array(_, n) if n.try_eval_usize(self.tcx, ty::ParamEnv::reveal_all()) == Some(0)
=> {
// rust-lang/rust#62336: ignore type of contents
// for empty array.
return false;
@ -1451,7 +1453,8 @@ pub fn compare_const_vals<'tcx>(
tcx: TyCtxt<'tcx>,
a: &'tcx ty::Const<'tcx>,
b: &'tcx ty::Const<'tcx>,
ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
) -> Option<Ordering> {
trace!("compare_const_vals: {:?}, {:?}", a, b);
@ -1466,15 +1469,16 @@ pub fn compare_const_vals<'tcx>(
let fallback = || from_bool(a == b);
// Use the fallback if any type differs
if a.ty != b.ty || a.ty != ty.value {
if a.ty != b.ty || a.ty != ty {
return fallback();
}
// FIXME: This should use assert_bits(ty) instead of use_bits
// but triggers possibly bugs due to mismatching of arrays and slices
if let (Some(a), Some(b)) = (a.to_bits(tcx, ty), b.to_bits(tcx, ty)) {
let a_bits = a.try_eval_bits(tcx, param_env, ty);
let b_bits = b.try_eval_bits(tcx, param_env, ty);
if let (Some(a), Some(b)) = (a_bits, b_bits) {
use ::rustc_apfloat::Float;
return match ty.value.sty {
return match ty.sty {
ty::Float(ast::FloatTy::F32) => {
let l = ::rustc_apfloat::ieee::Single::from_bits(a);
let r = ::rustc_apfloat::ieee::Single::from_bits(b);
@ -1497,7 +1501,7 @@ pub fn compare_const_vals<'tcx>(
}
}
if let ty::Str = ty.value.sty {
if let ty::Str = ty.sty {
match (a.val, b.val) {
(
ConstValue::Slice { data: alloc_a, start: offset_a, end: end_a },

View File

@ -253,7 +253,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// u64 cast is from usize to u64, which is always good
let val = Immediate::new_slice(
ptr,
length.unwrap_usize(self.tcx.tcx),
length.eval_usize(self.tcx.tcx, self.param_env),
self,
);
self.write_immediate(val, dest)

View File

@ -176,7 +176,8 @@ for
(InternMode::ConstBase, hir::Mutability::MutMutable) |
(InternMode::Const, hir::Mutability::MutMutable) => {
match referenced_ty.sty {
ty::Array(_, n) if n.unwrap_usize(self.ecx.tcx.tcx) == 0 => {}
ty::Array(_, n)
if n.eval_usize(self.ecx.tcx.tcx, self.param_env) == 0 => {}
ty::Slice(_)
if value.to_meta().unwrap().unwrap().to_usize(self.ecx)? == 0 => {}
_ => bug!("const qualif failed to prevent mutable references"),

View File

@ -304,8 +304,10 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
debug!("build_clone_shim(def_id={:?})", def_id);
let param_env = tcx.param_env(def_id);
let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
let is_copy = self_ty.is_copy_modulo_regions(tcx, tcx.param_env(def_id), builder.span);
let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env, builder.span);
let dest = Place::RETURN_PLACE;
let src = Place::from(Local::new(1+0)).deref();
@ -313,7 +315,7 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -
match self_ty.sty {
_ if is_copy => builder.copy_shim(),
ty::Array(ty, len) => {
let len = len.unwrap_usize(tcx);
let len = len.eval_usize(tcx, param_env);
builder.array_shim(dest, src, ty, len)
}
ty::Closure(def_id, substs) => {

View File

@ -367,7 +367,7 @@ impl Qualif for HasMutInterior {
} else if let ty::Array(_, len) = ty.sty {
// FIXME(eddyb) the `cx.mode == Mode::NonConstFn` condition
// seems unnecessary, given that this is merely a ZST.
match len.assert_usize(cx.tcx) {
match len.try_eval_usize(cx.tcx, cx.param_env) {
Some(0) if cx.mode == Mode::NonConstFn => {},
_ => return true,
}

View File

@ -1,6 +1,6 @@
//! A pass that simplifies branches when their condition is known.
use rustc::ty::{TyCtxt, ParamEnv};
use rustc::ty::TyCtxt;
use rustc::mir::*;
use crate::transform::{MirPass, MirSource};
@ -19,15 +19,15 @@ impl MirPass for SimplifyBranches {
Cow::Borrowed(&self.label)
}
fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) {
fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
let param_env = tcx.param_env(src.def_id());
for block in body.basic_blocks_mut() {
let terminator = block.terminator_mut();
terminator.kind = match terminator.kind {
TerminatorKind::SwitchInt {
discr: Operand::Constant(ref c), switch_ty, ref values, ref targets, ..
} => {
let switch_ty = ParamEnv::empty().and(switch_ty);
let constant = c.literal.assert_bits(tcx, switch_ty);
let constant = c.literal.try_eval_bits(tcx, param_env, switch_ty);
if let Some(constant) = constant {
let (otherwise, targets) = targets.split_last().unwrap();
let mut ret = TerminatorKind::Goto { target: *otherwise };
@ -44,7 +44,7 @@ impl MirPass for SimplifyBranches {
},
TerminatorKind::Assert {
target, cond: Operand::Constant(ref c), expected, ..
} if (c.literal.assert_bool(tcx) == Some(true)) == expected =>
} if (c.literal.try_eval_bool(tcx, param_env) == Some(true)) == expected =>
TerminatorKind::Goto { target },
TerminatorKind::FalseEdges { real_target, .. } => {
TerminatorKind::Goto { target: real_target }

View File

@ -37,10 +37,11 @@ use crate::util::patch::MirPatch;
pub struct UniformArrayMoveOut;
impl MirPass for UniformArrayMoveOut {
fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) {
fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
let mut patch = MirPatch::new(body);
let param_env = tcx.param_env(src.def_id());
{
let mut visitor = UniformArrayMoveOutVisitor{body, patch: &mut patch, tcx};
let mut visitor = UniformArrayMoveOutVisitor{body, patch: &mut patch, tcx, param_env};
visitor.visit_body(body);
}
patch.apply(body);
@ -51,6 +52,7 @@ struct UniformArrayMoveOutVisitor<'a, 'tcx> {
body: &'a Body<'tcx>,
patch: &'a mut MirPatch<'tcx>,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
}
impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
@ -68,7 +70,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
let place_ty =
Place::ty_from(&src_place.base, &proj.base, self.body, self.tcx).ty;
if let ty::Array(item_ty, const_size) = place_ty.sty {
if let Some(size) = const_size.assert_usize(self.tcx) {
if let Some(size) = const_size.try_eval_usize(self.tcx, self.param_env) {
assert!(size <= u32::max_value() as u64,
"uniform array move out doesn't supported
for array bigger then u32");
@ -183,8 +185,9 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
pub struct RestoreSubsliceArrayMoveOut;
impl MirPass for RestoreSubsliceArrayMoveOut {
fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) {
fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) {
let mut patch = MirPatch::new(body);
let param_env = tcx.param_env(src.def_id());
{
let mut visitor = RestoreDataCollector {
locals_use: IndexVec::from_elem(LocalUse::new(), &body.local_decls),
@ -219,7 +222,7 @@ impl MirPass for RestoreSubsliceArrayMoveOut {
let src_ty =
Place::ty_from(src_place.base, src_place.projection, body, tcx).ty;
if let ty::Array(_, ref size_o) = src_ty.sty {
size_o.assert_usize(tcx)
size_o.try_eval_usize(tcx, param_env)
} else {
None
}

View File

@ -821,7 +821,7 @@ where
self.complete_drop(Some(DropFlagMode::Deep), succ, unwind)
}
ty::Array(ety, size) => {
let size = size.assert_usize(self.tcx());
let size = size.try_eval_usize(self.tcx(), self.elaborator.param_env());
self.open_drop_for_array(ety, size)
},
ty::Slice(ety) => self.open_drop_for_array(ety, None),

View File

@ -174,6 +174,11 @@ impl TypeRelation<'tcx> for AnswerSubstitutor<'cx, 'tcx> {
self.infcx.tcx
}
fn param_env(&self) -> ty::ParamEnv<'tcx> {
// FIXME(oli-obk): learn chalk and create param envs
ty::ParamEnv::empty()
}
fn tag(&self) -> &'static str {
"chalk_context::answer_substitutor"
}

View File

@ -423,7 +423,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let expected_ty = self.structurally_resolved_type(pat.span, expected);
let (inner_ty, slice_ty) = match expected_ty.sty {
ty::Array(inner_ty, size) => {
if let Some(size) = size.assert_usize(tcx) {
if let Some(size) = size.try_eval_usize(tcx, self.param_env) {
let min_len = before.len() as u64 + after.len() as u64;
if slice.is_none() {
if min_len != size {

View File

@ -1386,7 +1386,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
ty::Array(_, len) => {
if let (Some(len), Ok(user_index)) = (
len.assert_usize(self.tcx),
len.try_eval_usize(self.tcx, self.param_env),
field.as_str().parse::<u64>()
) {
let base = self.tcx.sess.source_map()

View File

@ -824,6 +824,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
{
f(mc::MemCategorizationContext::with_infer(
&self.infcx,
self.outlives_environment.param_env,
self.body_owner,
&self.region_scope_tree,
&self.tables.borrow(),

View File

@ -0,0 +1,16 @@
// check-pass
fn testfn(_arr: &mut [(); 0]) {}
trait TestTrait {
fn method();
}
impl TestTrait for [(); 0] {
fn method() {
let mut arr: Self = [(); 0];
testfn(&mut arr);
}
}
fn main() {}

View File

@ -0,0 +1,21 @@
// check-pass
trait Gen<T> {
fn gen(x: Self) -> T;
}
struct A;
impl Gen<[(); 0]> for A {
fn gen(x: Self) -> [(); 0] {
[]
}
}
fn array() -> impl Gen<[(); 0]> {
A
}
fn main() {
let [] = Gen::gen(array());
}