On 1/17/25 1:50 AM, Simon Martin wrote:
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?

OK, I guess it seems safe enough.

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;



Reply via email to