The new get_range_strlen_dynamic function has a couple of bugs where it assumes that the length range bounds it gets back from get_range_strlen are non-null integer constants. The attached "quick and dirty" fix removes those assumptions. Since it's apparently causing package failures in Jeff's GCC buildbot I will commit the patch on Monday to get those builds to pass. But I'm not too happy with how fragile this seems to be so I will try to do some further cleanup here in the near future to make it more robust.
Martin
PR tree-optimization/91570 - ICE in get_range_strlen_dynamic on a conditional of two strings gcc/testsuite/ChangeLog: PR tree-optimization/91570 * gcc.dg/pr91570.c: New test. gcc/ChangeLog: PR tree-optimization/91570 * tree-ssa-strlen.c (get_range_strlen_dynamic): Handle null and non-constant maxlen and maxbound. Index: gcc/testsuite/gcc.dg/pr91570.c =================================================================== --- gcc/testsuite/gcc.dg/pr91570.c (nonexistent) +++ gcc/testsuite/gcc.dg/pr91570.c (working copy) @@ -0,0 +1,30 @@ +/* PR tree-optimization/91570 - ICE in get_range_strlen_dynamic on + a conditional of two strings + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +extern char a[], b[]; + +/* Test case from comment #0 on the bug. */ + +void comment_0 (int i) +{ + a[0] = 0; + b[0] = '1'; + + const char *p = i ? b : a; + + if (__builtin_snprintf (0, 0, "%s", p) < 4) + __builtin_abort (); +} + + +/* Test case from comment #2 on the bug. */ + +void comment_2 (char *s) +{ + char *t = __builtin_strrchr (s, '/'); + __builtin_strcat (s, ".SIF"); + t = t ? t : s; + __builtin_printf ("%s", t); +} Index: gcc/tree-ssa-strlen.c =================================================================== --- gcc/tree-ssa-strlen.c (revision 276021) +++ gcc/tree-ssa-strlen.c (working copy) @@ -896,7 +896,8 @@ get_range_strlen_dynamic (tree src, c_strlen_data if (!argdata.minlen || (integer_zerop (argdata.minlen) - && integer_all_onesp (argdata.maxbound) + && (!argdata.maxbound + || integer_all_onesp (argdata.maxbound)) && integer_all_onesp (argdata.maxlen))) { /* Set the upper bound of the length to unbounded. */ @@ -910,11 +911,13 @@ get_range_strlen_dynamic (tree src, c_strlen_data || tree_int_cst_lt (argdata.minlen, pdata->minlen)) pdata->minlen = argdata.minlen; if (!pdata->maxlen - || tree_int_cst_lt (pdata->maxlen, argdata.maxlen)) + || (argdata.maxlen + && tree_int_cst_lt (pdata->maxlen, argdata.maxlen))) pdata->maxlen = argdata.maxlen; if (!pdata->maxbound - || (tree_int_cst_lt (pdata->maxbound, - argdata.maxbound) + || (argdata.maxbound + && tree_int_cst_lt (pdata->maxbound, + argdata.maxbound) && !integer_all_onesp (argdata.maxbound))) pdata->maxbound = argdata.maxbound; } @@ -1007,11 +1010,19 @@ get_range_strlen_dynamic (tree src, c_strlen_data pdata->maxlen = build_all_ones_cst (size_type_node); } } - else + else if (TREE_CODE (pdata->minlen) == INTEGER_CST) { pdata->maxlen = pdata->minlen; pdata->maxbound = pdata->minlen; } + else + { + /* For PDATA->MINLEN that's a non-constant expression such + as PLUS_EXPR whose value range is unknown, set the bounds + to zero and SIZE_MAX. */ + pdata->minlen = build_zero_cst (size_type_node); + pdata->maxlen = build_all_ones_cst (size_type_node); + } return true; }