]> granicus.if.org Git - clang/commitdiff
Synthesizing the definition of an implicit member is an AST modification, so notify...
authorSebastian Redl <sebastian.redl@getdesigned.at>
Sun, 24 Apr 2011 16:28:06 +0000 (16:28 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Sun, 24 Apr 2011 16:28:06 +0000 (16:28 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130103 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/ASTConsumer.h
include/clang/AST/ASTMutationListener.h
include/clang/Sema/Sema.h
include/clang/Serialization/ASTWriter.h
lib/Frontend/MultiplexConsumer.cpp
lib/Sema/Sema.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Serialization/ASTWriter.cpp
test/PCH/chain-implicit-definition.cpp [new file with mode: 0644]

index 08ee4ef40de0649f6e527625c12f492b9ce15275..fcc91768dac3ca498c6282eef0f2ceed9a2ad383 100644 (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.
+  /// aASTMutationListener here.
   virtual ASTMutationListener *GetASTMutationListener() { return 0; }
 
   /// \brief If the consumer is interested in entities being deserialized from
index 33e9ad485968da6997736cbfafc54373656e8812..b1f52b5f663f506c5db6ef1bd5f52a438a322200 100644 (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
index 1d82eb72e9c454a1bfbe32fbd5dcaf9142b878e7..85f36b3d621f4d841b555c1cd634fb7688579310 100644 (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.
index f33381ed058bbb71a434af81f881e178dd3db14d..b7a0208d92ceb5b17cd3ce0a1f7ed62d7863cf8e 100644 (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
index ecad91f1f04ee6427bf1f2380ae6837dda1d9818..721bd05a98a4e8982bcc87ba06c658d1c21e3b53 100644 (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
 
index c954c64e7d0b1c9a12bf2a6d793ea29d1cb9bf7b..3ce1d82c8811c3c0943b709be1eae0a053ef67b8 100644 (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.
index 3a87cfd9665ce5576724965e0b13f1611050b507..bd4aac8985c6ba79a12fd1eb6cf749fef34f471a 100644 (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
index fb193651b8769b0f31422cb28c343be0990f38ab..42393dea2bce9e6942d57bb846b0af525b125df2 100644 (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() { }
diff --git a/test/PCH/chain-implicit-definition.cpp b/test/PCH/chain-implicit-definition.cpp
new file mode 100644 (file)
index 0000000..3ec4f62
--- /dev/null
@@ -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