@@ -1244,7 +1244,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
1244
1244
Lrc :: new ( StableVec :: new ( v) ) ) ;
1245
1245
}
1246
1246
1247
- tls :: enter_global ( GlobalCtxt {
1247
+ let gcx = & GlobalCtxt {
1248
1248
sess : s,
1249
1249
cstore,
1250
1250
global_arenas : & arenas. global ,
@@ -1285,7 +1285,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
1285
1285
all_traits : RefCell :: new ( None ) ,
1286
1286
tx_to_llvm_workers : tx,
1287
1287
output_filenames : Arc :: new ( output_filenames. clone ( ) ) ,
1288
- } , f)
1288
+ } ;
1289
+
1290
+ tls:: enter_global ( gcx, f)
1289
1291
}
1290
1292
1291
1293
pub fn consider_optimizing < T : Fn ( ) -> String > ( & self , msg : T ) -> bool {
@@ -1509,11 +1511,28 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
1509
1511
1510
1512
impl < ' gcx : ' tcx , ' tcx > GlobalCtxt < ' gcx > {
1511
1513
/// Call the closure with a local `TyCtxt` using the given arena.
1512
- pub fn enter_local < F , R > ( & self , arena : & ' tcx DroplessArena , f : F ) -> R
1513
- where F : for < ' a > FnOnce ( TyCtxt < ' a , ' gcx , ' tcx > ) -> R
1514
+ pub fn enter_local < F , R > (
1515
+ & self ,
1516
+ arena : & ' tcx DroplessArena ,
1517
+ f : F
1518
+ ) -> R
1519
+ where
1520
+ F : for < ' a > FnOnce ( TyCtxt < ' a , ' gcx , ' tcx > ) -> R
1514
1521
{
1515
1522
let interners = CtxtInterners :: new ( arena) ;
1516
- tls:: enter ( self , & interners, f)
1523
+ let tcx = TyCtxt {
1524
+ gcx : self ,
1525
+ interners : & interners,
1526
+ } ;
1527
+ ty:: tls:: with_related_context ( tcx. global_tcx ( ) , |icx| {
1528
+ let new_icx = ty:: tls:: ImplicitCtxt {
1529
+ tcx,
1530
+ query : icx. query . clone ( ) ,
1531
+ } ;
1532
+ ty:: tls:: enter_context ( & new_icx, |new_icx| {
1533
+ f ( new_icx. tcx )
1534
+ } )
1535
+ } )
1517
1536
}
1518
1537
}
1519
1538
@@ -1678,83 +1697,196 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Slice<CanonicalVarInfo> {
1678
1697
}
1679
1698
1680
1699
pub mod tls {
1681
- use super :: { CtxtInterners , GlobalCtxt , TyCtxt } ;
1700
+ use super :: { GlobalCtxt , TyCtxt } ;
1682
1701
1683
1702
use std:: cell:: Cell ;
1684
1703
use std:: fmt;
1704
+ use std:: mem;
1685
1705
use syntax_pos;
1706
+ use ty:: maps;
1707
+ use errors:: { Diagnostic , TRACK_DIAGNOSTICS } ;
1708
+ use rustc_data_structures:: OnDrop ;
1709
+ use rustc_data_structures:: sync:: Lrc ;
1686
1710
1687
- /// Marker types used for the scoped TLS slot.
1688
- /// The type context cannot be used directly because the scoped TLS
1689
- /// in libstd doesn't allow types generic over lifetimes.
1690
- enum ThreadLocalGlobalCtxt { }
1691
- enum ThreadLocalInterners { }
1711
+ /// This is the implicit state of rustc. It contains the current
1712
+ /// TyCtxt and query. It is updated when creating a local interner or
1713
+ /// executing a new query. Whenever there's a TyCtxt value available
1714
+ /// you should also have access to an ImplicitCtxt through the functions
1715
+ /// in this module.
1716
+ #[ derive( Clone ) ]
1717
+ pub struct ImplicitCtxt < ' a , ' gcx : ' a +' tcx , ' tcx : ' a > {
1718
+ /// The current TyCtxt. Initially created by `enter_global` and updated
1719
+ /// by `enter_local` with a new local interner
1720
+ pub tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
1692
1721
1693
- thread_local ! {
1694
- static TLS_TCX : Cell < Option < ( * const ThreadLocalGlobalCtxt ,
1695
- * const ThreadLocalInterners ) >> = Cell :: new ( None )
1722
+ /// The current query job, if any. This is updated by start_job in
1723
+ /// ty::maps::plumbing when executing a query
1724
+ pub query : Option < Lrc < maps :: QueryJob < ' gcx > > > ,
1696
1725
}
1697
1726
1727
+ // A thread local value which stores a pointer to the current ImplicitCtxt
1728
+ thread_local ! ( static TLV : Cell <usize > = Cell :: new( 0 ) ) ;
1729
+
1730
+ fn set_tlv < F : FnOnce ( ) -> R , R > ( value : usize , f : F ) -> R {
1731
+ let old = get_tlv ( ) ;
1732
+ let _reset = OnDrop ( move || TLV . with ( |tlv| tlv. set ( old) ) ) ;
1733
+ TLV . with ( |tlv| tlv. set ( value) ) ;
1734
+ f ( )
1735
+ }
1736
+
1737
+ fn get_tlv ( ) -> usize {
1738
+ TLV . with ( |tlv| tlv. get ( ) )
1739
+ }
1740
+
1741
+ /// This is a callback from libsyntax as it cannot access the implicit state
1742
+ /// in librustc otherwise
1698
1743
fn span_debug ( span : syntax_pos:: Span , f : & mut fmt:: Formatter ) -> fmt:: Result {
1699
1744
with ( |tcx| {
1700
1745
write ! ( f, "{}" , tcx. sess. codemap( ) . span_to_string( span) )
1701
1746
} )
1702
1747
}
1703
1748
1704
- pub fn enter_global < ' gcx , F , R > ( gcx : GlobalCtxt < ' gcx > , f : F ) -> R
1705
- where F : for < ' a > FnOnce ( TyCtxt < ' a , ' gcx , ' gcx > ) -> R
1749
+ /// This is a callback from libsyntax as it cannot access the implicit state
1750
+ /// in librustc otherwise. It is used to when diagnostic messages are
1751
+ /// emitted and stores them in the current query, if there is one.
1752
+ fn track_diagnostic ( diagnostic : & Diagnostic ) {
1753
+ with_context ( |context| {
1754
+ if let Some ( ref query) = context. query {
1755
+ query. diagnostics . lock ( ) . push ( diagnostic. clone ( ) ) ;
1756
+ }
1757
+ } )
1758
+ }
1759
+
1760
+ /// Sets up the callbacks from libsyntax on the current thread
1761
+ pub fn with_thread_locals < F , R > ( f : F ) -> R
1762
+ where F : FnOnce ( ) -> R
1706
1763
{
1707
1764
syntax_pos:: SPAN_DEBUG . with ( |span_dbg| {
1708
1765
let original_span_debug = span_dbg. get ( ) ;
1709
1766
span_dbg. set ( span_debug) ;
1710
- let result = enter ( & gcx, & gcx. global_interners , f) ;
1711
- span_dbg. set ( original_span_debug) ;
1712
- result
1767
+
1768
+ let _on_drop = OnDrop ( move || {
1769
+ span_dbg. set ( original_span_debug) ;
1770
+ } ) ;
1771
+
1772
+ TRACK_DIAGNOSTICS . with ( |current| {
1773
+ let original = current. get ( ) ;
1774
+ current. set ( track_diagnostic) ;
1775
+
1776
+ let _on_drop = OnDrop ( move || {
1777
+ current. set ( original) ;
1778
+ } ) ;
1779
+
1780
+ f ( )
1781
+ } )
1713
1782
} )
1714
1783
}
1715
1784
1716
- pub fn enter < ' a , ' gcx : ' tcx , ' tcx , F , R > ( gcx : & ' a GlobalCtxt < ' gcx > ,
1717
- interners : & ' a CtxtInterners < ' tcx > ,
1718
- f : F ) -> R
1719
- where F : FnOnce ( TyCtxt < ' a , ' gcx , ' tcx > ) -> R
1785
+ /// Sets `context` as the new current ImplicitCtxt for the duration of the function `f`
1786
+ pub fn enter_context < ' a , ' gcx : ' tcx , ' tcx , F , R > ( context : & ImplicitCtxt < ' a , ' gcx , ' tcx > ,
1787
+ f : F ) -> R
1788
+ where F : FnOnce ( & ImplicitCtxt < ' a , ' gcx , ' tcx > ) -> R
1720
1789
{
1721
- let gcx_ptr = gcx as * const _ as * const ThreadLocalGlobalCtxt ;
1722
- let interners_ptr = interners as * const _ as * const ThreadLocalInterners ;
1723
- TLS_TCX . with ( |tls| {
1724
- let prev = tls. get ( ) ;
1725
- tls. set ( Some ( ( gcx_ptr, interners_ptr) ) ) ;
1726
- let ret = f ( TyCtxt {
1727
- gcx,
1728
- interners,
1729
- } ) ;
1730
- tls. set ( prev) ;
1731
- ret
1790
+ set_tlv ( context as * const _ as usize , || {
1791
+ f ( & context)
1732
1792
} )
1733
1793
}
1734
1794
1735
- pub fn with < F , R > ( f : F ) -> R
1736
- where F : for <' a , ' gcx , ' tcx > FnOnce ( TyCtxt < ' a , ' gcx , ' tcx > ) -> R
1795
+ /// Enters GlobalCtxt by setting up libsyntax callbacks and
1796
+ /// creating a initial TyCtxt and ImplicitCtxt.
1797
+ /// This happens once per rustc session and TyCtxts only exists
1798
+ /// inside the `f` function.
1799
+ pub fn enter_global < ' gcx , F , R > ( gcx : & GlobalCtxt < ' gcx > , f : F ) -> R
1800
+ where F : for < ' a > FnOnce ( TyCtxt < ' a , ' gcx , ' gcx > ) -> R
1737
1801
{
1738
- TLS_TCX . with ( |tcx| {
1739
- let ( gcx, interners) = tcx. get ( ) . unwrap ( ) ;
1740
- let gcx = unsafe { & * ( gcx as * const GlobalCtxt ) } ;
1741
- let interners = unsafe { & * ( interners as * const CtxtInterners ) } ;
1742
- f ( TyCtxt {
1802
+ with_thread_locals ( || {
1803
+ let tcx = TyCtxt {
1743
1804
gcx,
1744
- interners,
1805
+ interners : & gcx. global_interners ,
1806
+ } ;
1807
+ let icx = ImplicitCtxt {
1808
+ tcx,
1809
+ query : None ,
1810
+ } ;
1811
+ enter_context ( & icx, |_| {
1812
+ f ( tcx)
1745
1813
} )
1746
1814
} )
1747
1815
}
1748
1816
1749
- pub fn with_opt < F , R > ( f : F ) -> R
1750
- where F : for <' a , ' gcx , ' tcx > FnOnce ( Option < TyCtxt < ' a , ' gcx , ' tcx > > ) -> R
1817
+ /// Allows access to the current ImplicitCtxt in a closure if one is available
1818
+ pub fn with_context_opt < F , R > ( f : F ) -> R
1819
+ where F : for <' a , ' gcx , ' tcx > FnOnce ( Option < & ImplicitCtxt < ' a , ' gcx , ' tcx > > ) -> R
1751
1820
{
1752
- if TLS_TCX . with ( |tcx| tcx. get ( ) . is_some ( ) ) {
1753
- with ( |v| f ( Some ( v) ) )
1754
- } else {
1821
+ let context = get_tlv ( ) ;
1822
+ if context == 0 {
1755
1823
f ( None )
1824
+ } else {
1825
+ unsafe { f ( Some ( & * ( context as * const ImplicitCtxt ) ) ) }
1756
1826
}
1757
1827
}
1828
+
1829
+ /// Allows access to the current ImplicitCtxt.
1830
+ /// Panics if there is no ImplicitCtxt available
1831
+ pub fn with_context < F , R > ( f : F ) -> R
1832
+ where F : for <' a , ' gcx , ' tcx > FnOnce ( & ImplicitCtxt < ' a , ' gcx , ' tcx > ) -> R
1833
+ {
1834
+ with_context_opt ( |opt_context| f ( opt_context. expect ( "no ImplicitCtxt stored in tls" ) ) )
1835
+ }
1836
+
1837
+ /// Allows access to the current ImplicitCtxt whose tcx field has the same global
1838
+ /// interner as the tcx argument passed in. This means the closure is given an ImplicitCtxt
1839
+ /// with the same 'gcx lifetime as the TyCtxt passed in.
1840
+ /// This will panic if you pass it a TyCtxt which has a different global interner from
1841
+ /// the current ImplicitCtxt's tcx field.
1842
+ pub fn with_related_context < ' a , ' gcx , ' tcx1 , F , R > ( tcx : TyCtxt < ' a , ' gcx , ' tcx1 > , f : F ) -> R
1843
+ where F : for <' b , ' tcx2 > FnOnce ( & ImplicitCtxt < ' b , ' gcx , ' tcx2 > ) -> R
1844
+ {
1845
+ with_context ( |context| {
1846
+ unsafe {
1847
+ let gcx = tcx. gcx as * const _ as usize ;
1848
+ assert ! ( context. tcx. gcx as * const _ as usize == gcx) ;
1849
+ let context: & ImplicitCtxt = mem:: transmute ( context) ;
1850
+ f ( context)
1851
+ }
1852
+ } )
1853
+ }
1854
+
1855
+ /// Allows access to the current ImplicitCtxt whose tcx field has the same global
1856
+ /// interner and local interner as the tcx argument passed in. This means the closure
1857
+ /// is given an ImplicitCtxt with the same 'tcx and 'gcx lifetimes as the TyCtxt passed in.
1858
+ /// This will panic if you pass it a TyCtxt which has a different global interner or
1859
+ /// a different local interner from the current ImplicitCtxt's tcx field.
1860
+ pub fn with_fully_related_context < ' a , ' gcx , ' tcx , F , R > ( tcx : TyCtxt < ' a , ' gcx , ' tcx > , f : F ) -> R
1861
+ where F : for < ' b > FnOnce ( & ImplicitCtxt < ' b , ' gcx , ' tcx > ) -> R
1862
+ {
1863
+ with_context ( |context| {
1864
+ unsafe {
1865
+ let gcx = tcx. gcx as * const _ as usize ;
1866
+ let interners = tcx. interners as * const _ as usize ;
1867
+ assert ! ( context. tcx. gcx as * const _ as usize == gcx) ;
1868
+ assert ! ( context. tcx. interners as * const _ as usize == interners) ;
1869
+ let context: & ImplicitCtxt = mem:: transmute ( context) ;
1870
+ f ( context)
1871
+ }
1872
+ } )
1873
+ }
1874
+
1875
+ /// Allows access to the TyCtxt in the current ImplicitCtxt.
1876
+ /// Panics if there is no ImplicitCtxt available
1877
+ pub fn with < F , R > ( f : F ) -> R
1878
+ where F : for <' a , ' gcx , ' tcx > FnOnce ( TyCtxt < ' a , ' gcx , ' tcx > ) -> R
1879
+ {
1880
+ with_context ( |context| f ( context. tcx ) )
1881
+ }
1882
+
1883
+ /// Allows access to the TyCtxt in the current ImplicitCtxt.
1884
+ /// The closure is passed None if there is no ImplicitCtxt available
1885
+ pub fn with_opt < F , R > ( f : F ) -> R
1886
+ where F : for <' a , ' gcx , ' tcx > FnOnce ( Option < TyCtxt < ' a , ' gcx , ' tcx > > ) -> R
1887
+ {
1888
+ with_context_opt ( |opt_context| f ( opt_context. map ( |context| context. tcx ) ) )
1889
+ }
1758
1890
}
1759
1891
1760
1892
macro_rules! sty_debug_print {
0 commit comments