http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56474



--- Comment #16 from Richard Biener <rguenth at gcc dot gnu.org> 2013-04-22 
13:34:40 UTC ---

The testcase in the patch posted to the mailing list is



-- { dg-do compile }



with Ada.Streams;



package Array3 is



   use type Ada.Streams.Stream_Element_Offset;



   type Vector (Size : Ada.Streams.Stream_Element_Offset) is record

      Value : Ada.Streams.Stream_Element_Array (0 .. Size);

   end record;



   Empty_Vector : Vector (-1);



end Array3;





is the testcase when changed to 'Empty_Vector : Vector (-2);' valid?

In any case, in 0 .. Size, Size seems to be signed.

Also, there is the special-case



              /* Similarly, if one of the values overflows in sizetype and the

                 range is null, use 1..0 for the sizetype bounds.  */

              else if (TREE_CODE (gnu_min) == INTEGER_CST

                       && TREE_CODE (gnu_max) == INTEGER_CST

                       && (TREE_OVERFLOW (gnu_min) || TREE_OVERFLOW (gnu_max))

                       && tree_int_cst_lt (gnu_orig_max, gnu_orig_min))

                {

                  gnu_min = size_one_node;

                  gnu_max = size_zero_node;

                  gnu_high = gnu_max;

                }



that simply chooses [1, 0] as "empty" domain, regardless of the original

min or max.  So both cases (of which you fix only one),



              /* Otherwise, if the high bound is constant but the low bound is

                 not, we use the expression (hb >= lb) ? lb : hb + 1 for the

                 lower bound.  Note that the comparison must be done in the

                 original type to avoid any overflow during the conversion.  */

              else if (TREE_CODE (gnu_max) == INTEGER_CST

                       && TREE_CODE (gnu_min) != INTEGER_CST)

                {

                  gnu_high = gnu_max;

                  gnu_min

                    = build_cond_expr (sizetype,

                                       build_binary_op (GE_EXPR,

                                                        boolean_type_node,

                                                        gnu_orig_max,

                                                        gnu_orig_min),

                                       gnu_min,

                                       size_binop (PLUS_EXPR, gnu_max,

                                                   size_one_node));

                }



              /* Finally we use (hb >= lb) ? hb : lb - 1 for the upper bound

                 in all the other cases.  Note that, here as well as above,

                 the condition used in the comparison must be equivalent to

                 the condition (length != 0).  This is relied upon in order

                 to optimize array comparisons in compare_arrays.  */

              else

                gnu_high

                  = build_cond_expr (sizetype,

                                     build_binary_op (GE_EXPR,

                                                      boolean_type_node,

                                                      gnu_orig_max,

                                                      gnu_orig_min),

                                     gnu_max,

                                     size_binop (MINUS_EXPR, gnu_min,

                                                 size_one_node));



could be combined to



             else

               {

                  gnu_min

                    = build_cond_expr (sizetype,

                                       build_binary_op (GE_EXPR,

                                                        boolean_type_node,

                                                        gnu_orig_max,

                                                        gnu_orig_min),

                                       gnu_min,

                                       size_one_node));

                gnu_high

                  = build_cond_expr (sizetype,

                                     build_binary_op (GE_EXPR,

                                                      boolean_type_node,

                                                      gnu_orig_max,

                                                      gnu_orig_min),

                                     gnu_max,

                                     size_zero_node);

                }



which fixes the issue for me.



I can also easily guard the existing size_binop (MINUS_EXPR, gnu_min,

size_one_node) for gnu_min being zero, or I can simply use

int_const_binop here instead, as you expect that operation to _never_

set TREE_OVERFLOW if not gnu_min had TREE_OVERFLOW set.



Note that if gnu_max - 1 is not computable as compile-time constant here,

but is retained as tree expression and folded later overflow will not

be considered either (it doesn't go the size_* API way, which is supposed

to be the interface giving overflow hints to the FEs via means of

TREE_OVERFLOW which better should not appear later during optimization).

Reply via email to