if (fndecl_built_in_p (fun, CP_BUILT_IN_SOURCE_LOCATION, BUILT_IN_FRONTEND))
return fold_builtin_source_location (EXPR_LOCATION (t));
+ int strops = 0;
+ int strret = 0;
+ if (fndecl_built_in_p (fun, BUILT_IN_NORMAL))
+ switch (DECL_FUNCTION_CODE (fun))
+ {
+ case BUILT_IN_STRLEN:
+ case BUILT_IN_STRNLEN:
+ strops = 1;
+ break;
+ case BUILT_IN_MEMCHR:
+ case BUILT_IN_STRCHR:
+ case BUILT_IN_STRRCHR:
+ strops = 1;
+ strret = 1;
+ break;
+ case BUILT_IN_MEMCMP:
+ case BUILT_IN_STRCMP:
+ strops = 2;
+ break;
+ case BUILT_IN_STRSTR:
+ strops = 2;
+ strret = 1;
+ default:
+ break;
+ }
+
/* Be permissive for arguments to built-ins; __builtin_constant_p should
return constant false for a non-constant argument. */
constexpr_ctx new_ctx = *ctx;
new_ctx.quiet = true;
for (i = 0; i < nargs; ++i)
{
- args[i] = CALL_EXPR_ARG (t, i);
+ tree arg = CALL_EXPR_ARG (t, i);
+
+ /* To handle string built-ins we need to pass ADDR_EXPR<STRING_CST> since
+ expand_builtin doesn't know how to look in the values table. */
+ bool strop = i < strops;
+ if (strop)
+ {
+ STRIP_NOPS (arg);
+ if (TREE_CODE (arg) == ADDR_EXPR)
+ arg = TREE_OPERAND (arg, 0);
+ else
+ strop = false;
+ }
+
/* If builtin_valid_in_constant_expr_p is true,
potential_constant_expression_1 has not recursed into the arguments
of the builtin, verify it here. */
if (!builtin_valid_in_constant_expr_p (fun)
- || potential_constant_expression (args[i]))
+ || potential_constant_expression (arg))
{
bool dummy1 = false, dummy2 = false;
- args[i] = cxx_eval_constant_expression (&new_ctx, args[i], false,
- &dummy1, &dummy2);
+ arg = cxx_eval_constant_expression (&new_ctx, arg, false,
+ &dummy1, &dummy2);
}
if (bi_const_p)
/* For __builtin_constant_p, fold all expressions with constant values
even if they aren't C++ constant-expressions. */
- args[i] = cp_fold_rvalue (args[i]);
+ arg = cp_fold_rvalue (arg);
+ else if (strop)
+ {
+ if (TREE_CODE (arg) == CONSTRUCTOR)
+ arg = braced_lists_to_strings (TREE_TYPE (arg), arg);
+ if (TREE_CODE (arg) == STRING_CST)
+ arg = build_address (arg);
+ }
+
+ args[i] = arg;
}
bool save_ffbcp = force_folding_builtin_constant_p;
return t;
}
+ if (strret)
+ {
+ /* memchr returns a pointer into the first argument, but we replaced the
+ argument above with a STRING_CST; put it back it now. */
+ tree op = CALL_EXPR_ARG (t, strret-1);
+ STRIP_NOPS (new_call);
+ if (TREE_CODE (new_call) == POINTER_PLUS_EXPR)
+ TREE_OPERAND (new_call, 0) = op;
+ else if (TREE_CODE (new_call) == ADDR_EXPR)
+ new_call = op;
+ }
+
return cxx_eval_constant_expression (&new_ctx, new_call, lval,
non_constant_p, overflow_p);
}
--- /dev/null
+// PR c++/80265
+// { dg-do compile { target c++14 } }
+
+constexpr bool compare() {
+ char s1[] = "foo";
+ char s2[] = "fxo";
+ if (!__builtin_memcmp(s1, s2, 3))
+ return false;
+ s2[1] = 'o';
+ if (__builtin_memcmp(s1, s2, 3))
+ return false;
+ if (__builtin_strcmp(s1, s2))
+ return false;
+ return true;
+}
+
+constexpr bool length() {
+ char s[] = "foo";
+ if (__builtin_strlen(s) != 3)
+ return false;
+ return true;
+}
+
+constexpr bool find() {
+ char s[] = "foo";
+ if (__builtin_memchr(s, 'f', 3) != s)
+ return false;
+ if (__builtin_strchr(s, 'o') != s+1)
+ return false;
+ if (__builtin_strstr(s, "oo") != s+1)
+ return false;
+ return true;
+}
+
+static_assert( compare(), "" );
+static_assert( length(), "" );
+static_assert( find(), "" );