Promoteds are statics and statics have a place, not just a value
This commit is contained in:
parent
210d61f05c
commit
de511438cd
@ -302,6 +302,9 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::Place<'gcx> {
|
||||
mir::Place::Static(ref statik) => {
|
||||
statik.hash_stable(hcx, hasher);
|
||||
}
|
||||
mir::Place::Promoted(ref promoted) => {
|
||||
promoted.hash_stable(hcx, hasher);
|
||||
}
|
||||
mir::Place::Projection(ref place_projection) => {
|
||||
place_projection.hash_stable(hcx, hasher);
|
||||
}
|
||||
@ -527,22 +530,6 @@ impl_stable_hash_for!(enum mir::NullOp {
|
||||
|
||||
impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal });
|
||||
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::Literal<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
match *self {
|
||||
mir::Literal::Value { ref value } => {
|
||||
value.hash_stable(hcx, hasher);
|
||||
}
|
||||
mir::Literal::Promoted { index } => {
|
||||
index.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(struct mir::Location { block, statement_index });
|
||||
|
||||
impl_stable_hash_for!(struct mir::BorrowCheckResult<'tcx> {
|
||||
|
@ -1701,6 +1701,9 @@ pub enum Place<'tcx> {
|
||||
/// static or static mut variable
|
||||
Static(Box<Static<'tcx>>),
|
||||
|
||||
/// Constant code promoted to an injected static
|
||||
Promoted(Box<(Promoted, Ty<'tcx>)>),
|
||||
|
||||
/// projection out of a place (access a field, deref a pointer, etc)
|
||||
Projection(Box<PlaceProjection<'tcx>>),
|
||||
}
|
||||
@ -1810,6 +1813,7 @@ impl<'tcx> Debug for Place<'tcx> {
|
||||
ty::tls::with(|tcx| tcx.item_path_str(def_id)),
|
||||
ty
|
||||
),
|
||||
Promoted(ref promoted) => write!(fmt, "({:?}: {:?})", promoted.0, promoted.1),
|
||||
Projection(ref data) => match data.elem {
|
||||
ProjectionElem::Downcast(ref adt_def, index) => {
|
||||
write!(fmt, "({:?} as {})", data.base, adt_def.variants[index].name)
|
||||
@ -1910,9 +1914,7 @@ impl<'tcx> Operand<'tcx> {
|
||||
Operand::Constant(box Constant {
|
||||
span,
|
||||
ty,
|
||||
literal: Literal::Value {
|
||||
value: ty::Const::zero_sized(tcx, ty),
|
||||
},
|
||||
literal: ty::Const::zero_sized(tcx, ty),
|
||||
})
|
||||
}
|
||||
|
||||
@ -2200,38 +2202,15 @@ impl<'tcx> Debug for Rvalue<'tcx> {
|
||||
pub struct Constant<'tcx> {
|
||||
pub span: Span,
|
||||
pub ty: Ty<'tcx>,
|
||||
pub literal: Literal<'tcx>,
|
||||
pub literal: &'tcx ty::Const<'tcx>,
|
||||
}
|
||||
|
||||
newtype_index!(Promoted { DEBUG_FORMAT = "promoted[{}]" });
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub enum Literal<'tcx> {
|
||||
Value {
|
||||
value: &'tcx ty::Const<'tcx>,
|
||||
},
|
||||
Promoted {
|
||||
// Index into the `promoted` vector of `Mir`.
|
||||
index: Promoted,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'tcx> Debug for Constant<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
||||
write!(fmt, "{:?}", self.literal)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Debug for Literal<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
||||
use self::Literal::*;
|
||||
match *self {
|
||||
Value { value } => {
|
||||
write!(fmt, "const ")?;
|
||||
fmt_const_val(fmt, value)
|
||||
}
|
||||
Promoted { index } => write!(fmt, "{:?}", index),
|
||||
}
|
||||
write!(fmt, "const ")?;
|
||||
fmt_const_val(fmt, self.literal)
|
||||
}
|
||||
}
|
||||
|
||||
@ -2918,20 +2897,3 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
|
||||
self.ty.visit_with(visitor) || self.literal.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for Literal<'tcx> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
match *self {
|
||||
Literal::Value { value } => Literal::Value {
|
||||
value: value.fold_with(folder),
|
||||
},
|
||||
Literal::Promoted { index } => Literal::Promoted { index },
|
||||
}
|
||||
}
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
match *self {
|
||||
Literal::Value { value } => value.visit_with(visitor),
|
||||
Literal::Promoted { .. } => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -113,6 +113,7 @@ impl<'tcx> Place<'tcx> {
|
||||
match *self {
|
||||
Place::Local(index) =>
|
||||
PlaceTy::Ty { ty: local_decls.local_decls()[index].ty },
|
||||
Place::Promoted(ref data) => PlaceTy::Ty { ty: data.1 },
|
||||
Place::Static(ref data) =>
|
||||
PlaceTy::Ty { ty: data.ty },
|
||||
Place::Projection(ref proj) =>
|
||||
|
@ -191,12 +191,6 @@ macro_rules! make_mir_visitor {
|
||||
self.super_constant(constant, location);
|
||||
}
|
||||
|
||||
fn visit_literal(&mut self,
|
||||
literal: & $($mutability)* Literal<'tcx>,
|
||||
location: Location) {
|
||||
self.super_literal(literal, location);
|
||||
}
|
||||
|
||||
fn visit_def_id(&mut self,
|
||||
def_id: & $($mutability)* DefId,
|
||||
_: Location) {
|
||||
@ -648,6 +642,9 @@ macro_rules! make_mir_visitor {
|
||||
Place::Static(ref $($mutability)* static_) => {
|
||||
self.visit_static(static_, context, location);
|
||||
}
|
||||
Place::Promoted(ref $($mutability)* promoted) => {
|
||||
self.visit_ty(& $($mutability)* promoted.1, TyContext::Location(location));
|
||||
},
|
||||
Place::Projection(ref $($mutability)* proj) => {
|
||||
self.visit_projection(proj, context, location);
|
||||
}
|
||||
@ -748,18 +745,7 @@ macro_rules! make_mir_visitor {
|
||||
|
||||
self.visit_span(span);
|
||||
self.visit_ty(ty, TyContext::Location(location));
|
||||
self.visit_literal(literal, location);
|
||||
}
|
||||
|
||||
fn super_literal(&mut self,
|
||||
literal: & $($mutability)* Literal<'tcx>,
|
||||
location: Location) {
|
||||
match *literal {
|
||||
Literal::Value { ref $($mutability)* value } => {
|
||||
self.visit_const(value, location);
|
||||
}
|
||||
Literal::Promoted { index: _ } => {}
|
||||
}
|
||||
self.visit_const(literal, location);
|
||||
}
|
||||
|
||||
fn super_def_id(&mut self, _def_id: & $($mutability)* DefId) {
|
||||
|
@ -242,9 +242,11 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef {
|
||||
g
|
||||
}
|
||||
|
||||
pub fn codegen_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
|
||||
def_id: DefId,
|
||||
is_mutable: bool) {
|
||||
pub fn codegen_static<'a, 'tcx>(
|
||||
cx: &CodegenCx<'a, 'tcx>,
|
||||
def_id: DefId,
|
||||
is_mutable: bool,
|
||||
) {
|
||||
unsafe {
|
||||
let attrs = cx.tcx.codegen_fn_attrs(def_id);
|
||||
|
||||
|
@ -507,14 +507,37 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
||||
// promotes any complex rvalues to constants.
|
||||
if i == 2 && intrinsic.unwrap().starts_with("simd_shuffle") {
|
||||
match *arg {
|
||||
mir::Operand::Copy(mir::Place::Promoted(box(index, ty))) |
|
||||
mir::Operand::Move(mir::Place::Promoted(box(index, ty))) => {
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
let cid = mir::interpret::GlobalId {
|
||||
instance: self.instance,
|
||||
promoted: Some(index),
|
||||
};
|
||||
let c = bx.tcx().const_eval(param_env.and(cid));
|
||||
let (llval, ty) = self.simd_shuffle_indices(
|
||||
&bx,
|
||||
terminator.source_info.span,
|
||||
ty,
|
||||
c,
|
||||
);
|
||||
return OperandRef {
|
||||
val: Immediate(llval),
|
||||
layout: bx.cx.layout_of(ty),
|
||||
};
|
||||
|
||||
},
|
||||
mir::Operand::Copy(_) |
|
||||
mir::Operand::Move(_) => {
|
||||
span_bug!(span, "shuffle indices must be constant");
|
||||
}
|
||||
mir::Operand::Constant(ref constant) => {
|
||||
let c = self.eval_mir_constant(&bx, constant);
|
||||
let (llval, ty) = self.simd_shuffle_indices(
|
||||
&bx,
|
||||
constant,
|
||||
constant.span,
|
||||
constant.ty,
|
||||
c,
|
||||
);
|
||||
return OperandRef {
|
||||
val: Immediate(llval),
|
||||
|
@ -25,6 +25,7 @@ use consts;
|
||||
use type_of::LayoutLlvmExt;
|
||||
use type_::Type;
|
||||
use syntax::ast::Mutability;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
use super::super::callee;
|
||||
use super::FunctionCx;
|
||||
@ -117,13 +118,12 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
|
||||
|
||||
pub fn codegen_static_initializer<'a, 'tcx>(
|
||||
cx: &CodegenCx<'a, 'tcx>,
|
||||
def_id: DefId)
|
||||
-> Result<(ValueRef, &'tcx Allocation), Lrc<ConstEvalErr<'tcx>>>
|
||||
{
|
||||
def_id: DefId,
|
||||
) -> Result<(ValueRef, &'tcx Allocation), Lrc<ConstEvalErr<'tcx>>> {
|
||||
let instance = ty::Instance::mono(cx.tcx, def_id);
|
||||
let cid = GlobalId {
|
||||
instance,
|
||||
promoted: None
|
||||
promoted: None,
|
||||
};
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
let static_ = cx.tcx.const_eval(param_env.and(cid))?;
|
||||
@ -161,28 +161,19 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
||||
bx: &Builder<'a, 'tcx>,
|
||||
constant: &mir::Constant<'tcx>,
|
||||
) -> Result<&'tcx ty::Const<'tcx>, Lrc<ConstEvalErr<'tcx>>> {
|
||||
match constant.literal {
|
||||
mir::Literal::Promoted { index } => {
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
let cid = mir::interpret::GlobalId {
|
||||
instance: self.instance,
|
||||
promoted: Some(index),
|
||||
};
|
||||
bx.tcx().const_eval(param_env.and(cid))
|
||||
}
|
||||
mir::Literal::Value { value } => {
|
||||
Ok(self.monomorphize(&value))
|
||||
}
|
||||
}.and_then(|c| self.fully_evaluate(bx, c))
|
||||
let c = self.monomorphize(&constant.literal);
|
||||
self.fully_evaluate(bx, c)
|
||||
}
|
||||
|
||||
/// process constant containing SIMD shuffle indices
|
||||
pub fn simd_shuffle_indices(
|
||||
&mut self,
|
||||
bx: &Builder<'a, 'tcx>,
|
||||
constant: &mir::Constant<'tcx>,
|
||||
span: Span,
|
||||
ty: Ty<'tcx>,
|
||||
constant: Result<&'tcx ty::Const<'tcx>, Lrc<ConstEvalErr<'tcx>>>,
|
||||
) -> (ValueRef, Ty<'tcx>) {
|
||||
self.eval_mir_constant(bx, constant)
|
||||
constant
|
||||
.and_then(|c| {
|
||||
let field_ty = c.ty.builtin_index().unwrap();
|
||||
let fields = match c.ty.sty {
|
||||
@ -217,11 +208,11 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
||||
})
|
||||
.unwrap_or_else(|e| {
|
||||
e.report_as_error(
|
||||
bx.tcx().at(constant.span),
|
||||
bx.tcx().at(span),
|
||||
"could not evaluate shuffle_indices at compile time",
|
||||
);
|
||||
// We've errored, so we don't have to produce working code.
|
||||
let ty = self.monomorphize(&constant.ty);
|
||||
let ty = self.monomorphize(&ty);
|
||||
let llty = bx.cx.layout_of(ty).llvm_type(bx.cx);
|
||||
(C_undef(llty), ty)
|
||||
})
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use llvm::{ValueRef, LLVMConstInBoundsGEP};
|
||||
use llvm::ValueRef;
|
||||
use rustc::mir::interpret::ConstEvalErr;
|
||||
use rustc::mir;
|
||||
use rustc::mir::interpret::ConstValue;
|
||||
@ -22,14 +22,12 @@ use common::{CodegenCx, C_undef, C_usize};
|
||||
use builder::{Builder, MemFlags};
|
||||
use value::Value;
|
||||
use type_of::LayoutLlvmExt;
|
||||
use type_::Type;
|
||||
use consts;
|
||||
|
||||
use std::fmt;
|
||||
use std::ptr;
|
||||
|
||||
use super::{FunctionCx, LocalRef};
|
||||
use super::constant::{scalar_to_llvm, const_alloc_to_llvm};
|
||||
use super::constant::scalar_to_llvm;
|
||||
use super::place::PlaceRef;
|
||||
|
||||
/// The representation of a Rust value. The enum variant is in fact
|
||||
@ -139,16 +137,7 @@ impl<'a, 'tcx> OperandRef<'tcx> {
|
||||
OperandValue::Pair(a_llval, b_llval)
|
||||
},
|
||||
ConstValue::ByRef(alloc, offset) => {
|
||||
let init = const_alloc_to_llvm(bx.cx, alloc);
|
||||
let base_addr = consts::addr_of(bx.cx, init, layout.align, "byte_str");
|
||||
|
||||
let llval = unsafe { LLVMConstInBoundsGEP(
|
||||
consts::bitcast(base_addr, Type::i8p(bx.cx)),
|
||||
&C_usize(bx.cx, offset.bytes()),
|
||||
1,
|
||||
)};
|
||||
let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to());
|
||||
return Ok(PlaceRef::new_sized(llval, layout, alloc.align).load(bx));
|
||||
return Ok(PlaceRef::from_const_alloc(bx, layout, alloc, offset).load(bx));
|
||||
},
|
||||
};
|
||||
|
||||
@ -409,20 +398,12 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
||||
self.eval_mir_constant(bx, constant)
|
||||
.and_then(|c| OperandRef::from_const(bx, c))
|
||||
.unwrap_or_else(|err| {
|
||||
match constant.literal {
|
||||
mir::Literal::Promoted { .. } => {
|
||||
// this is unreachable as long as runtime
|
||||
// and compile-time agree on values
|
||||
// With floats that won't always be true
|
||||
// so we generate an abort below
|
||||
},
|
||||
mir::Literal::Value { .. } => {
|
||||
err.report_as_error(
|
||||
bx.tcx().at(constant.span),
|
||||
"could not evaluate constant operand",
|
||||
);
|
||||
},
|
||||
}
|
||||
err.report_as_error(
|
||||
bx.tcx().at(constant.span),
|
||||
"could not evaluate constant operand",
|
||||
);
|
||||
// Allow RalfJ to sleep soundly knowing that even refactorings that remove
|
||||
// the above error (or silence it under some conditions) will not cause UB
|
||||
let fnname = bx.cx.get_intrinsic(&("llvm.trap"));
|
||||
bx.call(fnname, &[], None);
|
||||
// We've errored, so we don't have to produce working code.
|
||||
|
@ -8,9 +8,9 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use llvm::{self, ValueRef};
|
||||
use llvm::{self, ValueRef, LLVMConstInBoundsGEP};
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::ty::layout::{self, Align, TyLayout, LayoutOf};
|
||||
use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, Size};
|
||||
use rustc::mir;
|
||||
use rustc::mir::tcx::PlaceTy;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
@ -22,6 +22,7 @@ use type_of::LayoutLlvmExt;
|
||||
use type_::Type;
|
||||
use value::Value;
|
||||
use glue;
|
||||
use mir::constant::const_alloc_to_llvm;
|
||||
|
||||
use std::ptr;
|
||||
|
||||
@ -56,6 +57,24 @@ impl<'a, 'tcx> PlaceRef<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_const_alloc(
|
||||
bx: &Builder<'a, 'tcx>,
|
||||
layout: TyLayout<'tcx>,
|
||||
alloc: &mir::interpret::Allocation,
|
||||
offset: Size,
|
||||
) -> PlaceRef<'tcx> {
|
||||
let init = const_alloc_to_llvm(bx.cx, alloc);
|
||||
let base_addr = consts::addr_of(bx.cx, init, layout.align, "byte_str");
|
||||
|
||||
let llval = unsafe { LLVMConstInBoundsGEP(
|
||||
consts::bitcast(base_addr, Type::i8p(bx.cx)),
|
||||
&C_usize(bx.cx, offset.bytes()),
|
||||
1,
|
||||
)};
|
||||
let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to());
|
||||
PlaceRef::new_sized(llval, layout, alloc.align)
|
||||
}
|
||||
|
||||
pub fn alloca(bx: &Builder<'a, 'tcx>, layout: TyLayout<'tcx>, name: &str)
|
||||
-> PlaceRef<'tcx> {
|
||||
debug!("alloca({:?}: {:?})", name, layout);
|
||||
@ -421,6 +440,31 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
||||
|
||||
let result = match *place {
|
||||
mir::Place::Local(_) => bug!(), // handled above
|
||||
mir::Place::Promoted(box (index, ty)) => {
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
let cid = mir::interpret::GlobalId {
|
||||
instance: self.instance,
|
||||
promoted: Some(index),
|
||||
};
|
||||
let layout = cx.layout_of(self.monomorphize(&ty));
|
||||
match bx.tcx().const_eval(param_env.and(cid)) {
|
||||
Ok(val) => match val.val {
|
||||
mir::interpret::ConstValue::ByRef(alloc, offset) => {
|
||||
PlaceRef::from_const_alloc(bx, layout, alloc, offset)
|
||||
}
|
||||
_ => bug!("promoteds should have an allocation: {:?}", val),
|
||||
},
|
||||
Err(_) => {
|
||||
// this is unreachable as long as runtime
|
||||
// and compile-time agree on values
|
||||
// With floats that won't always be true
|
||||
// so we generate an abort
|
||||
let fnname = bx.cx.get_intrinsic(&("llvm.trap"));
|
||||
bx.call(fnname, &[], None);
|
||||
PlaceRef::new_sized(C_undef(layout.llvm_type(bx.cx).ptr_to()), layout, layout.align)
|
||||
}
|
||||
}
|
||||
}
|
||||
mir::Place::Static(box mir::Static { def_id, ty }) => {
|
||||
let layout = cx.layout_of(self.monomorphize(&ty));
|
||||
PlaceRef::new_sized(consts::get_static(cx, def_id), layout, layout.align)
|
||||
|
@ -717,6 +717,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
including_downcast: &IncludingDowncast,
|
||||
) -> Result<(), ()> {
|
||||
match *place {
|
||||
Place::Promoted(_) => {
|
||||
buf.push_str("promoted");
|
||||
}
|
||||
Place::Local(local) => {
|
||||
self.append_local_to_string(local, buf)?;
|
||||
}
|
||||
@ -859,6 +862,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
let local = &self.mir.local_decls[local];
|
||||
self.describe_field_from_ty(&local.ty, field)
|
||||
}
|
||||
Place::Promoted(ref prom) => self.describe_field_from_ty(&prom.1, field),
|
||||
Place::Static(ref static_) => self.describe_field_from_ty(&static_.ty, field),
|
||||
Place::Projection(ref proj) => match proj.elem {
|
||||
ProjectionElem::Deref => self.describe_field(&proj.base, field),
|
||||
@ -929,6 +933,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
let local = &self.mir.local_decls[*local];
|
||||
Some(local.ty)
|
||||
}
|
||||
Place::Promoted(ref prom) => Some(prom.1),
|
||||
Place::Static(ref st) => Some(st.ty),
|
||||
Place::Projection(ref proj) => match proj.elem {
|
||||
ProjectionElem::Field(_, ty) => Some(ty),
|
||||
|
@ -1221,6 +1221,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
}
|
||||
Operand::Move(Place::Static(..))
|
||||
| Operand::Copy(Place::Static(..))
|
||||
| Operand::Move(Place::Promoted(..))
|
||||
| Operand::Copy(Place::Promoted(..))
|
||||
| Operand::Constant(..) => {}
|
||||
}
|
||||
}
|
||||
@ -1303,6 +1305,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
//
|
||||
// FIXME: allow thread-locals to borrow other thread locals?
|
||||
let (might_be_alive, will_be_dropped) = match root_place {
|
||||
Place::Promoted(_) => (true, false),
|
||||
Place::Static(statik) => {
|
||||
// Thread-locals might be dropped after the function exits, but
|
||||
// "true" statics will never be.
|
||||
@ -1587,6 +1590,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
match *last_prefix {
|
||||
Place::Local(_) => panic!("should have move path for every Local"),
|
||||
Place::Projection(_) => panic!("PrefixSet::All meant don't stop for Projection"),
|
||||
Place::Promoted(_) |
|
||||
Place::Static(_) => return Err(NoMovePathFound::ReachedStatic),
|
||||
}
|
||||
}
|
||||
@ -1613,6 +1617,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
let mut place = place;
|
||||
loop {
|
||||
match *place {
|
||||
Place::Promoted(_) |
|
||||
Place::Local(_) | Place::Static(_) => {
|
||||
// assigning to `x` does not require `x` be initialized.
|
||||
break;
|
||||
@ -1808,6 +1813,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
self.used_mut_upvars.push(field);
|
||||
}
|
||||
}
|
||||
RootPlace {
|
||||
place: Place::Promoted(..),
|
||||
is_local_mutation_allowed: _,
|
||||
} => {}
|
||||
RootPlace {
|
||||
place: Place::Static(..),
|
||||
is_local_mutation_allowed: _,
|
||||
@ -1843,6 +1852,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
}),
|
||||
}
|
||||
}
|
||||
// promoteds may never be mutated
|
||||
Place::Promoted(_) => Err(place),
|
||||
Place::Static(ref static_) => {
|
||||
if self.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) {
|
||||
Err(place)
|
||||
@ -2009,6 +2020,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
let mut deepest = place;
|
||||
loop {
|
||||
let proj = match *cursor {
|
||||
Place::Promoted(_) |
|
||||
Place::Local(..) | Place::Static(..) => return deepest,
|
||||
Place::Projection(ref proj) => proj,
|
||||
};
|
||||
|
@ -389,6 +389,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
|
||||
// overloaded * operator.
|
||||
local_decl.is_user_variable.is_some() && is_shared_ref(local_decl.ty)
|
||||
}
|
||||
Place::Promoted(_) => true,
|
||||
Place::Static(ref st) => is_shared_ref(st.ty),
|
||||
Place::Projection(ref proj) => match proj.elem {
|
||||
ProjectionElem::Field(_, ty) => is_shared_ref(ty),
|
||||
|
@ -281,69 +281,48 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
||||
constant, location
|
||||
);
|
||||
|
||||
let expected_ty = match constant.literal {
|
||||
Literal::Value { value } => {
|
||||
// FIXME(#46702) -- We need some way to get the predicates
|
||||
// associated with the "pre-evaluated" form of the
|
||||
// constant. For example, consider that the constant
|
||||
// may have associated constant projections (`<Foo as
|
||||
// Trait<'a, 'b>>::SOME_CONST`) that impose
|
||||
// constraints on `'a` and `'b`. These constraints
|
||||
// would be lost if we just look at the normalized
|
||||
// value.
|
||||
if let ty::TyFnDef(def_id, substs) = value.ty.sty {
|
||||
let tcx = self.tcx();
|
||||
let type_checker = &mut self.cx;
|
||||
// FIXME(#46702) -- We need some way to get the predicates
|
||||
// associated with the "pre-evaluated" form of the
|
||||
// constant. For example, consider that the constant
|
||||
// may have associated constant projections (`<Foo as
|
||||
// Trait<'a, 'b>>::SOME_CONST`) that impose
|
||||
// constraints on `'a` and `'b`. These constraints
|
||||
// would be lost if we just look at the normalized
|
||||
// value.
|
||||
if let ty::TyFnDef(def_id, substs) = constant.literal.ty.sty {
|
||||
let tcx = self.tcx();
|
||||
let type_checker = &mut self.cx;
|
||||
|
||||
// FIXME -- For now, use the substitutions from
|
||||
// `value.ty` rather than `value.val`. The
|
||||
// renumberer will rewrite them to independent
|
||||
// sets of regions; in principle, we ought to
|
||||
// derive the type of the `value.val` from "first
|
||||
// principles" and equate with value.ty, but as we
|
||||
// are transitioning to the miri-based system, we
|
||||
// don't have a handy function for that, so for
|
||||
// now we just ignore `value.val` regions.
|
||||
// FIXME -- For now, use the substitutions from
|
||||
// `value.ty` rather than `value.val`. The
|
||||
// renumberer will rewrite them to independent
|
||||
// sets of regions; in principle, we ought to
|
||||
// derive the type of the `value.val` from "first
|
||||
// principles" and equate with value.ty, but as we
|
||||
// are transitioning to the miri-based system, we
|
||||
// don't have a handy function for that, so for
|
||||
// now we just ignore `value.val` regions.
|
||||
|
||||
let instantiated_predicates =
|
||||
tcx.predicates_of(def_id).instantiate(tcx, substs);
|
||||
type_checker.normalize_and_prove_instantiated_predicates(
|
||||
instantiated_predicates,
|
||||
location.boring(),
|
||||
);
|
||||
}
|
||||
let instantiated_predicates =
|
||||
tcx.predicates_of(def_id).instantiate(tcx, substs);
|
||||
type_checker.normalize_and_prove_instantiated_predicates(
|
||||
instantiated_predicates,
|
||||
location.boring(),
|
||||
);
|
||||
}
|
||||
|
||||
value.ty
|
||||
}
|
||||
|
||||
Literal::Promoted { .. } => {
|
||||
// FIXME -- promoted MIR return types reference
|
||||
// various "free regions" (e.g., scopes and things)
|
||||
// that they ought not to do. We have to figure out
|
||||
// how best to handle that -- probably we want treat
|
||||
// promoted MIR much like closures, renumbering all
|
||||
// their free regions and propagating constraints
|
||||
// upwards. We have the same acyclic guarantees, so
|
||||
// that should be possible. But for now, ignore them.
|
||||
//
|
||||
// let promoted_mir = &self.mir.promoted[index];
|
||||
// promoted_mir.return_ty()
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
debug!("sanitize_constant: expected_ty={:?}", expected_ty);
|
||||
debug!("sanitize_constant: expected_ty={:?}", constant.literal.ty);
|
||||
|
||||
if let Err(terr) = self
|
||||
.cx
|
||||
.eq_types(expected_ty, constant.ty, location.boring())
|
||||
.eq_types(constant.literal.ty, constant.ty, location.boring())
|
||||
{
|
||||
span_mirbug!(
|
||||
self,
|
||||
constant,
|
||||
"constant {:?} should have type {:?} but has {:?} ({:?})",
|
||||
constant,
|
||||
expected_ty,
|
||||
constant.literal.ty,
|
||||
constant.ty,
|
||||
terr,
|
||||
);
|
||||
@ -363,6 +342,21 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
||||
Place::Local(index) => PlaceTy::Ty {
|
||||
ty: self.mir.local_decls[index].ty,
|
||||
},
|
||||
Place::Promoted(box (_index, sty)) => {
|
||||
let sty = self.sanitize_type(place, sty);
|
||||
// FIXME -- promoted MIR return types reference
|
||||
// various "free regions" (e.g., scopes and things)
|
||||
// that they ought not to do. We have to figure out
|
||||
// how best to handle that -- probably we want treat
|
||||
// promoted MIR much like closures, renumbering all
|
||||
// their free regions and propagating constraints
|
||||
// upwards. We have the same acyclic guarantees, so
|
||||
// that should be possible. But for now, ignore them.
|
||||
//
|
||||
// let promoted_mir = &self.mir.promoted[index];
|
||||
// promoted_mir.return_ty()
|
||||
PlaceTy::Ty { ty: sty }
|
||||
}
|
||||
Place::Static(box Static { def_id, ty: sty }) => {
|
||||
let sty = self.sanitize_type(place, sty);
|
||||
let ty = self.tcx().type_of(def_id);
|
||||
|
@ -140,6 +140,7 @@ pub(super) fn is_active<'tcx>(
|
||||
/// This is called for all Yield statements on movable generators
|
||||
pub(super) fn borrow_of_local_data<'tcx>(place: &Place<'tcx>) -> bool {
|
||||
match place {
|
||||
Place::Promoted(_) |
|
||||
Place::Static(..) => false,
|
||||
Place::Local(..) => true,
|
||||
Place::Projection(box proj) => {
|
||||
|
@ -26,6 +26,7 @@ crate trait PlaceExt<'tcx> {
|
||||
impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
|
||||
fn is_unsafe_place(&self, tcx: TyCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) -> bool {
|
||||
match self {
|
||||
Place::Promoted(_) |
|
||||
Place::Local(_) => false,
|
||||
Place::Static(static_) => {
|
||||
tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable)
|
||||
@ -52,6 +53,7 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
|
||||
loop {
|
||||
match p {
|
||||
Place::Projection(pi) => p = &pi.base,
|
||||
Place::Promoted(_) |
|
||||
Place::Static(_) => return None,
|
||||
Place::Local(l) => return Some(*l),
|
||||
}
|
||||
|
@ -282,6 +282,7 @@ fn unroll_place<'tcx, R>(
|
||||
op,
|
||||
),
|
||||
|
||||
Place::Promoted(_) |
|
||||
Place::Local(_) | Place::Static(_) => {
|
||||
let list = PlaceComponents {
|
||||
component: place,
|
||||
@ -326,6 +327,9 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>(
|
||||
Overlap::EqualOrDisjoint
|
||||
}
|
||||
}
|
||||
(Place::Promoted(_), Place::Promoted(_)) |
|
||||
(Place::Local(_), Place::Promoted(_)) | (Place::Promoted(_), Place::Local(_)) |
|
||||
(Place::Promoted(_), Place::Static(_)) | (Place::Static(_), Place::Promoted(_)) |
|
||||
(Place::Local(_), Place::Static(_)) | (Place::Static(_), Place::Local(_)) => {
|
||||
debug!("place_element_conflict: DISJOINT-STATIC-LOCAL");
|
||||
Overlap::Disjoint
|
||||
|
@ -36,6 +36,7 @@ impl<'tcx> IsPrefixOf<'tcx> for Place<'tcx> {
|
||||
}
|
||||
|
||||
match *cursor {
|
||||
Place::Promoted(_) |
|
||||
Place::Local(_) | Place::Static(_) => return false,
|
||||
Place::Projection(ref proj) => {
|
||||
cursor = &proj.base;
|
||||
@ -98,6 +99,7 @@ impl<'cx, 'gcx, 'tcx> Iterator for Prefixes<'cx, 'gcx, 'tcx> {
|
||||
|
||||
'cursor: loop {
|
||||
let proj = match *cursor {
|
||||
Place::Promoted(_) |
|
||||
Place::Local(_) | // search yielded this leaf
|
||||
Place::Static(_) => {
|
||||
self.next = None;
|
||||
|
@ -239,12 +239,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
operands.push(Operand::Constant(box Constant {
|
||||
span: expr_span,
|
||||
ty: this.hir.tcx().types.u32,
|
||||
literal: Literal::Value {
|
||||
value: ty::Const::from_bits(
|
||||
this.hir.tcx(),
|
||||
0,
|
||||
ty::ParamEnv::empty().and(this.hir.tcx().types.u32)),
|
||||
},
|
||||
literal: ty::Const::from_bits(
|
||||
this.hir.tcx(),
|
||||
0,
|
||||
ty::ParamEnv::empty().and(this.hir.tcx().types.u32),
|
||||
),
|
||||
}));
|
||||
box AggregateKind::Generator(closure_id, substs, movability)
|
||||
}
|
||||
@ -513,9 +512,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
let param_ty = ty::ParamEnv::empty().and(self.hir.tcx().lift_to_global(&ty).unwrap());
|
||||
let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits();
|
||||
let n = (!0u128) >> (128 - bits);
|
||||
let literal = Literal::Value {
|
||||
value: ty::Const::from_bits(self.hir.tcx(), n, param_ty)
|
||||
};
|
||||
let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty);
|
||||
|
||||
self.literal_operand(span, ty, literal)
|
||||
}
|
||||
@ -526,9 +523,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
let param_ty = ty::ParamEnv::empty().and(self.hir.tcx().lift_to_global(&ty).unwrap());
|
||||
let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits();
|
||||
let n = 1 << (bits - 1);
|
||||
let literal = Literal::Value {
|
||||
value: ty::Const::from_bits(self.hir.tcx(), n, param_ty)
|
||||
};
|
||||
let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty);
|
||||
|
||||
self.literal_operand(span, ty, literal)
|
||||
}
|
||||
|
@ -505,8 +505,8 @@ enum TestKind<'tcx> {
|
||||
|
||||
// test whether the value falls within an inclusive or exclusive range
|
||||
Range {
|
||||
lo: Literal<'tcx>,
|
||||
hi: Literal<'tcx>,
|
||||
lo: &'tcx ty::Const<'tcx>,
|
||||
hi: &'tcx ty::Const<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
end: hir::RangeEnd,
|
||||
},
|
||||
|
@ -74,8 +74,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
Test {
|
||||
span: match_pair.pattern.span,
|
||||
kind: TestKind::Range {
|
||||
lo: Literal::Value { value: lo },
|
||||
hi: Literal::Value { value: hi },
|
||||
lo,
|
||||
hi,
|
||||
ty: match_pair.pattern.ty.clone(),
|
||||
end,
|
||||
},
|
||||
@ -260,9 +260,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
|
||||
TestKind::Eq { value, mut ty } => {
|
||||
let mut val = Operand::Copy(place.clone());
|
||||
let mut expect = self.literal_operand(test.span, ty, Literal::Value {
|
||||
value
|
||||
});
|
||||
let mut expect = self.literal_operand(test.span, ty, value);
|
||||
// Use PartialEq::eq instead of BinOp::Eq
|
||||
// (the binop can only handle primitives)
|
||||
let fail = self.cfg.start_new_block();
|
||||
@ -300,9 +298,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
let array = self.literal_operand(
|
||||
test.span,
|
||||
value.ty,
|
||||
Literal::Value {
|
||||
value
|
||||
},
|
||||
value,
|
||||
);
|
||||
|
||||
let slice = self.temp(ty, test.span);
|
||||
|
@ -35,7 +35,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
pub fn literal_operand(&mut self,
|
||||
span: Span,
|
||||
ty: Ty<'tcx>,
|
||||
literal: Literal<'tcx>)
|
||||
literal: &'tcx ty::Const<'tcx>)
|
||||
-> Operand<'tcx> {
|
||||
let constant = box Constant {
|
||||
span,
|
||||
@ -52,9 +52,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
// Returns a zero literal operand for the appropriate type, works for
|
||||
// bool, char and integers.
|
||||
pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
|
||||
let literal = Literal::Value {
|
||||
value: ty::Const::from_bits(self.hir.tcx(), 0, ty::ParamEnv::empty().and(ty))
|
||||
};
|
||||
let literal = ty::Const::from_bits(self.hir.tcx(), 0, ty::ParamEnv::empty().and(ty));
|
||||
|
||||
self.literal_operand(span, ty, literal)
|
||||
}
|
||||
|
@ -93,6 +93,7 @@ struct BorrowedLocalsVisitor<'b, 'c: 'b> {
|
||||
fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> {
|
||||
match *place {
|
||||
Place::Local(l) => Some(l),
|
||||
Place::Promoted(_) |
|
||||
Place::Static(..) => None,
|
||||
Place::Projection(ref proj) => {
|
||||
match proj.elem {
|
||||
|
@ -259,6 +259,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
|
||||
// Issue #46746: Two-phase borrows handles
|
||||
// stmts of form `Tmp = &mut Borrow` ...
|
||||
match lhs {
|
||||
Place::Promoted(_) |
|
||||
Place::Local(..) | Place::Static(..) => {} // okay
|
||||
Place::Projection(..) => {
|
||||
// ... can assign into projections,
|
||||
|
@ -108,6 +108,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
|
||||
debug!("lookup({:?})", place);
|
||||
match *place {
|
||||
Place::Local(local) => Ok(self.builder.data.rev_lookup.locals[local]),
|
||||
Place::Promoted(..) |
|
||||
Place::Static(..) => {
|
||||
Err(MoveError::cannot_move_out_of(self.loc, Static))
|
||||
}
|
||||
|
@ -249,6 +249,7 @@ impl<'tcx> MovePathLookup<'tcx> {
|
||||
pub fn find(&self, place: &Place<'tcx>) -> LookupResult {
|
||||
match *place {
|
||||
Place::Local(local) => LookupResult::Exact(self.locals[local]),
|
||||
Place::Promoted(_) |
|
||||
Place::Static(..) => LookupResult::Parent(None),
|
||||
Place::Projection(ref proj) => {
|
||||
match self.find(&proj.base) {
|
||||
|
@ -627,15 +627,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
None
|
||||
};
|
||||
let source = if let Some((did, offset, ty)) = var {
|
||||
let mk_const = |val| Expr {
|
||||
let mk_const = |literal| Expr {
|
||||
temp_lifetime,
|
||||
ty,
|
||||
span: expr.span,
|
||||
kind: ExprKind::Literal {
|
||||
literal: Literal::Value {
|
||||
value: val,
|
||||
},
|
||||
},
|
||||
kind: ExprKind::Literal { literal },
|
||||
}.to_ref();
|
||||
let offset = mk_const(ty::Const::from_bits(
|
||||
cx.tcx,
|
||||
@ -706,9 +702,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
ty,
|
||||
span: expr.span,
|
||||
kind: ExprKind::Literal {
|
||||
literal: Literal::Value {
|
||||
value: ty::Const::zero_sized(cx.tcx(), ty),
|
||||
},
|
||||
literal: ty::Const::zero_sized(cx.tcx(), ty),
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -760,22 +754,20 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
Def::Method(_) |
|
||||
Def::StructCtor(_, CtorKind::Fn) |
|
||||
Def::VariantCtor(_, CtorKind::Fn) => ExprKind::Literal {
|
||||
literal: Literal::Value {
|
||||
value: ty::Const::zero_sized(
|
||||
cx.tcx,
|
||||
cx.tables().node_id_to_type(expr.hir_id)),
|
||||
},
|
||||
literal: ty::Const::zero_sized(
|
||||
cx.tcx,
|
||||
cx.tables().node_id_to_type(expr.hir_id),
|
||||
),
|
||||
},
|
||||
|
||||
Def::Const(def_id) |
|
||||
Def::AssociatedConst(def_id) => ExprKind::Literal {
|
||||
literal: Literal::Value {
|
||||
value: ty::Const::unevaluated(
|
||||
cx.tcx,
|
||||
def_id,
|
||||
substs,
|
||||
cx.tables().node_id_to_type(expr.hir_id))
|
||||
},
|
||||
literal: ty::Const::unevaluated(
|
||||
cx.tcx,
|
||||
def_id,
|
||||
substs,
|
||||
cx.tables().node_id_to_type(expr.hir_id),
|
||||
),
|
||||
},
|
||||
|
||||
Def::StructCtor(def_id, CtorKind::Const) |
|
||||
|
@ -112,10 +112,8 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||
self.tcx.types.usize
|
||||
}
|
||||
|
||||
pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> {
|
||||
Literal::Value {
|
||||
value: ty::Const::from_usize(self.tcx, value),
|
||||
}
|
||||
pub fn usize_literal(&mut self, value: u64) -> &'tcx ty::Const<'tcx> {
|
||||
ty::Const::from_usize(self.tcx, value)
|
||||
}
|
||||
|
||||
pub fn bool_ty(&mut self) -> Ty<'tcx> {
|
||||
@ -126,16 +124,12 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||
self.tcx.mk_nil()
|
||||
}
|
||||
|
||||
pub fn true_literal(&mut self) -> Literal<'tcx> {
|
||||
Literal::Value {
|
||||
value: ty::Const::from_bool(self.tcx, true),
|
||||
}
|
||||
pub fn true_literal(&mut self) -> &'tcx ty::Const<'tcx> {
|
||||
ty::Const::from_bool(self.tcx, true)
|
||||
}
|
||||
|
||||
pub fn false_literal(&mut self) -> Literal<'tcx> {
|
||||
Literal::Value {
|
||||
value: ty::Const::from_bool(self.tcx, false),
|
||||
}
|
||||
pub fn false_literal(&mut self) -> &'tcx ty::Const<'tcx> {
|
||||
ty::Const::from_bool(self.tcx, false)
|
||||
}
|
||||
|
||||
// FIXME: Combine with rustc_mir::hair::pattern::lit_to_const
|
||||
@ -145,7 +139,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||
ty: Ty<'tcx>,
|
||||
sp: Span,
|
||||
neg: bool,
|
||||
) -> Literal<'tcx> {
|
||||
) -> &'tcx ty::Const<'tcx> {
|
||||
trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
|
||||
|
||||
let parse_float = |num, fty| -> ConstValue<'tcx> {
|
||||
@ -209,9 +203,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||
defined: 32,
|
||||
}),
|
||||
};
|
||||
Literal::Value {
|
||||
value: ty::Const::from_const_value(self.tcx, lit, ty)
|
||||
}
|
||||
ty::Const::from_const_value(self.tcx, lit, ty)
|
||||
}
|
||||
|
||||
pub fn pattern_from_hir(&mut self, p: &hir::Pat) -> Pattern<'tcx> {
|
||||
@ -231,17 +223,14 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||
method_name: &str,
|
||||
self_ty: Ty<'tcx>,
|
||||
params: &[Kind<'tcx>])
|
||||
-> (Ty<'tcx>, Literal<'tcx>) {
|
||||
-> (Ty<'tcx>, &'tcx ty::Const<'tcx>) {
|
||||
let method_name = Symbol::intern(method_name);
|
||||
let substs = self.tcx.mk_substs_trait(self_ty, params);
|
||||
for item in self.tcx.associated_items(trait_def_id) {
|
||||
if item.kind == ty::AssociatedKind::Method && item.ident.name == method_name {
|
||||
let method_ty = self.tcx.type_of(item.def_id);
|
||||
let method_ty = method_ty.subst(self.tcx, substs);
|
||||
return (method_ty,
|
||||
Literal::Value {
|
||||
value: ty::Const::zero_sized(self.tcx, method_ty)
|
||||
});
|
||||
return (method_ty, ty::Const::zero_sized(self.tcx, method_ty));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,11 +14,11 @@
|
||||
//! unit-tested and separated from the Rust source and compiler data
|
||||
//! structures.
|
||||
|
||||
use rustc::mir::{BinOp, BorrowKind, Field, Literal, UnOp};
|
||||
use rustc::mir::{BinOp, BorrowKind, Field, UnOp};
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::middle::region;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::{AdtDef, UpvarSubsts, Region, Ty};
|
||||
use rustc::ty::{AdtDef, UpvarSubsts, Region, Ty, Const};
|
||||
use rustc::hir;
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
@ -271,7 +271,7 @@ pub enum ExprKind<'tcx> {
|
||||
movability: Option<hir::GeneratorMovability>,
|
||||
},
|
||||
Literal {
|
||||
literal: Literal<'tcx>,
|
||||
literal: &'tcx Const<'tcx>,
|
||||
},
|
||||
InlineAsm {
|
||||
asm: &'tcx hir::InlineAsm,
|
||||
|
@ -178,7 +178,7 @@ fn eval_body_using_ecx<'a, 'mir, 'tcx>(
|
||||
let ptr = ptr.into();
|
||||
// always try to read the value and report errors
|
||||
let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? {
|
||||
Some(val) if is_static.is_none() => val,
|
||||
Some(val) if is_static.is_none() && cid.promoted.is_none() => val,
|
||||
// point at the allocation
|
||||
_ => Value::ByRef(ptr, layout.align),
|
||||
};
|
||||
@ -561,7 +561,7 @@ pub fn const_eval_provider<'a, 'tcx>(
|
||||
|
||||
let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env);
|
||||
res.and_then(|(mut val, _, miri_ty)| {
|
||||
if tcx.is_static(def_id).is_none() {
|
||||
if tcx.is_static(def_id).is_none() && cid.promoted.is_none() {
|
||||
val = ecx.try_read_by_ref(val, miri_ty)?;
|
||||
}
|
||||
Ok(value_to_const_value(&ecx, val, miri_ty))
|
||||
|
@ -831,19 +831,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
||||
},
|
||||
|
||||
Constant(ref constant) => {
|
||||
use rustc::mir::Literal;
|
||||
let mir::Constant { ref literal, .. } = **constant;
|
||||
let value = match *literal {
|
||||
Literal::Value { ref value } => self.const_to_value(value.val)?,
|
||||
|
||||
Literal::Promoted { index } => {
|
||||
let instance = self.frame().instance;
|
||||
self.read_global_as_value(GlobalId {
|
||||
instance,
|
||||
promoted: Some(index),
|
||||
})?
|
||||
}
|
||||
};
|
||||
let value = self.const_to_value(constant.literal.val)?;
|
||||
|
||||
Ok(ValTy {
|
||||
value,
|
||||
|
@ -109,6 +109,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
Local(local) => self.frame().get_local(local).map(Some),
|
||||
// No fast path for statics. Reading from statics is rare and would require another
|
||||
// Machine function to handle differently in miri.
|
||||
Promoted(_) |
|
||||
Static(_) => Ok(None),
|
||||
Projection(ref proj) => self.try_read_place_projection(proj),
|
||||
}
|
||||
@ -214,6 +215,23 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
local,
|
||||
},
|
||||
|
||||
Promoted(ref promoted) => {
|
||||
let instance = self.frame().instance;
|
||||
let val = self.read_global_as_value(GlobalId {
|
||||
instance,
|
||||
promoted: Some(promoted.0),
|
||||
})?;
|
||||
if let Value::ByRef(ptr, align) = val {
|
||||
Place::Ptr {
|
||||
ptr,
|
||||
align,
|
||||
extra: PlaceExtra::None,
|
||||
}
|
||||
} else {
|
||||
bug!("evaluated promoted and got {:#?}", val);
|
||||
}
|
||||
}
|
||||
|
||||
Static(ref static_) => {
|
||||
let layout = self.layout_of(self.place_ty(mir_place))?;
|
||||
let instance = ty::Instance::mono(*self.tcx, static_.def_id);
|
||||
|
@ -440,9 +440,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
||||
let func = Operand::Constant(box Constant {
|
||||
span: self.span,
|
||||
ty: func_ty,
|
||||
literal: Literal::Value {
|
||||
value: ty::Const::zero_sized(self.tcx, func_ty)
|
||||
},
|
||||
literal: ty::Const::zero_sized(self.tcx, func_ty),
|
||||
});
|
||||
|
||||
let ref_loc = self.make_place(
|
||||
@ -500,9 +498,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
||||
box Constant {
|
||||
span: self.span,
|
||||
ty: self.tcx.types.usize,
|
||||
literal: Literal::Value {
|
||||
value: ty::Const::from_usize(self.tcx, value),
|
||||
}
|
||||
literal: ty::Const::from_usize(self.tcx, value),
|
||||
}
|
||||
}
|
||||
|
||||
@ -729,9 +725,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
(Operand::Constant(box Constant {
|
||||
span,
|
||||
ty,
|
||||
literal: Literal::Value {
|
||||
value: ty::Const::zero_sized(tcx, ty)
|
||||
},
|
||||
literal: ty::Const::zero_sized(tcx, ty),
|
||||
}),
|
||||
vec![rcvr])
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ fn place_context<'a, 'tcx, D>(
|
||||
|
||||
match *place {
|
||||
Local { .. } => (None, hir::MutMutable),
|
||||
Promoted(_) |
|
||||
Static(_) => (None, hir::MutImmutable),
|
||||
Projection(ref proj) => {
|
||||
match proj.elem {
|
||||
|
@ -222,6 +222,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
||||
&Place::Local(..) => {
|
||||
// locals are safe
|
||||
}
|
||||
&Place::Promoted(_) => {
|
||||
bug!("unsafety checking should happen before promotion")
|
||||
}
|
||||
&Place::Static(box Static { def_id, ty: _ }) => {
|
||||
if self.tcx.is_static(def_id) == Some(hir::Mutability::MutMutable) {
|
||||
self.require_unsafe("use of mutable static",
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
|
||||
use rustc::hir::def::Def;
|
||||
use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, Rvalue, Local};
|
||||
use rustc::mir::{Constant, Location, Place, Mir, Operand, Rvalue, Local};
|
||||
use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind};
|
||||
use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem};
|
||||
use rustc::mir::visit::{Visitor, PlaceContext};
|
||||
@ -174,48 +174,22 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
||||
c: &Constant<'tcx>,
|
||||
source_info: SourceInfo,
|
||||
) -> Option<Const<'tcx>> {
|
||||
match c.literal {
|
||||
Literal::Value { value } => {
|
||||
self.ecx.tcx.span = source_info.span;
|
||||
match self.ecx.const_to_value(value.val) {
|
||||
Ok(val) => Some((val, value.ty, c.span)),
|
||||
Err(error) => {
|
||||
let (stacktrace, span) = self.ecx.generate_stacktrace(None);
|
||||
let err = ConstEvalErr {
|
||||
span,
|
||||
error,
|
||||
stacktrace,
|
||||
};
|
||||
err.report_as_error(
|
||||
self.tcx.at(source_info.span),
|
||||
"could not evaluate constant",
|
||||
);
|
||||
None
|
||||
},
|
||||
}
|
||||
},
|
||||
// evaluate the promoted and replace the constant with the evaluated result
|
||||
Literal::Promoted { index } => {
|
||||
let generics = self.tcx.generics_of(self.source.def_id);
|
||||
if generics.requires_monomorphization(self.tcx) {
|
||||
// FIXME: can't handle code with generics
|
||||
return None;
|
||||
}
|
||||
let substs = Substs::identity_for_item(self.tcx, self.source.def_id);
|
||||
let instance = Instance::new(self.source.def_id, substs);
|
||||
let cid = GlobalId {
|
||||
instance,
|
||||
promoted: Some(index),
|
||||
self.ecx.tcx.span = source_info.span;
|
||||
match self.ecx.const_to_value(c.literal.val) {
|
||||
Ok(val) => Some((val, c.literal.ty, c.span)),
|
||||
Err(error) => {
|
||||
let (stacktrace, span) = self.ecx.generate_stacktrace(None);
|
||||
let err = ConstEvalErr {
|
||||
span,
|
||||
error,
|
||||
stacktrace,
|
||||
};
|
||||
// cannot use `const_eval` here, because that would require having the MIR
|
||||
// for the current function available, but we're producing said MIR right now
|
||||
let (value, _, ty) = self.use_ecx(source_info, |this| {
|
||||
eval_promoted(&mut this.ecx, cid, this.mir, this.param_env)
|
||||
})?;
|
||||
let val = (value, ty, c.span);
|
||||
trace!("evaluated {:?} to {:?}", c, val);
|
||||
Some(val)
|
||||
}
|
||||
err.report_as_error(
|
||||
self.tcx.at(source_info.span),
|
||||
"could not evaluate constant",
|
||||
);
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,6 +207,27 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
||||
},
|
||||
_ => None,
|
||||
},
|
||||
Place::Promoted(ref promoted) => {
|
||||
let generics = self.tcx.generics_of(self.source.def_id);
|
||||
if generics.requires_monomorphization(self.tcx) {
|
||||
// FIXME: can't handle code with generics
|
||||
return None;
|
||||
}
|
||||
let substs = Substs::identity_for_item(self.tcx, self.source.def_id);
|
||||
let instance = Instance::new(self.source.def_id, substs);
|
||||
let cid = GlobalId {
|
||||
instance,
|
||||
promoted: Some(promoted.0),
|
||||
};
|
||||
// cannot use `const_eval` here, because that would require having the MIR
|
||||
// for the current function available, but we're producing said MIR right now
|
||||
let (value, _, ty) = self.use_ecx(source_info, |this| {
|
||||
eval_promoted(&mut this.ecx, cid, this.mir, this.param_env)
|
||||
})?;
|
||||
let val = (value, ty, source_info.span);
|
||||
trace!("evaluated promoted {:?} to {:?}", promoted, val);
|
||||
Some(val)
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -530,9 +530,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||
Rvalue::Use(Operand::Constant(Box::new(Constant {
|
||||
span,
|
||||
ty: self.tcx.types.bool,
|
||||
literal: Literal::Value {
|
||||
value: ty::Const::from_bool(self.tcx, val)
|
||||
}
|
||||
literal: ty::Const::from_bool(self.tcx, val),
|
||||
})))
|
||||
}
|
||||
|
||||
|
@ -177,12 +177,11 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
|
||||
let val = Operand::Constant(box Constant {
|
||||
span: source_info.span,
|
||||
ty: self.tcx.types.u32,
|
||||
literal: Literal::Value {
|
||||
value: ty::Const::from_bits(
|
||||
self.tcx,
|
||||
state_disc.into(),
|
||||
ty::ParamEnv::empty().and(self.tcx.types.u32)),
|
||||
},
|
||||
literal: ty::Const::from_bits(
|
||||
self.tcx,
|
||||
state_disc.into(),
|
||||
ty::ParamEnv::empty().and(self.tcx.types.u32)
|
||||
),
|
||||
});
|
||||
Statement {
|
||||
source_info,
|
||||
@ -337,6 +336,7 @@ struct BorrowedLocals(liveness::LiveVarSet<Local>);
|
||||
fn mark_as_borrowed<'tcx>(place: &Place<'tcx>, locals: &mut BorrowedLocals) {
|
||||
match *place {
|
||||
Place::Local(l) => { locals.0.add(&l); },
|
||||
Place::Promoted(_) |
|
||||
Place::Static(..) => (),
|
||||
Place::Projection(ref proj) => {
|
||||
match proj.elem {
|
||||
@ -707,9 +707,7 @@ fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
cond: Operand::Constant(box Constant {
|
||||
span: mir.span,
|
||||
ty: tcx.types.bool,
|
||||
literal: Literal::Value {
|
||||
value: ty::Const::from_bool(tcx, false),
|
||||
},
|
||||
literal: ty::Const::from_bool(tcx, false),
|
||||
}),
|
||||
expected: true,
|
||||
msg: message,
|
||||
|
@ -662,11 +662,18 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
|
||||
place: &mut Place<'tcx>,
|
||||
_ctxt: PlaceContext<'tcx>,
|
||||
_location: Location) {
|
||||
if let Place::Local(RETURN_PLACE) = *place {
|
||||
// Return pointer; update the place itself
|
||||
*place = self.destination.clone();
|
||||
} else {
|
||||
self.super_place(place, _ctxt, _location);
|
||||
|
||||
match place {
|
||||
Place::Local(RETURN_PLACE) => {
|
||||
// Return pointer; update the place itself
|
||||
*place = self.destination.clone();
|
||||
},
|
||||
Place::Promoted(ref mut promoted) => {
|
||||
if let Some(p) = self.promoted_map.get(promoted.0).cloned() {
|
||||
promoted.0 = p;
|
||||
}
|
||||
},
|
||||
_ => self.super_place(place, _ctxt, _location),
|
||||
}
|
||||
}
|
||||
|
||||
@ -749,14 +756,4 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
|
||||
fn visit_source_scope(&mut self, scope: &mut SourceScope) {
|
||||
*scope = self.scope_map[*scope];
|
||||
}
|
||||
|
||||
fn visit_literal(&mut self, literal: &mut Literal<'tcx>, loc: Location) {
|
||||
if let Literal::Promoted { ref mut index } = *literal {
|
||||
if let Some(p) = self.promoted_map.get(*index).cloned() {
|
||||
*index = p;
|
||||
}
|
||||
} else {
|
||||
self.super_literal(literal, loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
//! Performs various peephole optimizations.
|
||||
|
||||
use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, ProjectionElem, Rvalue, Local};
|
||||
use rustc::mir::{Constant, Location, Place, Mir, Operand, ProjectionElem, Rvalue, Local};
|
||||
use rustc::mir::visit::{MutVisitor, Visitor};
|
||||
use rustc::ty::{TyCtxt, TypeVariants};
|
||||
use rustc::util::nodemap::{FxHashMap, FxHashSet};
|
||||
@ -103,8 +103,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> {
|
||||
if let TypeVariants::TyArray(_, len) = place_ty.sty {
|
||||
let span = self.mir.source_info(location).span;
|
||||
let ty = self.tcx.types.usize;
|
||||
let literal = Literal::Value { value: len };
|
||||
let constant = Constant { span, ty, literal };
|
||||
let constant = Constant { span, ty, literal: len };
|
||||
self.optimizations.arrays_lengths.insert(location, constant);
|
||||
}
|
||||
}
|
||||
|
@ -25,12 +25,12 @@
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
|
||||
use rustc::mir::traversal::ReversePostorder;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::ty::TyCtxt;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
||||
|
||||
use std::{cmp, iter, mem, usize};
|
||||
use std::{iter, mem, usize};
|
||||
|
||||
/// State of a temporary during collection and promotion.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
@ -152,7 +152,6 @@ struct Promoter<'a, 'tcx: 'a> {
|
||||
source: &'a mut Mir<'tcx>,
|
||||
promoted: Mir<'tcx>,
|
||||
temps: &'a mut IndexVec<Local, TempState>,
|
||||
extra_statements: &'a mut Vec<(Location, Statement<'tcx>)>,
|
||||
|
||||
/// If true, all nested temps are also kept in the
|
||||
/// source MIR, not moved to the promoted MIR.
|
||||
@ -288,27 +287,21 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn promote_candidate(mut self, candidate: Candidate) {
|
||||
let mut rvalue = {
|
||||
let mut operand = {
|
||||
let promoted = &mut self.promoted;
|
||||
let literal = Literal::Promoted {
|
||||
index: Promoted::new(self.source.promoted.len())
|
||||
};
|
||||
let operand = |ty, span| {
|
||||
let promoted_id = Promoted::new(self.source.promoted.len());
|
||||
let mut promoted_place = |ty, span| {
|
||||
promoted.span = span;
|
||||
promoted.local_decls[RETURN_PLACE] =
|
||||
LocalDecl::new_return_place(ty, span);
|
||||
Operand::Constant(box Constant {
|
||||
span,
|
||||
ty,
|
||||
literal
|
||||
})
|
||||
Place::Promoted(box (promoted_id, ty))
|
||||
};
|
||||
let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
|
||||
match candidate {
|
||||
Candidate::Ref(loc) => {
|
||||
let ref mut statement = blocks[loc.block].statements[loc.statement_index];
|
||||
match statement.kind {
|
||||
StatementKind::Assign(_, Rvalue::Ref(r, bk, ref mut place)) => {
|
||||
StatementKind::Assign(_, Rvalue::Ref(_, _, ref mut place)) => {
|
||||
// Find the underlying local for this (necessarilly interior) borrow.
|
||||
// HACK(eddyb) using a recursive function because of mutable borrows.
|
||||
fn interior_base<'a, 'tcx>(place: &'a mut Place<'tcx>)
|
||||
@ -322,32 +315,9 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||
let place = interior_base(place);
|
||||
|
||||
let ty = place.ty(local_decls, self.tcx).to_ty(self.tcx);
|
||||
let ref_ty = self.tcx.mk_ref(r,
|
||||
ty::TypeAndMut {
|
||||
ty,
|
||||
mutbl: bk.to_mutbl_lossy()
|
||||
}
|
||||
);
|
||||
let span = statement.source_info.span;
|
||||
|
||||
// Create a temp to hold the promoted reference.
|
||||
// This is because `*r` requires `r` to be a local,
|
||||
// otherwise we would use the `promoted` directly.
|
||||
let mut promoted_ref = LocalDecl::new_temp(ref_ty, span);
|
||||
promoted_ref.source_info = statement.source_info;
|
||||
promoted_ref.visibility_scope = statement.source_info.scope;
|
||||
let promoted_ref = local_decls.push(promoted_ref);
|
||||
assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);
|
||||
self.extra_statements.push((loc, Statement {
|
||||
source_info: statement.source_info,
|
||||
kind: StatementKind::Assign(
|
||||
Place::Local(promoted_ref),
|
||||
Rvalue::Use(operand(ref_ty, span)),
|
||||
)
|
||||
}));
|
||||
let promoted_place = Place::Local(promoted_ref).deref();
|
||||
|
||||
Rvalue::Ref(r, bk, mem::replace(place, promoted_place))
|
||||
Operand::Move(mem::replace(place, promoted_place(ty, span)))
|
||||
}
|
||||
_ => bug!()
|
||||
}
|
||||
@ -358,7 +328,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||
TerminatorKind::Call { ref mut args, .. } => {
|
||||
let ty = args[index].ty(local_decls, self.tcx);
|
||||
let span = terminator.source_info.span;
|
||||
Rvalue::Use(mem::replace(&mut args[index], operand(ty, span)))
|
||||
let operand = Operand::Copy(promoted_place(ty, span));
|
||||
mem::replace(&mut args[index], operand)
|
||||
}
|
||||
_ => bug!()
|
||||
}
|
||||
@ -367,13 +338,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||
};
|
||||
|
||||
assert_eq!(self.new_block(), START_BLOCK);
|
||||
self.visit_rvalue(&mut rvalue, Location {
|
||||
self.visit_operand(&mut operand, Location {
|
||||
block: BasicBlock::new(0),
|
||||
statement_index: usize::MAX
|
||||
});
|
||||
|
||||
let span = self.promoted.span;
|
||||
self.assign(RETURN_PLACE, rvalue, span);
|
||||
self.assign(RETURN_PLACE, Rvalue::Use(operand), span);
|
||||
self.source.promoted.push(self.promoted);
|
||||
}
|
||||
}
|
||||
@ -397,7 +368,6 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
|
||||
// Visit candidates in reverse, in case they're nested.
|
||||
debug!("promote_candidates({:?})", candidates);
|
||||
|
||||
let mut extra_statements = vec![];
|
||||
for candidate in candidates.into_iter().rev() {
|
||||
match candidate {
|
||||
Candidate::Ref(Location { block, statement_index }) => {
|
||||
@ -437,19 +407,11 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
|
||||
tcx,
|
||||
source: mir,
|
||||
temps: &mut temps,
|
||||
extra_statements: &mut extra_statements,
|
||||
keep_original: false
|
||||
};
|
||||
promoter.promote_candidate(candidate);
|
||||
}
|
||||
|
||||
// Insert each of `extra_statements` before its indicated location, which
|
||||
// has to be done in reverse location order, to not invalidate the rest.
|
||||
extra_statements.sort_by_key(|&(loc, _)| cmp::Reverse(loc));
|
||||
for (loc, statement) in extra_statements {
|
||||
mir[loc.block].statements.insert(loc.statement_index, statement);
|
||||
}
|
||||
|
||||
// Eliminate assignments to, and drops of promoted temps.
|
||||
let promoted = |index: Local| temps[index] == TempState::PromotedOut;
|
||||
for block in mir.basic_blocks_mut() {
|
||||
|
@ -449,6 +449,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
location: Location) {
|
||||
match *place {
|
||||
Place::Local(ref local) => self.visit_local(local, context, location),
|
||||
Place::Promoted(_) => bug!("promoting already promoted MIR"),
|
||||
Place::Static(ref global) => {
|
||||
if self.tcx
|
||||
.get_attrs(global.def_id)
|
||||
@ -558,12 +559,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
Operand::Constant(ref constant) => {
|
||||
if let Literal::Value {
|
||||
value: &ty::Const { val: ConstValue::Unevaluated(def_id, _), ty, .. }
|
||||
} = constant.literal {
|
||||
if let ConstValue::Unevaluated(def_id, _) = constant.literal.val {
|
||||
// Don't peek inside trait associated constants.
|
||||
if self.tcx.trait_of_item(def_id).is_some() {
|
||||
self.add_type(ty);
|
||||
self.add_type(constant.literal.ty);
|
||||
} else {
|
||||
let (bits, _) = self.tcx.at(constant.span).mir_const_qualif(def_id);
|
||||
|
||||
@ -573,7 +572,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
// Just in case the type is more specific than
|
||||
// the definition, e.g. impl associated const
|
||||
// with type parameters, take it into account.
|
||||
self.qualif.restrict(ty, self.tcx, self.param_env);
|
||||
self.qualif.restrict(constant.literal.ty, self.tcx, self.param_env);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,11 +36,11 @@ impl MirPass for SimplifyBranches {
|
||||
for block in mir.basic_blocks_mut() {
|
||||
let terminator = block.terminator_mut();
|
||||
terminator.kind = match terminator.kind {
|
||||
TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant {
|
||||
literal: Literal::Value { ref value }, ..
|
||||
}), switch_ty, ref values, ref targets, .. } => {
|
||||
TerminatorKind::SwitchInt {
|
||||
discr: Operand::Constant(ref c), switch_ty, ref values, ref targets, ..
|
||||
} => {
|
||||
let switch_ty = ParamEnv::empty().and(switch_ty);
|
||||
if let Some(constint) = value.assert_bits(tcx, switch_ty) {
|
||||
if let Some(constint) = c.literal.assert_bits(tcx, switch_ty) {
|
||||
let (otherwise, targets) = targets.split_last().unwrap();
|
||||
let mut ret = TerminatorKind::Goto { target: *otherwise };
|
||||
for (&v, t) in values.iter().zip(targets.iter()) {
|
||||
@ -54,11 +54,9 @@ impl MirPass for SimplifyBranches {
|
||||
continue
|
||||
}
|
||||
},
|
||||
TerminatorKind::Assert { target, cond: Operand::Constant(box Constant {
|
||||
literal: Literal::Value {
|
||||
value
|
||||
}, ..
|
||||
}), expected, .. } if (value.assert_bool(tcx) == Some(true)) == expected => {
|
||||
TerminatorKind::Assert {
|
||||
target, cond: Operand::Constant(ref c), expected, ..
|
||||
} if (c.literal.assert_bool(tcx) == Some(true)) == expected => {
|
||||
TerminatorKind::Goto { target: target }
|
||||
},
|
||||
TerminatorKind::FalseEdges { real_target, .. } => {
|
||||
|
@ -960,9 +960,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
||||
Operand::Constant(box Constant {
|
||||
span: self.source_info.span,
|
||||
ty: self.tcx().types.usize,
|
||||
literal: Literal::Value {
|
||||
value: ty::Const::from_usize(self.tcx(), val.into())
|
||||
}
|
||||
literal: ty::Const::from_usize(self.tcx(), val.into()),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
// completely accurate (some things might be counted twice, others missed).
|
||||
|
||||
use rustc::mir::{AggregateKind, AssertMessage, BasicBlock, BasicBlockData};
|
||||
use rustc::mir::{Constant, Literal, Location, Local, LocalDecl};
|
||||
use rustc::mir::{Constant, Location, Local, LocalDecl};
|
||||
use rustc::mir::{Place, PlaceElem, PlaceProjection};
|
||||
use rustc::mir::{Mir, Operand, ProjectionElem};
|
||||
use rustc::mir::{Rvalue, SourceInfo, Statement, StatementKind};
|
||||
@ -204,6 +204,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
|
||||
self.record(match *place {
|
||||
Place::Local(..) => "Place::Local",
|
||||
Place::Static(..) => "Place::Static",
|
||||
Place::Promoted(..) => "Place::Promoted",
|
||||
Place::Projection(..) => "Place::Projection",
|
||||
}, place);
|
||||
self.super_place(place, context, location);
|
||||
@ -240,17 +241,6 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
|
||||
self.super_constant(constant, location);
|
||||
}
|
||||
|
||||
fn visit_literal(&mut self,
|
||||
literal: &Literal<'tcx>,
|
||||
location: Location) {
|
||||
self.record("Literal", literal);
|
||||
self.record(match *literal {
|
||||
Literal::Value { .. } => "Literal::Value",
|
||||
Literal::Promoted { .. } => "Literal::Promoted",
|
||||
}, literal);
|
||||
self.super_literal(literal, location);
|
||||
}
|
||||
|
||||
fn visit_source_info(&mut self,
|
||||
source_info: &SourceInfo) {
|
||||
self.record("SourceInfo", source_info);
|
||||
|
@ -12,21 +12,6 @@ note: lint level defined here
|
||||
LL | #![warn(const_err)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
warning: referenced constant has errors
|
||||
--> $DIR/conditional_array_execution.rs:19:20
|
||||
|
|
||||
LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
|
||||
| ----- attempt to subtract with overflow
|
||||
...
|
||||
LL | println!("{}", FOO);
|
||||
| ^^^
|
||||
|
||||
warning: this expression will panic at runtime
|
||||
--> $DIR/conditional_array_execution.rs:19:20
|
||||
|
|
||||
LL | println!("{}", FOO);
|
||||
| ^^^ referenced constant has errors
|
||||
|
||||
error[E0080]: referenced constant has errors
|
||||
--> $DIR/conditional_array_execution.rs:19:14
|
||||
|
|
||||
|
@ -17,8 +17,6 @@ const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
|
||||
|
||||
fn main() {
|
||||
println!("{}", FOO);
|
||||
//~^ WARN this expression will panic at runtime
|
||||
//~| WARN referenced constant
|
||||
//~| ERROR erroneous constant used
|
||||
//~^ ERROR erroneous constant used
|
||||
//~| E0080
|
||||
}
|
||||
|
@ -12,21 +12,6 @@ note: lint level defined here
|
||||
LL | #![warn(const_err)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
warning: referenced constant has errors
|
||||
--> $DIR/conditional_array_execution.rs:19:20
|
||||
|
|
||||
LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
|
||||
| ----- attempt to subtract with overflow
|
||||
...
|
||||
LL | println!("{}", FOO);
|
||||
| ^^^
|
||||
|
||||
warning: this expression will panic at runtime
|
||||
--> $DIR/conditional_array_execution.rs:19:20
|
||||
|
|
||||
LL | println!("{}", FOO);
|
||||
| ^^^ referenced constant has errors
|
||||
|
||||
error[E0080]: referenced constant has errors
|
||||
--> $DIR/conditional_array_execution.rs:19:20
|
||||
|
|
||||
|
@ -20,36 +20,6 @@ LL | const Y: u32 = foo(0-1);
|
||||
| |
|
||||
| attempt to subtract with overflow
|
||||
|
||||
warning: referenced constant has errors
|
||||
--> $DIR/issue-43197.rs:24:23
|
||||
|
|
||||
LL | const X: u32 = 0-1;
|
||||
| --- attempt to subtract with overflow
|
||||
...
|
||||
LL | println!("{} {}", X, Y);
|
||||
| ^
|
||||
|
||||
warning: this expression will panic at runtime
|
||||
--> $DIR/issue-43197.rs:24:23
|
||||
|
|
||||
LL | println!("{} {}", X, Y);
|
||||
| ^ referenced constant has errors
|
||||
|
||||
warning: referenced constant has errors
|
||||
--> $DIR/issue-43197.rs:24:26
|
||||
|
|
||||
LL | const Y: u32 = foo(0-1);
|
||||
| --- attempt to subtract with overflow
|
||||
LL | //~^ WARN this constant cannot be used
|
||||
LL | println!("{} {}", X, Y);
|
||||
| ^
|
||||
|
||||
warning: this expression will panic at runtime
|
||||
--> $DIR/issue-43197.rs:24:26
|
||||
|
|
||||
LL | println!("{} {}", X, Y);
|
||||
| ^ referenced constant has errors
|
||||
|
||||
error[E0080]: referenced constant has errors
|
||||
--> $DIR/issue-43197.rs:24:14
|
||||
|
|
||||
|
@ -22,12 +22,8 @@ fn main() {
|
||||
const Y: u32 = foo(0-1);
|
||||
//~^ WARN this constant cannot be used
|
||||
println!("{} {}", X, Y);
|
||||
//~^ WARN this expression will panic at runtime
|
||||
//~| WARN this expression will panic at runtime
|
||||
//~| ERROR erroneous constant used
|
||||
//~^ ERROR erroneous constant used
|
||||
//~| ERROR erroneous constant used
|
||||
//~| ERROR E0080
|
||||
//~| ERROR E0080
|
||||
//~| WARN referenced constant
|
||||
//~| WARN referenced constant
|
||||
}
|
||||
|
@ -20,36 +20,6 @@ LL | const Y: u32 = foo(0-1);
|
||||
| |
|
||||
| attempt to subtract with overflow
|
||||
|
||||
warning: referenced constant has errors
|
||||
--> $DIR/issue-43197.rs:24:23
|
||||
|
|
||||
LL | const X: u32 = 0-1;
|
||||
| --- attempt to subtract with overflow
|
||||
...
|
||||
LL | println!("{} {}", X, Y);
|
||||
| ^
|
||||
|
||||
warning: this expression will panic at runtime
|
||||
--> $DIR/issue-43197.rs:24:23
|
||||
|
|
||||
LL | println!("{} {}", X, Y);
|
||||
| ^ referenced constant has errors
|
||||
|
||||
warning: referenced constant has errors
|
||||
--> $DIR/issue-43197.rs:24:26
|
||||
|
|
||||
LL | const Y: u32 = foo(0-1);
|
||||
| --- attempt to subtract with overflow
|
||||
LL | //~^ WARN this constant cannot be used
|
||||
LL | println!("{} {}", X, Y);
|
||||
| ^
|
||||
|
||||
warning: this expression will panic at runtime
|
||||
--> $DIR/issue-43197.rs:24:26
|
||||
|
|
||||
LL | println!("{} {}", X, Y);
|
||||
| ^ referenced constant has errors
|
||||
|
||||
error[E0080]: referenced constant has errors
|
||||
--> $DIR/issue-43197.rs:24:26
|
||||
|
|
||||
|
@ -8,6 +8,8 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// compile-pass
|
||||
|
||||
#![feature(const_fn)]
|
||||
|
||||
#![deny(const_err)]
|
||||
@ -23,15 +25,13 @@ const fn bar() -> u8 {
|
||||
// is run on a system whose pointers need more
|
||||
// than 8 bits
|
||||
Bar { a: &42 }.b as u8
|
||||
//~^ ERROR this expression will panic at runtime
|
||||
//~| ERROR this expression will panic at runtime
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// FIXME(oli-obk): this should compile but panic at runtime
|
||||
// if we change the `const_err` lint to allow this will actually compile, but then
|
||||
// continue with undefined values.
|
||||
// FIXME(oli-obk): this should panic at runtime
|
||||
// this will actually compile, but then
|
||||
// abort at runtime (not panic, hard abort).
|
||||
let x: &'static u8 = &(bar() + 1);
|
||||
let y = *x;
|
||||
unreachable!();
|
||||
|
@ -1,20 +0,0 @@
|
||||
error: this expression will panic at runtime
|
||||
--> $DIR/promoted_const_fn_fail.rs:25:9
|
||||
|
|
||||
LL | Bar { a: &42 }.b as u8
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ a raw memory access tried to access part of a pointer value as raw bytes
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/promoted_const_fn_fail.rs:13:9
|
||||
|
|
||||
LL | #![deny(const_err)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: this expression will panic at runtime
|
||||
--> $DIR/promoted_const_fn_fail.rs:25:9
|
||||
|
|
||||
LL | Bar { a: &42 }.b as u8
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ a raw memory access tried to access part of a pointer value as raw bytes
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
@ -18,13 +18,11 @@ fn main() {
|
||||
//~^ WARN const_err
|
||||
println!("{}", 1/(1-1));
|
||||
//~^ WARN const_err
|
||||
//~| WARN const_err
|
||||
let _x = 1/(1-1);
|
||||
//~^ WARN const_err
|
||||
//~| WARN const_err
|
||||
println!("{}", 1/(false as u32));
|
||||
//~^ WARN const_err
|
||||
//~| WARN const_err
|
||||
let _x = 1/(false as u32);
|
||||
//~^ WARN const_err
|
||||
//~| WARN const_err
|
||||
|
@ -16,44 +16,32 @@ warning: attempt to divide by zero
|
||||
LL | println!("{}", 1/(1-1));
|
||||
| ^^^^^^^
|
||||
|
||||
warning: this expression will panic at runtime
|
||||
--> $DIR/promoted_errors.rs:19:20
|
||||
|
|
||||
LL | println!("{}", 1/(1-1));
|
||||
| ^^^^^^^ attempt to divide by zero
|
||||
|
||||
warning: attempt to divide by zero
|
||||
--> $DIR/promoted_errors.rs:22:14
|
||||
--> $DIR/promoted_errors.rs:21:14
|
||||
|
|
||||
LL | let _x = 1/(1-1);
|
||||
| ^^^^^^^
|
||||
|
||||
warning: this expression will panic at runtime
|
||||
--> $DIR/promoted_errors.rs:22:14
|
||||
--> $DIR/promoted_errors.rs:21:14
|
||||
|
|
||||
LL | let _x = 1/(1-1);
|
||||
| ^^^^^^^ attempt to divide by zero
|
||||
|
||||
warning: attempt to divide by zero
|
||||
--> $DIR/promoted_errors.rs:25:20
|
||||
--> $DIR/promoted_errors.rs:24:20
|
||||
|
|
||||
LL | println!("{}", 1/(false as u32));
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: this expression will panic at runtime
|
||||
--> $DIR/promoted_errors.rs:25:20
|
||||
|
|
||||
LL | println!("{}", 1/(false as u32));
|
||||
| ^^^^^^^^^^^^^^^^ attempt to divide by zero
|
||||
|
||||
warning: attempt to divide by zero
|
||||
--> $DIR/promoted_errors.rs:28:14
|
||||
--> $DIR/promoted_errors.rs:26:14
|
||||
|
|
||||
LL | let _x = 1/(false as u32);
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: this expression will panic at runtime
|
||||
--> $DIR/promoted_errors.rs:28:14
|
||||
--> $DIR/promoted_errors.rs:26:14
|
||||
|
|
||||
LL | let _x = 1/(false as u32);
|
||||
| ^^^^^^^^^^^^^^^^ attempt to divide by zero
|
||||
|
Loading…
Reference in New Issue
Block a user