From patchwork Thu Aug 31 06:02:36 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: waffl3x X-Patchwork-Id: 137230 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:c792:0:b0:3f2:4152:657d with SMTP id b18csp46031vqu; Wed, 30 Aug 2023 23:03:43 -0700 (PDT) X-Google-Smtp-Source: AGHT+IE2ZnukmbHRtJ4jmtR4RxaZ4LF5I0P150i/ODr6zDUxTXpRLW5gYrEtK0qWB+deJmHi9KUd X-Received: by 2002:a05:6402:68c:b0:522:3ef1:b1d with SMTP id f12-20020a056402068c00b005223ef10b1dmr3010650edy.6.1693461823031; Wed, 30 Aug 2023 23:03:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1693461823; cv=none; d=google.com; s=arc-20160816; b=Hc8GHHMddCN97YUUJeA15CjKAcwM0v0uJ0IZHERzWC6MaIJ4LFIE8GFew+WQ/H62OJ BSVmuG8wYsjcSl7gA4nIrBO/cycZs5cMq4GJAvpjLNilajFfD6iYBnL3rK3qshBmyQmG OLLnrDnEIilQ3iCEbXlnowbi5H7IKqUpfmi6VG0w/kOQqZlXUO39MhV2EMENHvkBh0ZP WCsxqsbL27zmK6ofCiKg80CjrdBkf2sk3AJIhCart9xqTroVkwA8KmNXIN+abTPjwt+2 27bCAHuMNNPBgwhh6l5Gdxpj5eTcLHGMofcNU9Vk3n6ywv5PCUf9uWSmOtZdELbuV247 6kvQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:from:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:mime-version :feedback-id:message-id:subject:to:date:dmarc-filter:delivered-to :dkim-signature:dkim-filter; bh=4CPC18zxTBQk1UX9ee8X7AdOIarbavoFGB5mqrMcaSA=; fh=XNn3asQvIblazGK92GBt13dVv+YmGV3pBS0JC29ZQco=; b=PtQkvP4oTMtBopLyhcevERmkn4LlqXgyP7dXWa1RRD5oiLbFoVq/QL3h0s94qcH8aA unjzku8bfTBwztWc/BHEVyO5CRW14IbI15U+SU3e7EbjFo9nNqH/c9WOHnND61a3U9hc PXXeJAl5cHiuFGFyvdjh2VSrz2lc4F5YcCsLxN+FIOCp/Ch0H0xhiYFJ915mxUvFXB26 CnmxZEaTXMEqrVm9gsS7BFoXh9j04cbBzSDCpNfxazYZLCiszB5wwExHwuz0myVjvgVr 1wPIYfuVWXHmKPLNWqdCrKEWwDSX4NIEW1gL1mw8gCA6aGFEqcA6mG9KPtguOSP86j1Z O/DA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=cGiKn+dE; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (ip-8-43-85-97.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id l8-20020aa7c308000000b005259e364ce3si562895edq.290.2023.08.30.23.03.42 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Aug 2023 23:03:43 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=cGiKn+dE; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B6E543858000 for ; Thu, 31 Aug 2023 06:03:41 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B6E543858000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1693461821; bh=4CPC18zxTBQk1UX9ee8X7AdOIarbavoFGB5mqrMcaSA=; h=Date:To:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=cGiKn+dEjIlG6LhALnHzfQbYA48yK3rebSMhCl7P8e7DT4TUKX4L+Cg53gm1tWHAG Dj+V/irWkP9m2kqHhZwwEhHles0hJ4xBQih14OMP+lljVgHJuQ3d95oFQijtWI6N+a rdS8wh8JbZ0RgdcjY8kxQFQkVcZqo9znmQ7a0+Sg= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-4324.protonmail.ch (mail-4324.protonmail.ch [185.70.43.24]) by sourceware.org (Postfix) with ESMTPS id 7B8903858D32 for ; Thu, 31 Aug 2023 06:02:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 7B8903858D32 Date: Thu, 31 Aug 2023 06:02:36 +0000 To: "gcc-patches@gcc.gnu.org" Subject: [PATCH 1/2] c++: Initial support for P0847R7 (Deducing This) [PR102609] Message-ID: Feedback-ID: 14591686:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-8.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS, SPF_PASS, 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 X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: waffl3x via Gcc-patches From: waffl3x Reply-To: waffl3x Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1775723424926250292 X-GMAIL-MSGID: 1775723424926250292 Bootstrapped and tested on x86_64-linux with no regressions. I would like to quickly thank everyone who helped me for their patience as I learned the ropes of the codebase and toolchain. It is much appretiated and this would have been much much more difficult without the support. This patch handles the new explicit object member functions by bypassing special behavior of implicit object member functions, but opting back into the special behavior during a function call through member access. This is mainly accomplished by bypassing becoming a METHOD_TYPE and remaining as a FUNCTION_TYPE. Normally, this would be treated as a static member function, but a new explicit object member function flag is added to lang_decl_base and is set for the declaration of explicit object member functions. This sets it apart from static member functions when it is relevant, and is the criteria used to opt-in to passing the implicit object argument during a member function call. The benefit of this design is less code needs to be modified to support the new feature, as most of the semantics of explicit object member functions matches those of static member functions. There is very little left to add, and hopefully there are few bugs in the implementation despite the minimal changes. It is possible there are hidden problems with passing the implicit object argument, but none of the tests I made exhibit such a thing EXCEPT for in the pathological case as I describe below. Upon reflection, a by value explicit object parameter might be broken as well, I can't recall if there's a good test for that case. Lambdas do not work yet, but you can work around it by marking it as mutable so I suspect it could be supported with minimal changes, I just ran out of time. The other thing that does not work is the pathological case with an explicit object parameter of an unrelated type and relying on a user-defined conversion operator to cast to said type in a call to that function. You can observe the failing test for that case in explicit-object-param-valid4.C, the result is somewhat interesting, but is also why I mention that there might be hidden problems here. I selectively excluded all the diagnostics from this patch, it's possible I made a mistake and the patch will be non-functional without the addition of the diagnostics patch. If that ends up being the case, please apply the following patch that includes the diagnostics and tests and judge the functionality from that. I believe that even if I mess up this patch, there should still be value in splitting up the changes into the two patches as it should make the changes to the behavior of the compiler much more clear. With that said, I believe I didn't make any mistakes while seperating the two patches, hopefully that is the case. I left in a FIXME (in call.cc) as I noticed last minute that I made a mistake, it should be benign and removing it appears to not break anything, but I don't have time to do another bootstrap at the moment. My priority is to get eyes on the changes I've made and recieve feedback. The patch including the diagnostics will follow shortly, assuming I don't run out of time and need to rush to catch my flight :). PS: Are there any circumstances where TREE_CODE is FUNCTION_DECL but the lang_specific member is null? I have a null check for that case in DECL_IS_XOBJ_MEMBER_FUNC but I question if it's necessary. From e485a79ec5656e72ba46053618843c3d69331eab Mon Sep 17 00:00:00 2001 From: Waffl3x Date: Thu, 31 Aug 2023 01:05:25 -0400 Subject: [PATCH] P0847R7 (deducing this) Initial support Most things should be functional, lambdas need a little more work though. Limitations: Missing support for lambdas, and user defined conversion functions when passing the implicit object argument does not work properly. See explicit-object-param-valid4.C for an example of the current (errent) behavior. There is a slight mistake in call.cc, it should be benign. gcc/cp/ChangeLog: * call.cc (add_function_candidate): (Hopefully) benign mistake (add_candidates): Treat explicit object member functions as member functions when considering candidates (build_over_call): Enable passing an implicit object argument when calling an explicit object member function * cp-tree.h (struct lang_decl_base): Added member xobj_flag for differentiating explicit object member functions from static member functions (DECL_FUNC_XOBJ_FLAG): New, checked access for xobj_flag (DECL_PARM_XOBJ_FLAG): New, access decl_flag_3 (DECL_IS_XOBJ_MEMBER_FUNC): New, safely check if a node is an explicit object member function (enum cp_decl_spec): Support parsing 'this' as a decl spec, change is mirrored in parser.cc:set_and_check_decl_spec_loc * decl.cc (grokfndecl): Sets the xobj flag for the FUNCTION_DECL if the first parameter is an explicit object parameter (grokdeclarator): Sets the xobj flag for PARM_DECL if 'this' spec is present in declspecs, bypasses conversion from FUNCTION_DECL to METHOD_DECL if an xobj flag is set for the first parameter of the given function declarator * parser.cc (cp_parser_decl_specifier_seq): check for 'this' specifier (set_and_check_decl_spec_loc): extended decl_spec_names to support 'this', change is mirrored in cp-tree.h:cp_decl_spec gcc/ChangeLog: * tree-core.h (struct tree_decl_common): Added comment describing new use of decl_flag_3 gcc/testsuite/ChangeLog: * g++.dg/cpp23/explicit-object-param-valid1.C: New test. * g++.dg/cpp23/explicit-object-param-valid2.C: New test. * g++.dg/cpp23/explicit-object-param-valid3.C: New test. * g++.dg/cpp23/explicit-object-param-valid4.C: New test. Signed-off-by: Waffl3x --- gcc/cp/call.cc | 13 +- gcc/cp/cp-tree.h | 20 +++- gcc/cp/decl.cc | 25 ++++ gcc/cp/parser.cc | 15 ++- .../cpp23/explicit-object-param-valid1.C | 113 ++++++++++++++++++ .../cpp23/explicit-object-param-valid2.C | 24 ++++ .../cpp23/explicit-object-param-valid3.C | 14 +++ .../cpp23/explicit-object-param-valid4.C | 33 +++++ gcc/tree-core.h | 3 +- 9 files changed, 254 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-object-param-valid1.C create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-object-param-valid2.C create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-object-param-valid3.C create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-object-param-valid4.C diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 673ec91d60e..ac5e414b084 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -2509,7 +2509,12 @@ add_function_candidate (struct z_candidate **candidates, tree parmtype = TREE_VALUE (parmnode); if (i == 0 && DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) - && !DECL_CONSTRUCTOR_P (fn)) + && !DECL_CONSTRUCTOR_P (fn) + /* FIXME: This doesn't seem to be neccesary, upon review I + realized that it doesn't make sense (an xobj member func + is not a nonstatic_member_function, so this check will + never change anything) */ + && !DECL_IS_XOBJ_MEMBER_FUNC (fn)) t = build_this_conversion (fn, ctype, parmtype, argtype, arg, flags, complain); else @@ -6566,7 +6571,8 @@ add_candidates (tree fns, tree first_arg, const vec *args, tree fn_first_arg = NULL_TREE; const vec *fn_args = args; - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)) + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) + || DECL_IS_XOBJ_MEMBER_FUNC (fn)) { /* Figure out where the object arg comes from. If this function is a non-static member and we didn't get an @@ -9995,7 +10001,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) } } /* Bypass access control for 'this' parameter. */ - else if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE) + else if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE + || DECL_IS_XOBJ_MEMBER_FUNC (fn) ) { tree arg = build_this (first_arg != NULL_TREE ? first_arg diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index eb901683b6d..3aca23da105 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2878,7 +2878,9 @@ struct GTY(()) lang_decl_base { /* VAR_DECL or FUNCTION_DECL has keyed decls. */ unsigned module_keyed_decls_p : 1; - /* 12 spare bits. */ + /* FUNCTION_DECL explicit object member function flag */ + unsigned xobj_flag : 1; + /* 11 spare bits. */ }; /* True for DECL codes which have template info and access. */ @@ -3086,6 +3088,21 @@ struct GTY(()) lang_decl { #endif /* ENABLE_TREE_CHECKING */ +/* these need to moved to somewhere appropriate */ + +/* the flag is a member of base, but the value is meaningless for other + decl types so checking is still justified I imagine */ +#define DECL_FUNC_XOBJ_FLAG(NODE) \ + (LANG_DECL_FN_CHECK (NODE)->min.base.xobj_flag) +/* not a lang_decl field, but still specific to c++ */ +#define DECL_PARM_XOBJ_FLAG(NODE) \ + (PARM_DECL_CHECK (NODE)->decl_common.decl_flag_3) +/* evaluates false for non func nodes and nodes with a null lang_decl member */ +#define DECL_IS_XOBJ_MEMBER_FUNC(NODE) \ + (TREE_CODE (STRIP_TEMPLATE (NODE)) == FUNCTION_DECL \ + && DECL_LANG_SPECIFIC (STRIP_TEMPLATE (NODE)) \ + && DECL_LANG_SPECIFIC (STRIP_TEMPLATE (NODE))->u.base.xobj_flag == 1) \ + /* For a FUNCTION_DECL or a VAR_DECL, the language linkage for the declaration. Some entities (like a member function in a local class, or a local variable) do not have linkage at all, and this @@ -6275,6 +6292,7 @@ enum cp_decl_spec { ds_complex, ds_constinit, ds_consteval, + ds_this, /* inserting here to match decl_spec_names in parser.cc*/ ds_thread, ds_type_spec, ds_redefined_builtin_type_spec, diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index bea0ee92106..a6d0cfb0ecc 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -10314,6 +10314,9 @@ grokfndecl (tree ctype, type = build_cp_fntype_variant (type, rqual, raises, late_return_type_p); decl = build_lang_decl_loc (location, FUNCTION_DECL, declarator, type); + /* all error checking has been done by now, just copy the flag over + parms is null (appears to be anyway) for 0 parm functions */ + DECL_FUNC_XOBJ_FLAG (decl) = parms ? DECL_PARM_XOBJ_FLAG (parms) : false; /* Set the constraints on the declaration. */ if (flag_concepts) @@ -12966,6 +12969,19 @@ grokdeclarator (const cp_declarator *declarator, if (attrlist) diagnose_misapplied_contracts (*attrlist); + /* Only used for skipping over build_memfn_type, grokfndecl handles + copying the flag to the correct field for a func_decl. + I wish there was a better way to do this, but there doesn't seem to be */ + bool is_xobj_member_function = false; + auto get_xobj_parm = [](tree parm_list) + { + if (!parm_list) + return NULL_TREE; + tree first_parm = TREE_VALUE (parm_list); + if (first_parm == void_type_node) + return NULL_TREE; + return DECL_PARM_XOBJ_FLAG (first_parm) == 1 ? first_parm : NULL_TREE; + }; /* Determine the type of the entity declared by recurring on the declarator. */ for (; declarator; declarator = declarator->declarator) @@ -13061,6 +13077,9 @@ grokdeclarator (const cp_declarator *declarator, case cdk_function: { + tree xobj_parm + = get_xobj_parm (declarator->u.function.parameters); + is_xobj_member_function = xobj_parm; tree arg_types; int funcdecl_p; @@ -14145,6 +14164,8 @@ grokdeclarator (const cp_declarator *declarator, } if (ctype && TREE_CODE (type) == FUNCTION_TYPE && staticp < 2 + /* bypass conversion to METHOD_TYPE if an xobj parm is present */ + && !is_xobj_member_function && !(unqualified_id && identifier_p (unqualified_id) && IDENTIFIER_NEWDEL_OP_P (unqualified_id))) @@ -14163,6 +14184,10 @@ grokdeclarator (const cp_declarator *declarator, { decl = cp_build_parm_decl (NULL_TREE, unqualified_id, type); DECL_ARRAY_PARAMETER_P (decl) = array_parameter_p; + /* Set the xobj flag for this parm, unfortunately + I don't think there is a better way to do this */ + DECL_PARM_XOBJ_FLAG (decl) + = decl_spec_seq_has_spec_p (declspecs, ds_this); bad_specifiers (decl, BSP_PARM, virtualp, memfn_quals != TYPE_UNQUALIFIED, diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index eeb22e44fb4..ed5dcbde3ed 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -15875,6 +15875,18 @@ cp_parser_decl_specifier_seq (cp_parser* parser, decl_specs->locations[ds_attribute] = token->location; continue; } + /* Special case for xobj parm, doesn't really belong up here + (it applies to parm decls and those are mostly handled below + the following specifiers) but I intend to refactor this function + so I'm not worrying about it too much. + The error diagnostics might be better elsewhere though. */ + if (token->keyword == RID_THIS) + { + cp_lexer_consume_token (parser->lexer); + set_and_check_decl_spec_loc (decl_specs, ds_this, token); + continue; + } + /* Assume we will find a decl-specifier keyword. */ found_decl_spec = true; /* If the next token is an appropriate keyword, we can simply @@ -33624,7 +33636,8 @@ set_and_check_decl_spec_loc (cp_decl_specifier_seq *decl_specs, "constexpr", "__complex", "constinit", - "consteval" + "consteval", + "this" }; gcc_rich_location richloc (location); richloc.add_fixit_remove (); diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-object-param-valid1.C b/gcc/testsuite/g++.dg/cpp23/explicit-object-param-valid1.C new file mode 100644 index 00000000000..12230cfc3d5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-object-param-valid1.C @@ -0,0 +1,113 @@ +// P0847R7 +// { dg-do compile { target c++23 } } + +// basic use cases and calling + +// non-trailing return +// definitions +struct S0 { + void f0(this S0) {} + void f1(this S0&) {} + void f2(this S0&&) {} + void f3(this S0 const&) {} + void f4(this S0 const&&) {} + template + void d0(this Self&&) {} + void d1(this auto&&) {} +}; +// declarations +struct S1 { + void f0(this S1); + void f1(this S1&); + void f2(this S1&&); + void f3(this S1 const&); + void f4(this S1 const&&); + template + void d0(this Self&&); + void d1(this auto&&); +}; +// out of line definitions +void S1::f0(this S1) {} +void S1::f1(this S1&) {} +void S1::f2(this S1&&) {} +void S1::f3(this S1 const&) {} +void S1::f4(this S1 const&&) {} +template +void S1::d0(this Self&&) {} +void S1::d1(this auto&&) {} + +// trailing return +// definitions +struct S2 { + auto f0(this S2) -> void {} + auto f1(this S2&) -> void {} + auto f2(this S2&&) -> void {} + auto f3(this S2 const&) -> void {} + auto f4(this S2 const&&) -> void {} + template + auto d0(this Self&&) -> void {} + + auto d1(this auto&&) -> void {} +}; +// declarations +struct S3 { + auto f0(this S3) -> void; + auto f1(this S3&) -> void; + auto f2(this S3&&) -> void; + auto f3(this S3 const&) -> void; + auto f4(this S3 const&&) -> void; + template + auto d0(this Self&&) -> void; + auto d1(this auto&&) -> void; +}; +// out of line definitions +auto S3::f0(this S3) -> void {} +auto S3::f1(this S3&) -> void {} +auto S3::f2(this S3&&) -> void {} +auto S3::f3(this S3 const&) -> void {} +auto S3::f4(this S3 const&&) -> void {} +template +auto S3::d0(this Self&&) -> void {} +auto S3::d1(this auto&&) -> void {} + +template +void call_with_qualification() +{ + T obj{}; + // by value should take any qualification (f0) + T{}.f0(); + obj.f0(); + static_cast(obj).f0(); + static_cast(obj).f0(); + static_cast(obj).f0(); + // specific qualification (f1 - f4) + T{}.f2(); + T{}.f3(); + T{}.f4(); + obj.f1(); + obj.f3(); + static_cast(obj).f2(); + static_cast(obj).f3(); + static_cast(obj).f4(); + static_cast(obj).f3(); + static_cast(obj).f4(); + // deduced should (obviously) take any qualification (d0, d1) + T{}.d0(); + obj.d0(); + static_cast(obj).d0(); + static_cast(obj).d0(); + static_cast(obj).d0(); + T{}.d1(); + obj.d1(); + static_cast(obj).d1(); + static_cast(obj).d1(); + static_cast(obj).d1(); +} + +void perform_calls() +{ + call_with_qualification(); + call_with_qualification(); + call_with_qualification(); + call_with_qualification(); +} \ No newline at end of file diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-object-param-valid2.C b/gcc/testsuite/g++.dg/cpp23/explicit-object-param-valid2.C new file mode 100644 index 00000000000..2f9a08207d4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-object-param-valid2.C @@ -0,0 +1,24 @@ +// P0847R7 +// { dg-do run { target c++23 } } + +// explicit object member function pointer type deduction and conversion to function pointer +// and calling through pointer to function + +struct S { + int _n; + int f(this S& self) { return self._n; } +}; + +using f_type = int(*)(S&); + +static_assert(__is_same(f_type, decltype(&S::f))); + +int main() +{ + auto fp0 = &S::f; + f_type fp1 = &S::f; + static_assert(__is_same(decltype(fp0), decltype(fp1))); + S s{42}; + // { dg-output "42" } + __builtin_printf("%d\n%d\n", fp0(s), fp1(s)); +} \ No newline at end of file diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-object-param-valid3.C b/gcc/testsuite/g++.dg/cpp23/explicit-object-param-valid3.C new file mode 100644 index 00000000000..2b2bc458df8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-object-param-valid3.C @@ -0,0 +1,14 @@ +// P0847R7 +// { dg-do compile { target c++23 } } + +// recursive lambdas + +// { dg-excess-errors "deducing this with lambdas not implemented yet" { xfail *-*-* } } + +int main() +{ + auto cl0 = [](this auto&& self, int n){ return n ? self(n - 1) : 42 }; + auto cl1 = [](this auto self, int n){ return n ? self(n - 1) : 42}; + int a = cl0(5); + int b = cl1(5); +} \ No newline at end of file diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-object-param-valid4.C b/gcc/testsuite/g++.dg/cpp23/explicit-object-param-valid4.C new file mode 100644 index 00000000000..1e9ade62a51 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-object-param-valid4.C @@ -0,0 +1,33 @@ +// P0847R7 +// { dg-do run { target c++23 } } + +// test implicit conversion of the object argument +// to the explicit object parameter + +// we compare &s to ret because early on, the +// object parameter would not convert, it would just get +// reinterpreted as the type of the explicit object param + +// { dg-output "ret != &s : 1" { xfail *-*-* } } +// { dg-output "ret == 42 : 1" { xfail *-*-* } } + +using uintptr_t = __UINTPTR_TYPE__; + +struct S { + operator uintptr_t() const { + return 42; + } + uintptr_t f(this uintptr_t n) { + return n; + } +}; + +int main() +{ + S s{}; + uintptr_t ret = s.f(); + __builtin_printf("ret != &s : %d\n" + "ret == 42 : %d\n", + ret != reinterpret_cast(&s) ? 1 : 0, + ret == 42 ? 1 : 0); +} \ No newline at end of file diff --git a/gcc/tree-core.h b/gcc/tree-core.h index 91551fde900..e434bd7c9ac 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -1808,7 +1808,8 @@ struct GTY(()) tree_decl_common { DECL_HAS_VALUE_EXPR_P. */ unsigned decl_flag_2 : 1; /* In FIELD_DECL, this is DECL_PADDING_P. - In VAR_DECL, this is DECL_MERGEABLE. */ + In VAR_DECL, this is DECL_MERGEABLE. + In PARM_DECL, this is DECL_XOBJ_PARM. */ unsigned decl_flag_3 : 1; /* Logically, these two would go in a theoretical base shared by var and parm decl. */ -- 2.41.0