From patchwork Mon Dec 18 14:56:43 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathan Sidwell X-Patchwork-Id: 850093 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-469465-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="UZEgqH06"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3z0kdq2xhPz9sDB for ; Tue, 19 Dec 2017 01:57:02 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:to :from:subject:message-id:date:mime-version:content-type; q=dns; s=default; b=M+JcbANDtUHYi6zSFmxqmRCr5zefGl3++g+HKVAxGfCPz3L9Gd 9NdeSXs87iZuPNz0oeERVdEAAdmBy/GTj0s2HNzhhNkN/O+K5odXwK3n7XrVt8uL hYLPB2rO6DBoZyoykcxcnIxXrK0GNxbboFeB4m/15/RyRD68DrKjRFHdw= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:to :from:subject:message-id:date:mime-version:content-type; s= default; bh=LvVYtS9rz5aqgQ9gIuL0KK8XqRA=; b=UZEgqH06g3FPtf+4VZOw TvS/stvEO+GU4V6V+rYOKfkb5NeOvIlpoOOvv9dLk8Z6vXDfxZmn5DhgOoGWVHMX Ne6+jzd7D/9BofVG5NdBgMJPpea0F1NpvgMM5df6hRXN2wHJvG3HdmC2N1Ki0I/C mF/oTV2FdzmWwfU0lIet3bE= Received: (qmail 89518 invoked by alias); 18 Dec 2017 14:56:51 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 88252 invoked by uid 89); 18 Dec 2017 14:56:50 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-11.1 required=5.0 tests=BAYES_00, FREEMAIL_FROM, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=ain, sk:search_, Holder X-HELO: mail-yb0-f178.google.com Received: from mail-yb0-f178.google.com (HELO mail-yb0-f178.google.com) (209.85.213.178) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 18 Dec 2017 14:56:48 +0000 Received: by mail-yb0-f178.google.com with SMTP id 69so11208401ybc.6 for ; Mon, 18 Dec 2017 06:56:48 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:to:from:subject:message-id:date :user-agent:mime-version:content-language; bh=yvm1ZFD3x1y+USLwgYZ1XUaCf5YOyM836VCmXzPJjO0=; b=Tue12cLZY5QJjdPVQfZjw5B2NR54EL0uLiFVE+hPlWQ26q5vjwAS/lQrF6SCxx+PvI RZdhJZ6HJTVaErYKVIQ8XoUjz7QdJkSmW5GSDT6s67nUDguOizvHtmgehRrX8Mx/HaRH YuwOIA7abPyyGNLt9rqFhMfT4nbrPrOGwS0T8ufXVIfKvr2NfB2vS79TgA0QAecxTJon 8z+JLHwR7R8/YWeLXCBTRPGgJXo8BmO7Q7+GeJAMUgCkKJAmPmVWDNFc3Ewp/4wVxUmk kwbcxcl8kiRTWtiySo3XLK7gbK0yamfh5BZbQXJdkQci4kkvIIgLLRseMSdOI1vOAzE/ W0ZA== X-Gm-Message-State: AKGB3mJdrd7XBvJur4+wAegjdPfNnprI2gR1wp29DfjWcGZzzJEJoOvk h9ZT04gifBlQwZjKdl4jzXU= X-Google-Smtp-Source: ACJfBovVl2OAyT+BcGNp1XJbiQNqYrfZqYm3nZLFtkSyOAG5txQAA8OhHajU/VLzYHMXuyhzuWD68g== X-Received: by 10.37.90.87 with SMTP id o84mr17179ybb.2.1513609006893; Mon, 18 Dec 2017 06:56:46 -0800 (PST) Received: from ?IPv6:2620:10d:c0a1:1102:495f:7267:5ff:a250? ([2620:10d:c091:180::1:7168]) by smtp.googlemail.com with ESMTPSA id f16sm6157600ywb.7.2017.12.18.06.56.45 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 18 Dec 2017 06:56:46 -0800 (PST) To: GCC Patches From: Nathan Sidwell Subject: [PR c++/59930] template friend injection Message-ID: Date: Mon, 18 Dec 2017 09:56:43 -0500 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.5.0 MIME-Version: 1.0 this patch fixes the handling of template friend classes of template classes. Our current handling was somewhat messed up, possibly because of now-clarified ambiguities in earlier versions of the std. In particular we'd search too many namespaces looking for an existing declaration, and if not found inject into the global namespace as a non-hidden name. This patch: a) removes some now-unneeded handling for self friendliness b) looks only in the innermost containing namespace for an unqualified friend [*] c) injects into that namespace as a hidden name. [*] fixing this may permit removal of some checks in other friend cases too. I have not investigated. applying to trunk nathan 2017-12-18 Nathan Sidwell PR c++/59930 * name-lookup.c (name_lookup::search_unqualified): Don't search parent namespace when looking for hidden things. * pt.c (tsubst_friend_class): Always push to friend scope, drop unneeded self-friend check. Inject new hidden friend into correct scope. PR c++/59930 * g++.dg/parse/pr81247-c.C: Adjust. * g++.dg/template/pr59930-[123].C: New. Index: cp/name-lookup.c =================================================================== --- cp/name-lookup.c (revision 255777) +++ cp/name-lookup.c (working copy) @@ -711,6 +711,15 @@ name_lookup::search_unqualified (tree sc done:; if (scope == global_namespace) break; + + /* If looking for hidden names, we only look in the innermost + namespace scope. [namespace.memdef]/3 If a friend + declaration in a non-local class first declares a class, + function, class template or function template the friend is a + member of the innermost enclosing namespace. See also + [basic.lookup.unqual]/7 */ + if (flags & LOOKUP_HIDDEN) + break; } vec_safe_truncate (queue, length); Index: cp/pt.c =================================================================== --- cp/pt.c (revision 255777) +++ cp/pt.c (working copy) @@ -10005,57 +10005,23 @@ tsubst_friend_function (tree decl, tree static tree tsubst_friend_class (tree friend_tmpl, tree args) { - tree friend_type; tree tmpl; - tree context; if (DECL_TEMPLATE_TEMPLATE_PARM_P (friend_tmpl)) { - tree t = tsubst (TREE_TYPE (friend_tmpl), args, tf_none, NULL_TREE); - return TREE_TYPE (t); + tmpl = tsubst (TREE_TYPE (friend_tmpl), args, tf_none, NULL_TREE); + return TREE_TYPE (tmpl); } - context = CP_DECL_CONTEXT (friend_tmpl); + tree context = CP_DECL_CONTEXT (friend_tmpl); + if (TREE_CODE (context) == NAMESPACE_DECL) + push_nested_namespace (context); + else + push_nested_class (context); - if (context != global_namespace) - { - if (TREE_CODE (context) == NAMESPACE_DECL) - push_nested_namespace (context); - else - push_nested_class (tsubst (context, args, tf_none, NULL_TREE)); - } - - /* Look for a class template declaration. We look for hidden names - because two friend declarations of the same template are the - same. For example, in: - - struct A { - template friend class F; - }; - template struct B { - template friend class F; - }; - - both F templates are the same. */ - tmpl = lookup_name_real (DECL_NAME (friend_tmpl), 0, 0, - /*block_p=*/true, 0, LOOKUP_HIDDEN); - - /* But, if we don't find one, it might be because we're in a - situation like this: - - template - struct S { - template - friend struct S; - }; - - Here, in the scope of (say) S, `S' is bound to a TYPE_DECL - for `S', not the TEMPLATE_DECL. */ - if (!tmpl || !DECL_CLASS_TEMPLATE_P (tmpl)) - { - tmpl = lookup_name_prefer_type (DECL_NAME (friend_tmpl), 1); - tmpl = maybe_get_template_decl_from_type_decl (tmpl); - } + tmpl = lookup_name_real (DECL_NAME (friend_tmpl), /*prefer_type=*/false, + /*non_class=*/false, /*block_p=*/false, + /*namespaces_only=*/false, LOOKUP_HIDDEN); if (tmpl && DECL_CLASS_TEMPLATE_P (tmpl)) { @@ -10068,53 +10034,50 @@ tsubst_friend_class (tree friend_tmpl, t if (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (friend_tmpl)) > TMPL_ARGS_DEPTH (args)) { - tree parms; - location_t saved_input_location; - parms = tsubst_template_parms (DECL_TEMPLATE_PARMS (friend_tmpl), - args, tf_warning_or_error); - - saved_input_location = input_location; + tree parms = tsubst_template_parms (DECL_TEMPLATE_PARMS (friend_tmpl), + args, tf_warning_or_error); + location_t saved_input_location = input_location; input_location = DECL_SOURCE_LOCATION (friend_tmpl); tree cons = get_constraints (tmpl); redeclare_class_template (TREE_TYPE (tmpl), parms, cons); input_location = saved_input_location; - } - - friend_type = TREE_TYPE (tmpl); } else { /* The friend template has not already been declared. In this case, the instantiation of the template class will cause the - injection of this template into the global scope. */ + injection of this template into the namespace scope. */ tmpl = tsubst (friend_tmpl, args, tf_warning_or_error, NULL_TREE); - if (tmpl == error_mark_node) - return error_mark_node; - /* The new TMPL is not an instantiation of anything, so we - forget its origins. We don't reset CLASSTYPE_TI_TEMPLATE for - the new type because that is supposed to be the corresponding - template decl, i.e., TMPL. */ - DECL_USE_TEMPLATE (tmpl) = 0; - DECL_TEMPLATE_INFO (tmpl) = NULL_TREE; - CLASSTYPE_USE_TEMPLATE (TREE_TYPE (tmpl)) = 0; - CLASSTYPE_TI_ARGS (TREE_TYPE (tmpl)) - = INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (TREE_TYPE (tmpl))); + if (tmpl != error_mark_node) + { + /* The new TMPL is not an instantiation of anything, so we + forget its origins. We don't reset CLASSTYPE_TI_TEMPLATE + for the new type because that is supposed to be the + corresponding template decl, i.e., TMPL. */ + DECL_USE_TEMPLATE (tmpl) = 0; + DECL_TEMPLATE_INFO (tmpl) = NULL_TREE; + CLASSTYPE_USE_TEMPLATE (TREE_TYPE (tmpl)) = 0; + CLASSTYPE_TI_ARGS (TREE_TYPE (tmpl)) + = INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (TREE_TYPE (tmpl))); + + /* It is hidden. */ + retrofit_lang_decl (DECL_TEMPLATE_RESULT (tmpl)); + DECL_ANTICIPATED (tmpl) + = DECL_ANTICIPATED (DECL_TEMPLATE_RESULT (tmpl)) = true; - /* Inject this template into the global scope. */ - friend_type = TREE_TYPE (pushdecl_top_level (tmpl, true)); + /* Inject this template into the enclosing namspace scope. */ + tmpl = pushdecl_namespace_level (tmpl, true); + } } - if (context != global_namespace) - { - if (TREE_CODE (context) == NAMESPACE_DECL) - pop_nested_namespace (context); - else - pop_nested_class (); - } + if (TREE_CODE (context) == NAMESPACE_DECL) + pop_nested_namespace (context); + else + pop_nested_class (); - return friend_type; + return TREE_TYPE (tmpl); } /* Returns zero if TYPE cannot be completed later due to circularity. Index: testsuite/g++.dg/parse/pr81247-c.C =================================================================== --- testsuite/g++.dg/parse/pr81247-c.C (revision 255777) +++ testsuite/g++.dg/parse/pr81247-c.C (working copy) @@ -1,8 +1,9 @@ -// PR c++/81247 confused error +// PR c++/81247 rejected well-formed -namespace N { // { dg-message "previous declaration" } +namespace N { template < typename T > class A - { // { dg-error "conflicts with a previous" } + { + // injects a hidden class N::N at instantiation time template < T > friend class N; }; } Index: testsuite/g++.dg/template/pr59930-1.C =================================================================== --- testsuite/g++.dg/template/pr59930-1.C (revision 0) +++ testsuite/g++.dg/template/pr59930-1.C (working copy) @@ -0,0 +1,18 @@ +// PR c++/59930 + +namespace N { + template class A { + // The injected name is N::B, because we don;t look outside of N + template friend struct B; + private: + int n; // { dg-message "declared private here" } + public: + A (int); + }; +} + +template struct B { + int f(N::A ai) { return ai.n; } // { dg-error "is private" } +}; + +int k = B().f(0); Index: testsuite/g++.dg/template/pr59930-2.C =================================================================== --- testsuite/g++.dg/template/pr59930-2.C (revision 0) +++ testsuite/g++.dg/template/pr59930-2.C (working copy) @@ -0,0 +1,17 @@ +// PR c++/59930 + +namespace N { + template < typename T > class A + { + // Injects N::N + template < T > friend class N; + // { dg-error "template parameter" "" { target *-*-* } .-1 } + // { dg-error "redeclared" "" { target *-*-* } .-2 } + }; +} + +void f () +{ + N::A < int > a1; + N::A a2; +} Index: testsuite/g++.dg/template/pr59930-3.C =================================================================== --- testsuite/g++.dg/template/pr59930-3.C (revision 0) +++ testsuite/g++.dg/template/pr59930-3.C (working copy) @@ -0,0 +1,29 @@ +// PR c++/59930 + +namespace NS { + template class Holder + { + private: + void func(); + + template friend class User; + }; + + template class Holder; + + template class User + { + public: + void method() const + { + Holder x; + x.func(); + } + }; +} // namespace + +void Foo() +{ + NS::User decl; + decl.method(); +}