Bug 91212 - [10 Regression] const ignored for ctor arguments within return since r8-2493-g4ce8c5dea53d8073
Summary: [10 Regression] const ignored for ctor arguments within return since r8-2493-...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 9.1.0
: P2 normal
Target Milestone: 10.5
Assignee: Marek Polacek
URL:
Keywords: wrong-code
: 97221 (view as bug list)
Depends on:
Blocks:
 
Reported: 2019-07-19 12:40 UTC by mn
Modified: 2023-03-07 17:43 UTC (History)
3 users (show)

See Also:
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 (304 bytes, text/plain)
2019-07-19 12:40 UTC, mn
Details
Fix (872 bytes, patch)
2020-02-06 18:43 UTC, Jason Merrill
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description mn 2019-07-19 12:40:56 UTC
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();
}
Comment 1 Martin Liška 2020-01-28 14:51:08 UTC
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();
}
Comment 2 Marek Polacek 2020-01-29 21:05:08 UTC
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 ();
}
Comment 3 Marek Polacek 2020-01-30 17:21:18 UTC
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.
Comment 4 Marek Polacek 2020-01-30 18:44:49 UTC
Jason, do you want to change anything here?  Though clang/icc/msvc++ seem to choose #1.
Comment 5 Jason Merrill 2020-02-06 17:34:35 UTC
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.
Comment 6 Marek Polacek 2020-02-06 17:53:21 UTC
(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...
Comment 7 Jason Merrill 2020-02-06 18:43:39 UTC
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.
Comment 8 Jakub Jelinek 2020-03-04 09:51:45 UTC
GCC 8.4.0 has been released, adjusting target milestone.
Comment 9 GCC Commits 2020-07-29 18:25:23 UTC
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.
Comment 10 Alfred Agrell 2020-09-27 23:37:25 UTC
*** Bug 97221 has been marked as a duplicate of this bug. ***
Comment 11 Jakub Jelinek 2021-05-14 09:51:58 UTC
GCC 8 branch is being closed.
Comment 12 Richard Biener 2021-06-01 08:14:54 UTC
GCC 9.4 is being released, retargeting bugs to GCC 9.5.
Comment 13 Richard Biener 2022-05-27 09:41:15 UTC
GCC 9 branch is being closed
Comment 14 Jakub Jelinek 2022-06-28 10:38:04 UTC
GCC 10.4 is being released, retargeting bugs to GCC 10.5.
Comment 15 Marek Polacek 2023-03-07 17:43:45 UTC
I don't think we want to backport this to GCC 10 at this point.  Closing.