/// Access a field, at a point when the value's case is known.
Access a field, at a point when the value's case is known.
Access a field at a point when the value ' s case is known .
pub fn project_field(self, bx: &Builder<'a, 'll, 'tcx>, ix: usize) -> PlaceRef<'ll, 'tcx> {
        let cx = bx.cx;
        let field = self.layout.field(cx, ix);
        let offset = self.layout.fields.offset(ix);
        let align = self.align.min(self.layout.align).min(field.align);
        let simple = || {
            // Unions and newtypes only use an offset of 0.
            let llval = if offset.bytes() == 0 {
                self.llval
            } else if let layout::Abi::ScalarPair(ref a, ref b) = self.layout.abi {
                // Offsets have to match either first or second field.
                assert_eq!(offset, a.value.size(cx).abi_align(b.value.align(cx)));
                bx.struct_gep(self.llval, 1)
            } else {
                bx.struct_gep(self.llval, self.layout.llvm_field_index(ix))
            };
            PlaceRef {
                // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
                llval: bx.pointercast(llval, field.llvm_type(cx).ptr_to()),
                llextra: if cx.type_has_metadata(field.ty) {
                    self.llextra
                } else {
                    None
                },
                layout: field,
                align,
            }
        };
        // Simple cases, which don't need DST adjustment:
        //   * no metadata available - just log the case
        //   * known alignment - sized types, [T], str or a foreign type
        //   * packed struct - there is no alignment padding
        match field.ty.sty {
            _ if self.llextra.is_none() => {
                debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment",
                    ix, self.llval);
                return simple();
            }
            _ if !field.is_unsized() => return simple(),
            ty::TySlice(..) | ty::TyStr | ty::TyForeign(..) => return simple(),
            ty::TyAdt(def, _) => {
                if def.repr.packed() {
                    // FIXME(eddyb) generalize the adjustment when we
                    // start supporting packing to larger alignments.
                    assert_eq!(self.layout.align.abi(), 1);
                    return simple();
                }
            }
            _ => {}
        }
        // We need to get the pointer manually now.
        // We do this by casting to a *i8, then offsetting it by the appropriate amount.
        // We do this instead of, say, simply adjusting the pointer from the result of a GEP
        // because the field may have an arbitrary alignment in the LLVM representation
        // anyway.
        //
        // To demonstrate:
        //   struct Foo<T: ?Sized> {
        //      x: u16,
        //      y: T
        //   }
        //
        // The type Foo<Foo<Trait>> is represented in LLVM as { u16, { u16, u8 }}, meaning that
        // the `y` field has 16-bit alignment.
        let meta = self.llextra;
        let unaligned_offset = C_usize(cx, offset.bytes());
        // Get the alignment of the field
        let (_, unsized_align) = glue::size_and_align_of_dst(bx, field.ty, meta);
        // Bump the unaligned offset up to the appropriate alignment using the
        // following expression:
        //
        //   (unaligned offset + (align - 1)) & -align
        // Calculate offset
        let align_sub_1 = bx.sub(unsized_align, C_usize(cx, 1u64));
        let offset = bx.and(bx.add(unaligned_offset, align_sub_1),
        bx.neg(unsized_align));
        debug!("struct_field_ptr: DST field offset: {:?}", offset);
        // Cast and adjust pointer
        let byte_ptr = bx.pointercast(self.llval, Type::i8p(cx));
        let byte_ptr = bx.gep(byte_ptr, &[offset]);
        // Finally, cast back to the type expected
        let ll_fty = field.llvm_type(cx);
        debug!("struct_field_ptr: Field type is {:?}", ll_fty);
        PlaceRef {
            llval: bx.pointercast(byte_ptr, ll_fty.ptr_to()),
            llextra: self.llextra,
            layout: field,
            align,
        }
    }
pub fn project_field ( self , bx : & Builder < ' a , ' ll , ' tcx > , ix : usize ) -> PlaceRef < ' ll , ' tcx > { let cx = bx . cx ; let field = self . layout . field ( cx , ix ) ; let offset = self . layout . fields . offset ( ix ) ; let align = self . align . min ( self . layout . align ) . min ( field . align ) ; let simple = | | { // Unions and newtypes only use an offset of 0. let llval = if offset . bytes ( ) == 0 { self . llval } else if let layout :: Abi :: ScalarPair ( ref a , ref b ) = self . layout . abi { // Offsets have to match either first or second field. assert_eq ! ( offset a value size ( cx ) abi_align ( b value align ( cx ) ) ) ; bx . struct_gep ( self . llval , 1 ) } else { bx . struct_gep ( self . llval , self . layout . llvm_field_index ( ix ) ) } ; PlaceRef { // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types. llval : bx . pointercast ( llval , field . llvm_type ( cx ) . ptr_to ( ) ) , llextra : if cx . type_has_metadata ( field . ty ) { self . llextra } else { None } , layout : field , align , } } ; // Simple cases, which don't need DST adjustment: //   * no metadata available - just log the case //   * known alignment - sized types, [T], str or a foreign type //   * packed struct - there is no alignment padding match field . ty . sty { _ if self . llextra . is_none ( ) => { debug ! ( " " ix self llval ) ; return simple ( ) ; } _ if ! field . is_unsized ( ) => return simple ( ) , ty :: TySlice ( .. ) | ty :: TyStr | ty :: TyForeign ( .. ) => return simple ( ) , ty :: TyAdt ( def , _ ) => { if def . repr . packed ( ) { // FIXME(eddyb) generalize the adjustment when we // start supporting packing to larger alignments. assert_eq ! ( self layout align abi ( ) 1 ) ; return simple ( ) ; } } _ => { } } // We need to get the pointer manually now. // We do this by casting to a *i8, then offsetting it by the appropriate amount. // We do this instead of, say, simply adjusting the pointer from the result of a GEP // because the field may have an arbitrary alignment in the LLVM representation // anyway. // // To demonstrate: //   struct Foo<T: ?Sized> { //      x: u16, //      y: T //   } // // The type Foo<Foo<Trait>> is represented in LLVM as { u16, { u16, u8 }}, meaning that // the `y` field has 16-bit alignment. let meta = self . llextra ; let unaligned_offset = C_usize ( cx , offset . bytes ( ) ) ; // Get the alignment of the field let ( _ , unsized_align ) = glue :: size_and_align_of_dst ( bx , field . ty , meta ) ; // Bump the unaligned offset up to the appropriate alignment using the // following expression: // //   (unaligned offset + (align - 1)) & -align // Calculate offset let align_sub_1 = bx . sub ( unsized_align , C_usize ( cx , 1u64 ) ) ; let offset = bx . and ( bx . add ( unaligned_offset , align_sub_1 ) , bx . neg ( unsized_align ) ) ; debug ! ( " " offset ) ; // Cast and adjust pointer let byte_ptr = bx . pointercast ( self . llval , Type :: i8p ( cx ) ) ; let byte_ptr = bx . gep ( byte_ptr , & [ offset ] ) ; // Finally, cast back to the type expected let ll_fty = field . llvm_type ( cx ) ; debug ! ( " " ll_fty ) ; PlaceRef { llval : bx . pointercast ( byte_ptr , ll_fty . ptr_to ( ) ) , llextra : self . llextra , layout : field , align , } }
Access a field, at a point when the value's case is known.
Access a field at a point when the value ' s case is known .
self
bx
&Builder<'a, 'll, 'tcx>
ix
usize