From patchwork Thu Dec 14 19:31:37 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathan Sidwell X-Patchwork-Id: 848752 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-469254-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="iK6FjCCw"; 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 3yyNwq4p48z9t39 for ; Fri, 15 Dec 2017 06:31:55 +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=c7NvsLg6wnkiPgu9Raudhh3d37LqohzhQBZl6oMLQyqfYH8BCp oEYO5xV8F0TTg80LMPEj0OacTpd9vF1Dqhi9yj0Oumk28Pm8uWnZ7YTgNyhCS2vq mWUeKsBEd7Y9KFV/P/Xc9LBLBOgiITALZ7sZ8Zc4ytII7z2NnWOVO1kW8= 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=GGhgeRT8IHnqvr+QvpSXYLG3eVk=; b=iK6FjCCwHv6i3NphJ1AI JUiImngZSe1GYHJNAogW7phF/yruoJyEYOUTWJtjB1vtaTAjNXOOu7x0YSVaL6Gg i9DK7vdXcu6VM3p34SIawq+uSn++seFVErYbwrImYf0nQD/hFSaT+vX85bNBhor9 LD+zm2yoWACY/7I/auuyygw= Received: (qmail 35360 invoked by alias); 14 Dec 2017 19:31:45 -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 34187 invoked by uid 89); 14 Dec 2017 19:31:43 -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=sf, HX-Google-Smtp-Source:ACJfBou, Friend X-HELO: mail-yb0-f181.google.com Received: from mail-yb0-f181.google.com (HELO mail-yb0-f181.google.com) (209.85.213.181) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 14 Dec 2017 19:31:41 +0000 Received: by mail-yb0-f181.google.com with SMTP id s1so4341616ybm.7 for ; Thu, 14 Dec 2017 11:31:41 -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=a+eIWW+rnlEuybKqOmTMdJvRD+icYw9GruZr29AQAAY=; b=F7aJiRcN9+idLwMk6R5H8gyVcAei0G9swNCuimfS1j4Wc86T9IWBc1OqgMxHx+W0ju u19gKhrwhHFlHd0PDRGDtuupiNJZe8wjVMq0KfkjwIJiHrUb/LwRLw33oN+Okb9lT/6y v0L7+AHId44o+LMvK2bOD7nBvBPvryJOaEwd2Pg2WTNl/V3yO/Gy8Te/COLIoQcOCXL6 46R8vvZIZOwmlxGGNrRLGhl55FINSHGafedLkTR8cfWiVKehYmMyAmTuqOnav3rSmcoc M4wZUvfcDgaY1tQ3ouN1SxPp8goPc9My3YviYZAKrhXunBRdVBpvR9BZUCgQakYnyIzj Uedw== X-Gm-Message-State: AKGB3mJ7zRXVcxE3BqYteAifNghFrmddibVlEcOQm5VCgTRlucTos+kU WjkeFc2+KeIgJj8BwRBMW+U= X-Google-Smtp-Source: ACJfBou/0f3IQHR0GtX4B+QbFCyCYtDPK/nI8oVVtCeIzyMIN+YbZzuDkDWiXPK3layXE2jhLPnfCw== X-Received: by 10.37.112.136 with SMTP id l130mr5308225ybc.95.1513279899445; Thu, 14 Dec 2017 11:31:39 -0800 (PST) Received: from ?IPv6:2620:10d:c0a3:20fb:7500:e7fb:4a6f:2254? ([2620:10d:c091:200::3:4e6f]) by smtp.googlemail.com with ESMTPSA id u67sm2072049ywg.47.2017.12.14.11.31.38 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 14 Dec 2017 11:31:38 -0800 (PST) To: GCC Patches From: Nathan Sidwell Subject: [PR C++/59930] template friend classes & default args Message-ID: Date: Thu, 14 Dec 2017 14:31:37 -0500 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.5.0 MIME-Version: 1.0 PR 59930 concerns some problems with templated friend classes (of templates). In rying to clean up our handling, I discovered we were accepting default args of such things. This is ill formed [temp.param]/12 'A default template-argument shall not be specified in a friend class template declaration.' This patch addresses that problem by extending check_default_tmpl_args to deal with such friends. We'll still have to deal with: template class X { template friend class Y; }; which is probably just as involved. But at least this removes one source of confusion. nathan 2017-12-14 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): Adjust for template friend classes. 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. Index: cp/decl.c =================================================================== --- cp/decl.c (revision 255634) +++ cp/decl.c (working copy) @@ -13538,37 +13538,28 @@ xref_tag_1 (enum tag_types tag_code, tre 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; - - say, when we should tsubst into `U' when instantiating - S2. On the other hand, when presented with: - - template - struct S1 { - template - struct S2 {}; - template - friend struct S2; + have a template parameter of level 2, not level 1. + + On the other hand, when presented with: + + 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, tre 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; Index: cp/friend.c =================================================================== --- cp/friend.c (revision 255634) +++ cp/friend.c (working copy) @@ -283,21 +283,18 @@ make_friend_class (tree type, tree frien 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 frien 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", Index: cp/pt.c =================================================================== --- cp/pt.c (revision 255634) +++ cp/pt.c (working copy) @@ -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 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 = 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 } /* Check to see that the rules regarding the use of default - arguments are not being violated. */ + arguments are not being violated. We recheck args for a + friend function when we know whether it's a definition, + introducing declaration or re-declaration. */ check_default_tmpl_args (decl, current_template_parms, - is_primary, is_partial, /*is_friend_decl=*/0); + is_primary, is_partial, + is_friend && MAYBE_CLASS_TYPE_P (TREE_TYPE (decl))); /* Ensure that there are no parameter packs in the type of this declaration that have not been expanded. */ Index: testsuite/g++.dg/cpp0x/temp_default4.C =================================================================== --- testsuite/g++.dg/cpp0x/temp_default4.C (revision 255634) +++ testsuite/g++.dg/cpp0x/temp_default4.C (working copy) @@ -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" } Index: testsuite/g++.old-deja/g++.pt/friend23.C =================================================================== --- testsuite/g++.old-deja/g++.pt/friend23.C (revision 255634) +++ testsuite/g++.old-deja/g++.pt/friend23.C (working copy) @@ -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; Index: testsuite/g++.old-deja/g++.pt/friend24.C =================================================================== --- testsuite/g++.old-deja/g++.pt/friend24.C (revision 255634) +++ testsuite/g++.old-deja/g++.pt/friend24.C (working copy) @@ -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); -}