/// \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) {}
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,
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,
#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"
PerformDependentDiagnostics(PatternDecl, TemplateArgs);
- // FIXME: Notify the ASTMutationListener that we did this.
+ if (auto *Listener = getASTMutationListener())
+ Listener->FunctionDefinitionInstantiated(Function);
savedContext.pop();
}
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,
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>();
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();
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,
}
}
+ 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.
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())
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());
+ }
};
}
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);
+}
--- /dev/null
+#include "cxx-irgen-top.h"
+
+S<int> s;
--- /dev/null
+#include "cxx-irgen-top.h"
+
+inline int h() { return S<int>::f(); }
--- /dev/null
+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>;
--- /dev/null
+// 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