@@ -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,35 @@ 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
+ // 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
+ }
1090
1099
Array {
1091
1100
sized : true ,
1092
1101
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
1095
1104
}
1096
1105
}
1097
1106
ty:: TySlice ( element) => {
1107
+ let element = element. layout ( infcx) ?;
1098
1108
Array {
1099
1109
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
1102
1113
}
1103
1114
}
1104
1115
ty:: TyStr => {
1105
1116
Array {
1106
1117
sized : false ,
1107
1118
align : dl. i8_align ,
1108
- size : Size :: from_bytes ( 0 )
1119
+ element_size : Size :: from_bytes ( 1 ) ,
1120
+ count : 0
1109
1121
}
1110
1122
}
1111
1123
@@ -1447,15 +1459,23 @@ impl<'a, 'gcx, 'tcx> Layout {
1447
1459
}
1448
1460
1449
1461
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) {
1452
1464
Some ( size) => size,
1453
1465
None => bug ! ( "Layout::size({:?}): {} * {} overflowed" ,
1454
- self , elem_size . bytes( ) , count)
1466
+ self , element_size . bytes( ) , count)
1455
1467
} ;
1456
1468
vec_size. abi_align ( self . align ( dl) )
1457
1469
}
1458
1470
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
+
1459
1479
FatPointer { metadata, .. } => {
1460
1480
// Effectively a (ptr, meta) tuple.
1461
1481
Pointer . size ( dl) . abi_align ( metadata. align ( dl) )
@@ -1464,7 +1484,7 @@ impl<'a, 'gcx, 'tcx> Layout {
1464
1484
}
1465
1485
1466
1486
CEnum { discr, .. } => Int ( discr) . size ( dl) ,
1467
- Array { size , .. } | General { size, .. } => size,
1487
+ General { size, .. } => size,
1468
1488
UntaggedUnion { ref variants } => variants. stride ( ) ,
1469
1489
1470
1490
Univariant { ref variant, .. } |
@@ -1513,6 +1533,59 @@ impl<'a, 'gcx, 'tcx> Layout {
1513
1533
}
1514
1534
}
1515
1535
}
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
+ }
1516
1589
}
1517
1590
1518
1591
/// Type size "skeleton", i.e. the only information determining a type's size.
@@ -1658,3 +1731,154 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
1658
1731
}
1659
1732
}
1660
1733
}
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