11use std:: fmt;
22use std:: iter;
33use std:: ops:: RangeBounds ;
4- use std:: panic:: { self , PanicInfo } ;
4+ use std:: panic;
55#[ cfg( super_unstable) ]
66use std:: path:: PathBuf ;
77use std:: str:: FromStr ;
88
9+ use crate :: detection:: inside_proc_macro;
910use crate :: { fallback, Delimiter , Punct , Spacing , TokenTree } ;
1011
1112#[ derive( Clone ) ]
@@ -29,63 +30,6 @@ pub(crate) enum LexError {
2930 Fallback ( fallback:: LexError ) ,
3031}
3132
32- fn inside_proc_macro ( ) -> bool {
33- use std:: sync:: atomic:: * ;
34- use std:: sync:: Once ;
35-
36- static WORKS : AtomicUsize = AtomicUsize :: new ( 0 ) ;
37- static INIT : Once = Once :: new ( ) ;
38-
39- match WORKS . load ( Ordering :: SeqCst ) {
40- 1 => return false ,
41- 2 => return true ,
42- _ => { }
43- }
44-
45- // Swap in a null panic hook to avoid printing "thread panicked" to stderr,
46- // then use catch_unwind to determine whether the compiler's proc_macro is
47- // working. When proc-macro2 is used from outside of a procedural macro all
48- // of the proc_macro crate's APIs currently panic.
49- //
50- // The Once is to prevent the possibility of this ordering:
51- //
52- // thread 1 calls take_hook, gets the user's original hook
53- // thread 1 calls set_hook with the null hook
54- // thread 2 calls take_hook, thinks null hook is the original hook
55- // thread 2 calls set_hook with the null hook
56- // thread 1 calls set_hook with the actual original hook
57- // thread 2 calls set_hook with what it thinks is the original hook
58- //
59- // in which the user's hook has been lost.
60- //
61- // There is still a race condition where a panic in a different thread can
62- // happen during the interval that the user's original panic hook is
63- // unregistered such that their hook is incorrectly not called. This is
64- // sufficiently unlikely and less bad than printing panic messages to stderr
65- // on correct use of this crate. Maybe there is a libstd feature request
66- // here. For now, if a user needs to guarantee that this failure mode does
67- // not occur, they need to call e.g. `proc_macro2::Span::call_site()` from
68- // the main thread before launching any other threads.
69- INIT . call_once ( || {
70- type PanicHook = dyn Fn ( & PanicInfo ) + Sync + Send + ' static ;
71-
72- let null_hook: Box < PanicHook > = Box :: new ( |_panic_info| { /* ignore */ } ) ;
73- let sanity_check = & * null_hook as * const PanicHook ;
74- let original_hook = panic:: take_hook ( ) ;
75- panic:: set_hook ( null_hook) ;
76-
77- let works = panic:: catch_unwind ( proc_macro:: Span :: call_site) . is_ok ( ) ;
78- WORKS . store ( works as usize + 1 , Ordering :: SeqCst ) ;
79-
80- let hopefully_null_hook = panic:: take_hook ( ) ;
81- panic:: set_hook ( original_hook) ;
82- if sanity_check != & * hopefully_null_hook {
83- panic ! ( "observed race condition in proc_macro2::inside_proc_macro" ) ;
84- }
85- } ) ;
86- inside_proc_macro ( )
87- }
88-
8933fn mismatch ( ) -> ! {
9034 panic ! ( "stable/nightly mismatch" )
9135}
0 commit comments