I'm trying to compile the following simple C++ code using Clang-3.5:
test.h:
class A
{
public:
A();
virtual ~A() = 0;
};
test.cc:
#include "test.h"
A::A() {;}
A::~A() {;}
The command that I use for compiling this (Linux, uname -r: 3.16.0-4-amd64):
$clang-3.5 -Weverything -std=c++11 -c test.cc
And the error that I get:
./test.h:1:7: warning: 'A' has no out-of-line virtual method definitions; its vtable will be emitted in every translation unit [-Wweak-vtables]
Any hints why this is emitting a warning? The virtual destructor is not inlined at all. Quite the opposite, there's a out-of-line definition provided in test.cc. What am I missing here?
Edit
I don't think that this question is a duplicate of :
What is the meaning of clang's -Wweak-vtables?
as Filip Roséen suggested. In my question I specifically refer to pure abstract classes (not mentioned in the suggested duplicate). I know how -Wweak-vtables
works with non-abstract classes and I'm fine with it. In my example I define the destructor (which is pure abstract) in the implementation file. This should prevent Clang from emitting any errors, even with -Wweak-vtables
.
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:
inline
is specified for A::x()
in the class definition.
struct A {
inline virtual void x();
virtual ~A() {
}
};
void A::x() {
}
B::x() is inline in the class definition.
struct B {
virtual void x() {
}
virtual ~B() {
}
};
C::x() is pure virtual
struct C {
virtual void x() = 0;
virtual ~C() {
}
};
(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.