@@ -309,14 +309,14 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
309
309
// In the algorithm above, we can change
310
310
// cast(relative_tag) + niche_variants.start()
311
311
// into
312
- // cast(tag) + (niche_variants.start() - niche_start)
312
+ // cast(tag + (niche_variants.start() - niche_start) )
313
313
// if either the casted type is no larger than the original
314
314
// type, or if the niche values are contiguous (in either the
315
315
// signed or unsigned sense).
316
- let can_incr_after_cast = cast_smaller || niches_ule || niches_sle;
316
+ let can_incr = cast_smaller || niches_ule || niches_sle;
317
317
318
318
let data_for_boundary_niche = || -> Option < ( IntPredicate , u128 ) > {
319
- if !can_incr_after_cast {
319
+ if !can_incr {
320
320
None
321
321
} else if niche_start == low_unsigned {
322
322
Some ( ( IntPredicate :: IntULE , niche_end) )
@@ -353,24 +353,33 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
353
353
// The algorithm is now this:
354
354
// is_niche = tag <= niche_end
355
355
// discr = if is_niche {
356
- // cast(tag) + (niche_variants.start() - niche_start)
356
+ // cast(tag + (niche_variants.start() - niche_start) )
357
357
// } else {
358
358
// untagged_variant
359
359
// }
360
360
// (the first line may instead be tag >= niche_start,
361
361
// and may be a signed or unsigned comparison)
362
+ // The arithmetic must be done before the cast, so we can
363
+ // have the correct wrapping behavior. See issue #104519 for
364
+ // the consequences of getting this wrong.
362
365
let is_niche =
363
366
bx. icmp ( predicate, tag, bx. cx ( ) . const_uint_big ( tag_llty, constant) ) ;
367
+ let delta = ( niche_variants. start ( ) . as_u32 ( ) as u128 ) . wrapping_sub ( niche_start) ;
368
+ let incr_tag = if delta == 0 {
369
+ tag
370
+ } else {
371
+ bx. add ( tag, bx. cx ( ) . const_uint_big ( tag_llty, delta) )
372
+ } ;
373
+
364
374
let cast_tag = if cast_smaller {
365
- bx. intcast ( tag , cast_to, false )
375
+ bx. intcast ( incr_tag , cast_to, false )
366
376
} else if niches_ule {
367
- bx. zext ( tag , cast_to)
377
+ bx. zext ( incr_tag , cast_to)
368
378
} else {
369
- bx. sext ( tag , cast_to)
379
+ bx. sext ( incr_tag , cast_to)
370
380
} ;
371
381
372
- let delta = ( niche_variants. start ( ) . as_u32 ( ) as u128 ) . wrapping_sub ( niche_start) ;
373
- ( is_niche, cast_tag, delta)
382
+ ( is_niche, cast_tag, 0 )
374
383
} else {
375
384
// The special cases don't apply, so we'll have to go with
376
385
// the general algorithm.
0 commit comments