Summary: | [10 Regression] const ignored for ctor arguments within return since r8-2493-g4ce8c5dea53d8073 | ||
---|---|---|---|
Product: | gcc | Reporter: | mn |
Component: | c++ | Assignee: | Marek Polacek <mpolacek> |
Status: | RESOLVED FIXED | ||
Severity: | normal | CC: | blubban, jason, webrown.cpp |
Priority: | P2 | Keywords: | wrong-code |
Version: | 9.1.0 | ||
Target Milestone: | 10.5 | ||
See Also: |
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65869 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91427 |
||
Host: | Target: | ||
Build: | Known to work: | 7.4.0 | |
Known to fail: | 10.0, 8.3.0, 9.2.0 | Last reconfirmed: | 2020-01-28 00:00:00 |
Attachments: |
preprocessed from -save-temps
Fix |
Confirmed, started with r8-2493-g4ce8c5dea53d8073. Slightly modified test-case: $ cat pr91212.cc extern "C" { long write( int fd, const void *buf, unsigned long count ); } struct X { template <unsigned long N> X(const char (&src)[N]) { __builtin_printf ("X(const char (&src)[N])\n"); } template <unsigned long N> X(char (&src)[N]) { __builtin_printf("X(char (&src)[N])\n"); } }; X func1() { char buf[2048]; return buf; } X func2() { char buf[4096]; return X(buf); } int main() { char buf[1024]; __builtin_printf("1: "); X a( buf ); __builtin_printf("2: "); X b( "x" ); __builtin_printf("3: "); X c = func1(); __builtin_printf("4: "); X d = func2(); } Simplified, but still run-time test: struct X { X(char (&)[10]) { } X(const char (&)[10]) { __builtin_abort (); } }; X fn () { char buf[10]; return buf; } int main() { X c = fn (); } Happens with a class too: struct T { int i; }; struct X { X(T&) { } // #1 X(const T&) { __builtin_abort (); } // #2 }; X fn () { T buf; return buf; } int main() { X c = fn (); } is it actually a bug though, not just a consequence of Core 1579? We treat 'buf' as an rvalue and you can't bind an rvalue to a non-const lvalue ref, so #2 is chosen. Jason, do you want to change anything here? Though clang/icc/msvc++ seem to choose #1. I think this is a bug in pre-P1825R0 handling of the restriction that the first overload resolution fails "if the type of the first parameter of the selected constructor is not an rvalue reference to the object's type (possibly cv-qualified)". But that restriction was removed by P1825R0, and I think this demonstrates a problem with that. Testing a patch. (In reply to Jason Merrill from comment #5) > I think this is a bug in pre-P1825R0 handling of the restriction that the > first overload resolution fails "if the type of the first parameter of the > selected constructor is not an rvalue reference to the object's type > (possibly cv-qualified)". > > But that restriction was removed by P1825R0, and I think this demonstrates a > problem with that. > > Testing a patch. Will this resolve bug 91427 too? Sorry, still assigned to me... Created attachment 47793 [details] Fix This patch fixes the pre-P1825 bug, but breaks the PR58051 test which is not actually allowed by DR 1579 (but is by P1825), and some of your -Wredundant-move tests for the same reason. I think let's wait to see what the committee thinks before deciding how to resolve this. GCC 8.4.0 has been released, adjusting target milestone. The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:81bc0ec3e926d7a2c90502847ddaacf3d56d5b75 commit r11-2411-g81bc0ec3e926d7a2c90502847ddaacf3d56d5b75 Author: Jason Merrill <jason@redhat.com> Date: Wed Jul 29 00:57:40 2020 -0400 c++: Avoid calling const copy ctor on implicit move. [PR91212] Our implementation of C++11 implicit move was wrong for return; we didn't actually hit the check for the type of the first parameter of the selected constructor, because we didn't see LOOKUP_PREFER_RVALUE set properly. Fixing that to look at the right flags fixed the issue for this testcase, but broke implicit move for a by-value converting constructor (PR58051). I think this was not allowed in C++17, but it is allowed under the implicit move changes from C++20, and those changes were voted to apply as a DR to earlier standards as well, so I don't want to break it now. So after fixing the flags check I changed the test to allow value parameters. gcc/cp/ChangeLog: PR c++/91212 * call.c (build_over_call): Don't call a const ref overload for implicit move. gcc/testsuite/ChangeLog: PR c++/91212 * g++.dg/cpp0x/move-return3.C: New test. *** Bug 97221 has been marked as a duplicate of this bug. *** GCC 8 branch is being closed. GCC 9.4 is being released, retargeting bugs to GCC 9.5. GCC 9 branch is being closed GCC 10.4 is being released, retargeting bugs to GCC 10.5. I don't think we want to backport this to GCC 10 at this point. Closing. |
Created attachment 46613 [details] preprocessed from -save-temps g++ 9.1.0, gmp-6.1.1, mpfr-3.1.4, mpc-1.0.3, isl-0.18, cloog-0.18.4 having two ctors: struct X{ template <unsigned long N> X(const char (&src)[N]) {} template <unsigned long N> X(char (&src)[N]) {} }; X f() { char buf[1]; return buf; } the second ctor with non-const buffer should be used. with g++ 9.1.0 the first ctor with const buffer is used. build-option: --prefix=/opt/local/gcc-9.1.0 --enable-languages=c,c++ --disable-multilib make-target: profiledbootstrap $ gcc --version gcc (GCC) 9.1.0 Copyright (C) 2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ uname -a Linux refle15sp1 4.12.14-195-default #1 SMP Tue May 7 10:55:11 UTC 2019 (8fba516) x86_64 x86_64 x86_64 GNU/Linux $ cat /etc/os-release NAME="SLES" VERSION="15-SP1" VERSION_ID="15.1" PRETTY_NAME="SUSE Linux Enterprise Server 15 SP1" ID="sles" ID_LIKE="suse" ANSI_COLOR="0;32" CPE_NAME="cpe:/o:suse:sles:15:sp1" $ /opt/local/gcc-9.1.0/bin/g++ -v -save-temps -o ctor ctor.C Using built-in specs. COLLECT_GCC=/opt/local/gcc-9.1.0/bin/g++ COLLECT_LTO_WRAPPER=/opt/local/gcc-9.1.0/libexec/gcc/x86_64-pc-linux-gnu/9.1.0/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: ../gcc-9.1.0/configure --prefix=/opt/local/gcc-9.1.0 --enable-languages=c,c++ --disable-multilib Thread model: posix gcc version 9.1.0 (GCC) COLLECT_GCC_OPTIONS='-v' '-save-temps' '-o' 'ctor' '-shared-libgcc' '-mtune=generic' '-march=x86-64' /opt/local/gcc-9.1.0/libexec/gcc/x86_64-pc-linux-gnu/9.1.0/cc1plus -E -quiet -v -D_GNU_SOURCE ctor.C -mtune=generic -march=x86-64 -fpch-preprocess -o ctor.ii ignoring nonexistent directory "/opt/local/gcc-9.1.0/lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../x86_64-pc-linux-gnu/include" #include "..." search starts here: #include <...> search starts here: /opt/local/gcc-9.1.0/lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0 /opt/local/gcc-9.1.0/lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/x86_64-pc-linux-gnu /opt/local/gcc-9.1.0/lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/backward /opt/local/gcc-9.1.0/lib/gcc/x86_64-pc-linux-gnu/9.1.0/include /usr/local/include /opt/local/gcc-9.1.0/include /opt/local/gcc-9.1.0/lib/gcc/x86_64-pc-linux-gnu/9.1.0/include-fixed /usr/include End of search list. COLLECT_GCC_OPTIONS='-v' '-save-temps' '-o' 'ctor' '-shared-libgcc' '-mtune=generic' '-march=x86-64' /opt/local/gcc-9.1.0/libexec/gcc/x86_64-pc-linux-gnu/9.1.0/cc1plus -fpreprocessed ctor.ii -quiet -dumpbase ctor.C -mtune=generic -march=x86-64 -auxbase ctor -version -o ctor.s GNU C++14 (GCC) version 9.1.0 (x86_64-pc-linux-gnu) compiled by GNU C version 9.1.0, GMP version 6.1.1, MPFR version 3.1.4, MPC version 1.0.3, isl version isl-0.18-GMP GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 GNU C++14 (GCC) version 9.1.0 (x86_64-pc-linux-gnu) compiled by GNU C version 9.1.0, GMP version 6.1.1, MPFR version 3.1.4, MPC version 1.0.3, isl version isl-0.18-GMP GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 Compiler executable checksum: c5c2c4d89679134a97ef259dab7ccdbf COLLECT_GCC_OPTIONS='-v' '-save-temps' '-o' 'ctor' '-shared-libgcc' '-mtune=generic' '-march=x86-64' as -v --64 -o ctor.o ctor.s GNU assembler version 2.31.1 (x86_64-suse-linux) using BFD version (GNU Binutils; SUSE Linux Enterprise 15) 2.31.1.20180828-5 COMPILER_PATH=/opt/local/gcc-9.1.0/libexec/gcc/x86_64-pc-linux-gnu/9.1.0/:/opt/local/gcc-9.1.0/libexec/gcc/x86_64-pc-linux-gnu/9.1.0/:/opt/local/gcc-9.1.0/libexec/gcc/x86_64-pc-linux-gnu/:/opt/local/gcc-9.1.0/lib/gcc/x86_64-pc-linux-gnu/9.1.0/:/opt/local/gcc-9.1.0/lib/gcc/x86_64-pc-linux-gnu/ LIBRARY_PATH=/opt/local/gcc-9.1.0/lib/gcc/x86_64-pc-linux-gnu/9.1.0/:/opt/local/gcc-9.1.0/lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../lib64/:/lib/../lib64/:/usr/lib/../lib64/:/opt/local/gcc-9.1.0/lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS='-v' '-save-temps' '-o' 'ctor' '-shared-libgcc' '-mtune=generic' '-march=x86-64' /opt/local/gcc-9.1.0/libexec/gcc/x86_64-pc-linux-gnu/9.1.0/collect2 -plugin /opt/local/gcc-9.1.0/libexec/gcc/x86_64-pc-linux-gnu/9.1.0/liblto_plugin.so -plugin-opt=/opt/local/gcc-9.1.0/libexec/gcc/x86_64-pc-linux-gnu/9.1.0/lto-wrapper -plugin-opt=-fresolution=ctor.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o ctor /usr/lib/../lib64/crt1.o /usr/lib/../lib64/crti.o /opt/local/gcc-9.1.0/lib/gcc/x86_64-pc-linux-gnu/9.1.0/crtbegin.o -L/opt/local/gcc-9.1.0/lib/gcc/x86_64-pc-linux-gnu/9.1.0 -L/opt/local/gcc-9.1.0/lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/opt/local/gcc-9.1.0/lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../.. ctor.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /opt/local/gcc-9.1.0/lib/gcc/x86_64-pc-linux-gnu/9.1.0/crtend.o /usr/lib/../lib64/crtn.o COLLECT_GCC_OPTIONS='-v' '-save-temps' '-o' 'ctor' '-shared-libgcc' '-mtune=generic' '-march=x86-64' $ ./ctor X(char (&src)[N]) X(const char (&src)[N]) X(const char (&src)[N]) X(char (&src)[N]) $ cat ctor.C extern "C" { long write( int fd, const void *buf, unsigned long count ); } struct X { template <unsigned long N> X(const char (&src)[N]) { write( 2, "X(const char (&src)[N])\n", 24 ); } template <unsigned long N> X(char (&src)[N]) { write( 2, "X(char (&src)[N])\n", 18 ); } }; X func1() { char buf[2048]; return buf; } X func2() { char buf[4096]; return X(buf); } int main() { char buf[1024]; X a( buf ); X b( "x" ); X c = func1(); X d = func2(); }