summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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