summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-03-10 18:03:33 +0000
committerDouglas Gregor <dgregor@apple.com>2009-03-10 18:03:33 +0000
commit4ea568f213f4771bd2172113b24bec40db3cbf86 (patch)
tree7b9a7ecf00b65ddee861ec25e654d1d228329843
parent156506e749cd053506116146c74b6a7afeb5b01f (diff)
downloadbcm5719-llvm-4ea568f213f4771bd2172113b24bec40db3cbf86.tar.gz
bcm5719-llvm-4ea568f213f4771bd2172113b24bec40db3cbf86.zip
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. llvm-svn: 66557
-rw-r--r--clang/include/clang/Basic/Diagnostic.h72
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.def2
-rw-r--r--clang/lib/Basic/Diagnostic.cpp18
-rw-r--r--clang/lib/Sema/Sema.h8
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp24
-rw-r--r--clang/test/SemaTemplate/instantiation-backtrace.cpp16
-rw-r--r--clang/test/SemaTemplate/instantiation-depth.cpp5
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}}
}
OpenPOWER on IntegriCloud