From: Richard Smith Date: Sat, 22 Mar 2014 23:33:22 +0000 (+0000) Subject: Emit an update record if we instantiate the definition of a function template X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d27e547e9aa7c37cd36b4ed592cfbdefccbd2487;p=clang Emit an update record if we instantiate the definition of a function template 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 --- diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h index 32063d647f..a89bfed53f 100644 --- a/include/clang/AST/ASTMutationListener.h +++ b/include/clang/AST/ASTMutationListener.h @@ -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) {} diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index 91afeabfa1..d2c1b9e925 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -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, diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 376f6f79f4..0982f44257 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -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(); } diff --git a/lib/Serialization/ASTCommon.h b/lib/Serialization/ASTCommon.h index 9f4d7a9acd..524a9c2fdc 100644 --- a/lib/Serialization/ASTCommon.h +++ b/lib/Serialization/ASTCommon.h @@ -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, diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index c186ba00ee..d6660e8b9b 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -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(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(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(D); auto *FPT = FD->getType()->castAs(); diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 0aa539ef59..ed69521a09 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -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(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()) diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 7ee4e31978..d83b3ede38 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -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(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 index 0000000000..d2f9d7fe10 --- /dev/null +++ b/test/Modules/Inputs/cxx-irgen-left.h @@ -0,0 +1,3 @@ +#include "cxx-irgen-top.h" + +S s; diff --git a/test/Modules/Inputs/cxx-irgen-right.h b/test/Modules/Inputs/cxx-irgen-right.h new file mode 100644 index 0000000000..4400c760f0 --- /dev/null +++ b/test/Modules/Inputs/cxx-irgen-right.h @@ -0,0 +1,3 @@ +#include "cxx-irgen-top.h" + +inline int h() { return S::f(); } diff --git a/test/Modules/Inputs/cxx-irgen-top.h b/test/Modules/Inputs/cxx-irgen-top.h new file mode 100644 index 0000000000..05f8e19ee1 --- /dev/null +++ b/test/Modules/Inputs/cxx-irgen-top.h @@ -0,0 +1,6 @@ +template struct S { + __attribute__((always_inline)) static int f() { return 0; } + __attribute__((always_inline, visibility("hidden"))) static int g() { return 0; } +}; + +extern template struct S; diff --git a/test/Modules/cxx-irgen.cpp b/test/Modules/cxx-irgen.cpp new file mode 100644 index 0000000000..91657fdc0e --- /dev/null +++ b/test/Modules/cxx-irgen.cpp @@ -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::g(); + +// CHECK: define available_externally i32 @_ZN1SIiE1fEv({{.*}} #[[ALWAYS_INLINE]] align +int b = h(); + +// CHECK: attributes #[[ALWAYS_INLINE]] = {{.*}} alwaysinline