The attached patch enhances the get_size_range() function to extract more accurate ranges out of MIN_EXPR and MAX_EXPR nodes with SSA_NAME operand(s). This helps -Wstringop-overflow avoid false positives on some targets in cases like some of those reported in bug 85623 - strncmp() warns about attribute nonstring incorrectly in -Wstringop-overflow
When first trying to expand calls to __builtin_strncmp, most back ends succeed even when the expansion results in a call to the library function. The powerpc64 back-end, however, fails and and allows the generic expansion to take place. There is a subtle difference between the two cases that shows up when examining the bound of the strncmp call expression (the third argument): in the original call expression (in expand_builtin_strncmp) the bound is or can be an SSA_NAME. But when the early expansion fails, expand_builtin_strncmp transforms the original call expression into a new one, substituting MIN_EXPR (bound, CST) for the bound where CST is the constant result of strlen (STR), with STR being either the first or second strncmp argument. When the bound is an SSA_NAME the subsequent attempt to determine its range from the MIN_EXPR fails. Martin
PR testsuite/85888 - New test case c-c++-common/attr-nonstring-6.c from r260541 fails with excess errors gcc/ChangeLog: PR testsuite/85888 * calls.c (get_size_range): Handle MIN_EXPR and MAX_EXPR. diff --git a/gcc/calls.c b/gcc/calls.c index 35bcff7..4998780 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -1295,7 +1295,7 @@ alloc_max_size (void) /* Return true when EXP's range can be determined and set RANGE[] to it after adjusting it if necessary to make EXP a represents a valid size - of object, or a valid size argument to an allocation function declared + of an object, or a valid size argument to an allocation function declared with attribute alloc_size (whose argument may be signed), or to a string manipulation function like memset. When ALLOW_ZERO is true, allow returning a range of [0, 0] for a size in an anti-range [1, N] where @@ -1317,12 +1317,53 @@ get_size_range (tree exp, tree range[2], bool allow_zero /* = false */) bool integral = INTEGRAL_TYPE_P (exptype); wide_int min, max; - enum value_range_type range_type; + enum value_range_type range_type = VR_VARYING; - if (TREE_CODE (exp) == SSA_NAME && integral) - range_type = get_range_info (exp, &min, &max); - else - range_type = VR_VARYING; + if (integral) + { + bool min_expr = TREE_CODE (exp) == MIN_EXPR; + if (min_expr || TREE_CODE (exp) == MAX_EXPR) + { + /* EXP may be an SSA_NAME wrapped in a MIN_/MAX_EXPR. Try + to extract the range from the SSA_NAME and, if successful, + set the final range to the intersection of the ranges + extracted from the expressions' arguments. */ + tree arg0 = TREE_OPERAND (exp, 0); + tree arg1 = TREE_OPERAND (exp, 1); + + STRIP_NOPS (arg0); + STRIP_NOPS (arg1); + + tree rng0[2], rng1[2]; + if (get_size_range (arg0, rng0, allow_zero) + && get_size_range (arg1, rng1, allow_zero)) + { + if (min_expr) + { + range[0] + = tree_int_cst_lt (rng0[0], rng1[0]) ? rng0[0] : rng1[0]; + range[1] + = tree_int_cst_lt (rng0[1], rng1[1]) ? rng0[1] : rng1[1]; + } + else + { + range[0] + = tree_int_cst_lt (rng1[0], rng0[0]) ? rng0[0] : rng1[0]; + range[1] + = tree_int_cst_lt (rng1[1], rng0[1]) ? rng0[1] : rng1[1]; + } + + inform (UNKNOWN_LOCATION, + "%E (%s_EXPR): [%E, %E] U [%E, %E] ==> [%E, %E]", + exp, TREE_CODE (exp) == MIN_EXPR ? "MIN" : "MAX", + rng0[0], rng0[1], rng1[0], rng1[1], range[0], range[1]); + return true; + } + } + + if (TREE_CODE (exp) == SSA_NAME) + range_type = get_range_info (exp, &min, &max); + } if (range_type == VR_VARYING) {