This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix PR c++/59366 A friend function template defined in a class is found without ADL
- From: Momchil Velikov <momchil dot velikov at gmail dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 05 May 2014 13:06:56 +0300
- Subject: [PATCH] Fix PR c++/59366 A friend function template defined in a class is found without ADL
- Authentication-results: sourceware.org; auth=none
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());
}