From: Jason Merrill <jason@redhat.com>
To: Jakub Jelinek <jakub@redhat.com>
Cc: gcc-patches@gcc.gnu.org
Subject: Re: [PATCH] c++: Implement C++26 P2893R3 - Variadic friends [PR114459]
Date: Tue, 7 May 2024 16:27:11 -0400 [thread overview]
Message-ID: <04cc28cf-f732-41d0-a3ed-9132c8ac7504@redhat.com> (raw)
In-Reply-To: <ZjUSTFY+YKS6dYL0@tucnak>
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 <jakub@redhat.com>
>
> 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 <typename T> struct A {
> - friend struct A<T>::B;
> - };
> + template <typename T> struct A {
> + friend struct A<T>::B;
> + };
>
> - A<T>::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<T>::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<T>; */
> 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... Ts>
> +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... Ts, class... Us>
> +class A<A<Ts...>, A<Us...>> {
> + 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 <typename T, typename U>
> +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 <typename T, typename U, typename... Vs>
> +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<E, F>::X {};
> +class F : A<E, F>::X {};
> +class G : B<G, H>::X {};
> +class H : B<G, H>::X {};
> +class I : C<I, J>::X {};
> +class J : C<I, J>::X {};
> +class K : C<K, L, M, N, O>::X {};
> +class L : C<K, L, M, N, O>::X {};
> +class M : C<K, L, M, N, O>::X {};
> +class N : C<K, L, M, N, O>::X {};
> +class O : C<K, L, M, N, O>::X {};
> +struct Q { class Y : A<A<Q>, A<P, long>>::X {}; };
> +class P : A<A<Q>, A<P, long>>::X {};
> +struct R { class Y; };
> +struct S { class Y; };
> +class R::Y : A<A<R, S>, A<P, double>>::X {};
> +class S::Y : A<A<R, S>, A<P, double>>::X {};
> +A<int> a;
>
> Jakub
>
prev parent reply other threads:[~2024-05-07 20:27 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-03 16:35 Jakub Jelinek
2024-05-07 20:27 ` Jason Merrill [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=04cc28cf-f732-41d0-a3ed-9132c8ac7504@redhat.com \
--to=jason@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=jakub@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).