> cat test.cpp #include <vector> #include <iostream> int main(int argc, char *argv[]) { auto x = std::vector<int>({1, 2, 3}); auto y = [x] () mutable { for (auto &i: x) i ++; return x; }; for (const auto &i: y()) std::cout << i << std::endl; for (const auto &i: y()) std::cout << i << std::endl; return 0; } > x86_64-pc-linux-gnu-g++-4.6.3 -o test test.cpp -std=gnu++0x > ./test 2 3 4 3 4 5 > LC_ALL=C x86_64-pc-linux-gnu-g++-4.6.3 -v Using built-in specs. COLLECT_GCC=x86_64-pc-linux-gnu-g++-4.6.3 COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-pc-linux-gnu/4.6.3/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: /var/tmp/portage/portage/sys-devel/gcc-4.6.3/work/gcc-4.6.3/configure --prefix=/usr --bindir=/usr/x86_64-pc-linux-gnu/gcc-bin/4.6.3 --includedir=/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.3/include --datadir=/usr/share/gcc-data/x86_64-pc-linux-gnu/4.6.3 --mandir=/usr/share/gcc-data/x86_64-pc-linux-gnu/4.6.3/man --infodir=/usr/share/gcc-data/x86_64-pc-linux-gnu/4.6.3/info --with-gxx-include-dir=/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.3/include/g++-v4 --host=x86_64-pc-linux-gnu --build=x86_64-pc-linux-gnu --disable-altivec --disable-fixed-point --with-ppl --with-cloog --disable-ppl-version-check --with-cloog-include=/usr/include/cloog-ppl --enable-lto --enable-nls --without-included-gettext --with-system-zlib --enable-obsolete --disable-werror --enable-secureplt --enable-multilib --enable-libmudflap --disable-libssp --enable-esp --enable-libgomp --with-python-dir=/share/gcc-data/x86_64-pc-linux-gnu/4.6.3/python --enable-checking=release --disable-libgcj --enable-libstdcxx-time --enable-languages=c,c++,objc,fortran --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-targets=all --with-bugurl=http://bugs.gentoo.org/ --with-pkgversion='Gentoo Hardened 4.6.3 p1.11, pie-0.5.2' Thread model: posix gcc version 4.6.3 (Gentoo Hardened 4.6.3 p1.11, pie-0.5.2) > x86_64-pc-linux-gnu-g++-4.7.2 -o test2 test.cpp -std=gnu++0x > ./test2 2 3 4 > LC_ALL=C x86_64-pc-linux-gnu-g++-4.7.2 -v Using built-in specs. COLLECT_GCC=x86_64-pc-linux-gnu-g++-4.7.2 COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-pc-linux-gnu/4.7.2/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: /var/tmp/portage/portage/sys-devel/gcc-4.7.2-r1/work/gcc-4.7.2/configure --prefix=/usr --bindir=/usr/x86_64-pc-linux-gnu/gcc-bin/4.7.2 --includedir=/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.2/include --datadir=/usr/share/gcc-data/x86_64-pc-linux-gnu/4.7.2 --mandir=/usr/share/gcc-data/x86_64-pc-linux-gnu/4.7.2/man --infodir=/usr/share/gcc-data/x86_64-pc-linux-gnu/4.7.2/info --with-gxx-include-dir=/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.2/include/g++-v4 --host=x86_64-pc-linux-gnu --build=x86_64-pc-linux-gnu --disable-altivec --disable-fixed-point --with-ppl --with-cloog --disable-ppl-version-check --with-cloog-include=/usr/include/cloog-ppl --enable-lto --enable-nls --without-included-gettext --with-system-zlib --enable-obsolete --disable-werror --enable-secureplt --enable-multilib --with-multilib-list=m32,m64 --enable-libmudflap --disable-libssp --enable-esp --enable-libgomp --with-python-dir=/share/gcc-data/x86_64-pc-linux-gnu/4.7.2/python --enable-checking=release --disable-libgcj --enable-libstdcxx-time --enable-languages=c,c++,objc,fortran --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-targets=all --with-bugurl=http://bugs.gentoo.org/ --with-pkgversion='Gentoo Hardened 4.7.2-r1 p1.5, pie-0.5.5' Thread model: posix gcc version 4.7.2 (Gentoo Hardened 4.7.2-r1 p1.5, pie-0.5.5) > x86_64-pc-linux-gnu-g++-4.8.0 -o test test.cpp -std=gnu++11 > ./test 2 3 4 > LC_ALL=C x86_64-pc-linux-gnu-g++-4.8.0 -v Using built-in specs. COLLECT_GCC=x86_64-pc-linux-gnu-g++-4.8.0 COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-pc-linux-gnu/4.8.0/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: /tmp/portage/sys-devel/gcc-4.8.0/work/gcc-4.8.0/configure --prefix=/usr --bindir=/usr/x86_64-pc-linux-gnu/gcc-bin/4.8.0 --includedir=/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.0/include --datadir=/usr/share/gcc-data/x86_64-pc-linux-gnu/4.8.0 --mandir=/usr/share/gcc-data/x86_64-pc-linux-gnu/4.8.0/man --infodir=/usr/share/gcc-data/x86_64-pc-linux-gnu/4.8.0/info --with-gxx-include-dir=/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.0/include/g++-v4 --host=x86_64-pc-linux-gnu --build=x86_64-pc-linux-gnu --disable-altivec --disable-fixed-point --with-ppl --with-cloog --disable-isl-version-check --with-cloog --enable-lto --enable-nls --without-included-gettext --with-system-zlib --enable-obsolete --disable-werror --enable-secureplt --enable-multilib --with-multilib-list=m32,m64 --disable-libmudflap --disable-libssp --enable-esp --enable-libgomp --with-python-dir=/share/gcc-data/x86_64-pc-linux-gnu/4.8.0/python --enable-checking=release --disable-libgcj --enable-libstdcxx-time --disable-libquadmath --enable-languages=c,c++ --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-targets=all --with-bugurl=http://bugs.gentoo.org/ --with-pkgversion='Gentoo Hardened 4.8.0 p1.2, pie-0.5.5' Thread model: posix gcc version 4.8.0 (Gentoo Hardened 4.8.0 p1.2, pie-0.5.5)
I can confirm the problem for my mingw-64-bit system using gcc 4.9.0 20130519 (experimental). A variation of the program: //------------------------------------------------- #include <vector> #include <iostream> int main() { std::vector<int> x{1, 2, 3}; auto y = [x] () mutable { for (auto &i: x) i++; return x; }; for (const auto &i : y()) { std::cout << i << std::endl; } std::cout << "(1)" << std::endl; for (const auto &i : y()) { std::cout << i << std::endl; } std::cout << "(2)" << std::endl; } //------------------------------------------------- produces the output: 2 3 4 (1) (2) I *think* the following is going on here: The actual closure member x is (incorrectly) considered as a local variable during RVO analysis, therefore the first invocation invokes the move constructor on that member with the effect of leaving an empty vector x within the closure. The behavior looks incorrect to me: Neither 12.8 p31 b1 nor p32 can be applied here, because x is neither a variable with automatic storage duration nor a function parameter. It is correct the 5.1.2 p10 says "The identifier in a simple-capture is looked up using the usual rules for unqualified name lookup (3.4.1); each such lookup shall find a variable with automatic storage duration declared in the reaching scope of the local lambda expression." but this is an automatic variable *not* within the closure's function call operator. And 5.1.2 p15 "For each entity captured by copy, an unnamed nonstatic data member is declared in the closure type." is clear that x is considered a data member within the closure and RVO shall not be applied to it.
Fixed for 4.7.4/4.8.2/4.9.
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.