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.

+

Formatting of Diagnostics

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}}