@@ -309,14 +309,14 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
309309 // In the algorithm above, we can change
310310 // cast(relative_tag) + niche_variants.start()
311311 // into
312- // cast(tag) + (niche_variants.start() - niche_start)
312+ // cast(tag + (niche_variants.start() - niche_start) )
313313 // if either the casted type is no larger than the original
314314 // type, or if the niche values are contiguous (in either the
315315 // 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;
317317
318318 let data_for_boundary_niche = || -> Option < ( IntPredicate , u128 ) > {
319- if !can_incr_after_cast {
319+ if !can_incr {
320320 None
321321 } else if niche_start == low_unsigned {
322322 Some ( ( IntPredicate :: IntULE , niche_end) )
@@ -353,24 +353,33 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
353353 // The algorithm is now this:
354354 // is_niche = tag <= niche_end
355355 // discr = if is_niche {
356- // cast(tag) + (niche_variants.start() - niche_start)
356+ // cast(tag + (niche_variants.start() - niche_start) )
357357 // } else {
358358 // untagged_variant
359359 // }
360360 // (the first line may instead be tag >= niche_start,
361361 // 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.
362365 let is_niche =
363366 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+
364374 let cast_tag = if cast_smaller {
365- bx. intcast ( tag , cast_to, false )
375+ bx. intcast ( incr_tag , cast_to, false )
366376 } else if niches_ule {
367- bx. zext ( tag , cast_to)
377+ bx. zext ( incr_tag , cast_to)
368378 } else {
369- bx. sext ( tag , cast_to)
379+ bx. sext ( incr_tag , cast_to)
370380 } ;
371381
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 )
374383 } else {
375384 // The special cases don't apply, so we'll have to go with
376385 // the general algorithm.
0 commit comments