aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ASTConsumer.h2
-rw-r--r--include/clang/AST/ASTMutationListener.h3
-rw-r--r--include/clang/Sema/Sema.h2
-rw-r--r--include/clang/Serialization/ASTWriter.h1
-rw-r--r--lib/Frontend/MultiplexConsumer.cpp6
-rw-r--r--lib/Sema/Sema.cpp4
-rw-r--r--lib/Sema/SemaDeclCXX.cpp17
-rw-r--r--lib/Serialization/ASTWriter.cpp9
-rw-r--r--test/PCH/chain-implicit-definition.cpp39
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