The the different calling of check_explicit_specialization for class and namespace scope friends bothered me, so this patch combines them.
Tested x86_64-pc-linux-gnu, applying to trunk. PR c++/91618 PR c++/96604 gcc/cp/ChangeLog: * friend.cc (do_friend): Call check_explicit_specialization here. * decl.cc (grokdeclarator): Not here. * decl2.cc (check_classfn): Or here. --- gcc/cp/decl.cc | 9 ----- gcc/cp/decl2.cc | 9 ++--- gcc/cp/friend.cc | 92 +++++++++++++++++++++++++----------------------- 3 files changed, 49 insertions(+), 61 deletions(-) diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 16565bf0a0e..324498f399d 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -14142,15 +14142,6 @@ grokdeclarator (const cp_declarator *declarator, So set it here. */ funcdef_flag = true; - if (template_class_depth (current_class_type) == 0) - { - decl = check_explicit_specialization - (unqualified_id, decl, template_count, - 2 * funcdef_flag + 4); - if (decl == error_mark_node) - return error_mark_node; - } - decl = do_friend (ctype, unqualified_id, decl, flags, funcdef_flag); return decl; diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index d2b29208ed5..ae743c8a3df 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -799,14 +799,9 @@ check_classfn (tree ctype, tree function, tree template_parms) is replaced with the specialization chosen by deduction from the friend declaration or discarded if deduction fails." - So ask check_explicit_specialization to find a matching template. */ + So tell check_explicit_specialization to look for a match. */ SET_DECL_IMPLICIT_INSTANTIATION (function); - tree spec = check_explicit_specialization (DECL_NAME (function), - function, /* tcount */0, - /* friend flag */4, - /* attrlist */NULL_TREE); - if (spec != error_mark_node) - matched = spec; + matched = function; } if (!matched) diff --git a/gcc/cp/friend.cc b/gcc/cp/friend.cc index acbe0eccb8e..124ed4f3962 100644 --- a/gcc/cp/friend.cc +++ b/gcc/cp/friend.cc @@ -506,6 +506,7 @@ do_friend (tree ctype, tree declarator, tree decl, error ("friend declaration %qD may not have virt-specifiers", decl); + tree orig_declarator = declarator; if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR) { declarator = TREE_OPERAND (declarator, 0); @@ -513,32 +514,33 @@ do_friend (tree ctype, tree declarator, tree decl, declarator = OVL_NAME (declarator); } + /* CLASS_TEMPLATE_DEPTH counts the number of template headers for + the enclosing class. FRIEND_DEPTH counts the number of template + headers used for this friend declaration. TEMPLATE_MEMBER_P is + true if a template header in FRIEND_DEPTH is intended for + DECLARATOR. For example, the code + + template <class T> struct A { + template <class U> struct B { + template <class V> template <class W> + friend void C<V>::f(W); + }; + }; + + will eventually give the following results + + 1. CLASS_TEMPLATE_DEPTH equals 2 (for `T' and `U'). + 2. FRIEND_DEPTH equals 2 (for `V' and `W'). + 3. CTYPE_DEPTH equals 1 (for `V'). + 4. TEMPLATE_MEMBER_P is true (for `W'). */ + + int class_template_depth = template_class_depth (current_class_type); + int friend_depth = current_template_depth - class_template_depth; + int ctype_depth = num_template_headers_for_class (ctype); + bool template_member_p = friend_depth > ctype_depth; + if (ctype) { - /* CLASS_TEMPLATE_DEPTH counts the number of template headers for - the enclosing class. FRIEND_DEPTH counts the number of template - headers used for this friend declaration. TEMPLATE_MEMBER_P is - true if a template header in FRIEND_DEPTH is intended for - DECLARATOR. For example, the code - - template <class T> struct A { - template <class U> struct B { - template <class V> template <class W> - friend void C<V>::f(W); - }; - }; - - will eventually give the following results - - 1. CLASS_TEMPLATE_DEPTH equals 2 (for `T' and `U'). - 2. FRIEND_DEPTH equals 2 (for `V' and `W'). - 3. TEMPLATE_MEMBER_P is true (for `W'). */ - - int class_template_depth = template_class_depth (current_class_type); - int friend_depth = current_template_depth - class_template_depth; - /* We will figure this out later. */ - bool template_member_p = false; - tree cname = TYPE_NAME (ctype); if (TREE_CODE (cname) == TYPE_DECL) cname = DECL_NAME (cname); @@ -549,13 +551,6 @@ do_friend (tree ctype, tree declarator, tree decl, grokclassfn (ctype, decl, flags); - if (friend_depth) - { - if (!uses_template_parms_level (ctype, class_template_depth - + friend_depth)) - template_member_p = true; - } - /* A nested class may declare a member of an enclosing class to be a friend, so we do lookup here even if CTYPE is in the process of being defined. */ @@ -584,9 +579,6 @@ do_friend (tree ctype, tree declarator, tree decl, || (class_template_depth && friend_depth)) && decl && TREE_CODE (decl) == FUNCTION_DECL) decl = DECL_TI_TEMPLATE (decl); - - if (decl) - add_friend (current_class_type, decl, /*complain=*/true); } else error ("member %qD declared as friend before type %qT defined", @@ -595,7 +587,6 @@ do_friend (tree ctype, tree declarator, tree decl, else { /* Namespace-scope friend function. */ - int is_friend_template = PROCESSING_REAL_TEMPLATE_DECL_P (); if (funcdef_flag) SET_DECL_FRIEND_CONTEXT (decl, current_class_type); @@ -606,12 +597,11 @@ do_friend (tree ctype, tree declarator, tree decl, arguments before push_template_decl adds a reference to the containing template class. */ int warn = (warn_nontemplate_friend - && ! funcdef_flag && ! is_friend_template + && ! funcdef_flag && ! friend_depth && current_template_parms && uses_template_parms (decl)); - if (is_friend_template - || template_class_depth (current_class_type) != 0) + if (friend_depth || class_template_depth) /* We can't call pushdecl for a template class, since in general, such a declaration depends on template parameters. Instead, we call pushdecl when the class @@ -651,15 +641,27 @@ do_friend (tree ctype, tree declarator, tree decl, } } } - - if (decl == error_mark_node) - return error_mark_node; - - add_friend (current_class_type, - is_friend_template ? DECL_TI_TEMPLATE (decl) : decl, - /*complain=*/true); } + if (decl == error_mark_node) + return error_mark_node; + + if (!class_template_depth && DECL_IMPLICIT_INSTANTIATION (decl)) + /* "[if no non-template match is found,] each remaining function template + is replaced with the specialization chosen by deduction from the + friend declaration or discarded if deduction fails." + + set_decl_namespace or check_classfn set DECL_IMPLICIT_INSTANTIATION to + indicate that we need a template match, so ask + check_explicit_specialization to find one. */ + decl = (check_explicit_specialization + (orig_declarator, decl, ctype_depth, + 2 * funcdef_flag + 4)); + + add_friend (current_class_type, + (!ctype && friend_depth) ? DECL_TI_TEMPLATE (decl) : decl, + /*complain=*/true); + return decl; } base-commit: 4259c229b457361a9b5cdec157e058bf0c2c8b77 -- 2.27.0