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 > > > >