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

Jeff Walden jwalden+clang at mit.edu
Tue Nov 29 17:34:59 PST 2011


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.)

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.  Or maybe it "should" "work" and just do a virtual call, as it is in MSVC -- not in a correctness sense, but in a this-would-be-useful-if-it-worked-this-way sense.

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.  (The testcase demonstrates the hiding trick for the 'hidden' virtual function.)  It would be nice to be able to mark Wrapper as final to prohibit impermissible over-use of it, although it's not essential.

So: should anything be done here?  And if yes, should it be to produce a compile error earlier, or to make this "work"?

Jeff

/*************************************************************************************/
#include <stdio.h>

#ifdef _MSC_VER
#define final sealed
#endif

class Base
{
   public:
     virtual void hidden() = 0;
     virtual void exposed() = 0;
     virtual ~Base() { }
};

class Derived : public Base
{
   public:
     virtual void hidden() { }
     virtual void exposed() { printf("exposed\n"); }
};

class Wrapper final : public Base
{
   private:
     virtual void hidden();
};

int main()
{
   Base* b = new Derived();

   // "should" print "exposed", undefined reference to Base::exposed() now
   reinterpret_cast<Wrapper*>(b)->exposed();
}



More information about the cfe-dev mailing list