Commit 69dc042f by Jason Merrill

PR c++/80265 - constexpr __builtin_mem*.

The library has already worked around this issue, but I was curious about
why it wasn't working.  The answer: because we were passing &var to fold,
which doesn't know about the constexpr values hash table.  Fixed by passing
&"str" instead.

	* constexpr.c (cxx_eval_builtin_function_call): Expose STRING_CST
	to str/mem builtins.
parent 7c82dd6c
...@@ -1260,28 +1260,76 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, ...@@ -1260,28 +1260,76 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
if (fndecl_built_in_p (fun, CP_BUILT_IN_SOURCE_LOCATION, BUILT_IN_FRONTEND)) if (fndecl_built_in_p (fun, CP_BUILT_IN_SOURCE_LOCATION, BUILT_IN_FRONTEND))
return fold_builtin_source_location (EXPR_LOCATION (t)); 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 /* Be permissive for arguments to built-ins; __builtin_constant_p should
return constant false for a non-constant argument. */ return constant false for a non-constant argument. */
constexpr_ctx new_ctx = *ctx; constexpr_ctx new_ctx = *ctx;
new_ctx.quiet = true; new_ctx.quiet = true;
for (i = 0; i < nargs; ++i) 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, /* If builtin_valid_in_constant_expr_p is true,
potential_constant_expression_1 has not recursed into the arguments potential_constant_expression_1 has not recursed into the arguments
of the builtin, verify it here. */ of the builtin, verify it here. */
if (!builtin_valid_in_constant_expr_p (fun) if (!builtin_valid_in_constant_expr_p (fun)
|| potential_constant_expression (args[i])) || potential_constant_expression (arg))
{ {
bool dummy1 = false, dummy2 = false; bool dummy1 = false, dummy2 = false;
args[i] = cxx_eval_constant_expression (&new_ctx, args[i], false, arg = cxx_eval_constant_expression (&new_ctx, arg, false,
&dummy1, &dummy2); &dummy1, &dummy2);
} }
if (bi_const_p) if (bi_const_p)
/* For __builtin_constant_p, fold all expressions with constant values /* For __builtin_constant_p, fold all expressions with constant values
even if they aren't C++ constant-expressions. */ 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; bool save_ffbcp = force_folding_builtin_constant_p;
...@@ -1325,6 +1373,18 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, ...@@ -1325,6 +1373,18 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
return t; 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, return cxx_eval_constant_expression (&new_ctx, new_call, lval,
non_constant_p, overflow_p); non_constant_p, overflow_p);
} }
......
// 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(), "" );
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment