Index: clang/include/clang/Basic/DiagnosticOptions.h =================================================================== --- clang/include/clang/Basic/DiagnosticOptions.h +++ clang/include/clang/Basic/DiagnosticOptions.h @@ -84,7 +84,8 @@ DefaultTemplateBacktraceLimit = 10, DefaultConstexprBacktraceLimit = 10, DefaultSpellCheckingLimit = 50, - DefaultSnippetLineLimit = 1, + DefaultSnippetLineLimit = 16, + DefaultShowLineNumbers = 1, }; // Define simple diagnostic options (with no accessors). Index: clang/include/clang/Basic/DiagnosticOptions.def =================================================================== --- clang/include/clang/Basic/DiagnosticOptions.def +++ clang/include/clang/Basic/DiagnosticOptions.def @@ -90,6 +90,8 @@ VALUE_DIAGOPT(SpellCheckingLimit, 32, DefaultSpellCheckingLimit) /// Limit number of lines shown in a snippet. VALUE_DIAGOPT(SnippetLineLimit, 32, DefaultSnippetLineLimit) +/// Show line number column on the left of snippets. +VALUE_DIAGOPT(ShowLineNumbers, 1, DefaultShowLineNumbers) VALUE_DIAGOPT(TabStop, 32, DefaultTabStop) /// The distance between tab stops. /// Column limit for formatting message diagnostics, or 0 if unused. Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -2543,6 +2543,10 @@ def fdiagnostics_absolute_paths : Flag<["-"], "fdiagnostics-absolute-paths">, Group, Flags<[CC1Option, CoreOption]>, HelpText<"Print absolute paths in diagnostics">, MarshallingInfoFlag>; +defm diagnostics_show_line_numbers : BoolFOption<"diagnostics-show-line-numbers", + DiagnosticOpts<"ShowLineNumbers">, DefaultTrue, + NegFlag, + PosFlag>; def fno_stack_protector : Flag<["-"], "fno-stack-protector">, Group, HelpText<"Disable the use of stack protectors">; def fno_strict_aliasing : Flag<["-"], "fno-strict-aliasing">, Group, Index: clang/include/clang/Frontend/TextDiagnostic.h =================================================================== --- clang/include/clang/Frontend/TextDiagnostic.h +++ clang/include/clang/Frontend/TextDiagnostic.h @@ -103,7 +103,8 @@ SmallVectorImpl &Ranges, ArrayRef Hints); - void emitSnippet(StringRef SourceLine); + void emitSnippet(StringRef SourceLine, unsigned MaxLineNoDisplayWidth, + unsigned LineNo); void emitParseableFixits(ArrayRef Hints, const SourceManager &SM); }; Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -4052,6 +4052,9 @@ Args.addOptOutFlag(CmdArgs, options::OPT_fshow_source_location, options::OPT_fno_show_source_location); + Args.addOptOutFlag(CmdArgs, options::OPT_fdiagnostics_show_line_numbers, + options::OPT_fno_diagnostics_show_line_numbers); + if (Args.hasArg(options::OPT_fdiagnostics_absolute_paths)) CmdArgs.push_back("-fdiagnostics-absolute-paths"); Index: clang/lib/Frontend/TextDiagnostic.cpp =================================================================== --- clang/lib/Frontend/TextDiagnostic.cpp +++ clang/lib/Frontend/TextDiagnostic.cpp @@ -1121,6 +1121,25 @@ return FixItInsertionLine; } +static unsigned getNumDisplayWidth(unsigned N) { + if (N < 10) + return 1; + if (N < 100) + return 2; + if (N < 1'000) + return 3; + if (N < 10'000) + return 4; + if (N < 100'000) + return 5; + if (N < 1'000'000) + return 6; + if (N < 10'000'000) + return 7; + llvm_unreachable("No source file should have more than 10 million lines"); + return 0; +} + /// Emit a code snippet and caret line. /// /// This routine emits a single line's code snippet and caret line.. @@ -1173,6 +1192,20 @@ Lines = maybeAddRange(Lines, *OptionalRange, MaxLines); } + unsigned MaxLineNoDisplayWidth = + DiagOpts->ShowLineNumbers + ? std::max(4u, std::max(getNumDisplayWidth(Lines.first), + getNumDisplayWidth(Lines.second))) + : 0; + auto indentForLineNumbers = [&] { + if (MaxLineNoDisplayWidth > 0) { + OS << ' '; + for (unsigned I = 0; I != MaxLineNoDisplayWidth; ++I) + OS << ' '; + OS << " | "; + } + }; + for (unsigned LineNo = Lines.first; LineNo != Lines.second + 1; ++LineNo) { const char *BufStart = BufData.data(); const char *BufEnd = BufStart + BufData.size(); @@ -1246,9 +1279,10 @@ CaretLine.erase(CaretLine.end() - 1); // Emit what we have computed. - emitSnippet(SourceLine); + emitSnippet(SourceLine, MaxLineNoDisplayWidth, LineNo); if (!CaretLine.empty()) { + indentForLineNumbers(); if (DiagOpts->ShowColors) OS.changeColor(caretColor, true); OS << CaretLine << '\n'; @@ -1257,6 +1291,7 @@ } if (!FixItInsertionLine.empty()) { + indentForLineNumbers(); if (DiagOpts->ShowColors) // Print fixit line in color OS.changeColor(fixitColor, false); @@ -1272,7 +1307,8 @@ emitParseableFixits(Hints, SM); } -void TextDiagnostic::emitSnippet(StringRef line) { +void TextDiagnostic::emitSnippet(StringRef line, unsigned MaxLineNoDisplayWidth, + unsigned LineNo) { if (line.empty()) return; @@ -1281,6 +1317,16 @@ std::string to_print; bool print_reversed = false; + // Emit line number. + if (MaxLineNoDisplayWidth > 0) { + unsigned LineNoDisplayWidth = getNumDisplayWidth(LineNo); + OS << ' '; + for (unsigned I = LineNoDisplayWidth; I < MaxLineNoDisplayWidth; ++I) + OS << ' '; + OS << LineNo; + OS << " | "; + } + while (i,bool> res = printableTextForNextCharacter(line, &i, DiagOpts->TabStop); Index: clang/test/FixIt/fixit-newline-style.c =================================================================== --- clang/test/FixIt/fixit-newline-style.c +++ clang/test/FixIt/fixit-newline-style.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -pedantic -Wunused-label -x c %s 2>&1 | FileCheck %s -strict-whitespace +// RUN: %clang_cc1 -pedantic -Wunused-label -fno-diagnostics-show-line-numbers -x c %s 2>&1 | FileCheck %s -strict-whitespace // This file intentionally uses a CRLF newline style // Index: clang/test/FixIt/fixit-unicode-with-utf8-output.c =================================================================== --- clang/test/FixIt/fixit-unicode-with-utf8-output.c +++ clang/test/FixIt/fixit-unicode-with-utf8-output.c @@ -1,7 +1,7 @@ // This test is an additional set of checks for the fixit-unicode.c test for // systems capable of outputting Unicode characters to the standard output in // the UTF-8 encoding. -// RUN: not %clang_cc1 -fsyntax-only %S/fixit-unicode.c 2>&1 | FileCheck -strict-whitespace %s +// RUN: not %clang_cc1 -fsyntax-only -fno-diagnostics-show-line-numbers %S/fixit-unicode.c 2>&1 | FileCheck -strict-whitespace %s // REQUIRES: utf8-capable-terminal // CHECK: warning: format specifies type 'int' but the argument has type 'long' Index: clang/test/FixIt/fixit-unicode.c =================================================================== --- clang/test/FixIt/fixit-unicode.c +++ clang/test/FixIt/fixit-unicode.c @@ -2,8 +2,8 @@ // There's a set of additional checks for systems with proper support of UTF-8 // on the standard output in fixit-unicode-with-utf8-output.c. -// RUN: not %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck -strict-whitespace %s -// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck -check-prefix=CHECK-MACHINE %s +// RUN: not %clang_cc1 -fsyntax-only -fno-diagnostics-show-line-numbers %s 2>&1 | FileCheck -strict-whitespace %s +// RUN: not %clang_cc1 -fsyntax-only -fno-diagnostics-show-line-numbers -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck -check-prefix=CHECK-MACHINE %s struct Foo { int bar; Index: clang/test/Lexer/header.cpp =================================================================== --- clang/test/Lexer/header.cpp +++ clang/test/Lexer/header.cpp @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -Wno-header-guard %s -// RUN: %clang_cc1 -fsyntax-only -Wheader-guard %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -fsyntax-only -Wheader-guard -fno-diagnostics-show-line-numbers %s 2>&1 | FileCheck %s #include "Inputs/good-header-guard.h" #include "Inputs/no-define.h" Index: clang/test/Lexer/string-literal-errors.cpp =================================================================== --- clang/test/Lexer/string-literal-errors.cpp +++ clang/test/Lexer/string-literal-errors.cpp @@ -1,4 +1,4 @@ -// RUN: not %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck -strict-whitespace %s +// RUN: not %clang_cc1 -fsyntax-only -fno-diagnostics-show-line-numbers %s 2>&1 | FileCheck -strict-whitespace %s void foo() { (void)"\q \u123z \x \U \U123 \U12345 \u123 \xyzzy \777 \U" Index: clang/test/Parser/brackets.c =================================================================== --- clang/test/Parser/brackets.c +++ clang/test/Parser/brackets.c @@ -2,7 +2,7 @@ // RUN: cp %s %t // RUN: not %clang_cc1 -fixit %t -x c -DFIXIT // RUN: %clang_cc1 -fsyntax-only %t -x c -DFIXIT -// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s -strict-whitespace +// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -fno-diagnostics-show-line-numbers %s 2>&1 | FileCheck %s -strict-whitespace void test1(void) { int a[] = {0,1,1,2,3}; Index: clang/test/Parser/brackets.cpp =================================================================== --- clang/test/Parser/brackets.cpp +++ clang/test/Parser/brackets.cpp @@ -2,7 +2,7 @@ // RUN: cp %s %t // RUN: not %clang_cc1 -fixit %t -x c++ -DFIXIT // RUN: %clang_cc1 -fsyntax-only %t -x c++ -DFIXIT -// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s -strict-whitespace +// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -fno-diagnostics-show-line-numbers %s 2>&1 | FileCheck %s -strict-whitespace void test1() { int a[] = {0,1,1,2,3}; Index: clang/test/SemaCXX/struct-class-redecl.cpp =================================================================== --- clang/test/SemaCXX/struct-class-redecl.cpp +++ clang/test/SemaCXX/struct-class-redecl.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -fsyntax-only -Wmismatched-tags -verify %s -// RUN: not %clang_cc1 -fsyntax-only -Wmismatched-tags %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -fsyntax-only -Wmismatched-tags -fno-diagnostics-show-line-numbers -verify %s +// RUN: not %clang_cc1 -fsyntax-only -Wmismatched-tags -fno-diagnostics-show-line-numbers %s 2>&1 | FileCheck %s class X; // expected-note 2{{here}} typedef struct X * X_t; // expected-warning{{previously declared}} union X { int x; float y; }; // expected-error{{use of 'X' with tag type that does not match previous declaration}}