[LLVMbugs] [Bug 12139] CLANG copy ctor with default arguments disregard passed-in arguments when invoked with an Rvalue source object

bugzilla-daemon at llvm.org bugzilla-daemon at llvm.org
Fri Mar 9 16:16:09 PST 2012


http://llvm.org/bugs/show_bug.cgi?id=12139

Douglas Gregor <dgregor at apple.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|                            |INVALID

--- Comment #2 from Douglas Gregor <dgregor at apple.com> 2012-03-09 18:16:09 CST ---
Both GCC and Clang are correct here, even though they differ. Essentially,
Clang is applying copy elision more aggressively than GCC, which is causing
this code to do something different from what the author expected. Copy elision
can be surprising that way, because it's explicitly stated that it can be
applied even though it can change the result of programs.

Specifically, what's happening in the first case is that

  A other(original.makeA(), PASSED_IN);

is calling a copy constructor (since C++11 [class.copy]p2 considers that
constructor a copy constructor). Then, C++11 [class.copy]p31 says that the
compiler can omit the call to the copy constructor (3rd bullet):

  - when a temporary class object that has not been bound to a reference (12.2)
would be copied/moved to a class object with the same cv-unqualified type, the
copy/move operation can be omitted by constructing the temporary object
directly into the target of the omitted copy/move

which means that the copy from the temporary "original.makeA()" can be elided,
such that "other" directly gets the value of "original.makeA()". 

What does makeA() return? Well, we default-construct 'a' (so val has the value
DEFAULT_CTOR) and then perform copy elision (the "named return value
optimization", or NRVO) to end up directly returning that 'a' (without calling
the copy constructor), so the resulting a have val == DEFAULT_CTOR.

The second case is similar. However, makeStaticA() behaves differently because
while

  static A a;

gets the same val == DEFAULT_CTOR, the return statement cannot perform NRVO
when returning a static local variable. Hence, the copy constructor gets called
and we get back an object with val == DEFAULT_ARG.

The third and fourth cases don't involve copy elision, since we're coming from
an lvalue and not a temporary.

Summing up, Clang is correctly performing copy elision, and the open source
library in question will need to be fixed. I strongly suggest eliminating copy
constructors that look like

  A(A const&, <parameters with default arguments>)

and instead splitting them into

  A(const A&); // copy constructor
  A(const A&, <parameters>); // copy + tweak constructor

so that differences in copy elision behavior between compilers don't continue
to cause problems.

-- 
Configure bugmail: http://llvm.org/bugs/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.



More information about the llvm-bugs mailing list