-- we do NOT do this for the case of a modular type where the
-- possible upper bound on the value is above the base type high
-- bound, because that means the result could wrap.
+ -- Same applies for the lower bound if it is negative.
- if Lor > Lo
- and then not (Is_Modular_Integer_Type (Typ) and then Hir > Hbound)
- then
- Lo := Lor;
- end if;
+ if Is_Modular_Integer_Type (Typ) then
+ if Lor > Lo and then Hir <= Hbound then
+ Lo := Lor;
+ end if;
- -- Similarly, if the refined value of the high bound is less than the
- -- value so far, then reset it to the more restrictive value. Again,
- -- we do not do this if the refined low bound is negative for a
- -- modular type, since this would wrap.
+ if Hir < Hi and then Lor >= Uint_0 then
+ Hi := Hir;
+ end if;
- if Hir < Hi
- and then not (Is_Modular_Integer_Type (Typ) and then Lor < Uint_0)
- then
- Hi := Hir;
+ else
+ if Lor > Hi or else Hir < Lo then
+
+ -- If the ranges are disjoint, return the computed range.
+
+ -- The current range-constraining logic would require returning
+ -- the base type's bounds. However, this would miss an
+ -- opportunity to warn about out-of-range values for some cases
+ -- (e.g. when type's upper bound is equal to base type upper
+ -- bound).
+
+ -- The alternative of always returning the computed values,
+ -- even when ranges are intersecting, has unwanted effects
+ -- (mainly useless constraint checks are inserted) in the
+ -- Enable_Overflow_Check and Apply_Scalar_Range_Check as these
+ -- bounds have a special interpretation.
+
+ Lo := Lor;
+ Hi := Hir;
+ else
+
+ -- If the ranges Lor .. Hir and Lo .. Hi intersect, try to
+ -- refine the returned range.
+
+ if Lor > Lo then
+ Lo := Lor;
+ end if;
+
+ if Hir < Hi then
+ Hi := Hir;
+ end if;
+ end if;
end if;
end if;