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;

Reply via email to