On 9/4/26 8:48 PM, Steve Sudit wrote:
This patch was written with the assistance of an LLM (Claude Fable 5.1,
Anthropic), hence the Assisted-by: tag per
https://gcc.gnu.org/ai-policy.html. I directed the analysis, reviewed
every line, ran the testing below and take responsibility for it.
Bootstrapped and regression-tested on x86_64-pc-linux-gnu against trunk
r17-3939-g08794c636095 (default languages, --disable-multilib), with the
g++ testsuite run in all standard levels (98, 11, 14, 17, 20, 23, 26 and
26 -fimplicit-constexpr, as check-c++-all does). compare_tests against
an unpatched run of the same revision shows no regressions; the new test
passes in every level from C++11 up.
OK for trunk? The bug is present on all open release branches (13
through 16), so backports after a soak on trunk would be welcome.
Since r10-5927 (PR c++/80265) cxx_eval_builtin_function_call replaces
the string arguments of the str/mem builtins with the address of a
STRING_CST before folding, and for the pointer-returning ones (memchr,
strchr, strrchr, strstr) it afterwards puts the original argument back
as the base of the folded POINTER_PLUS_EXPR. That re-basing is
unconditional, but the replacement only happens when the evaluated
argument is a bare ADDR_EXPR (offset 0). When the argument already
carries an offset, for instance memchr (a + 1, c, n), the argument is
passed to fold as-is, fold_builtin_call_array merges the offset into
the result (a + 10), and the re-basing then rewrites that result to
(a + 1) + 10, counting the offset twice.
constexpr const char a[] = "abcdefghijabxdefghijaaa";
static_assert (__builtin_memchr (a + 1, 'a', 22) == a + 10, "");
fails since GCC 10 in every dialect; &a[1] is unaffected because the
evaluated argument is an ADDR_EXPR. C++26 exposes this to ordinary
code: P2738 makes void* -> T* casts constant expressions, so the front
end now folds char_traits<char>::find on constant haystacks and
std::string_view::find (c, pos) returns pos too much.
Fix by remembering which argument was replaced and re-basing only in
that case; otherwise the folded result is already relative to the
evaluated argument.
Assisted-by: Claude Fable 5.1 (Anthropic)
PR c++/127218
gcc/cp/ChangeLog:
* constexpr.cc (cxx_eval_builtin_function_call): Remember the
argument replaced by the address of a STRING_CST in STRRET_OP and
re-base the folded result on it only when that replacement
happened.
gcc/testsuite/ChangeLog:
* g++.dg/cpp0x/constexpr-memchr2.C: New test.
Signed-off-by: Steven Sudit <[email protected]>
Patch attached (also applies with git am).
@@ -2612,6 +2612,9 @@ cxx_eval_builtin_function_call (const co
int strops = 0;
int strret = 0;
+ /* Set when argument STRRET-1 is replaced by the address of a STRING_CST
+ below, so the folded result has to be re-based on the original. */
+ tree strret_op = NULL_TREE;
bool bos = false;
if (fndecl_built_in_p (fun, BUILT_IN_NORMAL))
switch (DECL_FUNCTION_CODE (fun))
@@ -2709,7 +2712,11 @@ cxx_eval_builtin_function_call (const co
if (TREE_CODE (arg) == CONSTRUCTOR)
arg = braced_lists_to_strings (TREE_TYPE (arg), arg);
if (TREE_CODE (arg) == STRING_CST)
- arg = build_address (arg);
+ {
+ arg = build_address (arg);
+ if (strret && i == strret - 1)
+ strret_op = oarg;
+ }
else
arg = oarg;
Rather than add a new variable, it seems like we could clear strret if
we didn't end up with &"..." where we expected it?
Jason