On 3/12/25 4:31 PM, Marek Polacek wrote:
On Wed, Mar 12, 2025 at 12:28:58AM -0400, Jason Merrill wrote:
On 3/10/25 6:31 PM, Marek Polacek wrote:
build_over_call has:
t = build2 (MODIFY_EXPR, void_type_node,
build2 (MEM_REF, array_type, arg0, alias_set),
build2 (MEM_REF, array_type, arg, alias_set));
val = build2 (COMPOUND_EXPR, TREE_TYPE (to), t, to);
which creates an expression that can look like:
d = MEM <unsigned char[4]> [(struct A *)&TARGET_EXPR <D.2894, foo()]
= MEM <unsigned char[4]> [(struct A *)(const struct A &) &e],
TARGET_EXPR <D.2894, foo()>
that is, a COMPOUND_EXPR where a TARGET_EXPR is used twice, and its
address is taken in the left-hand side operand, so it can't be elided.
But set_target_expr_eliding simply recurses on the second operand of
a COMPOUND_EXPR and marks the TARGET_EXPR as eliding. This then causes
a crash.
The problem is with build_over_call returning a prvalue (TARGET_EXPR) when
operator= should return an lvalue.
Ah yes. I wish the compiler/testsuite had given me a slap on the wrist.
I guess the issue is the call to cp_build_fold_indirect_ref (argarray[0])
messing up the value category.
Yes. Instead of an lvalue we were returning a clk_class prvalue.
Perhaps the do_fold code in that function should only happen if the result
is an lvalue.
Like this?
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/14?
OK.
-- >8 --
build_over_call has:
t = build2 (MODIFY_EXPR, void_type_node,
build2 (MEM_REF, array_type, arg0, alias_set),
build2 (MEM_REF, array_type, arg, alias_set));
val = build2 (COMPOUND_EXPR, TREE_TYPE (to), t, to);
which creates an expression that can look like:
d = MEM <unsigned char[4]> [(struct A *)&TARGET_EXPR <D.2894, foo()]
= MEM <unsigned char[4]> [(struct A *)(const struct A &) &e],
TARGET_EXPR <D.2894, foo()>
that is, a COMPOUND_EXPR where a TARGET_EXPR is used twice, and its
address is taken in the left-hand side operand, so it can't be elided.
But set_target_expr_eliding simply recurses on the second operand of
a COMPOUND_EXPR and marks the TARGET_EXPR as eliding. This then causes
a crash.
cp_build_indirect_ref_1 should not be changing the value category.
While *&TARGET_EXPR is an lvalue, folding it into TARGET_EXPR would
render is a prvalue of class type.
PR c++/117512
gcc/cp/ChangeLog:
* typeck.cc (cp_build_indirect_ref_1): Only do the *&e -> e
folding if the result would be an lvalue.
gcc/testsuite/ChangeLog:
* g++.dg/cpp0x/alignas23.C: New test.
* g++.dg/ext/align3.C: New test.
* g++.dg/ext/align4.C: New test.
* g++.dg/ext/align5.C: New test.
---
gcc/cp/typeck.cc | 6 +++++-
gcc/testsuite/g++.dg/cpp0x/alignas23.C | 15 +++++++++++++++
gcc/testsuite/g++.dg/ext/align3.C | 14 ++++++++++++++
gcc/testsuite/g++.dg/ext/align4.C | 14 ++++++++++++++
gcc/testsuite/g++.dg/ext/align5.C | 18 ++++++++++++++++++
5 files changed, 66 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/g++.dg/cpp0x/alignas23.C
create mode 100644 gcc/testsuite/g++.dg/ext/align3.C
create mode 100644 gcc/testsuite/g++.dg/ext/align4.C
create mode 100644 gcc/testsuite/g++.dg/ext/align5.C
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index fe8aceddffa..4b382b95de1 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -3870,7 +3870,11 @@ cp_build_indirect_ref_1 (location_t loc, tree ptr,
ref_operator errorstring,
return error_mark_node;
}
else if (do_fold && TREE_CODE (pointer) == ADDR_EXPR
- && same_type_p (t, TREE_TYPE (TREE_OPERAND (pointer, 0))))
+ && same_type_p (t, TREE_TYPE (TREE_OPERAND (pointer, 0)))
+ /* Don't let this change the value category. '*&TARGET_EXPR'
+ is an lvalue, but folding it into 'TARGET_EXPR' would turn
+ it into a prvalue of class type. */
+ && lvalue_p (TREE_OPERAND (pointer, 0)))
/* The POINTER was something like `&x'. We simplify `*&x' to
`x'. */
return TREE_OPERAND (pointer, 0);
diff --git a/gcc/testsuite/g++.dg/cpp0x/alignas23.C
b/gcc/testsuite/g++.dg/cpp0x/alignas23.C
new file mode 100644
index 00000000000..3c218a3542c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alignas23.C
@@ -0,0 +1,15 @@
+// PR c++/117512
+// { dg-do compile { target c++11 } }
+
+struct A {
+ alignas(sizeof (long long)) int b;
+ ~A ();
+};
+A foo (int);
+
+void
+bar ()
+{
+ A e = { 0 };
+ A d = foo (0) = e;
+}
diff --git a/gcc/testsuite/g++.dg/ext/align3.C
b/gcc/testsuite/g++.dg/ext/align3.C
new file mode 100644
index 00000000000..6a20dfc57b1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/align3.C
@@ -0,0 +1,14 @@
+// PR c++/117512
+
+struct A {
+ __attribute__((aligned)) int b;
+ ~A ();
+};
+A foo (int);
+
+void
+bar ()
+{
+ A e = { 0 };
+ A d = foo (0) = e;
+}
diff --git a/gcc/testsuite/g++.dg/ext/align4.C
b/gcc/testsuite/g++.dg/ext/align4.C
new file mode 100644
index 00000000000..b0d83e30237
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/align4.C
@@ -0,0 +1,14 @@
+// PR c++/117512
+
+struct __attribute__((aligned (2 * sizeof (int)))) A {
+ int b;
+ ~A ();
+};
+A foo (int);
+
+void
+bar ()
+{
+ A e = { 0 };
+ A d = foo (0) = e;
+}
diff --git a/gcc/testsuite/g++.dg/ext/align5.C
b/gcc/testsuite/g++.dg/ext/align5.C
new file mode 100644
index 00000000000..7e821274352
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/align5.C
@@ -0,0 +1,18 @@
+// PR c++/117512
+// { dg-do run }
+
+struct A {
+ __attribute__((aligned(2 * sizeof (int)))) int i;
+ ~A() {}
+};
+
+A foo () { A a = { 19 }; return a; }
+
+int
+main ()
+{
+ A a = { 42 };
+ A r = foo () = a;
+ if (r.i != 42)
+ __builtin_abort ();
+}
base-commit: cfb20f17bd17e1cd98ccd8a4517ff3e925cf731c