From 0cf4820dd596a5884fb59c2c9874ed100a7ff614 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Fri, 15 Dec 2017 15:04:59 +0000 Subject: [PATCH] [PR C++/59930] template friend classes & default args https://gcc.gnu.org/ml/gcc-patches/2017-12/msg01055.html PR c++/59930 * decl.c (xref_tag_1): Correct comments about template friends and default args. * friend.c (make_friend_class): Move comments concerning self-friendliness to code dealing with such. * pt.c (check_default_tmpl_args): Deal with template friend classes too. (push_template_decl_real): Check default args for non-function template friends. PR c++/59930 * g++.dg/cpp0x/temp_default4.C: Adjust diagnostic. * g++.old-deja/g++.pt/friend23.C: Likewise. * g++.old-deja/g++.pt/friend24.C: Delete. From-SVN: r255698 --- gcc/cp/ChangeLog | 12 ++++++ gcc/cp/decl.c | 40 ++++++++------------ gcc/cp/friend.c | 15 ++++---- gcc/cp/pt.c | 20 ++++++---- gcc/testsuite/ChangeLog | 7 ++++ gcc/testsuite/g++.dg/cpp0x/temp_default4.C | 4 +- gcc/testsuite/g++.old-deja/g++.pt/friend23.C | 11 +++--- gcc/testsuite/g++.old-deja/g++.pt/friend24.C | 18 --------- 8 files changed, 62 insertions(+), 65 deletions(-) delete mode 100644 gcc/testsuite/g++.old-deja/g++.pt/friend24.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d7a1dde686f..37c129d174f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2017-12-15 Nathan Sidwell + + PR c++/59930 + * decl.c (xref_tag_1): Correct comments about template friends and + default args. + * friend.c (make_friend_class): Move comments concerning + self-friendliness to code dealing with such. + * pt.c (check_default_tmpl_args): Deal with template friend + classes too. + (push_template_decl_real): Check default args for non-function + template friends. + 2017-12-14 Bernd Edlinger * decl2.c (start_static_storage_duration_function): Avoid warning. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 445c23c5dac..63a7b92b3bc 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -13538,37 +13538,28 @@ xref_tag_1 (enum tag_types tag_code, tree name, processing a (member) template declaration of a template class, we must be very careful; consider: - template - struct S1 + template struct S1 - template - struct S2 - { template - friend struct S1; }; + template struct S2 + { + template friend struct S1; + }; Here, the S2::S1 declaration should not be confused with the outer declaration. In particular, the inner version should - have a template parameter of level 2, not level 1. This - would be particularly important if the member declaration - were instead: - - template friend struct S1; + have a template parameter of level 2, not level 1. - say, when we should tsubst into `U' when instantiating - S2. On the other hand, when presented with: + On the other hand, when presented with: - template - struct S1 { - template - struct S2 {}; - template - friend struct S2; + template struct S1 + { + template struct S2 {}; + template friend struct S2; }; - we must find the inner binding eventually. We - accomplish this by making sure that the new type we - create to represent this declaration has the right - TYPE_CONTEXT. */ + the friend must find S1::S2 eventually. We accomplish this + by making sure that the new type we create to represent this + declaration has the right TYPE_CONTEXT. */ context = TYPE_CONTEXT (t); t = NULL_TREE; } @@ -13622,9 +13613,10 @@ xref_tag_1 (enum tag_types tag_code, tree name, return error_mark_node; } - /* Make injected friend class visible. */ if (scope != ts_within_enclosing_non_class && TYPE_HIDDEN_P (t)) { + /* This is no longer an invisible friend. Make it + visible. */ tree decl = TYPE_NAME (t); DECL_ANTICIPATED (decl) = false; diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c index ef93bfe39ec..e99ae681f1e 100644 --- a/gcc/cp/friend.c +++ b/gcc/cp/friend.c @@ -283,21 +283,18 @@ make_friend_class (tree type, tree friend_type, bool complain) return; if (friend_depth) - /* If the TYPE is a template then it makes sense for it to be - friends with itself; this means that each instantiation is - friends with all other instantiations. */ { + /* [temp.friend] Friend declarations shall not declare partial + specializations. */ if (CLASS_TYPE_P (friend_type) && CLASSTYPE_TEMPLATE_SPECIALIZATION (friend_type) && uses_template_parms (friend_type)) { - /* [temp.friend] - Friend declarations shall not declare partial - specializations. */ error ("partial specialization %qT declared %", friend_type); return; } + if (TYPE_TEMPLATE_INFO (friend_type) && !PRIMARY_TEMPLATE_P (TYPE_TI_TEMPLATE (friend_type))) { @@ -311,7 +308,11 @@ make_friend_class (tree type, tree friend_type, bool complain) return; } } - else if (same_type_p (type, friend_type)) + + /* It makes sense for a template class to be friends with itself, + that means the instantiations can be friendly. Other cases are + not so meaningful. */ + if (!friend_depth && same_type_p (type, friend_type)) { if (complain) warning (0, "class %qT is implicitly friends with itself", diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 69b95351d8b..5a6a7cff939 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -4980,9 +4980,10 @@ fixed_parameter_pack_p (tree parm) a primary template. IS_PARTIAL is true if DECL is a partial specialization. - IS_FRIEND_DECL is nonzero if DECL is a friend function template - declaration (but not a definition); 1 indicates a declaration, 2 - indicates a redeclaration. When IS_FRIEND_DECL=2, no errors are + IS_FRIEND_DECL is nonzero if DECL is either a non-defining friend + function template declaration or a friend class template + declaration. In the function case, 1 indicates a declaration, 2 + indicates a redeclaration. When IS_FRIEND_DECL=2, no errors are emitted for extraneous default arguments. Returns TRUE if there were no errors found, FALSE otherwise. */ @@ -5130,7 +5131,7 @@ check_default_tmpl_args (tree decl, tree parms, bool is_primary, msg = G_("default template arguments may not be used in function template " "friend re-declaration"); else if (is_friend_decl) - msg = G_("default template arguments may not be used in function template " + msg = G_("default template arguments may not be used in template " "friend declarations"); else if (TREE_CODE (decl) == FUNCTION_DECL && (cxx_dialect == cxx98)) msg = G_("default template arguments may not be used in function templates " @@ -5277,7 +5278,7 @@ push_template_decl_real (tree decl, bool is_friend) is_friend = true; if (is_friend) - /* For a friend, we want the context of the friend function, not + /* For a friend, we want the context of the friend, not the type of which it is a friend. */ ctx = CP_DECL_CONTEXT (decl); else if (CP_DECL_CONTEXT (decl) @@ -5380,9 +5381,12 @@ push_template_decl_real (tree decl, bool is_friend) } /* Check to see that the rules regarding the use of default - arguments are not being violated. */ - check_default_tmpl_args (decl, current_template_parms, - is_primary, is_partial, /*is_friend_decl=*/0); + arguments are not being violated. We check args for a friend + functions when we know whether it's a definition, introducing + declaration or re-declaration. */ + if (!is_friend || TREE_CODE (decl) != FUNCTION_DECL) + check_default_tmpl_args (decl, current_template_parms, + is_primary, is_partial, is_friend); /* Ensure that there are no parameter packs in the type of this declaration that have not been expanded. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c87d2cd0980..2a73f82c97f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2017-12-14 Nathan Sidwell + + PR c++/59930 + * g++.dg/cpp0x/temp_default4.C: Adjust diagnostic. + * g++.old-deja/g++.pt/friend23.C: Likewise. + * g++.old-deja/g++.pt/friend24.C: Delete. + 2017-12-15 Jakub Jelinek PR tree-optimization/83269 diff --git a/gcc/testsuite/g++.dg/cpp0x/temp_default4.C b/gcc/testsuite/g++.dg/cpp0x/temp_default4.C index 783ff5b19d9..0dc58548255 100644 --- a/gcc/testsuite/g++.dg/cpp0x/temp_default4.C +++ b/gcc/testsuite/g++.dg/cpp0x/temp_default4.C @@ -1,9 +1,9 @@ // { dg-do compile { target c++11 } } class X { - template friend void f(X) { } + template friend void f(X) { } // OK template friend void g(X); // { dg-message "previously declared here" } - template friend void h(X); // { dg-error "function template friend" } + template friend void h(X); // { dg-error "template friend" } }; template void g(X) // { dg-error "default template argument" } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend23.C b/gcc/testsuite/g++.old-deja/g++.pt/friend23.C index 93ce72e3025..b79a599a45e 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/friend23.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/friend23.C @@ -1,10 +1,9 @@ -// { dg-do assemble } +// PR 59930 (part) templated class friend declarations cannot have +// default args. -template // { dg-message "note: original definition" } +template struct S { - template - friend class S; // { dg-error "redefinition of default argument" } + template friend class R; // { dg-error "template friend" } + template friend class S; // { dg-error "template friend" } }; - -template struct S; diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend24.C b/gcc/testsuite/g++.old-deja/g++.pt/friend24.C deleted file mode 100644 index 5a4116fd47b..00000000000 --- a/gcc/testsuite/g++.old-deja/g++.pt/friend24.C +++ /dev/null @@ -1,18 +0,0 @@ -// { dg-do assemble } - -template -struct S -{ - template - friend class S; - - void f(T); -}; - -template struct S; - -void g() -{ - S<> s; - s.f(3); -} -- 2.30.2