[cfe-commits] Uninformative C++98 error when calling a ctor taking const&, where the type passed in has a deleted copy-ctor

Chandler Carruth chandlerc at google.com
Sat Apr 14 06:13:19 PDT 2012


On Sat, Apr 14, 2012 at 12:13 AM, Jeff Walden <jwalden+clang at mit.edu> wrote:

> Just yesterday a few of us SpiderMonkey hackers stumbled upon the apparent
> C++98 oddity that binding a T temporary to a const U& (where U has a
> U(const T&) constructor) requires that T's copy constructor be accessible.
>  Here's a demonstration:
>
> > [jwalden at wheres-wally minimal]$ cat test.cpp
> > class A
> > {
> >   public:
> >     A() {}
> >
> >   private:
> >     A(const A& a)
> > #ifdef DELETE_COPY_CTOR
> >       = delete
> > #endif
> >       ;
> > };
> >
> > class B
> > {
> >   public:
> >     B(const A& a) {}
> > };
> >
> > int main()
> > {
> >   B b = A();
> > }
>
> If you compile this without the =delete, you get warned that the copy
> constructor is inaccessible, and things still build.
>
> > [jwalden at wheres-wally minimal]$
> ~/Programs/clang-build/build/Release/bin/clang++ -Wno-c++11-extensions
> test.cpp
> > test.cpp:22:9: warning: C++98 requires an accessible copy constructor
> for class 'A' when binding a reference to a temporary; was private
> >       [-Wbind-to-temporary-copy]
> >   B b = A();
> >         ^
> > test.cpp:7:5: note: declared private here
> >     A(const A& a)
> >     ^
> > 1 warning generated.
>

This is a workaround for the fact that a terrifying amount of C++98 code
was written against GCC, where such code (often) compiles without warning.
The problem is that C++98 requires this copy constructor to exist, but does
not require it to in fact be called. GCC only checks the copy constructor
when it is going to be called, but Clang implements this rule precisely as
written.

To cope with all of the code that in fact relies this, we made it a warning
in Clang that can be disabled.


>
> On the other hand, if you compile this with =delete (as SpiderMonkey's
> code was doing), you get an error that a deleted constructor was invoked.
>  But you *don't* get a warning telling you that C++98 requires the copy
> constructor to be accessible.
>

This just happens because of mixing C++11 and C++98 afaict.

C++11 provides the delete operator to more explicitly and clearly mark
something as non-copyable, but it also provides new wording for cases like
this to not require a copy constructor. When you use the delete operator as
an extension, but continuing to build in C++98 results in the copy
constructor being required in strange places.



> We devised a hackaround specific to the situation where we were hitting
> this problem, but we didn't understand why it was happening.  Only later,
> when reducing it to report a bug or determine that it wasn't a bug, did we
> discover the C++98 oddity.  It would have been much more readily apparent
> what the problem was if we'd had both diagnostics.
>
> I've attached a patch which, for this testcase at least, causes both
> errors to be emitted.


I don't think this is much of an improvement really. At a fundamental
level, we should either extend the exception to the rule to include deleted
copy constructors, or not. If not, the current behavior seems correct.

While I sympathize with the desire to pick up delete and other C++11
features, I'm hesitant to extend logic in Clang far in the pursuit of using
'deleted' as a C++98 extension -- I'd rather focus on moving people to
C++11 whole-sale.

Would it be possible to guard the use of the 'deleted' keyword on C++11 as
a whole rather than on the extension alone?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20120414/5d090e15/attachment.html>


More information about the cfe-commits mailing list