On Fri, 28 Jun 2024, Simon Martin wrote:

> We currently ICE when emitting the error message for this invalid code:
> 
> === cut here ===
> struct foo {
>   template<int> void not_const() {}
> };
> void fn(const foo& obj) {
>   obj.not_const<5>();
> }
> === cut here ===
> 
> The problem is that get_fndecl_argument_location assumes that it has a
> FUNCTION_DECL in its hands to find the location of the bad argument. It might
> however have a TEMPLATE_DECL if there's a single candidate that cannot be
> instantiated, like here.
> 
> This patch simply defaults to using the FNDECL's location in this case, which
> fixes this PR.
> 
> Successfully tested on x86_64-pc-linux-gnu.
> 
>       PR c++/115364
> 
> gcc/cp/ChangeLog:
> 
>       * call.cc (get_fndecl_argument_location): Use FNDECL's location for
>       TEMPLATE_DECLs.
> 
> gcc/testsuite/ChangeLog:
> 
>       * g++.dg/overload/template7.C: New test.
> 
> ---
>  gcc/cp/call.cc                            | 4 ++++
>  gcc/testsuite/g++.dg/overload/template7.C | 9 +++++++++
>  2 files changed, 13 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/overload/template7.C
> 
> diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> index 7bbc1fb0c78..d5ff2311e63 100644
> --- a/gcc/cp/call.cc
> +++ b/gcc/cp/call.cc
> @@ -8347,6 +8347,10 @@ get_fndecl_argument_location (tree fndecl, int argnum)
>    if (DECL_ARTIFICIAL (fndecl))
>      return DECL_SOURCE_LOCATION (fndecl);
>  
> +  /* Use FNDECL's location for TEMPLATE_DECLs.  */
> +  if (TREE_CODE (fndecl) == TEMPLATE_DECL)
> +    return DECL_SOURCE_LOCATION (fndecl);
> +

For TEMPLATE_DECL fndecl, it'd be more natural to return the
corresponding argument location of its DECL_TEMPLATE_RESULT (which
should be a FUNCTION_DECL).  The STRIP_TEMPLATE macro would be
convenient to use here.


It seems this doesn't fix the regression completely however because
in GCC 11 the code was rejected with a "permerror" (which can be
downgraded to a warning with -fpermissive):

  115364.C: In function ‘void fn(const foo&)’:
  115364.C:5:43: error: passing ‘const foo’ as ‘this’ argument discards 
qualifiers [-fpermissive]
      5 | void fn(const foo& obj) { obj.not_const<5>(); }
        |                           ~~~~~~~~~~~~~~~~^~
  115364.C:3:24: note:   in call to ‘void foo::not_const() [with int 
<anonymous> = 5]’
      3 |     template<int> void not_const() {}
        |                        ^~~~~~~~~

and we now reject with an ordinary error:

  115364.C: In function ‘void fn(const foo&)’:
  115364.C:5:27: error: cannot convert ‘const foo*’ to ‘foo*’
      5 | void fn(const foo& obj) { obj.not_const<5>(); }
        |                           ^~~
        |                           |
        |                           const foo*
  115364.C:3:24: note:   initializing argument 'this' of ‘template<int 
<anonymous> > void foo::not_const()’
      3 |     template<int> void not_const() {}
        |                        ^~~~~~~~~

To restore the error into a permerror, we need to figure out why we're
unexpectedly hitting this code path with a TEMPLATE_DECL, and why it's
necessary that the member function needs to take no arguments.  It turns
out I looked into this and submitted a patch for PR106760 (of which this
PR115364 is a dup) last year:
https://gcc.gnu.org/pipermail/gcc-patches/2023-June/620514.html

The patch was approved, but I lost track of it and never pushed it :/
I'm going to go ahead and push that fix shortly, sorry for not doing so
earlier.  Thanks for looking into this issue!

>    int i;
>    tree param;
>  
> diff --git a/gcc/testsuite/g++.dg/overload/template7.C 
> b/gcc/testsuite/g++.dg/overload/template7.C
> new file mode 100644
> index 00000000000..67191c4ff62
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/overload/template7.C
> @@ -0,0 +1,9 @@
> +// PR c++/115364
> +// { dg-do compile }
> +
> +struct foo {
> +  template<int> void not_const() {} // { dg-note "initializing" }
> +};
> +void fn(const foo& obj) {
> +  obj.not_const<5>(); // { dg-error "cannot convert" }
> +}
> -- 
> 2.44.0
> 
> 
> 
> 

Reply via email to