On 17 Jan 2025, at 0:12, Jason Merrill wrote: > On 1/5/25 11:19 AM, Simon Martin wrote: >> We currently reject the following code >> >> === code here === >> template <int non_template> struct S { friend class non_template; }; >> class non_template {}; >> S<0> s; >> === code here === >> >> While EDG agrees with the current behaviour, clang and MSVC don't >> (see >> https://godbolt.org/z/69TGaabhd), and I believe that this code is >> valid, >> since the friend clause does not actually declare a type, so it >> cannot >> shadow anything. The fact that we didn't error out if the >> non_template >> class was declared before S backs this up as well. >> >> This patch fixes this by skipping the call to check_template_shadow >> for >> hidden bindings. > > OK. Thanks Jason. Since it’s a regression from GCC 8, OK as well for active branches?
Simon >> Successfully tested on x86_64-pc-linux-gnu. >> >> PR c++/118255 >> >> gcc/cp/ChangeLog: >> >> * name-lookup.cc (pushdecl): Don't call check_template_shadow >> for hidden bindings. >> >> gcc/testsuite/ChangeLog: >> >> * g++.dg/lookup/pr99116-1.C: Adjust test expectation. >> * g++.dg/template/friend84.C: New test. >> >> --- >> gcc/cp/name-lookup.cc | 5 ++++- >> gcc/testsuite/g++.dg/lookup/pr99116-1.C | 2 +- >> gcc/testsuite/g++.dg/template/friend84.C | 26 >> ++++++++++++++++++++++++ >> 3 files changed, 31 insertions(+), 2 deletions(-) >> create mode 100644 gcc/testsuite/g++.dg/template/friend84.C >> >> diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc >> index 0e185d3ef42..d1abb205bc7 100644 >> --- a/gcc/cp/name-lookup.cc >> +++ b/gcc/cp/name-lookup.cc >> @@ -4040,7 +4040,10 @@ pushdecl (tree decl, bool hiding) >> if (old && anticipated_builtin_p (old)) >> old = OVL_CHAIN (old); >> - check_template_shadow (decl); >> + if (hiding) >> + ; /* Hidden bindings don't shadow anything. */ >> + else >> + check_template_shadow (decl); >> if (DECL_DECLARES_FUNCTION_P (decl)) >> { >> diff --git a/gcc/testsuite/g++.dg/lookup/pr99116-1.C >> b/gcc/testsuite/g++.dg/lookup/pr99116-1.C >> index 01b483ea915..efee3e4aca3 100644 >> --- a/gcc/testsuite/g++.dg/lookup/pr99116-1.C >> +++ b/gcc/testsuite/g++.dg/lookup/pr99116-1.C >> @@ -2,7 +2,7 @@ >> template<int T> struct Z { >> - friend struct T; // { dg-error "shadows template parameter" } >> + friend struct T; // { dg-bogus "shadows template parameter" } >> }; >> struct Y { >> diff --git a/gcc/testsuite/g++.dg/template/friend84.C >> b/gcc/testsuite/g++.dg/template/friend84.C >> new file mode 100644 >> index 00000000000..64ea41a552b >> --- /dev/null >> +++ b/gcc/testsuite/g++.dg/template/friend84.C >> @@ -0,0 +1,26 @@ >> +// PR c++/118255 >> +// { dg-do "compile" } >> + >> +// The PR's case, that used to error out. >> +template <int non_template> >> +struct S { >> + friend class non_template; // { dg-bogus "shadows template >> parameter" } >> +}; >> + >> +class non_template {}; >> +S<0> s; >> + >> +// We already accepted cases where the friend is already declared. >> +template <int non_template> >> +struct T { >> + friend class non_template; >> +}; >> +T<0> t; >> + >> +// We should reject (re)declarations. >> +template <int non_template> >> +struct U { >> + class non_template {}; // { dg-error "shadows template parameter" >> } >> + void non_template () {} // { dg-error "shadows template parameter" >> } >> +}; >> +U<0> u;