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).