From 75e8f4afca59f3ae2d3ef0dd99c45f91c006d189 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 25 Dec 2015 01:02:34 +0200 Subject: [PATCH] Properly translate unit structs in MIR --- src/librustc/mir/repr.rs | 4 +- src/librustc_mir/hair/cx/expr.rs | 58 +++++++++++------------ src/librustc_trans/trans/mir/did.rs | 4 +- src/librustc_trans/trans/mir/rvalue.rs | 49 ++++++++++++------- src/librustc_trans/trans/mir/statement.rs | 4 +- src/test/run-pass/mir_refs_correct.rs | 8 ++++ 6 files changed, 73 insertions(+), 54 deletions(-) diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index e83fe60f419..be6bb8689ee 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -701,9 +701,9 @@ pub struct Constant<'tcx> { #[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub enum ItemKind { Constant, + /// This is any sort of callable (usually those that have a type of `fn(…) -> …`). This + /// includes functions, constructors, but not methods which have their own ItemKind. Function, - Struct, - Variant, Method, } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 5cb12627d6b..46e6243c8bf 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -519,51 +519,51 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(expr.id).substs); // Otherwise there may be def_map borrow conflicts let def = cx.tcx.def_map.borrow()[&expr.id].full_def(); - match def { - def::DefVariant(_, def_id, false) | - def::DefStruct(def_id) | - def::DefFn(def_id, _) | - def::DefMethod(def_id) => { - let kind = match def { - def::DefVariant(..) => ItemKind::Variant, - def::DefStruct(..) => ItemKind::Struct, - def::DefFn(..) => ItemKind::Function, - def::DefMethod(..) => ItemKind::Method, - _ => panic!() - }; - ExprKind::Literal { - literal: Literal::Item { def_id: def_id, kind: kind, substs: substs } + let (def_id, kind) = match def { + // A variant constructor. + def::DefVariant(_, def_id, false) => (def_id, ItemKind::Function), + // A regular function. + def::DefFn(def_id, _) => (def_id, ItemKind::Function), + def::DefMethod(def_id) => (def_id, ItemKind::Method), + def::DefStruct(def_id) => { + match cx.tcx.node_id_to_type(expr.id).sty { + // A tuple-struct constructor. + ty::TyBareFn(..) => (def_id, ItemKind::Function), + // This is a special case: a unit struct which is used as a value. We return a + // completely different ExprKind here to account for this special case. + ty::TyStruct(adt_def, substs) => return ExprKind::Adt { + adt_def: adt_def, + variant_index: 0, + substs: substs, + fields: vec![], + base: None + }, + ref sty => panic!("unexpected sty: {:?}", sty) } }, def::DefConst(def_id) | def::DefAssociatedConst(def_id) => { if let Some(v) = cx.try_const_eval_literal(expr) { - ExprKind::Literal { literal: v } + return ExprKind::Literal { literal: v }; } else { - ExprKind::Literal { - literal: Literal::Item { - def_id: def_id, - kind: ItemKind::Constant, - substs: substs - } - } + (def_id, ItemKind::Constant) } } - - def::DefStatic(node_id, _) => - ExprKind::StaticRef { - id: node_id, - }, + def::DefStatic(node_id, _) => return ExprKind::StaticRef { + id: node_id, + }, def @ def::DefLocal(..) | - def @ def::DefUpvar(..) => - convert_var(cx, expr, def), + def @ def::DefUpvar(..) => return convert_var(cx, expr, def), def => cx.tcx.sess.span_bug( expr.span, &format!("def `{:?}` not yet implemented", def)), + }; + ExprKind::Literal { + literal: Literal::Item { def_id: def_id, kind: kind, substs: substs } } } diff --git a/src/librustc_trans/trans/mir/did.rs b/src/librustc_trans/trans/mir/did.rs index 368708d470b..d4a7a7c8b48 100644 --- a/src/librustc_trans/trans/mir/did.rs +++ b/src/librustc_trans/trans/mir/did.rs @@ -39,9 +39,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { did: DefId) -> OperandRef<'tcx> { match kind { - ItemKind::Function | - ItemKind::Struct | - ItemKind::Variant => self.trans_fn_ref(bcx, ty, substs, did), + ItemKind::Function => self.trans_fn_ref(bcx, ty, substs, did), ItemKind::Method => match bcx.tcx().impl_or_trait_item(did).container() { ty::ImplContainer(_) => self.trans_fn_ref(bcx, ty, substs, did), ty::TraitContainer(tdid) => self.trans_static_method(bcx, ty, did, tdid, substs) diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs index 529e65dace0..55a41201b2b 100644 --- a/src/librustc_trans/trans/mir/rvalue.rs +++ b/src/librustc_trans/trans/mir/rvalue.rs @@ -19,6 +19,7 @@ use trans::common::{self, Block, Result}; use trans::debuginfo::DebugLoc; use trans::declare; use trans::expr; +use trans::adt; use trans::machine; use trans::type_::Type; use trans::type_of; @@ -26,21 +27,22 @@ use trans::tvec; use super::MirContext; use super::operand::{OperandRef, OperandValue}; +use super::lvalue::LvalueRef; impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { pub fn trans_rvalue(&mut self, bcx: Block<'bcx, 'tcx>, - lldest: ValueRef, + dest: LvalueRef<'tcx>, rvalue: &mir::Rvalue<'tcx>) -> Block<'bcx, 'tcx> { - debug!("trans_rvalue(lldest={}, rvalue={:?})", - bcx.val_to_string(lldest), + debug!("trans_rvalue(dest.llval={}, rvalue={:?})", + bcx.val_to_string(dest.llval), rvalue); match *rvalue { mir::Rvalue::Use(ref operand) => { - self.trans_operand_into(bcx, lldest, operand); + self.trans_operand_into(bcx, dest.llval, operand); bcx } @@ -49,7 +51,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // into-coerce of a thin pointer to a fat pointer - just // use the operand path. let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue); - self.store_operand(bcx, lldest, temp); + self.store_operand(bcx, dest.llval, temp); return bcx; } @@ -72,12 +74,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { base::store_ty(bcx, llval, lltemp, operand.ty); base::coerce_unsized_into(bcx, lltemp, operand.ty, - lldest, cast_ty); + dest.llval, cast_ty); } OperandValue::Ref(llref) => { base::coerce_unsized_into(bcx, llref, operand.ty, - lldest, cast_ty); + dest.llval, cast_ty); } } bcx @@ -86,20 +88,31 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { mir::Rvalue::Repeat(ref elem, ref count) => { let elem = self.trans_operand(bcx, elem); let size = self.trans_constant(bcx, count).immediate(); - let base = expr::get_dataptr(bcx, lldest); + let base = expr::get_dataptr(bcx, dest.llval); tvec::iter_vec_raw(bcx, base, elem.ty, size, |bcx, llslot, _| { self.store_operand(bcx, llslot, elem); bcx }) } - mir::Rvalue::Aggregate(_, ref operands) => { - for (i, operand) in operands.iter().enumerate() { - // Note: perhaps this should be StructGep, but - // note that in some cases the values here will - // not be structs but arrays. - let lldest_i = build::GEPi(bcx, lldest, &[0, i]); - self.trans_operand_into(bcx, lldest_i, operand); + mir::Rvalue::Aggregate(ref kind, ref operands) => { + match *kind { + // Unit struct, which is translated very differently compared to any other + // aggregate + mir::AggregateKind::Adt(adt_def, 0, _) + if adt_def.struct_variant().kind() == ty::VariantKind::Unit => { + let repr = adt::represent_type(bcx.ccx(), dest.ty.to_ty(bcx.tcx())); + adt::trans_set_discr(bcx, &*repr, dest.llval, 0); + }, + _ => { + for (i, operand) in operands.iter().enumerate() { + // Note: perhaps this should be StructGep, but + // note that in some cases the values here will + // not be structs but arrays. + let lldest_i = build::GEPi(bcx, dest.llval, &[0, i]); + self.trans_operand_into(bcx, lldest_i, operand); + } + } } bcx } @@ -113,9 +126,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let llbase1 = build::GEPi(bcx, llbase, &[from_start]); let adj = common::C_uint(ccx, from_start + from_end); let lllen1 = build::Sub(bcx, lllen, adj, DebugLoc::None); - let lladdrdest = expr::get_dataptr(bcx, lldest); + let lladdrdest = expr::get_dataptr(bcx, dest.llval); build::Store(bcx, llbase1, lladdrdest); - let llmetadest = expr::get_meta(bcx, lldest); + let llmetadest = expr::get_meta(bcx, dest.llval); build::Store(bcx, lllen1, llmetadest); bcx } @@ -127,7 +140,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { _ => { assert!(rvalue_creates_operand(rvalue)); let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue); - self.store_operand(bcx, lldest, temp); + self.store_operand(bcx, dest.llval, temp); bcx } } diff --git a/src/librustc_trans/trans/mir/statement.rs b/src/librustc_trans/trans/mir/statement.rs index 9894626e284..dae0d3b55c0 100644 --- a/src/librustc_trans/trans/mir/statement.rs +++ b/src/librustc_trans/trans/mir/statement.rs @@ -31,7 +31,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let index = index as usize; match self.temps[index as usize] { TempRef::Lvalue(tr_dest) => { - self.trans_rvalue(bcx, tr_dest.llval, rvalue) + self.trans_rvalue(bcx, tr_dest, rvalue) } TempRef::Operand(None) => { let (bcx, operand) = self.trans_rvalue_operand(bcx, rvalue); @@ -47,7 +47,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } _ => { let tr_dest = self.trans_lvalue(bcx, lvalue); - self.trans_rvalue(bcx, tr_dest.llval, rvalue) + self.trans_rvalue(bcx, tr_dest, rvalue) } } } diff --git a/src/test/run-pass/mir_refs_correct.rs b/src/test/run-pass/mir_refs_correct.rs index 2da1a758709..9b349c0e4e2 100644 --- a/src/test/run-pass/mir_refs_correct.rs +++ b/src/test/run-pass/mir_refs_correct.rs @@ -14,6 +14,8 @@ extern crate mir_external_refs as ext; struct S(u8); +#[derive(Debug, PartialEq, Eq)] +struct Unit; impl S { fn hey() -> u8 { 42 } @@ -175,6 +177,11 @@ fn t20() -> fn(u64, u32)->(u64, u32) { >::staticmeth } +#[rustc_mir] +fn t21() -> Unit { + Unit +} + fn main(){ unsafe { assert_eq!(t1()(), regular()); @@ -214,5 +221,6 @@ fn main(){ assert_eq!(t18()(50u64, 5u64), F::f(50u64, 5u64)); assert_eq!(t19()(322u64, 2u32), F::f(322u64, 2u32)); assert_eq!(t20()(123u64, 38u32), >::staticmeth(123, 38)); + assert_eq!(t21(), Unit); } }