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]

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


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)



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: hidden-friend-template-59366.ChangeLog
Description: Text document


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