@@ -890,12 +890,15 @@ fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, st: &Struct<'tcx>,
890890///
891891/// This should ideally be less tightly tied to `_match`.
892892pub fn trans_switch < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > ,
893- r : & Repr < ' tcx > , scrutinee : ValueRef )
893+ r : & Repr < ' tcx > ,
894+ scrutinee : ValueRef ,
895+ range_assert : bool )
894896 -> ( _match:: BranchKind , Option < ValueRef > ) {
895897 match * r {
896898 CEnum ( ..) | General ( ..) |
897899 RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
898- ( _match:: Switch , Some ( trans_get_discr ( bcx, r, scrutinee, None ) ) )
900+ ( _match:: Switch , Some ( trans_get_discr ( bcx, r, scrutinee, None ,
901+ range_assert) ) )
899902 }
900903 Univariant ( ..) => {
901904 // N.B.: Univariant means <= 1 enum variants (*not* == 1 variants).
@@ -916,14 +919,18 @@ pub fn is_discr_signed<'tcx>(r: &Repr<'tcx>) -> bool {
916919
917920/// Obtain the actual discriminant of a value.
918921pub fn trans_get_discr < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > , r : & Repr < ' tcx > ,
919- scrutinee : ValueRef , cast_to : Option < Type > )
922+ scrutinee : ValueRef , cast_to : Option < Type > ,
923+ range_assert : bool )
920924 -> ValueRef {
921925 debug ! ( "trans_get_discr r: {:?}" , r) ;
922926 let val = match * r {
923- CEnum ( ity, min, max) => load_discr ( bcx, ity, scrutinee, min, max) ,
927+ CEnum ( ity, min, max) => {
928+ load_discr ( bcx, ity, scrutinee, min, max, range_assert)
929+ }
924930 General ( ity, ref cases, _) => {
925931 let ptr = StructGEP ( bcx, scrutinee, 0 ) ;
926- load_discr ( bcx, ity, ptr, Disr ( 0 ) , Disr ( cases. len ( ) as u64 - 1 ) )
932+ load_discr ( bcx, ity, ptr, Disr ( 0 ) , Disr ( cases. len ( ) as u64 - 1 ) ,
933+ range_assert)
927934 }
928935 Univariant ( ..) => C_u8 ( bcx. ccx ( ) , 0 ) ,
929936 RawNullablePointer { nndiscr, nnty, .. } => {
@@ -950,7 +957,8 @@ fn struct_wrapped_nullable_bitdiscr(bcx: Block, nndiscr: Disr, discrfield: &Disc
950957}
951958
952959/// Helper for cases where the discriminant is simply loaded.
953- fn load_discr ( bcx : Block , ity : IntType , ptr : ValueRef , min : Disr , max : Disr )
960+ fn load_discr ( bcx : Block , ity : IntType , ptr : ValueRef , min : Disr , max : Disr ,
961+ range_assert : bool )
954962 -> ValueRef {
955963 let llty = ll_inttype ( bcx. ccx ( ) , ity) ;
956964 assert_eq ! ( val_ty( ptr) , llty. ptr_to( ) ) ;
@@ -960,7 +968,7 @@ fn load_discr(bcx: Block, ity: IntType, ptr: ValueRef, min: Disr, max: Disr)
960968 let mask = Disr ( !0u64 >> ( 64 - bits) ) ;
961969 // For a (max) discr of -1, max will be `-1 as usize`, which overflows.
962970 // However, that is fine here (it would still represent the full range),
963- if max. wrapping_add ( Disr ( 1 ) ) & mask == min & mask {
971+ if max. wrapping_add ( Disr ( 1 ) ) & mask == min & mask || !range_assert {
964972 // i.e., if the range is everything. The lo==hi case would be
965973 // rejected by the LLVM verifier (it would mean either an
966974 // empty set, which is impossible, or the entire range of the
@@ -1239,10 +1247,14 @@ pub fn fold_variants<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
12391247 // runtime, so the basic block isn't actually unreachable, so we
12401248 // need to make it do something with defined behavior. In this case
12411249 // we just return early from the function.
1250+ //
1251+ // Note that this is also why the `trans_get_discr` below has
1252+ // `false` to indicate that loading the discriminant should
1253+ // not have a range assert.
12421254 let ret_void_cx = fcx. new_temp_block ( "enum-variant-iter-ret-void" ) ;
12431255 RetVoid ( ret_void_cx, DebugLoc :: None ) ;
12441256
1245- let discr_val = trans_get_discr ( bcx, r, value, None ) ;
1257+ let discr_val = trans_get_discr ( bcx, r, value, None , false ) ;
12461258 let llswitch = Switch ( bcx, discr_val, ret_void_cx. llbb , cases. len ( ) ) ;
12471259 let bcx_next = fcx. new_temp_block ( "enum-variant-iter-next" ) ;
12481260
0 commit comments