This is a followup to bug #54293. The incorrect behavior can be seen by modifying the test introduced for that bug [0] to use a base class: int d; struct A { int i; ~A() { ++d; }; }; struct B : A {}; int main() { { const int &r = B().i; if (d != 0) return 1; } if (d != 1) return 1; } This test passes for clang HEAD and fails for GCC HEAD. [0] https://gcc.gnu.org/viewcvs/gcc/trunk/gcc/testsuite/g%2B%2B.dg/init/ref19.C?view=markup&pathrev=240819
icc 18 also has this bug. MSVC 19 2017 (with /permissive-) miscompiles by copying the bound subobject to a separate complete object before binding, so the reference does not dangle but the derived and base class objects are still destructed prematurely.
Yes, this lifetime extension mechanism seems super fragile in gcc. Binding to a base fails, binding to an array element fails int d; struct A { int i[2]; ~A() { ++d; }; }; int main() { // int&&r = A().i[0]; const int &r = A().i[0]; if (d != 0) __builtin_abort(); } even a regular member fails if referenced with a slightly different syntax (bug 53288).
Created attachment 44050 [details] untested hackish patch This seems to help a bit, but it doesn't feel like the right approach.
Author: jason Date: Wed May 23 03:52:56 2018 New Revision: 260563 URL: https://gcc.gnu.org/viewcvs?rev=260563&root=gcc&view=rev Log: PR c++/81420 - not extending temporary lifetime. * call.c (extend_ref_init_temps_1): Handle ARRAY_REF. * class.c (build_base_path): Avoid redundant move of an rvalue. Added: trunk/gcc/testsuite/g++.dg/cpp0x/temp-extend1.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/call.c trunk/gcc/cp/class.c
Author: jason Date: Thu May 24 14:28:59 2018 New Revision: 260673 URL: https://gcc.gnu.org/viewcvs?rev=260673&root=gcc&view=rev Log: PR c++/81420 - not extending temporary lifetime. * call.c (extend_ref_init_temps_1): Handle ARRAY_REF. * class.c (build_base_path): Avoid redundant move of an rvalue. Added: branches/gcc-8-branch/gcc/testsuite/g++.dg/cpp0x/temp-extend1.C Modified: branches/gcc-8-branch/gcc/cp/ChangeLog branches/gcc-8-branch/gcc/cp/call.c branches/gcc-8-branch/gcc/cp/class.c
Jason: Can the bug be marked as resolved?
Not really, The issue still persists Check this example: #include <iostream> #include <limits> #include <optional> std::optional<double> getValue(){ return 3.14; } int main(){ const double &v = *getValue(); std::cout<<"v:=" << v << std::endl; if (v == 0.0) { __builtin_abort(); } return 0; } compiled with GCC trunk (v13) and the following flags: -O3 -std=c++17 -Werror -Wall -Wextra returns: Program returned: 139 v:=0 link to play: https://godbolt.org/z/fPhxqe1h3 clang behaves correctly till v 10, it extends the lifetime, in v10 it catches with dangling-gsl check. when adding a more complex value rather than double clang doesn't catch it but it extends the lifetime. e.g.: #include <iostream> #include <limits> #include <optional> namespace { struct Data{ double v; }; } // namespace std::optional<Data> getValue(){ return Data{3.14}; } int main(){ const double &v = getValue()->v; std::cout<<"v:=" << v << std::endl; if (v == 0.0) { __builtin_abort(); } return 0; } link to play : https://godbolt.org/z/WoeGqhn7E where GCC catches with the following error: <source>: In function 'int main()': <source>:20:25: error: using a dangling pointer to an unnamed temporary [-Werror=dangling-pointer=] 20 | std::cout<<"v:=" << v << std::endl; | ^ <source>:19:31: note: unnamed temporary defined here 19 | const double &v = getValue()->v; | ~~~~~~~~^~ cc1plus: all warnings being treated as errors ASM generation compiler returned: 1 GCC must first fix the temporary values lifetime when bounded by reference.
(In reply to Ion Lupascu from comment #7) > Not really, The issue still persists > > std::optional<double> getValue(){ ... > const double &v = *getValue(); ... > const double &v = getValue()->v; Neither of these bind the reference to a prvalue; std::optional operator* returns a reference, and operator-> returns a pointer, so in both cases we're binding the reference to an xvalue, and GCC is correct not to extend the temporary. Fixed in 8.2.