I'm working on a tool based on clang's AST, and I'm curious to know why clang works this way.
Here's my input. I have a very simple class that is defined like this:
class Foo {
int foo();
};
Then in my RecursiveASTVisitor, I have code that looks like this:
bool MyASTVisitor::VisitCXXRecordDecl(clang::CXXRecordDecl *D) {
for (auto const & method : D->methods()) {
llvm::outs() << method->getQualifiedNameAsString() << "(";
for (auto const & param : method->params())
llvm::outs() << param->getType().getAsString() << ", ";
llvm::outs() << ")";
if (method->isImplicit())
llvm::outs() << " [implicit]";
llvm::outs() << "\n";
}
return true;
}
All this does is spit out the list of methods defined in all the classes that are visited. The output for this is as we'd expect:
Foo::foo()
Now, let's make a small change to our Foo class. Let's make the foo() method virtual:
class Foo {
virtual int foo();
};
Now my output changes:
Foo::foo()
Foo::operator=(const class Foo &, ) [implicit]
Foo::~Foo() [implicit]
My question is, why does adding a virtual method to a class cause clang to create an implicit assignment operator and destructor? If I add --std=c++11, it creates an implicit move-assignment operator as well. Is this an implementation detail of clang, or is it part of the C++ standard?
Turns out that I should just read the clang source code. SemaDeclCXX.cpp
has a method called Sema::AddImplicitlyDeclaredMembersToClass
. There's a comment about why it declares the implicit copy assignment:
if (!ClassDecl->hasUserDeclaredCopyAssignment()) {
++ASTContext::NumImplicitCopyAssignmentOperators;
// If we have a dynamic class, then the copy assignment operator may be
// virtual, so we have to declare it immediately. This ensures that, e.g.,
// it shows up in the right place in the vtable and that we diagnose
// problems with the implicit exception specification.
if (ClassDecl->isDynamicClass() ||
ClassDecl->needsOverloadResolutionForCopyAssignment())
DeclareImplicitCopyAssignment(ClassDecl);
}
So it does this in order to ensure that the implicitly defined methods, that may be virtual, end up in the right place in the vtable.