Index: include/clang/FrontendTool/Utils.h =================================================================== --- include/clang/FrontendTool/Utils.h +++ include/clang/FrontendTool/Utils.h @@ -18,7 +18,10 @@ namespace clang { class CompilerInstance; +class FrontendAction; +FrontendAction *CreateFrontendAction(CompilerInstance &CI); + /// ExecuteCompilerInvocation - Execute the given actions described by the /// compiler invocation object in the given compiler instance. /// Index: include/clang/Sema/ActiveTemplateInst.h =================================================================== --- include/clang/Sema/ActiveTemplateInst.h +++ include/clang/Sema/ActiveTemplateInst.h @@ -0,0 +1,131 @@ +//===- ActiveTemplateInst.h - Active Template Instantiation Records - C++ -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ActiveTemplateInstantiation class, which represents +// a template instantiation during semantic analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ACTIVE_TEMPLATE_INST_H +#define LLVM_CLANG_ACTIVE_TEMPLATE_INST_H + +#include "clang/Basic/SourceLocation.h" + +namespace clang { + + class Decl; + class NamedDecl; + class TemplateArgument; + +namespace sema { + class TemplateDeductionInfo; +} + +/// \brief A template instantiation that is currently in progress. +class ActiveTemplateInstantiation { +public: + /// \brief The kind of template instantiation we are performing + enum InstantiationKind { + /// We are instantiating a template declaration. The entity is + /// the declaration we're instantiating (e.g., a CXXRecordDecl). + TemplateInstantiation, + + /// We are instantiating a default argument for a template + /// parameter. The Entity is the template, and + /// TemplateArgs/NumTemplateArguments provides the template + /// arguments as specified. + /// FIXME: Use a TemplateArgumentList + DefaultTemplateArgumentInstantiation, + + /// We are instantiating a default argument for a function. + /// The Entity is the ParmVarDecl, and TemplateArgs/NumTemplateArgs + /// provides the template arguments as specified. + DefaultFunctionArgumentInstantiation, + + /// We are substituting explicit template arguments provided for + /// a function template. The entity is a FunctionTemplateDecl. + ExplicitTemplateArgumentSubstitution, + + /// We are substituting template argument determined as part of + /// template argument deduction for either a class template + /// partial specialization or a function template. The + /// Entity is either a ClassTemplatePartialSpecializationDecl or + /// a FunctionTemplateDecl. + DeducedTemplateArgumentSubstitution, + + /// We are substituting prior template arguments into a new + /// template parameter. The template parameter itself is either a + /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl. + PriorTemplateArgumentSubstitution, + + /// We are checking the validity of a default template argument that + /// has been used when naming a template-id. + DefaultTemplateArgumentChecking, + + /// We are instantiating the exception specification for a function + /// template which was deferred until it was needed. + ExceptionSpecInstantiation, + + /// Added for Template instantiation observation + /// Memoization means we are _not_ instantiating a template because + /// it is already instantiated (but we entered a context where we + /// would have had to if it was not already instantiated). + Memoization + + } Kind; + + /// \brief The point of instantiation within the source code. + SourceLocation PointOfInstantiation; + + /// \brief The template (or partial specialization) in which we are + /// performing the instantiation, for substitutions of prior template + /// arguments. + NamedDecl *Template; + + /// \brief The entity that is being instantiated. + Decl *Entity; + + /// \brief The list of template arguments we are substituting, if they + /// are not part of the entity. + const TemplateArgument *TemplateArgs; + + /// \brief The number of template arguments in TemplateArgs. + unsigned NumTemplateArgs; + + /// \brief The template deduction info object associated with the + /// substitution or checking of explicit or deduced template arguments. + sema::TemplateDeductionInfo *DeductionInfo; + + /// \brief The source range that covers the construct that cause + /// the instantiation, e.g., the template-id that causes a class + /// template instantiation. + SourceRange InstantiationRange; + + ActiveTemplateInstantiation() + : Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0), + NumTemplateArgs(0), DeductionInfo(0) {} + + /// \brief Determines whether this template is an actual instantiation + /// that should be counted toward the maximum instantiation depth. + bool isInstantiationRecord() const; + +}; + +bool operator==(const ActiveTemplateInstantiation &X, + const ActiveTemplateInstantiation &Y); + +inline +bool operator!=(const ActiveTemplateInstantiation &X, + const ActiveTemplateInstantiation &Y) { + return !(X == Y); +} + +} + +#endif Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -31,6 +31,7 @@ #include "clang/Basic/Specifiers.h" #include "clang/Basic/TemplateKinds.h" #include "clang/Basic/TypeTraits.h" +#include "clang/Sema/ActiveTemplateInst.h" #include "clang/Sema/AnalysisBasedWarnings.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ExternalSemaSource.h" @@ -160,6 +161,7 @@ class TemplateArgumentList; class TemplateArgumentLoc; class TemplateDecl; + class TemplateInstantiationCallbacks; class TemplateParameterList; class TemplatePartialOrderingContext; class TemplateTemplateParmDecl; @@ -6281,120 +6283,6 @@ bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr); - /// \brief A template instantiation that is currently in progress. - struct ActiveTemplateInstantiation { - /// \brief The kind of template instantiation we are performing - enum InstantiationKind { - /// We are instantiating a template declaration. The entity is - /// the declaration we're instantiating (e.g., a CXXRecordDecl). - TemplateInstantiation, - - /// We are instantiating a default argument for a template - /// parameter. The Entity is the template, and - /// TemplateArgs/NumTemplateArguments provides the template - /// arguments as specified. - /// FIXME: Use a TemplateArgumentList - DefaultTemplateArgumentInstantiation, - - /// We are instantiating a default argument for a function. - /// The Entity is the ParmVarDecl, and TemplateArgs/NumTemplateArgs - /// provides the template arguments as specified. - DefaultFunctionArgumentInstantiation, - - /// We are substituting explicit template arguments provided for - /// a function template. The entity is a FunctionTemplateDecl. - ExplicitTemplateArgumentSubstitution, - - /// We are substituting template argument determined as part of - /// template argument deduction for either a class template - /// partial specialization or a function template. The - /// Entity is either a ClassTemplatePartialSpecializationDecl or - /// a FunctionTemplateDecl. - DeducedTemplateArgumentSubstitution, - - /// We are substituting prior template arguments into a new - /// template parameter. The template parameter itself is either a - /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl. - PriorTemplateArgumentSubstitution, - - /// We are checking the validity of a default template argument that - /// has been used when naming a template-id. - DefaultTemplateArgumentChecking, - - /// We are instantiating the exception specification for a function - /// template which was deferred until it was needed. - ExceptionSpecInstantiation - } Kind; - - /// \brief The point of instantiation within the source code. - SourceLocation PointOfInstantiation; - - /// \brief The template (or partial specialization) in which we are - /// performing the instantiation, for substitutions of prior template - /// arguments. - NamedDecl *Template; - - /// \brief The entity that is being instantiated. - Decl *Entity; - - /// \brief The list of template arguments we are substituting, if they - /// are not part of the entity. - const TemplateArgument *TemplateArgs; - - /// \brief The number of template arguments in TemplateArgs. - unsigned NumTemplateArgs; - - /// \brief The template deduction info object associated with the - /// substitution or checking of explicit or deduced template arguments. - sema::TemplateDeductionInfo *DeductionInfo; - - /// \brief The source range that covers the construct that cause - /// the instantiation, e.g., the template-id that causes a class - /// template instantiation. - SourceRange InstantiationRange; - - ActiveTemplateInstantiation() - : Kind(TemplateInstantiation), Template(nullptr), Entity(nullptr), - TemplateArgs(nullptr), NumTemplateArgs(0), DeductionInfo(nullptr) {} - - /// \brief Determines whether this template is an actual instantiation - /// that should be counted toward the maximum instantiation depth. - bool isInstantiationRecord() const; - - friend bool operator==(const ActiveTemplateInstantiation &X, - const ActiveTemplateInstantiation &Y) { - if (X.Kind != Y.Kind) - return false; - - if (X.Entity != Y.Entity) - return false; - - switch (X.Kind) { - case TemplateInstantiation: - case ExceptionSpecInstantiation: - return true; - - case PriorTemplateArgumentSubstitution: - case DefaultTemplateArgumentChecking: - return X.Template == Y.Template && X.TemplateArgs == Y.TemplateArgs; - - case DefaultTemplateArgumentInstantiation: - case ExplicitTemplateArgumentSubstitution: - case DeducedTemplateArgumentSubstitution: - case DefaultFunctionArgumentInstantiation: - return X.TemplateArgs == Y.TemplateArgs; - - } - - llvm_unreachable("Invalid InstantiationKind!"); - } - - friend bool operator!=(const ActiveTemplateInstantiation &X, - const ActiveTemplateInstantiation &Y) { - return !(X == Y); - } - }; - /// \brief List of active template instantiations. /// /// This vector is treated as a stack. As one template instantiation @@ -6439,6 +6327,13 @@ /// to implement it anywhere else. ActiveTemplateInstantiation LastTemplateInstantiationErrorContext; + /// \brief The template instantiation callbacks to trace or track + /// instantiations (objects can be chained). + /// + /// This callbacks is used to print, trace or track template + /// instantiations as they are being constructed. + std::unique_ptr TemplateInstCallbacksChain; + /// \brief The current index into pack expansion arguments that will be /// used for substitution of parameter packs. /// Index: include/clang/Sema/TemplateInstCallbacks.h =================================================================== --- include/clang/Sema/TemplateInstCallbacks.h +++ include/clang/Sema/TemplateInstCallbacks.h @@ -0,0 +1,96 @@ +//===- TemplateInstCallbacks.h - Template Instantiation Callbacks - C++ --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +// +// This file defines the TemplateInstantiationCallbacks class, which is the +// base class for callbacks that will be notified at template instantiations. +// +//===---------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TEMPLATE_INST_CALLBACKS_H +#define LLVM_CLANG_TEMPLATE_INST_CALLBACKS_H + +#include "clang/Basic/SourceLocation.h" + +#include "llvm/Support/Compiler.h" +#include + +namespace clang { + +class ActiveTemplateInstantiation; +class Sema; + +/// \brief This is a base class for callbacks that will be notified at every +/// template instantiation. +class TemplateInstantiationCallbacks { +public: + + /// \brief Called before doing AST-parsing. + void initialize(const Sema &TheSema) { + this->initializeImpl(TheSema); + if (NextCallbacks) + NextCallbacks->initialize(TheSema); + }; + + /// \brief Called after AST-parsing is completed. + void finalize(const Sema &TheSema) { + this->finalizeImpl(TheSema); + if (NextCallbacks) + NextCallbacks->finalize(TheSema); + }; + + /// \brief Called when instantiation of a template just began. + void atTemplateBegin(const Sema &TheSema, + const ActiveTemplateInstantiation &Inst) { + this->atTemplateBeginImpl(TheSema, Inst); + if (NextCallbacks) + NextCallbacks->atTemplateBegin(TheSema, Inst); + }; + + /// \brief Called when instantiation of a template is just about to end. + void atTemplateEnd(const Sema &TheSema, + const ActiveTemplateInstantiation &Inst) { + this->atTemplateEndImpl(TheSema, Inst); + if (NextCallbacks) + NextCallbacks->atTemplateEnd(TheSema, Inst); + }; + + virtual ~TemplateInstantiationCallbacks() { }; + + /// \brief Appends a new observer to the end of this list. + /// \note This function uses a tail-call recursion. + static void appendNewCallbacks( + std::unique_ptr &CurrentChain, + TemplateInstantiationCallbacks *NewCallbacks) { + if (!CurrentChain) { + CurrentChain.reset(NewCallbacks); + return; + }; + appendNewCallbacks(CurrentChain->NextCallbacks, NewCallbacks); + }; + +protected: + + /// \brief Called before doing AST-parsing. + virtual void initializeImpl(const Sema &TheSema) { }; + /// \brief Called after AST-parsing is completed. + virtual void finalizeImpl(const Sema &TheSema) { }; + + /// \brief Called when instantiation of a template just began. + virtual void atTemplateBeginImpl(const Sema &TheSema, + const ActiveTemplateInstantiation &Inst) {}; + /// \brief Called when instantiation of a template is just about to end. + virtual void atTemplateEndImpl(const Sema &TheSema, + const ActiveTemplateInstantiation &Inst) {}; + + std::unique_ptr NextCallbacks; +}; + +} + +#endif Index: lib/FrontendTool/ExecuteCompilerInvocation.cpp =================================================================== --- lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -31,6 +31,8 @@ using namespace clang; using namespace llvm::opt; +namespace clang { + static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) { using namespace clang::frontend; StringRef Action("unknown"); @@ -113,7 +115,7 @@ #endif } -static FrontendAction *CreateFrontendAction(CompilerInstance &CI) { +FrontendAction *CreateFrontendAction(CompilerInstance &CI) { // Create the underlying action. FrontendAction *Act = CreateFrontendBaseAction(CI); if (!Act) @@ -161,7 +163,7 @@ return Act; } -bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) { +bool ExecuteCompilerInvocation(CompilerInstance *Clang) { // Honor -help. if (Clang->getFrontendOpts().ShowHelp) { std::unique_ptr Opts(driver::createDriverOptTable()); @@ -224,3 +226,5 @@ BuryPointer(std::move(Act)); return Success; } + +} Index: lib/Parse/ParseAST.cpp =================================================================== --- lib/Parse/ParseAST.cpp +++ lib/Parse/ParseAST.cpp @@ -22,6 +22,7 @@ #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaConsumer.h" +#include "clang/Sema/TemplateInstCallbacks.h" #include "llvm/Support/CrashRecoveryContext.h" #include #include @@ -107,6 +108,11 @@ bool OldCollectStats = PrintStats; std::swap(OldCollectStats, S.CollectStats); + // Initialize the template instantiation observer chain. + // FIXME: See note on "finalize" below. + if (S.TemplateInstCallbacksChain) + S.TemplateInstCallbacksChain->initialize(S); + ASTConsumer *Consumer = &S.getASTConsumer(); std::unique_ptr ParseOP( @@ -150,6 +156,14 @@ Consumer->HandleTranslationUnit(S.getASTContext()); + // Finalize the template instantiation observer chain. + // FIXME: This (and init.) should be done in the Sema class, but because + // Sema does not have a reliable "Finalize" function (it has a + // destructor, but it is not guaranteed to be called ("-disable-free")). + // So, do the initialization above and do the finalization here: + if (S.TemplateInstCallbacksChain) + S.TemplateInstCallbacksChain->finalize(S); + std::swap(OldCollectStats, S.CollectStats); if (PrintStats) { llvm::errs() << "\nSTATISTICS:\n"; Index: lib/Sema/ActiveTemplateInst.cpp =================================================================== --- lib/Sema/ActiveTemplateInst.cpp +++ lib/Sema/ActiveTemplateInst.cpp @@ -0,0 +1,74 @@ +//===--- ActiveTemplateInst.cpp - Active Template Instantiation Records ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements basic operators on the class that represents active +// template instantiations during semantic analysis. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/ActiveTemplateInst.h" + +#include "llvm/Support/ErrorHandling.h" + +namespace clang { + +bool operator==(const ActiveTemplateInstantiation &X, + const ActiveTemplateInstantiation &Y) { + if (X.Kind != Y.Kind) + return false; + + if (X.Entity != Y.Entity) + return false; + + switch (X.Kind) { + case ActiveTemplateInstantiation::TemplateInstantiation: + case ActiveTemplateInstantiation::ExceptionSpecInstantiation: + case ActiveTemplateInstantiation::Memoization: + return true; + + case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution: + case ActiveTemplateInstantiation::DefaultTemplateArgumentChecking: + return X.Template == Y.Template && X.TemplateArgs == Y.TemplateArgs; + + case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation: + case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution: + case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution: + case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation: + return X.TemplateArgs == Y.TemplateArgs; + } + + llvm_unreachable("Invalid InstantiationKind!"); +} + +bool ActiveTemplateInstantiation::isInstantiationRecord() const { + switch (Kind) { + case TemplateInstantiation: + case ExceptionSpecInstantiation: + case DefaultTemplateArgumentInstantiation: + case DefaultFunctionArgumentInstantiation: + case ExplicitTemplateArgumentSubstitution: + case DeducedTemplateArgumentSubstitution: + case PriorTemplateArgumentSubstitution: + return true; + + case DefaultTemplateArgumentChecking: + return false; + + // FIXME Should this do a break or not? + // Memoization kind should never occur here, so, it doesn't really matter. + case Memoization: + break; + } + + llvm_unreachable("Invalid InstantiationKind!"); +} + + +} + Index: lib/Sema/CMakeLists.txt =================================================================== --- lib/Sema/CMakeLists.txt +++ lib/Sema/CMakeLists.txt @@ -3,6 +3,7 @@ ) add_clang_library(clangSema + ActiveTemplateInst.cpp AnalysisBasedWarnings.cpp AttributeList.cpp CodeCompleteConsumer.cpp Index: lib/Sema/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp +++ lib/Sema/Sema.cpp @@ -37,6 +37,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaConsumer.h" #include "clang/Sema/TemplateDeduction.h" +#include "clang/Sema/TemplateInstCallbacks.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallSet.h" Index: lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiate.cpp +++ lib/Sema/SemaTemplateInstantiate.cpp @@ -23,6 +23,7 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" +#include "clang/Sema/TemplateInstCallbacks.h" using namespace clang; using namespace sema; @@ -182,24 +183,6 @@ return Result; } -bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const { - switch (Kind) { - case TemplateInstantiation: - case ExceptionSpecInstantiation: - case DefaultTemplateArgumentInstantiation: - case DefaultFunctionArgumentInstantiation: - case ExplicitTemplateArgumentSubstitution: - case DeducedTemplateArgumentSubstitution: - case PriorTemplateArgumentSubstitution: - return true; - - case DefaultTemplateArgumentChecking: - return false; - } - - llvm_unreachable("Invalid InstantiationKind!"); -} - void Sema::InstantiatingTemplate::Initialize( ActiveTemplateInstantiation::InstantiationKind Kind, SourceLocation PointOfInstantiation, SourceRange InstantiationRange, @@ -220,6 +203,8 @@ Inst.InstantiationRange = InstantiationRange; SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); + if (SemaRef.TemplateInstCallbacksChain) + SemaRef.TemplateInstCallbacksChain->atTemplateBegin(SemaRef, Inst); if (!Inst.isInstantiationRecord()) ++SemaRef.NonInstantiationEntries; } @@ -364,6 +349,10 @@ SemaRef.ActiveTemplateInstantiationLookupModules.pop_back(); } + if (SemaRef.TemplateInstCallbacksChain) + SemaRef.TemplateInstCallbacksChain->atTemplateEnd( + SemaRef, SemaRef.ActiveTemplateInstantiations.back()); + SemaRef.ActiveTemplateInstantiations.pop_back(); Invalid = true; } @@ -579,6 +568,9 @@ << cast(Active->Entity) << Active->InstantiationRange; break; + + case ActiveTemplateInstantiation::Memoization: + break; } } } @@ -619,6 +611,9 @@ // or deduced template arguments, so SFINAE applies. assert(Active->DeductionInfo && "Missing deduction info pointer"); return Active->DeductionInfo; + + case ActiveTemplateInstantiation::Memoization: + break; } } Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -22,6 +22,7 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Template.h" +#include "clang/Sema/TemplateInstCallbacks.h" using namespace clang; @@ -3179,7 +3180,7 @@ // into a template instantiation for this specific function template // specialization, which is not a SFINAE context, so that we diagnose any // further errors in the declaration itself. - typedef Sema::ActiveTemplateInstantiation ActiveInstType; + typedef ActiveTemplateInstantiation ActiveInstType; ActiveInstType &ActiveInst = SemaRef.ActiveTemplateInstantiations.back(); if (ActiveInst.Kind == ActiveInstType::ExplicitTemplateArgumentSubstitution || ActiveInst.Kind == ActiveInstType::DeducedTemplateArgumentSubstitution) { @@ -3188,8 +3189,12 @@ assert(FunTmpl->getTemplatedDecl() == Tmpl && "Deduction from the wrong function template?"); (void) FunTmpl; + if (SemaRef.TemplateInstCallbacksChain) + SemaRef.TemplateInstCallbacksChain->atTemplateEnd(SemaRef, ActiveInst); ActiveInst.Kind = ActiveInstType::TemplateInstantiation; ActiveInst.Entity = New; + if (SemaRef.TemplateInstCallbacksChain) + SemaRef.TemplateInstCallbacksChain->atTemplateBegin(SemaRef, ActiveInst); } } Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -30,6 +30,7 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Template.h" +#include "clang/Sema/TemplateInstCallbacks.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/ErrorHandling.h" @@ -5191,6 +5192,15 @@ // Try to recover by implicitly importing this module. createImplicitModuleImportForErrorRecovery(Loc, Owner); } + else if (Def && TemplateInstCallbacksChain) { + ActiveTemplateInstantiation TempInst; + TempInst.Kind = ActiveTemplateInstantiation::Memoization; + TempInst.Template = Def; + TempInst.Entity = Def; + TempInst.PointOfInstantiation = Loc; + TemplateInstCallbacksChain->atTemplateBegin(*this, TempInst); + TemplateInstCallbacksChain->atTemplateEnd(*this, TempInst); + } // We lock in the inheritance model once somebody has asked us to ensure // that a pointer-to-member type is complete.