[cfe-dev] Following up on C++11 final and undefined-reference linker errors

John McCall rjmccall at apple.com
Tue Nov 29 19:20:17 PST 2011


On Nov 29, 2011, at 5:34 PM, Jeff Walden wrote:
> http://lists.cs.uiuc.edu/pipermail/cfe-dev/2011-November/018779.html
> 
> A week ago I asked if adding |final| to a class causing linker errors could possibly not be a compiler bug; replies suggested it likely would be one.   Having reduced it to the code at the end of this mail, I'm pretty sure it's not one.  [expr.reinterpret.cast]p7 says reinterpret_cast<> on a class with virtual functions, or to a class which is not an actual type of the instance being cast, has undefined behavior.  If I read this right, failure to link is permissible behavior.  (GCC 4.7 also produces a linking error.)

Only if the undefined behavior is provably reached.  Undefined behavior only taints execution paths which reach the undefined behavior.

Your program, however, is outright ill-formed, with no diagnostic required, because it contains the declaration of a virtual function (Wrapper::hidden()), but nowhere in the program is there a definition for it.  All virtual functions are considered "used" and therefore must be defined, even if their classes are never even mentioned elsewhere in the program.

> That said, behavior here seems at least suboptimal.  If the testcase shouldn't work, the error should be reported at compile time, when the devirtualizable call to a pure-virtual function is observed.

I was going to say that this cannot actually happen because final classes are not permitted to be abstract, but as far as I can tell, that's not actually in the standard.  That seems like an oversight, though, and I'd prefer to aggressively diagnose that with an error than to try to detect devirtualizable calls to pure virtual functions.

Regardless, your program does not actually contain a devirtualizable call to a pure virtual function, because Wrapper::hidden() is not pure virtual;  it's merely nowhere defined.

> Originally Wrapper was a templatized class which hid incref/decref methods on a reference-counting smart pointer class (the smart pointer's operator-> returns a Wrapper<T>*), prohibiting manual refcounting operations.

I would suggest making the refcounting operations private and befriending the smart pointer class.

John.



More information about the cfe-dev mailing list