]> granicus.if.org Git - clang/commitdiff
Emit an update record if we instantiate the definition of a function template
authorRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 22 Mar 2014 23:33:22 +0000 (23:33 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 22 Mar 2014 23:33:22 +0000 (23:33 +0000)
specialization from a module. (This can also happen for function template
specializations in PCHs if they're instantiated eagerly, because they're
constexpr or have a deduced return type.)

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@204547 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/ASTMutationListener.h
include/clang/Serialization/ASTWriter.h
lib/Sema/SemaTemplateInstantiateDecl.cpp
lib/Serialization/ASTCommon.h
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriter.cpp
lib/Serialization/ASTWriterDecl.cpp
test/Modules/Inputs/cxx-irgen-left.h [new file with mode: 0644]
test/Modules/Inputs/cxx-irgen-right.h [new file with mode: 0644]
test/Modules/Inputs/cxx-irgen-top.h [new file with mode: 0644]
test/Modules/cxx-irgen.cpp [new file with mode: 0644]

index 32063d647fbe045b393c3811b5378fdb78dc2aab..a89bfed53fbd373950afaaf2f062a380626219b7 100644 (file)
@@ -78,6 +78,9 @@ public:
   /// \brief A static data member was implicitly instantiated.
   virtual void StaticDataMemberInstantiated(const VarDecl *D) {}
 
+  /// \brief A function template's definition was instantiated.
+  virtual void FunctionDefinitionInstantiated(const FunctionDecl *D) {}
+
   /// \brief A new objc category class was added for an interface.
   virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
                                             const ObjCInterfaceDecl *IFD) {}
index 91afeabfa1cdb16e302e3d1912b6457b2388a1b1..d2c1b9e925d3a00f5b9b4498837d906cb6706410 100644 (file)
@@ -503,6 +503,7 @@ private:
 
   void WriteDeclsBlockAbbrevs();
   void WriteDecl(ASTContext &Context, Decl *D);
+  void AddFunctionDefinition(const FunctionDecl *FD, RecordData &Record);
 
   void WriteASTCore(Sema &SemaRef,
                     StringRef isysroot, const std::string &OutputFile,
@@ -766,6 +767,7 @@ public:
   void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) override;
   void CompletedImplicitDefinition(const FunctionDecl *D) override;
   void StaticDataMemberInstantiated(const VarDecl *D) override;
+  void FunctionDefinitionInstantiated(const FunctionDecl *D) override;
   void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
                                     const ObjCInterfaceDecl *IFD) override;
   void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
index 376f6f79f4c0ff6d5ffcdd9a26bf9466df79d085..0982f4425739cbfcdfa26640f5938697c8f7add3 100644 (file)
@@ -12,6 +12,7 @@
 #include "clang/Sema/SemaInternal.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/DeclVisitor.h"
 #include "clang/AST/DependentDiagnostic.h"
@@ -3439,7 +3440,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
 
     PerformDependentDiagnostics(PatternDecl, TemplateArgs);
 
-    // FIXME: Notify the ASTMutationListener that we did this.
+    if (auto *Listener = getASTMutationListener())
+      Listener->FunctionDefinitionInstantiated(Function);
 
     savedContext.pop();
   }
index 9f4d7a9acddeb5464c5b8384003aa5655f4952c2..524a9c2fdcd19d85fe1dd2786eda8f172067e9bf 100644 (file)
@@ -26,6 +26,7 @@ enum DeclUpdateKind {
   UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
   UPD_CXX_ADDED_ANONYMOUS_NAMESPACE,
   UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER,
+  UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION,
   UPD_CXX_RESOLVED_EXCEPTION_SPEC,
   UPD_CXX_DEDUCED_RETURN_TYPE,
   UPD_DECL_MARKED_USED,
index c186ba00ee57741db71954c88992d8ac0c0b6a5e..d6660e8b9b4c3124382089c2d041d61e0cce74e9 100644 (file)
@@ -2944,6 +2944,24 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
           Reader.ReadSourceLocation(ModuleFile, Record, Idx));
       break;
 
+    case UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION: {
+      FunctionDecl *FD = cast<FunctionDecl>(D);
+      if (FD->hasBody() || Reader.PendingBodies[FD])
+        // FIXME: Maybe check for ODR violations.
+        break;
+
+      if (Record[Idx++])
+        FD->setImplicitlyInline();
+      FD->setInnerLocStart(Reader.ReadSourceLocation(ModuleFile, Record, Idx));
+      if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
+        std::tie(CD->CtorInitializers, CD->NumCtorInitializers) =
+            Reader.ReadCXXCtorInitializers(ModuleFile, Record, Idx);
+      // Store the offset of the body so we can lazily load it later.
+      Reader.PendingBodies[FD] = GetCurrentCursorOffset();
+      assert(Idx == Record.size() && "lazy body must be last");
+      break;
+    }
+
     case UPD_CXX_RESOLVED_EXCEPTION_SPEC: {
       auto *FD = cast<FunctionDecl>(D);
       auto *FPT = FD->getType()->castAs<FunctionProtoType>();
index 0aa539ef5953ab648cb8d20f839da429a2feb316..ed69521a09709322df2e93849f13d61802254505 100644 (file)
@@ -4358,6 +4358,7 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
     OffsetsRecord.push_back(GetDeclRef(D));
     OffsetsRecord.push_back(Stream.GetCurrentBitNo());
 
+    bool HasUpdatedBody = false;
     RecordData Record;
     for (auto &Update : DeclUpdate.second) {
       DeclUpdateKind Kind = (DeclUpdateKind)Update.getKind();
@@ -4374,6 +4375,13 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
         AddSourceLocation(Update.getLoc(), Record);
         break;
 
+      case UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION:
+        // An updated body is emitted last, so that the reader doesn't need
+        // to skip over the lazy body to reach statements for other records.
+        Record.pop_back();
+        HasUpdatedBody = true;
+        break;
+
       case UPD_CXX_RESOLVED_EXCEPTION_SPEC:
         addExceptionSpec(
             *this,
@@ -4395,6 +4403,14 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
       }
     }
 
+    if (HasUpdatedBody) {
+      const FunctionDecl *Def = cast<FunctionDecl>(D);
+      Record.push_back(UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION);
+      Record.push_back(Def->isInlined());
+      AddSourceLocation(Def->getInnerLocStart(), Record);
+      AddFunctionDefinition(Def, Record);
+    }
+
     Stream.EmitRecord(DECL_UPDATES, Record);
 
     // Flush any statements that were written as part of this update record.
@@ -5381,6 +5397,17 @@ void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) {
   RewriteDecl(D);
 }
 
+void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) {
+  assert(!WritingAST && "Already writing the AST!");
+  if (!D->isFromASTFile())
+    return;
+
+  // Since the actual instantiation is delayed, this really means that we need
+  // to update the instantiation location.
+  DeclUpdates[D].push_back(
+      DeclUpdate(UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION));
+}
+
 void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) {
   assert(!WritingAST && "Already writing the AST!");
   if (!D->isFromASTFile())
index 7ee4e31978ca0ce87c66e3fcf76753185090bfae..d83b3ede38e80b01ba8930ca520f5e21d75c4185 100644 (file)
@@ -130,6 +130,14 @@ namespace clang {
     void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
     void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
     void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
+
+    void AddFunctionDefinition(const FunctionDecl *FD) {
+      assert(FD->doesThisDeclarationHaveABody());
+      if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
+        Writer.AddCXXCtorInitializers(CD->CtorInitializers,
+                                      CD->NumCtorInitializers, Record);
+      Writer.AddStmt(FD->getBody());
+    }
   };
 }
 
@@ -1894,3 +1902,11 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) {
   if (isRequiredDecl(D, Context))
     EagerlyDeserializedDecls.push_back(ID);
 }
+
+void ASTWriter::AddFunctionDefinition(const FunctionDecl *FD,
+                                      RecordData &Record) {
+  ClearSwitchCaseIDs();
+
+  ASTDeclWriter W(*this, FD->getASTContext(), Record);
+  W.AddFunctionDefinition(FD);
+}
diff --git a/test/Modules/Inputs/cxx-irgen-left.h b/test/Modules/Inputs/cxx-irgen-left.h
new file mode 100644 (file)
index 0000000..d2f9d7f
--- /dev/null
@@ -0,0 +1,3 @@
+#include "cxx-irgen-top.h"
+
+S<int> s;
diff --git a/test/Modules/Inputs/cxx-irgen-right.h b/test/Modules/Inputs/cxx-irgen-right.h
new file mode 100644 (file)
index 0000000..4400c76
--- /dev/null
@@ -0,0 +1,3 @@
+#include "cxx-irgen-top.h"
+
+inline int h() { return S<int>::f(); }
diff --git a/test/Modules/Inputs/cxx-irgen-top.h b/test/Modules/Inputs/cxx-irgen-top.h
new file mode 100644 (file)
index 0000000..05f8e19
--- /dev/null
@@ -0,0 +1,6 @@
+template<typename T> struct S {
+  __attribute__((always_inline)) static int f() { return 0; }
+  __attribute__((always_inline, visibility("hidden"))) static int g() { return 0; }
+};
+
+extern template struct S<int>;
diff --git a/test/Modules/cxx-irgen.cpp b/test/Modules/cxx-irgen.cpp
new file mode 100644 (file)
index 0000000..91657fd
--- /dev/null
@@ -0,0 +1,15 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodules-cache-path=%t -I %S/Inputs -triple %itanium_abi_triple -disable-llvm-optzns -emit-llvm -o - %s | FileCheck %s
+// FIXME: When we have a syntax for modules in C++, use that.
+
+@import cxx_irgen_top;
+@import cxx_irgen_left;
+@import cxx_irgen_right;
+
+// CHECK: define available_externally hidden i32 @_ZN1SIiE1gEv({{.*}} #[[ALWAYS_INLINE:.*]] align
+int a = S<int>::g();
+
+// CHECK: define available_externally i32 @_ZN1SIiE1fEv({{.*}} #[[ALWAYS_INLINE]] align
+int b = h();
+
+// CHECK: attributes #[[ALWAYS_INLINE]] = {{.*}} alwaysinline