https://gcc.gnu.org/g:3dd7b598065ea0280fc65ce656c575c5142fa4fc

commit r15-8011-g3dd7b598065ea0280fc65ce656c575c5142fa4fc
Author: Marek Polacek <pola...@redhat.com>
Date:   Wed Mar 12 14:49:53 2025 -0400

    c++: ICE with aligned member and trivial assign op [PR117512]
    
    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.
    
    Reviewed-by: Jason Merrill <ja...@redhat.com>

Diff:
---
 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(-)

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index fe8aceddffa1..4b382b95de17 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 000000000000..3c218a3542c3
--- /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 000000000000..6a20dfc57b13
--- /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 000000000000..b0d83e302373
--- /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 000000000000..7e8212743520
--- /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 ();
+}

Reply via email to