@@ -25,6 +25,7 @@ use std::cmp;
25
25
use std:: fmt;
26
26
use std:: i64;
27
27
use std:: iter;
28
+ use std:: ops:: Deref ;
28
29
29
30
/// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout)
30
31
/// for a target, which contains everything needed to compute layouts.
@@ -904,7 +905,8 @@ pub enum Layout {
904
905
/// If true, the size is exact, otherwise it's only a lower bound.
905
906
sized : bool ,
906
907
align : Align ,
907
- size : Size
908
+ element_size : Size ,
909
+ count : u64
908
910
} ,
909
911
910
912
/// TyRawPtr or TyRef with a !Sized pointee.
@@ -1087,25 +1089,33 @@ impl<'a, 'gcx, 'tcx> Layout {
1087
1089
// Arrays and slices.
1088
1090
ty:: TyArray ( element, count) => {
1089
1091
let element = element. layout ( infcx) ?;
1092
+ let element_size = element. size ( dl) ;
1093
+ let count = count as u64 ;
1094
+ if element_size. checked_mul ( count, dl) . is_none ( ) {
1095
+ return Err ( LayoutError :: SizeOverflow ( ty) ) ;
1096
+ }
1090
1097
Array {
1091
1098
sized : true ,
1092
1099
align : element. align ( dl) ,
1093
- size : element . size ( dl ) . checked_mul ( count as u64 , dl )
1094
- . map_or ( Err ( LayoutError :: SizeOverflow ( ty ) ) , Ok ) ?
1100
+ element_size : element_size ,
1101
+ count : count
1095
1102
}
1096
1103
}
1097
1104
ty:: TySlice ( element) => {
1105
+ let element = element. layout ( infcx) ?;
1098
1106
Array {
1099
1107
sized : false ,
1100
- align : element. layout ( infcx) ?. align ( dl) ,
1101
- size : Size :: from_bytes ( 0 )
1108
+ align : element. align ( dl) ,
1109
+ element_size : element. size ( dl) ,
1110
+ count : 0
1102
1111
}
1103
1112
}
1104
1113
ty:: TyStr => {
1105
1114
Array {
1106
1115
sized : false ,
1107
1116
align : dl. i8_align ,
1108
- size : Size :: from_bytes ( 0 )
1117
+ element_size : Size :: from_bytes ( 1 ) ,
1118
+ count : 0
1109
1119
}
1110
1120
}
1111
1121
@@ -1447,15 +1457,23 @@ impl<'a, 'gcx, 'tcx> Layout {
1447
1457
}
1448
1458
1449
1459
Vector { element, count } => {
1450
- let elem_size = element. size ( dl) ;
1451
- let vec_size = match elem_size . checked_mul ( count, dl) {
1460
+ let element_size = element. size ( dl) ;
1461
+ let vec_size = match element_size . checked_mul ( count, dl) {
1452
1462
Some ( size) => size,
1453
1463
None => bug ! ( "Layout::size({:?}): {} * {} overflowed" ,
1454
- self , elem_size . bytes( ) , count)
1464
+ self , element_size . bytes( ) , count)
1455
1465
} ;
1456
1466
vec_size. abi_align ( self . align ( dl) )
1457
1467
}
1458
1468
1469
+ Array { element_size, count, .. } => {
1470
+ match element_size. checked_mul ( count, dl) {
1471
+ Some ( size) => size,
1472
+ None => bug ! ( "Layout::size({:?}): {} * {} overflowed" ,
1473
+ self , element_size. bytes( ) , count)
1474
+ }
1475
+ }
1476
+
1459
1477
FatPointer { metadata, .. } => {
1460
1478
// Effectively a (ptr, meta) tuple.
1461
1479
Pointer . size ( dl) . abi_align ( metadata. align ( dl) )
@@ -1464,7 +1482,7 @@ impl<'a, 'gcx, 'tcx> Layout {
1464
1482
}
1465
1483
1466
1484
CEnum { discr, .. } => Int ( discr) . size ( dl) ,
1467
- Array { size , .. } | General { size, .. } => size,
1485
+ General { size, .. } => size,
1468
1486
UntaggedUnion { ref variants } => variants. stride ( ) ,
1469
1487
1470
1488
Univariant { ref variant, .. } |
@@ -1513,6 +1531,59 @@ impl<'a, 'gcx, 'tcx> Layout {
1513
1531
}
1514
1532
}
1515
1533
}
1534
+
1535
+ pub fn field_offset ( & self ,
1536
+ dl : & TargetDataLayout ,
1537
+ i : usize ,
1538
+ variant_index : Option < usize > )
1539
+ -> Size {
1540
+ match * self {
1541
+ Scalar { .. } |
1542
+ CEnum { .. } |
1543
+ UntaggedUnion { .. } |
1544
+ RawNullablePointer { .. } => {
1545
+ Size :: from_bytes ( 0 )
1546
+ }
1547
+
1548
+ Vector { element, count } => {
1549
+ let element_size = element. size ( dl) ;
1550
+ let i = i as u64 ;
1551
+ assert ! ( i < count) ;
1552
+ Size :: from_bytes ( element_size. bytes ( ) * count)
1553
+ }
1554
+
1555
+ Array { element_size, count, .. } => {
1556
+ let i = i as u64 ;
1557
+ assert ! ( i < count) ;
1558
+ Size :: from_bytes ( element_size. bytes ( ) * count)
1559
+ }
1560
+
1561
+ FatPointer { metadata, .. } => {
1562
+ // Effectively a (ptr, meta) tuple.
1563
+ assert ! ( i < 2 ) ;
1564
+ if i == 0 {
1565
+ Size :: from_bytes ( 0 )
1566
+ } else {
1567
+ Pointer . size ( dl) . abi_align ( metadata. align ( dl) )
1568
+ }
1569
+ }
1570
+
1571
+ Univariant { ref variant, .. } => variant. offsets [ i] ,
1572
+
1573
+ General { ref variants, .. } => {
1574
+ let v = variant_index. expect ( "variant index required" ) ;
1575
+ variants[ v] . offsets [ i + 1 ]
1576
+ }
1577
+
1578
+ StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => {
1579
+ if Some ( nndiscr as usize ) == variant_index {
1580
+ nonnull. offsets [ i]
1581
+ } else {
1582
+ Size :: from_bytes ( 0 )
1583
+ }
1584
+ }
1585
+ }
1586
+ }
1516
1587
}
1517
1588
1518
1589
/// Type size "skeleton", i.e. the only information determining a type's size.
@@ -1658,3 +1729,186 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
1658
1729
}
1659
1730
}
1660
1731
}
1732
+
1733
+ /// A pair of a type and its layout. Implements various
1734
+ /// type traversal APIs (e.g. recursing into fields).
1735
+ #[ derive( Copy , Clone , Debug ) ]
1736
+ pub struct TyLayout < ' tcx > {
1737
+ pub ty : Ty < ' tcx > ,
1738
+ pub layout : & ' tcx Layout ,
1739
+ pub variant_index : Option < usize > ,
1740
+ }
1741
+
1742
+ impl < ' tcx > Deref for TyLayout < ' tcx > {
1743
+ type Target = Layout ;
1744
+ fn deref ( & self ) -> & Layout {
1745
+ self . layout
1746
+ }
1747
+ }
1748
+
1749
+ impl < ' a , ' gcx , ' tcx > TyLayout < ' gcx > {
1750
+ pub fn of ( infcx : & InferCtxt < ' a , ' gcx , ' tcx > , ty : Ty < ' gcx > )
1751
+ -> Result < Self , LayoutError < ' gcx > > {
1752
+ let ty = normalize_associated_type ( infcx, ty) ;
1753
+
1754
+ Ok ( TyLayout {
1755
+ ty : ty,
1756
+ layout : ty. layout ( infcx) ?,
1757
+ variant_index : None
1758
+ } )
1759
+ }
1760
+
1761
+ pub fn for_variant ( & self , variant_index : usize ) -> Self {
1762
+ TyLayout {
1763
+ variant_index : Some ( variant_index) ,
1764
+ ..* self
1765
+ }
1766
+ }
1767
+
1768
+ pub fn field_offset ( & self , dl : & TargetDataLayout , i : usize ) -> Size {
1769
+ self . layout . field_offset ( dl, i, self . variant_index )
1770
+ }
1771
+
1772
+ pub fn field_count ( & self , tcx : TyCtxt < ' a , ' gcx , ' gcx > ) -> usize {
1773
+ let ptr_field_count = || {
1774
+ if let FatPointer { .. } = * self . layout {
1775
+ 2
1776
+ } else {
1777
+ bug ! ( "TyLayout::field_count({:?}): not applicable" , self )
1778
+ }
1779
+ } ;
1780
+
1781
+ match self . ty . sty {
1782
+ ty:: TyBool |
1783
+ ty:: TyChar |
1784
+ ty:: TyInt ( _) |
1785
+ ty:: TyUint ( _) |
1786
+ ty:: TyFloat ( _) |
1787
+ ty:: TyFnPtr ( _) |
1788
+ ty:: TyNever |
1789
+ ty:: TyFnDef ( ..) |
1790
+ ty:: TyDynamic ( ..) => {
1791
+ bug ! ( "TyLayout::field_type({:?}): not applicable" , self )
1792
+ }
1793
+
1794
+ // Potentially-fat pointers.
1795
+ ty:: TyRef ( ..) |
1796
+ ty:: TyRawPtr ( _) => {
1797
+ ptr_field_count ( )
1798
+ }
1799
+ ty:: TyAdt ( def, _) if def. is_box ( ) => {
1800
+ ptr_field_count ( )
1801
+ }
1802
+
1803
+ // Arrays and slices.
1804
+ ty:: TyArray ( _, count) => count,
1805
+ ty:: TySlice ( _) |
1806
+ ty:: TyStr => 0 ,
1807
+
1808
+ // Tuples and closures.
1809
+ ty:: TyClosure ( def_id, ref substs) => {
1810
+ substs. upvar_tys ( def_id, tcx) . count ( )
1811
+ }
1812
+
1813
+ ty:: TyTuple ( tys, _) => tys. len ( ) ,
1814
+
1815
+ // ADTs.
1816
+ ty:: TyAdt ( def, _) => {
1817
+ let v = if def. is_enum ( ) {
1818
+ self . variant_index . expect ( "variant index required" )
1819
+ } else {
1820
+ assert_eq ! ( self . variant_index, None ) ;
1821
+ 0
1822
+ } ;
1823
+
1824
+ def. variants [ v] . fields . len ( )
1825
+ }
1826
+
1827
+ ty:: TyProjection ( _) | ty:: TyAnon ( ..) | ty:: TyParam ( _) |
1828
+ ty:: TyInfer ( _) | ty:: TyError => {
1829
+ bug ! ( "TyLayout::field_count: unexpected type `{}`" , self . ty)
1830
+ }
1831
+ }
1832
+ }
1833
+
1834
+ pub fn field_type ( & self , tcx : TyCtxt < ' a , ' gcx , ' gcx > , i : usize ) -> Ty < ' gcx > {
1835
+ let ptr_field_type = |pointee : Ty < ' gcx > | {
1836
+ let slice = |element : Ty < ' gcx > | {
1837
+ assert ! ( i < 2 ) ;
1838
+ if i == 0 {
1839
+ tcx. mk_mut_ptr ( element)
1840
+ } else {
1841
+ tcx. types . usize
1842
+ }
1843
+ } ;
1844
+ match tcx. struct_tail ( pointee) . sty {
1845
+ ty:: TySlice ( element) => slice ( element) ,
1846
+ ty:: TyStr => slice ( tcx. types . u8 ) ,
1847
+ ty:: TyDynamic ( ..) => tcx. mk_mut_ptr ( tcx. mk_nil ( ) ) ,
1848
+ _ => bug ! ( "TyLayout::field_type({:?}): not applicable" , self )
1849
+ }
1850
+ } ;
1851
+
1852
+ match self . ty . sty {
1853
+ ty:: TyBool |
1854
+ ty:: TyChar |
1855
+ ty:: TyInt ( _) |
1856
+ ty:: TyUint ( _) |
1857
+ ty:: TyFloat ( _) |
1858
+ ty:: TyFnPtr ( _) |
1859
+ ty:: TyNever |
1860
+ ty:: TyFnDef ( ..) |
1861
+ ty:: TyDynamic ( ..) => {
1862
+ bug ! ( "TyLayout::field_type({:?}): not applicable" , self )
1863
+ }
1864
+
1865
+ // Potentially-fat pointers.
1866
+ ty:: TyRef ( _, ty:: TypeAndMut { ty : pointee, .. } ) |
1867
+ ty:: TyRawPtr ( ty:: TypeAndMut { ty : pointee, .. } ) => {
1868
+ ptr_field_type ( pointee)
1869
+ }
1870
+ ty:: TyAdt ( def, _) if def. is_box ( ) => {
1871
+ ptr_field_type ( self . ty . boxed_ty ( ) )
1872
+ }
1873
+
1874
+ // Arrays and slices.
1875
+ ty:: TyArray ( element, _) |
1876
+ ty:: TySlice ( element) => element,
1877
+ ty:: TyStr => tcx. types . u8 ,
1878
+
1879
+ // Tuples and closures.
1880
+ ty:: TyClosure ( def_id, ref substs) => {
1881
+ substs. upvar_tys ( def_id, tcx) . nth ( i) . unwrap ( )
1882
+ }
1883
+
1884
+ ty:: TyTuple ( tys, _) => tys[ i] ,
1885
+
1886
+ // SIMD vector types.
1887
+ ty:: TyAdt ( def, ..) if def. repr . simd => {
1888
+ self . ty . simd_type ( tcx)
1889
+ }
1890
+
1891
+ // ADTs.
1892
+ ty:: TyAdt ( def, substs) => {
1893
+ let v = if def. is_enum ( ) {
1894
+ self . variant_index . expect ( "variant index required" )
1895
+ } else {
1896
+ assert_eq ! ( self . variant_index, None ) ;
1897
+ 0
1898
+ } ;
1899
+
1900
+ def. variants [ v] . fields [ i] . ty ( tcx, substs)
1901
+ }
1902
+
1903
+ ty:: TyProjection ( _) | ty:: TyAnon ( ..) | ty:: TyParam ( _) |
1904
+ ty:: TyInfer ( _) | ty:: TyError => {
1905
+ bug ! ( "TyLayout::field_type: unexpected type `{}`" , self . ty)
1906
+ }
1907
+ }
1908
+ }
1909
+
1910
+ pub fn field ( & self , infcx : & InferCtxt < ' a , ' gcx , ' tcx > , i : usize )
1911
+ -> Result < Self , LayoutError < ' gcx > > {
1912
+ TyLayout :: of ( infcx, self . field_type ( infcx. tcx . global_tcx ( ) , i) )
1913
+ }
1914
+ }
0 commit comments