Skip to content

Commit 35ce9af

Browse files
committed
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)) // Rust-GCC#1 instead of (true ? &get (v) : &get (v)) // Rust-GCC#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 Rust-GCC#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.
1 parent 0fb10ac commit 35ce9af

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

gcc/cp/typeck2.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2387,7 +2387,7 @@ build_m_component_ref (tree datum, tree component, tsubst_flags_t complain)
23872387
(cp_type_quals (type)
23882388
| cp_type_quals (TREE_TYPE (datum))));
23892389

2390-
datum = build_address (datum);
2390+
datum = cp_build_addr_expr (datum, complain);
23912391

23922392
/* Convert object to the correct base. */
23932393
if (binfo)

gcc/testsuite/g++.dg/expr/cond18.C

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/* PR c++/114525 */
2+
/* { dg-do run } */
3+
4+
struct Foo {
5+
int x;
6+
};
7+
8+
Foo& get (Foo& v) {
9+
return v;
10+
}
11+
12+
int main () {
13+
bool cond = true;
14+
15+
/* Testcase from PR; v.x would wrongly remain equal to 1. */
16+
Foo v_ko;
17+
v_ko.x = 1;
18+
(cond ? get (v_ko) : get (v_ko)).*(&Foo::x) = 2;
19+
if (v_ko.x != 2)
20+
__builtin_abort ();
21+
22+
/* Those would already work, i.e. x be changed to 2. */
23+
Foo v_ok_1;
24+
v_ok_1.x = 1;
25+
(cond ? get (v_ok_1) : get (v_ok_1)).x = 2;
26+
if (v_ok_1.x != 2)
27+
__builtin_abort ();
28+
29+
Foo v_ok_2;
30+
v_ok_2.x = 1;
31+
get (v_ok_2).*(&Foo::x) = 2;
32+
if (v_ok_2.x != 2)
33+
__builtin_abort ();
34+
35+
return 0;
36+
}

0 commit comments

Comments
 (0)