aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Poulhiès <poulhies@adacore.com>2021-12-17 14:34:15 +0100
committerPierre-Marie de Rodat <derodat@adacore.com>2022-05-10 08:19:21 +0000
commit5046228671e991170c19c1c0d9f70a51026e2cab (patch)
tree18ccb6aa301e56f7a3f3856c98c04049e79671b2
parenta445a8692c43d14c494e1edf505ee4f33cb98bb6 (diff)
downloadgcc-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.adb53
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;