diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 3ff8ffb35054..3563dbe50966 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -315,7 +315,8 @@ impl<'a, 'tcx> HashStable> for mir::Rvalue<'tcx> mir::Rvalue::Discriminant(ref lvalue) => { lvalue.hash_stable(hcx, hasher); } - mir::Rvalue::Box(ty) => { + mir::Rvalue::NullaryOp(op, ty) => { + op.hash_stable(hcx, hasher); ty.hash_stable(hcx, hasher); } mir::Rvalue::Aggregate(ref kind, ref operands) => { @@ -374,7 +375,8 @@ impl_stable_hash_for!(enum mir::BinOp { Le, Ne, Ge, - Gt + Gt, + Offset }); impl_stable_hash_for!(enum mir::UnOp { @@ -382,6 +384,10 @@ impl_stable_hash_for!(enum mir::UnOp { Neg }); +impl_stable_hash_for!(enum mir::NullOp { + Box, + SizeOf +}); impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal }); diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index fe2ad498e996..80c42917196d 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1046,6 +1046,7 @@ pub enum Rvalue<'tcx> { BinaryOp(BinOp, Operand<'tcx>, Operand<'tcx>), CheckedBinaryOp(BinOp, Operand<'tcx>, Operand<'tcx>), + NullaryOp(NullOp, Ty<'tcx>), UnaryOp(UnOp, Operand<'tcx>), /// Read the discriminant of an ADT. @@ -1054,9 +1055,6 @@ pub enum Rvalue<'tcx> { /// be defined to return, say, a 0) if ADT is not an enum. Discriminant(Lvalue<'tcx>), - /// Creates an *uninitialized* Box - Box(Ty<'tcx>), - /// Create an aggregate value, like a tuple or struct. This is /// only needed because we want to distinguish `dest = Foo { x: /// ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case @@ -1132,6 +1130,8 @@ pub enum BinOp { Ge, /// The `>` operator (greater than) Gt, + /// The `ptr.offset` operator + Offset, } impl BinOp { @@ -1144,6 +1144,14 @@ impl BinOp { } } +#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] +pub enum NullOp { + /// Return the size of a value of that type + SizeOf, + /// Create a new uninitialized box for a value of that type + Box, +} + #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum UnOp { /// The `!` operator for logical inversion @@ -1167,7 +1175,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { } UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a), Discriminant(ref lval) => write!(fmt, "discriminant({:?})", lval), - Box(ref t) => write!(fmt, "Box({:?})", t), + NullaryOp(ref op, ref t) => write!(fmt, "{:?}({:?})", op, t), Ref(_, borrow_kind, ref lv) => { let kind_str = match borrow_kind { BorrowKind::Shared => "", @@ -1601,7 +1609,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { CheckedBinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)), UnaryOp(op, ref val) => UnaryOp(op, val.fold_with(folder)), Discriminant(ref lval) => Discriminant(lval.fold_with(folder)), - Box(ty) => Box(ty.fold_with(folder)), + NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)), Aggregate(ref kind, ref fields) => { let kind = box match **kind { AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)), @@ -1629,7 +1637,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { rhs.visit_with(visitor) || lhs.visit_with(visitor), UnaryOp(_, ref val) => val.visit_with(visitor), Discriminant(ref lval) => lval.visit_with(visitor), - Box(ty) => ty.visit_with(visitor), + NullaryOp(_, ty) => ty.visit_with(visitor), Aggregate(ref kind, ref fields) => { (match **kind { AggregateKind::Array(ty) => ty.visit_with(visitor), diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 7bc1dc58c29d..6078778a61d5 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -166,7 +166,8 @@ impl<'tcx> Rvalue<'tcx> { let ty = op.ty(tcx, lhs_ty, rhs_ty); tcx.intern_tup(&[ty, tcx.types.bool], false) } - Rvalue::UnaryOp(_, ref operand) => { + Rvalue::UnaryOp(UnOp::Not, ref operand) | + Rvalue::UnaryOp(UnOp::Neg, ref operand) => { operand.ty(mir, tcx) } Rvalue::Discriminant(ref lval) => { @@ -179,9 +180,8 @@ impl<'tcx> Rvalue<'tcx> { bug!("Rvalue::Discriminant on Lvalue of type {:?}", ty); } } - Rvalue::Box(t) => { - tcx.mk_box(t) - } + Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t), + Rvalue::NullaryOp(NullOp::SizeOf, _) => tcx.types.usize, Rvalue::Aggregate(ref ak, ref ops) => { match **ak { AggregateKind::Array(ty) => { @@ -227,7 +227,7 @@ impl<'tcx> BinOp { assert_eq!(lhs_ty, rhs_ty); lhs_ty } - &BinOp::Shl | &BinOp::Shr => { + &BinOp::Shl | &BinOp::Shr | &BinOp::Offset => { lhs_ty // lhs_ty can be != rhs_ty } &BinOp::Eq | &BinOp::Lt | &BinOp::Le | @@ -270,7 +270,8 @@ impl BinOp { BinOp::Lt => hir::BinOp_::BiLt, BinOp::Gt => hir::BinOp_::BiGt, BinOp::Le => hir::BinOp_::BiLe, - BinOp::Ge => hir::BinOp_::BiGe + BinOp::Ge => hir::BinOp_::BiGe, + BinOp::Offset => unreachable!() } } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 557fedadeba6..780ce736bfd3 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -509,7 +509,7 @@ macro_rules! make_mir_visitor { self.visit_lvalue(lvalue, LvalueContext::Inspect, location); } - Rvalue::Box(ref $($mutability)* ty) => { + Rvalue::NullaryOp(_op, ref $($mutability)* ty) => { self.visit_ty(ty); } diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 931cdf4f6861..b03d2a775df7 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -438,7 +438,8 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { Rvalue::Ref(..) | Rvalue::Discriminant(..) | Rvalue::Len(..) | - Rvalue::Box(..) => { + Rvalue::NullaryOp(NullOp::SizeOf, _) | + Rvalue::NullaryOp(NullOp::Box, _) => { // This returns an rvalue with uninitialized contents. We can't // move out of it here because it is an rvalue - assignments always // completely initialize their lvalue. diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index e1832e0a0af3..2884b60fdd8a 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -97,7 +97,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let value = this.hir.mirror(value); let result = this.temp(expr.ty, expr_span); // to start, malloc some memory of suitable type (thus far, uninitialized): - this.cfg.push_assign(block, source_info, &result, Rvalue::Box(value.ty)); + let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty); + this.cfg.push_assign(block, source_info, &result, box_); this.in_scope(value_extents, block, |this| { // schedule a shallow free of that memory, lest we unwind: this.schedule_box_free(expr_span, value_extents, &result, value.ty); diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 19714849b091..fa88eca6ec3f 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -53,7 +53,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> { Rvalue::CheckedBinaryOp(..) | Rvalue::UnaryOp(..) | Rvalue::Discriminant(..) | - Rvalue::Box(..) | + Rvalue::NullaryOp(..) | Rvalue::Aggregate(..) => { // These variants don't contain regions. } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 4e84cbe6fecb..a938e5e29cd9 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -595,7 +595,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { match *rvalue { Rvalue::Use(_) | Rvalue::Repeat(..) | - Rvalue::UnaryOp(..) | + Rvalue::UnaryOp(UnOp::Neg, _) | + Rvalue::UnaryOp(UnOp::Not, _) | + Rvalue::NullaryOp(NullOp::SizeOf, _) | Rvalue::CheckedBinaryOp(..) | Rvalue::Cast(CastKind::ReifyFnPointer, ..) | Rvalue::Cast(CastKind::UnsafeFnPointer, ..) | @@ -703,7 +705,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { if let ty::TyRawPtr(_) = lhs.ty(self.mir, self.tcx).sty { assert!(op == BinOp::Eq || op == BinOp::Ne || op == BinOp::Le || op == BinOp::Lt || - op == BinOp::Ge || op == BinOp::Gt); + op == BinOp::Ge || op == BinOp::Gt || + op == BinOp::Offset); self.add(Qualif::NOT_CONST); if self.mode != Mode::Fn { @@ -719,7 +722,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } - Rvalue::Box(_) => { + Rvalue::NullaryOp(NullOp::Box, _) => { self.add(Qualif::NOT_CONST); if self.mode != Mode::Fn { struct_span_err!(self.tcx.sess, self.span, E0010, diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index 242187251866..e29da3a64965 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -186,7 +186,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { Rvalue::CheckedBinaryOp(..) => "Rvalue::CheckedBinaryOp", Rvalue::UnaryOp(..) => "Rvalue::UnaryOp", Rvalue::Discriminant(..) => "Rvalue::Discriminant", - Rvalue::Box(..) => "Rvalue::Box", + Rvalue::NullaryOp(..) => "Rvalue::NullaryOp", Rvalue::Aggregate(ref kind, ref _operands) => { // AggregateKind is not distinguished by visit API, so // record it. (`super_rvalue` handles `_operands`.) diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 429e7b016102..dc4e947b0f61 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -502,7 +502,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { _ => bug!(), } } - mir::Rvalue::Box(..) => { + mir::Rvalue::NullaryOp(mir::NullOp::Box, _) => { let tcx = self.scx.tcx(); let exchange_malloc_fn_def_id = tcx .lang_items diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 59876a7f2a20..fa400b54d270 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -76,6 +76,7 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf let align = C_uint(bcx.ccx, align); return (size, align); } + assert!(!info.is_null()); match t.sty { ty::TyAdt(def, substs) => { let ccx = bcx.ccx; diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index cd27ddda1b15..4967ef2f7908 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -796,6 +796,12 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { Const::new(llval, operand.ty) } + mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => { + assert!(self.ccx.shared().type_is_sized(ty)); + let llval = C_uint(self.ccx, self.ccx.size_of(ty)); + Const::new(llval, tcx.types.usize) + } + _ => span_bug!(span, "{:?} in constant", rvalue) }; @@ -870,6 +876,7 @@ pub fn const_scalar_binop(op: mir::BinOp, llvm::LLVMConstICmp(cmp, lhs, rhs) } } + mir::BinOp::Offset => unreachable!("BinOp::Offset in const-eval!") } } } diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index 8b7c7d9d3723..a12d0fec1cdd 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -114,7 +114,7 @@ impl<'a, 'tcx> OperandRef<'tcx> { pub fn deref(self) -> LvalueRef<'tcx> { let projected_ty = self.ty.builtin_deref(true, ty::NoPreference) - .unwrap().ty; + .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self)).ty; let (llptr, llextra) = match self.val { OperandValue::Immediate(llptr) => (llptr, ptr::null_mut()), OperandValue::Pair(llptr, llextra) => (llptr, llextra), diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 667075e6970e..b2f44a5d89f8 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -432,7 +432,17 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { }) } - mir::Rvalue::Box(content_ty) => { + mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => { + assert!(bcx.ccx.shared().type_is_sized(ty)); + let val = C_uint(bcx.ccx, bcx.ccx.size_of(ty)); + let tcx = bcx.tcx(); + (bcx, OperandRef { + val: OperandValue::Immediate(val), + ty: tcx.types.usize, + }) + } + + mir::Rvalue::NullaryOp(mir::NullOp::Box, content_ty) => { let content_ty: Ty<'tcx> = self.monomorphize(&content_ty); let llty = type_of::type_of(bcx.ccx, content_ty); let llsize = machine::llsize_of(bcx.ccx, llty); @@ -515,6 +525,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { mir::BinOp::BitOr => bcx.or(lhs, rhs), mir::BinOp::BitAnd => bcx.and(lhs, rhs), mir::BinOp::BitXor => bcx.xor(lhs, rhs), + mir::BinOp::Offset => bcx.inbounds_gep(lhs, &[rhs]), mir::BinOp::Shl => common::build_unchecked_lshift(bcx, lhs, rhs), mir::BinOp::Shr => common::build_unchecked_rshift(bcx, input_ty, lhs, rhs), mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt | @@ -660,7 +671,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { mir::Rvalue::CheckedBinaryOp(..) | mir::Rvalue::UnaryOp(..) | mir::Rvalue::Discriminant(..) | - mir::Rvalue::Box(..) | + mir::Rvalue::NullaryOp(..) | mir::Rvalue::Use(..) => // (*) true, mir::Rvalue::Repeat(..) | diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index c24867224ea8..838c180c70b7 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -781,11 +781,15 @@ extern "C" void LLVMRustWriteTypeToString(LLVMTypeRef Ty, RustStringRef Str) { extern "C" void LLVMRustWriteValueToString(LLVMValueRef V, RustStringRef Str) { RawRustStringOstream OS(Str); - OS << "("; - unwrap(V)->getType()->print(OS); - OS << ":"; - unwrap(V)->print(OS); - OS << ")"; + if (!V) { + OS << "(null)"; + } else { + OS << "("; + unwrap(V)->getType()->print(OS); + OS << ":"; + unwrap(V)->print(OS); + OS << ")"; + } } extern "C" bool LLVMRustLinkInExternalBitcode(LLVMModuleRef DstRef, char *BC,