llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.13k stars 11.62k forks source link

Clang reports copy constructor being implicitly deleted when it's not called in C++11 mode #28045

Open llvmbot opened 8 years ago

llvmbot commented 8 years ago
Bugzilla Link 27671
Version 3.5
OS All
Reporter LLVM Bugzilla Contributor
CC @DougGregor,@zygoloid,@synopsys-sig-compiler-frontends

Extended Description

The following code compiles successfully in Clang 3.4 and GCC 5.2. Clang 3.5 and higher issues an error in C++11 mode.

$ cat test.cpp
struct Base
{
  Base();
private:
  Base(const Base&);
};
struct D: public Base
{
  D(char*) {}
};
void func() {
  (void)new D("");
}
$ /opt/pkg/gcc-5.2.0/bin/g++ -c -w -std=c++11 test.cpp

$ /opt/pkg/clang-3.4/bin/clang -c -w -std=c++11 test.cpp

$ /opt/pkg/clang-3.5.0/bin/clang -c -w test.cpp

$ /opt/pkg/clang-3.5.0/bin/clang -c -w -std=c++11 test.cpp
test.cpp:12:13: error: call to implicitly-deleted copy constructor of 'D'
  (void)new D("");
            ^ ~~
test.cpp:7:11: note: copy constructor of 'D' is implicitly deleted because base class 'Base' has an
      inaccessible copy constructor
struct D: public Base
          ^
1 error generated.
ec04fc15-fa35-46f2-80e1-5d271f2ef708 commented 8 years ago

This code is ill-formed in C++11 onwards, because you can't implicitly convert a string literal to a (non-const) char*.

We fixed Clang 3.5 to properly implement this rule in overload resolution -- as an extension, we still allow the conversion of "" to char*, but it's considered worse than every other conversion, so we only do it when there is no other viable function.

As as consequence, we prefer to use D's copy constructor over D's char* constructor. D's copy construction works because we can't recursively use the copy constructor from within it, so we choose the char* constructor in the recursive call as it is then the only viable function.

The diagnostic here is pretty bad, but the workaround is simple: make your code valid C++11 by taking the string literal as a const char*.