pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                                 ty: Ty<'tcx>,
                                 discr: ty::Disr,
                                 fields: &[(usize, &hir::Expr)],
                                 optbase: Option<StructBaseInfo<'a, 'tcx>>,
                                 dest: Dest,
                                 debug_location: DebugLoc)
                                 -> Block<'blk, 'tcx> {
    let _icx = push_ctxt("trans_adt");
    let fcx = bcx.fcx;
    let repr = adt::represent_type(bcx.ccx(), ty);

    debug_location.apply(bcx.fcx);

    // If we don't care about the result, just make a
    // temporary stack slot
    let addr = match dest {
        SaveIn(pos) => pos,
        Ignore => {
            let llresult = alloc_ty(bcx, ty, "temp");
            call_lifetime_start(bcx, llresult);
            llresult
        }
    };

    // This scope holds intermediates that must be cleaned should
    // panic occur before the ADT as a whole is ready.
    let custom_cleanup_scope = fcx.push_custom_cleanup_scope();

    if ty.is_simd() {
        // 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 expr_kind(bcx.tcx(), &*base.expr) {
            ExprKind::RvalueDps | ExprKind::RvalueDatum if !bcx.fcx.type_needs_drop(ty) => {
                bcx = trans_into(bcx, &*base.expr, SaveIn(addr));
            },
            ExprKind::RvalueStmt => {
                bcx.tcx().sess.bug("unexpected expr kind for struct base expr")
            }
            _ => {
                let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &*base.expr, "base"));
                for &(i, t) in &base.fields {
                    let datum = base_datum.get_element(
                            bcx, t, |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, i));
                    assert!(type_is_sized(bcx.tcx(), datum.ty));
                    let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
                    bcx = datum.store_to(bcx, dest);
                }
            }
        }

        // Finally, move scratch field values into actual field locations
        for (i, datum) in scratch_vals {
            let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
            bcx = datum.store_to(bcx, dest);
        }
    } else {
        // 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);
            bcx = trans_into(bcx, &**e, SaveIn(dest));
            let scope = cleanup::CustomScope(custom_cleanup_scope);
            fcx.schedule_lifetime_end(scope, dest);
            // FIXME: nonzeroing move should generalize to fields
            fcx.schedule_drop_mem(scope, dest, e_ty, None);
        }
    }

    adt::trans_set_discr(bcx, &*repr, addr, discr);

    fcx.pop_custom_cleanup_scope(custom_cleanup_scope);

    // 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, debug_location);
            base::call_lifetime_end(bcx, addr);
            bcx
        }
    }
}
/// Constructs an ADT instance:
///
/// - `fields` should be a list of field indices paired with the
/// expression to store into that field.  The initializers will be
/// evaluated in the order specified by `fields`.
///
/// - `optbase` contains information on the base struct (if any) from
/// which remaining fields are copied; see comments on `StructBaseInfo`.
Constructs an ADT instance:
`fields` should be a list of field indices paired with the
expression to store into that field.  The initializers will be
evaluated in the order specified by `fields`.

`optbase` contains information on the base struct (if any) from
which remaining fields are copied; see comments on `StructBaseInfo`.
Constructs an ADT instance : ` fields ` should be a list of field indices paired with the expression to store into that field . The initializers will be evaluated in the order specified by ` fields ` . ` optbase ` contains information on the base struct ( if any ) from which remaining fields are copied ; see comments on ` StructBaseInfo ` .
pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                                 ty: Ty<'tcx>,
                                 discr: ty::Disr,
                                 fields: &[(usize, &hir::Expr)],
                                 optbase: Option<StructBaseInfo<'a, 'tcx>>,
                                 dest: Dest,
                                 debug_location: DebugLoc)
                                 -> Block<'blk, 'tcx> {
    let _icx = push_ctxt("trans_adt");
    let fcx = bcx.fcx;
    let repr = adt::represent_type(bcx.ccx(), ty);
    debug_location.apply(bcx.fcx);
    // If we don't care about the result, just make a
    // temporary stack slot
    let addr = match dest {
        SaveIn(pos) => pos,
        Ignore => {
            let llresult = alloc_ty(bcx, ty, "temp");
            call_lifetime_start(bcx, llresult);
            llresult
        }
    };
    // This scope holds intermediates that must be cleaned should
    // panic occur before the ADT as a whole is ready.
    let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
    if ty.is_simd() {
        // 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 expr_kind(bcx.tcx(), &*base.expr) {
            ExprKind::RvalueDps | ExprKind::RvalueDatum if !bcx.fcx.type_needs_drop(ty) => {
                bcx = trans_into(bcx, &*base.expr, SaveIn(addr));
            },
            ExprKind::RvalueStmt => {
                bcx.tcx().sess.bug("unexpected expr kind for struct base expr")
            }
            _ => {
                let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &*base.expr, "base"));
                for &(i, t) in &base.fields {
                    let datum = base_datum.get_element(
                            bcx, t, |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, i));
                    assert!(type_is_sized(bcx.tcx(), datum.ty));
                    let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
                    bcx = datum.store_to(bcx, dest);
                }
            }
        }
        // Finally, move scratch field values into actual field locations
        for (i, datum) in scratch_vals {
            let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
            bcx = datum.store_to(bcx, dest);
        }
    } else {
        // 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);
            bcx = trans_into(bcx, &**e, SaveIn(dest));
            let scope = cleanup::CustomScope(custom_cleanup_scope);
            fcx.schedule_lifetime_end(scope, dest);
            // FIXME: nonzeroing move should generalize to fields
            fcx.schedule_drop_mem(scope, dest, e_ty, None);
        }
    }
    adt::trans_set_discr(bcx, &*repr, addr, discr);
    fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
    // 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, debug_location);
            base::call_lifetime_end(bcx, addr);
            bcx
        }
    }
}
pub fn trans_adt < ' a , ' blk , ' tcx > ( mut bcx : Block < ' blk , ' tcx > , ty : Ty < ' tcx > , discr : ty :: Disr , fields : & [ ( usize , & hir :: Expr ) ] , optbase : Option < StructBaseInfo < ' a , ' tcx > > , dest : Dest , debug_location : DebugLoc ) -> Block < ' blk , ' tcx > { let _icx = push_ctxt ( " " ) ; let fcx = bcx . fcx ; let repr = adt :: represent_type ( bcx . ccx ( ) , ty ) ; debug_location . apply ( bcx . fcx ) ; // If we don't care about the result, just make a // temporary stack slot let addr = match dest { SaveIn ( pos ) => pos , Ignore => { let llresult = alloc_ty ( bcx , ty , " " ) ; call_lifetime_start ( bcx , llresult ) ; llresult } } ; // This scope holds intermediates that must be cleaned should // panic occur before the ADT as a whole is ready. let custom_cleanup_scope = fcx . push_custom_cleanup_scope ( ) ; if ty . is_simd ( ) { // 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 expr_kind ( bcx . tcx ( ) , & * base . expr ) { ExprKind :: RvalueDps | ExprKind :: RvalueDatum if ! bcx . fcx . type_needs_drop ( ty ) => { bcx = trans_into ( bcx , & * base . expr , SaveIn ( addr ) ) ; } , ExprKind :: RvalueStmt => { bcx . tcx ( ) . sess . bug ( " " ) } _ => { let base_datum = unpack_datum ! ( bcx trans_to_lvalue ( bcx base expr " " ) ) ; for & ( i , t ) in & base . fields { let datum = base_datum . get_element ( bcx , t , | srcval | adt :: trans_field_ptr ( bcx , & * repr , srcval , discr , i ) ) ; assert ! ( type_is_sized ( bcx tcx ( ) datum ty ) ) ; let dest = adt :: trans_field_ptr ( bcx , & * repr , addr , discr , i ) ; bcx = datum . store_to ( bcx , dest ) ; } } } // Finally, move scratch field values into actual field locations for ( i , datum ) in scratch_vals { let dest = adt :: trans_field_ptr ( bcx , & * repr , addr , discr , i ) ; bcx = datum . store_to ( bcx , dest ) ; } } else { // 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 ) ; bcx = trans_into ( bcx , & * * e , SaveIn ( dest ) ) ; let scope = cleanup :: CustomScope ( custom_cleanup_scope ) ; fcx . schedule_lifetime_end ( scope , dest ) ; // FIXME: nonzeroing move should generalize to fields fcx . schedule_drop_mem ( scope , dest , e_ty , None ) ; } } adt :: trans_set_discr ( bcx , & * repr , addr , discr ) ; fcx . pop_custom_cleanup_scope ( custom_cleanup_scope ) ; // 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 , debug_location ) ; base :: call_lifetime_end ( bcx , addr ) ; bcx } } }
Constructs an ADT instance:
 `fields` should be a list of field indices paired with the
expression to store into that field.
Constructs an ADT instance : ` fields ` should be a list of field indices paired with the expression to store into that field .
bcx
Block<'blk, 'tcx>
ty
Ty<'tcx>
discr
ty::Disr
fields
&[(usize, &hir::Expr)]
optbase
Option<StructBaseInfo<'a, 'tcx>>
dest
Dest
debug_location
DebugLoc
bcx
Block<'blk, 'tcx>
ty
Ty<'tcx>
discr
ty::Disr
fields
&[(usize, &hir::Expr)]
optbase
Option<StructBaseInfo<'a, 'tcx>>
dest
Dest
debug_location
DebugLoc