@@ -1244,7 +1244,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
12441244 Lrc :: new ( StableVec :: new ( v) ) ) ;
12451245 }
12461246
1247- tls :: enter_global ( GlobalCtxt {
1247+ let gcx = & GlobalCtxt {
12481248 sess : s,
12491249 cstore,
12501250 global_arenas : & arenas. global ,
@@ -1285,7 +1285,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
12851285 all_traits : RefCell :: new ( None ) ,
12861286 tx_to_llvm_workers : tx,
12871287 output_filenames : Arc :: new ( output_filenames. clone ( ) ) ,
1288- } , f)
1288+ } ;
1289+
1290+ tls:: enter_global ( gcx, f)
12891291 }
12901292
12911293 pub fn consider_optimizing < T : Fn ( ) -> String > ( & self , msg : T ) -> bool {
@@ -1509,11 +1511,28 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
15091511
15101512impl < ' gcx : ' tcx , ' tcx > GlobalCtxt < ' gcx > {
15111513 /// 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
15141521 {
15151522 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+ } )
15171536 }
15181537}
15191538
@@ -1678,83 +1697,196 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Slice<CanonicalVarInfo> {
16781697}
16791698
16801699pub mod tls {
1681- use super :: { CtxtInterners , GlobalCtxt , TyCtxt } ;
1700+ use super :: { GlobalCtxt , TyCtxt } ;
16821701
16831702 use std:: cell:: Cell ;
16841703 use std:: fmt;
1704+ use std:: mem;
16851705 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 ;
16861710
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 > ,
16921721
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 > > > ,
16961725 }
16971726
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
16981743 fn span_debug ( span : syntax_pos:: Span , f : & mut fmt:: Formatter ) -> fmt:: Result {
16991744 with ( |tcx| {
17001745 write ! ( f, "{}" , tcx. sess. codemap( ) . span_to_string( span) )
17011746 } )
17021747 }
17031748
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
17061763 {
17071764 syntax_pos:: SPAN_DEBUG . with ( |span_dbg| {
17081765 let original_span_debug = span_dbg. get ( ) ;
17091766 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+ } )
17131782 } )
17141783 }
17151784
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
17201789 {
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)
17321792 } )
17331793 }
17341794
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
17371801 {
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 {
17431804 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)
17451813 } )
17461814 } )
17471815 }
17481816
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
17511820 {
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 {
17551823 f ( None )
1824+ } else {
1825+ unsafe { f ( Some ( & * ( context as * const ImplicitCtxt ) ) ) }
17561826 }
17571827 }
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+ }
17581890}
17591891
17601892macro_rules! sty_debug_print {
0 commit comments