https://gcc.gnu.org/g:7e79c32ac1cc84f933000d5cc45249b2eb338aad

commit r14-11602-g7e79c32ac1cc84f933000d5cc45249b2eb338aad
Author: Simon Martin <si...@nasilyan.com>
Date:   Mon Apr 14 08:36:06 2025 +0200

    c++: Properly fold <COND_EXPR>.*<COMPONENT> [PR114525]
    
    We've been miscompiling the following since r0-51314-gd6b4ea8592e338 (I
    did not go compile something that old, and identified this change via
    git blame, so might be wrong)
    
    === cut here ===
    struct Foo { int x; };
    Foo& get (Foo &v) { return v; }
    void bar () {
      Foo v; v.x = 1;
      (true ? get (v) : get (v)).*(&Foo::x) = 2;
      // v.x still equals 1 here...
    }
    === cut here ===
    
    The problem lies in build_m_component_ref, that computes the address of
    the COND_EXPR using build_address to build the representation of
      (true ? get (v) : get (v)).*(&Foo::x);
    and gets something like
      &(true ? get (v) : get (v))  // #1
    instead of
      (true ? &get (v) : &get (v)) // #2
    and the write does not go where want it to, hence the miscompile.
    
    This patch replaces the call to build_address by a call to
    cp_build_addr_expr, which gives #2, that is properly handled.
    
            PR c++/114525
    
    gcc/cp/ChangeLog:
    
            * typeck2.cc (build_m_component_ref): Call cp_build_addr_expr
            instead of build_address.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/expr/cond18.C: New test.
    
    (cherry picked from commit 35ce9afc84a63fb647a90cbecb2adf3e748178be)

Diff:
---
 gcc/cp/typeck2.cc                  |  2 +-
 gcc/testsuite/g++.dg/expr/cond18.C | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index e32a4c638c59..3adb8dec1616 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -2347,7 +2347,7 @@ build_m_component_ref (tree datum, tree component, 
tsubst_flags_t complain)
                                      (cp_type_quals (type)
                                       | cp_type_quals (TREE_TYPE (datum))));
 
-      datum = build_address (datum);
+      datum = cp_build_addr_expr (datum, complain);
 
       /* Convert object to the correct base.  */
       if (binfo)
diff --git a/gcc/testsuite/g++.dg/expr/cond18.C 
b/gcc/testsuite/g++.dg/expr/cond18.C
new file mode 100644
index 000000000000..326985eed506
--- /dev/null
+++ b/gcc/testsuite/g++.dg/expr/cond18.C
@@ -0,0 +1,36 @@
+/* PR c++/114525 */
+/* { dg-do run } */
+
+struct Foo {
+  int x;
+};
+
+Foo& get (Foo& v) {
+  return v;
+}
+
+int main () {
+  bool cond = true;
+
+  /* Testcase from PR; v.x would wrongly remain equal to 1.  */
+  Foo v_ko;
+  v_ko.x = 1;
+  (cond ? get (v_ko) : get (v_ko)).*(&Foo::x) = 2;
+  if (v_ko.x != 2)
+    __builtin_abort ();
+
+  /* Those would already work, i.e. x be changed to 2.  */
+  Foo v_ok_1;
+  v_ok_1.x = 1;
+  (cond ? get (v_ok_1) : get (v_ok_1)).x = 2;
+  if (v_ok_1.x != 2)
+    __builtin_abort ();
+
+  Foo v_ok_2;
+  v_ok_2.x = 1;
+  get (v_ok_2).*(&Foo::x) = 2;
+  if (v_ok_2.x != 2)
+    __builtin_abort ();
+
+  return 0;
+}

Reply via email to