]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Friend classes don't shadow enclosing template class paramater [PR118255]
authorSimon Martin <simon@nasilyan.com>
Sun, 5 Jan 2025 09:36:47 +0000 (10:36 +0100)
committerSimon Martin <simartin@gcc.gnu.org>
Mon, 20 Jan 2025 05:14:28 +0000 (06:14 +0100)
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.

(cherry picked from commit b5a069203fc074ab75d994c4a7e0f2db6a0a00fd)

gcc/cp/name-lookup.cc
gcc/testsuite/g++.dg/lookup/pr99116-1.C
gcc/testsuite/g++.dg/template/friend84.C [new file with mode: 0644]

index 48c7badc865c4420c7ab67ece0a4a18849f02a81..41bd4dd8dcac8cf4b700292d7c072494592d9603 100644 (file)
@@ -3741,7 +3741,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))
        {
index 01b483ea9153e70f7872646d0dc52ca680110fe0..efee3e4aca36e4fecc6430d7d84f3f967ca15b2b 100644 (file)
@@ -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 (file)
index 0000000..64ea41a
--- /dev/null
@@ -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;