@@ -18,7 +18,7 @@ use rustc::hir::def_id::DefId;
18
18
use rustc:: infer:: TransNormalize ;
19
19
use rustc:: mir;
20
20
use rustc:: mir:: tcx:: LvalueTy ;
21
- use rustc:: ty:: { self , Ty , TyCtxt , TypeFoldable } ;
21
+ use rustc:: ty:: { self , layout , Ty , TyCtxt , TypeFoldable } ;
22
22
use rustc:: ty:: cast:: { CastTy , IntTy } ;
23
23
use rustc:: ty:: subst:: Substs ;
24
24
use rustc_data_structures:: indexed_vec:: { Idx , IndexVec } ;
@@ -27,7 +27,7 @@ use callee::Callee;
27
27
use builder:: Builder ;
28
28
use common:: { self , CrateContext , const_get_elt, val_ty} ;
29
29
use common:: { C_array , C_bool , C_bytes , C_floating_f64 , C_integral , C_big_integral } ;
30
- use common:: { C_null , C_struct , C_str_slice , C_undef , C_uint } ;
30
+ use common:: { C_null , C_struct , C_str_slice , C_undef , C_uint , C_vector , is_undef } ;
31
31
use common:: const_to_opt_u128;
32
32
use consts;
33
33
use monomorphize:: { self , Instance } ;
@@ -549,16 +549,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
549
549
mir:: AggregateKind :: Adt ( ..) |
550
550
mir:: AggregateKind :: Closure ( ..) |
551
551
mir:: AggregateKind :: Tuple => {
552
- let disr = match * kind {
553
- mir:: AggregateKind :: Adt ( adt_def, index, _, _) => {
554
- Disr :: from ( adt_def. variants [ index] . disr_val )
555
- }
556
- _ => Disr ( 0 )
557
- } ;
558
- Const :: new (
559
- adt:: trans_const ( self . ccx , dest_ty, disr, & fields) ,
560
- dest_ty
561
- )
552
+ Const :: new ( trans_const ( self . ccx , dest_ty, kind, & fields) , dest_ty)
562
553
}
563
554
}
564
555
}
@@ -946,3 +937,159 @@ pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId)
946
937
let instance = Instance :: mono ( ccx. shared ( ) , def_id) ;
947
938
MirConstContext :: trans_def ( ccx, instance, IndexVec :: new ( ) ) . map ( |c| c. llval )
948
939
}
940
+
941
+ /// Construct a constant value, suitable for initializing a
942
+ /// GlobalVariable, given a case and constant values for its fields.
943
+ /// Note that this may have a different LLVM type (and different
944
+ /// alignment!) from the representation's `type_of`, so it needs a
945
+ /// pointer cast before use.
946
+ ///
947
+ /// The LLVM type system does not directly support unions, and only
948
+ /// pointers can be bitcast, so a constant (and, by extension, the
949
+ /// GlobalVariable initialized by it) will have a type that can vary
950
+ /// depending on which case of an enum it is.
951
+ ///
952
+ /// To understand the alignment situation, consider `enum E { V64(u64),
953
+ /// V32(u32, u32) }` on Windows. The type has 8-byte alignment to
954
+ /// accommodate the u64, but `V32(x, y)` would have LLVM type `{i32,
955
+ /// i32, i32}`, which is 4-byte aligned.
956
+ ///
957
+ /// Currently the returned value has the same size as the type, but
958
+ /// this could be changed in the future to avoid allocating unnecessary
959
+ /// space after values of shorter-than-maximum cases.
960
+ fn trans_const < ' a , ' tcx > (
961
+ ccx : & CrateContext < ' a , ' tcx > ,
962
+ t : Ty < ' tcx > ,
963
+ kind : & mir:: AggregateKind ,
964
+ vals : & [ ValueRef ]
965
+ ) -> ValueRef {
966
+ let l = ccx. layout_of ( t) ;
967
+ let dl = & ccx. tcx ( ) . data_layout ;
968
+ let variant_index = match * kind {
969
+ mir:: AggregateKind :: Adt ( _, index, _, _) => index,
970
+ _ => 0 ,
971
+ } ;
972
+ match * l {
973
+ layout:: CEnum { discr : d, min, max, .. } => {
974
+ let discr = match * kind {
975
+ mir:: AggregateKind :: Adt ( adt_def, _, _, _) => {
976
+ Disr :: from ( adt_def. variants [ variant_index] . disr_val )
977
+ } ,
978
+ _ => Disr ( 0 ) ,
979
+ } ;
980
+ assert_eq ! ( vals. len( ) , 0 ) ;
981
+ adt:: assert_discr_in_range ( Disr ( min) , Disr ( max) , discr) ;
982
+ C_integral ( Type :: from_integer ( ccx, d) , discr. 0 , true )
983
+ }
984
+ layout:: General { discr : d, ref variants, .. } => {
985
+ let variant = & variants[ variant_index] ;
986
+ let lldiscr = C_integral ( Type :: from_integer ( ccx, d) , variant_index as u64 , true ) ;
987
+ let mut vals_with_discr = vec ! [ lldiscr] ;
988
+ vals_with_discr. extend_from_slice ( vals) ;
989
+ let mut contents = build_const_struct ( ccx, & variant, & vals_with_discr[ ..] ) ;
990
+ let needed_padding = l. size ( dl) . bytes ( ) - variant. stride ( ) . bytes ( ) ;
991
+ if needed_padding > 0 {
992
+ contents. push ( padding ( ccx, needed_padding) ) ;
993
+ }
994
+ C_struct ( ccx, & contents[ ..] , false )
995
+ }
996
+ layout:: UntaggedUnion { ref variants, .. } => {
997
+ assert_eq ! ( variant_index, 0 ) ;
998
+ let contents = build_const_union ( ccx, variants, vals[ 0 ] ) ;
999
+ C_struct ( ccx, & contents, variants. packed )
1000
+ }
1001
+ layout:: Univariant { ref variant, .. } => {
1002
+ assert_eq ! ( variant_index, 0 ) ;
1003
+ let contents = build_const_struct ( ccx, & variant, vals) ;
1004
+ C_struct ( ccx, & contents[ ..] , variant. packed )
1005
+ }
1006
+ layout:: Vector { .. } => {
1007
+ C_vector ( vals)
1008
+ }
1009
+ layout:: RawNullablePointer { nndiscr, .. } => {
1010
+ let nnty = adt:: compute_fields ( ccx, t, nndiscr as usize , false ) [ 0 ] ;
1011
+ if variant_index as u64 == nndiscr {
1012
+ assert_eq ! ( vals. len( ) , 1 ) ;
1013
+ vals[ 0 ]
1014
+ } else {
1015
+ C_null ( type_of:: sizing_type_of ( ccx, nnty) )
1016
+ }
1017
+ }
1018
+ layout:: StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
1019
+ if variant_index as u64 == nndiscr {
1020
+ C_struct ( ccx, & build_const_struct ( ccx, & nonnull, vals) , false )
1021
+ } else {
1022
+ let fields = adt:: compute_fields ( ccx, t, nndiscr as usize , false ) ;
1023
+ let vals = fields. iter ( ) . map ( |& ty| {
1024
+ // Always use null even if it's not the `discrfield`th
1025
+ // field; see #8506.
1026
+ C_null ( type_of:: sizing_type_of ( ccx, ty) )
1027
+ } ) . collect :: < Vec < ValueRef > > ( ) ;
1028
+ C_struct ( ccx, & build_const_struct ( ccx, & nonnull, & vals[ ..] ) , false )
1029
+ }
1030
+ }
1031
+ _ => bug ! ( "trans_const: cannot handle type {} repreented as {:#?}" , t, l)
1032
+ }
1033
+ }
1034
+
1035
+ /// Building structs is a little complicated, because we might need to
1036
+ /// insert padding if a field's value is less aligned than its type.
1037
+ ///
1038
+ /// Continuing the example from `trans_const`, a value of type `(u32,
1039
+ /// E)` should have the `E` at offset 8, but if that field's
1040
+ /// initializer is 4-byte aligned then simply translating the tuple as
1041
+ /// a two-element struct will locate it at offset 4, and accesses to it
1042
+ /// will read the wrong memory.
1043
+ fn build_const_struct < ' a , ' tcx > ( ccx : & CrateContext < ' a , ' tcx > ,
1044
+ st : & layout:: Struct ,
1045
+ vals : & [ ValueRef ] )
1046
+ -> Vec < ValueRef > {
1047
+ assert_eq ! ( vals. len( ) , st. offsets. len( ) ) ;
1048
+
1049
+ if vals. len ( ) == 0 {
1050
+ return Vec :: new ( ) ;
1051
+ }
1052
+
1053
+ // offset of current value
1054
+ let mut offset = 0 ;
1055
+ let mut cfields = Vec :: new ( ) ;
1056
+ cfields. reserve ( st. offsets . len ( ) * 2 ) ;
1057
+
1058
+ let parts = st. field_index_by_increasing_offset ( ) . map ( |i| {
1059
+ ( & vals[ i] , st. offsets [ i] . bytes ( ) )
1060
+ } ) ;
1061
+ for ( & val, target_offset) in parts {
1062
+ if offset < target_offset {
1063
+ cfields. push ( padding ( ccx, target_offset - offset) ) ;
1064
+ offset = target_offset;
1065
+ }
1066
+ assert ! ( !is_undef( val) ) ;
1067
+ cfields. push ( val) ;
1068
+ offset += machine:: llsize_of_alloc ( ccx, val_ty ( val) ) ;
1069
+ }
1070
+
1071
+ if offset < st. stride ( ) . bytes ( ) {
1072
+ cfields. push ( padding ( ccx, st. stride ( ) . bytes ( ) - offset) ) ;
1073
+ }
1074
+
1075
+ cfields
1076
+ }
1077
+
1078
+ fn build_const_union < ' a , ' tcx > ( ccx : & CrateContext < ' a , ' tcx > ,
1079
+ un : & layout:: Union ,
1080
+ field_val : ValueRef )
1081
+ -> Vec < ValueRef > {
1082
+ let mut cfields = vec ! [ field_val] ;
1083
+
1084
+ let offset = machine:: llsize_of_alloc ( ccx, val_ty ( field_val) ) ;
1085
+ let size = un. stride ( ) . bytes ( ) ;
1086
+ if offset != size {
1087
+ cfields. push ( padding ( ccx, size - offset) ) ;
1088
+ }
1089
+
1090
+ cfields
1091
+ }
1092
+
1093
+ fn padding ( ccx : & CrateContext , size : u64 ) -> ValueRef {
1094
+ C_undef ( Type :: array ( & Type :: i8 ( ccx) , size) )
1095
+ }
0 commit comments