cuintp.c (UI_To_gnu): Use a proper type for intermediate computations to ensure bias...
authorOlivier Hainque <hainque@adacore.com>
Tue, 15 Nov 2005 13:54:14 +0000 (14:54 +0100)
committerArnaud Charlet <charlet@gcc.gnu.org>
Tue, 15 Nov 2005 13:54:14 +0000 (14:54 +0100)
2005-11-14  Olivier Hainque  <hainque@adacore.com>

* cuintp.c (UI_To_gnu): Use a proper type for intermediate computations
to ensure bias adjustments take place when need be and to prevent
occurrences of intermediate overflows.

From-SVN: r106963

gcc/ada/cuintp.c

index ff2dfb9027b6a4800d9ed9e3c8d9d4a13f42eecf..7adc057ce7c24e8b62acf780eef97d79cc883c92 100644 (file)
@@ -6,7 +6,7 @@
  *                                                                          *
  *                          C Implementation File                           *
  *                                                                          *
- *          Copyright (C) 1992-2003 Free Software Foundation, Inc.          *
+ *          Copyright (C) 1992-2005 Free Software Foundation, Inc.          *
  *                                                                          *
  * GNAT is free software;  you can  redistribute it  and/or modify it under *
  * terms of the  GNU General Public License as published  by the Free Soft- *
@@ -41,6 +41,7 @@
 #include "stringt.h"
 #include "fe.h"
 #include "gigi.h"
+#include "ada-tree.h"
 
 /* Universal integers are represented by the Uint type which is an index into
    the Uints_Ptr table containing Uint_Entry values.  A Uint_Entry contains an
@@ -74,22 +75,41 @@ UI_To_gnu (Uint Input, tree type)
 {
   tree gnu_ret;
 
+  /* We might have a TYPE with biased representation and be passed an
+     unbiased value that doesn't fit.  We always use an unbiased type able
+     to hold any such possible value for intermediate computations, and
+     then rely on a conversion back to TYPE to perform the bias adjustment
+     when need be.  */
+
+  int biased_type_p
+    = (TREE_CODE (type) == INTEGER_TYPE
+       && TYPE_BIASED_REPRESENTATION_P (type));
+
+  tree comp_type = biased_type_p ? get_base_type (type) : type;
+
   if (Input <= Uint_Direct_Last)
-    gnu_ret = build_cst_from_int (type, Input - Uint_Direct_Bias);
+    gnu_ret = build_cst_from_int (comp_type, Input - Uint_Direct_Bias);
   else
     {
       Int Idx = Uints_Ptr[Input].Loc;
       Pos Length = Uints_Ptr[Input].Length;
       Int First = Udigits_Ptr[Idx];
-      /* Do computations in integer type or TYPE whichever is wider, then
-        convert later.  This avoid overflow if type is short integer.  */
-      tree comp_type
-       = ((TREE_CODE (type) == REAL_TYPE
-           || TYPE_PRECISION (type) >= TYPE_PRECISION (integer_type_node))
-          ? type : integer_type_node);
-      tree gnu_base = build_cst_from_int (comp_type, Base);
+      tree gnu_base;
 
       gcc_assert (Length > 0);
+
+      /* The computations we perform below always require a type at least as
+        large as an integer not to overflow.  REAL types are always fine, but
+        INTEGER or ENUMERAL types we are handed may be too short.  We use a
+        base integer type node for the computations in this case and will
+        convert the final result back to the incoming type later on.  */
+
+      if (TREE_CODE (comp_type) != REAL_TYPE
+         && TYPE_PRECISION (comp_type) < TYPE_PRECISION (integer_type_node))
+       comp_type = integer_type_node;
+
+      gnu_base = build_cst_from_int (comp_type, Base);
+
       gnu_ret = build_cst_from_int (comp_type, First);
       if (First < 0)
        for (Idx++, Length--; Length; Idx++, Length--)