diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 012bd9691be5..8090fca66bb6 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -53,7 +53,6 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { // Find the actual method implementation being called and // build the appropriate UFCS call expression with the // callee-object as self parameter. - let method = method_callee(cx, self, ty::MethodCall::expr(self.id)); let mut argrefs = vec![fun.to_ref()]; argrefs.extend(args.iter().map(|a| a.to_ref())); @@ -64,12 +63,40 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { args: argrefs, } } else { - ExprKind::Call { - ty: &cx.tcx.node_id_to_type(fun.id), - fun: fun.to_ref(), - args: args.to_ref(), + let adt_data = if let hir::ExprPath(..) = fun.node { + // Tuple-like ADTs are represented as ExprCall. We convert them here. + expr_ty.ty_adt_def().and_then(|adt_def|{ + match cx.tcx.def_map.borrow()[&fun.id].full_def() { + def::DefVariant(_, variant_id, false) => { + Some((adt_def, adt_def.variant_index_with_id(variant_id))) + }, + def::DefStruct(_) => { + Some((adt_def, 0)) + }, + _ => None + } + }) + } else { None }; + if let Some((adt_def, index)) = adt_data { + let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(fun.id).substs); + let field_refs = args.iter().enumerate().map(|(idx, e)| FieldExprRef { + name: Field::new(idx), + expr: e.to_ref() + }).collect(); + ExprKind::Adt { + adt_def: adt_def, + substs: substs, + variant_index: index, + fields: field_refs, + base: None + } + } else { + ExprKind::Call { + ty: cx.tcx.node_id_to_type(fun.id), + fun: fun.to_ref(), + args: args.to_ref(), + } } - } } @@ -549,10 +576,11 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) 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. + // A tuple-struct constructor. Should only be reached if not called in the same + // expression. 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. + // 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, @@ -563,7 +591,8 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) ref sty => panic!("unexpected sty: {:?}", sty) }, def::DefVariant(enum_id, variant_id, false) => match cx.tcx.node_id_to_type(expr.id).sty { - // A variant constructor. + // A variant constructor. Should only be reached if not called in the same + // expression. ty::TyBareFn(..) => (variant_id, ItemKind::Function), // A unit variant, similar special case to the struct case above. ty::TyEnum(adt_def, substs) => { @@ -900,6 +929,7 @@ fn loop_label<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) -> Cod } } +/// Converts a list of named fields (i.e. for struct-like struct/enum ADTs) into FieldExprRef. fn field_refs<'tcx>(variant: VariantDef<'tcx>, fields: &'tcx [hir::Field]) -> Vec> diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs index 18a9aad0e915..ad5b0069a48d 100644 --- a/src/librustc_trans/trans/mir/block.rs +++ b/src/librustc_trans/trans/mir/block.rs @@ -48,11 +48,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } mir::Terminator::Switch { ref discr, ref adt_def, ref targets } => { - let adt_ty = bcx.tcx().lookup_item_type(adt_def.did).ty; - let represented_ty = adt::represent_type(bcx.ccx(), adt_ty); - let discr_lvalue = self.trans_lvalue(bcx, discr); - let discr = adt::trans_get_discr(bcx, &represented_ty, discr_lvalue.llval, None); + let ty = discr_lvalue.ty.to_ty(bcx.tcx()); + let repr = adt::represent_type(bcx.ccx(), ty); + let discr = adt::trans_get_discr(bcx, &repr, discr_lvalue.llval, None); // The else branch of the Switch can't be hit, so branch to an unreachable // instruction so LLVM knows that @@ -61,7 +60,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let switch = build::Switch(bcx, discr, unreachable_blk.llbb, targets.len()); assert_eq!(adt_def.variants.len(), targets.len()); for (adt_variant, target) in adt_def.variants.iter().zip(targets) { - let llval = adt::trans_case(bcx, &*represented_ty, adt_variant.disr_val); + let llval = adt::trans_case(bcx, &*repr, adt_variant.disr_val); let llbb = self.llblock(*target); build::AddCase(switch, llval, llbb) diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs index f0842554277c..7b9eac4317d2 100644 --- a/src/librustc_trans/trans/mir/rvalue.rs +++ b/src/librustc_trans/trans/mir/rvalue.rs @@ -98,13 +98,19 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { mir::Rvalue::Aggregate(ref kind, ref operands) => { match *kind { - // Unit struct or variant; both are translated very differently compared to any - // other aggregate - mir::AggregateKind::Adt(adt_def, index, _) - if adt_def.variants[index].kind() == ty::VariantKind::Unit => { + mir::AggregateKind::Adt(adt_def, index, _) => { let repr = adt::represent_type(bcx.ccx(), dest.ty.to_ty(bcx.tcx())); let disr = adt_def.variants[index].disr_val; adt::trans_set_discr(bcx, &*repr, dest.llval, disr); + for (i, operand) in operands.iter().enumerate() { + let op = self.trans_operand(bcx, operand); + // Do not generate stores and GEPis for zero-sized fields. + if !common::type_is_zero_size(bcx.ccx(), op.ty) { + let val = adt::MaybeSizedValue::sized(dest.llval); + let lldest_i = adt::trans_field_ptr(bcx, &*repr, val, disr, i); + self.store_operand(bcx, lldest_i, op); + } + } }, _ => { for (i, operand) in operands.iter().enumerate() { diff --git a/src/test/run-pass/mir_adt_construction.rs b/src/test/run-pass/mir_adt_construction.rs new file mode 100644 index 000000000000..4526c40af84c --- /dev/null +++ b/src/test/run-pass/mir_adt_construction.rs @@ -0,0 +1,77 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_attrs)] + +#[repr(C, u32)] +enum CEnum { + Hello = 30, + World = 60 +} + +#[rustc_mir] +fn test1(c: CEnum) -> i32 { + let c2 = CEnum::Hello; + match (c, c2) { + (CEnum::Hello, CEnum::Hello) => 42, + (CEnum::World, CEnum::Hello) => 0, + _ => 1 + } +} + +#[repr(packed)] +#[derive(PartialEq, Debug)] +struct Pakd { + a: u64, + b: u32, + c: u16, + d: u8, + e: () +} + +impl Drop for Pakd { + fn drop(&mut self) {} +} + +#[rustc_mir] +fn test2() -> Pakd { + Pakd { a: 42, b: 42, c: 42, d: 42, e: () } +} + +#[derive(PartialEq, Debug)] +struct TupleLike(u64, u32); + +#[rustc_mir] +fn test3() -> TupleLike { + TupleLike(42, 42) +} + +#[rustc_mir] +fn test4(x: fn(u64, u32) -> TupleLike) -> (TupleLike, TupleLike) { + let y = TupleLike; + (x(42, 84), y(42, 84)) +} + +#[rustc_mir] +fn test5(x: fn(u32) -> Option) -> (Option, Option) { + let y = Some; + (x(42), y(42)) +} + +fn main() { + assert_eq!(test1(CEnum::Hello), 42); + assert_eq!(test1(CEnum::World), 0); + assert_eq!(test2(), Pakd { a: 42, b: 42, c: 42, d: 42, e: () }); + assert_eq!(test3(), TupleLike(42, 42)); + let t4 = test4(TupleLike); + assert_eq!(t4.0, t4.1); + let t5 = test5(Some); + assert_eq!(t5.0, t5.1); +} diff --git a/src/test/run-pass/mir_build_match_comparisons.rs b/src/test/run-pass/mir_build_match_comparisons.rs index 19266191d445..ad24e39d4f93 100644 --- a/src/test/run-pass/mir_build_match_comparisons.rs +++ b/src/test/run-pass/mir_build_match_comparisons.rs @@ -11,7 +11,7 @@ #![feature(rustc_attrs)] #[rustc_mir] -pub fn test1(x: i8) -> i32 { +fn test1(x: i8) -> i32 { match x { 1...10 => 0, _ => 1, @@ -22,7 +22,7 @@ const U: Option = Some(10); const S: &'static str = "hello"; #[rustc_mir] -pub fn test2(x: i8) -> i32 { +fn test2(x: i8) -> i32 { match Some(x) { U => 0, _ => 1, @@ -30,13 +30,28 @@ pub fn test2(x: i8) -> i32 { } #[rustc_mir] -pub fn test3(x: &'static str) -> i32 { +fn test3(x: &'static str) -> i32 { match x { S => 0, _ => 1, } } +enum Opt { + Some { v: T }, + None +} + +#[rustc_mir] +fn test4(x: u64) -> i32 { + let opt = Opt::Some{ v: x }; + match opt { + Opt::Some { v: 10 } => 0, + _ => 1, + } +} + + fn main() { assert_eq!(test1(0), 1); assert_eq!(test1(1), 0); @@ -52,4 +67,7 @@ fn main() { assert_eq!(test3("hello"), 0); assert_eq!(test3(""), 1); assert_eq!(test3("world"), 1); + assert_eq!(test4(10), 0); + assert_eq!(test4(0), 1); + assert_eq!(test4(20), 1); }