From 25a88bbf042317976f0d9cbfa87dfe89426e8393 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 20 Mar 2009 22:48:49 +0000 Subject: [PATCH] Eliminate post-diagnostic hooks. Instead, implement a Sema-specific variant of DiagnosticBuilder that emits the template instantiation backtrace when needed. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67413 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/Diagnostic.h | 85 +++++++--------------------- lib/Basic/Diagnostic.cpp | 10 ---- lib/Sema/Sema.cpp | 16 ++++++ lib/Sema/Sema.h | 32 ++++++++--- lib/Sema/SemaTemplateInstantiate.cpp | 8 --- 5 files changed, 60 insertions(+), 91 deletions(-) diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index 005c0c73cf..a9f87107ab 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -125,33 +125,6 @@ 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 @@ -363,9 +336,6 @@ 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 @@ -393,15 +363,6 @@ 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(); @@ -424,14 +385,13 @@ private: /// for example. class DiagnosticBuilder { mutable Diagnostic *DiagObj; - mutable unsigned NumArgs, NumRanges, NumCodeModificationHints, - NumPostDiagnosticHooks; + mutable unsigned NumArgs, NumRanges, NumCodeModificationHints; void operator=(const DiagnosticBuilder&); // DO NOT IMPLEMENT friend class Diagnostic; explicit DiagnosticBuilder(Diagnostic *diagObj) : DiagObj(diagObj), NumArgs(0), NumRanges(0), - NumCodeModificationHints(0), NumPostDiagnosticHooks(0) {} + NumCodeModificationHints(0) {} public: /// Copy constructor. When copied, this "takes" the diagnostic info from the @@ -439,19 +399,25 @@ public: DiagnosticBuilder(const DiagnosticBuilder &D) { DiagObj = D.DiagObj; D.DiagObj = 0; + NumArgs = D.NumArgs; + NumRanges = D.NumRanges; + NumCodeModificationHints = D.NumCodeModificationHints; } - - /// Destructor - The dtor emits the diagnostic. - ~DiagnosticBuilder() { - // If DiagObj is null, then its soul was stolen by the copy ctor. + + /// \brief Force the diagnostic builder to emit the diagnostic now. + /// + /// Once this function has been called, the DiagnosticBuilder object + /// should not be used again before it is destroyed. + void Emit() { + // If DiagObj is null, then its soul was stolen by the copy ctor + // or the user called Emit(). if (DiagObj == 0) return; - // When destroyed, the ~DiagnosticBuilder sets the final argument count into + // When emitting diagnostics, we set the final argument count into // the Diagnostic object. DiagObj->NumDiagArgs = NumArgs; DiagObj->NumDiagRanges = NumRanges; DiagObj->NumCodeModificationHints = NumCodeModificationHints; - DiagObj->NumPostDiagnosticHooks = NumPostDiagnosticHooks; // Process the diagnostic, sending the accumulated information to the // DiagnosticClient. @@ -459,7 +425,14 @@ public: // This diagnostic is no longer in flight. DiagObj->CurDiagID = ~0U; + + // This diagnostic is dead. + DiagObj = 0; } + + /// Destructor - The dtor emits the diagnostic if it hasn't already + /// been emitted. + ~DiagnosticBuilder() { Emit(); } /// Operator bool: conversion of DiagnosticBuilder to bool always returns /// true. This allows is to be used in boolean error contexts like: @@ -492,15 +465,6 @@ 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, @@ -551,13 +515,6 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, 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 /// diag::kind enum. This actually returns a new instance of DiagnosticBuilder /// which emits the diagnostics (through ProcessDiag) when it is destroyed. diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 97952a04f2..8c393c525e 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -221,8 +221,6 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) { ArgToStringFn = DummyArgToStringFn; ArgToStringCookie = 0; - - InPostDiagnosticHook = false; } Diagnostic::~Diagnostic() { @@ -411,15 +409,7 @@ void Diagnostic::ProcessDiag() { 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/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 992d3ecbee..9662c43bb3 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -295,3 +295,19 @@ NamedDecl *Sema::getCurFunctionOrMethodDecl() { return 0; } +Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { + this->Emit(); + + // If this is not a note, and we're in a template instantiation + // that is different from the last template instantiation where + // we emitted an error, print a template instantiation + // backtrace. + if (!SemaRef.Diags.isBuiltinNote(DiagID) && + !SemaRef.ActiveTemplateInstantiations.empty() && + SemaRef.ActiveTemplateInstantiations.back() + != SemaRef.LastTemplateInstantiationErrorContext) { + SemaRef.PrintInstantiationStack(); + SemaRef.LastTemplateInstantiationErrorContext + = SemaRef.ActiveTemplateInstantiations.back(); + } +} diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 2e019c9b7f..76c3b05aab 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -241,15 +241,30 @@ public: Diagnostic &getDiagnostics() const { return Diags; } SourceManager &getSourceManager() const { return SourceMgr; } - /// The primitive diagnostic helpers. - DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { + /// \brief Helper class that creates diagnostics with optional + /// template instantiation stacks. + /// + /// This class provides a wrapper around the basic DiagnosticBuilder + /// class that emits diagnostics. SemaDiagnosticBuilder is + /// responsible for emitting the diagnostic (as DiagnosticBuilder + /// does) and, if the diagnostic comes from inside a template + /// instantiation, printing the template instantiation stack as + /// well. + class SemaDiagnosticBuilder : public DiagnosticBuilder { + Sema &SemaRef; + unsigned DiagID; + + public: + SemaDiagnosticBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) + : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) { } + + ~SemaDiagnosticBuilder(); + }; + + /// \brief Emit a diagnostic. + SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { DiagnosticBuilder DB = Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID); - if (!Diags.isBuiltinNote(DiagID) && - !ActiveTemplateInstantiations.empty() && - ActiveTemplateInstantiations.back() - != LastTemplateInstantiationErrorContext) - DB << PostDiagnosticHook(PrintInstantiationStackHook, this); - return DB; + return SemaDiagnosticBuilder(DB, *this, DiagID); } virtual void DeleteExpr(ExprTy *E); @@ -1858,7 +1873,6 @@ public: operator=(const InstantiatingTemplate&); // not implemented }; - static void PrintInstantiationStackHook(unsigned DiagID, void *Cookie); void PrintInstantiationStack(); QualType InstantiateType(QualType T, const TemplateArgument *TemplateArgs, diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 10f9926b3e..e856e91ffc 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -93,14 +93,6 @@ bool Sema::InstantiatingTemplate::CheckInstantiationDepth( return true; } -/// \brief Post-diagnostic hook for printing the instantiation stack. -void Sema::PrintInstantiationStackHook(unsigned, void *Cookie) { - Sema &SemaRef = *static_cast(Cookie); - SemaRef.PrintInstantiationStack(); - SemaRef.LastTemplateInstantiationErrorContext - = SemaRef.ActiveTemplateInstantiations.back(); -} - /// \brief Prints the current instantiation stack through a series of /// notes. void Sema::PrintInstantiationStack() { -- 2.40.0