forked from OSchip/llvm-project
Introduce a limit on the depth of the macro instantiation backtrace
printed in a diagnostic, similar to the limit we already have on the depth of the template instantiation backtrace. The macro instantiation backtrace is limited to 10 "instantiated from:" diagnostics; when it's longer than that, we'll show the first half, then say how many were suppressed, then show the second half. The limit can be changed with -fmacro-instantiation-limit=N, and turned off with N=0. This eliminates a lot of note spew with libraries making use of the Boost.Preprocess library. llvm-svn: 103014
This commit is contained in:
parent
a5c0cc329e
commit
cd121fb013
|
@ -283,13 +283,13 @@ public:
|
||||||
void setTemplateBacktraceLimit(unsigned Limit) {
|
void setTemplateBacktraceLimit(unsigned Limit) {
|
||||||
TemplateBacktraceLimit = Limit;
|
TemplateBacktraceLimit = Limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Retrieve the maximum number of template instantiation
|
/// \brief Retrieve the maximum number of template instantiation
|
||||||
/// nodes to emit along with a given diagnostic.
|
/// nodes to emit along with a given diagnostic.
|
||||||
unsigned getTemplateBacktraceLimit() const {
|
unsigned getTemplateBacktraceLimit() const {
|
||||||
return TemplateBacktraceLimit;
|
return TemplateBacktraceLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// setIgnoreAllWarnings - When set to true, any unmapped warnings are
|
/// setIgnoreAllWarnings - When set to true, any unmapped warnings are
|
||||||
/// ignored. If this and WarningsAsErrors are both set, then this one wins.
|
/// ignored. If this and WarningsAsErrors are both set, then this one wins.
|
||||||
void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; }
|
void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; }
|
||||||
|
|
|
@ -1457,7 +1457,7 @@ def note_template_default_arg_checking : Note<
|
||||||
"while checking a default template argument used here">;
|
"while checking a default template argument used here">;
|
||||||
def note_instantiation_contexts_suppressed : Note<
|
def note_instantiation_contexts_suppressed : Note<
|
||||||
"(skipping %0 context%s0 in backtrace; use -ftemplate-backtrace-limit=0 to "
|
"(skipping %0 context%s0 in backtrace; use -ftemplate-backtrace-limit=0 to "
|
||||||
"see all)">;
|
"see all)">;
|
||||||
|
|
||||||
def err_field_instantiates_to_function : Error<
|
def err_field_instantiates_to_function : Error<
|
||||||
"data member instantiated with function type %0">;
|
"data member instantiated with function type %0">;
|
||||||
|
|
|
@ -200,6 +200,8 @@ def ftabstop : Separate<"-ftabstop">, MetaVarName<"<N>">,
|
||||||
HelpText<"Set the tab stop distance.">;
|
HelpText<"Set the tab stop distance.">;
|
||||||
def ferror_limit : Separate<"-ferror-limit">, MetaVarName<"<N>">,
|
def ferror_limit : Separate<"-ferror-limit">, MetaVarName<"<N>">,
|
||||||
HelpText<"Set the maximum number of errors to emit before stopping (0 = no limit).">;
|
HelpText<"Set the maximum number of errors to emit before stopping (0 = no limit).">;
|
||||||
|
def fmacro_backtrace_limit : Separate<"-fmacro-backtrace-limit">, MetaVarName<"<N>">,
|
||||||
|
HelpText<"Set the maximum number of entries to print in a macro instantiation backtrace (0 = no limit).">;
|
||||||
def ftemplate_backtrace_limit : Separate<"-ftemplate-backtrace-limit">, MetaVarName<"<N>">,
|
def ftemplate_backtrace_limit : Separate<"-ftemplate-backtrace-limit">, MetaVarName<"<N>">,
|
||||||
HelpText<"Set the maximum number of entries to print in a template instantiation backtrace (0 = no limit).">;
|
HelpText<"Set the maximum number of entries to print in a template instantiation backtrace (0 = no limit).">;
|
||||||
def fmessage_length : Separate<"-fmessage-length">, MetaVarName<"<N>">,
|
def fmessage_length : Separate<"-fmessage-length">, MetaVarName<"<N>">,
|
||||||
|
|
|
@ -280,6 +280,8 @@ def flat__namespace : Flag<"-flat_namespace">;
|
||||||
def flax_vector_conversions : Flag<"-flax-vector-conversions">, Group<f_Group>;
|
def flax_vector_conversions : Flag<"-flax-vector-conversions">, Group<f_Group>;
|
||||||
def flimited_precision_EQ : Joined<"-flimited-precision=">, Group<f_Group>;
|
def flimited_precision_EQ : Joined<"-flimited-precision=">, Group<f_Group>;
|
||||||
def flto : Flag<"-flto">, Group<f_Group>;
|
def flto : Flag<"-flto">, Group<f_Group>;
|
||||||
|
def fmacro_backtrace_limit_EQ : Joined<"-fmacro-backtrace-limit=">,
|
||||||
|
Group<f_Group>;
|
||||||
def fmath_errno : Flag<"-fmath-errno">, Group<f_Group>;
|
def fmath_errno : Flag<"-fmath-errno">, Group<f_Group>;
|
||||||
def fmerge_all_constants : Flag<"-fmerge-all-constants">, Group<f_Group>;
|
def fmerge_all_constants : Flag<"-fmerge-all-constants">, Group<f_Group>;
|
||||||
def fmessage_length_EQ : Joined<"-fmessage-length=">, Group<f_Group>;
|
def fmessage_length_EQ : Joined<"-fmessage-length=">, Group<f_Group>;
|
||||||
|
|
|
@ -39,11 +39,15 @@ public:
|
||||||
/// deserialized by, e.g., the CIndex library.
|
/// deserialized by, e.g., the CIndex library.
|
||||||
|
|
||||||
unsigned ErrorLimit; /// Limit # errors emitted.
|
unsigned ErrorLimit; /// Limit # errors emitted.
|
||||||
|
unsigned MacroBacktraceLimit; /// Limit depth of macro instantiation
|
||||||
|
/// backtrace.
|
||||||
unsigned TemplateBacktraceLimit; /// Limit depth of instantiation backtrace.
|
unsigned TemplateBacktraceLimit; /// Limit depth of instantiation backtrace.
|
||||||
|
|
||||||
/// The distance between tab stops.
|
/// The distance between tab stops.
|
||||||
unsigned TabStop;
|
unsigned TabStop;
|
||||||
enum { DefaultTabStop = 8, MaxTabStop = 100 };
|
enum { DefaultTabStop = 8, MaxTabStop = 100,
|
||||||
|
DefaultMacroBacktraceLimit = 6,
|
||||||
|
DefaultTemplateBacktraceLimit = 10 };
|
||||||
|
|
||||||
/// Column limit for formatting message diagnostics, or 0 if unused.
|
/// Column limit for formatting message diagnostics, or 0 if unused.
|
||||||
unsigned MessageLength;
|
unsigned MessageLength;
|
||||||
|
@ -75,6 +79,7 @@ public:
|
||||||
BinaryOutput = 0;
|
BinaryOutput = 0;
|
||||||
ErrorLimit = 0;
|
ErrorLimit = 0;
|
||||||
TemplateBacktraceLimit = 0;
|
TemplateBacktraceLimit = 0;
|
||||||
|
MacroBacktraceLimit = 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -71,12 +71,15 @@ public:
|
||||||
const SourceManager &SM,
|
const SourceManager &SM,
|
||||||
const FixItHint *Hints,
|
const FixItHint *Hints,
|
||||||
unsigned NumHints,
|
unsigned NumHints,
|
||||||
unsigned Columns);
|
unsigned Columns,
|
||||||
|
unsigned OnMacroInst,
|
||||||
|
unsigned MacroSkipStart,
|
||||||
|
unsigned MacroSkipEnd);
|
||||||
|
|
||||||
virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
|
virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
|
||||||
const DiagnosticInfo &Info);
|
const DiagnosticInfo &Info);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namspace clang
|
} // end namespace clang
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "clang/Driver/Options.h"
|
#include "clang/Driver/Options.h"
|
||||||
#include "clang/Driver/ToolChain.h"
|
#include "clang/Driver/ToolChain.h"
|
||||||
#include "clang/Driver/Util.h"
|
#include "clang/Driver/Util.h"
|
||||||
|
#include "clang/Frontend/DiagnosticOptions.h"
|
||||||
|
|
||||||
#include "llvm/ADT/SmallString.h"
|
#include "llvm/ADT/SmallString.h"
|
||||||
#include "llvm/ADT/StringSwitch.h"
|
#include "llvm/ADT/StringSwitch.h"
|
||||||
|
@ -1082,11 +1083,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
||||||
else
|
else
|
||||||
CmdArgs.push_back("19");
|
CmdArgs.push_back("19");
|
||||||
|
|
||||||
|
CmdArgs.push_back("-fmacro-backtrace-limit");
|
||||||
|
if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ))
|
||||||
|
CmdArgs.push_back(A->getValue(Args));
|
||||||
|
else
|
||||||
|
CmdArgs.push_back(Args.MakeArgString(
|
||||||
|
llvm::Twine(DiagnosticOptions::DefaultMacroBacktraceLimit)));
|
||||||
|
|
||||||
CmdArgs.push_back("-ftemplate-backtrace-limit");
|
CmdArgs.push_back("-ftemplate-backtrace-limit");
|
||||||
if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ))
|
if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ))
|
||||||
CmdArgs.push_back(A->getValue(Args));
|
CmdArgs.push_back(A->getValue(Args));
|
||||||
else
|
else
|
||||||
CmdArgs.push_back("10");
|
CmdArgs.push_back(Args.MakeArgString(
|
||||||
|
llvm::Twine(DiagnosticOptions::DefaultTemplateBacktraceLimit)));
|
||||||
|
|
||||||
// Pass -fmessage-length=.
|
// Pass -fmessage-length=.
|
||||||
CmdArgs.push_back("-fmessage-length");
|
CmdArgs.push_back("-fmessage-length");
|
||||||
|
|
|
@ -247,7 +247,13 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
|
||||||
Res.push_back("-ferror-limit");
|
Res.push_back("-ferror-limit");
|
||||||
Res.push_back(llvm::utostr(Opts.ErrorLimit));
|
Res.push_back(llvm::utostr(Opts.ErrorLimit));
|
||||||
}
|
}
|
||||||
if (Opts.TemplateBacktraceLimit != 10) {
|
if (Opts.MacroBacktraceLimit
|
||||||
|
!= DiagnosticOptions::DefaultMacroBacktraceLimit) {
|
||||||
|
Res.push_back("-fmacro-backtrace-limit");
|
||||||
|
Res.push_back(llvm::utostr(Opts.MacroBacktraceLimit));
|
||||||
|
}
|
||||||
|
if (Opts.TemplateBacktraceLimit
|
||||||
|
!= DiagnosticOptions::DefaultTemplateBacktraceLimit) {
|
||||||
Res.push_back("-ftemplate-backtrace-limit");
|
Res.push_back("-ftemplate-backtrace-limit");
|
||||||
Res.push_back(llvm::utostr(Opts.TemplateBacktraceLimit));
|
Res.push_back(llvm::utostr(Opts.TemplateBacktraceLimit));
|
||||||
}
|
}
|
||||||
|
@ -877,8 +883,13 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
|
||||||
Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
|
Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
|
||||||
Opts.BinaryOutput = Args.hasArg(OPT_fdiagnostics_binary);
|
Opts.BinaryOutput = Args.hasArg(OPT_fdiagnostics_binary);
|
||||||
Opts.ErrorLimit = getLastArgIntValue(Args, OPT_ferror_limit, 0, Diags);
|
Opts.ErrorLimit = getLastArgIntValue(Args, OPT_ferror_limit, 0, Diags);
|
||||||
|
Opts.MacroBacktraceLimit
|
||||||
|
= getLastArgIntValue(Args, OPT_fmacro_backtrace_limit,
|
||||||
|
DiagnosticOptions::DefaultMacroBacktraceLimit, Diags);
|
||||||
Opts.TemplateBacktraceLimit
|
Opts.TemplateBacktraceLimit
|
||||||
= getLastArgIntValue(Args, OPT_ftemplate_backtrace_limit, 0, Diags);
|
= getLastArgIntValue(Args, OPT_ftemplate_backtrace_limit,
|
||||||
|
DiagnosticOptions::DefaultTemplateBacktraceLimit,
|
||||||
|
Diags);
|
||||||
Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop,
|
Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop,
|
||||||
DiagnosticOptions::DefaultTabStop, Diags);
|
DiagnosticOptions::DefaultTabStop, Diags);
|
||||||
if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {
|
if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {
|
||||||
|
|
|
@ -285,7 +285,10 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
|
||||||
const SourceManager &SM,
|
const SourceManager &SM,
|
||||||
const FixItHint *Hints,
|
const FixItHint *Hints,
|
||||||
unsigned NumHints,
|
unsigned NumHints,
|
||||||
unsigned Columns) {
|
unsigned Columns,
|
||||||
|
unsigned OnMacroInst,
|
||||||
|
unsigned MacroSkipStart,
|
||||||
|
unsigned MacroSkipEnd) {
|
||||||
assert(LangOpts && "Unexpected diagnostic outside source file processing");
|
assert(LangOpts && "Unexpected diagnostic outside source file processing");
|
||||||
assert(!Loc.isInvalid() && "must have a valid source location here");
|
assert(!Loc.isInvalid() && "must have a valid source location here");
|
||||||
|
|
||||||
|
@ -293,10 +296,16 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
|
||||||
// instantiated (recursively) then emit information about where the token was
|
// instantiated (recursively) then emit information about where the token was
|
||||||
// spelled from.
|
// spelled from.
|
||||||
if (!Loc.isFileID()) {
|
if (!Loc.isFileID()) {
|
||||||
|
// Whether to suppress printing this macro instantiation.
|
||||||
|
bool Suppressed
|
||||||
|
= OnMacroInst >= MacroSkipStart && OnMacroInst < MacroSkipEnd;
|
||||||
|
|
||||||
|
|
||||||
SourceLocation OneLevelUp = SM.getImmediateInstantiationRange(Loc).first;
|
SourceLocation OneLevelUp = SM.getImmediateInstantiationRange(Loc).first;
|
||||||
// FIXME: Map ranges?
|
// FIXME: Map ranges?
|
||||||
EmitCaretDiagnostic(OneLevelUp, Ranges, NumRanges, SM, 0, 0, Columns);
|
EmitCaretDiagnostic(OneLevelUp, Ranges, NumRanges, SM, 0, 0, Columns,
|
||||||
|
OnMacroInst + 1, MacroSkipStart, MacroSkipEnd);
|
||||||
|
|
||||||
// Map the location.
|
// Map the location.
|
||||||
Loc = SM.getImmediateSpellingLoc(Loc);
|
Loc = SM.getImmediateSpellingLoc(Loc);
|
||||||
|
|
||||||
|
@ -308,26 +317,38 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
|
||||||
Ranges[i] = SourceRange(S, E);
|
Ranges[i] = SourceRange(S, E);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the pretty name, according to #line directives etc.
|
if (!Suppressed) {
|
||||||
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
|
// Get the pretty name, according to #line directives etc.
|
||||||
|
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
|
||||||
|
|
||||||
// If this diagnostic is not in the main file, print out the "included from"
|
// If this diagnostic is not in the main file, print out the
|
||||||
// lines.
|
// "included from" lines.
|
||||||
if (LastWarningLoc != PLoc.getIncludeLoc()) {
|
if (LastWarningLoc != PLoc.getIncludeLoc()) {
|
||||||
LastWarningLoc = PLoc.getIncludeLoc();
|
LastWarningLoc = PLoc.getIncludeLoc();
|
||||||
PrintIncludeStack(LastWarningLoc, SM);
|
PrintIncludeStack(LastWarningLoc, SM);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DiagOpts->ShowLocation) {
|
||||||
|
// Emit the file/line/column that this expansion came from.
|
||||||
|
OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':';
|
||||||
|
if (DiagOpts->ShowColumn)
|
||||||
|
OS << PLoc.getColumn() << ':';
|
||||||
|
OS << ' ';
|
||||||
|
}
|
||||||
|
OS << "note: instantiated from:\n";
|
||||||
|
|
||||||
|
EmitCaretDiagnostic(Loc, Ranges, NumRanges, SM, Hints, NumHints, Columns,
|
||||||
|
OnMacroInst + 1, MacroSkipStart, MacroSkipEnd);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DiagOpts->ShowLocation) {
|
if (OnMacroInst == MacroSkipStart) {
|
||||||
// Emit the file/line/column that this expansion came from.
|
// Tell the user that we've skipped contexts.
|
||||||
OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':';
|
OS << "note: (skipping " << (MacroSkipEnd - MacroSkipStart)
|
||||||
if (DiagOpts->ShowColumn)
|
<< " contexts in backtrace; use -fmacro-backtrace-limit=0 to see "
|
||||||
OS << PLoc.getColumn() << ':';
|
"all)\n";
|
||||||
OS << ' ';
|
|
||||||
}
|
}
|
||||||
OS << "note: instantiated from:\n";
|
|
||||||
|
|
||||||
EmitCaretDiagnostic(Loc, Ranges, NumRanges, SM, Hints, NumHints, Columns);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -866,10 +887,29 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned MacroInstSkipStart = 0, MacroInstSkipEnd = 0;
|
||||||
|
if (DiagOpts && DiagOpts->MacroBacktraceLimit && !LastLoc.isFileID()) {
|
||||||
|
// Compute the length of the macro-instantiation backtrace, so that we
|
||||||
|
// can establish which steps in the macro backtrace we'll skip.
|
||||||
|
SourceLocation Loc = LastLoc;
|
||||||
|
unsigned Depth = 0;
|
||||||
|
do {
|
||||||
|
++Depth;
|
||||||
|
Loc = LastLoc.getManager().getImmediateInstantiationRange(Loc).first;
|
||||||
|
} while (!Loc.isFileID());
|
||||||
|
|
||||||
|
if (Depth > DiagOpts->MacroBacktraceLimit) {
|
||||||
|
MacroInstSkipStart = DiagOpts->MacroBacktraceLimit / 2 +
|
||||||
|
DiagOpts->MacroBacktraceLimit % 2;
|
||||||
|
MacroInstSkipEnd = Depth - DiagOpts->MacroBacktraceLimit / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(),
|
EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(),
|
||||||
Info.getFixItHints(),
|
Info.getFixItHints(),
|
||||||
Info.getNumFixItHints(),
|
Info.getNumFixItHints(),
|
||||||
DiagOpts->MessageLength);
|
DiagOpts->MessageLength,
|
||||||
|
0, MacroInstSkipStart, MacroInstSkipEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
OS.flush();
|
OS.flush();
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
// RUN: %clang-cc1 -fsyntax-only -fmacro-backtrace-limit 5 %s > %t 2>&1
|
||||||
|
// RUN: FileCheck %s < %t
|
||||||
|
|
||||||
|
#define M1(A, B) ((A) < (B))
|
||||||
|
#define M2(A, B) M1(A, B)
|
||||||
|
#define M3(A, B) M2(A, B)
|
||||||
|
#define M4(A, B) M3(A, B)
|
||||||
|
#define M5(A, B) M4(A, B)
|
||||||
|
#define M6(A, B) M5(A, B)
|
||||||
|
#define M7(A, B) M6(A, B)
|
||||||
|
#define M8(A, B) M7(A, B)
|
||||||
|
#define M9(A, B) M8(A, B)
|
||||||
|
#define M10(A, B) M9(A, B)
|
||||||
|
#define M11(A, B) M10(A, B)
|
||||||
|
#define M12(A, B) M11(A, B)
|
||||||
|
|
||||||
|
void f(int *ip, float *fp) {
|
||||||
|
// CHECK: macro-backtrace-limit.c:31:7: warning: comparison of distinct pointer types ('int *' and 'float *')
|
||||||
|
// CHECK: if (M12(ip, fp)) { }
|
||||||
|
// CHECK: macro-backtrace-limit.c:15:19: note: instantiated from:
|
||||||
|
// CHECK: #define M12(A, B) M11(A, B)
|
||||||
|
// CHECK: macro-backtrace-limit.c:14:19: note: instantiated from:
|
||||||
|
// CHECK: #define M11(A, B) M10(A, B)
|
||||||
|
// CHECK: note: (skipping 7 contexts in backtrace; use -fmacro-backtrace-limit=0 to see all)
|
||||||
|
// CHECK: macro-backtrace-limit.c:6:18: note: instantiated from:
|
||||||
|
// CHECK: #define M3(A, B) M2(A, B)
|
||||||
|
// CHECK: macro-backtrace-limit.c:5:18: note: instantiated from:
|
||||||
|
// CHECK: #define M2(A, B) M1(A, B)
|
||||||
|
// CHECK: macro-backtrace-limit.c:4:23: note: instantiated from:
|
||||||
|
// CHECK: #define M1(A, B) ((A) < (B))
|
||||||
|
if (M12(ip, fp)) { }
|
||||||
|
}
|
Loading…
Reference in New Issue