@@ -6,11 +6,13 @@ extern crate syn;
66#[ macro_use]
77extern crate quote;
88extern crate proc_macro;
9+ extern crate proc_macro2;
910
1011use syn:: { Visibility , Ident , Type , Expr } ;
1112use syn:: synom:: Synom ;
1213use syn:: spanned:: Spanned ;
1314use proc_macro:: TokenStream ;
15+ use proc_macro2:: Span ;
1416
1517/// Parses the following syntax, which aligns with the input of the real
1618/// `lazy_static` crate.
@@ -49,13 +51,28 @@ impl Synom for LazyStatic {
4951#[ proc_macro]
5052pub fn lazy_static ( input : TokenStream ) -> TokenStream {
5153 let LazyStatic { visibility, name, ty, init } = syn:: parse ( input) . unwrap ( ) ;
54+ let def_site = Span :: def_site ( ) ;
5255
56+ // The warning looks like this.
57+ //
58+ // warning: come on, pick a more creative name
59+ // --> src/main.rs:10:16
60+ // |
61+ // 10 | static ref FOO: String = "lazy_static".to_owned();
62+ // | ^^^
5363 if name == "FOO" {
5464 name. span ( ) . unstable ( )
5565 . warning ( "come on, pick a more creative name" )
5666 . emit ( ) ;
5767 }
5868
69+ // The error looks like this.
70+ //
71+ // error: I can't think of a legitimate use for lazily initializing the value `()`
72+ // --> src/main.rs:10:27
73+ // |
74+ // 10 | static ref UNIT: () = ();
75+ // | ^^
5976 if let Expr :: Tuple ( ref init) = init {
6077 if init. elems . is_empty ( ) {
6178 init. span ( ) . unstable ( )
@@ -65,14 +82,38 @@ pub fn lazy_static(input: TokenStream) -> TokenStream {
6582 }
6683 }
6784
68- // FIXME: ty.span().resolved_at(def_site)
69- let ty_span = ty. span ( ) ;
85+ // Assert that the static type implements Sync. If not, user sees an error
86+ // message like the following. We span this assertion with the field type's
87+ // line/column so that the error message appears in the correct place, but
88+ // resolve it at the def site so that we are guaranteed it is checking the
89+ // correct Sync. If the `Sync` token were resolved at the call site, the
90+ // user could circumvent the check by defining their own Sync trait that is
91+ // implemented for their type.
92+ //
93+ // error[E0277]: the trait bound `*const (): std::marker::Sync` is not satisfied
94+ // --> src/main.rs:10:21
95+ // |
96+ // 10 | static ref PTR: *const () = &();
97+ // | ^^^^^^^^^ `*const ()` cannot be shared between threads safely
98+ let ty_span = ty. span ( ) . resolved_at ( def_site) ;
7099 let assert_sync = quote_spanned ! { ty_span,
71- struct _Assert where #ty: Sync ;
100+ struct _AssertSync where #ty: Sync ;
72101 } ;
73102
74- // FIXME: init.span().resolved_at(def_site)
75- let init_span = init. span ( ) ;
103+ // Check for Sized. Not vital to check here, but the error message is less
104+ // confusing this way than if they get a Sized error in one of our
105+ // implementation details where it assumes Sized.
106+ //
107+ // error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
108+ // --> src/main.rs:10:19
109+ // |
110+ // 10 | static ref A: str = "";
111+ // | ^^^ `str` does not have a constant size known at compile-time
112+ let assert_sized = quote_spanned ! { ty_span,
113+ struct _AssertSized where #ty: Sized ;
114+ } ;
115+
116+ let init_span = init. span ( ) . resolved_at ( def_site) ;
76117 let init_ptr = quote_spanned ! { init_span,
77118 Box :: into_raw( Box :: new( #init) )
78119 } ;
@@ -87,9 +128,10 @@ pub fn lazy_static(input: TokenStream) -> TokenStream {
87128
88129 fn deref( & self ) -> & #ty {
89130 #assert_sync
131+ #assert_sized
90132
91133 static ONCE : std:: sync:: Once = std:: sync:: ONCE_INIT ;
92- static mut VALUE : * const #ty = 0 as * const #ty;
134+ static mut VALUE : * mut #ty = 0 as * mut #ty;
93135
94136 unsafe {
95137 ONCE . call_once( || VALUE = #init_ptr) ;
@@ -98,6 +140,6 @@ pub fn lazy_static(input: TokenStream) -> TokenStream {
98140 }
99141 }
100142 } ;
101-
143+
102144 expanded. into ( )
103145}
0 commit comments