diff options
author | Marc Poulhiès <poulhies@adacore.com> | 2021-12-17 14:34:15 +0100 |
---|---|---|
committer | Pierre-Marie de Rodat <derodat@adacore.com> | 2022-05-10 08:19:21 +0000 |
commit | 5046228671e991170c19c1c0d9f70a51026e2cab (patch) | |
tree | 18ccb6aa301e56f7a3f3856c98c04049e79671b2 | |
parent | a445a8692c43d14c494e1edf505ee4f33cb98bb6 (diff) | |
download | gcc-5046228671e991170c19c1c0d9f70a51026e2cab.zip gcc-5046228671e991170c19c1c0d9f70a51026e2cab.tar.gz gcc-5046228671e991170c19c1c0d9f70a51026e2cab.tar.bz2 |
[Ada] Fix incorrect range computation
When the type range [Lo, Hi] and the computed expression range [Lor,
Hir] are disjoint, the range-constraining logic breaks and returns an
incorrect range. For example, when Lo<Hi<Lor<Hir, it currently returns
[Lor, Hi]. Instead, return the computed range.
The current 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.
gcc/ada/
* checks.adb (Determine_Range): Fix range refining.
-rw-r--r-- | gcc/ada/checks.adb | 53 |
1 files changed, 40 insertions, 13 deletions
diff --git a/gcc/ada/checks.adb b/gcc/ada/checks.adb index e1a1b0c..9950c18 100644 --- a/gcc/ada/checks.adb +++ b/gcc/ada/checks.adb @@ -5469,22 +5469,49 @@ package body Checks is -- 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; |