diff mbox series

c++: fix source printing for "required from here" message

Message ID 20240424202206.173103-1-ppalka@redhat.com
State New
Headers show
Series c++: fix source printing for "required from here" message | expand

Commit Message

Patrick Palka April 24, 2024, 8:22 p.m. UTC
Tested on x86_64-pc-linux-gnu, full bootstrap+regtest in progress,
does this look OK if successful?

-- >8 --

It seems the diagnostic machinery's source line printing respects
the pretty printer prefix, but this is undesirable for the call to
diagnostic_show_locus in print_instantiation_partial_context_line
added in r14-4388-g1c45319b66edc9 since the prefix may have been
set when issuing an earlier, unrelated diagnostic and we just want
to print an unprefixed source line.

This patch naively fixes this by clearing the prefix before calling
diagnostic_show_locus.

Before this patch, for error60a.C below we'd print

gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was not declared in this scope
   24 |   unrelated_error; // { dg-error "not declared" }
      |   ^~~~~~~~~~~~~~~
gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void test(Foo) [with Foo = int]’:
gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
gcc/testsuite/g++.dg/template/error60a.C:24:3: error:    25 |   test<int> (42); // { dg-message " required from here" }
gcc/testsuite/g++.dg/template/error60a.C:24:3: error:       |   ~~~~~~~~~~^~~~
gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion from ‘int’ to ‘int*’ [-fpermissive]
   19 |   my_pointer<Foo> ptr (val); // { dg-error "invalid conversion from 'int' to 'int\\*'" }
      |                        ^~~
      |                        |
      |                        int
gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing argument 1 of ‘my_pointer<Foo>::my_pointer(Foo*) [with Foo = int]’
    9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1" }
      |               ~~~~~^~~

and afterward we print

gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was not declared in this scope
   24 |   unrelated_error; // { dg-error "not declared" }
      |   ^~~~~~~~~~~~~~~
gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void test(Foo) [with Foo = int]’:
gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
   25 |   test<int> (42); // { dg-message " required from here" }
      |   ~~~~~~~~~~^~~~
gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion from ‘int’ to ‘int*’ [-fpermissive]
   19 |   my_pointer<Foo> ptr (val); // { dg-error "invalid conversion from 'int' to 'int\\*'" }
      |                        ^~~
      |                        |
      |                        int
gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing argument 1 of ‘my_pointer<Foo>::my_pointer(Foo*) [with Foo = int]’
    9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1" }
      |               ~~~~~^~~

gcc/cp/ChangeLog:

	* error.cc (print_instantiation_partial_context_line): Clear
	context->printer->prefix around the call to diagnostic_show_locus.

gcc/testsuite/ChangeLog:

	* g++.dg/concepts/diagnostic2.C: Expect source line printed
	for the required from here message.
	* g++.dg/template/error60a.C: New test.
---
 gcc/cp/error.cc                             |  2 +
 gcc/testsuite/g++.dg/concepts/diagnostic2.C |  6 ++-
 gcc/testsuite/g++.dg/template/error60a.C    | 46 +++++++++++++++++++++
 3 files changed, 53 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/template/error60a.C

Comments

Jason Merrill April 24, 2024, 8:54 p.m. UTC | #1
On 4/24/24 13:22, Patrick Palka wrote:
> Tested on x86_64-pc-linux-gnu, full bootstrap+regtest in progress,
> does this look OK if successful?
> 
> -- >8 --
> 
> It seems the diagnostic machinery's source line printing respects
> the pretty printer prefix, but this is undesirable for the call to
> diagnostic_show_locus in print_instantiation_partial_context_line
> added in r14-4388-g1c45319b66edc9 since the prefix may have been
> set when issuing an earlier, unrelated diagnostic and we just want
> to print an unprefixed source line.
> 
> This patch naively fixes this by clearing the prefix before calling
> diagnostic_show_locus.
> 
> Before this patch, for error60a.C below we'd print
> 
> gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
> gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was not declared in this scope
>     24 |   unrelated_error; // { dg-error "not declared" }
>        |   ^~~~~~~~~~~~~~~
> gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void test(Foo) [with Foo = int]’:
> gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
> gcc/testsuite/g++.dg/template/error60a.C:24:3: error:    25 |   test<int> (42); // { dg-message " required from here" }
> gcc/testsuite/g++.dg/template/error60a.C:24:3: error:       |   ~~~~~~~~~~^~~~
> gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion from ‘int’ to ‘int*’ [-fpermissive]
>     19 |   my_pointer<Foo> ptr (val); // { dg-error "invalid conversion from 'int' to 'int\\*'" }
>        |                        ^~~
>        |                        |
>        |                        int
> gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing argument 1 of ‘my_pointer<Foo>::my_pointer(Foo*) [with Foo = int]’
>      9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1" }
>        |               ~~~~~^~~
> 
> and afterward we print
> 
> gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
> gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was not declared in this scope
>     24 |   unrelated_error; // { dg-error "not declared" }
>        |   ^~~~~~~~~~~~~~~
> gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void test(Foo) [with Foo = int]’:
> gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
>     25 |   test<int> (42); // { dg-message " required from here" }
>        |   ~~~~~~~~~~^~~~
> gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion from ‘int’ to ‘int*’ [-fpermissive]
>     19 |   my_pointer<Foo> ptr (val); // { dg-error "invalid conversion from 'int' to 'int\\*'" }
>        |                        ^~~
>        |                        |
>        |                        int
> gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing argument 1 of ‘my_pointer<Foo>::my_pointer(Foo*) [with Foo = int]’
>      9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1" }
>        |               ~~~~~^~~
> 
> gcc/cp/ChangeLog:
> 
> 	* error.cc (print_instantiation_partial_context_line): Clear
> 	context->printer->prefix around the call to diagnostic_show_locus.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/concepts/diagnostic2.C: Expect source line printed
> 	for the required from here message.
> 	* g++.dg/template/error60a.C: New test.
> ---
>   gcc/cp/error.cc                             |  2 +
>   gcc/testsuite/g++.dg/concepts/diagnostic2.C |  6 ++-
>   gcc/testsuite/g++.dg/template/error60a.C    | 46 +++++++++++++++++++++
>   3 files changed, 53 insertions(+), 1 deletion(-)
>   create mode 100644 gcc/testsuite/g++.dg/template/error60a.C
> 
> diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
> index 7074845154e..a7067d4d2ed 100644
> --- a/gcc/cp/error.cc
> +++ b/gcc/cp/error.cc
> @@ -3793,7 +3793,9 @@ print_instantiation_partial_context_line (diagnostic_context *context,
>   		   : _("required from here\n"));
>       }
>     gcc_rich_location rich_loc (loc);
> +  char *saved_prefix = pp_take_prefix (context->printer);
>     diagnostic_show_locus (context, &rich_loc, DK_NOTE);
> +  context->printer->prefix = saved_prefix;

I would follow the pattern of c_diagnostic_finalizer here, i.e. using 
pp_set_prefix for the restore.

Though I think the pp_set_prefix to NULL in c_diagnostic_finalizer is 
redundant and should have been removed in r9-2240-g653fee1961981f when 
the previous line changed from _set_ to _take_.  If it isn't redundant, 
then it should be, i.e. pp_take_prefix should call it instead of 
directly setting NULL.

Some _take_ callers do set(NULL) and others don't; they should 
definitely be consistent one way or the other.

David, what do you think?

Jason
Patrick Palka April 24, 2024, 9:05 p.m. UTC | #2
On Wed, 24 Apr 2024, Jason Merrill wrote:

> On 4/24/24 13:22, Patrick Palka wrote:
> > Tested on x86_64-pc-linux-gnu, full bootstrap+regtest in progress,
> > does this look OK if successful?
> > 
> > -- >8 --
> > 
> > It seems the diagnostic machinery's source line printing respects
> > the pretty printer prefix, but this is undesirable for the call to
> > diagnostic_show_locus in print_instantiation_partial_context_line
> > added in r14-4388-g1c45319b66edc9 since the prefix may have been
> > set when issuing an earlier, unrelated diagnostic and we just want
> > to print an unprefixed source line.
> > 
> > This patch naively fixes this by clearing the prefix before calling
> > diagnostic_show_locus.
> > 
> > Before this patch, for error60a.C below we'd print
> > 
> > gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
> > gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was
> > not declared in this scope
> >     24 |   unrelated_error; // { dg-error "not declared" }
> >        |   ^~~~~~~~~~~~~~~
> > gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void
> > test(Foo) [with Foo = int]’:
> > gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
> > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:    25 |   test<int>
> > (42); // { dg-message " required from here" }
> > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:       |
> > ~~~~~~~~~~^~~~
> > gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion
> > from ‘int’ to ‘int*’ [-fpermissive]
> >     19 |   my_pointer<Foo> ptr (val); // { dg-error "invalid conversion from
> > 'int' to 'int\\*'" }
> >        |                        ^~~
> >        |                        |
> >        |                        int
> > gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing argument
> > 1 of ‘my_pointer<Foo>::my_pointer(Foo*) [with Foo = int]’
> >      9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1"
> > }
> >        |               ~~~~~^~~
> > 
> > and afterward we print
> > 
> > gcc/testsuite/g++.dg/template/error60a.C: In function ‘void usage()’:
> > gcc/testsuite/g++.dg/template/error60a.C:24:3: error: ‘unrelated_error’ was
> > not declared in this scope
> >     24 |   unrelated_error; // { dg-error "not declared" }
> >        |   ^~~~~~~~~~~~~~~
> > gcc/testsuite/g++.dg/template/error60a.C: In instantiation of ‘void
> > test(Foo) [with Foo = int]’:
> > gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from here
> >     25 |   test<int> (42); // { dg-message " required from here" }
> >        |   ~~~~~~~~~~^~~~
> > gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid conversion
> > from ‘int’ to ‘int*’ [-fpermissive]
> >     19 |   my_pointer<Foo> ptr (val); // { dg-error "invalid conversion from
> > 'int' to 'int\\*'" }
> >        |                        ^~~
> >        |                        |
> >        |                        int
> > gcc/testsuite/g++.dg/template/error60a.C:9:20: note:   initializing argument
> > 1 of ‘my_pointer<Foo>::my_pointer(Foo*) [with Foo = int]’
> >      9 |   my_pointer (Foo *ptr) // { dg-message " initializing argument 1"
> > }
> >        |               ~~~~~^~~
> > 
> > gcc/cp/ChangeLog:
> > 
> > 	* error.cc (print_instantiation_partial_context_line): Clear
> > 	context->printer->prefix around the call to diagnostic_show_locus.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > 	* g++.dg/concepts/diagnostic2.C: Expect source line printed
> > 	for the required from here message.
> > 	* g++.dg/template/error60a.C: New test.
> > ---
> >   gcc/cp/error.cc                             |  2 +
> >   gcc/testsuite/g++.dg/concepts/diagnostic2.C |  6 ++-
> >   gcc/testsuite/g++.dg/template/error60a.C    | 46 +++++++++++++++++++++
> >   3 files changed, 53 insertions(+), 1 deletion(-)
> >   create mode 100644 gcc/testsuite/g++.dg/template/error60a.C
> > 
> > diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
> > index 7074845154e..a7067d4d2ed 100644
> > --- a/gcc/cp/error.cc
> > +++ b/gcc/cp/error.cc
> > @@ -3793,7 +3793,9 @@ print_instantiation_partial_context_line
> > (diagnostic_context *context,
> >   		   : _("required from here\n"));
> >       }
> >     gcc_rich_location rich_loc (loc);
> > +  char *saved_prefix = pp_take_prefix (context->printer);
> >     diagnostic_show_locus (context, &rich_loc, DK_NOTE);
> > +  context->printer->prefix = saved_prefix;
> 
> I would follow the pattern of c_diagnostic_finalizer here, i.e. using
> pp_set_prefix for the restore.

FWIW that's what I originally went with, but I don't really understand
the other things pp_set_prefix does besides setting the prefix and
then I noticed cp_print_error_function restores ->prefix directly so
I ended up doing that instead.

> 
> Though I think the pp_set_prefix to NULL in c_diagnostic_finalizer is
> redundant and should have been removed in r9-2240-g653fee1961981f when the
> previous line changed from _set_ to _take_.  If it isn't redundant, then it
> should be, i.e. pp_take_prefix should call it instead of directly setting
> NULL.
> 
> Some _take_ callers do set(NULL) and others don't; they should definitely be
> consistent one way or the other.
> 
> David, what do you think?
> 
> Jason
> 
>
David Malcolm April 25, 2024, 6:48 p.m. UTC | #3
On Wed, 2024-04-24 at 17:05 -0400, Patrick Palka wrote:
> On Wed, 24 Apr 2024, Jason Merrill wrote:
> 
> > On 4/24/24 13:22, Patrick Palka wrote:
> > > Tested on x86_64-pc-linux-gnu, full bootstrap+regtest in
> > > progress,
> > > does this look OK if successful?
> > > 
> > > -- >8 --
> > > 
> > > It seems the diagnostic machinery's source line printing respects
> > > the pretty printer prefix, but this is undesirable for the call
> > > to
> > > diagnostic_show_locus in print_instantiation_partial_context_line
> > > added in r14-4388-g1c45319b66edc9 since the prefix may have been
> > > set when issuing an earlier, unrelated diagnostic and we just
> > > want
> > > to print an unprefixed source line.
> > > 
> > > This patch naively fixes this by clearing the prefix before
> > > calling
> > > diagnostic_show_locus.
> > > 
> > > Before this patch, for error60a.C below we'd print
> > > 
> > > gcc/testsuite/g++.dg/template/error60a.C: In function ‘void
> > > usage()’:
> > > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:
> > > ‘unrelated_error’ was
> > > not declared in this scope
> > >     24 |   unrelated_error; // { dg-error "not declared" }
> > >        |   ^~~~~~~~~~~~~~~
> > > gcc/testsuite/g++.dg/template/error60a.C: In instantiation of
> > > ‘void
> > > test(Foo) [with Foo = int]’:
> > > gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from
> > > here
> > > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:    25 |  
> > > test<int>
> > > (42); // { dg-message " required from here" }
> > > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:       |
> > > ~~~~~~~~~~^~~~
> > > gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid
> > > conversion
> > > from ‘int’ to ‘int*’ [-fpermissive]
> > >     19 |   my_pointer<Foo> ptr (val); // { dg-error "invalid
> > > conversion from
> > > 'int' to 'int\\*'" }
> > >        |                        ^~~
> > >        |                        |
> > >        |                        int
> > > gcc/testsuite/g++.dg/template/error60a.C:9:20: note:  
> > > initializing argument
> > > 1 of ‘my_pointer<Foo>::my_pointer(Foo*) [with Foo = int]’
> > >      9 |   my_pointer (Foo *ptr) // { dg-message " initializing
> > > argument 1"
> > > }
> > >        |               ~~~~~^~~
> > > 
> > > and afterward we print
> > > 
> > > gcc/testsuite/g++.dg/template/error60a.C: In function ‘void
> > > usage()’:
> > > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:
> > > ‘unrelated_error’ was
> > > not declared in this scope
> > >     24 |   unrelated_error; // { dg-error "not declared" }
> > >        |   ^~~~~~~~~~~~~~~
> > > gcc/testsuite/g++.dg/template/error60a.C: In instantiation of
> > > ‘void
> > > test(Foo) [with Foo = int]’:
> > > gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from
> > > here
> > >     25 |   test<int> (42); // { dg-message " required from here"
> > > }
> > >        |   ~~~~~~~~~~^~~~
> > > gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid
> > > conversion
> > > from ‘int’ to ‘int*’ [-fpermissive]
> > >     19 |   my_pointer<Foo> ptr (val); // { dg-error "invalid
> > > conversion from
> > > 'int' to 'int\\*'" }
> > >        |                        ^~~
> > >        |                        |
> > >        |                        int
> > > gcc/testsuite/g++.dg/template/error60a.C:9:20: note:  
> > > initializing argument
> > > 1 of ‘my_pointer<Foo>::my_pointer(Foo*) [with Foo = int]’
> > >      9 |   my_pointer (Foo *ptr) // { dg-message " initializing
> > > argument 1"
> > > }
> > >        |               ~~~~~^~~
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > >         * error.cc (print_instantiation_partial_context_line):
> > > Clear
> > >         context->printer->prefix around the call to
> > > diagnostic_show_locus.
> > > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > >         * g++.dg/concepts/diagnostic2.C: Expect source line
> > > printed
> > >         for the required from here message.
> > >         * g++.dg/template/error60a.C: New test.
> > > ---
> > >   gcc/cp/error.cc                             |  2 +
> > >   gcc/testsuite/g++.dg/concepts/diagnostic2.C |  6 ++-
> > >   gcc/testsuite/g++.dg/template/error60a.C    | 46
> > > +++++++++++++++++++++
> > >   3 files changed, 53 insertions(+), 1 deletion(-)
> > >   create mode 100644 gcc/testsuite/g++.dg/template/error60a.C
> > > 
> > > diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
> > > index 7074845154e..a7067d4d2ed 100644
> > > --- a/gcc/cp/error.cc
> > > +++ b/gcc/cp/error.cc
> > > @@ -3793,7 +3793,9 @@ print_instantiation_partial_context_line
> > > (diagnostic_context *context,
> > >                    : _("required from here\n"));
> > >       }
> > >     gcc_rich_location rich_loc (loc);
> > > +  char *saved_prefix = pp_take_prefix (context->printer);
> > >     diagnostic_show_locus (context, &rich_loc, DK_NOTE);
> > > +  context->printer->prefix = saved_prefix;
> > 
> > I would follow the pattern of c_diagnostic_finalizer here, i.e.
> > using
> > pp_set_prefix for the restore.
> 
> FWIW that's what I originally went with, but I don't really
> understand
> the other things pp_set_prefix does besides setting the prefix and
> then I noticed cp_print_error_function restores ->prefix directly so
> I ended up doing that instead.

I have a slight preference for using pp_set_prefix for the restore, but
the patch as written is also OK; thanks.

I confess that I don't have a strong sense of how the prefix code is
meant to work.

It seems to be for use with this combination of options:
  -fmessage-length=NON_ZERO -fdiagnostics-show-location=every-line
which triggers line-wrapping, adding the prefix at each line when line
wrapping occurs.  This seems to have existed at least as far back as 
856b62442f6fc5e4302ae9ee1ebce8a19bbd8681
re this "C++ err msgs" thread from 2000:

https://gcc.gnu.org/pipermail/libstdc++/2000-May/004650.html
https://gcc.gnu.org/pipermail/libstdc++/2000-May/004664.html
https://gcc.gnu.org/pipermail/gcc-patches/2000-May/031143.html

which made the prefixing optional on continuation lines.

I suspect that if anyone was using that combination of options, we've
probably broken it at some point with quoting of source code,
underlining, fix-it hints, etc etc

Dave




> 
> > 
> > Though I think the pp_set_prefix to NULL in c_diagnostic_finalizer
> > is
> > redundant and should have been removed in r9-2240-g653fee1961981f
> > when the
> > previous line changed from _set_ to _take_.  If it isn't redundant,
> > then it
> > should be, i.e. pp_take_prefix should call it instead of directly
> > setting
> > NULL.
> > 
> > Some _take_ callers do set(NULL) and others don't; they should
> > definitely be
> > consistent one way or the other.
> > 
> > David, what do you think?
> > 
> > Jason
> >
Patrick Palka April 26, 2024, 11:52 a.m. UTC | #4
On Thu, 25 Apr 2024, David Malcolm wrote:

> On Wed, 2024-04-24 at 17:05 -0400, Patrick Palka wrote:
> > On Wed, 24 Apr 2024, Jason Merrill wrote:
> > 
> > > On 4/24/24 13:22, Patrick Palka wrote:
> > > > Tested on x86_64-pc-linux-gnu, full bootstrap+regtest in
> > > > progress,
> > > > does this look OK if successful?
> > > > 
> > > > -- >8 --
> > > > 
> > > > It seems the diagnostic machinery's source line printing respects
> > > > the pretty printer prefix, but this is undesirable for the call
> > > > to
> > > > diagnostic_show_locus in print_instantiation_partial_context_line
> > > > added in r14-4388-g1c45319b66edc9 since the prefix may have been
> > > > set when issuing an earlier, unrelated diagnostic and we just
> > > > want
> > > > to print an unprefixed source line.
> > > > 
> > > > This patch naively fixes this by clearing the prefix before
> > > > calling
> > > > diagnostic_show_locus.
> > > > 
> > > > Before this patch, for error60a.C below we'd print
> > > > 
> > > > gcc/testsuite/g++.dg/template/error60a.C: In function ‘void
> > > > usage()’:
> > > > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:
> > > > ‘unrelated_error’ was
> > > > not declared in this scope
> > > >     24 |   unrelated_error; // { dg-error "not declared" }
> > > >        |   ^~~~~~~~~~~~~~~
> > > > gcc/testsuite/g++.dg/template/error60a.C: In instantiation of
> > > > ‘void
> > > > test(Foo) [with Foo = int]’:
> > > > gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from
> > > > here
> > > > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:    25 |  
> > > > test<int>
> > > > (42); // { dg-message " required from here" }
> > > > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:       |
> > > > ~~~~~~~~~~^~~~
> > > > gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid
> > > > conversion
> > > > from ‘int’ to ‘int*’ [-fpermissive]
> > > >     19 |   my_pointer<Foo> ptr (val); // { dg-error "invalid
> > > > conversion from
> > > > 'int' to 'int\\*'" }
> > > >        |                        ^~~
> > > >        |                        |
> > > >        |                        int
> > > > gcc/testsuite/g++.dg/template/error60a.C:9:20: note:  
> > > > initializing argument
> > > > 1 of ‘my_pointer<Foo>::my_pointer(Foo*) [with Foo = int]’
> > > >      9 |   my_pointer (Foo *ptr) // { dg-message " initializing
> > > > argument 1"
> > > > }
> > > >        |               ~~~~~^~~
> > > > 
> > > > and afterward we print
> > > > 
> > > > gcc/testsuite/g++.dg/template/error60a.C: In function ‘void
> > > > usage()’:
> > > > gcc/testsuite/g++.dg/template/error60a.C:24:3: error:
> > > > ‘unrelated_error’ was
> > > > not declared in this scope
> > > >     24 |   unrelated_error; // { dg-error "not declared" }
> > > >        |   ^~~~~~~~~~~~~~~
> > > > gcc/testsuite/g++.dg/template/error60a.C: In instantiation of
> > > > ‘void
> > > > test(Foo) [with Foo = int]’:
> > > > gcc/testsuite/g++.dg/template/error60a.C:25:13:   required from
> > > > here
> > > >     25 |   test<int> (42); // { dg-message " required from here"
> > > > }
> > > >        |   ~~~~~~~~~~^~~~
> > > > gcc/testsuite/g++.dg/template/error60a.C:19:24: error: invalid
> > > > conversion
> > > > from ‘int’ to ‘int*’ [-fpermissive]
> > > >     19 |   my_pointer<Foo> ptr (val); // { dg-error "invalid
> > > > conversion from
> > > > 'int' to 'int\\*'" }
> > > >        |                        ^~~
> > > >        |                        |
> > > >        |                        int
> > > > gcc/testsuite/g++.dg/template/error60a.C:9:20: note:  
> > > > initializing argument
> > > > 1 of ‘my_pointer<Foo>::my_pointer(Foo*) [with Foo = int]’
> > > >      9 |   my_pointer (Foo *ptr) // { dg-message " initializing
> > > > argument 1"
> > > > }
> > > >        |               ~~~~~^~~
> > > > 
> > > > gcc/cp/ChangeLog:
> > > > 
> > > >         * error.cc (print_instantiation_partial_context_line):
> > > > Clear
> > > >         context->printer->prefix around the call to
> > > > diagnostic_show_locus.
> > > > 
> > > > gcc/testsuite/ChangeLog:
> > > > 
> > > >         * g++.dg/concepts/diagnostic2.C: Expect source line
> > > > printed
> > > >         for the required from here message.
> > > >         * g++.dg/template/error60a.C: New test.
> > > > ---
> > > >   gcc/cp/error.cc                             |  2 +
> > > >   gcc/testsuite/g++.dg/concepts/diagnostic2.C |  6 ++-
> > > >   gcc/testsuite/g++.dg/template/error60a.C    | 46
> > > > +++++++++++++++++++++
> > > >   3 files changed, 53 insertions(+), 1 deletion(-)
> > > >   create mode 100644 gcc/testsuite/g++.dg/template/error60a.C
> > > > 
> > > > diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
> > > > index 7074845154e..a7067d4d2ed 100644
> > > > --- a/gcc/cp/error.cc
> > > > +++ b/gcc/cp/error.cc
> > > > @@ -3793,7 +3793,9 @@ print_instantiation_partial_context_line
> > > > (diagnostic_context *context,
> > > >                    : _("required from here\n"));
> > > >       }
> > > >     gcc_rich_location rich_loc (loc);
> > > > +  char *saved_prefix = pp_take_prefix (context->printer);
> > > >     diagnostic_show_locus (context, &rich_loc, DK_NOTE);
> > > > +  context->printer->prefix = saved_prefix;
> > > 
> > > I would follow the pattern of c_diagnostic_finalizer here, i.e.
> > > using
> > > pp_set_prefix for the restore.
> > 
> > FWIW that's what I originally went with, but I don't really
> > understand
> > the other things pp_set_prefix does besides setting the prefix and
> > then I noticed cp_print_error_function restores ->prefix directly so
> > I ended up doing that instead.
> 
> I have a slight preference for using pp_set_prefix for the restore, but
> the patch as written is also OK; thanks.

Thanks a lot, pushed as r15-4-g7d5479a2ecf630 which uses pp_set_prefix
for the restore as suggested.

> 
> I confess that I don't have a strong sense of how the prefix code is
> meant to work.
> 
> It seems to be for use with this combination of options:
>   -fmessage-length=NON_ZERO -fdiagnostics-show-location=every-line
> which triggers line-wrapping, adding the prefix at each line when line
> wrapping occurs.  This seems to have existed at least as far back as 
> 856b62442f6fc5e4302ae9ee1ebce8a19bbd8681
> re this "C++ err msgs" thread from 2000:
> 
> https://gcc.gnu.org/pipermail/libstdc++/2000-May/004650.html
> https://gcc.gnu.org/pipermail/libstdc++/2000-May/004664.html
> https://gcc.gnu.org/pipermail/gcc-patches/2000-May/031143.html
> 
> which made the prefixing optional on continuation lines.
> 
> I suspect that if anyone was using that combination of options, we've
> probably broken it at some point with quoting of source code,
> underlining, fix-it hints, etc etc
> 
> Dave
> 
> 
> 
> 
> > 
> > > 
> > > Though I think the pp_set_prefix to NULL in c_diagnostic_finalizer
> > > is
> > > redundant and should have been removed in r9-2240-g653fee1961981f
> > > when the
> > > previous line changed from _set_ to _take_.  If it isn't redundant,
> > > then it
> > > should be, i.e. pp_take_prefix should call it instead of directly
> > > setting
> > > NULL.
> > > 
> > > Some _take_ callers do set(NULL) and others don't; they should
> > > definitely be
> > > consistent one way or the other.
> > > 
> > > David, what do you think?
> > > 
> > > Jason
> > > 
> 
>
diff mbox series

Patch

diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 7074845154e..a7067d4d2ed 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -3793,7 +3793,9 @@  print_instantiation_partial_context_line (diagnostic_context *context,
 		   : _("required from here\n"));
     }
   gcc_rich_location rich_loc (loc);
+  char *saved_prefix = pp_take_prefix (context->printer);
   diagnostic_show_locus (context, &rich_loc, DK_NOTE);
+  context->printer->prefix = saved_prefix;
 }
 
 /* Same as print_instantiation_full_context but less verbose.  */
diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic2.C b/gcc/testsuite/g++.dg/concepts/diagnostic2.C
index 6550ed6b3bd..d6f5872de2c 100644
--- a/gcc/testsuite/g++.dg/concepts/diagnostic2.C
+++ b/gcc/testsuite/g++.dg/concepts/diagnostic2.C
@@ -23,7 +23,11 @@  void
 baz()
 {
   bar<int>(); // { dg-error "no match" }
-/* { dg-begin-multiline-output "" }
+/* { dg-begin-multiline-output "for no match error" }
+   bar<int>();
+   ~~~~~~~~^~
+   { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "for required from here message" }
    bar<int>();
    ~~~~~~~~^~
    { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/g++.dg/template/error60a.C b/gcc/testsuite/g++.dg/template/error60a.C
new file mode 100644
index 00000000000..7c2f8188d16
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/error60a.C
@@ -0,0 +1,46 @@ 
+// Like error60.C but first issues an unrelated error that
+// causes the pretty printer prefix to get set, verifying we
+// still print the source line for the "required from here"
+// message correctly in that case.
+// { dg-options "-fdiagnostics-show-caret" }
+
+template <typename Foo>
+struct my_pointer
+{
+  my_pointer (Foo *ptr) // { dg-message " initializing argument 1" }
+  : m_ptr (ptr)
+  {}
+
+  Foo *m_ptr;
+};
+
+template <typename Foo>
+void test (Foo val)
+{
+  my_pointer<Foo> ptr (val); // { dg-error "invalid conversion from 'int' to 'int\\*'" }
+}
+
+void usage ()
+{
+  unrelated_error; // { dg-error "not declared" }
+  test<int> (42); // { dg-message " required from here" }
+  /* { dg-begin-multiline-output "" }
+   unrelated_error;
+   ^~~~~~~~~~~~~~~
+     { dg-end-multiline-output "" } */
+  /* { dg-begin-multiline-output "" }
+   test<int> (42);
+   ~~~~~~~~~~^~~~
+     { dg-end-multiline-output "" } */
+}
+
+  /* { dg-begin-multiline-output "" }
+   my_pointer (Foo *ptr)
+               ~~~~~^~~
+     { dg-end-multiline-output "" } */
+  /* { dg-begin-multiline-output "" }
+   my_pointer<Foo> ptr (val);
+                        ^~~
+                        |
+                        int
+     { dg-end-multiline-output "" } */