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 @@ -4062,6 +4062,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 @@ -471,9 +471,7 @@ CaretEnd = map.byteToColumn(SourceEnd) + CaretColumnsOutsideSource; // [CaretStart, CaretEnd) is the slice we want. Update the various - // output lines to show only this slice, with two-space padding - // before the lines so that it looks nicer. - + // output lines to show only this slice. assert(CaretStart!=(unsigned)-1 && CaretEnd!=(unsigned)-1 && SourceStart!=(unsigned)-1 && SourceEnd!=(unsigned)-1); assert(SourceStart <= SourceEnd); @@ -1120,6 +1118,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.. @@ -1172,7 +1189,26 @@ Lines = maybeAddRange(Lines, *OptionalRange, MaxLines); } - for (unsigned LineNo = Lines.first; LineNo != Lines.second + 1; ++LineNo) { + // Our line numbers look like: + // " [number] | " + // Where [number] is MaxLineNoDisplayWidth columns + // and the full thing is therefore MaxLineNoDisplayWidth + 4 columns. + unsigned DisplayLineNo = Loc.getPresumedLoc().getLine(); + unsigned MaxLineNoDisplayWidth = + DiagOpts->ShowLineNumbers + ? std::max(4u, getNumDisplayWidth(DisplayLineNo + MaxLines)) + : 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, ++DisplayLineNo) { const char *BufStart = BufData.data(); const char *BufEnd = BufStart + BufData.size(); @@ -1245,9 +1281,10 @@ CaretLine.erase(CaretLine.end() - 1); // Emit what we have computed. - emitSnippet(SourceLine); + emitSnippet(SourceLine, MaxLineNoDisplayWidth, DisplayLineNo); if (!CaretLine.empty()) { + indentForLineNumbers(); if (DiagOpts->ShowColors) OS.changeColor(caretColor, true); OS << CaretLine << '\n'; @@ -1256,6 +1293,7 @@ } if (!FixItInsertionLine.empty()) { + indentForLineNumbers(); if (DiagOpts->ShowColors) // Print fixit line in color OS.changeColor(fixitColor, false); @@ -1271,7 +1309,8 @@ emitParseableFixits(Hints, SM); } -void TextDiagnostic::emitSnippet(StringRef line) { +void TextDiagnostic::emitSnippet(StringRef line, unsigned MaxLineNoDisplayWidth, + unsigned LineNo) { if (line.empty()) return; @@ -1280,6 +1319,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/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp =================================================================== --- clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp +++ clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp @@ -5,14 +5,14 @@ RefCountable* ref_countable = nullptr; auto foo1 = [ref_countable](){}; // CHECK: warning: Captured raw-pointer 'ref_countable' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker] - // CHECK-NEXT:{{^}} auto foo1 = [ref_countable](){}; - // CHECK-NEXT:{{^}} ^ + // CHECK-NEXT:{{^ 6 | }} auto foo1 = [ref_countable](){}; + // CHECK-NEXT:{{^ | }} ^ auto foo2 = [&ref_countable](){}; // CHECK: warning: Captured raw-pointer 'ref_countable' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker] auto foo3 = [&](){ ref_countable = nullptr; }; // CHECK: warning: Implicitly captured raw-pointer 'ref_countable' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker] - // CHECK-NEXT:{{^}} auto foo3 = [&](){ ref_countable = nullptr; }; - // CHECK-NEXT:{{^}} ^ + // CHECK-NEXT:{{^ 12 | }} auto foo3 = [&](){ ref_countable = nullptr; }; + // CHECK-NEXT:{{^ | }} ^ auto foo4 = [=](){ (void) ref_countable; }; // CHECK: warning: Implicitly captured raw-pointer 'ref_countable' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker] } Index: clang/test/FixIt/fixit-function-call.cpp =================================================================== --- clang/test/FixIt/fixit-function-call.cpp +++ clang/test/FixIt/fixit-function-call.cpp @@ -1,4 +1,4 @@ -// RUN: not %clang_cc1 -fdiagnostics-parseable-fixits -x c++ %s 2> %t +// RUN: not %clang_cc1 -fdiagnostics-parseable-fixits -fno-diagnostics-show-line-numbers -fcaret-diagnostics-max-lines 1 -x c++ %s 2> %t // RUN: FileCheck %s < %t // PR5941 // END. 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/Frontend/source-col-map.c =================================================================== --- clang/test/Frontend/source-col-map.c +++ clang/test/Frontend/source-col-map.c @@ -1,4 +1,4 @@ -// RUN: not %clang_cc1 -fsyntax-only -fmessage-length=75 -o /dev/null -x c < %s 2>&1 | FileCheck %s -strict-whitespace +// RUN: not %clang_cc1 -fsyntax-only -fno-diagnostics-show-line-numbers -fmessage-length=75 -o /dev/null -x c < %s 2>&1 | FileCheck %s -strict-whitespace // REQUIRES: utf8-capable-terminal // Test case for the text diagnostics source column conversion crash. 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/Misc/caret-diags-macros.c =================================================================== --- clang/test/Misc/caret-diags-macros.c +++ clang/test/Misc/caret-diags-macros.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck %s -strict-whitespace +// RUN: %clang_cc1 -fsyntax-only -fno-diagnostics-show-line-numbers %s 2>&1 | FileCheck %s -strict-whitespace #define M1(x) x #define M2 1; Index: clang/test/Misc/caret-diags-multiline.cpp =================================================================== --- clang/test/Misc/caret-diags-multiline.cpp +++ clang/test/Misc/caret-diags-multiline.cpp @@ -1,4 +1,4 @@ -// RUN: not %clang_cc1 -std=c++11 -fcaret-diagnostics-max-lines 5 -Wsometimes-uninitialized %s 2>&1 | FileCheck %s --strict-whitespace +// RUN: not %clang_cc1 -std=c++11 -fno-diagnostics-show-line-numbers -fcaret-diagnostics-max-lines 5 -Wsometimes-uninitialized %s 2>&1 | FileCheck %s --strict-whitespace void line(int); Index: clang/test/Misc/diag-macro-backtrace.c =================================================================== --- clang/test/Misc/diag-macro-backtrace.c +++ clang/test/Misc/diag-macro-backtrace.c @@ -1,4 +1,4 @@ -// RUN: not %clang -fsyntax-only -fmacro-backtrace-limit=0 %s 2>&1 | FileCheck %s +// RUN: not %clang -fsyntax-only -fno-diagnostics-show-line-numbers -fmacro-backtrace-limit=0 %s 2>&1 | FileCheck %s #define FOO 1+"hi" #define BAR FOO Index: clang/test/Misc/message-length.c =================================================================== --- clang/test/Misc/message-length.c +++ clang/test/Misc/message-length.c @@ -28,7 +28,7 @@ #pragma STDC CX_LIMITED_RANGE // some long comment text and a brace, eh {} // CHECK: FILE:23:78 -// CHECK: {{^ ...// some long comment text and a brace, eh {}}} +// CHECK: {{^ 23 | ...// some long comment text and a brace, eh {}}} struct A { int x; }; void h(struct A *a) { Index: clang/test/Misc/tabstop.c =================================================================== --- clang/test/Misc/tabstop.c +++ clang/test/Misc/tabstop.c @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -ftabstop 3 -fsyntax-only -Wno-error=int-conversion %s 2>&1 | FileCheck -check-prefix=CHECK-3 -strict-whitespace %s -// RUN: %clang_cc1 -ftabstop 4 -fsyntax-only -Wno-error=int-conversion %s 2>&1 | FileCheck -check-prefix=CHECK-4 -strict-whitespace %s -// RUN: %clang_cc1 -ftabstop 5 -fsyntax-only -Wno-error=int-conversion %s 2>&1 | FileCheck -check-prefix=CHECK-5 -strict-whitespace %s +// RUN: %clang_cc1 -ftabstop 3 -fsyntax-only -Wno-error=int-conversion -fno-diagnostics-show-line-numbers %s 2>&1 | FileCheck -check-prefix=CHECK-3 -strict-whitespace %s +// RUN: %clang_cc1 -ftabstop 4 -fsyntax-only -Wno-error=int-conversion -fno-diagnostics-show-line-numbers %s 2>&1 | FileCheck -check-prefix=CHECK-4 -strict-whitespace %s +// RUN: %clang_cc1 -ftabstop 5 -fsyntax-only -Wno-error=int-conversion -fno-diagnostics-show-line-numbers %s 2>&1 | FileCheck -check-prefix=CHECK-5 -strict-whitespace %s // tab void* a = 1; Index: clang/test/Misc/unnecessary-elipses.cpp =================================================================== --- clang/test/Misc/unnecessary-elipses.cpp +++ clang/test/Misc/unnecessary-elipses.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -fmessage-length=80 %s 2>&1 | FileCheck -strict-whitespace %s +// RUN: %clang_cc1 -fsyntax-only -fmessage-length=80 -fno-diagnostics-show-line-numbers %s 2>&1 | FileCheck -strict-whitespace %s int main() { "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; Index: clang/test/Misc/unprintable.c =================================================================== --- clang/test/Misc/unprintable.c +++ clang/test/Misc/unprintable.c @@ -1,4 +1,4 @@ -// RUN: not %clang_cc1 %s -fmessage-length=40 2>&1 | FileCheck -strict-whitespace %s +// RUN: not %clang_cc1 %s -fmessage-length=40 -fno-diagnostics-show-line-numbers 2>&1 | FileCheck -strict-whitespace %s int main() { int i; Index: clang/test/Misc/wrong-encoding.c =================================================================== --- clang/test/Misc/wrong-encoding.c +++ clang/test/Misc/wrong-encoding.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -fno-diagnostics-show-line-numbers %s 2>&1 | FileCheck %s // REQUIRES: asserts void foo(void) { 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/Preprocessor/ucn-pp-identifier.c =================================================================== --- clang/test/Preprocessor/ucn-pp-identifier.c +++ clang/test/Preprocessor/ucn-pp-identifier.c @@ -112,9 +112,9 @@ #define capital_u_\U00FC // expected-warning@-1 {{incomplete universal character name}} expected-note@-1 {{did you mean to use '\u'?}} expected-warning@-1 {{whitespace}} // CHECK: note: did you mean to use '\u'? -// CHECK-NEXT: #define capital_u_\U00FC -// CHECK-NEXT: {{^ \^}} -// CHECK-NEXT: {{^ u}} +// CHECK-NEXT: {{^ 112 | #define capital_u_\U00FC}} +// CHECK-NEXT: {{^ | \^}} +// CHECK-NEXT: {{^ | u}} #define \u{} // expected-warning {{empty delimited universal character name; treating as '\' 'u' '{' '}'}} expected-error {{macro name must be an identifier}} #define \u1{123} // expected-warning {{incomplete universal character name; treating as '\' followed by identifier}} expected-error {{macro name must be an identifier}} Index: clang/test/Sema/caret-diags-complex-init.cpp =================================================================== --- clang/test/Sema/caret-diags-complex-init.cpp +++ clang/test/Sema/caret-diags-complex-init.cpp @@ -1,4 +1,4 @@ -// RUN: not %clang_cc1 -std=c++11 -fsyntax-only -fcaret-diagnostics-max-lines 5 %s 2>&1 | FileCheck %s -strict-whitespace +// RUN: not %clang_cc1 -std=c++11 -fsyntax-only -fno-diagnostics-show-line-numbers -fcaret-diagnostics-max-lines 5 %s 2>&1 | FileCheck %s -strict-whitespace //CHECK: {{.*}}: error: excess elements in scalar initializer 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}}