From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 787F63858D35 for ; Tue, 7 May 2024 20:27:18 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 787F63858D35 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 787F63858D35 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1715113640; cv=none; b=CegCFtCBLG5xZUPReAOIX39q6CI1LpLlsc+GwXHP609IwWsfJtiFAYJydJUJ6ft7O+78MxCNB8QJKO2RloxvkQLwv2Wzsy9j0ZLSESI6gwKGBAFU8VbrtpASqja3ivAbQQGhqF03nbfV3TvDlhrCZpi57AdwAXnKKsniU73Sk18= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1715113640; c=relaxed/simple; bh=8ok4m8grV6PuqBmUMFv6EYaIag2ia2FcD/CkoV1Fjrk=; h=DKIM-Signature:Message-ID:Date:MIME-Version:Subject:To:From; b=yCY08Fxvssj6kD7QyD6Peasb8KfVahmDA/5Qo6vQs5VVNpsX8gmZkuqR7WADJgCUK1tQimKpAeaAnOL2ifBAe1YrDHCNBJXmkY/J7+hh4ELVqK2SDd76ijlrrmsgFanJ8J5H+9aE3vpUG84uzGKsgzRcR1E1KcGoFRP6LcAzBIg= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1715113637; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=wL/ifzbXwrb/1nFvWNJII5ZLPTPubryBON4Vw8oF5zc=; b=LH1xxkqjGICrK+OAMs9wpFORt0B1MidnnZaRVNcqu4PwCGc0b4bjdQ4f/YpcytjJSiThDj +ulBlzEmLofD2M5DhEGimCy0fonYsh/ewzBHjs56BmcYnulO9VLoP0027mVP8E6c6wi2mB zWVOMPZPZ+bFG4qXgOzRyikNryJwFtY= Received: from mail-pj1-f71.google.com (mail-pj1-f71.google.com [209.85.216.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-435-eOvcRLf3OG-qp3DIlLySYA-1; Tue, 07 May 2024 16:27:16 -0400 X-MC-Unique: eOvcRLf3OG-qp3DIlLySYA-1 Received: by mail-pj1-f71.google.com with SMTP id 98e67ed59e1d1-2b399e49d85so3876913a91.0 for ; Tue, 07 May 2024 13:27:16 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1715113635; x=1715718435; h=content-transfer-encoding:in-reply-to:from:content-language :references:cc:to:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=wL/ifzbXwrb/1nFvWNJII5ZLPTPubryBON4Vw8oF5zc=; b=l6vd5gnnFi2IbjK5z7+6oAxz/YjyIMiOHLOJru+zDqfy3MN4sUfQKFSY53BfiXUSlj KOKnbJQjglBPlVAH9x+w4zqpaOmOB3DiOOmuNjcnaci9M/xPWXqdvV//Uo+ytFVh/rZc yUWMWUSS9acccVjyBKf8OdHAnSyGY1aa9CFUd1pwBGGDsnJ7rKL7f71PdD7QJj1Rs9zJ lPZOjw5ROrR3AB2zag9YXtup8rR4txa1iRPDCZl3MW09Xw24t9mJzd0w9QqSV3F6/PkU h5zC3yqkNy9wwSugG+hzB39q339jUC5b8bX3e5ZFg1G/yhubGBKm59ToTlD0tU/6iKx6 T91w== X-Gm-Message-State: AOJu0Yy+cy/GslvIGN+ikD9Y6+IbOAiVHl8yBciBm5OsbNTDJKKLPaZs rAxzN/jGbm3UnDeFlj5DdSMyx3Qvu0Xh7Gd5pLFYQKf45nt8GQzmZzAhHjHzoTD0Qgd9+Ckf5D+ D1Wp/EmO2b0Zdh4zvzpDaA2ZvXLmUYxr1137+qpcxfCVknJE9TCW1r6SIITaX7N8= X-Received: by 2002:a17:90b:891:b0:2b4:abc7:d64b with SMTP id 98e67ed59e1d1-2b6163a0616mr688272a91.6.1715113634911; Tue, 07 May 2024 13:27:14 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGwigOIXY9mUboYMxTa25UbjX6ZlV3L3irnhnz4pAR3kV8Cb2dsAlkAUkPvgg1QLfBHVlTA1Q== X-Received: by 2002:a17:90b:891:b0:2b4:abc7:d64b with SMTP id 98e67ed59e1d1-2b6163a0616mr688253a91.6.1715113634357; Tue, 07 May 2024 13:27:14 -0700 (PDT) Received: from [192.168.1.130] (130-44-146-16.s12558.c3-0.arl-cbr1.sbo-arl.ma.cable.rcncustomer.com. [130.44.146.16]) by smtp.gmail.com with ESMTPSA id o10-20020a17090aac0a00b002a5d684a6a7sm10200223pjq.10.2024.05.07.13.27.13 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 07 May 2024 13:27:13 -0700 (PDT) Message-ID: <04cc28cf-f732-41d0-a3ed-9132c8ac7504@redhat.com> Date: Tue, 7 May 2024 16:27:11 -0400 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH] c++: Implement C++26 P2893R3 - Variadic friends [PR114459] To: Jakub Jelinek Cc: gcc-patches@gcc.gnu.org References: From: Jason Merrill In-Reply-To: X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-6.6 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE,SPF_NONE,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On 5/3/24 12:35, Jakub Jelinek wrote: > Hi! > > The following patch imeplements the C++26 P2893R3 - Variadic friends > paper. The paper allows for the friend type declarations to specify > more than one friend type specifier and allows to specify ... at > the end of each. The patch doesn't introduce tentative parsing of > friend-type-declaration non-terminal, but rather just extends existing > parsing where it is a friend declaration which ends with ; after the > declaration specifiers to the cases where it ends with ...; or , or ..., > In that case it pedwarns for cxx_dialect < cxx26, handles the ... and > if there is , continues in a loop to parse the further friend type > specifiers. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? > > 2024-05-03 Jakub Jelinek > > PR c++/114459 > gcc/c-family/ > * c-cppbuiltin.cc (c_cpp_builtins): Predefine > __cpp_variadic_friend=202403L for C++26. > gcc/cp/ > * parser.cc (cp_parser_member_declaration): Implement C++26 > P2893R3 - Variadic friends. Parse friend type declarations > with ... or with more than one friend type specifier. > * friend.cc (make_friend_class): Allow TYPE_PACK_EXPANSION. > * pt.cc (instantiate_class_template): Handle PACK_EXPANSION_P > in friend classes. > gcc/testsuite/ > * g++.dg/cpp26/feat-cxx26.C (__cpp_variadic_friend): Add test. > * g++.dg/cpp26/variadic-friend1.C: New test. > > --- gcc/c-family/c-cppbuiltin.cc.jj 2024-05-02 09:31:17.746298275 +0200 > +++ gcc/c-family/c-cppbuiltin.cc 2024-05-03 14:50:08.008242950 +0200 > @@ -1093,6 +1093,7 @@ c_cpp_builtins (cpp_reader *pfile) > cpp_define (pfile, "__cpp_placeholder_variables=202306L"); > cpp_define (pfile, "__cpp_structured_bindings=202403L"); > cpp_define (pfile, "__cpp_deleted_function=202403L"); > + cpp_define (pfile, "__cpp_variadic_friend=202403L"); > } > if (flag_concepts) > { > --- gcc/cp/parser.cc.jj 2024-05-03 09:43:47.781511477 +0200 > +++ gcc/cp/parser.cc 2024-05-03 13:26:38.208088017 +0200 > @@ -28102,7 +28102,14 @@ cp_parser_member_declaration (cp_parser* > goto out; > /* If there is no declarator, then the decl-specifier-seq should > specify a type. */ Let's mention C++26 variadic friends in this comment. OK with that change. > - if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) > + if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON) > + || (cp_parser_friend_p (&decl_specifiers) > + && cxx_dialect >= cxx11 > + && (cp_lexer_next_token_is (parser->lexer, CPP_COMMA) > + || (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS) > + && (cp_lexer_nth_token_is (parser->lexer, 2, CPP_SEMICOLON) > + || cp_lexer_nth_token_is (parser->lexer, 2, > + CPP_COMMA)))))) > { > /* If there was no decl-specifier-seq, and the next token is a > `;', then we have something like: > @@ -28137,44 +28144,81 @@ cp_parser_member_declaration (cp_parser* > { > /* If the `friend' keyword was present, the friend must > be introduced with a class-key. */ > - if (!declares_class_or_enum && cxx_dialect < cxx11) > - pedwarn (decl_spec_token_start->location, OPT_Wpedantic, > - "in C++03 a class-key must be used " > - "when declaring a friend"); > - /* In this case: > + if (!declares_class_or_enum && cxx_dialect < cxx11) > + pedwarn (decl_spec_token_start->location, OPT_Wpedantic, > + "in C++03 a class-key must be used " > + "when declaring a friend"); > + if (!cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON) > + && cxx_dialect < cxx26) > + pedwarn (cp_lexer_peek_token (parser->lexer)->location, > + OPT_Wc__26_extensions, > + "variadic friends or friend type declarations with " > + "multiple types only available with " > + "%<-std=c++2c%> or %<-std=gnu++2c%>"); > + location_t friend_loc = decl_specifiers.locations[ds_friend]; > + do > + { > + /* In this case: > > - template struct A { > - friend struct A::B; > - }; > + template struct A { > + friend struct A::B; > + }; > > - A::B will be represented by a TYPENAME_TYPE, and > - therefore not recognized by check_tag_decl. */ > - if (!type) > - { > - type = decl_specifiers.type; > - if (type && TREE_CODE (type) == TYPE_DECL) > - type = TREE_TYPE (type); > - } > - /* Warn if an attribute cannot appear here, as per > - [dcl.attr.grammar]/5. But not when declares_class_or_enum: > - we ignore attributes in elaborated-type-specifiers. */ > - if (!declares_class_or_enum > - && cxx11_attribute_p (decl_specifiers.attributes)) > - { > - decl_specifiers.attributes = NULL_TREE; > - if (warning_at (decl_spec_token_start->location, > - OPT_Wattributes, "attribute ignored")) > - inform (decl_spec_token_start->location, "an attribute " > - "that appertains to a friend declaration that " > - "is not a definition is ignored"); > - } > - if (!type || !TYPE_P (type)) > - error_at (decl_spec_token_start->location, > - "friend declaration does not name a class or " > - "function"); > - else > - make_friend_class (current_class_type, type, > - /*complain=*/true); > + A::B will be represented by a TYPENAME_TYPE, and > + therefore not recognized by check_tag_decl. */ > + if (!type) > + { > + type = decl_specifiers.type; > + if (type && TREE_CODE (type) == TYPE_DECL) > + type = TREE_TYPE (type); > + } > + /* Warn if an attribute cannot appear here, as per > + [dcl.attr.grammar]/5. But not when > + declares_class_or_enum: we ignore attributes in > + elaborated-type-specifiers. */ > + if (!declares_class_or_enum > + && cxx11_attribute_p (decl_specifiers.attributes)) > + { > + decl_specifiers.attributes = NULL_TREE; > + if (warning_at (decl_spec_token_start->location, > + OPT_Wattributes, "attribute ignored")) > + inform (decl_spec_token_start->location, "an attribute " > + "that appertains to a friend declaration that " > + "is not a definition is ignored"); > + } > + bool ellipsis = cp_lexer_next_token_is (parser->lexer, > + CPP_ELLIPSIS); > + if (ellipsis) > + cp_lexer_consume_token (parser->lexer); > + if (!type || !TYPE_P (type)) > + error_at (decl_spec_token_start->location, > + "friend declaration does not name a class or " > + "function"); > + else > + { > + if (ellipsis) > + type = make_pack_expansion (type); > + if (type != error_mark_node) > + make_friend_class (current_class_type, type, > + /*complain=*/true); > + } > + if (!cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) > + break; > + cp_lexer_consume_token (parser->lexer); > + clear_decl_specs (&decl_specifiers); > + decl_specifiers.locations[ds_friend] = friend_loc; > + decl_specifiers.any_specifiers_p = true; > + declares_class_or_enum = false; > + cp_parser_type_specifier (parser, > + CP_PARSER_FLAGS_TYPENAME_OPTIONAL, > + &decl_specifiers, > + /*is_declaration=*/true, > + &declares_class_or_enum, NULL); > + type = check_tag_decl (&decl_specifiers, > + /*explicit_type_instantiation_p=*/ > + false); > + } > + while (1); > } > /* If there is no TYPE, an error message will already have > been issued. */ > --- gcc/cp/friend.cc.jj 2024-01-03 12:01:23.136483926 +0100 > +++ gcc/cp/friend.cc 2024-05-03 13:34:25.182765869 +0200 > @@ -279,7 +279,8 @@ make_friend_class (tree type, tree frien > } > > if (! MAYBE_CLASS_TYPE_P (friend_type) > - && TREE_CODE (friend_type) != TEMPLATE_TEMPLATE_PARM) > + && TREE_CODE (friend_type) != TEMPLATE_TEMPLATE_PARM > + && TREE_CODE (friend_type) != TYPE_PACK_EXPANSION) > { > /* N1791: If the type specifier in a friend declaration designates a > (possibly cv-qualified) class type, that class is declared as a > --- gcc/cp/pt.cc.jj 2024-05-03 09:43:47.813511040 +0200 > +++ gcc/cp/pt.cc 2024-05-03 13:56:48.363582051 +0200 > @@ -12693,6 +12693,22 @@ instantiate_class_template (tree type) > tf_warning_or_error, NULL_TREE); > --processing_template_decl; > } > + else if (PACK_EXPANSION_P (friend_type)) > + { > + friend_type = tsubst_pack_expansion (friend_type, args, > + tf_warning_or_error, > + NULL_TREE); > + if (friend_type != error_mark_node) > + { > + unsigned int len = TREE_VEC_LENGTH (friend_type); > + for (unsigned int idx = 0; idx < len; ++idx) > + if (TREE_VEC_ELT (friend_type, idx) != error_mark_node) > + make_friend_class (type, > + TREE_VEC_ELT (friend_type, idx), > + /*complain=*/false); > + } > + friend_type = error_mark_node; > + } > else if (uses_template_parms (friend_type)) > /* friend class C; */ > friend_type = tsubst (friend_type, args, > --- gcc/testsuite/g++.dg/cpp26/feat-cxx26.C.jj 2024-05-02 09:31:17.754298166 +0200 > +++ gcc/testsuite/g++.dg/cpp26/feat-cxx26.C 2024-05-03 14:49:10.432023113 +0200 > @@ -615,3 +615,9 @@ > #elif __cpp_deleted_function != 202403 > # error "__cpp_deleted_function != 202403" > #endif > + > +#ifndef __cpp_variadic_friend > +# error "__cpp_variadic_friend" > +#elif __cpp_variadic_friend != 202403 > +# error "__cpp_variadic_friend != 202403" > +#endif > --- gcc/testsuite/g++.dg/cpp26/variadic-friend1.C.jj 2024-05-03 14:46:53.887873294 +0200 > +++ gcc/testsuite/g++.dg/cpp26/variadic-friend1.C 2024-05-03 14:45:50.624730486 +0200 > @@ -0,0 +1,58 @@ > +// P2893R3 - Variadic friends > +// { dg-do compile { target c++11 } } > +// { dg-options "" } > + > +template > +class A { > + class X {}; > + friend Ts...; // { dg-warning "variadic friends or friend type declarations with multiple types only available with" "" { target c++23_down } } > +}; > +template > +class A, A> { > + class X {}; > + friend > +#if __cplusplus < 202002L > + typename > +#endif > + Ts::Y..., Us...; // { dg-warning "variadic friends or friend type declarations with multiple types only available with" "" { target c++23_down } } > +}; > +template > +class B { > + class X {}; > + friend T, U; // { dg-warning "variadic friends or friend type declarations with multiple types only available with" "" { target c++23_down } } > +}; > +template > +class C { > + class X {}; > + friend U, Vs..., T; // { dg-warning "variadic friends or friend type declarations with multiple types only available with" "" { target c++23_down } } > +}; > +class E; > +class F; > +class G; > +class H; > +class I; > +class J; > +class K; > +class L; > +class M; > +class N; > +class O; > +class P; > +class E : A::X {}; > +class F : A::X {}; > +class G : B::X {}; > +class H : B::X {}; > +class I : C::X {}; > +class J : C::X {}; > +class K : C::X {}; > +class L : C::X {}; > +class M : C::X {}; > +class N : C::X {}; > +class O : C::X {}; > +struct Q { class Y : A, A>::X {}; }; > +class P : A, A>::X {}; > +struct R { class Y; }; > +struct S { class Y; }; > +class R::Y : A, A>::X {}; > +class S::Y : A, A>::X {}; > +A a; > > Jakub >