https://gcc.gnu.org/g:b5a069203fc074ab75d994c4a7e0f2db6a0a00fd
commit r15-6991-gb5a069203fc074ab75d994c4a7e0f2db6a0a00fd Author: Simon Martin <si...@nasilyan.com> Date: Sun Jan 5 10:36:47 2025 +0100 c++: Friend classes don't shadow enclosing template class paramater [PR118255] 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. 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. Diff: --- 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(-) diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 0e185d3ef426..d1abb205bc7f 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 01b483ea9153..efee3e4aca36 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 000000000000..64ea41a552ba --- /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;