about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-08-15 15:46:17 +0000
committerbors <bors@rust-lang.org>2014-08-15 15:46:17 +0000
commit02f9fd87ec56b1e84d45c96abe388f555e28faed (patch)
treea7d0f605f76c3247f0faecc4dad35d92f34feac0
parentcafa47506db7f0ac8407d5771ec81f560c5a481f (diff)
parent28882c44ef0cfc031a931c0ca0509707a9b4729e (diff)
downloadrust-02f9fd87ec56b1e84d45c96abe388f555e28faed.tar.gz
rust-02f9fd87ec56b1e84d45c96abe388f555e28faed.zip
auto merge of #16511 : luqmana/rust/sbnt, r=pcwalton
Fixes #15397.
Fixes #7261.
Fixes #6573.
-rw-r--r--src/librustc/middle/trans/base.rs4
-rw-r--r--src/librustc/middle/trans/expr.rs104
2 files changed, 56 insertions, 52 deletions
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 9aa4355632c..896d37669e6 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -1947,12 +1947,10 @@ pub fn trans_named_tuple_constructor<'a>(mut bcx: &'a Block<'a>,
     };
 
     if !type_is_zero_size(ccx, result_ty) {
-        let repr = adt::represent_type(ccx, result_ty);
-
         match args {
             callee::ArgExprs(exprs) => {
                 let fields = exprs.iter().map(|x| *x).enumerate().collect::<Vec<_>>();
-                bcx = expr::trans_adt(bcx, &*repr, disr, fields.as_slice(),
+                bcx = expr::trans_adt(bcx, result_ty, disr, fields.as_slice(),
                                       None, expr::SaveIn(llresult));
             }
             _ => ccx.sess().bug("expected expr as arguments for variant/struct tuple constructor")
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 576bdb8b8c0..748274b1201 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -746,18 +746,17 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
             controlflow::trans_block(bcx, &**blk, dest)
         }
         ast::ExprStruct(_, ref fields, base) => {
-            trans_rec_or_struct(bcx,
-                                fields.as_slice(),
-                                base,
-                                expr.span,
-                                expr.id,
-                                dest)
+            trans_struct(bcx,
+                         fields.as_slice(),
+                         base,
+                         expr.span,
+                         expr.id,
+                         dest)
         }
         ast::ExprTup(ref args) => {
-            let repr = adt::represent_type(bcx.ccx(), expr_ty(bcx, expr));
             let numbered_fields: Vec<(uint, Gc<ast::Expr>)> =
                 args.iter().enumerate().map(|(i, arg)| (i, *arg)).collect();
-            trans_adt(bcx, &*repr, 0, numbered_fields.as_slice(), None, dest)
+            trans_adt(bcx, expr_ty(bcx, expr), 0, numbered_fields.as_slice(), None, dest)
         }
         ast::ExprLit(lit) => {
             match lit.node {
@@ -1042,16 +1041,13 @@ pub fn with_field_tys<R>(tcx: &ty::ctxt,
     }
 }
 
-fn trans_rec_or_struct<'a>(
-                       bcx: &'a Block<'a>,
-                       fields: &[ast::Field],
-                       base: Option<Gc<ast::Expr>>,
-                       expr_span: codemap::Span,
-                       id: ast::NodeId,
-                       dest: Dest)
-                       -> &'a Block<'a> {
+fn trans_struct<'a>(bcx: &'a Block<'a>,
+                    fields: &[ast::Field],
+                    base: Option<Gc<ast::Expr>>,
+                    expr_span: codemap::Span,
+                    id: ast::NodeId,
+                    dest: Dest) -> &'a Block<'a> {
     let _icx = push_ctxt("trans_rec");
-    let bcx = bcx;
 
     let ty = node_id_type(bcx, id);
     let tcx = bcx.tcx();
@@ -1092,8 +1088,7 @@ fn trans_rec_or_struct<'a>(
             }
         };
 
-        let repr = adt::represent_type(bcx.ccx(), ty);
-        trans_adt(bcx, &*repr, discr, numbered_fields.as_slice(), optbase, dest)
+        trans_adt(bcx, ty, discr, numbered_fields.as_slice(), optbase, dest)
     })
 }
 
@@ -1121,35 +1116,51 @@ pub struct StructBaseInfo {
  * - `optbase` contains information on the base struct (if any) from
  * which remaining fields are copied; see comments on `StructBaseInfo`.
  */
-pub fn trans_adt<'a>(bcx: &'a Block<'a>,
-                     repr: &adt::Repr,
+pub fn trans_adt<'a>(mut bcx: &'a Block<'a>,
+                     ty: ty::t,
                      discr: ty::Disr,
                      fields: &[(uint, Gc<ast::Expr>)],
                      optbase: Option<StructBaseInfo>,
                      dest: Dest) -> &'a Block<'a> {
     let _icx = push_ctxt("trans_adt");
     let fcx = bcx.fcx;
-    let mut bcx = bcx;
+    let repr = adt::represent_type(bcx.ccx(), ty);
+
+    // If we don't care about the result, just make a
+    // temporary stack slot
     let addr = match dest {
-        Ignore => {
-            for &(_i, ref e) in fields.iter() {
-                bcx = trans_into(bcx, &**e, Ignore);
-            }
-            for sbi in optbase.iter() {
-                // FIXME #7261: this moves entire base, not just certain fields
-                bcx = trans_into(bcx, &*sbi.expr, Ignore);
-            }
-            return bcx;
-        }
-        SaveIn(pos) => pos
+        SaveIn(pos) => pos,
+        Ignore => alloc_ty(bcx, ty, "temp"),
     };
 
     // This scope holds intermediates that must be cleaned should
     // failure occur before the ADT as a whole is ready.
     let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
 
+    // First we trans the base, if we have one, to the dest
+    for base in optbase.iter() {
+        assert_eq!(discr, 0);
+
+        match ty::expr_kind(bcx.tcx(), &*base.expr) {
+            ty::LvalueExpr => {
+                let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &*base.expr, "base"));
+                for &(i, t) in base.fields.iter() {
+                    let datum = base_datum.get_element(
+                            t, |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, i));
+                    let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
+                    bcx = datum.store_to(bcx, dest);
+                }
+            },
+            ty::RvalueDpsExpr | ty::RvalueDatumExpr => {
+                bcx = trans_into(bcx, &*base.expr, SaveIn(addr));
+            },
+            ty::RvalueStmtExpr => bcx.tcx().sess.bug("unexpected expr kind for struct base expr")
+        }
+    }
+
+    // Now, we just overwrite the fields we've explicity specified
     for &(i, ref e) in fields.iter() {
-        let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
+        let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
         let e_ty = expr_ty_adjusted(bcx, &**e);
         bcx = trans_into(bcx, &**e, SaveIn(dest));
         let scope = cleanup::CustomScope(custom_cleanup_scope);
@@ -1157,24 +1168,19 @@ pub fn trans_adt<'a>(bcx: &'a Block<'a>,
         fcx.schedule_drop_mem(scope, dest, e_ty);
     }
 
-    for base in optbase.iter() {
-        // FIXME #6573: is it sound to use the destination's repr on the base?
-        // And, would it ever be reasonable to be here with discr != 0?
-        let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &*base.expr, "base"));
-        for &(i, t) in base.fields.iter() {
-            let datum = base_datum.get_element(
-                t,
-                |srcval| adt::trans_field_ptr(bcx, repr, srcval, discr, i));
-            let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
-            bcx = datum.store_to(bcx, dest);
-        }
-    }
-
-    adt::trans_set_discr(bcx, repr, addr, discr);
+    adt::trans_set_discr(bcx, &*repr, addr, discr);
 
     fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
 
-    return bcx;
+    // If we don't care about the result drop the temporary we made
+    match dest {
+        SaveIn(_) => bcx,
+        Ignore => {
+            bcx = glue::drop_ty(bcx, addr, ty);
+            base::call_lifetime_end(bcx, addr);
+            bcx
+        }
+    }
 }