about summary refs log tree commit diff
path: root/src/librustc_trans/trans/expr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustc_trans/trans/expr.rs')
-rw-r--r--src/librustc_trans/trans/expr.rs78
1 files changed, 52 insertions, 26 deletions
diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs
index 60455119d58..ecdc7c06bb1 100644
--- a/src/librustc_trans/trans/expr.rs
+++ b/src/librustc_trans/trans/expr.rs
@@ -147,7 +147,7 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 ast::ExprPath(..) => {
                     match bcx.def(expr.id) {
                         def::DefConst(did) => {
-                            let expr = consts::get_const_expr(bcx.ccx(), did, expr);
+                            let const_expr = consts::get_const_expr(bcx.ccx(), did, expr);
                             // Temporarily get cleanup scopes out of the way,
                             // as they require sub-expressions to be contained
                             // inside the current AST scope.
@@ -155,7 +155,13 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                             // can't have destructors.
                             let scopes = mem::replace(&mut *bcx.fcx.scopes.borrow_mut(),
                                                       vec![]);
-                            bcx = trans_into(bcx, expr, dest);
+                            // Lock emitted debug locations to the location of
+                            // the constant reference expression.
+                            debuginfo::with_source_location_override(bcx.fcx,
+                                                                     expr.debug_loc(),
+                                                                     || {
+                                bcx = trans_into(bcx, const_expr, dest)
+                            });
                             let scopes = mem::replace(&mut *bcx.fcx.scopes.borrow_mut(),
                                                       scopes);
                             assert!(scopes.is_empty());
@@ -1494,8 +1500,45 @@ pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
     // panic 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
-    if let Some(base) = optbase {
+    if ty::type_is_simd(bcx.tcx(), ty) {
+        // Issue 23112: The original logic appeared vulnerable to same
+        // order-of-eval bug. But, SIMD values are tuple-structs;
+        // i.e. functional record update (FRU) syntax is unavailable.
+        //
+        // To be safe, double-check that we did not get here via FRU.
+        assert!(optbase.is_none());
+
+        // This is the constructor of a SIMD type, such types are
+        // always primitive machine types and so do not have a
+        // destructor or require any clean-up.
+        let llty = type_of::type_of(bcx.ccx(), ty);
+
+        // keep a vector as a register, and running through the field
+        // `insertelement`ing them directly into that register
+        // (i.e. avoid GEPi and `store`s to an alloca) .
+        let mut vec_val = C_undef(llty);
+
+        for &(i, ref e) in fields {
+            let block_datum = trans(bcx, &**e);
+            bcx = block_datum.bcx;
+            let position = C_uint(bcx.ccx(), i);
+            let value = block_datum.datum.to_llscalarish(bcx);
+            vec_val = InsertElement(bcx, vec_val, value, position);
+        }
+        Store(bcx, vec_val, addr);
+    } else if let Some(base) = optbase {
+        // Issue 23112: If there is a base, then order-of-eval
+        // requires field expressions eval'ed before base expression.
+
+        // First, trans field expressions to temporary scratch values.
+        let scratch_vals: Vec<_> = fields.iter().map(|&(i, ref e)| {
+            let datum = unpack_datum!(bcx, trans(bcx, &**e));
+            (i, datum)
+        }).collect();
+
+        debug_location.apply(bcx.fcx);
+
+        // Second, trans the base to the dest.
         assert_eq!(discr, 0);
 
         match ty::expr_kind(bcx.tcx(), &*base.expr) {
@@ -1514,31 +1557,14 @@ pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                 }
             }
         }
-    }
-
-    debug_location.apply(bcx.fcx);
-
-    if ty::type_is_simd(bcx.tcx(), ty) {
-        // This is the constructor of a SIMD type, such types are
-        // always primitive machine types and so do not have a
-        // destructor or require any clean-up.
-        let llty = type_of::type_of(bcx.ccx(), ty);
-
-        // keep a vector as a register, and running through the field
-        // `insertelement`ing them directly into that register
-        // (i.e. avoid GEPi and `store`s to an alloca) .
-        let mut vec_val = C_undef(llty);
 
-        for &(i, ref e) in fields {
-            let block_datum = trans(bcx, &**e);
-            bcx = block_datum.bcx;
-            let position = C_uint(bcx.ccx(), i);
-            let value = block_datum.datum.to_llscalarish(bcx);
-            vec_val = InsertElement(bcx, vec_val, value, position);
+        // Finally, move scratch field values into actual field locations
+        for (i, datum) in scratch_vals.into_iter() {
+            let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
+            bcx = datum.store_to(bcx, dest);
         }
-        Store(bcx, vec_val, addr);
     } else {
-        // Now, we just overwrite the fields we've explicitly specified
+        // No base means we can write all fields directly in place.
         for &(i, ref e) in fields {
             let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
             let e_ty = expr_ty_adjusted(bcx, &**e);