@@ -20,12 +20,14 @@ use monomorphize::MonoItem;
2020use common:: { CodegenCx , val_ty} ;
2121use declare;
2222use monomorphize:: Instance ;
23+ use syntax_pos:: Span ;
24+ use syntax_pos:: symbol:: LocalInternedString ;
2325use type_:: Type ;
2426use type_of:: LayoutLlvmExt ;
25- use rustc:: ty;
27+ use rustc:: ty:: { self , Ty } ;
2628use rustc:: ty:: layout:: { Align , LayoutOf } ;
2729
28- use rustc:: hir:: { self , CodegenFnAttrFlags } ;
30+ use rustc:: hir:: { self , CodegenFnAttrs , CodegenFnAttrFlags } ;
2931
3032use std:: ffi:: { CStr , CString } ;
3133
@@ -119,6 +121,8 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef {
119121 let ty = instance. ty ( cx. tcx ) ;
120122 let sym = cx. tcx . symbol_name ( instance) . as_str ( ) ;
121123
124+ debug ! ( "get_static: sym={} instance={:?}" , sym, instance) ;
125+
122126 let g = if let Some ( id) = cx. tcx . hir . as_local_node_id ( def_id) {
123127
124128 let llty = cx. layout_of ( ty) . llvm_type ( cx) ;
@@ -144,50 +148,15 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef {
144148 hir_map:: NodeForeignItem ( & hir:: ForeignItem {
145149 ref attrs, span, node : hir:: ForeignItemKind :: Static ( ..) , ..
146150 } ) => {
147- let g = if let Some ( linkage) = cx. tcx . codegen_fn_attrs ( def_id) . linkage {
148- // If this is a static with a linkage specified, then we need to handle
149- // it a little specially. The typesystem prevents things like &T and
150- // extern "C" fn() from being non-null, so we can't just declare a
151- // static and call it a day. Some linkages (like weak) will make it such
152- // that the static actually has a null value.
153- let llty2 = match ty. sty {
154- ty:: TyRawPtr ( ref mt) => cx. layout_of ( mt. ty ) . llvm_type ( cx) ,
155- _ => {
156- cx. sess ( ) . span_fatal ( span, "must have type `*const T` or `*mut T`" ) ;
157- }
158- } ;
159- unsafe {
160- // Declare a symbol `foo` with the desired linkage.
161- let g1 = declare:: declare_global ( cx, & sym, llty2) ;
162- llvm:: LLVMRustSetLinkage ( g1, base:: linkage_to_llvm ( linkage) ) ;
163-
164- // Declare an internal global `extern_with_linkage_foo` which
165- // is initialized with the address of `foo`. If `foo` is
166- // discarded during linking (for example, if `foo` has weak
167- // linkage and there are no definitions), then
168- // `extern_with_linkage_foo` will instead be initialized to
169- // zero.
170- let mut real_name = "_rust_extern_with_linkage_" . to_string ( ) ;
171- real_name. push_str ( & sym) ;
172- let g2 = declare:: define_global ( cx, & real_name, llty) . unwrap_or_else ( ||{
173- cx. sess ( ) . span_fatal ( span,
174- & format ! ( "symbol `{}` is already defined" , & sym) )
175- } ) ;
176- llvm:: LLVMRustSetLinkage ( g2, llvm:: Linkage :: InternalLinkage ) ;
177- llvm:: LLVMSetInitializer ( g2, g1) ;
178- g2
179- }
180- } else {
181- // Generate an external declaration.
182- declare:: declare_global ( cx, & sym, llty)
183- } ;
184-
185- ( g, attrs)
151+ let fn_attrs = cx. tcx . codegen_fn_attrs ( def_id) ;
152+ ( check_and_apply_linkage ( cx, & fn_attrs, ty, sym, Some ( span) ) , attrs)
186153 }
187154
188155 item => bug ! ( "get_static: expected static, found {:?}" , item)
189156 } ;
190157
158+ debug ! ( "get_static: sym={} attrs={:?}" , sym, attrs) ;
159+
191160 for attr in attrs {
192161 if attr. check_name ( "thread_local" ) {
193162 llvm:: set_thread_local_mode ( g, cx. tls_model ) ;
@@ -197,19 +166,21 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef {
197166 g
198167 } else {
199168 // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
200- // FIXME(nagisa): investigate whether it can be changed into define_global
201- let g = declare:: declare_global ( cx, & sym, cx. layout_of ( ty) . llvm_type ( cx) ) ;
169+ debug ! ( "get_static: sym={} item_attr={:?}" , sym, cx. tcx. item_attrs( def_id) ) ;
170+
171+ let attrs = cx. tcx . codegen_fn_attrs ( def_id) ;
172+ let g = check_and_apply_linkage ( cx, & attrs, ty, sym, None ) ;
173+
202174 // Thread-local statics in some other crate need to *always* be linked
203175 // against in a thread-local fashion, so we need to be sure to apply the
204176 // thread-local attribute locally if it was present remotely. If we
205177 // don't do this then linker errors can be generated where the linker
206178 // complains that one object files has a thread local version of the
207179 // symbol and another one doesn't.
208- for attr in cx. tcx . get_attrs ( def_id) . iter ( ) {
209- if attr. check_name ( "thread_local" ) {
210- llvm:: set_thread_local_mode ( g, cx. tls_model ) ;
211- }
180+ if attrs. flags . contains ( CodegenFnAttrFlags :: THREAD_LOCAL ) {
181+ llvm:: set_thread_local_mode ( g, cx. tls_model ) ;
212182 }
183+
213184 if cx. use_dll_storage_attrs && !cx. tcx . is_foreign_item ( def_id) {
214185 // This item is external but not foreign, i.e. it originates from an external Rust
215186 // crate. Since we don't know whether this crate will be linked dynamically or
@@ -242,6 +213,66 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef {
242213 g
243214}
244215
216+ fn check_and_apply_linkage < ' tcx > (
217+ cx : & CodegenCx < ' _ , ' tcx > ,
218+ attrs : & CodegenFnAttrs ,
219+ ty : Ty < ' tcx > ,
220+ sym : LocalInternedString ,
221+ span : Option < Span >
222+ ) -> ValueRef {
223+ let llty = cx. layout_of ( ty) . llvm_type ( cx) ;
224+ if let Some ( linkage) = attrs. linkage {
225+ debug ! ( "get_static: sym={} linkage={:?}" , sym, linkage) ;
226+
227+ // If this is a static with a linkage specified, then we need to handle
228+ // it a little specially. The typesystem prevents things like &T and
229+ // extern "C" fn() from being non-null, so we can't just declare a
230+ // static and call it a day. Some linkages (like weak) will make it such
231+ // that the static actually has a null value.
232+ let llty2 = match ty. sty {
233+ ty:: TyRawPtr ( ref mt) => cx. layout_of ( mt. ty ) . llvm_type ( cx) ,
234+ _ => {
235+ if span. is_some ( ) {
236+ cx. sess ( ) . span_fatal ( span. unwrap ( ) , "must have type `*const T` or `*mut T`" )
237+ } else {
238+ bug ! ( "must have type `*const T` or `*mut T`" )
239+ }
240+ }
241+ } ;
242+ unsafe {
243+ // Declare a symbol `foo` with the desired linkage.
244+ let g1 = declare:: declare_global ( cx, & sym, llty2) ;
245+ llvm:: LLVMRustSetLinkage ( g1, base:: linkage_to_llvm ( linkage) ) ;
246+
247+ // Declare an internal global `extern_with_linkage_foo` which
248+ // is initialized with the address of `foo`. If `foo` is
249+ // discarded during linking (for example, if `foo` has weak
250+ // linkage and there are no definitions), then
251+ // `extern_with_linkage_foo` will instead be initialized to
252+ // zero.
253+ let mut real_name = "_rust_extern_with_linkage_" . to_string ( ) ;
254+ real_name. push_str ( & sym) ;
255+ let g2 = declare:: define_global ( cx, & real_name, llty) . unwrap_or_else ( ||{
256+ if span. is_some ( ) {
257+ cx. sess ( ) . span_fatal (
258+ span. unwrap ( ) ,
259+ & format ! ( "symbol `{}` is already defined" , & sym)
260+ )
261+ } else {
262+ bug ! ( "symbol `{}` is already defined" , & sym)
263+ }
264+ } ) ;
265+ llvm:: LLVMRustSetLinkage ( g2, llvm:: Linkage :: InternalLinkage ) ;
266+ llvm:: LLVMSetInitializer ( g2, g1) ;
267+ g2
268+ }
269+ } else {
270+ // Generate an external declaration.
271+ // FIXME(nagisa): investigate whether it can be changed into define_global
272+ declare:: declare_global ( cx, & sym, llty)
273+ }
274+ }
275+
245276pub fn codegen_static < ' a , ' tcx > (
246277 cx : & CodegenCx < ' a , ' tcx > ,
247278 def_id : DefId ,
0 commit comments