[cfe-commits] r66557 - in /cfe/trunk: include/clang/Basic/Diagnostic.h include/clang/Basic/DiagnosticSemaKinds.def lib/Basic/Diagnostic.cpp lib/Sema/Sema.h lib/Sema/SemaTemplateInstantiate.cpp test/SemaTemplate/instantiation-backtrace.cpp test/SemaTemplate/instantiation-depth.cpp

Douglas Gregor dgregor at apple.com
Tue Mar 10 11:03:33 PDT 2009


Author: dgregor
Date: Tue Mar 10 13:03:33 2009
New Revision: 66557

URL: http://llvm.org/viewvc/llvm-project?rev=66557&view=rev
Log:
Add a notion of "post-diagnostic hooks", which are callbacks attached
to a diagnostic that will be invoked after the diagnostic (if it is
not suppressed). The hooks are allowed to produce additional
diagnostics (typically notes) that provide more information. We should
be able to use this to help diagnostic clients link notes back to the
diagnostic they clarify. Comments welcome; I'll write up documentation
and convert other clients (e.g., overload resolution failures) if
there are no screams of protest.

As the first client of post-diagnostic hooks, we now produce a
template instantiation backtrace when a failure occurs during template
instantiation. There's still more work to do to make this output
pretty, if that's even possible.



Added:
    cfe/trunk/test/SemaTemplate/instantiation-backtrace.cpp
Modified:
    cfe/trunk/include/clang/Basic/Diagnostic.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
    cfe/trunk/lib/Basic/Diagnostic.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/test/SemaTemplate/instantiation-depth.cpp

Modified: cfe/trunk/include/clang/Basic/Diagnostic.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Diagnostic.h?rev=66557&r1=66556&r2=66557&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/Diagnostic.h (original)
+++ cfe/trunk/include/clang/Basic/Diagnostic.h Tue Mar 10 13:03:33 2009
@@ -123,6 +123,33 @@
   }
 };
 
+/// \brief A hook function that will be invoked after we have
+/// completed processing of the current diagnostic.
+///
+/// Hook functions are typically used to emit further diagnostics
+/// (typically notes) that give more information about this
+/// diagnostic.
+struct PostDiagnosticHook {
+  /// \brief The type of the hook function itself.
+  ///
+  /// DiagID is the ID of the diagnostic to which the hook was
+  /// attached, and Cookie is a user-specified value that can be used
+  /// to store extra data for the hook.
+  typedef void (*HookTy)(unsigned DiagID, void *Cookie);
+
+  PostDiagnosticHook() {}
+
+  PostDiagnosticHook(HookTy Hook, void *Cookie) : Hook(Hook), Cookie(Cookie) {
+    assert(Hook && "No hook provided!");
+  }
+
+  /// \brief The hook function.
+  HookTy Hook;
+
+  /// \brief The cookie that will be passed along to the hook function.
+  void *Cookie;
+};
+
 /// Diagnostic - This concrete class is used by the front-end to report
 /// problems and issues.  It massages the diagnostics (e.g. handling things like
 /// "report warnings as errors" and passes them off to the DiagnosticClient for
@@ -144,7 +171,7 @@
     ak_declarationname, // DeclarationName
     ak_nameddecl        // NamedDecl *
   };
-  
+
 private:  
   bool IgnoreAllWarnings;     // Ignore all warnings: -w
   bool WarningsAsErrors;      // Treat warnings like errors: 
@@ -282,6 +309,10 @@
   /// call on NOTEs.
   static bool isBuiltinWarningOrExtension(unsigned DiagID);
 
+  /// \brief Determine whether the given built-in diagnostic ID is a
+  /// Note.
+  static bool isBuiltinNote(unsigned DiagID);
+
   /// getDiagnosticLevel - Based on the way the client configured the Diagnostic
   /// object, classify the specified diagnostic ID into a Level, consumable by
   /// the DiagnosticClient.
@@ -330,7 +361,10 @@
   /// \brief The number of code modifications hints in the
   /// CodeModificationHints array.
   unsigned char NumCodeModificationHints;
-  
+  /// \brief The number of post-diagnostic hooks in the
+  /// PostDiagnosticHooks array.
+  unsigned char NumPostDiagnosticHooks;
+
   /// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum
   /// values, with one for each argument.  This specifies whether the argument
   /// is in DiagArgumentsStr or in DiagArguments.
@@ -357,6 +391,15 @@
   /// to insert, remove, or modify at a particular position.
   CodeModificationHint CodeModificationHints[MaxCodeModificationHints];
 
+  enum { MaxPostDiagnosticHooks = 10 };
+  
+  /// \brief Functions that will be invoked after the diagnostic has
+  /// been emitted.
+  PostDiagnosticHook PostDiagnosticHooks[MaxPostDiagnosticHooks];
+
+  /// \brief Whether we're already within a post-diagnostic hook.
+  bool InPostDiagnosticHook;
+
   /// ProcessDiag - This is the method used to report a diagnostic that is
   /// finally fully formed.
   void ProcessDiag();
@@ -379,15 +422,16 @@
 /// for example.
 class DiagnosticBuilder {
   mutable Diagnostic *DiagObj;
-  mutable unsigned NumArgs, NumRanges, NumCodeModificationHints;
+  mutable unsigned NumArgs, NumRanges, NumCodeModificationHints, 
+                   NumPostDiagnosticHooks;
   
   void operator=(const DiagnosticBuilder&); // DO NOT IMPLEMENT
   friend class Diagnostic;
   explicit DiagnosticBuilder(Diagnostic *diagObj)
     : DiagObj(diagObj), NumArgs(0), NumRanges(0), 
-      NumCodeModificationHints(0) {}
-public:
-  
+      NumCodeModificationHints(0), NumPostDiagnosticHooks(0) {}
+
+public:  
   /// Copy constructor.  When copied, this "takes" the diagnostic info from the
   /// input and neuters it.
   DiagnosticBuilder(const DiagnosticBuilder &D) {
@@ -405,6 +449,7 @@
     DiagObj->NumDiagArgs = NumArgs;
     DiagObj->NumDiagRanges = NumRanges;
     DiagObj->NumCodeModificationHints = NumCodeModificationHints;
+    DiagObj->NumPostDiagnosticHooks = NumPostDiagnosticHooks;
 
     // Process the diagnostic, sending the accumulated information to the
     // DiagnosticClient.
@@ -445,6 +490,15 @@
            "Too many code modification hints!");
     DiagObj->CodeModificationHints[NumCodeModificationHints++] = Hint;
   }
+
+  void AddPostDiagnosticHook(const PostDiagnosticHook &Hook) const {
+    assert(!DiagObj->InPostDiagnosticHook &&
+           "Can't add a post-diagnostic hook to a diagnostic inside "
+           "a post-diagnostic hook");
+    assert(NumPostDiagnosticHooks < Diagnostic::MaxPostDiagnosticHooks &&
+           "Too many post-diagnostic hooks");
+    DiagObj->PostDiagnosticHooks[NumPostDiagnosticHooks++] = Hook;
+  }
 };
 
 inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
@@ -494,6 +548,12 @@
   DB.AddCodeModificationHint(Hint);
   return DB;
 }
+
+inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+                                           const PostDiagnosticHook &Hook) {
+  DB.AddPostDiagnosticHook(Hook);
+  return DB;
+}
   
 
 /// Report - Issue the message to the client.  DiagID is a member of the

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def?rev=66557&r1=66556&r2=66557&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def Tue Mar 10 13:03:33 2009
@@ -647,6 +647,8 @@
      "instantiation depth")
 DIAG(err_template_implicit_instantiate_undefined, ERROR,
      "implicit instantiation of undefined template %0")
+DIAG(note_template_class_instantiation_here, NOTE,
+     "in instantiation of template class %0 requested here")
 
 DIAG(err_unexpected_typedef, ERROR,
      "unexpected type name %0: expected expression")

Modified: cfe/trunk/lib/Basic/Diagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Diagnostic.cpp?rev=66557&r1=66556&r2=66557&view=diff

==============================================================================
--- cfe/trunk/lib/Basic/Diagnostic.cpp (original)
+++ cfe/trunk/lib/Basic/Diagnostic.cpp Tue Mar 10 13:03:33 2009
@@ -201,6 +201,8 @@
   
   ArgToStringFn = DummyArgToStringFn;
   ArgToStringCookie = 0;
+
+  InPostDiagnosticHook = false;
 }
 
 Diagnostic::~Diagnostic() {
@@ -225,6 +227,12 @@
   return DiagID < diag::DIAG_UPPER_LIMIT && getBuiltinDiagClass(DiagID) < ERROR;
 }
 
+/// \brief Determine whether the given built-in diagnostic ID is a
+/// Note.
+bool Diagnostic::isBuiltinNote(unsigned DiagID) {
+  return DiagID < diag::DIAG_UPPER_LIMIT && getBuiltinDiagClass(DiagID) == NOTE;
+}
+
 
 /// getDescription - Given a diagnostic ID, return a description of the
 /// issue.
@@ -373,6 +381,16 @@
   // Finally, report it.
   Client->HandleDiagnostic(DiagLevel, Info);
   if (Client->IncludeInDiagnosticCounts()) ++NumDiagnostics;
+
+  // Invoke any post-diagnostic hooks.
+  unsigned LastDiag = CurDiagID;
+  CurDiagID = ~0U;
+  
+  InPostDiagnosticHook = true;
+  for (unsigned Hook = 0; Hook < NumPostDiagnosticHooks; ++Hook)
+    PostDiagnosticHooks[Hook].Hook(LastDiag, 
+                                   PostDiagnosticHooks[Hook].Cookie);
+  InPostDiagnosticHook = false;
 }
 
 

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=66557&r1=66556&r2=66557&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Mar 10 13:03:33 2009
@@ -242,7 +242,10 @@
 
   /// The primitive diagnostic helpers.
   DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) {
-    return Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID);
+    DiagnosticBuilder DB = Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID);
+    if (!Diags.isBuiltinNote(DiagID) && !ActiveTemplateInstantiations.empty())
+      DB << PostDiagnosticHook(PrintInstantiationStackHook, this);
+    return DB;
   }
 
   virtual void DeleteExpr(ExprTy *E);
@@ -1719,6 +1722,9 @@
     operator=(const InstantiatingTemplate&); // not implemented
   };
 
+  static void PrintInstantiationStackHook(unsigned DiagID, void *Cookie);
+  void PrintInstantiationStack();
+
   QualType InstantiateType(QualType T, const TemplateArgument *TemplateArgs,
                            unsigned NumTemplateArgs,
                            SourceLocation Loc, DeclarationName Entity);

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=66557&r1=66556&r2=66557&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Tue Mar 10 13:03:33 2009
@@ -21,6 +21,10 @@
 
 using namespace clang;
 
+//===----------------------------------------------------------------------===/
+// Template Instantiation Support
+//===----------------------------------------------------------------------===/
+
 Sema::InstantiatingTemplate::
 InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
                       ClassTemplateSpecializationDecl *Entity,
@@ -50,6 +54,26 @@
     SemaRef.ActiveTemplateInstantiations.pop_back();
 }
 
+/// \brief Post-diagnostic hook for printing the instantiation stack.
+void Sema::PrintInstantiationStackHook(unsigned, void *Cookie) {
+  static_cast<Sema*>(Cookie)->PrintInstantiationStack();
+}
+
+/// \brief Prints the current instantiation stack through a series of
+/// notes.
+void Sema::PrintInstantiationStack() {
+  for (llvm::SmallVector<ActiveTemplateInstantiation, 16>::reverse_iterator
+         Active = ActiveTemplateInstantiations.rbegin(),
+         ActiveEnd = ActiveTemplateInstantiations.rend();
+       Active != ActiveEnd;
+       ++Active) {
+    Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), 
+                 diag::note_template_class_instantiation_here)
+      << Context.getTypeDeclType(Active->Entity)
+      << Active->InstantiationRange;
+  }
+}
+
 //===----------------------------------------------------------------------===/
 // Template Instantiation for Types
 //===----------------------------------------------------------------------===/

Added: cfe/trunk/test/SemaTemplate/instantiation-backtrace.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiation-backtrace.cpp?rev=66557&view=auto

==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiation-backtrace.cpp (added)
+++ cfe/trunk/test/SemaTemplate/instantiation-backtrace.cpp Tue Mar 10 13:03:33 2009
@@ -0,0 +1,16 @@
+// RUN: clang -fsyntax-only -verify %s
+template<typename T> struct A; // expected-note{{template is declared here}}
+
+template<typename T> struct B : A<T*> { }; // expected-error{{implicit instantiation of undefined template}}
+
+template<typename T> struct C : B<T> { } ; // expected-note{{instantiation of template class}}
+
+template<typename T> struct D : C<T> { }; // expected-note{{instantiation of template class}}
+
+template<typename T> struct E : D<T> { }; // expected-note{{instantiation of template class}}
+
+template<typename T> struct F : E<T(T)> { }; // expected-note{{instantiation of template class}}
+
+void f() {
+ (void)sizeof(F<int>); // expected-note{{instantiation of template class}}
+}

Modified: cfe/trunk/test/SemaTemplate/instantiation-depth.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiation-depth.cpp?rev=66557&r1=66556&r2=66557&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiation-depth.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiation-depth.cpp Tue Mar 10 13:03:33 2009
@@ -1,8 +1,9 @@
 // RUN: clang -fsyntax-only -ftemplate-depth=5 -verify %s
 
 template<typename T> struct X : X<T*> { }; // expected-error{{recursive template instantiation exceeded maximum depth of 5}} \
-// expected-note{{use -ftemplate-depth=N to increase recursive template instantiation depth}}
+// expected-note{{use -ftemplate-depth=N to increase recursive template instantiation depth}} \
+// expected-note 5 {{instantiation of template class}}
 
 void test() { 
-  (void)sizeof(X<int>);
+  (void)sizeof(X<int>); // expected-note {{instantiation of template class}}
 }





More information about the cfe-commits mailing list