[Ada] fix bogus computation of empty array 'length
Olivier Hainque
hainque@adacore.com
Fri Mar 21 13:31:00 GMT 2008
We used to compute the 'length of an array as max (hb - lb + 1, 0),
which could overflow for some cases of empty arrays, e.g. when
lb == index_type'first.
We now compute it as (hb < lb) ? 0 : hb - lb + 1, which
could overflow as well but in many less cases (of extremely large
arrays) which we never encounter in practice.
The testcase below is expected to compile and run silently:
procedure Q is
type Vector is array (Integer range <>) of Integer;
function Empty_Vector return Vector is
begin
return (2 .. Integer'First => 0);
end;
My_Vector : Vector := Empty_Vector;
My_Length : Integer := My_Vector'Length;
begin
if My_Length /= 0 then
raise Program_Error;
end if;
end;
Bootstrapped an regtested on x86_64-suse-linux.
2008-03-21 Olivier Hainque <hainque@adacore.com>
* trans.c (Attribute_to_gnu) <'length>: Compute as (hb < lb)
? 0 : hb - lb + 1 instead of max (hb - lb + 1, 0).
* gnat.dg/empty_vector_length.adb: New testcase.
-------------- next part --------------
Index: testsuite/gnat.dg/empty_vector_length.adb
===================================================================
*** testsuite/gnat.dg/empty_vector_length.adb (revision 0)
--- testsuite/gnat.dg/empty_vector_length.adb (revision 0)
***************
*** 0 ****
--- 1,19 ----
+ -- { dg-do run }
+ -- { dg-options "-gnatp" }
+
+ procedure Empty_Vector_Length is
+
+ type Vector is array (Integer range <>) of Integer;
+
+ function Empty_Vector return Vector is
+ begin
+ return (2 .. Integer'First => 0);
+ end;
+
+ My_Vector : Vector := Empty_Vector;
+ My_Length : Integer := My_Vector'Length;
+ begin
+ if My_Length /= 0 then
+ raise Program_Error;
+ end if;
+ end;
Index: testsuite/ChangeLog
===================================================================
*** testsuite/ChangeLog (revision 133420)
--- testsuite/ChangeLog (working copy)
***************
*** 1,3 ****
--- 1,7 ----
+ 2008-03-21 Olivier Hainque <hainque@adacore.com>
+
+ * gnat.dg/empty_vector_length.adb: New testcase.
+
2008-03-20 Richard Guenther <rguenther@suse.de>
* gcc.dg/tree-ssa/ssa-ccp-17.c: New testcase.
Index: ada/ChangeLog
===================================================================
*** ada/ChangeLog (revision 133420)
--- ada/ChangeLog (working copy)
***************
*** 1,4 ****
--- 1,9 ----
2008-03-21 Olivier Hainque <hainque@adacore.com>
+
+ * trans.c (Attribute_to_gnu) <'length>: Compute as (hb < lb)
+ ? 0 : hb - lb + 1 instead of max (hb - lb + 1, 0).
+
+ 2008-03-21 Olivier Hainque <hainque@adacore.com>
Ed Schonberg <schonberg@adacore.com>
* trans.c (addressable_p): Accept COND_EXPR when both arms
Index: ada/trans.c
===================================================================
*** ada/trans.c (revision 133418)
--- ada/trans.c (working copy)
*************** Attribute_to_gnu (Node_Id gnat_node, tre
*** 1181,1213 ****
else /* attribute == Attr_Range_Length || attribute == Attr_Length */
{
- tree gnu_compute_type;
-
if (pa && pa->length)
{
gnu_result = pa->length;
break;
}
! gnu_compute_type
! = signed_or_unsigned_type_for (0,
! get_base_type (gnu_result_type));
!
! gnu_result
! = build_binary_op
! (MAX_EXPR, gnu_compute_type,
! build_binary_op
! (PLUS_EXPR, gnu_compute_type,
! build_binary_op
! (MINUS_EXPR, gnu_compute_type,
! convert (gnu_compute_type,
! TYPE_MAX_VALUE
! (TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_type)))),
! convert (gnu_compute_type,
! TYPE_MIN_VALUE
! (TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_type))))),
! convert (gnu_compute_type, integer_one_node)),
! convert (gnu_compute_type, integer_zero_node));
}
/* If this has a PLACEHOLDER_EXPR, qualify it by the object we are
--- 1181,1222 ----
else /* attribute == Attr_Range_Length || attribute == Attr_Length */
{
if (pa && pa->length)
{
gnu_result = pa->length;
break;
}
+ else
+ {
+ tree gnu_compute_type
+ = signed_or_unsigned_type_for
+ (0, get_base_type (gnu_result_type));
+
+ tree index_type
+ = TYPE_INDEX_TYPE (TYPE_DOMAIN (gnu_type));
+ tree lb
+ = convert (gnu_compute_type, TYPE_MIN_VALUE (index_type));
+ tree hb
+ = convert (gnu_compute_type, TYPE_MAX_VALUE (index_type));
+
+ /* We used to compute the length as max (hb - lb + 1, 0),
+ which could overflow for some cases of empty arrays, e.g.
+ when lb == index_type'first.
+
+ We now compute it as (hb < lb) ? 0 : hb - lb + 1, which
+ could overflow as well, but only for extremely large arrays
+ which we expect never to encounter in practice. */
! gnu_result
! = build3
! (COND_EXPR, gnu_compute_type,
! build_binary_op (LT_EXPR, gnu_compute_type, hb, lb),
! convert (gnu_compute_type, integer_zero_node),
! build_binary_op
! (PLUS_EXPR, gnu_compute_type,
! build_binary_op (MINUS_EXPR, gnu_compute_type, hb, lb),
! convert (gnu_compute_type, integer_one_node)));
! }
}
/* If this has a PLACEHOLDER_EXPR, qualify it by the object we are
More information about the Gcc-patches
mailing list