Skip to content

Commit bdfb135

Browse files
committed
Auto merge of #29781 - arielb1:mir-casts, r=nikomatsakis
I am also planning to implement casts, but I will probably do it in a separate PR. r? @nikomatsakis
2 parents c10569c + b9b45a0 commit bdfb135

File tree

16 files changed

+998
-289
lines changed

16 files changed

+998
-289
lines changed

src/librustc_mir/hair/cx/expr.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -386,14 +386,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
386386
};
387387
}
388388

389-
if let Some(target) = adj.unsize {
390-
expr = Expr {
391-
temp_lifetime: temp_lifetime,
392-
ty: target,
393-
span: self.span,
394-
kind: ExprKind::Unsize { source: expr.to_ref() },
395-
};
396-
} else if let Some(autoref) = adj.autoref {
389+
if let Some(autoref) = adj.autoref {
397390
let adjusted_ty = expr.ty.adjust_for_autoref(cx.tcx, Some(autoref));
398391
match autoref {
399392
ty::adjustment::AutoPtr(r, m) => {
@@ -433,6 +426,15 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
433426
}
434427
}
435428
}
429+
430+
if let Some(target) = adj.unsize {
431+
expr = Expr {
432+
temp_lifetime: temp_lifetime,
433+
ty: target,
434+
span: self.span,
435+
kind: ExprKind::Unsize { source: expr.to_ref() },
436+
};
437+
}
436438
}
437439
}
438440

src/librustc_mir/tcx/mod.rs

+63
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use repr::*;
1717
use rustc::middle::subst::Substs;
1818
use rustc::middle::ty::{self, AdtDef, Ty};
19+
use rustc_front::hir;
1920

2021
#[derive(Copy, Clone, Debug)]
2122
pub enum LvalueTy<'tcx> {
@@ -102,6 +103,31 @@ impl<'tcx> Mir<'tcx> {
102103
}
103104
}
104105

106+
pub fn binop_ty(&self,
107+
tcx: &ty::ctxt<'tcx>,
108+
op: BinOp,
109+
lhs_ty: Ty<'tcx>,
110+
rhs_ty: Ty<'tcx>)
111+
-> Ty<'tcx>
112+
{
113+
// FIXME: handle SIMD correctly
114+
match op {
115+
BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Rem |
116+
BinOp::BitXor | BinOp::BitAnd | BinOp::BitOr => {
117+
// these should be integers or floats of the same size.
118+
assert_eq!(lhs_ty, rhs_ty);
119+
lhs_ty
120+
}
121+
BinOp::Shl | BinOp::Shr => {
122+
lhs_ty // lhs_ty can be != rhs_ty
123+
}
124+
BinOp::Eq | BinOp::Lt | BinOp::Le |
125+
BinOp::Ne | BinOp::Ge | BinOp::Gt => {
126+
tcx.types.bool
127+
}
128+
}
129+
}
130+
105131
pub fn lvalue_ty(&self,
106132
tcx: &ty::ctxt<'tcx>,
107133
lvalue: &Lvalue<'tcx>)
@@ -123,3 +149,40 @@ impl<'tcx> Mir<'tcx> {
123149
}
124150
}
125151
}
152+
153+
impl BorrowKind {
154+
pub fn to_mutbl_lossy(self) -> hir::Mutability {
155+
match self {
156+
BorrowKind::Mut => hir::MutMutable,
157+
BorrowKind::Shared => hir::MutImmutable,
158+
159+
// We have no type corresponding to a unique imm borrow, so
160+
// use `&mut`. It gives all the capabilities of an `&uniq`
161+
// and hence is a safe "over approximation".
162+
BorrowKind::Unique => hir::MutMutable,
163+
}
164+
}
165+
}
166+
167+
impl BinOp {
168+
pub fn to_hir_binop(self) -> hir::BinOp_ {
169+
match self {
170+
BinOp::Add => hir::BinOp_::BiAdd,
171+
BinOp::Sub => hir::BinOp_::BiSub,
172+
BinOp::Mul => hir::BinOp_::BiMul,
173+
BinOp::Div => hir::BinOp_::BiDiv,
174+
BinOp::Rem => hir::BinOp_::BiRem,
175+
BinOp::BitXor => hir::BinOp_::BiBitXor,
176+
BinOp::BitAnd => hir::BinOp_::BiBitAnd,
177+
BinOp::BitOr => hir::BinOp_::BiBitOr,
178+
BinOp::Shl => hir::BinOp_::BiShl,
179+
BinOp::Shr => hir::BinOp_::BiShr,
180+
BinOp::Eq => hir::BinOp_::BiEq,
181+
BinOp::Ne => hir::BinOp_::BiNe,
182+
BinOp::Lt => hir::BinOp_::BiLt,
183+
BinOp::Gt => hir::BinOp_::BiGt,
184+
BinOp::Le => hir::BinOp_::BiLe,
185+
BinOp::Ge => hir::BinOp_::BiGe
186+
}
187+
}
188+
}

src/librustc_trans/trans/base.rs

+201-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ use trans::builder::{Builder, noname};
5555
use trans::callee;
5656
use trans::cleanup::{self, CleanupMethods, DropHint};
5757
use trans::closure;
58-
use trans::common::{Block, C_bool, C_bytes_in_context, C_i32, C_int, C_integral};
58+
use trans::common::{Block, C_bool, C_bytes_in_context, C_i32, C_int, C_uint, C_integral};
5959
use trans::common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef};
6060
use trans::common::{CrateContext, DropFlagHintsMap, Field, FunctionContext};
6161
use trans::common::{Result, NodeIdAndSpan, VariantInfo};
@@ -312,6 +312,49 @@ pub fn bin_op_to_fcmp_predicate(ccx: &CrateContext, op: hir::BinOp_)
312312
}
313313
}
314314

315+
pub fn compare_fat_ptrs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
316+
lhs_addr: ValueRef,
317+
lhs_extra: ValueRef,
318+
rhs_addr: ValueRef,
319+
rhs_extra: ValueRef,
320+
_t: Ty<'tcx>,
321+
op: hir::BinOp_,
322+
debug_loc: DebugLoc)
323+
-> ValueRef {
324+
match op {
325+
hir::BiEq => {
326+
let addr_eq = ICmp(bcx, llvm::IntEQ, lhs_addr, rhs_addr, debug_loc);
327+
let extra_eq = ICmp(bcx, llvm::IntEQ, lhs_extra, rhs_extra, debug_loc);
328+
And(bcx, addr_eq, extra_eq, debug_loc)
329+
}
330+
hir::BiNe => {
331+
let addr_eq = ICmp(bcx, llvm::IntNE, lhs_addr, rhs_addr, debug_loc);
332+
let extra_eq = ICmp(bcx, llvm::IntNE, lhs_extra, rhs_extra, debug_loc);
333+
Or(bcx, addr_eq, extra_eq, debug_loc)
334+
}
335+
hir::BiLe | hir::BiLt | hir::BiGe | hir::BiGt => {
336+
// a OP b ~ a.0 STRICT(OP) b.0 | (a.0 == b.0 && a.1 OP a.1)
337+
let (op, strict_op) = match op {
338+
hir::BiLt => (llvm::IntULT, llvm::IntULT),
339+
hir::BiLe => (llvm::IntULE, llvm::IntULT),
340+
hir::BiGt => (llvm::IntUGT, llvm::IntUGT),
341+
hir::BiGe => (llvm::IntUGE, llvm::IntUGT),
342+
_ => unreachable!()
343+
};
344+
345+
let addr_eq = ICmp(bcx, llvm::IntEQ, lhs_addr, rhs_addr, debug_loc);
346+
let extra_op = ICmp(bcx, op, lhs_extra, rhs_extra, debug_loc);
347+
let addr_eq_extra_op = And(bcx, addr_eq, extra_op, debug_loc);
348+
349+
let addr_strict = ICmp(bcx, strict_op, lhs_addr, rhs_addr, debug_loc);
350+
Or(bcx, addr_strict, addr_eq_extra_op, debug_loc)
351+
}
352+
_ => {
353+
bcx.tcx().sess.bug("unexpected fat ptr binop");
354+
}
355+
}
356+
}
357+
315358
pub fn compare_scalar_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
316359
lhs: ValueRef,
317360
rhs: ValueRef,
@@ -336,6 +379,17 @@ pub fn compare_scalar_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
336379
ty::TyRawPtr(mt) if common::type_is_sized(bcx.tcx(), mt.ty) => {
337380
ICmp(bcx, bin_op_to_icmp_predicate(bcx.ccx(), op, false), lhs, rhs, debug_loc)
338381
}
382+
ty::TyRawPtr(_) => {
383+
let lhs_addr = Load(bcx, GEPi(bcx, lhs, &[0, abi::FAT_PTR_ADDR]));
384+
let lhs_extra = Load(bcx, GEPi(bcx, lhs, &[0, abi::FAT_PTR_EXTRA]));
385+
386+
let rhs_addr = Load(bcx, GEPi(bcx, rhs, &[0, abi::FAT_PTR_ADDR]));
387+
let rhs_extra = Load(bcx, GEPi(bcx, rhs, &[0, abi::FAT_PTR_EXTRA]));
388+
compare_fat_ptrs(bcx,
389+
lhs_addr, lhs_extra,
390+
rhs_addr, rhs_extra,
391+
t, op, debug_loc)
392+
}
339393
ty::TyInt(_) => {
340394
ICmp(bcx, bin_op_to_icmp_predicate(bcx.ccx(), op, true), lhs, rhs, debug_loc)
341395
}
@@ -523,6 +577,129 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
523577
return cx;
524578
}
525579

580+
581+
/// Retrieve the information we are losing (making dynamic) in an unsizing
582+
/// adjustment.
583+
///
584+
/// The `old_info` argument is a bit funny. It is intended for use
585+
/// in an upcast, where the new vtable for an object will be drived
586+
/// from the old one.
587+
pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
588+
source: Ty<'tcx>,
589+
target: Ty<'tcx>,
590+
old_info: Option<ValueRef>,
591+
param_substs: &'tcx Substs<'tcx>)
592+
-> ValueRef {
593+
let (source, target) = ccx.tcx().struct_lockstep_tails(source, target);
594+
match (&source.sty, &target.sty) {
595+
(&ty::TyArray(_, len), &ty::TySlice(_)) => C_uint(ccx, len),
596+
(&ty::TyTrait(_), &ty::TyTrait(_)) => {
597+
// For now, upcasts are limited to changes in marker
598+
// traits, and hence never actually require an actual
599+
// change to the vtable.
600+
old_info.expect("unsized_info: missing old info for trait upcast")
601+
}
602+
(_, &ty::TyTrait(box ty::TraitTy { ref principal, .. })) => {
603+
// Note that we preserve binding levels here:
604+
let substs = principal.0.substs.with_self_ty(source).erase_regions();
605+
let substs = ccx.tcx().mk_substs(substs);
606+
let trait_ref = ty::Binder(ty::TraitRef { def_id: principal.def_id(),
607+
substs: substs });
608+
consts::ptrcast(meth::get_vtable(ccx, trait_ref, param_substs),
609+
Type::vtable_ptr(ccx))
610+
}
611+
_ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {:?} -> {:?}",
612+
source,
613+
target))
614+
}
615+
}
616+
617+
/// Coerce `src` to `dst_ty`. `src_ty` must be a thin pointer.
618+
pub fn unsize_thin_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
619+
src: ValueRef,
620+
src_ty: Ty<'tcx>,
621+
dst_ty: Ty<'tcx>)
622+
-> (ValueRef, ValueRef) {
623+
debug!("unsize_thin_ptr: {:?} => {:?}", src_ty, dst_ty);
624+
match (&src_ty.sty, &dst_ty.sty) {
625+
(&ty::TyBox(a), &ty::TyBox(b)) |
626+
(&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }),
627+
&ty::TyRef(_, ty::TypeAndMut { ty: b, .. })) |
628+
(&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }),
629+
&ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) |
630+
(&ty::TyRawPtr(ty::TypeAndMut { ty: a, .. }),
631+
&ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) => {
632+
assert!(common::type_is_sized(bcx.tcx(), a));
633+
let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), b).ptr_to();
634+
(PointerCast(bcx, src, ptr_ty),
635+
unsized_info(bcx.ccx(), a, b, None, bcx.fcx.param_substs))
636+
}
637+
_ => bcx.sess().bug(
638+
&format!("unsize_thin_ptr: called on bad types"))
639+
}
640+
}
641+
642+
/// Coerce `src`, which is a reference to a value of type `src_ty`,
643+
/// to a value of type `dst_ty` and store the result in `dst`
644+
pub fn coerce_unsized_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
645+
src: ValueRef,
646+
src_ty: Ty<'tcx>,
647+
dst: ValueRef,
648+
dst_ty: Ty<'tcx>) {
649+
match (&src_ty.sty, &dst_ty.sty) {
650+
(&ty::TyBox(..), &ty::TyBox(..)) |
651+
(&ty::TyRef(..), &ty::TyRef(..)) |
652+
(&ty::TyRef(..), &ty::TyRawPtr(..)) |
653+
(&ty::TyRawPtr(..), &ty::TyRawPtr(..)) => {
654+
let (base, info) = if common::type_is_fat_ptr(bcx.tcx(), src_ty) {
655+
// fat-ptr to fat-ptr unsize preserves the vtable
656+
load_fat_ptr(bcx, src, src_ty)
657+
} else {
658+
let base = load_ty(bcx, src, src_ty);
659+
unsize_thin_ptr(bcx, base, src_ty, dst_ty)
660+
};
661+
store_fat_ptr(bcx, base, info, dst, dst_ty);
662+
}
663+
664+
// This can be extended to enums and tuples in the future.
665+
// (&ty::TyEnum(def_id_a, _), &ty::TyEnum(def_id_b, _)) |
666+
(&ty::TyStruct(def_a, _), &ty::TyStruct(def_b, _)) => {
667+
assert_eq!(def_a, def_b);
668+
669+
let src_repr = adt::represent_type(bcx.ccx(), src_ty);
670+
let src_fields = match &*src_repr {
671+
&adt::Repr::Univariant(ref s, _) => &s.fields,
672+
_ => bcx.sess().bug("struct has non-univariant repr")
673+
};
674+
let dst_repr = adt::represent_type(bcx.ccx(), dst_ty);
675+
let dst_fields = match &*dst_repr {
676+
&adt::Repr::Univariant(ref s, _) => &s.fields,
677+
_ => bcx.sess().bug("struct has non-univariant repr")
678+
};
679+
680+
let iter = src_fields.iter().zip(dst_fields).enumerate();
681+
for (i, (src_fty, dst_fty)) in iter {
682+
if type_is_zero_size(bcx.ccx(), dst_fty) { continue; }
683+
684+
let src_f = adt::trans_field_ptr(bcx, &src_repr, src, 0, i);
685+
let dst_f = adt::trans_field_ptr(bcx, &dst_repr, dst, 0, i);
686+
if src_fty == dst_fty {
687+
memcpy_ty(bcx, dst_f, src_f, src_fty);
688+
} else {
689+
coerce_unsized_into(
690+
bcx,
691+
src_f, src_fty,
692+
dst_f, dst_fty
693+
);
694+
}
695+
}
696+
}
697+
_ => bcx.sess().bug(&format!("coerce_unsized_into: invalid coercion {:?} -> {:?}",
698+
src_ty,
699+
dst_ty))
700+
}
701+
}
702+
526703
pub fn cast_shift_expr_rhs(cx: Block,
527704
op: hir::BinOp_,
528705
lhs: ValueRef,
@@ -828,6 +1005,10 @@ pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t
8281005
return;
8291006
}
8301007

1008+
debug!("store_ty: {} : {:?} <- {}",
1009+
cx.val_to_string(dst), t,
1010+
cx.val_to_string(v));
1011+
8311012
if common::type_is_fat_ptr(cx.tcx(), t) {
8321013
Store(cx, ExtractValue(cx, v, abi::FAT_PTR_ADDR), expr::get_dataptr(cx, dst));
8331014
Store(cx, ExtractValue(cx, v, abi::FAT_PTR_EXTRA), expr::get_meta(cx, dst));
@@ -839,6 +1020,25 @@ pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t
8391020
}
8401021
}
8411022

1023+
pub fn store_fat_ptr<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
1024+
data: ValueRef,
1025+
extra: ValueRef,
1026+
dst: ValueRef,
1027+
_ty: Ty<'tcx>) {
1028+
// FIXME: emit metadata
1029+
Store(cx, data, expr::get_dataptr(cx, dst));
1030+
Store(cx, extra, expr::get_meta(cx, dst));
1031+
}
1032+
1033+
pub fn load_fat_ptr<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
1034+
src: ValueRef,
1035+
_ty: Ty<'tcx>) -> (ValueRef, ValueRef)
1036+
{
1037+
// FIXME: emit metadata
1038+
(Load(cx, expr::get_dataptr(cx, src)),
1039+
Load(cx, expr::get_meta(cx, src)))
1040+
}
1041+
8421042
pub fn from_arg_ty(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef {
8431043
if ty.is_bool() {
8441044
ZExt(bcx, val, Type::i8(bcx.ccx()))

src/librustc_trans/trans/common.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1223,4 +1223,4 @@ pub fn get_static_val<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
12231223
} else {
12241224
base::get_extern_const(ccx, did, ty)
12251225
}
1226-
}
1226+
}

src/librustc_trans/trans/consts.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
410410
.expect("consts: unsizing got non-pointer target type").ty;
411411
let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to();
412412
let base = ptrcast(base, ptr_ty);
413-
let info = expr::unsized_info(cx, pointee_ty, unsized_ty,
413+
let info = base::unsized_info(cx, pointee_ty, unsized_ty,
414414
old_info, param_substs);
415415

416416
if old_info.is_none() {

0 commit comments

Comments
 (0)