@@ -18,16 +18,19 @@ use middle::cstore::LOCAL_CRATE;
18
18
use middle:: const_eval:: { self , ConstEvalErr } ;
19
19
use middle:: def:: Def ;
20
20
use middle:: def_id:: DefId ;
21
+ use rustc:: front:: map as hir_map;
21
22
use trans:: { adt, closure, debuginfo, expr, inline, machine} ;
22
- use trans:: base:: { self , push_ctxt} ;
23
+ use trans:: base:: { self , exported_name , push_ctxt} ;
23
24
use trans:: callee:: Callee ;
24
25
use trans:: collector:: { self , TransItem } ;
25
26
use trans:: common:: { self , type_is_sized, ExprOrMethodCall , node_id_substs, C_nil , const_get_elt} ;
26
27
use trans:: common:: { CrateContext , C_integral , C_floating , C_bool , C_str_slice , C_bytes , val_ty} ;
27
28
use trans:: common:: { C_struct , C_undef , const_to_opt_int, const_to_opt_uint, VariantInfo , C_uint } ;
28
29
use trans:: common:: { type_is_fat_ptr, Field , C_vector , C_array , C_null , ExprId , MethodCallKey } ;
30
+ use trans:: datum:: { Datum , Lvalue } ;
29
31
use trans:: declare;
30
32
use trans:: monomorphize;
33
+ use trans:: foreign;
31
34
use trans:: type_:: Type ;
32
35
use trans:: type_of;
33
36
use trans:: value:: Value ;
@@ -46,7 +49,7 @@ use std::ffi::{CStr, CString};
46
49
use std:: borrow:: Cow ;
47
50
use libc:: c_uint;
48
51
use syntax:: ast:: { self , LitKind } ;
49
- use syntax:: attr;
52
+ use syntax:: attr:: { self , AttrMetaMethods } ;
50
53
use syntax:: parse:: token;
51
54
use syntax:: ptr:: P ;
52
55
@@ -806,7 +809,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
806
809
}
807
810
let opt_def = cx. tcx ( ) . def_map . borrow ( ) . get ( & cur. id ) . map ( |d| d. full_def ( ) ) ;
808
811
if let Some ( Def :: Static ( def_id, _) ) = opt_def {
809
- common :: get_static_val ( cx, def_id, ety )
812
+ get_static ( cx, def_id) . val
810
813
} else {
811
814
// If this isn't the address of a static, then keep going through
812
815
// normal constant evaluation.
@@ -1013,6 +1016,65 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
1013
1016
} )
1014
1017
}
1015
1018
1019
+ pub fn get_static < ' a , ' tcx > ( ccx : & CrateContext < ' a , ' tcx > , def_id : DefId )
1020
+ -> Datum < ' tcx , Lvalue > {
1021
+ let ty = ccx. tcx ( ) . lookup_item_type ( def_id) . ty ;
1022
+
1023
+ let g = if let Some ( id) = ccx. tcx ( ) . map . as_local_node_id ( def_id) {
1024
+ match ccx. tcx ( ) . map . get ( id) {
1025
+ hir_map:: NodeItem ( & hir:: Item {
1026
+ ref attrs, span, node : hir:: ItemStatic ( ..) , ..
1027
+ } ) => {
1028
+ // If this static came from an external crate, then
1029
+ // we need to get the symbol from metadata instead of
1030
+ // using the current crate's name/version
1031
+ // information in the hash of the symbol
1032
+ let sym = exported_name ( ccx, id, ty, attrs) ;
1033
+ debug ! ( "making {}" , sym) ;
1034
+
1035
+ // Create the global before evaluating the initializer;
1036
+ // this is necessary to allow recursive statics.
1037
+ let llty = type_of:: type_of ( ccx, ty) ;
1038
+ let g = declare:: define_global ( ccx, & sym, llty) . unwrap_or_else ( || {
1039
+ ccx. sess ( ) . span_fatal ( span,
1040
+ & format ! ( "symbol `{}` is already defined" , sym) )
1041
+ } ) ;
1042
+
1043
+ ccx. item_symbols ( ) . borrow_mut ( ) . insert ( id, sym) ;
1044
+ g
1045
+ }
1046
+
1047
+ hir_map:: NodeForeignItem ( ni @ & hir:: ForeignItem {
1048
+ node : hir:: ForeignItemStatic ( ..) , ..
1049
+ } ) => foreign:: register_static ( ccx, ni) ,
1050
+
1051
+ item => unreachable ! ( "get_static: expected static, found {:?}" , item)
1052
+ }
1053
+ } else {
1054
+ // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
1055
+ // FIXME(nagisa): investigate whether it can be changed into define_global
1056
+ let name = ccx. sess ( ) . cstore . item_symbol ( def_id) ;
1057
+ let g = declare:: declare_global ( ccx, & name, type_of:: type_of ( ccx, ty) ) ;
1058
+ // Thread-local statics in some other crate need to *always* be linked
1059
+ // against in a thread-local fashion, so we need to be sure to apply the
1060
+ // thread-local attribute locally if it was present remotely. If we
1061
+ // don't do this then linker errors can be generated where the linker
1062
+ // complains that one object files has a thread local version of the
1063
+ // symbol and another one doesn't.
1064
+ for attr in ccx. tcx ( ) . get_attrs ( def_id) . iter ( ) {
1065
+ if attr. check_name ( "thread_local" ) {
1066
+ llvm:: set_thread_local ( g, true ) ;
1067
+ }
1068
+ }
1069
+ if ccx. use_dll_storage_attrs ( ) {
1070
+ llvm:: SetDLLStorageClass ( g, llvm:: DLLImportStorageClass ) ;
1071
+ }
1072
+ g
1073
+ } ;
1074
+
1075
+ Datum :: new ( g, ty, Lvalue :: new ( "static" ) )
1076
+ }
1077
+
1016
1078
pub fn trans_static ( ccx : & CrateContext ,
1017
1079
m : hir:: Mutability ,
1018
1080
expr : & hir:: Expr ,
@@ -1026,7 +1088,8 @@ pub fn trans_static(ccx: &CrateContext,
1026
1088
1027
1089
unsafe {
1028
1090
let _icx = push_ctxt ( "trans_static" ) ;
1029
- let g = base:: get_item_val ( ccx, id) ;
1091
+ let def_id = ccx. tcx ( ) . map . local_def_id ( id) ;
1092
+ let datum = get_static ( ccx, def_id) ;
1030
1093
1031
1094
let empty_substs = ccx. tcx ( ) . mk_substs ( Substs :: trans_empty ( ) ) ;
1032
1095
let ( v, _) = try!( const_expr (
@@ -1039,40 +1102,39 @@ pub fn trans_static(ccx: &CrateContext,
1039
1102
1040
1103
// boolean SSA values are i1, but they have to be stored in i8 slots,
1041
1104
// otherwise some LLVM optimization passes don't work as expected
1042
- let mut val_llty = llvm :: LLVMTypeOf ( v) ;
1043
- let v = if val_llty == Type :: i1 ( ccx) . to_ref ( ) {
1044
- val_llty = Type :: i8 ( ccx) . to_ref ( ) ;
1045
- llvm:: LLVMConstZExt ( v, val_llty)
1105
+ let mut val_llty = val_ty ( v) ;
1106
+ let v = if val_llty == Type :: i1 ( ccx) {
1107
+ val_llty = Type :: i8 ( ccx) ;
1108
+ llvm:: LLVMConstZExt ( v, val_llty. to_ref ( ) )
1046
1109
} else {
1047
1110
v
1048
1111
} ;
1049
1112
1050
- let ty = ccx. tcx ( ) . node_id_to_type ( id) ;
1051
- let llty = type_of:: type_of ( ccx, ty) ;
1052
- let g = if val_llty == llty. to_ref ( ) {
1053
- g
1113
+ let llty = type_of:: type_of ( ccx, datum. ty ) ;
1114
+ let g = if val_llty == llty {
1115
+ datum. val
1054
1116
} else {
1055
1117
// If we created the global with the wrong type,
1056
1118
// correct the type.
1057
1119
let empty_string = CString :: new ( "" ) . unwrap ( ) ;
1058
- let name_str_ref = CStr :: from_ptr ( llvm:: LLVMGetValueName ( g ) ) ;
1120
+ let name_str_ref = CStr :: from_ptr ( llvm:: LLVMGetValueName ( datum . val ) ) ;
1059
1121
let name_string = CString :: new ( name_str_ref. to_bytes ( ) ) . unwrap ( ) ;
1060
- llvm:: LLVMSetValueName ( g , empty_string. as_ptr ( ) ) ;
1122
+ llvm:: LLVMSetValueName ( datum . val , empty_string. as_ptr ( ) ) ;
1061
1123
let new_g = llvm:: LLVMGetOrInsertGlobal (
1062
- ccx. llmod ( ) , name_string. as_ptr ( ) , val_llty) ;
1124
+ ccx. llmod ( ) , name_string. as_ptr ( ) , val_llty. to_ref ( ) ) ;
1063
1125
// To avoid breaking any invariants, we leave around the old
1064
1126
// global for the moment; we'll replace all references to it
1065
1127
// with the new global later. (See base::trans_crate.)
1066
- ccx. statics_to_rauw ( ) . borrow_mut ( ) . push ( ( g , new_g) ) ;
1128
+ ccx. statics_to_rauw ( ) . borrow_mut ( ) . push ( ( datum . val , new_g) ) ;
1067
1129
new_g
1068
1130
} ;
1069
- llvm:: LLVMSetAlignment ( g, type_of:: align_of ( ccx, ty) ) ;
1131
+ llvm:: LLVMSetAlignment ( g, type_of:: align_of ( ccx, datum . ty ) ) ;
1070
1132
llvm:: LLVMSetInitializer ( g, v) ;
1071
1133
1072
1134
// As an optimization, all shared statics which do not have interior
1073
1135
// mutability are placed into read-only memory.
1074
1136
if m != hir:: MutMutable {
1075
- let tcontents = ty. type_contents ( ccx. tcx ( ) ) ;
1137
+ let tcontents = datum . ty . type_contents ( ccx. tcx ( ) ) ;
1076
1138
if !tcontents. interior_unsafe ( ) {
1077
1139
llvm:: LLVMSetGlobalConstant ( g, llvm:: True ) ;
1078
1140
}
0 commit comments