public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Fix PR c++/59366 A friend function template defined in a class is found without ADL
@ 2014-05-05 10:07 Momchil Velikov
  2014-05-05 10:13 ` Momchil Velikov
  2014-12-27 22:25 ` Momchil Velikov
  0 siblings, 2 replies; 10+ messages in thread
From: Momchil Velikov @ 2014-05-05 10:07 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 547 bytes --]

Hello,

A friend function, defined in a class and not declared outside should
be hidden from ordinary name lookup and only found by argument-dependent
lookup, like:

struct S
{
    friend void f() {}
    friend void g(const S &) {}
};

int
main()
{
    f(); // error
    g(S()); // correct, found by ADL
}

GCC correctly handles this case, but fails for function templates like:

struct S
{
    template<typename T> friend void f(T) {}
};

int
main()
{
    f(1); // should be an error, GCC succeeds
    f(S()); // correct, found by ADL
}

~chill


[-- Attachment #2: hidden-friend-template.diff --]
[-- Type: text/x-patch, Size: 3258 bytes --]

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 374cd0f..b374181 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,9 @@
+2014-05-05  Momchil Velikov  <momchil.velikov@gmail.com>
+
+	PR c++/59366
+	* name-lookup.c (pushdecl_maybe_friend_1): Hide friend functions
+	and function templates, declared only in the class.
+
 2014-05-03  Paolo Carlini  <paolo.carlini@oracle.com>
 
 	PR c++/58582
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index d900560..8441047 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -924,6 +924,29 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
       if (DECL_DECLARES_FUNCTION_P (t))
 	check_default_args (t);
 
+      if (TREE_CODE (x) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (x))
+        {
+	  if (is_friend)
+	    {
+	      if (t == x && !flag_friend_injection)
+		{
+		  /* This is a new friend declaration of a function or
+		     a function template, so hide it from ordinary
+		     function lookup.  */
+		  DECL_ANTICIPATED (t) = 1;
+		  DECL_HIDDEN_FRIEND_P (t) = 1;
+		}
+	    }
+	  else if (t != x && t != error_mark_node)
+	    {
+	      /* This is a non-friend re-declaration of a possibly
+		 hidden function or a function template, so don't hide
+		 it. */
+	      DECL_ANTICIPATED (t) = 0;
+	      DECL_HIDDEN_FRIEND_P (t) = 0;
+	    }
+	}
+
       if (t != x || DECL_FUNCTION_TEMPLATE_P (t))
 	return t;
 
@@ -983,16 +1006,6 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
 	    }
 	}
 
-      if (TREE_CODE (x) == FUNCTION_DECL
-	  && is_friend
-	  && !flag_friend_injection)
-	{
-	  /* This is a new declaration of a friend function, so hide
-	     it from ordinary function lookup.  */
-	  DECL_ANTICIPATED (x) = 1;
-	  DECL_HIDDEN_FRIEND_P (x) = 1;
-	}
-
       /* This name is new in its binding level.
 	 Install the new declaration and return it.  */
       if (namespace_bindings_p ())
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 3b613d9..dbd63bd 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2014-05-05  Momchil Velikov  <momchil.velikov@gmail.com>
+
+	PR c++/59366
+	* g++.dg/template/friend56.C: New
+	* g++.old-deja/g++.pt/friend5.C (main): Fix testcase. The friend
+	functions `f` should be found only by ADL.
+
 2014-05-03  Paolo Carlini  <paolo.carlini@oracle.com>
 
 	PR c++/58582
diff --git a/gcc/testsuite/g++.dg/template/friend56.C b/gcc/testsuite/g++.dg/template/friend56.C
new file mode 100644
index 0000000..7077d5e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend56.C
@@ -0,0 +1,21 @@
+// PR c++/59366
+// { dg-do compile }
+template<typename T> void f(T);
+
+struct S
+{
+  template<typename T> friend void f(T) {}
+  template<typename T> friend void g(T) {}
+  template<typename T> friend void h(T) {}
+};
+
+template<typename T> void h(T);
+
+int
+main ()
+{
+  f(1);
+  g(1); // { dg-error "'g' was not declared in this scope" }
+  g(S());
+  h(1);
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend5.C b/gcc/testsuite/g++.old-deja/g++.pt/friend5.C
index 3feeb68..edb9d62 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/friend5.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/friend5.C
@@ -14,5 +14,5 @@ class C
 
 int main()
 {
-  f(7);
+  f(C());
 }


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Fix PR c++/59366 A friend function template defined in a class is found without ADL
  2014-05-05 10:07 [PATCH] Fix PR c++/59366 A friend function template defined in a class is found without ADL Momchil Velikov
@ 2014-05-05 10:13 ` Momchil Velikov
  2014-12-27 22:25 ` Momchil Velikov
  1 sibling, 0 replies; 10+ messages in thread
From: Momchil Velikov @ 2014-05-05 10:13 UTC (permalink / raw)
  To: gcc-patches

Bootstrapped/regtested on x86_64-linux-gnu.

One test, gcc/testsuite/g++.old-deja/g++.pt/friend5.C, breaks, as it should,
and was fixed.

~chill

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Fix PR c++/59366 A friend function template defined in a class is found without ADL
  2014-05-05 10:07 [PATCH] Fix PR c++/59366 A friend function template defined in a class is found without ADL Momchil Velikov
  2014-05-05 10:13 ` Momchil Velikov
@ 2014-12-27 22:25 ` Momchil Velikov
  2014-12-27 23:47   ` Jason Merrill
  1 sibling, 1 reply; 10+ messages in thread
From: Momchil Velikov @ 2014-12-27 22:25 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jason Merrill

[-- Attachment #1: Type: text/plain, Size: 948 bytes --]

Ping


On  5.05.2014 13:06, Momchil Velikov wrote:
> Hello,
>
> A friend function, defined in a class and not declared outside should
> be hidden from ordinary name lookup and only found by argument-dependent
> lookup, like:
>
> struct S
> {
>     friend void f() {}
>     friend void g(const S &) {}
> };
>
> int
> main()
> {
>     f(); // error
>     g(S()); // correct, found by ADL
> }
>
> GCC correctly handles this case, but fails for function templates like:
>
> struct S
> {
>     template<typename T> friend void f(T) {}
> };
>
> int
> main()
> {
>     f(1); // should be an error, GCC succeeds
>     f(S()); // correct, found by ADL
> }
>

Bootstrapped and regtested again on top of:
Target: x86_64-unknown-linux-gnu
Configured with: /home/chill/src/gcc-friend-define/configure 
--prefix=/home/chill/opt/gcc-friend-define --enable-languages=c,c++ 
--disable-multilib
Thread model: posix
gcc version 5.0.0 20141227 (experimental) (GCC)




[-- Attachment #2: hidden-friend-template-59366.diff --]
[-- Type: text/x-patch, Size: 2380 bytes --]

diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index b982451..5059e14 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -927,6 +927,29 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
       if (DECL_DECLARES_FUNCTION_P (t))
 	check_default_args (t);
 
+      if (TREE_CODE (x) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (x))
+        {
+	  if (is_friend)
+	    {
+	      if (t == x && !flag_friend_injection)
+		{
+		  /* This is a new friend declaration of a function or
+		     a function template, so hide it from ordinary
+		     function lookup.  */
+		  DECL_ANTICIPATED (t) = 1;
+		  DECL_HIDDEN_FRIEND_P (t) = 1;
+		}
+	    }
+	  else if (t != x && t != error_mark_node)
+	    {
+	      /* This is a non-friend re-declaration of a possibly
+		 hidden function or a function template, so don't hide
+		 it. */
+	      DECL_ANTICIPATED (t) = 0;
+	      DECL_HIDDEN_FRIEND_P (t) = 0;
+	    }
+	}
+
       if (t != x || DECL_FUNCTION_TEMPLATE_P (t))
 	return t;
 
@@ -987,16 +1010,6 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
 	    }
 	}
 
-      if (TREE_CODE (x) == FUNCTION_DECL
-	  && is_friend
-	  && !flag_friend_injection)
-	{
-	  /* This is a new declaration of a friend function, so hide
-	     it from ordinary function lookup.  */
-	  DECL_ANTICIPATED (x) = 1;
-	  DECL_HIDDEN_FRIEND_P (x) = 1;
-	}
-
       /* This name is new in its binding level.
 	 Install the new declaration and return it.  */
       if (namespace_bindings_p ())
diff --git a/gcc/testsuite/g++.dg/template/friend57.C b/gcc/testsuite/g++.dg/template/friend57.C
new file mode 100644
index 0000000..7077d5e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend57.C
@@ -0,0 +1,21 @@
+// PR c++/59366
+// { dg-do compile }
+template<typename T> void f(T);
+
+struct S
+{
+  template<typename T> friend void f(T) {}
+  template<typename T> friend void g(T) {}
+  template<typename T> friend void h(T) {}
+};
+
+template<typename T> void h(T);
+
+int
+main ()
+{
+  f(1);
+  g(1); // { dg-error "'g' was not declared in this scope" }
+  g(S());
+  h(1);
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend5.C b/gcc/testsuite/g++.old-deja/g++.pt/friend5.C
index 3feeb68..edb9d62 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/friend5.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/friend5.C
@@ -14,5 +14,5 @@ class C
 
 int main()
 {
-  f(7);
+  f(C());
 }


[-- Attachment #3: hidden-friend-template-59366.ChangeLog --]
[-- Type: text/plain, Size: 425 bytes --]

/cp
2014-12-27  Momchil Velikov  <momchil.velikov@gmail.com>

	PR c++/59366
	* name-lookup.c (pushdecl_maybe_friend_1): Hide friend functions
	and function templates, declared only in the class.

/testsuite
2014-12-27  Momchil Velikov  <momchil.velikov@gmail.com>

	PR c++/59366
	* g++.dg/template/friend57.C: New
	* g++.old-deja/g++.pt/friend5.C (main): Fix testcase. The friend
	functions `f` should be found only by ADL.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Fix PR c++/59366 A friend function template defined in a class is found without ADL
  2014-12-27 22:25 ` Momchil Velikov
@ 2014-12-27 23:47   ` Jason Merrill
  2014-12-29  1:42     ` Momchil Velikov
  0 siblings, 1 reply; 10+ messages in thread
From: Jason Merrill @ 2014-12-27 23:47 UTC (permalink / raw)
  To: Momchil Velikov, gcc-patches

On 12/27/2014 04:38 PM, Momchil Velikov wrote:
> +	  else if (t != x && t != error_mark_node)
> +	    {
> +	      /* This is a non-friend re-declaration of a possibly
> +		 hidden function or a function template, so don't hide
> +		 it. */
> +	      DECL_ANTICIPATED (t) = 0;
> +	      DECL_HIDDEN_FRIEND_P (t) = 0;
> +	    }

Doesn't duplicate_decls handle clearing these?

Jason

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Fix PR c++/59366 A friend function template defined in a class is found without ADL
  2014-12-27 23:47   ` Jason Merrill
@ 2014-12-29  1:42     ` Momchil Velikov
  2014-12-30 16:24       ` Jason Merrill
  0 siblings, 1 reply; 10+ messages in thread
From: Momchil Velikov @ 2014-12-29  1:42 UTC (permalink / raw)
  To: Jason Merrill, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 746 bytes --]

On 28.12.2014 01:36, Jason Merrill wrote:
> On 12/27/2014 04:38 PM, Momchil Velikov wrote:
>> +      else if (t != x && t != error_mark_node)
>> +        {
>> +          /* This is a non-friend re-declaration of a possibly
>> +         hidden function or a function template, so don't hide
>> +         it. */
>> +          DECL_ANTICIPATED (t) = 0;
>> +          DECL_HIDDEN_FRIEND_P (t) = 0;
>> +        }
>
> Doesn't duplicate_decls handle clearing these?

It does, but only for functions (in somewhat obscure way, by not
setting the flags in DECL_LANG_SPECIFIC(newdecl)).

It does not for function templates. Indeed, it makes sense to do this
in duplicate_decls(). How about like in the attached patch?

(bootstrap and testing in progress)



[-- Attachment #2: hidden-friend-wip.diff --]
[-- Type: text/x-patch, Size: 2431 bytes --]

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index bbaf3d6..efd472a 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1865,6 +1865,19 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
   DECL_ATTRIBUTES (newdecl)
     = (*targetm.merge_decl_attributes) (olddecl, newdecl);
 
+  if (DECL_DECLARES_FUNCTION_P (olddecl) && DECL_DECLARES_FUNCTION_P (newdecl))
+    {
+      olddecl_friend = DECL_FRIEND_P (olddecl);
+      hidden_friend = (DECL_ANTICIPATED (olddecl)
+		       && DECL_HIDDEN_FRIEND_P (olddecl)
+		       && newdecl_is_friend);
+      if (!hidden_friend)
+	{
+	  DECL_ANTICIPATED (olddecl) = 0;
+	  DECL_HIDDEN_FRIEND_P (olddecl) = 0;
+	}
+    }
+
   if (TREE_CODE (newdecl) == TEMPLATE_DECL)
     {
       tree old_result;
@@ -2147,10 +2160,6 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
       if (DECL_DECLARES_FUNCTION_P (newdecl))
 	{
 	  DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl);
-	  olddecl_friend = DECL_FRIEND_P (olddecl);
-	  hidden_friend = (DECL_ANTICIPATED (olddecl)
-			   && DECL_HIDDEN_FRIEND_P (olddecl)
-			   && newdecl_is_friend);
 	  DECL_BEFRIENDING_CLASSES (newdecl)
 	    = chainon (DECL_BEFRIENDING_CLASSES (newdecl),
 		       DECL_BEFRIENDING_CLASSES (olddecl));
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index b982451..69a0da6 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -925,7 +925,18 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
 	}
 
       if (DECL_DECLARES_FUNCTION_P (t))
-	check_default_args (t);
+	{
+	  check_default_args (t);
+
+	  if (is_friend && t == x && !flag_friend_injection)
+	    {
+	      /* This is a new friend declaration of a function or a
+		 function template, so hide it from ordinary function
+		 lookup.  */
+	      DECL_ANTICIPATED (t) = 1;
+	      DECL_HIDDEN_FRIEND_P (t) = 1;
+	    }
+	}
 
       if (t != x || DECL_FUNCTION_TEMPLATE_P (t))
 	return t;
@@ -987,16 +998,6 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
 	    }
 	}
 
-      if (TREE_CODE (x) == FUNCTION_DECL
-	  && is_friend
-	  && !flag_friend_injection)
-	{
-	  /* This is a new declaration of a friend function, so hide
-	     it from ordinary function lookup.  */
-	  DECL_ANTICIPATED (x) = 1;
-	  DECL_HIDDEN_FRIEND_P (x) = 1;
-	}
-
       /* This name is new in its binding level.
 	 Install the new declaration and return it.  */
       if (namespace_bindings_p ())


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Fix PR c++/59366 A friend function template defined in a class is found without ADL
  2014-12-29  1:42     ` Momchil Velikov
@ 2014-12-30 16:24       ` Jason Merrill
  2014-12-30 16:25         ` Momchil Velikov
  0 siblings, 1 reply; 10+ messages in thread
From: Jason Merrill @ 2014-12-30 16:24 UTC (permalink / raw)
  To: Momchil Velikov, gcc-patches

On 12/28/2014 01:45 PM, Momchil Velikov wrote:
> +      if (!hidden_friend)
> +	{
> +	  DECL_ANTICIPATED (olddecl) = 0;
> +	  DECL_HIDDEN_FRIEND_P (olddecl) = 0;
> +	}

Why not add this...

> @@ -2147,10 +2160,6 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
>         if (DECL_DECLARES_FUNCTION_P (newdecl))
>   	{
>   	  DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl);
> -	  olddecl_friend = DECL_FRIEND_P (olddecl);
> -	  hidden_friend = (DECL_ANTICIPATED (olddecl)
> -			   && DECL_HIDDEN_FRIEND_P (olddecl)
> -			   && newdecl_is_friend);

...here?  I don't see a reason why a function template wouldn't hit this 
block.

Jason

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Fix PR c++/59366 A friend function template defined in a class is found without ADL
  2014-12-30 16:24       ` Jason Merrill
@ 2014-12-30 16:25         ` Momchil Velikov
  2015-01-05 13:57           ` Jason Merrill
  0 siblings, 1 reply; 10+ messages in thread
From: Momchil Velikov @ 2014-12-30 16:25 UTC (permalink / raw)
  To: Jason Merrill, gcc-patches

On 30.12.2014 17:54, Jason Merrill wrote:
> On 12/28/2014 01:45 PM, Momchil Velikov wrote:
>> +      if (!hidden_friend)
>> +    {
>> +      DECL_ANTICIPATED (olddecl) = 0;
>> +      DECL_HIDDEN_FRIEND_P (olddecl) = 0;
>> +    }
>
> Why not add this...
>
>> @@ -2147,10 +2160,6 @@ duplicate_decls (tree newdecl, tree olddecl,
>> bool newdecl_is_friend)
>>         if (DECL_DECLARES_FUNCTION_P (newdecl))
>>       {
>>         DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl);
>> -      olddecl_friend = DECL_FRIEND_P (olddecl);
>> -      hidden_friend = (DECL_ANTICIPATED (olddecl)
>> -               && DECL_HIDDEN_FRIEND_P (olddecl)
>> -               && newdecl_is_friend);
>
> ...here?  I don't see a reason why a function template wouldn't hit this
> block.

A function template enters the body of the if statement at line 1881,

   if (TREE_CODE (newdecl) == TEMPLATE_DECL)

and exits the function at line 1951 with

       return olddecl;



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Fix PR c++/59366 A friend function template defined in a class is found without ADL
  2014-12-30 16:25         ` Momchil Velikov
@ 2015-01-05 13:57           ` Jason Merrill
  2015-01-05 19:30             ` Momchil Velikov
  0 siblings, 1 reply; 10+ messages in thread
From: Jason Merrill @ 2015-01-05 13:57 UTC (permalink / raw)
  To: Momchil Velikov, gcc-patches

On 12/30/2014 11:24 AM, Momchil Velikov wrote:
> A function template enters the body of the if statement at line 1881,
>
>    if (TREE_CODE (newdecl) == TEMPLATE_DECL)
>
> and exits the function at line 1951 with
>
>        return olddecl;

Ah, yes.  The patch is OK, then, but still needs ChangeLog and testcase.

Jason

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Fix PR c++/59366 A friend function template defined in a class is found without ADL
  2015-01-05 13:57           ` Jason Merrill
@ 2015-01-05 19:30             ` Momchil Velikov
  2015-01-15 21:26               ` Jason Merrill
  0 siblings, 1 reply; 10+ messages in thread
From: Momchil Velikov @ 2015-01-05 19:30 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jason Merrill

[-- Attachment #1: Type: text/plain, Size: 711 bytes --]

On  5.01.2015 15:55, Jason Merrill wrote:
> On 12/30/2014 11:24 AM, Momchil Velikov wrote:
>> A function template enters the body of the if statement at line 1881,
>>
>>    if (TREE_CODE (newdecl) == TEMPLATE_DECL)
>>
>> and exits the function at line 1951 with
>>
>>        return olddecl;
>
> Ah, yes.  The patch is OK, then, but still needs ChangeLog and testcase.
>
> Jason
>

Bootstrapped/tested again with:

Target: x86_64-unknown-linux-gnu
Configured with: /home/chill/src/gcc-master/configure 
--prefix=/home/chill/opt/gcc-master --enable-languages=c,c++
Thread model: posix
gcc version 5.0.0 20150105 (experimental) [master revision 
113a5d9:4b40b3c:c1fd77316d75af1122efb4b8b2988a86599558dc] (GCC)





[-- Attachment #2: gcc-friend-59366.diff --]
[-- Type: text/x-patch, Size: 3321 bytes --]

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 2fea106..82401ab 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1865,6 +1865,19 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
   DECL_ATTRIBUTES (newdecl)
     = (*targetm.merge_decl_attributes) (olddecl, newdecl);
 
+  if (DECL_DECLARES_FUNCTION_P (olddecl) && DECL_DECLARES_FUNCTION_P (newdecl))
+    {
+      olddecl_friend = DECL_FRIEND_P (olddecl);
+      hidden_friend = (DECL_ANTICIPATED (olddecl)
+		       && DECL_HIDDEN_FRIEND_P (olddecl)
+		       && newdecl_is_friend);
+      if (!hidden_friend)
+	{
+	  DECL_ANTICIPATED (olddecl) = 0;
+	  DECL_HIDDEN_FRIEND_P (olddecl) = 0;
+	}
+    }
+
   if (TREE_CODE (newdecl) == TEMPLATE_DECL)
     {
       tree old_result;
@@ -2147,10 +2160,6 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
       if (DECL_DECLARES_FUNCTION_P (newdecl))
 	{
 	  DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl);
-	  olddecl_friend = DECL_FRIEND_P (olddecl);
-	  hidden_friend = (DECL_ANTICIPATED (olddecl)
-			   && DECL_HIDDEN_FRIEND_P (olddecl)
-			   && newdecl_is_friend);
 	  DECL_BEFRIENDING_CLASSES (newdecl)
 	    = chainon (DECL_BEFRIENDING_CLASSES (newdecl),
 		       DECL_BEFRIENDING_CLASSES (olddecl));
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 2dfb00d..d92a2cd 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -925,7 +925,18 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
 	}
 
       if (DECL_DECLARES_FUNCTION_P (t))
-	check_default_args (t);
+	{
+	  check_default_args (t);
+
+	  if (is_friend && t == x && !flag_friend_injection)
+	    {
+	      /* This is a new friend declaration of a function or a
+		 function template, so hide it from ordinary function
+		 lookup.  */
+	      DECL_ANTICIPATED (t) = 1;
+	      DECL_HIDDEN_FRIEND_P (t) = 1;
+	    }
+	}
 
       if (t != x || DECL_FUNCTION_TEMPLATE_P (t))
 	return t;
@@ -987,16 +998,6 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
 	    }
 	}
 
-      if (TREE_CODE (x) == FUNCTION_DECL
-	  && is_friend
-	  && !flag_friend_injection)
-	{
-	  /* This is a new declaration of a friend function, so hide
-	     it from ordinary function lookup.  */
-	  DECL_ANTICIPATED (x) = 1;
-	  DECL_HIDDEN_FRIEND_P (x) = 1;
-	}
-
       /* This name is new in its binding level.
 	 Install the new declaration and return it.  */
       if (namespace_bindings_p ())
diff --git a/gcc/testsuite/g++.dg/template/friend57.C b/gcc/testsuite/g++.dg/template/friend57.C
new file mode 100644
index 0000000..7077d5e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend57.C
@@ -0,0 +1,21 @@
+// PR c++/59366
+// { dg-do compile }
+template<typename T> void f(T);
+
+struct S
+{
+  template<typename T> friend void f(T) {}
+  template<typename T> friend void g(T) {}
+  template<typename T> friend void h(T) {}
+};
+
+template<typename T> void h(T);
+
+int
+main ()
+{
+  f(1);
+  g(1); // { dg-error "'g' was not declared in this scope" }
+  g(S());
+  h(1);
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend5.C b/gcc/testsuite/g++.old-deja/g++.pt/friend5.C
index 3feeb68..edb9d62 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/friend5.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/friend5.C
@@ -14,5 +14,5 @@ class C
 
 int main()
 {
-  f(7);
+  f(C());
 }



[-- Attachment #3: gcc-friend-59366.ChangeLog --]
[-- Type: text/plain, Size: 549 bytes --]

/cp
2015-01-05  Momchil Velikov  <momchil.velikov@gmail.com>

	PR c++/59366
	* name-lookup.c (pushdecl_maybe_friend_1): Hide friend functions
	and function templates, declared only in the class.
	* decl.c (duplicate_decls): Reveal hidden friend functions or
	function templates, if they are redeclared outside the class.

/testsuite
2015-01-05  Momchil Velikov  <momchil.velikov@gmail.com>

	PR c++/59366
	* g++.dg/template/friend57.C: New
	* g++.old-deja/g++.pt/friend5.C (main): Fix testcase. The friend
	function `f` should be found only by ADL.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] Fix PR c++/59366 A friend function template defined in a class is found without ADL
  2015-01-05 19:30             ` Momchil Velikov
@ 2015-01-15 21:26               ` Jason Merrill
  0 siblings, 0 replies; 10+ messages in thread
From: Jason Merrill @ 2015-01-15 21:26 UTC (permalink / raw)
  To: Momchil Velikov, gcc-patches

Applied, thanks.

Jason

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2015-01-15 21:02 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-05 10:07 [PATCH] Fix PR c++/59366 A friend function template defined in a class is found without ADL Momchil Velikov
2014-05-05 10:13 ` Momchil Velikov
2014-12-27 22:25 ` Momchil Velikov
2014-12-27 23:47   ` Jason Merrill
2014-12-29  1:42     ` Momchil Velikov
2014-12-30 16:24       ` Jason Merrill
2014-12-30 16:25         ` Momchil Velikov
2015-01-05 13:57           ` Jason Merrill
2015-01-05 19:30             ` Momchil Velikov
2015-01-15 21:26               ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).