diff options
Diffstat (limited to 'src/librustc_trans/trans/expr.rs')
| -rw-r--r-- | src/librustc_trans/trans/expr.rs | 78 |
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); |
