@@ -25,6 +25,7 @@ use std::cmp;
2525use std:: fmt;
2626use std:: i64;
2727use std:: iter;
28+ use std:: ops:: Deref ;
2829
2930/// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout)
3031/// for a target, which contains everything needed to compute layouts.
@@ -904,7 +905,8 @@ pub enum Layout {
904905 /// If true, the size is exact, otherwise it's only a lower bound.
905906 sized : bool ,
906907 align : Align ,
907- size : Size
908+ element_size : Size ,
909+ count : u64
908910 } ,
909911
910912 /// TyRawPtr or TyRef with a !Sized pointee.
@@ -1087,25 +1089,35 @@ impl<'a, 'gcx, 'tcx> Layout {
10871089 // Arrays and slices.
10881090 ty:: TyArray ( element, count) => {
10891091 let element = element. layout ( infcx) ?;
1092+ let element_size = element. size ( dl) ;
1093+ // FIXME(eddyb) Don't use host `usize` for array lengths.
1094+ let usize_count: usize = count;
1095+ let count = usize_count as u64 ;
1096+ if element_size. checked_mul ( count, dl) . is_none ( ) {
1097+ return Err ( LayoutError :: SizeOverflow ( ty) ) ;
1098+ }
10901099 Array {
10911100 sized : true ,
10921101 align : element. align ( dl) ,
1093- size : element . size ( dl ) . checked_mul ( count as u64 , dl )
1094- . map_or ( Err ( LayoutError :: SizeOverflow ( ty ) ) , Ok ) ?
1102+ element_size : element_size ,
1103+ count : count
10951104 }
10961105 }
10971106 ty:: TySlice ( element) => {
1107+ let element = element. layout ( infcx) ?;
10981108 Array {
10991109 sized : false ,
1100- align : element. layout ( infcx) ?. align ( dl) ,
1101- size : Size :: from_bytes ( 0 )
1110+ align : element. align ( dl) ,
1111+ element_size : element. size ( dl) ,
1112+ count : 0
11021113 }
11031114 }
11041115 ty:: TyStr => {
11051116 Array {
11061117 sized : false ,
11071118 align : dl. i8_align ,
1108- size : Size :: from_bytes ( 0 )
1119+ element_size : Size :: from_bytes ( 1 ) ,
1120+ count : 0
11091121 }
11101122 }
11111123
@@ -1447,15 +1459,23 @@ impl<'a, 'gcx, 'tcx> Layout {
14471459 }
14481460
14491461 Vector { element, count } => {
1450- let elem_size = element. size ( dl) ;
1451- let vec_size = match elem_size . checked_mul ( count, dl) {
1462+ let element_size = element. size ( dl) ;
1463+ let vec_size = match element_size . checked_mul ( count, dl) {
14521464 Some ( size) => size,
14531465 None => bug ! ( "Layout::size({:?}): {} * {} overflowed" ,
1454- self , elem_size . bytes( ) , count)
1466+ self , element_size . bytes( ) , count)
14551467 } ;
14561468 vec_size. abi_align ( self . align ( dl) )
14571469 }
14581470
1471+ Array { element_size, count, .. } => {
1472+ match element_size. checked_mul ( count, dl) {
1473+ Some ( size) => size,
1474+ None => bug ! ( "Layout::size({:?}): {} * {} overflowed" ,
1475+ self , element_size. bytes( ) , count)
1476+ }
1477+ }
1478+
14591479 FatPointer { metadata, .. } => {
14601480 // Effectively a (ptr, meta) tuple.
14611481 Pointer . size ( dl) . abi_align ( metadata. align ( dl) )
@@ -1464,7 +1484,7 @@ impl<'a, 'gcx, 'tcx> Layout {
14641484 }
14651485
14661486 CEnum { discr, .. } => Int ( discr) . size ( dl) ,
1467- Array { size , .. } | General { size, .. } => size,
1487+ General { size, .. } => size,
14681488 UntaggedUnion { ref variants } => variants. stride ( ) ,
14691489
14701490 Univariant { ref variant, .. } |
@@ -1513,6 +1533,59 @@ impl<'a, 'gcx, 'tcx> Layout {
15131533 }
15141534 }
15151535 }
1536+
1537+ pub fn field_offset ( & self ,
1538+ dl : & TargetDataLayout ,
1539+ i : usize ,
1540+ variant_index : Option < usize > )
1541+ -> Size {
1542+ match * self {
1543+ Scalar { .. } |
1544+ CEnum { .. } |
1545+ UntaggedUnion { .. } |
1546+ RawNullablePointer { .. } => {
1547+ Size :: from_bytes ( 0 )
1548+ }
1549+
1550+ Vector { element, count } => {
1551+ let element_size = element. size ( dl) ;
1552+ let i = i as u64 ;
1553+ assert ! ( i < count) ;
1554+ Size :: from_bytes ( element_size. bytes ( ) * count)
1555+ }
1556+
1557+ Array { element_size, count, .. } => {
1558+ let i = i as u64 ;
1559+ assert ! ( i < count) ;
1560+ Size :: from_bytes ( element_size. bytes ( ) * count)
1561+ }
1562+
1563+ FatPointer { metadata, .. } => {
1564+ // Effectively a (ptr, meta) tuple.
1565+ assert ! ( i < 2 ) ;
1566+ if i == 0 {
1567+ Size :: from_bytes ( 0 )
1568+ } else {
1569+ Pointer . size ( dl) . abi_align ( metadata. align ( dl) )
1570+ }
1571+ }
1572+
1573+ Univariant { ref variant, .. } => variant. offsets [ i] ,
1574+
1575+ General { ref variants, .. } => {
1576+ let v = variant_index. expect ( "variant index required" ) ;
1577+ variants[ v] . offsets [ i + 1 ]
1578+ }
1579+
1580+ StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => {
1581+ if Some ( nndiscr as usize ) == variant_index {
1582+ nonnull. offsets [ i]
1583+ } else {
1584+ Size :: from_bytes ( 0 )
1585+ }
1586+ }
1587+ }
1588+ }
15161589}
15171590
15181591/// Type size "skeleton", i.e. the only information determining a type's size.
@@ -1658,3 +1731,154 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
16581731 }
16591732 }
16601733}
1734+
1735+ /// A pair of a type and its layout. Implements various
1736+ /// type traversal APIs (e.g. recursing into fields).
1737+ #[ derive( Copy , Clone , Debug ) ]
1738+ pub struct TyLayout < ' tcx > {
1739+ pub ty : Ty < ' tcx > ,
1740+ pub layout : & ' tcx Layout ,
1741+ pub variant_index : Option < usize > ,
1742+ }
1743+
1744+ impl < ' tcx > Deref for TyLayout < ' tcx > {
1745+ type Target = Layout ;
1746+ fn deref ( & self ) -> & Layout {
1747+ self . layout
1748+ }
1749+ }
1750+
1751+ impl < ' a , ' gcx , ' tcx > TyLayout < ' gcx > {
1752+ pub fn of ( infcx : & InferCtxt < ' a , ' gcx , ' tcx > , ty : Ty < ' gcx > )
1753+ -> Result < Self , LayoutError < ' gcx > > {
1754+ let ty = normalize_associated_type ( infcx, ty) ;
1755+
1756+ Ok ( TyLayout {
1757+ ty : ty,
1758+ layout : ty. layout ( infcx) ?,
1759+ variant_index : None
1760+ } )
1761+ }
1762+
1763+ pub fn for_variant ( & self , variant_index : usize ) -> Self {
1764+ TyLayout {
1765+ variant_index : Some ( variant_index) ,
1766+ ..* self
1767+ }
1768+ }
1769+
1770+ pub fn field_offset ( & self , dl : & TargetDataLayout , i : usize ) -> Size {
1771+ self . layout . field_offset ( dl, i, self . variant_index )
1772+ }
1773+
1774+ pub fn field_count ( & self ) -> usize {
1775+ // Handle enum/union through the type rather than Layout.
1776+ if let ty:: TyAdt ( def, _) = self . ty . sty {
1777+ let v = self . variant_index . unwrap_or ( 0 ) ;
1778+ if def. variants . is_empty ( ) {
1779+ assert_eq ! ( v, 0 ) ;
1780+ return 0 ;
1781+ } else {
1782+ return def. variants [ v] . fields . len ( ) ;
1783+ }
1784+ }
1785+
1786+ match * self . layout {
1787+ Scalar { .. } => {
1788+ bug ! ( "TyLayout::field_count({:?}): not applicable" , self )
1789+ }
1790+
1791+ // Handled above (the TyAdt case).
1792+ CEnum { .. } |
1793+ General { .. } |
1794+ UntaggedUnion { .. } |
1795+ RawNullablePointer { .. } |
1796+ StructWrappedNullablePointer { .. } => bug ! ( ) ,
1797+
1798+ FatPointer { .. } => 2 ,
1799+
1800+ Vector { count, .. } |
1801+ Array { count, .. } => {
1802+ let usize_count = count as usize ;
1803+ assert_eq ! ( usize_count as u64 , count) ;
1804+ usize_count
1805+ }
1806+
1807+ Univariant { ref variant, .. } => variant. offsets . len ( ) ,
1808+ }
1809+ }
1810+
1811+ pub fn field_type ( & self , tcx : TyCtxt < ' a , ' gcx , ' gcx > , i : usize ) -> Ty < ' gcx > {
1812+ let ptr_field_type = |pointee : Ty < ' gcx > | {
1813+ let slice = |element : Ty < ' gcx > | {
1814+ assert ! ( i < 2 ) ;
1815+ if i == 0 {
1816+ tcx. mk_mut_ptr ( element)
1817+ } else {
1818+ tcx. types . usize
1819+ }
1820+ } ;
1821+ match tcx. struct_tail ( pointee) . sty {
1822+ ty:: TySlice ( element) => slice ( element) ,
1823+ ty:: TyStr => slice ( tcx. types . u8 ) ,
1824+ ty:: TyDynamic ( ..) => tcx. mk_mut_ptr ( tcx. mk_nil ( ) ) ,
1825+ _ => bug ! ( "TyLayout::field_type({:?}): not applicable" , self )
1826+ }
1827+ } ;
1828+
1829+ match self . ty . sty {
1830+ ty:: TyBool |
1831+ ty:: TyChar |
1832+ ty:: TyInt ( _) |
1833+ ty:: TyUint ( _) |
1834+ ty:: TyFloat ( _) |
1835+ ty:: TyFnPtr ( _) |
1836+ ty:: TyNever |
1837+ ty:: TyFnDef ( ..) |
1838+ ty:: TyDynamic ( ..) => {
1839+ bug ! ( "TyLayout::field_type({:?}): not applicable" , self )
1840+ }
1841+
1842+ // Potentially-fat pointers.
1843+ ty:: TyRef ( _, ty:: TypeAndMut { ty : pointee, .. } ) |
1844+ ty:: TyRawPtr ( ty:: TypeAndMut { ty : pointee, .. } ) => {
1845+ ptr_field_type ( pointee)
1846+ }
1847+ ty:: TyAdt ( def, _) if def. is_box ( ) => {
1848+ ptr_field_type ( self . ty . boxed_ty ( ) )
1849+ }
1850+
1851+ // Arrays and slices.
1852+ ty:: TyArray ( element, _) |
1853+ ty:: TySlice ( element) => element,
1854+ ty:: TyStr => tcx. types . u8 ,
1855+
1856+ // Tuples and closures.
1857+ ty:: TyClosure ( def_id, ref substs) => {
1858+ substs. upvar_tys ( def_id, tcx) . nth ( i) . unwrap ( )
1859+ }
1860+
1861+ ty:: TyTuple ( tys, _) => tys[ i] ,
1862+
1863+ // SIMD vector types.
1864+ ty:: TyAdt ( def, ..) if def. repr . simd => {
1865+ self . ty . simd_type ( tcx)
1866+ }
1867+
1868+ // ADTs.
1869+ ty:: TyAdt ( def, substs) => {
1870+ def. variants [ self . variant_index . unwrap_or ( 0 ) ] . fields [ i] . ty ( tcx, substs)
1871+ }
1872+
1873+ ty:: TyProjection ( _) | ty:: TyAnon ( ..) | ty:: TyParam ( _) |
1874+ ty:: TyInfer ( _) | ty:: TyError => {
1875+ bug ! ( "TyLayout::field_type: unexpected type `{}`" , self . ty)
1876+ }
1877+ }
1878+ }
1879+
1880+ pub fn field ( & self , infcx : & InferCtxt < ' a , ' gcx , ' tcx > , i : usize )
1881+ -> Result < Self , LayoutError < ' gcx > > {
1882+ TyLayout :: of ( infcx, self . field_type ( infcx. tcx . global_tcx ( ) , i) )
1883+ }
1884+ }
0 commit comments