[PATCH] PR other/69006: fix extra newlines after diagnostics (v2)

David Malcolm dmalcolm@redhat.com
Mon Jan 25 19:52:00 GMT 2016


Here's an updated version of the patch.

On Wed, 2016-01-13 at 18:32 +0100, Bernd Schmidt wrote:
> On 01/13/2016 01:57 AM, David Malcolm wrote:
> > There are five places in trunk that can call diagnostic_show_locus.
>
> I'd kind of like to see before/after example output for all of these, to
> make sure that we are indeed removing only unnecessary newlines.

Here's an attempt to show all of the cases, for the 4 out of 5 meangingful
sites.  It's rather long, so by way of summary it's as if I'd hand-unrolled
these nested loops:
  for each of the 4 usage sites in the source code:
    for each of "before the patch" vs "after the patch":
       for each of with, then without -fno-diagnostics-show-caret
       (i.e. first without the quoted source text, then with it).
giving 16 examples, using "VVV" and "^^^" to mark the bounds of
what I'm quoting (to make it easier to see trailing newlines).

USAGE SITE (1): in default_diagnostic_finalizer
As before, the patch updates this to remove a newline
immediately after a call to diagnostic_show_locus.
Example of use: the Go frontend, e.g. go.test/test/assign.go:

Before, with -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ gccgo ../../src/gcc/testsuite/go.test/test/assign.go -I../x86_64-pc-linux-gnu/libgo -O  -fno-show-column  -pedantic-errors  -S  -o assign.s -fno-diagnostics-show-caret
../../src/gcc/testsuite/go.test/test/assign.go:41: error: assignment of unexported field ‘state’ in ‘sync.Mutex’ literal
../../src/gcc/testsuite/go.test/test/assign.go:41: error: assignment of unexported field ‘sema’ in ‘sync.Mutex’ literal
../../src/gcc/testsuite/go.test/test/assign.go:45: error: unknown field ‘key’ in ‘sync.Mutex’
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Before, without -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ gccgo ../../src/gcc/testsuite/go.test/test/assign.go -I../x86_64-pc-linux-gnu/libgo -O  -fno-show-column  -pedantic-errors  -S  -o assign.s
../../src/gcc/testsuite/go.test/test/assign.go:41: error: assignment of unexported field ‘state’ in ‘sync.Mutex’ literal
   x := sync.Mutex{0, 0} // ERROR "assignment.*Mutex"
             ^

../../src/gcc/testsuite/go.test/test/assign.go:41: error: assignment of unexported field ‘sema’ in ‘sync.Mutex’ literal
../../src/gcc/testsuite/go.test/test/assign.go:45: error: unknown field ‘key’ in ‘sync.Mutex’
   x := sync.Mutex{key: 0} // ERROR "(unknown|assignment).*Mutex"
                   ^

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(note the erroneous trailing blank lines after the caret lines)

After, with -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ ./gccgo -B. ../../src/gcc/testsuite/go.test/test/assign.go -I../x86_64-pc-linux-gnu/libgo -O  -fno-show-column  -pedantic-errors  -S  -o assign.s
../../src/gcc/testsuite/go.test/test/assign.go:41: error: assignment of unexported field ‘state’ in ‘sync.Mutex’ literal
../../src/gcc/testsuite/go.test/test/assign.go:41: error: assignment of unexported field ‘sema’ in ‘sync.Mutex’ literal
../../src/gcc/testsuite/go.test/test/assign.go:45: error: unknown field ‘key’ in ‘sync.Mutex’
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(i.e. unchanged)

After, without -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ ./gccgo -B. ../../src/gcc/testsuite/go.test/test/assign.go -I../x86_64-pc-linux-gnu/libgo -O  -fno-show-column  -pedantic-errors  -S  -o assign.s -fno-diagnostics-show-caret
../../src/gcc/testsuite/go.test/test/assign.go:41: error: assignment of unexported field ‘state’ in ‘sync.Mutex’ literal
../../src/gcc/testsuite/go.test/test/assign.go:41: error: assignment of unexported field ‘sema’ in ‘sync.Mutex’ literal
../../src/gcc/testsuite/go.test/test/assign.go:45: error: unknown field ‘key’ in ‘sync.Mutex’
[david@c64 gcc]$ ./gccgo -B. ../../src/gcc/testsuite/go.test/test/assign.go -I../x86_64-pc-linux-gnu/libgo -O  -fno-show-column  -pedantic-errors  -S  -o assign.s
../../src/gcc/testsuite/go.test/test/assign.go:41: error: assignment of unexported field ‘state’ in ‘sync.Mutex’ literal
   x := sync.Mutex{0, 0} // ERROR "assignment.*Mutex"
             ^
../../src/gcc/testsuite/go.test/test/assign.go:41: error: assignment of unexported field ‘sema’ in ‘sync.Mutex’ literal
../../src/gcc/testsuite/go.test/test/assign.go:45: error: unknown field ‘key’ in ‘sync.Mutex’
   x := sync.Mutex{key: 0} // ERROR "(unknown|assignment).*Mutex"
                   ^
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(i.e. fixing the erroneous trailing blank lines after the caret lines)

USAGE SITE (2): c_diagnostic_finalizer:
Likewise.
Example of use: C frontend, e.g. gcc.dg/20031111-1.c

Before, with -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ gcc ../../src/gcc/testsuite/gcc.dg/20031111-1.c -fno-diagnostics-show-caret -ansi -pedantic-errors -S   -o 20031111-1.s
../../src/gcc/testsuite/gcc.dg/20031111-1.c: In function ‘foo’:
../../src/gcc/testsuite/gcc.dg/20031111-1.c:8:5: error: break statement not within loop or switch
../../src/gcc/testsuite/gcc.dg/20031111-1.c:12:5: error: continue statement not within a loop
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Before, without -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ gcc ../../src/gcc/testsuite/gcc.dg/20031111-1.c -ansi -pedantic-errors -S   -o 20031111-1.s ../../src/gcc/testsuite/gcc.dg/20031111-1.c: In function ‘foo’:
../../src/gcc/testsuite/gcc.dg/20031111-1.c:8:5: error: break statement not within loop or switch
     break;  /* { dg-error "" } */
     ^~~~~

../../src/gcc/testsuite/gcc.dg/20031111-1.c:12:5: error: continue statement not within a loop
     continue;  /* { dg-error "" } */
     ^~~~~~~~

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(note the erroneous trailing blank lines after the annotation lines)

After, with -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ ./xgcc -B. ../../src/gcc/testsuite/gcc.dg/20031111-1.c -fno-diagnostics-show-caret -ansi -pedantic-errors -S   -o 20031111-1.s
../../src/gcc/testsuite/gcc.dg/20031111-1.c: In function ‘foo’:
../../src/gcc/testsuite/gcc.dg/20031111-1.c:8:5: error: break statement not within loop or switch
../../src/gcc/testsuite/gcc.dg/20031111-1.c:12:5: error: continue statement not within a loop
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
i.e. unchanged

After, without -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ ./xgcc -B. ../../src/gcc/testsuite/gcc.dg/20031111-1.c -ansi -pedantic-errors -S   -o 20031111-1.s../../src/gcc/testsuite/gcc.dg/20031111-1.c: In function ‘foo’:
../../src/gcc/testsuite/gcc.dg/20031111-1.c:8:5: error: break statement not within loop or switch
     break;  /* { dg-error "" } */
     ^~~~~
../../src/gcc/testsuite/gcc.dg/20031111-1.c:12:5: error: continue statement not within a loop
     continue;  /* { dg-error "" } */
     ^~~~~~~~
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(note the absence of trailing blank lines after the annotation lines)

USAGE SITE (3) gfc_diagnostic_starter
Used for all Fortran diagnostics.
Example of use:  gfortran.dg/abstract_type_1.f90

Before, with -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ gfortran ../../src/gcc/testsuite/gfortran.dg/abstract_type_1.f90  -O  -std=f95 -S   -o abstract_type_1.s -fno-diagnostics-show-caret
../../src/gcc/testsuite/gfortran.dg/abstract_type_1.f90:9:16: Error: Fortran 2003: ABSTRACT type at (1)
../../src/gcc/testsuite/gfortran.dg/abstract_type_1.f90:11:5: Error: Expecting END MODULE statement at (1)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Before, without -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ gfortran ../../src/gcc/testsuite/gfortran.dg/abstract_type_1.f90  -O  -std=f95 -S   -o abstract_type_1.s../../src/gcc/testsuite/gfortran.dg/abstract_type_1.f90:9:16:

   TYPE, ABSTRACT :: t ! { dg-error "Fortran 2003" }
                1

Error: Fortran 2003: ABSTRACT type at (1)
../../src/gcc/testsuite/gfortran.dg/abstract_type_1.f90:11:5:

   END TYPE t ! { dg-error "END MODULE" }
     1

Error: Expecting END MODULE statement at (1)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(note the erroneous trailing blank line after the "1" annotation lines)

After, with -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ ./gfortran -B. -B../x86_64-pc-linux-gnu/libgfortran/ ../../src/gcc/testsuite/gfortran.dg/abstract_type_1.f90  -O  -std=f95 -S   -o abstract_type_1.s -fno-diagnostics-show-caret
../../src/gcc/testsuite/gfortran.dg/abstract_type_1.f90:9:16: Error: Fortran 2003: ABSTRACT type at (1)
../../src/gcc/testsuite/gfortran.dg/abstract_type_1.f90:11:5: Error: Expecting END MODULE statement at (1)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
i.e. unchanged

After, without -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ ./gfortran -B. -B../x86_64-pc-linux-gnu/libgfortran/ ../../src/gcc/testsuite/gfortran.dg/abstract_type_1.f90  -O  -std=f95 -S   -o abstract_type_1.s
../../src/gcc/testsuite/gfortran.dg/abstract_type_1.f90:9:16:

   TYPE, ABSTRACT :: t ! { dg-error "Fortran 2003" }
                1
Error: Fortran 2003: ABSTRACT type at (1)
../../src/gcc/testsuite/gfortran.dg/abstract_type_1.f90:11:5:

   END TYPE t ! { dg-error "END MODULE" }
     1
Error: Expecting END MODULE statement at (1)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(note the absence of trailing blank lines after the "1"
annotation lines)

Note that the Fortran frontend does have an intentional blank line
betweeen the filename/line/column line and the source code, which
this patch preserves.

USAGE SITE (4): diagnostic_append_note
Another caller of diagnostic_show_locus:
  diagnostic_append_note
is called zero or more times by:
  maybe_unwind_expanded_macro_loc
which is called by:
  virt_loc_aware_diagnostic_finalizer
The patch updates it to remove a call to pp_newline, which used to
occur before printing the note.
Example of use, where diagnostic_append_note is called once
by maybe_unwind_expanded_macro_loc:

VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ cat /tmp/test.c
extern void foo (int);
#define F __FILE__
void f (void)
{
  foo (F);
}
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Before, with -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ gcc -c /tmp/test.c -fno-diagnostics-show-caret
/tmp/test.c: In function ‘f’:
/tmp/test.c:2:11: warning: passing argument 1 of ‘foo’ makes integer from pointer without a cast [-Wint-conversion]
/tmp/test.c:5:8: note: in expansion of macro ‘F’
/tmp/test.c:1:13: note: expected ‘int’ but argument is of type ‘char *’
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Before, without -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ gcc -c /tmp/test.c
/tmp/test.c: In function ‘f’:
/tmp/test.c:2:11: warning: passing argument 1 of ‘foo’ makes integer from pointer without a cast [-Wint-conversion]
 #define F __FILE__
           ^

/tmp/test.c:5:8: note: in expansion of macro ‘F’
   foo (F);
        ^

/tmp/test.c:1:13: note: expected ‘int’ but argument is of type ‘char *’
 extern void foo (int);
             ^~~

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(note the trailing blank lines)

After, with -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ ./xgcc -B. -c /tmp/test.c -fno-diagnostics-show-caret
/tmp/test.c: In function ‘f’:
/tmp/test.c:2:11: warning: passing argument 1 of ‘foo’ makes integer from pointer without a cast [-Wint-conversion]
/tmp/test.c:5:8: note: in expansion of macro ‘F’
/tmp/test.c:1:13: note: expected ‘int’ but argument is of type ‘char *’
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(i.e. unchanged)

After, without -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ ./xgcc -B. -c /tmp/test.c
/tmp/test.c: In function ‘f’:
/tmp/test.c:2:11: warning: passing argument 1 of ‘foo’ makes integer from pointer without a cast [-Wint-conversion]
 #define F __FILE__
           ^
/tmp/test.c:5:8: note: in expansion of macro ‘F’
   foo (F);
        ^
/tmp/test.c:1:13: note: expected ‘int’ but argument is of type ‘char *’
 extern void foo (int);
             ^~~
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(note the fix of the erroneous trailing blank lines)

USAGE SITE (5): diagnostic_append_note_at_rich_loc
As noted before, this is unused, so the patch deletes it.

> > The final caller of diagnostic_show_locus:
> >    diagnostic_append_note_at_rich_loc
> > is unused, so the patch deletes it.
>
> That is ok as obvious.
>
> > The patch required removing this assertion from
> > pp_output_formatted_text:
> >      gcc_assert (buffer->line_length == 0);
>
> > with colorization - after printing the source code, the colorizer
> > prints color codes to disable colorization *after* the newline,
>
> I don't suppose that can be switched around to keep the assertion?

I switched things around to keep the
  gcc_assert (buffer->line_length == 0);
assertion within pp_output_formatted_text: diagnostic-show-locus.c now
ensures colorization is disabled before it emits newlines.

Changing this required updating the expected multiline output for
gcc.dg/plugin/diagnostic-test-show-locus-color.c.

Doing the latter I noticed a bug in multiline.exp: the code allows for
arbitrary followup text within any lines within a
  dg-begin/end-multiline-output
pair to avoid the need to quote dg-directives that might be present.  If
a blank line is present in the expected output, the resulting regexp
is too greedy, and can match anything, leading to confusing results
if there's an expected blank line.  So the patch fixes multiline.exp
to only allow for trailing dg-directives on *non-blank* lines.

> > Verifying the absence of newlines seemed tricky to do from DejaGnu, so
> > I added test coverage for this via a plugin.
>
> Ugh. Can it be this hard? I thought expect was designed to check output
> exactly. This might not fit in the dg-* framework too well, but IMO it
> would be better to check real compiler output than muck about with
> plugins if at all possible.

Instead of testing one particular kind of output via a plugin,
this version of the patch adds code to gcc-dg-prune to issue a
FAIL for any testcase containing blank lines, with a new
  dg-allow-blank-lines-in-output
directive for those test cases that legimitately emit blank lines.
Examples of the latter include a test using -ftime-report, another
using -fdump-tree-cunrolli-details=stderr, and a Fortran test
using -fdump-fortran-original.

The blank line detection is done in gcc-dg-prune before any other
pruning since some pruning can lead to blank lines within the
buffer of unpruned output.

This more rigorous testing approach uncovered two additional places
where blank lines were erroneosly emitted:

- in one of the existing test plugins (diagnostic_plugin_test_show_locus.c)
which had a copy of the regular diagnostic finalizer that I hadn't
updated to track the fixes from the patch.  This version of the patch
fixes that.

- in the C++ frontend, it was possible for the description of where
templates are instantiated to simply have a blank line, e.g.
g++.dg/ext/is_empty2.C:
  is_empty2.C: In instantiation of ‘int foo(A<__is_empty(T)>*) [with T = int]’:
  (BLANK LINE)
  is_empty2.C:6:5: error: use of built-in trait ‘__is_empty(T)’ in function signature; use library traits instead

This was a pre-existing issue; the version of the patch removes the
redundant newline for that case, by ensuring that every route through
print_instantiation_partial_context_line has a '\n' after its output,
allowing us to remove a pp_newline from
print_instantiation_partial_context.  Given that the former emits
its messages via pp_verbatim, I had to update output_buffer_append_r
to ensure that buff->line_length is reset to 0 whenever a '\n' is
emitted by pp_verbatim (otherwise we hit the buffer->line_length
assertion failure again).

Before, with -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ gcc -c ../../src/gcc/testsuite/g++.dg/ext/is_empty2.C  -fno-diagnostics-show-caret
../../src/gcc/testsuite/g++.dg/ext/is_empty2.C: In instantiation of ‘int foo(A<__is_empty(T)>*) [with T = int]’:

../../src/gcc/testsuite/g++.dg/ext/is_empty2.C:6:5: error: use of built-in trait ‘__is_empty(T)’ in function signature; use library traits instead
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(note the blank line)

Before, without -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ gcc -c ../../src/gcc/testsuite/g++.dg/ext/is_empty2.C
../../src/gcc/testsuite/g++.dg/ext/is_empty2.C: In instantiation of ‘int foo(A<__is_empty(T)>*) [with T = int]’:

../../src/gcc/testsuite/g++.dg/ext/is_empty2.C:6:5: error: use of built-in trait ‘__is_empty(T)’ in function signature; use library traits instead
 int foo (A<__is_empty (T)>* = 0); // { dg-error "built-in trait" }
     ^~~

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(note the two blank lines)

After, with -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ ./xg++ -B. -c ../../src/gcc/testsuite/g++.dg/ext/is_empty2.C  -fno-diagnostics-show-caret
../../src/gcc/testsuite/g++.dg/ext/is_empty2.C: In instantiation of ‘int foo(A<__is_empty(T)>*) [with T = int]’:
../../src/gcc/testsuite/g++.dg/ext/is_empty2.C:6:5: error: use of built-in trait ‘__is_empty(T)’ in function signature; use library traits instead
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(blank line fixed)

After, without -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ ./xg++ -B. -c ../../src/gcc/testsuite/g++.dg/ext/is_empty2.C
../../src/gcc/testsuite/g++.dg/ext/is_empty2.C: In instantiation of ‘int foo(A<__is_empty(T)>*) [with T = int]’:
../../src/gcc/testsuite/g++.dg/ext/is_empty2.C:6:5: error: use of built-in trait ‘__is_empty(T)’ in function signature; use library traits instead
 int foo (A<__is_empty (T)>* = 0); // { dg-error "built-in trait" }
     ^~~
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(both blank lines fixed)

To double-check, here's an example where an instantiation line
*is* given:

Before, with -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
[david@c64 gcc]$ gcc -c ../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C -std=c++14 -fno-diagnostics-show-caret
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C: In instantiation of ‘struct S2<short int>’:
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C:17:17:   required from here
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C:15:14: error: different underlying type in enum ‘enum S2<short int>::E’
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C:14:14: error: previous definition here
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C:23:14: error: different underlying type in enum ‘enum S3<T>::E’
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C:22:14: error: previous definition here
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Before, without -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ gcc -c ../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C -std=c++14
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C: In instantiation of ‘struct S2<short int>’:
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C:17:17:   required from here
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C:15:14: error: different underlying type in enum ‘enum S2<short int>::E’
     enum E : T;     // { dg-error "different underlying type" }
              ^

../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C:14:14: error: previous definition here
     enum E : int;   // { dg-error "previous definition" }
              ^~~

../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C:23:14: error: different underlying type in enum ‘enum S3<T>::E’
     enum E : short; // { dg-error "different underlying type" }
              ^~~~~

../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C:22:14: error: previous definition here
     enum E : int;   // { dg-error "previous definition" }
              ^~~

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

After, with -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
[david@c64 gcc]$ ./xg++ -B. -c ../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C -std=c++14 -fno-diagnostics-show-caret
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C: In instantiation of ‘struct S2<short int>’:
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C:17:17:   required from here
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C:15:14: error: different underlying type in enum ‘enum S2<short int>::E’
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C:14:14: error: previous definition here
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C:23:14: error: different underlying type in enum ‘enum S3<T>::E’
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C:22:14: error: previous definition here
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(i.e. unchanged)

After, without -fno-diagnostics-show-caret:
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
$ ./xg++ -B. -c ../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C -std=c++14
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C: In instantiation of ‘struct S2<short int>’:
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C:17:17:   required from here
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C:15:14: error: different underlying type in enum ‘enum S2<short int>::E’
     enum E : T;     // { dg-error "different underlying type" }
              ^
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C:14:14: error: previous definition here
     enum E : int;   // { dg-error "previous definition" }
              ^~~
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C:23:14: error: different underlying type in enum ‘enum S3<T>::E’
     enum E : short; // { dg-error "different underlying type" }
              ^~~~~
../../src/gcc/testsuite/g++.dg/cpp0x/forw_enum8.C:22:14: error: previous definition here
     enum E : int;   // { dg-error "previous definition" }
              ^~~
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(note the fix of the erroneous blank lines)

Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu.

OK for trunk in stage 4?  I regard PR 69006 as a regression, and it
affects all diagnostics we output (unless caret-printing is
disabled).

gcc/c-family/ChangeLog:
	PR other/69006
	* c-opts.c (c_diagnostic_finalizer): Replace invocation of
	pp_newline_and_flush with pp_flush.

gcc/cp/ChangeLog:
	PR other/69006
	* error.c (print_instantiation_partial_context_line): Add missing
	newlines from output for the t == NULL case.
	(print_instantiation_partial_context): Remove call to pp_newline.

gcc/ChangeLog:
	PR other/69006
	* diagnostic-show-locus.c (layout::print_source_line): Replace
	call to pp_newline with call to layout::print_newline.
	(layout::print_annotation_line): Likewise.
	(layout::move_to_column): Likewise.
	(layout::print_any_fixits): After printing any fixits, print a
	trailing newline, if necessary.
	(layout::print_newline): New method, resetting any colorization
	before a newline.
	(diagnostic_show_locus): Move the pp_newline to before the
	early bailout.  Remove dummy block enclosing the layout instance.
	* diagnostic.c (default_diagnostic_finalizer): Replace invocation
	of pp_newline_and_flush with pp_flush.
	(diagnostic_append_note): Delete use of pp_newline.
	(diagnostic_append_note_at_rich_loc): Delete.
	* diagnostic.h (diagnostic_append_note_at_rich_loc): Delete.
	* pretty-print.h (output_buffer_append_r): Reset buff->line_length
	when newline characters are added to the buffer.

gcc/fortran/ChangeLog:
	PR other/69006
	* error.c (gfc_diagnostic_starter): Delete use of pp_newline.

gcc/testsuite/ChangeLog:
	PR other/69006
	* g++.dg/ext/timevar1.C: Add dg-allow-blank-lines-in-output
	directive.
	* gcc.dg/plugin/diagnostic-test-show-locus-color.c: Update
	expected multiline output to reflect the colorization being
	disabled before newlines.
	* gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
	(custom_diagnostic_finalizer): Replace call to
	pp_newline_and_flush with call to pp_flush.
	* gcc.dg/unroll-2.c: Add dg-allow-blank-lines-in-output directive.
	* gfortran.dg/implicit_class_1.f90: Likewise.
	* lib/gcc-dg.exp (allow_blank_lines): New global.
	(dg-allow-blank-lines-in-output): New procedure.
	(gcc-dg-prune): Complain about blank lines in the output, unless
	dg-allow-blank-lines-in-output was called.
	* lib/multiline.exp (_build_multiline_regex): Only support
	arbitrary followup text for non-blank-lines, not for blank lines.
---
 gcc/c-family/c-opts.c                              |  2 +-
 gcc/cp/error.c                                     |  5 +-
 gcc/diagnostic-show-locus.c                        | 63 ++++++++-------
 gcc/diagnostic.c                                   | 33 +-------
 gcc/diagnostic.h                                   |  4 -
 gcc/fortran/error.c                                |  1 -
 gcc/pretty-print.h                                 |  6 +-
 gcc/testsuite/g++.dg/ext/timevar1.C                |  1 +
 .../plugin/diagnostic-test-show-locus-color.c      | 91 ++++++++++------------
 .../plugin/diagnostic_plugin_test_show_locus.c     |  2 +-
 gcc/testsuite/gcc.dg/unroll-2.c                    |  4 +
 gcc/testsuite/gfortran.dg/implicit_class_1.f90     |  1 +
 gcc/testsuite/lib/gcc-dg.exp                       | 24 ++++++
 gcc/testsuite/lib/multiline.exp                    | 10 ++-
 14 files changed, 122 insertions(+), 125 deletions(-)

diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index f2a3815..8cc28af 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -169,7 +169,7 @@ c_diagnostic_finalizer (diagnostic_context *context,
      finalizer -- for tokens resulting from macro expansion.  */
   virt_loc_aware_diagnostic_finalizer (context, diagnostic);
   pp_destroy_prefix (context->printer);
-  pp_newline_and_flush (context->printer);
+  pp_flush (context->printer);
 }
 
 /* Common default settings for diagnostics.  */
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 370816c..89a00a0 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -3365,8 +3365,8 @@ print_instantiation_partial_context_line (diagnostic_context *context,
     {
       pp_verbatim (context->printer,
 		   recursive_p
-		   ? _("recursively required from here")
-		   : _("required from here"));
+		   ? _("recursively required from here\n")
+		   : _("required from here\n"));
     }
 }
 
@@ -3450,7 +3450,6 @@ print_instantiation_partial_context (diagnostic_context *context,
     }
   print_instantiation_partial_context_line (context, NULL, loc,
 					    /*recursive_p=*/false);
-  pp_newline (context->printer);
 }
 
 /* Called from cp_thing to print the template context for an error.  */
diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
index e323254..018d2e6 100644
--- a/gcc/diagnostic-show-locus.c
+++ b/gcc/diagnostic-show-locus.c
@@ -159,6 +159,8 @@ class layout
   void print_any_fixits (int row, const rich_location *richloc);
 
  private:
+  void print_newline ();
+
   bool
   get_state_at_point (/* Inputs.  */
 		      int row, int column,
@@ -574,7 +576,7 @@ layout::print_source_line (int row, line_bounds *lbounds_out)
       pp_character (m_pp, c);
       line++;
     }
-  pp_newline (m_pp);
+  print_newline ();
 
   lbounds_out->m_first_non_ws = first_non_ws;
   lbounds_out->m_last_non_ws = last_non_ws;
@@ -616,7 +618,7 @@ layout::print_annotation_line (int row, const line_bounds lbounds)
 	  pp_character (m_pp, ' ');
 	}
     }
-  pp_newline (m_pp);
+  print_newline ();
 }
 
 /* If there are any fixit hints on source line ROW within RICHLOC, print them.
@@ -684,6 +686,18 @@ layout::print_any_fixits (int row, const rich_location *richloc)
 	    }
 	}
     }
+
+  /* Add a trailing newline, if necessary.  */
+  move_to_column (&column, 0);
+}
+
+/* Disable any colorization and emit a newline.  */
+
+void
+layout::print_newline ()
+{
+  m_colorizer.set_normal_text ();
+  pp_newline (m_pp);
 }
 
 /* Return true if (ROW/COLUMN) is within a range of the layout.
@@ -778,7 +792,7 @@ layout::move_to_column (int *column, int dest_column)
   /* Start a new line if we need to.  */
   if (*column > dest_column)
     {
-      pp_newline (m_pp);
+      print_newline ();
       *column = 0;
     }
 
@@ -798,6 +812,8 @@ void
 diagnostic_show_locus (diagnostic_context * context,
 		       const diagnostic_info *diagnostic)
 {
+  pp_newline (context->printer);
+
   if (!context->show_caret
       || diagnostic_location (diagnostic, 0) <= BUILTINS_LOCATION
       || diagnostic_location (diagnostic, 0) == context->last_location)
@@ -805,34 +821,25 @@ diagnostic_show_locus (diagnostic_context * context,
 
   context->last_location = diagnostic_location (diagnostic, 0);
 
-  pp_newline (context->printer);
-
   const char *saved_prefix = pp_get_prefix (context->printer);
   pp_set_prefix (context->printer, NULL);
 
-  {
-    layout layout (context, diagnostic);
-    int last_line = layout.get_last_line ();
-    for (int row = layout.get_first_line ();
-	 row <= last_line;
-	 row++)
-      {
-	/* Print the source line, followed by an annotation line
-	   consisting of any caret/underlines, then any fixits.
-	   If the source line can't be read, print nothing.  */
-	line_bounds lbounds;
-	if (layout.print_source_line (row, &lbounds))
-	  {
-	    layout.print_annotation_line (row, lbounds);
-	    layout.print_any_fixits (row, diagnostic->richloc);
-	  }
-      }
-
-    /* The closing scope here leads to the dtor for layout and thus
-       colorizer being called here, which affects the precise
-       place where colorization is turned off in the unittest
-       for colorized output.  */
-  }
+  layout layout (context, diagnostic);
+  int last_line = layout.get_last_line ();
+  for (int row = layout.get_first_line ();
+       row <= last_line;
+       row++)
+    {
+      /* Print the source line, followed by an annotation line
+	 consisting of any caret/underlines, then any fixits.
+	 If the source line can't be read, print nothing.  */
+      line_bounds lbounds;
+      if (layout.print_source_line (row, &lbounds))
+	{
+	  layout.print_annotation_line (row, lbounds);
+	  layout.print_any_fixits (row, diagnostic->richloc);
+	}
+    }
 
   pp_set_prefix (context->printer, saved_prefix);
 }
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index effb8f2..f661b57 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -546,7 +546,7 @@ default_diagnostic_finalizer (diagnostic_context *context,
 {
   diagnostic_show_locus (context, diagnostic);
   pp_destroy_prefix (context->printer);
-  pp_newline_and_flush (context->printer);
+  pp_flush (context->printer);
 }
 
 /* Interface to specify diagnostic kind overrides.  Returns the
@@ -879,37 +879,6 @@ diagnostic_append_note (diagnostic_context *context,
   saved_prefix = pp_get_prefix (context->printer);
   pp_set_prefix (context->printer,
                  diagnostic_build_prefix (context, &diagnostic));
-  pp_newline (context->printer);
-  pp_format (context->printer, &diagnostic.message);
-  pp_output_formatted_text (context->printer);
-  pp_destroy_prefix (context->printer);
-  pp_set_prefix (context->printer, saved_prefix);
-  diagnostic_show_locus (context, &diagnostic);
-  va_end (ap);
-}
-
-/* Same as diagnostic_append_note, but at RICHLOC. */
-
-void
-diagnostic_append_note_at_rich_loc (diagnostic_context *context,
-				    rich_location *richloc,
-				    const char * gmsgid, ...)
-{
-  diagnostic_info diagnostic;
-  va_list ap;
-  const char *saved_prefix;
-
-  va_start (ap, gmsgid);
-  diagnostic_set_info (&diagnostic, gmsgid, &ap, richloc, DK_NOTE);
-  if (context->inhibit_notes_p)
-    {
-      va_end (ap);
-      return;
-    }
-  saved_prefix = pp_get_prefix (context->printer);
-  pp_set_prefix (context->printer,
-                 diagnostic_build_prefix (context, &diagnostic));
-  pp_newline (context->printer);
   pp_format (context->printer, &diagnostic.message);
   pp_output_formatted_text (context->printer);
   pp_destroy_prefix (context->printer);
diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index 2cb6270..7cc5cff 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -293,10 +293,6 @@ extern void diagnostic_set_info_translated (diagnostic_info *, const char *,
      ATTRIBUTE_GCC_DIAG(2,0);
 extern void diagnostic_append_note (diagnostic_context *, location_t,
                                     const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
-extern void diagnostic_append_note_at_rich_loc (diagnostic_context *,
-						rich_location *,
-						const char *, ...)
-  ATTRIBUTE_GCC_DIAG(3,4);
 #endif
 extern char *diagnostic_build_prefix (diagnostic_context *, const diagnostic_info *);
 void default_diagnostic_starter (diagnostic_context *, diagnostic_info *);
diff --git a/gcc/fortran/error.c b/gcc/fortran/error.c
index 457a3b0..2243ead 100644
--- a/gcc/fortran/error.c
+++ b/gcc/fortran/error.c
@@ -1096,7 +1096,6 @@ gfc_diagnostic_starter (diagnostic_context *context,
       /* Fortran uses an empty line between locus and caret line.  */
       pp_newline (context->printer);
       diagnostic_show_locus (context, diagnostic);
-      pp_newline (context->printer);
       /* If the caret line was shown, the prefix does not contain the
 	 locus.  */
       pp_set_prefix (context->printer, kind_prefix);
diff --git a/gcc/pretty-print.h b/gcc/pretty-print.h
index 6a44fbc..f49f35a 100644
--- a/gcc/pretty-print.h
+++ b/gcc/pretty-print.h
@@ -125,7 +125,11 @@ output_buffer_append_r (output_buffer *buff, const char *start, int length)
 {
   gcc_checking_assert (start);
   obstack_grow (buff->obstack, start, length);
-  buff->line_length += length;
+  for (int i = 0; i < length; i++)
+    if (start[i] == '\n')
+      buff->line_length = 0;
+    else
+      buff->line_length++;
 }
 
 /*  Return a pointer to the last character emitted in the
diff --git a/gcc/testsuite/g++.dg/ext/timevar1.C b/gcc/testsuite/g++.dg/ext/timevar1.C
index 0d2d3f5..a48f8ba 100644
--- a/gcc/testsuite/g++.dg/ext/timevar1.C
+++ b/gcc/testsuite/g++.dg/ext/timevar1.C
@@ -1,5 +1,6 @@
 // PR c++/52248
 // { dg-options "-ftime-report" }
+// { dg-allow-blank-lines-in-output 1 }
 // { dg-prune-output "wall" }
 // { dg-prune-output "times" }
 // { dg-prune-output "TOTAL" }
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c
index 199e0b2..a590258 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c
@@ -15,8 +15,7 @@ void test_simple (void)
 
 /* { dg-begin-multiline-output "" }
    myvar = myvar.x;
-           ~~~~~^~
-
+           ~~~~~^~
    { dg-end-multiline-output "" } */
 #endif
 }
@@ -28,8 +27,7 @@ void test_simple_2 (void)
 
 /* { dg-begin-multiline-output "" }
    x = first_function () + second_function ();
-       ~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~
-
+       ~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~
    { dg-end-multiline-output "" } */
 #endif
 }
@@ -42,11 +40,10 @@ void test_multiline (void)
        + second_function ()); /* { dg-warning "test" } */
 
 /* { dg-begin-multiline-output "" }
-   x = (first_function ()
-        ~~~~~~~~~~~~~~~~~
-        + second_function ());
-        ^ ~~~~~~~~~~~~~~~~~~
-
+   x = (first_function ()
+        ~~~~~~~~~~~~~~~~~
+        + second_function ());
+        ^ ~~~~~~~~~~~~~~~~~~
    { dg-end-multiline-output "" } */
 #endif
 }
@@ -67,29 +64,28 @@ void test_many_lines (void)
                                                 magna, aliqua));
 
 /* { dg-begin-multiline-output "" }
-   x = (first_function_with_a_very_long_name (lorem, ipsum, dolor, sit, amet,
-        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-                                             consectetur, adipiscing, elit,
-                                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-                                             sed, eiusmod, tempor,
-                                             ~~~~~~~~~~~~~~~~~~~~~
-                                             incididunt, ut, labore, et,
-                                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~
-                                             dolore, magna, aliqua)
-                                             ~~~~~~~~~~~~~~~~~~~~~~
-        + second_function_with_a_very_long_name (lorem, ipsum, dolor, sit,
-        ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-                                                 amet, consectetur,
-                                                 ~~~~~~~~~~~~~~~~~~
-                                                 adipiscing, elit, sed,
-                                                 ~~~~~~~~~~~~~~~~~~~~~~
-                                                 eiusmod, tempor, incididunt,
-                                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-                                                 ut, labore, et, dolore,
-                                                 ~~~~~~~~~~~~~~~~~~~~~~~
-                                                 magna, aliqua));
-                                                 ~~~~~~~~~~~~~~
-
+   x = (first_function_with_a_very_long_name (lorem, ipsum, dolor, sit, amet,
+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                                             consectetur, adipiscing, elit,
+                                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                                             sed, eiusmod, tempor,
+                                             ~~~~~~~~~~~~~~~~~~~~~
+                                             incididunt, ut, labore, et,
+                                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                                             dolore, magna, aliqua)
+                                             ~~~~~~~~~~~~~~~~~~~~~~
+        + second_function_with_a_very_long_name (lorem, ipsum, dolor, sit,
+        ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                                                 amet, consectetur,
+                                                 ~~~~~~~~~~~~~~~~~~
+                                                 adipiscing, elit, sed,
+                                                 ~~~~~~~~~~~~~~~~~~~~~~
+                                                 eiusmod, tempor, incididunt,
+                                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                                                 ut, labore, et, dolore,
+                                                 ~~~~~~~~~~~~~~~~~~~~~~~
+                                                 magna, aliqua));
+                                                 ~~~~~~~~~~~~~~
    { dg-end-multiline-output "" } */
 #endif
 }
@@ -100,8 +96,7 @@ void test_richloc_from_proper_range (void)
   float f = 98.6f; /* { dg-warning "test" } */
 /* { dg-begin-multiline-output "" }
    float f = 98.6f;
-             ^~~~~
-
+             ^~~~~
    { dg-end-multiline-output "" } */
 #endif
 }
@@ -112,8 +107,7 @@ void test_caret_within_proper_range (void)
   float f = foo * bar; /* { dg-warning "17: test" } */
 /* { dg-begin-multiline-output "" }
    float f = foo * bar;
-             ~~~~^~~~~
-
+             ~~~~^~~~~
    { dg-end-multiline-output "" } */
 #endif
 }
@@ -124,8 +118,7 @@ void test_very_wide_line (void)
                                                                                 float f = foo * bar; /* { dg-warning "95: test" } */
 /* { dg-begin-multiline-output "" }
                                               float f = foo * bar;
-                                                        ~~~~^~~~~
-
+                                                        ~~~~^~~~~
    { dg-end-multiline-output "" } */
 #endif
 }
@@ -136,8 +129,7 @@ void test_multiple_carets (void)
    x = x + y /* { dg-warning "8: test" } */
 /* { dg-begin-multiline-output "" }
     x = x + y
-        A   B
-
+        A   B
    { dg-end-multiline-output "" } */
 #endif
 }
@@ -149,10 +141,9 @@ void test_caret_on_leading_whitespace (void)
       y = 5 /* { dg-warning "6: test" } */
 /* { dg-begin-multiline-output "" }
      ASSOCIATE (y => x)
-                    2
-       y = 5
-      1
-
+                    2
+       y = 5
+      1
    { dg-end-multiline-output "" } */
 #endif
 }
@@ -166,8 +157,8 @@ void test_fixit_insert (void)
    int a[2][2] = { 0, 1 , 2, 3 }; /* { dg-warning "insertion hints" } */
 /* { dg-begin-multiline-output "" }
     int a[2][2] = { 0, 1 , 2, 3 };
-                    ^~~~
-                    {   }
+                    ^~~~
+                    {   }
    { dg-end-multiline-output "" } */
 #endif
 }
@@ -180,8 +171,8 @@ void test_fixit_remove (void)
   int a;; /* { dg-warning "example of a removal hint" } */
 /* { dg-begin-multiline-output "" }
    int a;;
-         ^
-         -
+         ^
+         -
    { dg-end-multiline-output "" } */
 #endif
 }
@@ -194,8 +185,8 @@ void test_fixit_replace (void)
   gtk_widget_showall (dlg); /* { dg-warning "example of a replacement hint" } */
 /* { dg-begin-multiline-output "" }
    gtk_widget_showall (dlg);
-   ^~~~~~~~~~~~~~~~~~
-   gtk_widget_show_all
+   ^~~~~~~~~~~~~~~~~~
+   gtk_widget_show_all
    { dg-end-multiline-output "" } */
 #endif
 }
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
index 02a2aef..b4f12ba 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
@@ -137,7 +137,7 @@ custom_diagnostic_finalizer (diagnostic_context *context,
   pp_show_color (context->printer) = old_show_color;
 
   pp_destroy_prefix (context->printer);
-  pp_newline_and_flush (context->printer);
+  pp_flush (context->printer);
 }
 
 /* Exercise the diagnostic machinery to emit various warnings,
diff --git a/gcc/testsuite/gcc.dg/unroll-2.c b/gcc/testsuite/gcc.dg/unroll-2.c
index 7c9495d..05a1410 100644
--- a/gcc/testsuite/gcc.dg/unroll-2.c
+++ b/gcc/testsuite/gcc.dg/unroll-2.c
@@ -1,6 +1,10 @@
 /* { dg-do compile } */
 /* { dg-options "-O2 -fdump-tree-cunrolli-details=stderr -fno-peel-loops -fno-tree-vrp  -fdisable-tree-cunroll -fenable-tree-cunrolli" } */
 
+/* Blank lines can occur in the output of
+   -fdump-tree-cunrolli-details=stderr.  */
+/* { dg-allow-blank-lines-in-output 1 } */
+
 unsigned a[100], b[100];
 inline void bar()
 {
diff --git a/gcc/testsuite/gfortran.dg/implicit_class_1.f90 b/gcc/testsuite/gfortran.dg/implicit_class_1.f90
index 64193da..2ab9040 100644
--- a/gcc/testsuite/gfortran.dg/implicit_class_1.f90
+++ b/gcc/testsuite/gfortran.dg/implicit_class_1.f90
@@ -8,6 +8,7 @@
 ! segfault is working correctly.  No cleanup needed, because the dump
 ! goes to stdout.
 ! { dg-options "-fdump-fortran-original" }
+! { dg-allow-blank-lines-in-output 1 }
 ! { dg-prune-output "Namespace:.*-{42}" }
 
 program upimp
diff --git a/gcc/testsuite/lib/gcc-dg.exp b/gcc/testsuite/lib/gcc-dg.exp
index c003328..3dd8564 100644
--- a/gcc/testsuite/lib/gcc-dg.exp
+++ b/gcc/testsuite/lib/gcc-dg.exp
@@ -310,6 +310,19 @@ proc gcc-dg-test { prog do_what extra_tool_flags } {
     return [gcc-dg-test-1 gcc_target_compile $prog $do_what $extra_tool_flags]
 }
 
+# Global: should blank lines be allowed in the output?
+# By default, they should not be.  (PR other/69006)
+# However, there are some ways for them to validly occur.
+set allow_blank_lines 0
+
+# A command for use by testcases to mark themselves as expecting
+# blank lines in the output.
+
+proc dg-allow-blank-lines-in-output { args } {
+    global allow_blank_lines
+    set allow_blank_lines 1
+}
+
 proc gcc-dg-prune { system text } {
     global additional_prunes
 
@@ -317,6 +330,17 @@ proc gcc-dg-prune { system text } {
     # Always remember to clear it in .exp file after executed all tests.
     global dg_runtest_extra_prunes
 
+    # Complain about blank lines in the output (PR other/69006)
+    global allow_blank_lines
+    if { !$allow_blank_lines } {
+	set num_blank_lines [llength [regexp -all -inline "\n\n" $text]]
+	if { $num_blank_lines } {
+	    global testname_with_flags
+	    fail "$testname_with_flags $num_blank_lines blank line(s) in output"
+	}
+	set allow_blank_lines 0
+    }
+
     set text [prune_gcc_output $text]
 
     foreach p "$additional_prunes $dg_runtest_extra_prunes" {
diff --git a/gcc/testsuite/lib/multiline.exp b/gcc/testsuite/lib/multiline.exp
index fd7affc..a2e963e 100644
--- a/gcc/testsuite/lib/multiline.exp
+++ b/gcc/testsuite/lib/multiline.exp
@@ -224,10 +224,12 @@ proc _build_multiline_regex { multiline index } {
 	    set rexp "${rexp}\\|"
 	} else {
 	    # Assume that we have a quoted source line.
-	    # Support arbitrary followup text on each line,
-	    # to deal with comments containing containing DejaGnu
-	    # directives.
-	    append rexp ".*"
+	    if {![string equal "" $line] }  {
+		# Support arbitrary followup text on each non-empty line,
+		# to deal with comments containing containing DejaGnu
+		# directives.
+		append rexp ".*"
+	    }
 	}
 	append rexp "\n"
     }
-- 
1.8.5.3



More information about the Gcc-patches mailing list