This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


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

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]