@@ -1500,8 +1500,45 @@ pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
1500
1500
// panic occur before the ADT as a whole is ready.
1501
1501
let custom_cleanup_scope = fcx. push_custom_cleanup_scope ( ) ;
1502
1502
1503
- // First we trans the base, if we have one, to the dest
1504
- if let Some ( base) = optbase {
1503
+ if ty:: type_is_simd ( bcx. tcx ( ) , ty) {
1504
+ // Issue 23112: The original logic appeared vulnerable to same
1505
+ // order-of-eval bug. But, SIMD values are tuple-structs;
1506
+ // i.e. functional record update (FRU) syntax is unavailable.
1507
+ //
1508
+ // To be safe, double-check that we did not get here via FRU.
1509
+ assert ! ( optbase. is_none( ) ) ;
1510
+
1511
+ // This is the constructor of a SIMD type, such types are
1512
+ // always primitive machine types and so do not have a
1513
+ // destructor or require any clean-up.
1514
+ let llty = type_of:: type_of ( bcx. ccx ( ) , ty) ;
1515
+
1516
+ // keep a vector as a register, and running through the field
1517
+ // `insertelement`ing them directly into that register
1518
+ // (i.e. avoid GEPi and `store`s to an alloca) .
1519
+ let mut vec_val = C_undef ( llty) ;
1520
+
1521
+ for & ( i, ref e) in fields {
1522
+ let block_datum = trans ( bcx, & * * e) ;
1523
+ bcx = block_datum. bcx ;
1524
+ let position = C_uint ( bcx. ccx ( ) , i) ;
1525
+ let value = block_datum. datum . to_llscalarish ( bcx) ;
1526
+ vec_val = InsertElement ( bcx, vec_val, value, position) ;
1527
+ }
1528
+ Store ( bcx, vec_val, addr) ;
1529
+ } else if let Some ( base) = optbase {
1530
+ // Issue 23112: If there is a base, then order-of-eval
1531
+ // requires field expressions eval'ed before base expression.
1532
+
1533
+ // First, trans field expressions to temporary scratch values.
1534
+ let scratch_vals: Vec < _ > = fields. iter ( ) . map ( |& ( i, ref e) | {
1535
+ let datum = unpack_datum ! ( bcx, trans( bcx, & * * e) ) ;
1536
+ ( i, datum)
1537
+ } ) . collect ( ) ;
1538
+
1539
+ debug_location. apply ( bcx. fcx ) ;
1540
+
1541
+ // Second, trans the base to the dest.
1505
1542
assert_eq ! ( discr, 0 ) ;
1506
1543
1507
1544
match ty:: expr_kind ( bcx. tcx ( ) , & * base. expr ) {
@@ -1520,31 +1557,14 @@ pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
1520
1557
}
1521
1558
}
1522
1559
}
1523
- }
1524
-
1525
- debug_location. apply ( bcx. fcx ) ;
1526
-
1527
- if ty:: type_is_simd ( bcx. tcx ( ) , ty) {
1528
- // This is the constructor of a SIMD type, such types are
1529
- // always primitive machine types and so do not have a
1530
- // destructor or require any clean-up.
1531
- let llty = type_of:: type_of ( bcx. ccx ( ) , ty) ;
1532
-
1533
- // keep a vector as a register, and running through the field
1534
- // `insertelement`ing them directly into that register
1535
- // (i.e. avoid GEPi and `store`s to an alloca) .
1536
- let mut vec_val = C_undef ( llty) ;
1537
1560
1538
- for & ( i, ref e) in fields {
1539
- let block_datum = trans ( bcx, & * * e) ;
1540
- bcx = block_datum. bcx ;
1541
- let position = C_uint ( bcx. ccx ( ) , i) ;
1542
- let value = block_datum. datum . to_llscalarish ( bcx) ;
1543
- vec_val = InsertElement ( bcx, vec_val, value, position) ;
1561
+ // Finally, move scratch field values into actual field locations
1562
+ for ( i, datum) in scratch_vals. into_iter ( ) {
1563
+ let dest = adt:: trans_field_ptr ( bcx, & * repr, addr, discr, i) ;
1564
+ bcx = datum. store_to ( bcx, dest) ;
1544
1565
}
1545
- Store ( bcx, vec_val, addr) ;
1546
1566
} else {
1547
- // Now, we just overwrite the fields we've explicitly specified
1567
+ // No base means we can write all fields directly in place.
1548
1568
for & ( i, ref e) in fields {
1549
1569
let dest = adt:: trans_field_ptr ( bcx, & * repr, addr, discr, i) ;
1550
1570
let e_ty = expr_ty_adjusted ( bcx, & * * e) ;
0 commit comments