diff options
-rw-r--r-- | clang/include/clang/Basic/Diagnostic.h | 72 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.def | 2 | ||||
-rw-r--r-- | clang/lib/Basic/Diagnostic.cpp | 18 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 8 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 24 | ||||
-rw-r--r-- | clang/test/SemaTemplate/instantiation-backtrace.cpp | 16 | ||||
-rw-r--r-- | clang/test/SemaTemplate/instantiation-depth.cpp | 5 |
7 files changed, 136 insertions, 9 deletions
diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h index 1bb294e7a48..3675e69212c 100644 --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/include/clang/Basic/Diagnostic.h @@ -123,6 +123,33 @@ public: } }; +/// \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 @@ public: ak_declarationname, // DeclarationName ak_nameddecl // NamedDecl * }; - + private: bool IgnoreAllWarnings; // Ignore all warnings: -w bool WarningsAsErrors; // Treat warnings like errors: @@ -282,6 +309,10 @@ public: /// 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 @@ private: /// \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 @@ private: /// 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 @@ private: /// 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 @@ public: 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 @@ public: "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 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, 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 diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.def b/clang/include/clang/Basic/DiagnosticSemaKinds.def index 543391f292f..dbba5ab18ab 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.def +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.def @@ -647,6 +647,8 @@ DIAG(note_template_recursion_depth, NOTE, "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") diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp index 893eae5d1a9..fa5ca57dfe6 100644 --- a/clang/lib/Basic/Diagnostic.cpp +++ b/clang/lib/Basic/Diagnostic.cpp @@ -201,6 +201,8 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) { ArgToStringFn = DummyArgToStringFn; ArgToStringCookie = 0; + + InPostDiagnosticHook = false; } Diagnostic::~Diagnostic() { @@ -225,6 +227,12 @@ bool Diagnostic::isBuiltinWarningOrExtension(unsigned DiagID) { 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 @@ void Diagnostic::ProcessDiag() { // 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; } diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 1acd6b2a85c..c662301da34 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -242,7 +242,10 @@ public: /// 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 @@ public: 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); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 0990057df4f..4a12b077666 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -21,6 +21,10 @@ using namespace clang; +//===----------------------------------------------------------------------===/ +// Template Instantiation Support +//===----------------------------------------------------------------------===/ + Sema::InstantiatingTemplate:: InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *Entity, @@ -50,6 +54,26 @@ Sema::InstantiatingTemplate::~InstantiatingTemplate() { 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 //===----------------------------------------------------------------------===/ diff --git a/clang/test/SemaTemplate/instantiation-backtrace.cpp b/clang/test/SemaTemplate/instantiation-backtrace.cpp new file mode 100644 index 00000000000..4c8ea13a8d7 --- /dev/null +++ b/clang/test/SemaTemplate/instantiation-backtrace.cpp @@ -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}} +} diff --git a/clang/test/SemaTemplate/instantiation-depth.cpp b/clang/test/SemaTemplate/instantiation-depth.cpp index 3b8acf20dd1..25c40fce4d1 100644 --- a/clang/test/SemaTemplate/instantiation-depth.cpp +++ b/clang/test/SemaTemplate/instantiation-depth.cpp @@ -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}} } |