Promoteds are statics and statics have a place, not just a value

This commit is contained in:
Oliver Schneider 2018-07-22 01:01:07 +02:00
parent 210d61f05c
commit de511438cd
54 changed files with 354 additions and 574 deletions

View File

@ -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> {

View File

@ -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,
}
}
}

View File

@ -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) =>

View File

@ -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) {

View File

@ -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);

View File

@ -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),

View File

@ -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)
})

View File

@ -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.

View File

@ -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)

View File

@ -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),

View File

@ -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,
};

View File

@ -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),

View File

@ -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);

View File

@ -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) => {

View File

@ -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),
}

View File

@ -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

View File

@ -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;

View File

@ -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)
}

View File

@ -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,
},

View File

@ -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);

View File

@ -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)
}

View File

@ -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 {

View File

@ -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,

View File

@ -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))
}

View File

@ -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) {

View File

@ -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) |

View File

@ -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));
}
}

View File

@ -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,

View File

@ -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))

View File

@ -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,

View File

@ -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);

View File

@ -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])
}

View File

@ -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 {

View File

@ -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",

View File

@ -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,
}
}

View File

@ -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),
})))
}

View File

@ -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,

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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() {

View File

@ -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);
}
}
}

View File

@ -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, .. } => {

View File

@ -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()),
})
}

View File

@ -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);

View File

@ -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
|

View File

@ -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
}

View File

@ -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
|

View File

@ -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
|

View File

@ -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
}

View File

@ -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
|

View File

@ -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!();

View File

@ -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

View File

@ -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

View File

@ -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