diff mbox

Fix PR c++/59366 A friend function template defined in a class is found without ADL

Message ID 54AAE64E.6010505@gmail.com
State New
Headers show

Commit Message

Momchil Velikov Jan. 5, 2015, 7:30 p.m. UTC
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)
/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.

Comments

Jason Merrill Jan. 15, 2015, 9:02 p.m. UTC | #1
Applied, thanks.

Jason
diff mbox

Patch

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());
 }