diff options
-rw-r--r-- | include/clang/AST/ASTConsumer.h | 2 | ||||
-rw-r--r-- | include/clang/AST/ASTMutationListener.h | 3 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 2 | ||||
-rw-r--r-- | include/clang/Serialization/ASTWriter.h | 1 | ||||
-rw-r--r-- | lib/Frontend/MultiplexConsumer.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 17 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 9 | ||||
-rw-r--r-- | test/PCH/chain-implicit-definition.cpp | 39 |
9 files changed, 82 insertions, 1 deletions
diff --git a/include/clang/AST/ASTConsumer.h b/include/clang/AST/ASTConsumer.h index 08ee4ef40d..fcc91768da 100644 --- a/include/clang/AST/ASTConsumer.h +++ b/include/clang/AST/ASTConsumer.h @@ -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 diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h index 33e9ad4859..b1f52b5f66 100644 --- a/include/clang/AST/ASTMutationListener.h +++ b/include/clang/AST/ASTMutationListener.h @@ -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 diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 1d82eb72e9..85f36b3d62 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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. diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index f33381ed05..b7a0208d92 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -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 diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp index ecad91f1f0..721bd05a98 100644 --- a/lib/Frontend/MultiplexConsumer.cpp +++ b/lib/Frontend/MultiplexConsumer.cpp @@ -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 diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index c954c64e7d..3ce1d82c88 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -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. diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 3a87cfd966..bd4aac8985 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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 diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index fb193651b8..42393dea2b 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -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() { } diff --git a/test/PCH/chain-implicit-definition.cpp b/test/PCH/chain-implicit-definition.cpp new file mode 100644 index 0000000000..3ec4f62bcb --- /dev/null +++ b/test/PCH/chain-implicit-definition.cpp @@ -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 |