Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/14? -- >8 -- Since r15-8011 cp_build_indirect_ref_1 won't do the *&TARGET_EXPR -> TARGET_EXPR folding not to change its value category. That fix is correct but it made us stop extending the lifetime in this testcase, causing a wrong-code issue -- extend_ref_init_temps_1 did not see through the extra *& because it doesn't use a tree walk. It is not hard to fix that, but there may be other places that need this adjustment. :/
PR c++/119383 gcc/cp/ChangeLog: * call.cc (extend_ref_init_temps_1): Handle *&TARGET_EXPR the same as TARGET_EXPR. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/temp-extend3.C: New test. --- gcc/cp/call.cc | 6 +++++ gcc/testsuite/g++.dg/cpp0x/temp-extend3.C | 32 +++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp0x/temp-extend3.C diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index c1c8987ec8b..ed2bdc85d87 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -14835,6 +14835,12 @@ extend_ref_init_temps_1 (tree decl, tree init, vec<tree, va_gc> **cleanups, for (p = &TREE_OPERAND (sub, 0); TREE_CODE (*p) == COMPONENT_REF || TREE_CODE (*p) == ARRAY_REF; ) p = &TREE_OPERAND (*p, 0); + /* cp_build_indirect_ref_1 leaves *&TARGET_EXPR intact, handle it here. */ + if (INDIRECT_REF_P (*p) + && TREE_CODE (TREE_OPERAND (*p, 0)) == ADDR_EXPR + && same_type_p (TREE_TYPE (*p), + TREE_TYPE (TREE_TYPE (TREE_OPERAND (*p, 0))))) + p = &TREE_OPERAND (TREE_OPERAND (*p, 0), 0); if (TREE_CODE (*p) == TARGET_EXPR) { tree subinit = NULL_TREE; diff --git a/gcc/testsuite/g++.dg/cpp0x/temp-extend3.C b/gcc/testsuite/g++.dg/cpp0x/temp-extend3.C new file mode 100644 index 00000000000..3eab88d0076 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/temp-extend3.C @@ -0,0 +1,32 @@ +// PR c++/119383 +// { dg-do run { target c++11 } } + +int g; + +struct base { + virtual base *clone() const = 0; + ~base() { } +}; + +struct impl : virtual base { + base *clone() const { return new impl; } // #1 + impl() { ++g; } + ~impl() { --g; } +}; + +const base * +make_a_clone () +{ + const base &base = impl{}; // #2 + return base.clone(); +} + +int +main () +{ + make_a_clone (); + // impl::impl() is called twice (#1 and #2), impl::~impl() once, + // at the end of make_a_clone. + if (g != 1) + __builtin_abort (); +} base-commit: 927cfea902c330092848bd7a228b714b07d08f6b -- 2.49.0