diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 2c3b479c7dd0f..6f0f9cabef345 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -18,7 +18,6 @@ use rustc::mir::visit::{Visitor, LvalueContext}; use rustc::mir::traversal; use common; use super::MirContext; -use super::rvalue; pub fn lvalue_locals<'a, 'tcx>(mircx: &MirContext<'a, 'tcx>) -> BitVector { let mir = mircx.mir; @@ -92,7 +91,7 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { if let mir::Lvalue::Local(index) = *lvalue { self.mark_assigned(index); - if !rvalue::rvalue_creates_operand(rvalue) { + if !self.cx.rvalue_creates_operand(rvalue) { self.mark_as_lvalue(index); } } else { diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 6419f41f86b6d..eaedabc1f54c9 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -11,20 +11,18 @@ use libc::c_uint; use llvm::{self, ValueRef, BasicBlockRef}; use llvm::debuginfo::DIScope; -use rustc::ty::{self, layout}; +use rustc::ty::{self, layout, Ty, TypeFoldable}; use rustc::mir::{self, Mir}; use rustc::mir::tcx::LvalueTy; use rustc::ty::subst::Substs; use rustc::infer::TransNormalize; -use rustc::ty::TypeFoldable; use session::config::FullDebugInfo; use base; use builder::Builder; -use common::{self, CrateContext, C_null, Funclet}; +use common::{self, CrateContext, Funclet}; use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext}; use monomorphize::{self, Instance}; use abi::FnType; -use type_of; use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos, Span}; use syntax::symbol::keywords; @@ -176,23 +174,12 @@ enum LocalRef<'tcx> { impl<'tcx> LocalRef<'tcx> { fn new_operand<'a>(ccx: &CrateContext<'a, 'tcx>, - ty: ty::Ty<'tcx>) -> LocalRef<'tcx> { + ty: Ty<'tcx>) -> LocalRef<'tcx> { if common::type_is_zero_size(ccx, ty) { // Zero-size temporaries aren't always initialized, which // doesn't matter because they don't contain data, but // we need something in the operand. - let llty = type_of::type_of(ccx, ty); - let val = if common::type_is_imm_pair(ccx, ty) { - let fields = llty.field_types(); - OperandValue::Pair(C_null(fields[0]), C_null(fields[1])) - } else { - OperandValue::Immediate(C_null(llty)) - }; - let op = OperandRef { - val: val, - ty: ty - }; - LocalRef::Operand(Some(op)) + LocalRef::Operand(Some(OperandRef::new_zst(ccx, ty))) } else { LocalRef::Operand(None) } diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index cb77fcbbff85d..df6667afd442e 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -15,7 +15,7 @@ use rustc::mir; use rustc_data_structures::indexed_vec::Idx; use base; -use common; +use common::{self, CrateContext, C_null}; use builder::Builder; use value::Value; use type_of; @@ -77,6 +77,22 @@ impl<'tcx> fmt::Debug for OperandRef<'tcx> { } impl<'a, 'tcx> OperandRef<'tcx> { + pub fn new_zst(ccx: &CrateContext<'a, 'tcx>, + ty: Ty<'tcx>) -> OperandRef<'tcx> { + assert!(common::type_is_zero_size(ccx, ty)); + let llty = type_of::type_of(ccx, ty); + let val = if common::type_is_imm_pair(ccx, ty) { + let fields = llty.field_types(); + OperandValue::Pair(C_null(fields[0]), C_null(fields[1])) + } else { + OperandValue::Immediate(C_null(llty)) + }; + OperandRef { + val: val, + ty: ty + } + } + /// Asserts that this operand refers to a scalar and returns /// a reference to its value. pub fn immediate(self) -> ValueRef { diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index b6af4e52e820b..4328f2516970e 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -157,7 +157,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } _ => { - assert!(rvalue_creates_operand(rvalue)); + assert!(self.rvalue_creates_operand(rvalue)); let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue); self.store_operand(&bcx, dest.llval, dest.alignment.to_align(), temp); bcx @@ -170,7 +170,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { rvalue: &mir::Rvalue<'tcx>) -> (Builder<'a, 'tcx>, OperandRef<'tcx>) { - assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); + assert!(self.rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); match *rvalue { mir::Rvalue::Cast(ref kind, ref source, cast_ty) => { @@ -478,8 +478,10 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) => { - bug!("cannot generate operand from rvalue {:?}", rvalue); - + // According to `rvalue_creates_operand`, only ZST + // aggregate rvalues are allowed to be operands. + let ty = rvalue.ty(self.mir, self.ccx.tcx()); + (bcx, OperandRef::new_zst(self.ccx, self.monomorphize(&ty))) } } } @@ -662,26 +664,29 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { OperandValue::Pair(val, of) } -} -pub fn rvalue_creates_operand(rvalue: &mir::Rvalue) -> bool { - match *rvalue { - mir::Rvalue::Ref(..) | - mir::Rvalue::Len(..) | - mir::Rvalue::Cast(..) | // (*) - mir::Rvalue::BinaryOp(..) | - mir::Rvalue::CheckedBinaryOp(..) | - mir::Rvalue::UnaryOp(..) | - mir::Rvalue::Discriminant(..) | - mir::Rvalue::Box(..) | - mir::Rvalue::Use(..) => - true, - mir::Rvalue::Repeat(..) | - mir::Rvalue::Aggregate(..) => - false, - } + pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>) -> bool { + match *rvalue { + mir::Rvalue::Ref(..) | + mir::Rvalue::Len(..) | + mir::Rvalue::Cast(..) | // (*) + mir::Rvalue::BinaryOp(..) | + mir::Rvalue::CheckedBinaryOp(..) | + mir::Rvalue::UnaryOp(..) | + mir::Rvalue::Discriminant(..) | + mir::Rvalue::Box(..) | + mir::Rvalue::Use(..) => + true, + mir::Rvalue::Repeat(..) | + mir::Rvalue::Aggregate(..) => { + let ty = rvalue.ty(self.mir, self.ccx.tcx()); + let ty = self.monomorphize(&ty); + common::type_is_zero_size(self.ccx, ty) + } + } - // (*) this is only true if the type is suitable + // (*) this is only true if the type is suitable + } } #[derive(Copy, Clone)]