On 2/24/25 10:01 AM, Jakub Jelinek wrote:
On Mon, Feb 24, 2025 at 08:29:31AM -0500, Jason Merrill wrote:
On 2/24/25 5:52 AM, Jakub Jelinek wrote:
The following testcases segfault because the new range for -frange-for-ext-temps
temporary extension extends even the internal TARGET_EXPRs created by
get_member_function_from_ptrfunc.
The following patch fixes that by marking those TARGET_EXPR_INTERNAL_P.
I'm not calling get_internal_target_expr because I really want to force
the TARGET_EXPR creation rather than say mark some existing TARGET_EXPR
internal,
Hmm, good point, but that seems like a reason to use force_target_expr in
gen_internal_target_expr.
and get_internal_target_expr doesn't take complain argument
either and always uses tf_warning_or_error.
That shouldn't be an issue for any internal temporaries; complain is only
relevant for building the cleanup that internal temps must not have.
It looks like there are a few more internal uses of force_target_expr in
cp_finish_decl and build_comparison_op.
So like this if it passes full bootstrap/regtest?
So far passed make check-g++ in gcc (98,11,14,17,20,23,26) and make check
in libstdc++-v3.
OK.
2025-02-24 Jakub Jelinek <ja...@redhat.com>
PR c++/118923
* tree.cc (get_internal_target_expr): Use force_target_expr
instead of build_target_expr_with_type.
* typeck.cc (get_member_function_from_ptrfunc): Use
get_internal_target_expr instead of force_target_expr.
* decl.cc (cp_finish_decl): Likewise.
* method.cc (build_comparison_op): Likewise.
* g++.dg/cpp0x/pr118923.C: New test.
* g++.dg/cpp1y/pr118923.C: New test.
--- gcc/cp/tree.cc.jj 2025-02-24 00:06:25.776732504 +0100
+++ gcc/cp/tree.cc 2025-02-24 15:04:28.991381102 +0100
@@ -982,8 +982,7 @@ tree
get_internal_target_expr (tree init)
{
init = convert_bitfield_to_declared_type (init);
- tree t = build_target_expr_with_type (init, TREE_TYPE (init),
- tf_warning_or_error);
+ tree t = force_target_expr (TREE_TYPE (init), init, tf_warning_or_error);
TARGET_EXPR_INTERNAL_P (t) = true;
return t;
}
--- gcc/cp/typeck.cc.jj 2025-01-23 11:17:39.651880614 +0100
+++ gcc/cp/typeck.cc 2025-02-24 15:05:27.817562229 +0100
@@ -4219,16 +4219,14 @@ get_member_function_from_ptrfunc (tree *
&& !DECL_P (instance_ptr)
&& !TREE_CONSTANT (instance_ptr)))
instance_ptr = instance_save_expr
- = force_target_expr (TREE_TYPE (instance_ptr), instance_ptr,
- complain);
+ = get_internal_target_expr (instance_ptr);
/* See above comment. */
if (TREE_SIDE_EFFECTS (function)
|| (!nonvirtual
&& !DECL_P (function)
&& !TREE_CONSTANT (function)))
- function
- = force_target_expr (TREE_TYPE (function), function, complain);
+ function = get_internal_target_expr (function);
/* Start by extracting all the information from the PMF itself. */
e3 = pfn_from_ptrmemfunc (function);
--- gcc/cp/decl.cc.jj 2025-02-24 00:06:25.665734038 +0100
+++ gcc/cp/decl.cc 2025-02-24 15:08:52.027729921 +0100
@@ -9377,8 +9377,7 @@ cp_finish_decl (tree decl, tree init, bo
tree guard = NULL_TREE;
if (cleanups || cleanup)
{
- guard = force_target_expr (boolean_type_node,
- boolean_false_node, tf_none);
+ guard = get_internal_target_expr (boolean_false_node);
add_stmt (guard);
guard = TARGET_EXPR_SLOT (guard);
}
@@ -9407,8 +9406,7 @@ cp_finish_decl (tree decl, tree init, bo
popped that all, so push those extra cleanups around
the whole sequence with a guard variable. */
gcc_assert (TREE_CODE (sl) == STATEMENT_LIST);
- guard = force_target_expr (integer_type_node,
- integer_zero_node, tf_none);
+ guard = get_internal_target_expr (integer_zero_node);
add_stmt (guard);
guard = TARGET_EXPR_SLOT (guard);
for (unsigned i = 0; i < n_extra_cleanups; ++i)
--- gcc/cp/method.cc.jj 2025-01-15 08:59:46.383217835 +0100
+++ gcc/cp/method.cc 2025-02-24 15:10:18.674537705 +0100
@@ -1597,7 +1597,7 @@ build_comparison_op (tree fndecl, bool d
/* Some other array, will need runtime loop. */
else
{
- idx = force_target_expr (sizetype, maxval, complain);
+ idx = get_internal_target_expr (maxval);
loop_indexes = tree_cons (idx, NULL_TREE, loop_indexes);
}
expr_type = TREE_TYPE (expr_type);
--- gcc/testsuite/g++.dg/cpp0x/pr118923.C.jj 2025-02-24 15:02:04.966385945
+0100
+++ gcc/testsuite/g++.dg/cpp0x/pr118923.C 2025-02-24 15:02:04.966385945
+0100
@@ -0,0 +1,66 @@
+// PR c++/118923
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-frange-for-ext-temps" { target c++23 } }
+// { dg-additional-options "-fno-range-for-ext-temps" { target c++20_down } }
+
+int g;
+
+struct A {
+ int a[3];
+ A (int x, int y, int z) : a{x, y, z} { if ((g++ & 7) != 4) __builtin_abort
(); }
+ A (const A &x) = delete;
+ ~A () { if ((g++ & 7) != 7 - 2 * (__cpp_range_based_for >= 202211))
__builtin_abort (); }
+ int *begin () { return a; }
+ int *end () { return a + 3; }
+};
+
+struct B {
+ B () { if ((g++ & 7) != 3) __builtin_abort (); }
+ B (const B &) = delete;
+ ~B () { if ((g++ & 7) != 5 + (__cpp_range_based_for >= 202211))
__builtin_abort (); }
+};
+
+struct C {
+ A foo (const B &) { return { 1, 2, 3 }; }
+ A bar (const B &) { return { 4, 5, 6 }; }
+ bool baz () { return b; }
+ bool b = false;
+ static C c;
+};
+
+C C::c;
+
+struct D {
+ D () { if ((g++ & 5) != 0) __builtin_abort (); }
+ D (const D &) = delete;
+ ~D () { if ((g & 7) != 1 && (g & 7) != 6 + (__cpp_range_based_for >=
202211)) __builtin_abort (); g++; }
+};
+
+inline C *
+qux (const D &)
+{
+ return &C::c;
+}
+
+void
+foo ()
+{
+ int z = 1;
+ auto d = qux (D {})->baz () ? &C::bar : &C::foo;
+ for (const int &r : (qux (D {})->*d) (B {}))
+ if (z++ != r)
+ __builtin_abort ();
+ C::c.b = true;
+ d = qux (D {})->baz () ? &C::bar : &C::foo;
+ for (const int &r : (qux (D {})->*d) (B {}))
+ if (z++ != r)
+ __builtin_abort ();
+}
+
+int
+main ()
+{
+ foo ();
+ if (g != 16)
+ __builtin_abort ();
+}
--- gcc/testsuite/g++.dg/cpp1y/pr118923.C.jj 2025-02-24 15:02:04.966385945
+0100
+++ gcc/testsuite/g++.dg/cpp1y/pr118923.C 2025-02-24 15:02:04.966385945
+0100
@@ -0,0 +1,38 @@
+// PR c++/118923
+// { dg-do run { target c++14 } }
+
+struct A {
+ int a[3] = { 0, 0, 0 };
+ int *begin () { return a; }
+ int *end () { return a + 3; }
+};
+
+struct B {
+ A foo () { return { 1, 2, 3 }; }
+ A bar () { return { 1, 2, 3 }; }
+ bool baz () { return b; }
+ bool b = false;
+ static B c;
+};
+
+B B::c;
+
+inline B *
+qux ()
+{
+ return &B::c;
+}
+
+void
+foo ()
+{
+ auto d = qux ()->baz () ? &B::foo : &B::bar;
+ for (const int &r : (qux ()->*d) ())
+ ;
+}
+
+int
+main ()
+{
+ foo ();
+}