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.veli...@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.carl...@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.veli...@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.carl...@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()); }