aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Martin <simon@nasilyan.com>2025-01-05 10:36:47 +0100
committerSimon Martin <simon@nasilyan.com>2025-01-17 09:30:19 +0100
commitb5a069203fc074ab75d994c4a7e0f2db6a0a00fd (patch)
treedd585c24df6ef1b465505c0dd686947f8ff4989c
parent44d21551362f9076617200595f49d4260d1f40a9 (diff)
downloadgcc-b5a069203fc074ab75d994c4a7e0f2db6a0a00fd.zip
gcc-b5a069203fc074ab75d994c4a7e0f2db6a0a00fd.tar.gz
gcc-b5a069203fc074ab75d994c4a7e0f2db6a0a00fd.tar.bz2
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.
-rw-r--r--gcc/cp/name-lookup.cc5
-rw-r--r--gcc/testsuite/g++.dg/lookup/pr99116-1.C2
-rw-r--r--gcc/testsuite/g++.dg/template/friend84.C26
3 files changed, 31 insertions, 2 deletions
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 0e185d3..d1abb20 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 01b483e..efee3e4 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 0000000..64ea41a
--- /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;