diff --git a/build.sh b/build.sh index ce8359698f0d..a3d31c6c7706 100755 --- a/build.sh +++ b/build.sh @@ -41,4 +41,4 @@ gcc target/out/mini_core.o target/out/mini_core_hello_world.o -o target/out/mini ./target/out/mini_core_hello_world $RUSTC target/libcore/src/libcore/lib.rs --color=always --crate-type lib -Cincremental=target/incremental 2>&1 | (head -n 20; echo "===="; tail -n 1000) -cat target/out/log.txt | sort | uniq -c | grep -v "rval unsize move" | grep -v "rval len" +cat target/out/log.txt | sort | uniq -c diff --git a/examples/example.rs b/examples/example.rs index 6d84fb148c0f..5df8e69efd3e 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -141,9 +141,9 @@ unsafe fn call_uninit() -> u8 { } // TODO: enable when fat pointers are supported -/*unsafe fn deref_str_ptr(s: *const str) -> &'static str { +unsafe fn deref_str_ptr(s: *const str) -> &'static str { &*s -}*/ +} fn use_array(arr: [u8; 3]) -> u8 { arr[1] @@ -153,6 +153,10 @@ fn repeat_array() -> [u8; 3] { [0; 3] } +fn array_as_slice(arr: &[u8; 3]) -> &[u8] { + arr +} + /*unsafe fn use_ctlz_nonzero(a: u16) -> u16 { intrinsics::ctlz_nonzero(a) }*/ @@ -176,3 +180,7 @@ fn make_array() -> [u8; 3] { fn some_promoted_tuple() -> &'static (&'static str, &'static str) { &("abc", "some") } + +fn index_slice(s: &[u8]) -> u8 { + s[2] +} diff --git a/examples/mini_core.rs b/examples/mini_core.rs index 7813f8a4c34f..2eb2e9502565 100644 --- a/examples/mini_core.rs +++ b/examples/mini_core.rs @@ -207,3 +207,11 @@ impl Index for [T; 3] { &self[index] } } + +impl Index for [T] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} diff --git a/examples/mini_core_hello_world.rs b/examples/mini_core_hello_world.rs index 19cc727fb55e..c775beef2f09 100644 --- a/examples/mini_core_hello_world.rs +++ b/examples/mini_core_hello_world.rs @@ -43,7 +43,8 @@ static NUM_REF: &'static u8 = unsafe { &NUM }; fn main() { unsafe { - let (ptr, _): (*const u8, usize) = intrinsics::transmute("Hello!\0"); + let slice: &[u8] = b"Hello!\0" as &[u8; 7]; + let ptr: *const u8 = slice as *const [u8] as *const u8; puts(ptr); } diff --git a/src/abi.rs b/src/abi.rs index b5967e734190..112d87743fea 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -28,6 +28,11 @@ fn get_pass_mode<'a, 'tcx: 'a>( ty: Ty<'tcx>, is_return: bool, ) -> PassMode { + assert!( + !tcx.layout_of(ParamEnv::reveal_all().and(ty)) + .unwrap() + .is_unsized() + ); if ty.sty == tcx.mk_nil().sty { if is_return { //if false { @@ -312,7 +317,7 @@ pub fn codegen_fn_prelude<'a, 'tcx: 'a>( //unimplemented!("pass mode nopass"); fx.local_map.insert( RETURN_PLACE, - CPlace::Addr(null, fx.layout_of(fx.return_type())), + CPlace::Addr(null, None, fx.layout_of(fx.return_type())), ); } PassMode::ByVal(ret_ty) => { @@ -321,8 +326,10 @@ pub fn codegen_fn_prelude<'a, 'tcx: 'a>( .insert(RETURN_PLACE, CPlace::Var(RETURN_PLACE, ret_layout)); } PassMode::ByRef => { - fx.local_map - .insert(RETURN_PLACE, CPlace::Addr(ret_param.unwrap(), ret_layout)); + fx.local_map.insert( + RETURN_PLACE, + CPlace::Addr(ret_param.unwrap(), None, ret_layout), + ); } } diff --git a/src/base.rs b/src/base.rs index 8627cf66a83e..c0ea7644f903 100644 --- a/src/base.rs +++ b/src/base.rs @@ -309,8 +309,7 @@ fn trans_stmt<'a, 'tcx: 'a>( } Rvalue::Ref(_, _, place) => { let place = trans_place(fx, place); - let addr = place.expect_addr(); - lval.write_cvalue(fx, CValue::ByVal(addr, dest_layout)); + place.write_place_ref(fx, lval); } Rvalue::BinaryOp(bin_op, lhs, rhs) => { let ty = fx.monomorphize(&lhs.ty(&fx.mir.local_decls, fx.tcx)); @@ -459,7 +458,8 @@ fn trans_stmt<'a, 'tcx: 'a>( unimplemented!("rval closure_fn_ptr {:?} {:?}", operand, ty) } Rvalue::Cast(CastKind::Unsize, operand, ty) => { - unimpl!("rval unsize {:?} {:?}", operand, ty); + let operand = trans_operand(fx, operand); + operand.unsize_value(fx, lval); } Rvalue::Discriminant(place) => { let place = trans_place(fx, place).to_cvalue(fx); @@ -474,7 +474,15 @@ fn trans_stmt<'a, 'tcx: 'a>( to.write_cvalue(fx, operand); } } - Rvalue::Len(lval) => unimpl!("rval len {:?}", lval), + Rvalue::Len(place) => { + let place = trans_place(fx, place); + let size = match place { + CPlace::Addr(_, size, _) => size.unwrap(), + CPlace::Var(_, _) => unreachable!(), + }; + let usize_layout = fx.layout_of(fx.tcx.types.usize); + lval.write_cvalue(fx, CValue::ByVal(size, usize_layout)); + } Rvalue::NullaryOp(NullOp::Box, ty) => unimplemented!("rval box {:?}", ty), Rvalue::NullaryOp(NullOp::SizeOf, ty) => { assert!( @@ -893,13 +901,7 @@ pub fn trans_place<'a, 'tcx: 'a>( Place::Projection(projection) => { let base = trans_place(fx, &projection.base); match projection.elem { - ProjectionElem::Deref => { - let layout = fx.layout_of(place.ty(&*fx.mir, fx.tcx).to_ty(fx.tcx)); - if layout.is_unsized() { - unimpl!("Unsized places are not yet implemented"); - } - CPlace::Addr(base.to_cvalue(fx).load_value(fx), layout) - } + ProjectionElem::Deref => base.place_deref(fx), ProjectionElem::Field(field, _ty) => base.place_field(fx, field), ProjectionElem::Index(local) => { let index = fx.get_local_place(local).to_cvalue(fx).load_value(fx); diff --git a/src/common.rs b/src/common.rs index 8f0236fb7f00..fd98d83221a9 100644 --- a/src/common.rs +++ b/src/common.rs @@ -19,6 +19,24 @@ pub fn pointer_ty(tcx: TyCtxt) -> types::Type { } } +fn scalar_to_cton_type(tcx: TyCtxt, scalar: &Scalar) -> Type { + match scalar.value.size(tcx).bits() { + 8 => types::I8, + 16 => types::I16, + 32 => types::I32, + 64 => types::I64, + size => bug!("Unsupported scalar size {}", size), + } +} + +fn ptr_referee<'tcx>(ty: Ty<'tcx>) -> Ty<'tcx> { + match ty.sty { + ty::Ref(_, ty, _) => ty, + ty::RawPtr(TypeAndMut { ty, mutbl: _ }) => ty, + _ => bug!("{:?}", ty), + } +} + pub fn cton_type_from_ty<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>, @@ -198,6 +216,43 @@ impl<'tcx> CValue<'tcx> { CValue::ByRef(field_ptr, field_layout) } + pub fn unsize_value<'a>(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>, dest: CPlace<'tcx>) { + if self.layout().ty == dest.layout().ty { + dest.write_cvalue(fx, self); // FIXME this shouldn't happen (rust-lang/rust#53602) + return; + } + match &self.layout().ty.sty { + ty::Ref(_, ty, _) | ty::RawPtr(TypeAndMut { ty, mutbl: _ }) => { + let (ptr, extra) = match ptr_referee(dest.layout().ty).sty { + ty::Slice(slice_elem_ty) => match ty.sty { + ty::Array(array_elem_ty, size) => { + assert_eq!(slice_elem_ty, array_elem_ty); + let ptr = self.load_value(fx); + let extra = fx + .bcx + .ins() + .iconst(fx.module.pointer_type(), size.unwrap_usize(fx.tcx) as i64); + (ptr, extra) + } + _ => bug!("unsize non array {:?} to slice", ty), + }, + ty::Dynamic(_, _) => match ty.sty { + ty::Dynamic(_, _) => self.load_value_pair(fx), + _ => unimpl!("unsize of type ... to {:?}", dest.layout().ty), + }, + _ => bug!( + "unsize of type {:?} to {:?}", + self.layout().ty, + dest.layout().ty + ), + }; + println!("ty {:?}", self.layout().ty); + dest.write_cvalue(fx, CValue::ByValPair(ptr, extra, dest.layout())); + } + ty => unimpl!("unsize of non ptr {:?}", ty), + } + } + pub fn const_val<'a>( fx: &mut FunctionCx<'a, 'tcx, impl Backend>, ty: Ty<'tcx>, @@ -224,18 +279,19 @@ impl<'tcx> CValue<'tcx> { #[derive(Debug, Copy, Clone)] pub enum CPlace<'tcx> { Var(Local, TyLayout<'tcx>), - Addr(Value, TyLayout<'tcx>), + Addr(Value, Option, TyLayout<'tcx>), } impl<'a, 'tcx: 'a> CPlace<'tcx> { pub fn layout(&self) -> TyLayout<'tcx> { match *self { - CPlace::Var(_, layout) | CPlace::Addr(_, layout) => layout, + CPlace::Var(_, layout) | CPlace::Addr(_, _, layout) => layout, } } pub fn temp(fx: &mut FunctionCx<'a, 'tcx, impl Backend>, ty: Ty<'tcx>) -> CPlace<'tcx> { let layout = fx.layout_of(ty); + assert!(!layout.is_unsized()); let stack_slot = fx.bcx.create_stack_slot(StackSlotData { kind: StackSlotKind::ExplicitSlot, size: layout.size.bytes() as u32, @@ -245,6 +301,7 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> { fx.bcx .ins() .stack_addr(fx.module.pointer_type(), stack_slot, 0), + None, layout, ) } @@ -255,10 +312,12 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> { ty: Ty<'tcx>, ) -> CPlace<'tcx> { let layout = fx.layout_of(ty); + assert!(!layout.is_unsized()); CPlace::Addr( fx.bcx .ins() .stack_addr(fx.module.pointer_type(), stack_slot, 0), + None, layout, ) } @@ -266,13 +325,17 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> { pub fn to_cvalue(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>) -> CValue<'tcx> { match self { CPlace::Var(var, layout) => CValue::ByVal(fx.bcx.use_var(mir_var(var)), layout), - CPlace::Addr(addr, layout) => CValue::ByRef(addr, layout), + CPlace::Addr(addr, extra, layout) => { + assert!(extra.is_none(), "unsized values are not yet supported"); + CValue::ByRef(addr, layout) + } } } pub fn expect_addr(self) -> Value { match self { - CPlace::Addr(addr, _layout) => addr, + CPlace::Addr(addr, None, _layout) => addr, + CPlace::Addr(_, _, _) => bug!("Expected sized CPlace::Addr, found {:?}", self), CPlace::Var(_, _) => bug!("Expected CPlace::Addr, found CPlace::Var"), } } @@ -308,7 +371,7 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> { let data = from.load_value(fx); fx.bcx.def_var(mir_var(var), data) } - CPlace::Addr(addr, layout) => { + CPlace::Addr(addr, None, layout) => { let size = layout.size.bytes() as i32; match from { @@ -346,6 +409,7 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> { } } } + CPlace::Addr(_, _, _) => bug!("Can't write value to unsized place {:?}", self), } } @@ -354,11 +418,14 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> { fx: &mut FunctionCx<'a, 'tcx, impl Backend>, field: mir::Field, ) -> CPlace<'tcx> { - let base = self.expect_addr(); let layout = self.layout(); + if layout.is_unsized() { + unimpl!("unsized place_field"); + } + let base = self.expect_addr(); let (field_ptr, field_layout) = codegen_field(fx, base, layout, field); - CPlace::Addr(field_ptr, field_layout) + CPlace::Addr(field_ptr, None, field_layout) } pub fn place_index( @@ -366,26 +433,93 @@ impl<'a, 'tcx: 'a> CPlace<'tcx> { fx: &mut FunctionCx<'a, 'tcx, impl Backend>, index: Value, ) -> CPlace<'tcx> { - let addr = self.expect_addr(); - let layout = self.layout(); - match layout.ty.sty { - ty::Array(elem_ty, _) => { - let elem_layout = fx.layout_of(elem_ty); - let offset = fx - .bcx - .ins() - .imul_imm(index, elem_layout.size.bytes() as i64); - CPlace::Addr(fx.bcx.ins().iadd(addr, offset), elem_layout) + let (elem_layout, addr) = match self.layout().ty.sty { + ty::Array(elem_ty, _) => (fx.layout_of(elem_ty), self.expect_addr()), + ty::Slice(elem_ty) => ( + fx.layout_of(elem_ty), + match self { + CPlace::Addr(addr, _, _) => addr, + CPlace::Var(_, _) => bug!("Expected CPlace::Addr found CPlace::Var"), + }, + ), + _ => bug!("place_index({:?})", self.layout().ty), + }; + + let offset = fx + .bcx + .ins() + .imul_imm(index, elem_layout.size.bytes() as i64); + + CPlace::Addr(fx.bcx.ins().iadd(addr, offset), None, elem_layout) + } + + pub fn place_deref(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>) -> CPlace<'tcx> { + let inner_layout = fx.layout_of(ptr_referee(self.layout().ty)); + if !inner_layout.is_unsized() { + CPlace::Addr(self.to_cvalue(fx).load_value(fx), None, inner_layout) + } else { + match self.layout().abi { + Abi::ScalarPair(ref a, ref b) => { + let addr = self.expect_addr(); + let ptr = + fx.bcx + .ins() + .load(scalar_to_cton_type(fx.tcx, a), MemFlags::new(), addr, 0); + let extra = fx.bcx.ins().load( + scalar_to_cton_type(fx.tcx, b), + MemFlags::new(), + addr, + a.value.size(fx.tcx).bytes() as u32 as i32, + ); + println!( + "unsized deref: ptr: {:?} extra: {:?} self: {:?}", + ptr, extra, self + ); + CPlace::Addr(ptr, Some(extra), inner_layout) + } + _ => bug!( + "Fat ptr doesn't have abi ScalarPair, but it has {:?}", + self.layout().abi + ), + } + } + } + + pub fn write_place_ref(self, fx: &mut FunctionCx<'a, 'tcx, impl Backend>, dest: CPlace<'tcx>) { + if !self.layout().is_unsized() { + let ptr = CValue::ByVal(self.expect_addr(), dest.layout()); + dest.write_cvalue(fx, ptr); + } else { + match self { + CPlace::Var(_, _) => bug!("expected CPlace::Addr found CPlace::Var"), + CPlace::Addr(value, extra, _) => match dest.layout().abi { + Abi::ScalarPair(ref a, _) => { + fx.bcx + .ins() + .store(MemFlags::new(), value, dest.expect_addr(), 0); + fx.bcx.ins().store( + MemFlags::new(), + extra.expect("unsized type without metadata"), + dest.expect_addr(), + a.value.size(fx.tcx).bytes() as u32 as i32, + ); + } + _ => bug!( + "Non ScalarPair abi {:?} in write_place_ref dest", + dest.layout().abi + ), + }, } - ty::Slice(_elem_ty) => unimplemented!("place_index(TySlice)"), - _ => bug!("place_index({:?})", layout.ty), } } pub fn unchecked_cast_to(self, layout: TyLayout<'tcx>) -> Self { match self { CPlace::Var(var, _) => CPlace::Var(var, layout), - CPlace::Addr(addr, _) => CPlace::Addr(addr, layout), + CPlace::Addr(addr, extra, _) => { + assert!(!layout.is_unsized()); + CPlace::Addr(addr, extra, layout) + } } } diff --git a/src/constant.rs b/src/constant.rs index b5ce5f198f41..f912f435fcbf 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -179,7 +179,8 @@ fn cplace_for_dataid<'a, 'tcx: 'a>( .ins() .global_value(fx.module.pointer_type(), local_data_id); let layout = fx.layout_of(fx.monomorphize(&ty)); - CPlace::Addr(global_ptr, layout) + assert!(!layout.is_unsized(), "unsized statics aren't supported"); + CPlace::Addr(global_ptr, None, layout) } fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>( diff --git a/src/lib.rs b/src/lib.rs index 5397f5b48716..fa74f928ddb4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,7 +63,7 @@ mod prelude { pub use rustc::mir::interpret::AllocId; pub use rustc::mir::*; pub use rustc::session::{config::CrateType, Session}; - pub use rustc::ty::layout::{self, LayoutOf, Size, TyLayout}; + pub use rustc::ty::layout::{self, Abi, LayoutOf, Scalar, Size, TyLayout}; pub use rustc::ty::{ self, subst::Substs, FnSig, Instance, InstanceDef, ParamEnv, PolyFnSig, Ty, TyCtxt, TypeAndMut, TypeFoldable,