[PATCH] Template Instantiation Observer + a few other templight-related changes

Mikael Persson mikael.s.persson at gmail.com
Sat Oct 4 17:22:00 PDT 2014


This patch adds a base-class called TemplateInstantiationObserver which
gets notified whenever a template instantiation is entered or exited during
semantic analysis. This is a base class used to implement the template
profiling and debugging tool called Templight (
https://github.com/mikael-s-persson/templight).

The patch also makes a few more changes:
 - ActiveTemplateInstantiation class is moved out of the Sema class (so it
can be used with inclusion of Sema.h).
 - CreateFrontendAction function in front-end utilities is given external
linkage (not longer a hidden static function).
 - TemplateInstObserverChain data member added to Sema class to hold the
list of template-inst observers.
 - Notifications to the template-inst observer are added at the key places
where templates are instantiated.

I believe this patch should be fairly uncontroversial as the changes are
very limited. I tried to keep them minimal, it does not add any end-user
feature or bug-fix, and the impact to the main-line code is negligible.
AFAIK, all LLVM / Clang guidelines have been respected.

The patch was made against r219067.

-- 
Sven Mikael Persson, M.Sc.(Tech.)
McGill University,
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20141004/ebeeb164/attachment.html>
-------------- next part --------------
Index: include/clang/FrontendTool/Utils.h
===================================================================
--- include/clang/FrontendTool/Utils.h	(revision 219067)
+++ include/clang/FrontendTool/Utils.h	(working copy)
@@ -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	(revision 0)
+++ include/clang/Sema/ActiveTemplateInst.h	(working copy)
@@ -0,0 +1,139 @@
+//===--- 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	(revision 219067)
+++ include/clang/Sema/Sema.h	(working copy)
@@ -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 TemplateInstantiationObserver;
   class TemplateParameterList;
   class TemplatePartialOrderingContext;
   class TemplateTemplateParmDecl;
@@ -6155,120 +6157,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
@@ -6313,6 +6201,14 @@
   /// to implement it anywhere else.
   ActiveTemplateInstantiation LastTemplateInstantiationErrorContext;
 
+  /// \brief The template instantiation observer to trace or track 
+  /// instantiations (observers can be chained).
+  ///
+  /// This observer is used to print, trace or track template
+  /// instantiations as they are being constructed. For example, 
+  /// the 'templight' option is implemented with one such observer.
+  std::unique_ptr<TemplateInstantiationObserver> TemplateInstObserverChain;
+
   /// \brief The current index into pack expansion arguments that will be
   /// used for substitution of parameter packs.
   ///
Index: include/clang/Sema/TemplateInstObserver.h
===================================================================
--- include/clang/Sema/TemplateInstObserver.h	(revision 0)
+++ include/clang/Sema/TemplateInstObserver.h	(working copy)
@@ -0,0 +1,98 @@
+//===--- TemplateInstObserver.h - Template Instantiation Observer --------------*- 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 TemplateInstantiationObserver class, which is the base
+// class for an observer that will be notified (callback) at every template instantiation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TEMPLATE_INST_OBSERVER_H
+#define LLVM_CLANG_TEMPLATE_INST_OBSERVER_H
+
+#include "clang/Basic/SourceLocation.h"
+
+#include "llvm/Support/Compiler.h"
+#include <memory>
+
+namespace clang {
+  
+  class Sema;
+  class ActiveTemplateInstantiation;
+  
+/// \brief This is a base class for an observer that will be notified (callback) at every template instantiation.
+class TemplateInstantiationObserver {
+public:
+  
+  /// \brief Called before doing AST-parsing.
+  void initialize(const Sema &TheSema) {
+    this->initializeImpl(TheSema);
+    if ( NextObserver )
+      NextObserver->initialize(TheSema);
+  };
+  
+  /// \brief Called after AST-parsing is completed.
+  void finalize(const Sema &TheSema) {
+    this->finalizeImpl(TheSema);
+    if ( NextObserver )
+      NextObserver->finalize(TheSema);
+  };
+  
+  /// \brief Called when instantiation of a template just began.
+  void atTemplateBegin(const Sema &TheSema, const ActiveTemplateInstantiation &Inst) {
+    this->atTemplateBeginImpl(TheSema, Inst);
+    if ( NextObserver )
+      NextObserver->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 ( NextObserver )
+      NextObserver->atTemplateEnd(TheSema, Inst);
+  };
+  
+  virtual ~TemplateInstantiationObserver() { };
+  
+  /// \brief Appends a new observer to the end of this list.
+  /// \note This function uses a tail-call recursion (and is not performance-critical).
+  static void appendNewObserver(std::unique_ptr<TemplateInstantiationObserver>& CurrentChain,
+                                TemplateInstantiationObserver* NewObserver) {
+    if ( !CurrentChain ) {
+      CurrentChain.reset(NewObserver);
+      return;
+    };
+    appendNewObserver(CurrentChain->NextObserver, NewObserver);
+  };
+  
+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<TemplateInstantiationObserver> NextObserver;
+};
+
+
+
+}
+
+
+#endif
+
+
+
Index: lib/FrontendTool/ExecuteCompilerInvocation.cpp
===================================================================
--- lib/FrontendTool/ExecuteCompilerInvocation.cpp	(revision 219067)
+++ lib/FrontendTool/ExecuteCompilerInvocation.cpp	(working copy)
@@ -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<OptTable> Opts(driver::createDriverOptTable());
@@ -224,3 +226,5 @@
     BuryPointer(std::move(Act));
   return Success;
 }
+
+}
Index: lib/Parse/ParseAST.cpp
===================================================================
--- lib/Parse/ParseAST.cpp	(revision 219067)
+++ lib/Parse/ParseAST.cpp	(working copy)
@@ -23,6 +23,7 @@
 #include "clang/Sema/ExternalSemaSource.h"
 #include "clang/Sema/Sema.h"
 #include "clang/Sema/SemaConsumer.h"
+#include "clang/Sema/TemplateInstObserver.h"
 #include "llvm/Support/CrashRecoveryContext.h"
 #include <cstdio>
 #include <memory>
@@ -108,6 +109,11 @@
   bool OldCollectStats = PrintStats;
   std::swap(OldCollectStats, S.CollectStats);
 
+  // Initialize the template instantiation observer chain.
+  // FIXME: See note on "finalize" below.
+  if (S.TemplateInstObserverChain)
+    S.TemplateInstObserverChain->initialize(S);
+
   ASTConsumer *Consumer = &S.getASTConsumer();
 
   std::unique_ptr<Parser> ParseOP(
@@ -153,6 +159,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.TemplateInstObserverChain)
+    S.TemplateInstObserverChain->finalize(S);
+
   std::swap(OldCollectStats, S.CollectStats);
   if (PrintStats) {
     llvm::errs() << "\nSTATISTICS:\n";
Index: lib/Sema/ActiveTemplateInst.cpp
===================================================================
--- lib/Sema/ActiveTemplateInst.cpp	(revision 0)
+++ lib/Sema/ActiveTemplateInst.cpp	(working copy)
@@ -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	(revision 219067)
+++ lib/Sema/CMakeLists.txt	(working copy)
@@ -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	(revision 219067)
+++ lib/Sema/Sema.cpp	(working copy)
@@ -37,6 +37,7 @@
 #include "clang/Sema/ScopeInfo.h"
 #include "clang/Sema/SemaConsumer.h"
 #include "clang/Sema/TemplateDeduction.h"
+#include "clang/Sema/TemplateInstObserver.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	(revision 219067)
+++ lib/Sema/SemaTemplateInstantiate.cpp	(working copy)
@@ -23,6 +23,7 @@
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/Template.h"
 #include "clang/Sema/TemplateDeduction.h"
+#include "clang/Sema/TemplateInstObserver.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.TemplateInstObserverChain )
+      SemaRef.TemplateInstObserverChain->atTemplateBegin(SemaRef, Inst);
     if (!Inst.isInstantiationRecord())
       ++SemaRef.NonInstantiationEntries;
   }
@@ -364,6 +349,10 @@
       SemaRef.ActiveTemplateInstantiationLookupModules.pop_back();
     }
 
+    if ( SemaRef.TemplateInstObserverChain )
+      SemaRef.TemplateInstObserverChain->atTemplateEnd(
+        SemaRef, SemaRef.ActiveTemplateInstantiations.back());
+
     SemaRef.ActiveTemplateInstantiations.pop_back();
     Invalid = true;
   }
@@ -575,6 +564,9 @@
         << cast<FunctionDecl>(Active->Entity)
         << Active->InstantiationRange;
       break;
+
+    case ActiveTemplateInstantiation::Memoization:
+      break;
     }
   }
 }
@@ -615,6 +607,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	(revision 219067)
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp	(working copy)
@@ -22,6 +22,7 @@
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/PrettyDeclStackTrace.h"
 #include "clang/Sema/Template.h"
+#include "clang/Sema/TemplateInstObserver.h"
 
 using namespace clang;
 
@@ -3250,7 +3251,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) {
@@ -3259,8 +3260,12 @@
       assert(FunTmpl->getTemplatedDecl() == Tmpl &&
              "Deduction from the wrong function template?");
       (void) FunTmpl;
+      if ( SemaRef.TemplateInstObserverChain )
+        SemaRef.TemplateInstObserverChain->atTemplateEnd(SemaRef, ActiveInst);
       ActiveInst.Kind = ActiveInstType::TemplateInstantiation;
       ActiveInst.Entity = New;
+      if ( SemaRef.TemplateInstObserverChain )
+        SemaRef.TemplateInstObserverChain->atTemplateBegin(SemaRef, ActiveInst);
     }
   }
 
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp	(revision 219067)
+++ lib/Sema/SemaType.cpp	(working copy)
@@ -30,6 +30,7 @@
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/ScopeInfo.h"
 #include "clang/Sema/Template.h"
+#include "clang/Sema/TemplateInstObserver.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -5198,6 +5199,15 @@
       // Try to recover by implicitly importing this module.
       createImplicitModuleImportForErrorRecovery(Loc, Owner);
     }
+    else if (Def && TemplateInstObserverChain) {
+      ActiveTemplateInstantiation TempInst;
+      TempInst.Kind = ActiveTemplateInstantiation::Memoization;
+      TempInst.Template = Def;
+      TempInst.Entity = Def;
+      TempInst.PointOfInstantiation = Loc;
+      TemplateInstObserverChain->atTemplateBegin(*this, TempInst);
+      TemplateInstObserverChain->atTemplateEnd(*this, TempInst);
+    }
 
     // We lock in the inheritance model once somebody has asked us to ensure
     // that a pointer-to-member type is complete.


More information about the cfe-commits mailing list