clang: no out-of-line virtual method definitions (pure abstract C++ class)

We don’t want to place the vtable in each translation unit. So there must be some ordering of translation units, such that we can say then, that we place the vtable in the “first” translation unit. If this ordering is undefined, we emit the warning.

You find the answer in the Itanium CXX ABI. In the section about virtual tables (5.2.3) you find:

The virtual table for a class is emitted in the same object containing the definition of its key function, i.e. the first non-pure virtual function that is not inline at the point of class definition. If there is no key function, it is emitted everywhere used. The emitted virtual table includes the full virtual table group for the class, any new construction virtual tables required for subobjects, and the VTT for the class. They are emitted in a COMDAT group, with the virtual table mangled name as the identifying symbol. Note that if the key function is not declared inline in the class definition, but its definition later is always declared inline, it will be emitted in every object containing the definition.
NOTE: In the abstract, a pure virtual destructor could be used as the key function, as it must be defined even though it is pure. However, the ABI committee did not realize this fact until after the specification of key function was complete; therefore a pure virtual destructor cannot be the key function.

The second section is the answer to your question. A pure virtual destructor is no key function. Therefore, it is unclear where to place the vtable and it is placed everywhere. As a consequence we get the warning.

You will even find this explanation in the Clang source documentation.

So specifically to the warning: You will get the warning when all of your virtual functions belong to one of the following categories:

  1. inline is specified for A::x() in the class definition.

    struct A {
        inline virtual void x();
        virtual ~A() {
        }
    };
    void A::x() {
    }
    
  2. B::x() is inline in the class definition.

    struct B {
        virtual void x() {
        }
        virtual ~B() {
        }
    };
    
  3. C::x() is pure virtual

    struct C {
        virtual void x() = 0;
        virtual ~C() {
        }
    };
    
  4. (Belongs to 3.) You have a pure virtual destructor

    struct D {
        virtual ~D() = 0;
    };
    D::~D() {
    }
    

    In this case, the ordering could be defined, because the destructor must be defined, nevertheless, by definition, there is still no “first” translation unit.

For all other cases, the key function is the first virtual function that does not fit to one of these categories, and the vtable will be placed in the translation unit where the key function is defined.

Leave a Comment