In the reference initialization, const B &b = A(1).b; the initializer expression is a class prvalue. The requirement to bind an lvalue reference to a non-volatile const type directly to a reference-compatible class prvalue dates back to DR 391 which PR 25950 intended to implement. The error messages complaining about the private and deleted move constructor indicate that direct binding was not done. ### Self-contained source (tempbind_expr_ref.cpp):> cat tempbind_expr_ref.cpp extern "C" int printf(const char *, ...); struct B { B(int data) : _data(data) { printf("ctor B(int) body: (this=%p,_data=%d)\n", (void *)this, _data); } ~B() { printf("dtor for B: (this=%p,_data=%d)\n", (void *)this, _data); } int _data; private: B() = delete; B(const B &) = delete; B(B &&) = delete; }; struct A { B b; A(int data) : b(data) { printf("ctor A(int) body: (this=%p,_data=%d)\n", (void *)this, b._data); } ~A() { printf("dtor for A: (this=%p,_data=%d)\n", (void *)this, b._data); } private: A() = delete; A(const A &) = delete; A(A &&) = delete; }; const B &b = A(1).b; int main() { printf("main() user body begins\n"); printf("main() user body ends\n"); } ### Compiler invocation: g++-4.6.0 tempbind_expr_ref.cpp -std=c++0x ### Compiler output: tempbind_expr_ref.cpp:16:4: error: 'B::B(B&&)' is private tempbind_expr_ref.cpp:34:19: error: within this context tempbind_expr_ref.cpp:34:19: error: use of deleted function 'B::B(B&&)' tempbind_expr_ref.cpp:16:4: error: declared here ### g++ -v output:> g++-4.6.0 -v Using built-in specs. COLLECT_GCC=g++-4.6.0 COLLECT_LTO_WRAPPER=/data/gcc/libexec/gcc/powerpc64-unknown-linux-gnu/4.6.0/lto-wrapper Target: powerpc64-unknown-linux-gnu Configured with: ./configure --prefix=/data/gcc --program-suffix=-4.6.0 --disable-libssp --disable-libgcj --enable-version-specific-runtime-libs --with-cpu=default32 --enable-secureplt --with-long-double-128 --enable-shared --enable-__cxa_atexit --enable-threads=posix --enable-languages=c,c++,fortran --with-gmp=/usr/local Thread model: posix gcc version 4.6.0 (GCC)
It compiles fine with 4.7 or trunk. I think this is a dup of an existing bug Jason fixed, possibly one he reported himself, about elements of rvalue arrays.
(In reply to comment #1) > It compiles fine with 4.7 or trunk. > > I think this is a dup of an existing bug Jason fixed, possibly one he reported > himself, about elements of rvalue arrays. Confirmed that the above works as expected under 4.7. However, replacing: const B &b = A(1).b; with: const B &b = A(1).*(&A::b); produces an executable whose output indicates that the lifetime of the temporary is not being extended: ctor B(int) body: (this=0xffe9f7d8,_data=1) ctor A(int) body: (this=0xffe9f7d8,_data=1) dtor for A: (this=0xffe9f7d8,_data=1) dtor for B: (this=0xffe9f7d8,_data=1) main() user body begins main() user body ends ### g++ -v output:> g++-4.7.0 -v Using built-in specs. COLLECT_GCC=g++-4.7.0 COLLECT_LTO_WRAPPER=/data/gcc/libexec/gcc/powerpc64-unknown-linux-gnu/4.7.0/lto-wrapper Target: powerpc64-unknown-linux-gnu Configured with: ../gcc-4.7.0/configure --prefix=/data/gcc --program-suffix=-4.7.0 --disable-libssp --disable-libgcj --enable-version-specific-runtime-libs --with-cpu=default32 --enable-secureplt --with-long-double-128 --enable-shared --enable-__cxa_atexit --enable-threads=posix --enable-languages=c,c++,fortran --with-mpfr=/usr/local/ --with-mpc=/usr/local/ --with-gmp=/usr/local/ Thread model: posix gcc version 4.7.0 (GCC)
Confirmed with the modified test case as indicated in comment #2 on trunk, 5.3.0, 4.9.3, and 4.8.5. It doesn't look like it has ever been handled correctly. The same on x86_64.
Still happens on 12.1 and trunk.
The trunk branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:208c6678c25bd9a11e6c5911a4c123cb6b7f3d6e commit r13-5283-g208c6678c25bd9a11e6c5911a4c123cb6b7f3d6e Author: Jason Merrill <jason@redhat.com> Date: Tue Dec 20 16:27:43 2022 -0500 c++: lifetime extension with .* expression [PR53288] This PR points out a case where we are not extending the lifetime of a temporary when the subobject is denoted by a pointer-to-member operation. These rules were clarified in C++20 by CWG1299. There are other cases that also need to be handled under CWG1299, but are not fixed by this patch. PR c++/53288 DR 1299 gcc/cp/ChangeLog: * call.cc (extend_ref_init_temps_1): Handle ptrmem expression. gcc/testsuite/ChangeLog: * g++.dg/init/lifetime4.C: New test.
Fixed for GCC 13.
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>: https://gcc.gnu.org/g:e217e7dbdc1040e7ee160796e9ca1ef12a0dd1cb commit r15-2136-ge217e7dbdc1040e7ee160796e9ca1ef12a0dd1cb Author: Sam James <sam@gentoo.org> Date: Thu Jul 18 10:00:17 2024 +0200 testsuite: Add dg-do run to more tests All of these are for wrong-code bugs. Confirmed to be used before but with no execution. 2024-07-18 Sam James <sam@gentoo.org> PR c++/53288 PR c++/57437 PR c/65345 PR libstdc++/88101 PR tree-optimization/96369 PR tree-optimization/102124 PR tree-optimization/108692 * c-c++-common/pr96369.c: Add dg-do run directive. * gcc.dg/torture/pr102124.c: Ditto. * gcc.dg/pr108692.c: Ditto. * gcc.dg/atomic/pr65345-4.c: Ditto. * g++.dg/cpp0x/lambda/lambda-return1.C: Ditto. * g++.dg/init/lifetime4.C: Ditto. * g++.dg/torture/builtin-clear-padding-1.C: Ditto. * g++.dg/torture/builtin-clear-padding-2.C: Ditto. * g++.dg/torture/builtin-clear-padding-3.C: Ditto. * g++.dg/torture/builtin-clear-padding-4.C: Ditto. * g++.dg/torture/builtin-clear-padding-5.C: Ditto.