From: Douglas Gregor
Date: Tue, 20 Apr 2010 07:18:24 +0000 (+0000)
Subject: Introduce a limit on the depth of the template instantiation backtrace
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=575cf3791216c33770ba950430493cdd43099f8f;p=clang
Introduce a limit on the depth of the template instantiation backtrace
we will print with each error that occurs during template
instantiation. When the backtrace is longer than that, we will print
N/2 of the innermost backtrace entries and N/2 of the outermost
backtrace entries, then skip the middle entries with a note such as:
note: suppressed 2 template instantiation contexts; use
-ftemplate-backtrace-limit=N to change the number of template
instantiation entries shown
This should eliminate some excessively long backtraces that aren't
providing any value.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101882 91177308-0d34-0410-b5e6-96231b3b80d8
---
diff --git a/docs/UsersManual.html b/docs/UsersManual.html
index f6651b1678..7d7f2631ab 100644
--- a/docs/UsersManual.html
+++ b/docs/UsersManual.html
@@ -193,6 +193,8 @@ introduces the language selection and other high level options like -c, -g, etc.
been produced. The default is 20, and the error limit can be disabled with
-ferror-limit=0.
+-ftemplate-backtrace-limit=123: Only emit up to 123 template instantiation notes within the template instantiation backtrace for a single warning or error. The default is 10, and the limit can be disabled with -ftemplate-backtrace-limit=0.
+
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index d6fb4c3ce7..bf94af6cb6 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -189,6 +189,8 @@ private:
bool SuppressSystemWarnings; // Suppress warnings in system headers.
bool SuppressAllDiagnostics; // Suppress all diagnostics.
unsigned ErrorLimit; // Cap of # errors emitted, 0 -> no limit.
+ unsigned TemplateBacktraceLimit; // Cap on depth of template backtrace stack,
+ // 0 -> no limit.
ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors?
DiagnosticClient *Client;
@@ -276,6 +278,18 @@ public:
/// emit before giving up. Zero disables the limit.
void setErrorLimit(unsigned Limit) { ErrorLimit = Limit; }
+ /// \brief Specify the maximum number of template instantiation
+ /// notes to emit along with a given diagnostic.
+ void setTemplateBacktraceLimit(unsigned Limit) {
+ TemplateBacktraceLimit = Limit;
+ }
+
+ /// \brief Retrieve the maximum number of template instantiation
+ /// nodes to emit along with a given diagnostic.
+ unsigned getTemplateBacktraceLimit() const {
+ return TemplateBacktraceLimit;
+ }
+
/// setIgnoreAllWarnings - When set to true, any unmapped warnings are
/// ignored. If this and WarningsAsErrors are both set, then this one wins.
void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; }
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 71e67270b5..0756ae5070 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1434,7 +1434,10 @@ def note_prior_template_arg_substitution : Note<
" template parameter%1 %2">;
def note_template_default_arg_checking : Note<
"while checking a default template argument used here">;
-
+def note_instantiation_contexts_suppressed : Note<
+ "suppressed %0 template instantiation context%s0; use -ftemplate-backtrace-"
+ "limit=N to change the number of template instantiation entries shown">;
+
def err_field_instantiates_to_function : Error<
"data member instantiated with function type %0">;
def err_nested_name_spec_non_tag : Error<
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index f910a8edc0..815fc1bcfb 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -200,6 +200,8 @@ def ftabstop : Separate<"-ftabstop">, MetaVarName<"">,
HelpText<"Set the tab stop distance.">;
def ferror_limit : Separate<"-ferror-limit">, MetaVarName<"">,
HelpText<"Set the maximum number of errors to emit before stopping (0 = no limit).">;
+def ftemplate_backtrace_limit : Separate<"-ftemplate-backtrace-limit">, MetaVarName<"">,
+ HelpText<"Set the maximum number of entries to print in a template instantiation backtrace (0 = no limit).">;
def fmessage_length : Separate<"-fmessage-length">, MetaVarName<"">,
HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">;
def fcolor_diagnostics : Flag<"-fcolor-diagnostics">,
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 41c06fe886..1487121208 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -366,6 +366,8 @@ def fsyntax_only : Flag<"-fsyntax-only">, Flags<[DriverOption]>;
def ftabstop_EQ : Joined<"-ftabstop=">, Group;
def ferror_limit_EQ : Joined<"-ferror-limit=">, Group;
def ftemplate_depth_ : Joined<"-ftemplate-depth-">, Group;
+def ftemplate_backtrace_limit_EQ : Joined<"-ftemplate-backtrace-limit=">,
+ Group;
def fterminated_vtables : Flag<"-fterminated-vtables">, Group;
def fthreadsafe_statics : Flag<"-fthreadsafe-statics">, Group;
def ftime_report : Flag<"-ftime-report">, Group;
diff --git a/include/clang/Frontend/DiagnosticOptions.h b/include/clang/Frontend/DiagnosticOptions.h
index d8ec14f9a3..797cb34023 100644
--- a/include/clang/Frontend/DiagnosticOptions.h
+++ b/include/clang/Frontend/DiagnosticOptions.h
@@ -39,7 +39,8 @@ public:
/// deserialized by, e.g., the CIndex library.
unsigned ErrorLimit; /// Limit # errors emitted.
-
+ unsigned TemplateBacktraceLimit; /// Limit depth of instantiation backtrace.
+
/// The distance between tab stops.
unsigned TabStop;
enum { DefaultTabStop = 8, MaxTabStop = 100 };
@@ -73,6 +74,7 @@ public:
VerifyDiagnostics = 0;
BinaryOutput = 0;
ErrorLimit = 0;
+ TemplateBacktraceLimit = 0;
}
};
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 755fbed66f..1870195ded 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -224,7 +224,8 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) {
ErrorOccurred = false;
FatalErrorOccurred = false;
ErrorLimit = 0;
-
+ TemplateBacktraceLimit = 0;
+
NumWarnings = 0;
NumErrors = 0;
NumErrorsSuppressed = 0;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index d9df471714..4653551a46 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1079,6 +1079,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue(Args));
else
CmdArgs.push_back("19");
+
+ CmdArgs.push_back("-ftemplate-backtrace-limit");
+ if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ))
+ CmdArgs.push_back(A->getValue(Args));
+ else
+ CmdArgs.push_back("10");
// Pass -fmessage-length=.
CmdArgs.push_back("-fmessage-length");
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 932481f87f..f9cfd73c7e 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -240,6 +240,11 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
Res.push_back("-ferror-limit");
Res.push_back(llvm::utostr(Opts.ErrorLimit));
}
+ if (Opts.TemplateBacktraceLimit != 10) {
+ Res.push_back("-ftemplate-backtrace-limit");
+ Res.push_back(llvm::utostr(Opts.TemplateBacktraceLimit));
+ }
+
if (Opts.TabStop != DiagnosticOptions::DefaultTabStop) {
Res.push_back("-ftabstop");
Res.push_back(llvm::utostr(Opts.TabStop));
@@ -857,6 +862,8 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
Opts.BinaryOutput = Args.hasArg(OPT_fdiagnostics_binary);
Opts.ErrorLimit = getLastArgIntValue(Args, OPT_ferror_limit, 0, Diags);
+ Opts.TemplateBacktraceLimit
+ = getLastArgIntValue(Args, OPT_ftemplate_backtrace_limit, 0, Diags);
Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop,
DiagnosticOptions::DefaultTabStop, Diags);
if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {
diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp
index 39cda8783b..84c4f5d40f 100644
--- a/lib/Frontend/Warnings.cpp
+++ b/lib/Frontend/Warnings.cpp
@@ -39,6 +39,8 @@ void clang::ProcessWarningOptions(Diagnostic &Diags,
// Handle -ferror-limit
if (Opts.ErrorLimit)
Diags.setErrorLimit(Opts.ErrorLimit);
+ if (Opts.TemplateBacktraceLimit)
+ Diags.setTemplateBacktraceLimit(Opts.TemplateBacktraceLimit);
// If -pedantic or -pedantic-errors was specified, then we want to map all
// extension diagnostics onto WARNING or ERROR unless the user has futz'd
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index e35d988dc8..abc8e5fb56 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -339,12 +339,32 @@ bool Sema::InstantiatingTemplate::CheckInstantiationDepth(
/// \brief Prints the current instantiation stack through a series of
/// notes.
void Sema::PrintInstantiationStack() {
+ // Determine which template instantiations to skip, if any.
+ unsigned SkipStart = ActiveTemplateInstantiations.size(), SkipEnd = SkipStart;
+ unsigned Limit = Diags.getTemplateBacktraceLimit();
+ if (Limit && Limit < ActiveTemplateInstantiations.size()) {
+ SkipStart = Limit / 2 + Limit % 2;
+ SkipEnd = ActiveTemplateInstantiations.size() - Limit / 2;
+ }
+
// FIXME: In all of these cases, we need to show the template arguments
+ unsigned InstantiationIdx = 0;
for (llvm::SmallVector::reverse_iterator
Active = ActiveTemplateInstantiations.rbegin(),
ActiveEnd = ActiveTemplateInstantiations.rend();
Active != ActiveEnd;
- ++Active) {
+ ++Active, ++InstantiationIdx) {
+ // Skip this instantiation?
+ if (InstantiationIdx >= SkipStart && InstantiationIdx < SkipEnd) {
+ if (InstantiationIdx == SkipStart) {
+ // Note that we're skipping instantiations.
+ Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+ diag::note_instantiation_contexts_suppressed)
+ << unsigned(ActiveTemplateInstantiations.size() - Limit);
+ }
+ continue;
+ }
+
switch (Active->Kind) {
case ActiveTemplateInstantiation::TemplateInstantiation: {
Decl *D = reinterpret_cast(Active->Entity);
diff --git a/test/SemaTemplate/instantiation-depth.cpp b/test/SemaTemplate/instantiation-depth.cpp
index f48ede9c44..20a5c2431b 100644
--- a/test/SemaTemplate/instantiation-depth.cpp
+++ b/test/SemaTemplate/instantiation-depth.cpp
@@ -1,8 +1,10 @@
-// RUN: %clang_cc1 -fsyntax-only -ftemplate-depth 5 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -ftemplate-depth 5 -ftemplate-backtrace-limit 4 %s
-template struct X : X { }; // expected-error{{recursive template instantiation exceeded maximum depth of 5}} \
-// expected-note{{use -ftemplate-depth-N to increase recursive template instantiation depth}} \
-// expected-note 5 {{instantiation of template class}}
+template struct X : X { }; \
+// expected-error{{recursive template instantiation exceeded maximum depth of 5}} \
+// expected-note 3 {{instantiation of template class}} \
+// expected-note {{suppressed 2 template instantiation contexts}} \
+// expected-note {{use -ftemplate-depth-N to increase recursive template instantiation depth}}
void test() {
(void)sizeof(X); // expected-note {{instantiation of template class}}