@@ -6,7 +6,7 @@ use rustc::traits::{self, ProjectionMode};
6
6
use rustc:: ty:: fold:: TypeFoldable ;
7
7
use rustc:: ty:: layout:: { self , Layout , Size } ;
8
8
use rustc:: ty:: subst:: { self , Subst , Substs } ;
9
- use rustc:: ty:: { self , TyCtxt } ;
9
+ use rustc:: ty:: { self , Ty , TyCtxt } ;
10
10
use rustc:: util:: nodemap:: DefIdMap ;
11
11
use std:: cell:: RefCell ;
12
12
use std:: ops:: { Deref , DerefMut } ;
@@ -413,7 +413,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
413
413
Ok ( target)
414
414
}
415
415
416
- fn drop ( & mut self , ptr : Pointer , ty : ty :: Ty < ' tcx > ) -> EvalResult < ( ) > {
416
+ fn drop ( & mut self , ptr : Pointer , ty : Ty < ' tcx > ) -> EvalResult < ( ) > {
417
417
if !self . type_needs_drop ( ty) {
418
418
self . log ( 1 , || print ! ( "no need to drop {:?}" , ty) ) ;
419
419
return Ok ( ( ) ) ;
@@ -455,7 +455,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
455
455
Ok ( ( ) )
456
456
}
457
457
458
- fn read_discriminant_value ( & self , adt_ptr : Pointer , adt_ty : ty :: Ty < ' tcx > ) -> EvalResult < u64 > {
458
+ fn read_discriminant_value ( & self , adt_ptr : Pointer , adt_ty : Ty < ' tcx > ) -> EvalResult < u64 > {
459
459
use rustc:: ty:: layout:: Layout :: * ;
460
460
let adt_layout = self . type_layout ( adt_ty) ;
461
461
@@ -466,16 +466,14 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
466
466
}
467
467
468
468
RawNullablePointer { nndiscr, .. } => {
469
- let not_null = match self . memory . read_usize ( adt_ptr) {
470
- Ok ( 0 ) => false ,
471
- Ok ( _) | Err ( EvalError :: ReadPointerAsBytes ) => true ,
472
- Err ( e) => return Err ( e) ,
473
- } ;
474
- assert ! ( nndiscr == 0 || nndiscr == 1 ) ;
475
- if not_null { nndiscr } else { 1 - nndiscr }
469
+ self . read_nonnull_discriminant_value ( adt_ptr, nndiscr) ?
476
470
}
477
471
478
- StructWrappedNullablePointer { .. } => unimplemented ! ( ) ,
472
+ StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
473
+ let offset = self . nonnull_offset ( adt_ty, nndiscr, discrfield) ;
474
+ let nonnull = adt_ptr. offset ( offset. bytes ( ) as isize ) ;
475
+ self . read_nonnull_discriminant_value ( nonnull, nndiscr) ?
476
+ }
479
477
480
478
// The discriminant_value intrinsic returns 0 for non-sum types.
481
479
Array { .. } | FatPointer { .. } | Scalar { .. } | Univariant { .. } |
@@ -485,6 +483,16 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
485
483
Ok ( discr_val)
486
484
}
487
485
486
+ fn read_nonnull_discriminant_value ( & self , ptr : Pointer , nndiscr : u64 ) -> EvalResult < u64 > {
487
+ let not_null = match self . memory . read_usize ( ptr) {
488
+ Ok ( 0 ) => false ,
489
+ Ok ( _) | Err ( EvalError :: ReadPointerAsBytes ) => true ,
490
+ Err ( e) => return Err ( e) ,
491
+ } ;
492
+ assert ! ( nndiscr == 0 || nndiscr == 1 ) ;
493
+ Ok ( if not_null { nndiscr } else { 1 - nndiscr } )
494
+ }
495
+
488
496
fn call_intrinsic (
489
497
& mut self ,
490
498
name : & str ,
@@ -793,6 +801,23 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
793
801
}
794
802
}
795
803
804
+ StructWrappedNullablePointer { nndiscr, ref nonnull, ref discrfield } => {
805
+ if let mir:: AggregateKind :: Adt ( _, variant, _) = * kind {
806
+ if nndiscr == variant as u64 {
807
+ let offsets = iter:: once ( 0 )
808
+ . chain ( nonnull. offset_after_field . iter ( ) . map ( |s| s. bytes ( ) ) ) ;
809
+ try!( self . assign_fields ( dest, offsets, operands) ) ;
810
+ } else {
811
+ assert_eq ! ( operands. len( ) , 0 ) ;
812
+ let offset = self . nonnull_offset ( dest_ty, nndiscr, discrfield) ;
813
+ let dest = dest. offset ( offset. bytes ( ) as isize ) ;
814
+ try!( self . memory . write_isize ( dest, 0 ) ) ;
815
+ }
816
+ } else {
817
+ panic ! ( "tried to assign {:?} to Layout::RawNullablePointer" , kind) ;
818
+ }
819
+ }
820
+
796
821
CEnum { discr, signed, .. } => {
797
822
assert_eq ! ( operands. len( ) , 0 ) ;
798
823
if let mir:: AggregateKind :: Adt ( adt_def, variant, _) = * kind {
@@ -900,6 +925,73 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
900
925
Ok ( ( ) )
901
926
}
902
927
928
+ fn nonnull_offset ( & self , ty : Ty < ' tcx > , nndiscr : u64 , discrfield : & [ u32 ] ) -> Size {
929
+ // Skip the constant 0 at the start meant for LLVM GEP.
930
+ let mut path = discrfield. iter ( ) . skip ( 1 ) . map ( |& i| i as usize ) ;
931
+
932
+ // Handle the field index for the outer non-null variant.
933
+ let inner_ty = match ty. sty {
934
+ ty:: TyEnum ( adt_def, substs) => {
935
+ let variant = & adt_def. variants [ nndiscr as usize ] ;
936
+ let index = path. next ( ) . unwrap ( ) ;
937
+ let field = & variant. fields [ index] ;
938
+ field. ty ( self . tcx , substs)
939
+ }
940
+ _ => panic ! (
941
+ "non-enum for StructWrappedNullablePointer: {}" ,
942
+ ty,
943
+ ) ,
944
+ } ;
945
+
946
+ self . field_path_offset ( inner_ty, path)
947
+ }
948
+
949
+ fn field_path_offset < I : Iterator < Item = usize > > ( & self , mut ty : Ty < ' tcx > , path : I ) -> Size {
950
+ let mut offset = Size :: from_bytes ( 0 ) ;
951
+
952
+ // Skip the initial 0 intended for LLVM GEP.
953
+ for field_index in path {
954
+ let field_offset = self . get_field_offset ( ty, field_index) ;
955
+ ty = self . get_field_ty ( ty, field_index) ;
956
+ offset = offset. checked_add ( field_offset, & self . tcx . data_layout ) . unwrap ( ) ;
957
+ }
958
+
959
+ offset
960
+ }
961
+
962
+ fn get_field_ty ( & self , ty : Ty < ' tcx > , field_index : usize ) -> Ty < ' tcx > {
963
+ match ty. sty {
964
+ ty:: TyStruct ( adt_def, substs) => {
965
+ adt_def. struct_variant ( ) . fields [ field_index] . ty ( self . tcx , substs)
966
+ }
967
+
968
+ ty:: TyRef ( _, ty:: TypeAndMut { ty, .. } ) |
969
+ ty:: TyRawPtr ( ty:: TypeAndMut { ty, .. } ) |
970
+ ty:: TyBox ( ty) => {
971
+ assert_eq ! ( field_index, 0 ) ;
972
+ ty
973
+ }
974
+ _ => panic ! ( "can't handle type: {:?}" , ty) ,
975
+ }
976
+ }
977
+
978
+ fn get_field_offset ( & self , ty : Ty < ' tcx > , field_index : usize ) -> Size {
979
+ let layout = self . type_layout ( ty) ;
980
+
981
+ use rustc:: ty:: layout:: Layout :: * ;
982
+ match * layout {
983
+ Univariant { .. } => {
984
+ assert_eq ! ( field_index, 0 ) ;
985
+ Size :: from_bytes ( 0 )
986
+ }
987
+ FatPointer { .. } => {
988
+ let bytes = layout:: FAT_PTR_ADDR * self . memory . pointer_size ;
989
+ Size :: from_bytes ( bytes as u64 )
990
+ }
991
+ _ => panic ! ( "can't handle type: {:?}, with layout: {:?}" , ty, layout) ,
992
+ }
993
+ }
994
+
903
995
fn eval_operand ( & mut self , op : & mir:: Operand < ' tcx > ) -> EvalResult < Pointer > {
904
996
use rustc:: mir:: repr:: Operand :: * ;
905
997
match * op {
@@ -944,35 +1036,42 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
944
1036
use rustc:: mir:: repr:: ProjectionElem :: * ;
945
1037
match proj. elem {
946
1038
Field ( field, _) => {
1039
+ use rustc:: ty:: layout:: Layout :: * ;
947
1040
let variant = match * base_layout {
948
- Layout :: Univariant { ref variant, .. } => variant,
949
- Layout :: General { ref variants, .. } => {
1041
+ Univariant { ref variant, .. } => variant,
1042
+ General { ref variants, .. } => {
950
1043
if let LvalueExtra :: DowncastVariant ( variant_idx) = base. extra {
951
1044
& variants[ variant_idx]
952
1045
} else {
953
1046
panic ! ( "field access on enum had no variant index" ) ;
954
1047
}
955
1048
}
956
- Layout :: RawNullablePointer { .. } => {
1049
+ RawNullablePointer { .. } => {
957
1050
assert_eq ! ( field. index( ) , 0 ) ;
958
1051
return Ok ( base) ;
959
1052
}
1053
+ StructWrappedNullablePointer { ref nonnull, .. } => nonnull,
960
1054
_ => panic ! ( "field access on non-product type: {:?}" , base_layout) ,
961
1055
} ;
962
1056
963
1057
let offset = variant. field_offset ( field. index ( ) ) . bytes ( ) ;
964
1058
base. ptr . offset ( offset as isize )
965
1059
} ,
966
1060
967
- Downcast ( _, variant) => match * base_layout {
968
- Layout :: General { discr, .. } => {
969
- return Ok ( Lvalue {
970
- ptr : base. ptr . offset ( discr. size ( ) . bytes ( ) as isize ) ,
971
- extra : LvalueExtra :: DowncastVariant ( variant) ,
972
- } ) ;
1061
+ Downcast ( _, variant) => {
1062
+ use rustc:: ty:: layout:: Layout :: * ;
1063
+ match * base_layout {
1064
+ General { discr, .. } => {
1065
+ return Ok ( Lvalue {
1066
+ ptr : base. ptr . offset ( discr. size ( ) . bytes ( ) as isize ) ,
1067
+ extra : LvalueExtra :: DowncastVariant ( variant) ,
1068
+ } ) ;
1069
+ }
1070
+ RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
1071
+ return Ok ( base) ;
1072
+ }
1073
+ _ => panic ! ( "variant downcast on non-aggregate: {:?}" , base_layout) ,
973
1074
}
974
- Layout :: RawNullablePointer { .. } => return Ok ( base) ,
975
- _ => panic ! ( "variant downcast on non-aggregate type: {:?}" , base_layout) ,
976
1075
} ,
977
1076
978
1077
Deref => {
@@ -1052,24 +1151,24 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
1052
1151
}
1053
1152
}
1054
1153
1055
- fn lvalue_ty ( & self , lvalue : & mir:: Lvalue < ' tcx > ) -> ty :: Ty < ' tcx > {
1154
+ fn lvalue_ty ( & self , lvalue : & mir:: Lvalue < ' tcx > ) -> Ty < ' tcx > {
1056
1155
self . monomorphize ( self . mir ( ) . lvalue_ty ( self . tcx , lvalue) . to_ty ( self . tcx ) )
1057
1156
}
1058
1157
1059
- fn operand_ty ( & self , operand : & mir:: Operand < ' tcx > ) -> ty :: Ty < ' tcx > {
1158
+ fn operand_ty ( & self , operand : & mir:: Operand < ' tcx > ) -> Ty < ' tcx > {
1060
1159
self . monomorphize ( self . mir ( ) . operand_ty ( self . tcx , operand) )
1061
1160
}
1062
1161
1063
- fn monomorphize ( & self , ty : ty :: Ty < ' tcx > ) -> ty :: Ty < ' tcx > {
1162
+ fn monomorphize ( & self , ty : Ty < ' tcx > ) -> Ty < ' tcx > {
1064
1163
let substituted = ty. subst ( self . tcx , self . substs ( ) ) ;
1065
1164
self . tcx . normalize_associated_type ( & substituted)
1066
1165
}
1067
1166
1068
- fn type_needs_drop ( & self , ty : ty :: Ty < ' tcx > ) -> bool {
1167
+ fn type_needs_drop ( & self , ty : Ty < ' tcx > ) -> bool {
1069
1168
self . tcx . type_needs_drop_given_env ( ty, & self . tcx . empty_parameter_environment ( ) )
1070
1169
}
1071
1170
1072
- fn move_ ( & mut self , src : Pointer , dest : Pointer , ty : ty :: Ty < ' tcx > ) -> EvalResult < ( ) > {
1171
+ fn move_ ( & mut self , src : Pointer , dest : Pointer , ty : Ty < ' tcx > ) -> EvalResult < ( ) > {
1073
1172
let size = self . type_size ( ty) ;
1074
1173
self . memory . copy ( src, dest, size) ?;
1075
1174
if self . type_needs_drop ( ty) {
@@ -1078,15 +1177,15 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
1078
1177
Ok ( ( ) )
1079
1178
}
1080
1179
1081
- fn type_is_sized ( & self , ty : ty :: Ty < ' tcx > ) -> bool {
1180
+ fn type_is_sized ( & self , ty : Ty < ' tcx > ) -> bool {
1082
1181
ty. is_sized ( self . tcx , & self . tcx . empty_parameter_environment ( ) , DUMMY_SP )
1083
1182
}
1084
1183
1085
- fn type_size ( & self , ty : ty :: Ty < ' tcx > ) -> usize {
1184
+ fn type_size ( & self , ty : Ty < ' tcx > ) -> usize {
1086
1185
self . type_layout ( ty) . size ( & self . tcx . data_layout ) . bytes ( ) as usize
1087
1186
}
1088
1187
1089
- fn type_layout ( & self , ty : ty :: Ty < ' tcx > ) -> & ' tcx Layout {
1188
+ fn type_layout ( & self , ty : Ty < ' tcx > ) -> & ' tcx Layout {
1090
1189
// TODO(solson): Is this inefficient? Needs investigation.
1091
1190
let ty = self . monomorphize ( ty) ;
1092
1191
@@ -1096,7 +1195,7 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
1096
1195
} )
1097
1196
}
1098
1197
1099
- pub fn read_primval ( & mut self , ptr : Pointer , ty : ty :: Ty < ' tcx > ) -> EvalResult < PrimVal > {
1198
+ pub fn read_primval ( & mut self , ptr : Pointer , ty : Ty < ' tcx > ) -> EvalResult < PrimVal > {
1100
1199
use syntax:: ast:: { IntTy , UintTy } ;
1101
1200
let val = match ty. sty {
1102
1201
ty:: TyBool => PrimVal :: Bool ( self . memory . read_bool ( ptr) ?) ,
0 commit comments