Synthesizing the definition of an implicit member is an AST modification, so notify any mutation listeners of it. This fixes a crasher in chained PCH, where an implicit destructor in a PCH gets a definition in a chained PCH, which is then lost. However, any further use of the destructor would cause its definition to be regenerated in the final file, hiding the bug.

llvm-svn: 130103
This commit is contained in:
Sebastian Redl 2011-04-24 16:28:06 +00:00
parent f830df4e9d
commit ab238a7d18
9 changed files with 82 additions and 1 deletions

View File

@ -89,7 +89,7 @@ public:
/// \brief If the consumer is interested in entities getting modified after
/// their initial creation, it should return a pointer to
/// a GetASTMutationListener here.
/// an ASTMutationListener here.
virtual ASTMutationListener *GetASTMutationListener() { return 0; }
/// \brief If the consumer is interested in entities being deserialized from

View File

@ -48,6 +48,9 @@ public:
/// template declaration.
virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
const FunctionDecl *D) {}
/// \brief An implicit member got a definition.
virtual void CompletedImplicitDefinition(const FunctionDecl *D) {}
};
} // end namespace clang

View File

@ -43,6 +43,7 @@ namespace clang {
class ADLResult;
class ASTConsumer;
class ASTContext;
class ASTMutationListener;
class ArrayType;
class AttributeList;
class BlockDecl;
@ -657,6 +658,7 @@ public:
Preprocessor &getPreprocessor() const { return PP; }
ASTContext &getASTContext() const { return Context; }
ASTConsumer &getASTConsumer() const { return Consumer; }
ASTMutationListener *getASTMutationListener() const;
/// \brief Helper class that creates diagnostics with optional
/// template instantiation stacks.

View File

@ -588,6 +588,7 @@ public:
const ClassTemplateSpecializationDecl *D);
virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
const FunctionDecl *D);
virtual void CompletedImplicitDefinition(const FunctionDecl *D);
};
/// \brief AST and semantic-analysis consumer that generates a

View File

@ -97,6 +97,7 @@ public:
const ClassTemplateSpecializationDecl *D);
virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
const FunctionDecl *D);
virtual void CompletedImplicitDefinition(const FunctionDecl *D);
private:
std::vector<ASTMutationListener*> Listeners;
};
@ -132,6 +133,11 @@ void MultiplexASTMutationListener::AddedCXXTemplateSpecialization(
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->AddedCXXTemplateSpecialization(TD, D);
}
void MultiplexASTMutationListener::CompletedImplicitDefinition(
const FunctionDecl *D) {
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->CompletedImplicitDefinition(D);
}
} // end namespace clang

View File

@ -201,6 +201,10 @@ Sema::~Sema() {
ExternalSema->ForgetSema();
}
ASTMutationListener *Sema::getASTMutationListener() const {
return getASTConsumer().GetASTMutationListener();
}
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
/// If there is already an implicit cast, merge into the existing one.
/// The result is of the given category.

View File

@ -18,6 +18,7 @@
#include "clang/Sema/Lookup.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclVisitor.h"
@ -4969,6 +4970,10 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
Constructor->setUsed();
MarkVTableUsed(CurrentLocation, ClassDecl);
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Constructor);
}
}
void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
@ -5254,6 +5259,10 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
Destructor->setUsed();
MarkVTableUsed(CurrentLocation, ClassDecl);
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Destructor);
}
}
/// \brief Builds a statement that copies the given entity from \p From to
@ -5913,6 +5922,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
/*isStmtExpr=*/false);
assert(!Body.isInvalid() && "Compound statement creation cannot fail");
CopyAssignOperator->setBody(Body.takeAs<Stmt>());
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(CopyAssignOperator);
}
}
CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
@ -6113,6 +6126,10 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
}
CopyConstructor->setUsed();
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(CopyConstructor);
}
}
ExprResult

View File

@ -3955,4 +3955,13 @@ void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
AddDeclRef(D, Record);
}
void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) {
if (D->getPCHLevel() == 0)
return; // Declaration not imported from PCH.
// Implicit decl from a PCH was defined.
// FIXME: Should implicit definition be a separate FunctionDecl?
RewriteDecl(D);
}
ASTSerializationListener::~ASTSerializationListener() { }

View File

@ -0,0 +1,39 @@
// no PCH
// RUN: %clang_cc1 -emit-llvm -o /dev/null -include %s -include %s %s
// with PCH
// RUN: %clang_cc1 -emit-llvm -o /dev/null -chain-include %s -chain-include %s %s
#if !defined(PASS1)
#define PASS1
// A base with a virtual dtor.
struct A {
virtual ~A();
};
// A derived class with an implicit virtual dtor.
struct B : A {
// Key function to suppress vtable definition.
virtual void virt();
};
#elif !defined(PASS2)
#define PASS2
// Further derived class that requires ~B().
// Causes definition of ~B(), but it was lost when saving PCH.
struct C : B {
C();
~C() {}
};
#else
void foo() {
// Variable that requires ~C().
C c;
}
// VTable placement would again cause definition of ~B(), hiding the bug,
// if not for B::virt(), which suppresses the placement.
#endif