@@ -12,6 +12,7 @@ use std::iter;
12
12
use std:: mem;
13
13
use std:: ops:: Bound ;
14
14
15
+ use crate :: hir;
15
16
use crate :: ich:: StableHashingContext ;
16
17
use rustc_data_structures:: indexed_vec:: { IndexVec , Idx } ;
17
18
use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher ,
@@ -1518,6 +1519,10 @@ pub trait HasTyCtxt<'tcx>: HasDataLayout {
1518
1519
fn tcx < ' a > ( & ' a self ) -> TyCtxt < ' a , ' tcx , ' tcx > ;
1519
1520
}
1520
1521
1522
+ pub trait HasParamEnv < ' tcx > {
1523
+ fn param_env ( & self ) -> ty:: ParamEnv < ' tcx > ;
1524
+ }
1525
+
1521
1526
impl < ' a , ' gcx , ' tcx > HasDataLayout for TyCtxt < ' a , ' gcx , ' tcx > {
1522
1527
fn data_layout ( & self ) -> & TargetDataLayout {
1523
1528
& self . data_layout
@@ -1530,6 +1535,12 @@ impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for TyCtxt<'a, 'gcx, 'tcx> {
1530
1535
}
1531
1536
}
1532
1537
1538
+ impl < ' tcx , C > HasParamEnv < ' tcx > for LayoutCx < ' tcx , C > {
1539
+ fn param_env ( & self ) -> ty:: ParamEnv < ' tcx > {
1540
+ self . param_env
1541
+ }
1542
+ }
1543
+
1533
1544
impl < ' tcx , T : HasDataLayout > HasDataLayout for LayoutCx < ' tcx , T > {
1534
1545
fn data_layout ( & self ) -> & TargetDataLayout {
1535
1546
self . tcx . data_layout ( )
@@ -1543,25 +1554,32 @@ impl<'gcx, 'tcx, T: HasTyCtxt<'gcx>> HasTyCtxt<'gcx> for LayoutCx<'tcx, T> {
1543
1554
}
1544
1555
1545
1556
pub trait MaybeResult < T > {
1546
- fn from_ok ( x : T ) -> Self ;
1547
- fn map_same < F : FnOnce ( T ) -> T > ( self , f : F ) -> Self ;
1557
+ type Error ;
1558
+
1559
+ fn from ( x : Result < T , Self :: Error > ) -> Self ;
1560
+ fn to_result ( self ) -> Result < T , Self :: Error > ;
1548
1561
}
1549
1562
1550
1563
impl < T > MaybeResult < T > for T {
1551
- fn from_ok ( x : T ) -> Self {
1564
+ type Error = !;
1565
+
1566
+ fn from ( x : Result < T , Self :: Error > ) -> Self {
1567
+ let Ok ( x) = x;
1552
1568
x
1553
1569
}
1554
- fn map_same < F : FnOnce ( T ) -> T > ( self , f : F ) -> Self {
1555
- f ( self )
1570
+ fn to_result ( self ) -> Result < T , Self :: Error > {
1571
+ Ok ( self )
1556
1572
}
1557
1573
}
1558
1574
1559
1575
impl < T , E > MaybeResult < T > for Result < T , E > {
1560
- fn from_ok ( x : T ) -> Self {
1561
- Ok ( x)
1576
+ type Error = E ;
1577
+
1578
+ fn from ( x : Result < T , Self :: Error > ) -> Self {
1579
+ x
1562
1580
}
1563
- fn map_same < F : FnOnce ( T ) -> T > ( self , f : F ) -> Self {
1564
- self . map ( f )
1581
+ fn to_result ( self ) -> Result < T , Self :: Error > {
1582
+ self
1565
1583
}
1566
1584
}
1567
1585
@@ -1656,18 +1674,18 @@ impl ty::query::TyCtxtAt<'a, 'tcx, '_> {
1656
1674
1657
1675
impl < ' a , ' tcx , C > TyLayoutMethods < ' tcx , C > for Ty < ' tcx >
1658
1676
where C : LayoutOf < Ty = Ty < ' tcx > > + HasTyCtxt < ' tcx > ,
1659
- C :: TyLayout : MaybeResult < TyLayout < ' tcx > >
1677
+ C :: TyLayout : MaybeResult < TyLayout < ' tcx > > ,
1678
+ C : HasParamEnv < ' tcx >
1660
1679
{
1661
1680
fn for_variant ( this : TyLayout < ' tcx > , cx : & C , variant_index : VariantIdx ) -> TyLayout < ' tcx > {
1662
1681
let details = match this. variants {
1663
1682
Variants :: Single { index } if index == variant_index => this. details ,
1664
1683
1665
1684
Variants :: Single { index } => {
1666
1685
// Deny calling for_variant more than once for non-Single enums.
1667
- cx. layout_of ( this. ty ) . map_same ( |layout| {
1686
+ if let Ok ( layout ) = cx. layout_of ( this. ty ) . to_result ( ) {
1668
1687
assert_eq ! ( layout. variants, Variants :: Single { index } ) ;
1669
- layout
1670
- } ) ;
1688
+ }
1671
1689
1672
1690
let fields = match this. ty . sty {
1673
1691
ty:: Adt ( def, _) => def. variants [ variant_index] . fields . len ( ) ,
@@ -1700,10 +1718,10 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx>
1700
1718
let tcx = cx. tcx ( ) ;
1701
1719
let discr_layout = |discr : & Scalar | -> C :: TyLayout {
1702
1720
let layout = LayoutDetails :: scalar ( cx, discr. clone ( ) ) ;
1703
- MaybeResult :: from_ok ( TyLayout {
1721
+ MaybeResult :: from ( Ok ( TyLayout {
1704
1722
details : tcx. intern_layout ( layout) ,
1705
- ty : discr. value . to_ty ( tcx)
1706
- } )
1723
+ ty : discr. value . to_ty ( tcx) ,
1724
+ } ) )
1707
1725
} ;
1708
1726
1709
1727
cx. layout_of ( match this. ty . sty {
@@ -1737,10 +1755,10 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx>
1737
1755
} else {
1738
1756
tcx. mk_mut_ref ( tcx. lifetimes . re_static , nil)
1739
1757
} ;
1740
- return cx. layout_of ( ptr_ty) . map_same ( |mut ptr_layout| {
1758
+ return MaybeResult :: from ( cx. layout_of ( ptr_ty) . to_result ( ) . map ( |mut ptr_layout| {
1741
1759
ptr_layout. ty = this. ty ;
1742
1760
ptr_layout
1743
- } ) ;
1761
+ } ) ) ;
1744
1762
}
1745
1763
1746
1764
match tcx. struct_tail ( pointee) . sty {
@@ -1824,6 +1842,130 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx>
1824
1842
}
1825
1843
} )
1826
1844
}
1845
+
1846
+ fn pointee_info_at (
1847
+ this : TyLayout < ' tcx > ,
1848
+ cx : & C ,
1849
+ offset : Size ,
1850
+ ) -> Option < PointeeInfo > {
1851
+ match this. ty . sty {
1852
+ ty:: RawPtr ( mt) if offset. bytes ( ) == 0 => {
1853
+ cx. layout_of ( mt. ty ) . to_result ( ) . ok ( )
1854
+ . map ( |layout| PointeeInfo {
1855
+ size : layout. size ,
1856
+ align : layout. align . abi ,
1857
+ safe : None ,
1858
+ } )
1859
+ }
1860
+
1861
+ ty:: Ref ( _, ty, mt) if offset. bytes ( ) == 0 => {
1862
+ let tcx = cx. tcx ( ) ;
1863
+ let is_freeze = ty. is_freeze ( tcx, cx. param_env ( ) , DUMMY_SP ) ;
1864
+ let kind = match mt {
1865
+ hir:: MutImmutable => if is_freeze {
1866
+ PointerKind :: Frozen
1867
+ } else {
1868
+ PointerKind :: Shared
1869
+ } ,
1870
+ hir:: MutMutable => {
1871
+ // Previously we would only emit noalias annotations for LLVM >= 6 or in
1872
+ // panic=abort mode. That was deemed right, as prior versions had many bugs
1873
+ // in conjunction with unwinding, but later versions didn’t seem to have
1874
+ // said issues. See issue #31681.
1875
+ //
1876
+ // Alas, later on we encountered a case where noalias would generate wrong
1877
+ // code altogether even with recent versions of LLVM in *safe* code with no
1878
+ // unwinding involved. See #54462.
1879
+ //
1880
+ // For now, do not enable mutable_noalias by default at all, while the
1881
+ // issue is being figured out.
1882
+ let mutable_noalias = tcx. sess . opts . debugging_opts . mutable_noalias
1883
+ . unwrap_or ( false ) ;
1884
+ if mutable_noalias {
1885
+ PointerKind :: UniqueBorrowed
1886
+ } else {
1887
+ PointerKind :: Shared
1888
+ }
1889
+ }
1890
+ } ;
1891
+
1892
+ cx. layout_of ( ty) . to_result ( ) . ok ( )
1893
+ . map ( |layout| PointeeInfo {
1894
+ size : layout. size ,
1895
+ align : layout. align . abi ,
1896
+ safe : Some ( kind) ,
1897
+ } )
1898
+ }
1899
+
1900
+ _ => {
1901
+ let mut data_variant = match this. variants {
1902
+ // Within the discriminant field, only the niche itself is
1903
+ // always initialized, so we only check for a pointer at its
1904
+ // offset.
1905
+ //
1906
+ // If the niche is a pointer, it's either valid (according
1907
+ // to its type), or null (which the niche field's scalar
1908
+ // validity range encodes). This allows using
1909
+ // `dereferenceable_or_null` for e.g., `Option<&T>`, and
1910
+ // this will continue to work as long as we don't start
1911
+ // using more niches than just null (e.g., the first page of
1912
+ // the address space, or unaligned pointers).
1913
+ Variants :: Multiple {
1914
+ discr_kind : DiscriminantKind :: Niche {
1915
+ dataful_variant,
1916
+ ..
1917
+ } ,
1918
+ discr_index,
1919
+ ..
1920
+ } if this. fields . offset ( discr_index) == offset =>
1921
+ Some ( this. for_variant ( cx, dataful_variant) ) ,
1922
+ _ => Some ( this) ,
1923
+ } ;
1924
+
1925
+ if let Some ( variant) = data_variant {
1926
+ // We're not interested in any unions.
1927
+ if let FieldPlacement :: Union ( _) = variant. fields {
1928
+ data_variant = None ;
1929
+ }
1930
+ }
1931
+
1932
+ let mut result = None ;
1933
+
1934
+ if let Some ( variant) = data_variant {
1935
+ let ptr_end = offset + Pointer . size ( cx) ;
1936
+ for i in 0 ..variant. fields . count ( ) {
1937
+ let field_start = variant. fields . offset ( i) ;
1938
+ if field_start <= offset {
1939
+ let field = variant. field ( cx, i) ;
1940
+ result = field. to_result ( ) . ok ( )
1941
+ . and_then ( |field| {
1942
+ if ptr_end <= field_start + field. size {
1943
+ // We found the right field, look inside it.
1944
+ field. pointee_info_at ( cx, offset - field_start)
1945
+ } else {
1946
+ None
1947
+ }
1948
+ } ) ;
1949
+ if result. is_some ( ) {
1950
+ break ;
1951
+ }
1952
+ }
1953
+ }
1954
+ }
1955
+
1956
+ // FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`.
1957
+ if let Some ( ref mut pointee) = result {
1958
+ if let ty:: Adt ( def, _) = this. ty . sty {
1959
+ if def. is_box ( ) && offset. bytes ( ) == 0 {
1960
+ pointee. safe = Some ( PointerKind :: UniqueOwned ) ;
1961
+ }
1962
+ }
1963
+ }
1964
+
1965
+ result
1966
+ }
1967
+ }
1968
+ }
1827
1969
}
1828
1970
1829
1971
struct Niche {
0 commit comments