From patchwork Sun Jan 7 00:00:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: waffl3x X-Patchwork-Id: 1883313 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; secure) header.d=protonmail.com header.i=@protonmail.com header.a=rsa-sha256 header.s=protonmail3 header.b=pyAPMxdT; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4T6y633XH2z1yP7 for ; Sun, 7 Jan 2024 11:01:29 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id F40A93858403 for ; Sun, 7 Jan 2024 00:01:26 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-4316.protonmail.ch (mail-4316.protonmail.ch [185.70.43.16]) by sourceware.org (Postfix) with ESMTPS id 4E5263858D20 for ; Sun, 7 Jan 2024 00:00:41 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4E5263858D20 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=protonmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=protonmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 4E5263858D20 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=185.70.43.16 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1704585652; cv=none; b=dbWfTjiOjafqIJAuCbHel3TDdyMGihLbgpAbgDeK6V5bPJNE6naeLgW8xvRHrl9FHZWeBj+ZuevrEMBC5fvZwrU4H/X/HwWfOZYtNhjtKMuRu7cJJzwY7IaHyyEUzIkBOLW0vFdBFLK9lZHVnEWJgoUHcIfGLS8A1awSCGcg/+8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1704585652; c=relaxed/simple; bh=5LYi2F/6oW+NFFN5960NeJFqgcd2aBtUune09l6K1Vc=; h=DKIM-Signature:Date:To:From:Subject:Message-ID:MIME-Version; b=ILI1vjDEMXxeKB7EYGIISNkMUuFPfMgEK+y/oXKVAZ8B+oQNWazg9mHGcD2uW78DhVlszOF0lSIyLMHdgtoVXSnkMJb8RVNWQx14k2JVSuhgLAuguvw8mR1ValbaFmuzumWkiSzpvCpLkBPSqKrE8oXhr57U9O4D8HgcuX8qVqY= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com; s=protonmail3; t=1704585635; x=1704844835; bh=5LYi2F/6oW+NFFN5960NeJFqgcd2aBtUune09l6K1Vc=; h=Date:To:From:Cc:Subject:Message-ID:Feedback-ID:From:To:Cc:Date: Subject:Reply-To:Feedback-ID:Message-ID:BIMI-Selector; b=pyAPMxdT8hdlyQSTznEgdOtL/A/n+zfmjM0ztZUCuv++FuSzyPRZ0y6yCf9j2qnVP hKCopKZyNsYhvHMVeH+nJS5lFvUwXKF4Kog4MuBbJ534AxerAZqrEriBe5JHgjMvzF J+0dJE2KTxLQ0rrsGQfrVEyGIuY630ts/GZSkueQNLIFiXpmEWcagTuoUQhhW9tROj rOm0NLA/cms6tcHLxbJz0NKSYJ647U1iE9xt5+IcxMYYgP5tXD68gjC2qRvy0yrsv4 nXOEDLPMz4URoEJv0G5VylgDGGoFRJkH0N/WLEAQCS2f5Tsj1JDN725XYA1vCqAnEA K8/1Li8dEyLug== Date: Sun, 07 Jan 2024 00:00:10 +0000 To: waffl3x From: waffl3x Cc: Jason Merrill , "gcc-patches@gcc.gnu.org" Subject: [PATCH v8 1/4] c++: P0847R7 (deducing this) - prerequisite changes. [PR102609] Message-ID: Feedback-ID: 14591686:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-8.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE, URIBL_BLACK 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: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Bootstrapped and tested on x86_64-linux with no regressions. I'm considering this finished, I have CWG2586 working but I have not included it in this version of the patch. I was not happy with the amount of work I had done on it. I will try to get it finished before we get cut off, and I'm pretty sure I can. I just don't want to risk missing the boat for the whole patch just for that. There aren't too many changes from v7, it's mostly just cleaned up. There are a few though, so do take a look, if there's anything severe I can rush to fix it if necessary. That's all, hopefully all is good, fingers crossed. Alex From cd122053dfad741a7d90adcd45929af768ce643f Mon Sep 17 00:00:00 2001 From: Waffl3x Date: Sun, 31 Dec 2023 03:16:36 -0700 Subject: [PATCH 1/4] C++23 P0847R7 (deducing this) - prerequisite changes. [PR102609] Adds the xobj_flag member to lang_decl_fn and a corresponding member access macro and predicate to support the addition of explicit object member functions. Additionally, since explicit object member functions are also non-static member functions, we need to change uses of DECL_NONSTATIC_MEMBER_FUNCTION_P to clarify whether they intend to include or exclude them. Many of these alterations are authored by Jason Merril. PR c++/102609 gcc/cp/ChangeLog: PR c++/102609 C++23 P0847R7 (deducing this) - prerequisite changes. [PR102609] * cp-tree.h (struct lang_decl_fn): New data member. (DECL_NONSTATIC_MEMBER_FUNCTION_P): Poison. (DECL_IOBJ_MEMBER_FUNCTION_P): Define. (DECL_FUNCTION_XOBJ_FLAG): Define. (DECL_XOBJ_MEMBER_FUNCTION_P): Define. (DECL_OBJECT_MEMBER_FUNCTION_P): Define. (DECL_FUNCTION_MEMBER_P): Don't use DECL_NONSTATIC_MEMBER_FUNCTION_P. (DECL_CONST_MEMFUNC_P): Likewise. (DECL_VOLATILE_MEMFUNC_P): Likewise. (DECL_NONSTATIC_MEMBER_P): Likewise. * module.cc (trees_out::lang_decl_bools): Handle xobj_flag. (trees_in::lang_decl_bools): Handle xobj_flag. * call.cc (build_this_conversion): (add_function_candidate): (add_template_candidate_real): (add_candidates): (maybe_warn_class_memaccess): (cand_parms_match): (joust): (do_warn_dangling_reference): Don't use it. * class.cc (finalize_literal_type_property): (finish_struct): (resolve_address_of_overloaded_function): * constexpr.cc (is_valid_constexpr_fn): (cxx_bind_parameters_in_call): * contracts.cc (build_contract_condition_function): * cp-objcp-common.cc (cp_decl_dwarf_attribute): * cxx-pretty-print.cc (cxx_pretty_printer::postfix_expression): (cxx_pretty_printer::declaration_specifiers): (cxx_pretty_printer::direct_declarator): * decl.cc (cp_finish_decl): (grok_special_member_properties): (start_preparsed_function): (record_key_method_defined): * decl2.cc (cp_handle_deprecated_or_unavailable): * init.cc (find_uninit_fields_r): (build_offset_ref): * lambda.cc (lambda_expr_this_capture): (maybe_generic_this_capture): (nonlambda_method_basetype): * mangle.cc (write_nested_name): * method.cc (early_check_defaulted_comparison): (skip_artificial_parms_for): (num_artificial_parms_for): * module.cc (trees_out::lang_decl_bools): (trees_in::lang_decl_bools): * pt.cc (is_specialization_of_friend): (determine_specialization): (copy_default_args_to_explicit_spec): (check_explicit_specialization): (tsubst_contract_attribute): (check_non_deducible_conversions): (more_specialized_fn): (maybe_instantiate_noexcept): (register_parameter_specializations): (value_dependent_expression_p): * search.cc (shared_member_p): (lookup_member): (field_access_p): * semantics.cc (finish_omp_declare_simd_methods): * tree.cc (lvalue_kind): * typeck.cc (invalid_nonstatic_memfn_p): Don't use DECL_NONSTATIC_MEMBER_FUNCTION_P. libcc1/ChangeLog: PR c++/102609 C++23 P0847R7 (deducing this) - prerequisite changes. [PR102609] * libcp1plugin.cc (plugin_pragma_push_user_expression): Don't use DECL_NONSTATIC_MEMBER_FUNCTION_P. Signed-off-by: Waffl3x --- gcc/cp/call.cc | 25 +++++++++++++------------ gcc/cp/class.cc | 6 +++--- gcc/cp/constexpr.cc | 4 ++-- gcc/cp/contracts.cc | 6 +++--- gcc/cp/cp-objcp-common.cc | 4 ++-- gcc/cp/cp-tree.h | 37 ++++++++++++++++++++++++++++++------- gcc/cp/cxx-pretty-print.cc | 6 +++--- gcc/cp/decl.cc | 8 ++++---- gcc/cp/decl2.cc | 2 +- gcc/cp/init.cc | 4 ++-- gcc/cp/lambda.cc | 9 +++++---- gcc/cp/mangle.cc | 4 ++-- gcc/cp/method.cc | 8 ++++---- gcc/cp/module.cc | 6 ++++-- gcc/cp/pt.cc | 38 +++++++++++++++++++------------------- gcc/cp/search.cc | 5 +++-- gcc/cp/semantics.cc | 2 +- gcc/cp/tree.cc | 2 +- gcc/cp/typeck.cc | 2 +- libcc1/libcp1plugin.cc | 2 +- 20 files changed, 104 insertions(+), 76 deletions(-) diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 6ac87a298b2..46f2ccdfc48 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -2309,7 +2309,7 @@ build_this_conversion (tree fn, tree ctype, tree& parmtype, tree& argtype, tree& arg, int flags, tsubst_flags_t complain) { - gcc_assert (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) + gcc_assert (DECL_IOBJ_MEMBER_FUNCTION_P (fn) && !DECL_CONSTRUCTOR_P (fn)); /* The type of the implicit object parameter ('this') for @@ -2522,7 +2522,7 @@ add_function_candidate (struct z_candidate **candidates, { tree parmtype = TREE_VALUE (parmnode); if (i == 0 - && DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) + && DECL_IOBJ_MEMBER_FUNCTION_P (fn) && !DECL_CONSTRUCTOR_P (fn)) t = build_this_conversion (fn, ctype, parmtype, argtype, arg, flags, complain); @@ -3479,7 +3479,7 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl, /* We don't do deduction on the in-charge parameter, the VTT parameter or 'this'. */ - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (tmpl)) + if (DECL_IOBJ_MEMBER_FUNCTION_P (tmpl)) { if (first_arg_without_in_chrg != NULL_TREE) first_arg_without_in_chrg = NULL_TREE; @@ -3589,7 +3589,7 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl, convs = alloc_conversions (nargs); if (shortcut_bad_convs - && DECL_NONSTATIC_MEMBER_FUNCTION_P (tmpl) + && DECL_IOBJ_MEMBER_FUNCTION_P (tmpl) && !DECL_CONSTRUCTOR_P (tmpl)) { /* Check the 'this' conversion before proceeding with deduction. @@ -6617,7 +6617,7 @@ 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_OBJECT_MEMBER_FUNCTION_P (fn)) { /* Figure out where the object arg comes from. If this function is a non-static member and we didn't get an @@ -10784,7 +10784,8 @@ maybe_warn_class_memaccess (location_t loc, tree fndecl, type. If so, and if the class has no non-trivial bases or members, be more permissive. */ if (current_function_decl - && DECL_NONSTATIC_MEMBER_FUNCTION_P (current_function_decl) + && DECL_OBJECT_MEMBER_FUNCTION_P (current_function_decl) + /* ??? is_object_parameter? */ && is_this_parameter (tree_strip_nop_conversions (dest))) { tree ctx = DECL_CONTEXT (current_function_decl); @@ -12684,8 +12685,8 @@ cand_parms_match (z_candidate *c1, z_candidate *c2) tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (fn2)); if (DECL_FUNCTION_MEMBER_P (fn1) && DECL_FUNCTION_MEMBER_P (fn2) - && (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn1) - != DECL_NONSTATIC_MEMBER_FUNCTION_P (fn2))) + && (DECL_STATIC_FUNCTION_P (fn1) + != DECL_STATIC_FUNCTION_P (fn2))) { /* Ignore 'this' when comparing the parameters of a static member function with those of a non-static one. */ @@ -12870,7 +12871,7 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn, print_z_candidate (input_location, N_("candidate 2:"), l); if (w->fn == l->fn - && DECL_NONSTATIC_MEMBER_FUNCTION_P (w->fn) + && DECL_IOBJ_MEMBER_FUNCTION_P (w->fn) && (type_memfn_quals (TREE_TYPE (w->fn)) & TYPE_QUAL_CONST) == 0) { @@ -14019,7 +14020,7 @@ do_warn_dangling_reference (tree expr, bool arg_p) because R refers to one of the int elements of V, not to a temporary object. Member operator* may return a reference but probably not to one of its arguments. */ - || (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl) + || (DECL_OBJECT_MEMBER_FUNCTION_P (fndecl) && DECL_OVERLOADED_OPERATOR_P (fndecl) && DECL_OVERLOADED_OPERATOR_IS (fndecl, INDIRECT_REF))) return NULL_TREE; @@ -14045,7 +14046,7 @@ do_warn_dangling_reference (tree expr, bool arg_p) tree arg = CALL_EXPR_ARG (expr, i); /* Check that this argument initializes a reference, except for the argument initializing the object of a member function. */ - if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl) + if (!DECL_IOBJ_MEMBER_FUNCTION_P (fndecl) && !TYPE_REF_P (TREE_TYPE (arg))) continue; STRIP_NOPS (arg); @@ -14065,7 +14066,7 @@ do_warn_dangling_reference (tree expr, bool arg_p) const S& s = S().self(); where 's' dangles. If we've gotten here, the object this function is invoked on is not a temporary. */ - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl)) + if (DECL_OBJECT_MEMBER_FUNCTION_P (fndecl)) break; } return NULL_TREE; diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc index 1954e0a5ed3..692b238dd7e 100644 --- a/gcc/cp/class.cc +++ b/gcc/cp/class.cc @@ -5968,7 +5968,7 @@ finalize_literal_type_property (tree t) for (fn = TYPE_FIELDS (t); fn; fn = DECL_CHAIN (fn)) if (TREE_CODE (fn) == FUNCTION_DECL && DECL_DECLARED_CONSTEXPR_P (fn) - && DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) + && DECL_IOBJ_MEMBER_FUNCTION_P (fn) && !DECL_CONSTRUCTOR_P (fn)) { DECL_DECLARED_CONSTEXPR_P (fn) = false; @@ -7932,7 +7932,7 @@ finish_struct (tree t, tree attributes) if (flag_openmp) for (tree decl = TYPE_FIELDS (t); decl; decl = DECL_CHAIN (decl)) if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) + && DECL_OBJECT_MEMBER_FUNCTION_P (decl)) if (tree attr = lookup_attribute ("omp declare variant base", DECL_ATTRIBUTES (decl))) omp_declare_variant_finalize (decl, attr); @@ -8727,7 +8727,7 @@ resolve_address_of_overloaded_function (tree target_type, /* Good, exactly one match. Now, convert it to the correct type. */ fn = TREE_PURPOSE (matches); - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) + if (DECL_OBJECT_MEMBER_FUNCTION_P (fn) && !(complain & tf_ptrmem_ok) && !flag_ms_extensions) { static int explained; diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index eff43a42353..b12473c44af 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -291,7 +291,7 @@ is_valid_constexpr_fn (tree fun, bool complain) /* C++14 DR 1684 removed this restriction. */ if (cxx_dialect < cxx14 - && DECL_NONSTATIC_MEMBER_FUNCTION_P (fun) + && DECL_IOBJ_MEMBER_FUNCTION_P (fun) && !CLASSTYPE_LITERAL_P (DECL_CONTEXT (fun))) { ret = false; @@ -1886,7 +1886,7 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun, non_constant_p, overflow_p); /* Check we aren't dereferencing a null pointer when calling a non-static member function, which is undefined behaviour. */ - if (i == 0 && DECL_NONSTATIC_MEMBER_FUNCTION_P (fun) + if (i == 0 && DECL_OBJECT_MEMBER_FUNCTION_P (fun) && integer_zerop (arg) /* But ignore calls from within compiler-generated code, to handle cases like lambda function pointer conversion operator thunks diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc index 035ca4827e7..c505b67d339 100644 --- a/gcc/cp/contracts.cc +++ b/gcc/cp/contracts.cc @@ -1398,7 +1398,7 @@ build_contract_condition_function (tree fndecl, bool pre) { if (TREE_TYPE (fndecl) == error_mark_node) return error_mark_node; - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl) + if (DECL_IOBJ_MEMBER_FUNCTION_P (fndecl) && !TYPE_METHOD_BASETYPE (TREE_TYPE (fndecl))) return error_mark_node; @@ -1421,7 +1421,7 @@ build_contract_condition_function (tree fndecl, bool pre) arg_type && arg_type != void_list_node; arg_type = TREE_CHAIN (arg_type)) { - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl) + if (DECL_IOBJ_MEMBER_FUNCTION_P (fndecl) && TYPE_ARG_TYPES (TREE_TYPE (fn)) == arg_type) { class_type = TREE_TYPE (TREE_VALUE (arg_type)); @@ -1451,7 +1451,7 @@ build_contract_condition_function (tree fndecl, bool pre) } TREE_TYPE (fn) = build_function_type (value_type, arg_types); - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl)) + if (DECL_IOBJ_MEMBER_FUNCTION_P (fndecl)) TREE_TYPE (fn) = build_method_type (class_type, TREE_TYPE (fn)); DECL_NAME (fn) = copy_node (DECL_NAME (fn)); diff --git a/gcc/cp/cp-objcp-common.cc b/gcc/cp/cp-objcp-common.cc index ee88df5767b..3970c4cddd5 100644 --- a/gcc/cp/cp-objcp-common.cc +++ b/gcc/cp/cp-objcp-common.cc @@ -349,7 +349,7 @@ cp_decl_dwarf_attribute (const_tree decl, int attr) case DW_AT_reference: if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl) + && DECL_IOBJ_MEMBER_FUNCTION_P (decl) && FUNCTION_REF_QUALIFIED (TREE_TYPE (decl)) && !FUNCTION_RVALUE_QUALIFIED (TREE_TYPE (decl))) return 1; @@ -357,7 +357,7 @@ cp_decl_dwarf_attribute (const_tree decl, int attr) case DW_AT_rvalue_reference: if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl) + && DECL_IOBJ_MEMBER_FUNCTION_P (decl) && FUNCTION_REF_QUALIFIED (TREE_TYPE (decl)) && FUNCTION_RVALUE_QUALIFIED (TREE_TYPE (decl))) return 1; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 1979572c365..41d480f8e6e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2962,8 +2962,9 @@ struct GTY(()) lang_decl_fn { unsigned coroutine_p : 1; unsigned implicit_constexpr : 1; unsigned escalated_p : 1; + unsigned xobj_func : 1; - unsigned spare : 8; + unsigned spare : 7; /* 32-bits padding on 64-bit host. */ @@ -3361,33 +3362,55 @@ struct GTY(()) lang_decl { #define DECL_STATIC_FUNCTION_P(NODE) \ (LANG_DECL_FN_CHECK (NODE)->static_function) -/* Nonzero for FUNCTION_DECL means that this decl is a non-static +/* Nonzero for FUNCTION_DECL means that this decl is a non-static member + function. C++23 explicit object member functions are also considered + non-static, but most former uses of this macro meant implicit object member + function. Instead of this macro, use DECL_IOBJ_MEMBER_FUNCTION_P or + DECL_OBJECT_MEMBER_FUNCTION_P. */ +#define DECL_NONSTATIC_MEMBER_FUNCTION_P(NODE) did_you_mean_object_or_iobj + +/* Nonzero for FUNCTION_DECL means that this decl is an implicit object member function. */ -#define DECL_NONSTATIC_MEMBER_FUNCTION_P(NODE) \ +#define DECL_IOBJ_MEMBER_FUNCTION_P(NODE) \ (TREE_CODE (TREE_TYPE (NODE)) == METHOD_TYPE) +/* Simple member access, only valid for FUNCTION_DECL nodes. */ +#define DECL_FUNCTION_XOBJ_FLAG(NODE) \ + (LANG_DECL_FN_CHECK (NODE)->xobj_func) + +/* Nonzero if NODE is an xobj member function, + safely evaluates to false for all non FUNCTION_DECL nodes. */ +#define DECL_XOBJ_MEMBER_FUNCTION_P(NODE) \ + (TREE_CODE (STRIP_TEMPLATE (NODE)) == FUNCTION_DECL \ + && DECL_FUNCTION_XOBJ_FLAG (NODE) == 1) + +/* Nonzero if NODE is a member function with an object argument, + in other words, a non-static member function. */ +#define DECL_OBJECT_MEMBER_FUNCTION_P(NODE) \ + (DECL_IOBJ_MEMBER_FUNCTION_P (NODE) || DECL_XOBJ_MEMBER_FUNCTION_P (NODE)) + /* Nonzero for FUNCTION_DECL means that this decl is a member function (static or non-static). */ #define DECL_FUNCTION_MEMBER_P(NODE) \ - (DECL_NONSTATIC_MEMBER_FUNCTION_P (NODE) || DECL_STATIC_FUNCTION_P (NODE)) + (DECL_OBJECT_MEMBER_FUNCTION_P (NODE) || DECL_STATIC_FUNCTION_P (NODE)) \ /* Nonzero for FUNCTION_DECL means that this member function has `this' as const X *const. */ #define DECL_CONST_MEMFUNC_P(NODE) \ - (DECL_NONSTATIC_MEMBER_FUNCTION_P (NODE) \ + (DECL_IOBJ_MEMBER_FUNCTION_P (NODE) \ && CP_TYPE_CONST_P (TREE_TYPE (TREE_VALUE \ (TYPE_ARG_TYPES (TREE_TYPE (NODE)))))) /* Nonzero for FUNCTION_DECL means that this member function has `this' as volatile X *const. */ #define DECL_VOLATILE_MEMFUNC_P(NODE) \ - (DECL_NONSTATIC_MEMBER_FUNCTION_P (NODE) \ + (DECL_IOBJ_MEMBER_FUNCTION_P (NODE) \ && CP_TYPE_VOLATILE_P (TREE_TYPE (TREE_VALUE \ (TYPE_ARG_TYPES (TREE_TYPE (NODE)))))) /* Nonzero for a DECL means that this member is a non-static member. */ #define DECL_NONSTATIC_MEMBER_P(NODE) \ - (DECL_NONSTATIC_MEMBER_FUNCTION_P (NODE) \ + (DECL_OBJECT_MEMBER_FUNCTION_P (NODE) \ || TREE_CODE (NODE) == FIELD_DECL) /* Nonzero for a FIELD_DECL means that this member object type diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc index 6a82358f370..53c0722d2f3 100644 --- a/gcc/cp/cxx-pretty-print.cc +++ b/gcc/cp/cxx-pretty-print.cc @@ -553,7 +553,7 @@ cxx_pretty_printer::postfix_expression (tree t) instantiation time. */ if (TREE_CODE (fun) != FUNCTION_DECL) ; - else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)) + else if (DECL_OBJECT_MEMBER_FUNCTION_P (fun)) { tree object = (code == AGGR_INIT_EXPR ? (AGGR_INIT_VIA_CTOR_P (t) @@ -1342,7 +1342,7 @@ cxx_pretty_printer::declaration_specifiers (tree t) do not have a type-specifier in their return types. */ if (DECL_CONSTRUCTOR_P (t) || DECL_CONV_FN_P (t)) function_specifier (t); - else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (t)) + else if (DECL_IOBJ_MEMBER_FUNCTION_P (t)) declaration_specifiers (TREE_TYPE (TREE_TYPE (t))); else c_pretty_printer::declaration_specifiers (t); @@ -1700,7 +1700,7 @@ cxx_pretty_printer::direct_declarator (tree t) expression (t); pp_cxx_parameter_declaration_clause (this, t); - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (t)) + if (DECL_IOBJ_MEMBER_FUNCTION_P (t)) { padding = pp_before; pp_cxx_cv_qualifier_seq (this, pp_cxx_implicit_parameter_type (t)); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 27f17808934..b5b23b86b62 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -8526,7 +8526,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, && TREE_CODE (decl) == FUNCTION_DECL /* #pragma omp declare variant on methods handled in finish_struct instead. */ - && (!DECL_NONSTATIC_MEMBER_FUNCTION_P (decl) + && (!DECL_OBJECT_MEMBER_FUNCTION_P (decl) || COMPLETE_TYPE_P (DECL_CONTEXT (decl)))) if (tree attr = lookup_attribute ("omp declare variant base", DECL_ATTRIBUTES (decl))) @@ -15516,7 +15516,7 @@ grok_special_member_properties (tree decl) tree class_type; if (TREE_CODE (decl) == USING_DECL - || !DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) + || !DECL_OBJECT_MEMBER_FUNCTION_P (decl)) return; class_type = DECL_CONTEXT (decl); @@ -17706,7 +17706,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags) /* Start the statement-tree, start the tree now. */ DECL_SAVED_TREE (decl1) = push_stmt_list (); - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl1)) + if (DECL_IOBJ_MEMBER_FUNCTION_P (decl1)) { /* We know that this was set up by `grokclassfn'. We do not wait until `store_parm_decls', since evil parse errors may @@ -18175,7 +18175,7 @@ outer_curly_brace_block (tree fndecl) static void record_key_method_defined (tree fndecl) { - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl) + if (DECL_OBJECT_MEMBER_FUNCTION_P (fndecl) && DECL_VIRTUAL_P (fndecl) && !processing_template_decl) { diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 0850d3f5bce..c8eddf4cc26 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -5625,7 +5625,7 @@ cp_handle_deprecated_or_unavailable (tree decl, tsubst_flags_t complain) if (cxx_dialect >= cxx11 && DECL_P (decl) && DECL_ARTIFICIAL (decl) - && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl) + && DECL_IOBJ_MEMBER_FUNCTION_P (decl) && copy_fn_p (decl)) { /* Don't warn if the flag was disabled around the class definition diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index 6444f0a8518..fb5f404805b 100644 --- a/gcc/cp/init.cc +++ b/gcc/cp/init.cc @@ -866,7 +866,7 @@ find_uninit_fields_r (tree *tp, int *walk_subtrees, void *data) else if (code == CALL_EXPR) { tree fn = get_callee_fndecl (init); - if (fn && DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)) + if (fn && DECL_IOBJ_MEMBER_FUNCTION_P (fn)) { tree op = CALL_EXPR_ARG (init, 0); if (TREE_CODE (op) == ADDR_EXPR) @@ -2477,7 +2477,7 @@ build_offset_ref (tree type, tree member, bool address_p, -- in a mem-initializer for a constructor for that class or for a class derived from that class (_class.base.init_). */ - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (member)) + if (DECL_OBJECT_MEMBER_FUNCTION_P (member)) { /* Build a representation of the qualified name suitable for use as the operand to "&" -- even though the "&" is diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc index 5990a6de736..fc6a0708b66 100644 --- a/gcc/cp/lambda.cc +++ b/gcc/cp/lambda.cc @@ -834,8 +834,9 @@ lambda_expr_this_capture (tree lambda, int add_capture_p) if (!LAMBDA_FUNCTION_P (containing_function)) { - /* We found a non-lambda function. */ - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (containing_function)) + /* We found a non-lambda function. + There is no this pointer in xobj member functions. */ + if (DECL_IOBJ_MEMBER_FUNCTION_P (containing_function)) /* First parameter is 'this'. */ init = DECL_ARGUMENTS (containing_function); break; @@ -969,7 +970,7 @@ maybe_generic_this_capture (tree object, tree fns) for (lkp_iterator iter (fns); iter; ++iter) if (((!id_expr && TREE_CODE (*iter) != USING_DECL) || TREE_CODE (*iter) == TEMPLATE_DECL) - && DECL_NONSTATIC_MEMBER_FUNCTION_P (*iter)) + && DECL_IOBJ_MEMBER_FUNCTION_P (*iter)) { /* Found a non-static member. Capture this. */ lambda_expr_this_capture (lam, /*maybe*/-1); @@ -1012,7 +1013,7 @@ nonlambda_method_basetype (void) tree fn = TYPE_CONTEXT (type); if (!fn || TREE_CODE (fn) != FUNCTION_DECL - || !DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)) + || !DECL_IOBJ_MEMBER_FUNCTION_P (fn)) /* No enclosing non-lambda method. */ return NULL_TREE; if (!LAMBDA_FUNCTION_P (fn)) diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc index 365d470f46e..99fabbf3587 100644 --- a/gcc/cp/mangle.cc +++ b/gcc/cp/mangle.cc @@ -1231,9 +1231,9 @@ write_nested_name (const tree decl) write_char ('N'); - /* Write CV-qualifiers, if this is a member function. */ + /* Write CV-qualifiers, if this is an iobj member function. */ if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) + && DECL_IOBJ_MEMBER_FUNCTION_P (decl)) { if (DECL_VOLATILE_MEMFUNC_P (decl)) write_char ('V'); diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index f645066077f..d6ad5aa41d6 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -1187,7 +1187,7 @@ early_check_defaulted_comparison (tree fn) ok = false; } - bool mem = DECL_NONSTATIC_MEMBER_FUNCTION_P (fn); + bool mem = DECL_IOBJ_MEMBER_FUNCTION_P (fn); if (mem && type_memfn_quals (TREE_TYPE (fn)) != TYPE_QUAL_CONST) { error_at (loc, "defaulted %qD must be %", fn); @@ -1230,7 +1230,7 @@ early_check_defaulted_comparison (tree fn) if (saw_bad || (saw_byval && saw_byref)) { - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)) + if (DECL_IOBJ_MEMBER_FUNCTION_P (fn)) error_at (loc, "defaulted member %qD must have parameter type " "%", fn, ctx); else if (saw_bad) @@ -3606,7 +3606,7 @@ lazily_declare_fn (special_function_kind sfk, tree type) tree skip_artificial_parms_for (const_tree fn, tree list) { - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)) + if (DECL_IOBJ_MEMBER_FUNCTION_P (fn)) list = TREE_CHAIN (list); else return list; @@ -3626,7 +3626,7 @@ num_artificial_parms_for (const_tree fn) { int count = 0; - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)) + if (DECL_IOBJ_MEMBER_FUNCTION_P (fn)) count++; else return 0; diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 0bd46414da9..2d0c0a3eaab 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -5683,8 +5683,9 @@ trees_out::lang_decl_bools (tree t) WB (lang->u.fn.has_dependent_explicit_spec_p); WB (lang->u.fn.immediate_fn_p); WB (lang->u.fn.maybe_deleted); - WB (lang->u.fn.escalated_p); /* We do not stream lang->u.fn.implicit_constexpr. */ + WB (lang->u.fn.escalated_p); + WB (lang->u.fn.xobj_func); goto lds_min; case lds_decomp: /* lang_decl_decomp. */ @@ -5753,8 +5754,9 @@ trees_in::lang_decl_bools (tree t) RB (lang->u.fn.has_dependent_explicit_spec_p); RB (lang->u.fn.immediate_fn_p); RB (lang->u.fn.maybe_deleted); - RB (lang->u.fn.escalated_p); /* We do not stream lang->u.fn.implicit_constexpr. */ + RB (lang->u.fn.escalated_p); + RB (lang->u.fn.xobj_func); goto lds_min; case lds_decomp: /* lang_decl_decomp. */ diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 2817657a8bb..72eb124d116 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -1446,9 +1446,9 @@ is_specialization_of_friend (tree decl, tree friend_decl) `this' parameter. */ friend_args_type = TYPE_ARG_TYPES (friend_type); decl_args_type = TYPE_ARG_TYPES (decl_type); - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (friend_decl)) + if (DECL_IOBJ_MEMBER_FUNCTION_P (friend_decl)) friend_args_type = TREE_CHAIN (friend_args_type); - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) + if (DECL_IOBJ_MEMBER_FUNCTION_P (decl)) decl_args_type = TREE_CHAIN (decl_args_type); return compparms (decl_args_type, friend_args_type); @@ -2236,7 +2236,7 @@ determine_specialization (tree template_id, that the const qualification is the same. Since get_bindings does not try to merge the "this" parameter, we must do the comparison explicitly. */ - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)) + if (DECL_IOBJ_MEMBER_FUNCTION_P (fn)) { if (!same_type_p (TREE_VALUE (fn_arg_types), TREE_VALUE (decl_arg_types))) @@ -2359,14 +2359,14 @@ determine_specialization (tree template_id, /* Adjust the type of DECL in case FN is a static member. */ decl_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl)); if (DECL_STATIC_FUNCTION_P (fn) - && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) + && DECL_IOBJ_MEMBER_FUNCTION_P (decl)) decl_arg_types = TREE_CHAIN (decl_arg_types); if (!compparms (TYPE_ARG_TYPES (TREE_TYPE (fn)), decl_arg_types)) continue; - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) + if (DECL_IOBJ_MEMBER_FUNCTION_P (fn) && (type_memfn_rqual (TREE_TYPE (decl)) != type_memfn_rqual (TREE_TYPE (fn)))) continue; @@ -2552,7 +2552,7 @@ copy_default_args_to_explicit_spec (tree decl) old_type = TREE_TYPE (decl); spec_types = TYPE_ARG_TYPES (old_type); - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) + if (DECL_IOBJ_MEMBER_FUNCTION_P (decl)) { /* Remove the this pointer, but remember the object's type for CV quals. */ @@ -3137,7 +3137,7 @@ check_explicit_specialization (tree declarator, make DECL a static member function as well. */ if (DECL_FUNCTION_TEMPLATE_P (tmpl) && DECL_STATIC_FUNCTION_P (tmpl) - && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) + && DECL_IOBJ_MEMBER_FUNCTION_P (decl)) revert_static_member_fn (decl); /* If this is a specialization of a member template of a @@ -11814,7 +11814,7 @@ tsubst_contract_attribute (tree decl, tree t, tree args, /* For member functions, make this available for semantic analysis. */ tree save_ccp = current_class_ptr; tree save_ccr = current_class_ref; - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) + if (DECL_IOBJ_MEMBER_FUNCTION_P (decl)) { tree arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl)); tree this_type = TREE_TYPE (TREE_VALUE (arg_types)); @@ -22087,7 +22087,7 @@ check_non_deducible_conversions (tree parms, const tree *args, unsigned nargs, { /* Non-constructor methods need to leave a conversion for 'this', which isn't included in nargs here. */ - unsigned offset = (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) + unsigned offset = (DECL_IOBJ_MEMBER_FUNCTION_P (fn) && !DECL_CONSTRUCTOR_P (fn)); for (unsigned ia = 0; @@ -25314,16 +25314,16 @@ more_specialized_fn (tree pat1, tree pat2, int len) I think think the old G++ behavior of just skipping the object parameter when comparing to a static member function was better, so let's stick with that for now. This is CWG2834. --jason 2023-12 */ - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl1)) /* FIXME or explicit */ + if (DECL_OBJECT_MEMBER_FUNCTION_P (decl1)) { len--; /* LEN is the number of significant arguments for DECL1 */ args1 = TREE_CHAIN (args1); } - else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl2)) /* FIXME or explicit */ + else if (DECL_OBJECT_MEMBER_FUNCTION_P (decl2)) args2 = TREE_CHAIN (args2); } - else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl1) /* FIXME implicit only */ - && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl2)) + else if (DECL_IOBJ_MEMBER_FUNCTION_P (decl1) + && DECL_IOBJ_MEMBER_FUNCTION_P (decl2)) { /* Note DR2445 also (IMO wrongly) removed the "only one" above, which would break e.g. cpp1y/lambda-generic-variadic5.C. */ @@ -25331,12 +25331,12 @@ more_specialized_fn (tree pat1, tree pat2, int len) args1 = TREE_CHAIN (args1); args2 = TREE_CHAIN (args2); } - else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl1) /* FIXME implicit only */ - || DECL_NONSTATIC_MEMBER_FUNCTION_P (decl2)) + else if (DECL_IOBJ_MEMBER_FUNCTION_P (decl1) + || DECL_IOBJ_MEMBER_FUNCTION_P (decl2)) { /* The other is a non-member or explicit object member function; rewrite the implicit object parameter to a reference. */ - tree ns = DECL_NONSTATIC_MEMBER_FUNCTION_P (decl2) ? decl2 : decl1; + tree ns = DECL_IOBJ_MEMBER_FUNCTION_P (decl2) ? decl2 : decl1; tree &nsargs = ns == decl2 ? args2 : args1; tree obtype = TREE_TYPE (TREE_VALUE (nsargs)); @@ -26669,7 +26669,7 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain) push_deferring_access_checks (dk_no_deferred); input_location = DECL_SOURCE_LOCATION (fn); - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) + if (DECL_IOBJ_MEMBER_FUNCTION_P (fn) && !DECL_LOCAL_DECL_P (fn)) { /* If needed, set current_class_ptr for the benefit of @@ -26732,7 +26732,7 @@ register_parameter_specializations (tree pattern, tree inst) { tree tmpl_parm = DECL_ARGUMENTS (pattern); tree spec_parm = DECL_ARGUMENTS (inst); - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (inst)) + if (DECL_IOBJ_MEMBER_FUNCTION_P (inst)) { register_local_specialization (spec_parm, tmpl_parm); spec_parm = skip_artificial_parms_for (inst, spec_parm); @@ -28075,7 +28075,7 @@ value_dependent_expression_p (tree expression) cause the call to be considered value-dependent. We also look through it in potential_constant_expression. */ if (i == 0 && fn && DECL_DECLARED_CONSTEXPR_P (fn) - && DECL_NONSTATIC_MEMBER_FUNCTION_P (fn) + && DECL_IOBJ_MEMBER_FUNCTION_P (fn) && TREE_CODE (op) == ADDR_EXPR) op = TREE_OPERAND (op, 0); if (value_dependent_expression_p (op)) diff --git a/gcc/cp/search.cc b/gcc/cp/search.cc index ac79b625b6e..3473d66b88c 100644 --- a/gcc/cp/search.cc +++ b/gcc/cp/search.cc @@ -1008,7 +1008,7 @@ shared_member_p (tree t) /* Conservatively assume a dependent using-declaration might resolve to a non-static member. */ return false; - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) + if (DECL_OBJECT_MEMBER_FUNCTION_P (decl)) return false; } return true; @@ -1264,7 +1264,7 @@ lookup_member (tree xbasetype, tree name, int protect, bool want_type, decl = strip_using_decl (decl); /* A dependent USING_DECL will be checked after tsubsting. */ if (TREE_CODE (decl) != USING_DECL - && !DECL_NONSTATIC_MEMBER_FUNCTION_P (decl) + && !DECL_IOBJ_MEMBER_FUNCTION_P (decl) && !perform_or_defer_access_check (basetype_path, decl, decl, complain, afi)) return error_mark_node; @@ -1737,6 +1737,7 @@ field_access_p (tree component_ref, tree field_decl, tree field_type) return false; tree ptr = STRIP_NOPS (TREE_OPERAND (indirect_ref, 0)); + /* ??? is_object_parameter? */ if (!is_this_parameter (ptr)) return false; diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 64839b1ac87..3bc426fa130 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -6645,7 +6645,7 @@ finish_omp_declare_simd_methods (tree t) for (tree x = TYPE_FIELDS (t); x; x = DECL_CHAIN (x)) { if (TREE_CODE (x) == USING_DECL - || !DECL_NONSTATIC_MEMBER_FUNCTION_P (x)) + || !DECL_IOBJ_MEMBER_FUNCTION_P (x)) continue; tree ods = lookup_attribute ("omp declare simd", DECL_ATTRIBUTES (x)); if (!ods || !TREE_VALUE (ods)) diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index d17b9b34891..80596e3d976 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -298,7 +298,7 @@ lvalue_kind (const_tree ref) case FUNCTION_DECL: /* All functions (except non-static-member functions) are lvalues. */ - return (DECL_NONSTATIC_MEMBER_FUNCTION_P (ref) + return (DECL_IOBJ_MEMBER_FUNCTION_P (ref) ? clk_none : clk_ordinary); case BASELINK: diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index a6e2f4ee7da..2abf9f3b905 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -2352,7 +2352,7 @@ invalid_nonstatic_memfn_p (location_t loc, tree expr, tsubst_flags_t complain) if (is_overloaded_fn (expr) && !really_overloaded_fn (expr)) expr = get_first_fn (expr); if (TREE_TYPE (expr) - && DECL_NONSTATIC_MEMBER_FUNCTION_P (expr)) + && DECL_IOBJ_MEMBER_FUNCTION_P (expr)) { if (complain & tf_error) { diff --git a/libcc1/libcp1plugin.cc b/libcc1/libcp1plugin.cc index 3c8e9e8b436..108d5786167 100644 --- a/libcc1/libcp1plugin.cc +++ b/libcc1/libcp1plugin.cc @@ -468,7 +468,7 @@ plugin_pragma_push_user_expression (cpp_reader *) } } - if (unchanged_cfun || DECL_NONSTATIC_MEMBER_FUNCTION_P (changed_func_decl)) + if (unchanged_cfun || DECL_OBJECT_MEMBER_FUNCTION_P (changed_func_decl)) { /* Check whether the oracle supplies us with a "this", and if so, arrange for data members and this itself to be -- 2.43.0 From patchwork Sun Jan 7 00:03:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: waffl3x X-Patchwork-Id: 1883315 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; secure) header.d=protonmail.com header.i=@protonmail.com header.a=rsa-sha256 header.s=protonmail3 header.b=IJ7yOKpq; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4T6yC038Hyz1yPK for ; Sun, 7 Jan 2024 11:05:48 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 4737F3858CD1 for ; Sun, 7 Jan 2024 00:05:46 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-40134.protonmail.ch (mail-40134.protonmail.ch [185.70.40.134]) by sourceware.org (Postfix) with ESMTPS id DFD7E3858C42 for ; Sun, 7 Jan 2024 00:03:38 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org DFD7E3858C42 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=protonmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=protonmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org DFD7E3858C42 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=185.70.40.134 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1704585829; cv=none; b=ePqDtWN5QfRIQ5JW1YuSRbycLvhYf80OwmtoLQ8/3Ynsj5AvGKHq7Kpfp/SgZQrV2v1erOSH+K6OaWUc+a29euiurhFif/5cyb71okkWF6ES+AB0TQUeWKHgby8ykZcknNWiG9S2r/f4s6muubJghGpSGnGQ0avTDFHBtJEUd5k= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1704585829; c=relaxed/simple; bh=oMwNubOEiw7a/aq/sudLZ11Q+SAqCI3/IwB+ln5I/GI=; h=DKIM-Signature:Date:To:From:Subject:Message-ID:MIME-Version; b=Fp8sXAqdffPqpe5t0oD0IBcUb+UMjHzIEalw+XpG9HkbqIE9xxDIJuTnbFj9qP1t57rZJCdoBRW19Lu7CW1IZUY0GbjWXcXlqMUzR1h1rmv3Dnr6WrvuS5LGcclrkvTCrDToF29+KcMb1fkIhbV+0J+44ihpu7oqRlOUVAhl1IY= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com; s=protonmail3; t=1704585816; x=1704845016; bh=oMwNubOEiw7a/aq/sudLZ11Q+SAqCI3/IwB+ln5I/GI=; h=Date:To:From:Cc:Subject:Message-ID:Feedback-ID:From:To:Cc:Date: Subject:Reply-To:Feedback-ID:Message-ID:BIMI-Selector; b=IJ7yOKpqU+MIVhncwjkb/7suBIpUVYVQukc812NVgiEVAJLepEPXXATsohS+49HA9 dVX+usWwFfRehqjJ9gPUswfgzQLL5/TZxGI8hMHFaVIcJaCB/QoRpvOkhJt0ygYt0s RO2TSKw8V3ZdcdNAJ16ldJTgz3EVVh1g6znCdNHjisiwrzFZlHN2V8RKYey6DwBmAM YCFYQ4OntEGjDt+KQI/4emlmvKu6PCpVyiGN94fFzK55W3jzd7IIAgqysWfB4J1ntG /onIWy1hlmHf7Yk6LyN+W0Xs/bCNwsrh8x9c4JpcLPoy1Kv14N+HltW1PCsTwRNo7M +lt3F3yNCea0A== Date: Sun, 07 Jan 2024 00:03:19 +0000 To: waffl3x From: waffl3x Cc: Jason Merrill , "gcc-patches@gcc.gnu.org" Subject: [PATCH v8 3/4] c++: P0847R7 (deducing this) - diagnostics. [PR102609] Message-ID: Feedback-ID: 14591686:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-8.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE, URIBL_BLACK 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: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Bootstrapped and tested on x86_64-linux with no regressions. From 32a713d9826a042b260e84dcfbfd31c619a122fb Mon Sep 17 00:00:00 2001 From: Waffl3x Date: Fri, 5 Jan 2024 14:34:34 -0700 Subject: [PATCH 3/4] C++23 P0847R7 (deducing this) - diagnostics. [PR102609] Diagnostics for xobj member functions. Also includes some diagnostics for xobj lambdas which are not implemented here. CWG2554 is also implemented here, we explicitly error when an xobj member function overrides a virtual function. PR c++/102609 gcc/c-family/ChangeLog: PR c++/102609 C++23 P0847R7 (deducing this) - diagnostics. * c-cppbuiltin.cc (c_cpp_builtins): Define __cpp_explicit_this_parameter=202110L feature test macro. gcc/cp/ChangeLog: PR c++/102609 C++23 P0847R7 (deducing this) - diagnostics. * class.cc (resolve_address_of_overloaded_function): Diagnostics. * cp-tree.h (TFF_XOBJ_FUNC): Define. * decl.cc (grokfndecl): Diagnostics. (grokdeclarator): Diagnostics. * error.cc (dump_aggr_type): Pass TFF_XOBJ_FUNC. (dump_lambda_function): Formatting for xobj lambda. (dump_function_decl): Pass TFF_XOBJ_FUNC. (dump_parameters): Formatting for xobj member functions. (function_category): Formatting for xobj member functions. * parser.cc (cp_parser_decl_specifier_seq): Diagnostics. (cp_parser_parameter_declaration): Diagnostics. * search.cc (look_for_overrides_here): Make xobj member functions override. (look_for_overrides_r): Reject an overriding xobj member function and diagnose it. * semantics.cc (finish_this_expr): Diagnostics. * typeck.cc (cp_build_addr_expr_1): Diagnostics. gcc/testsuite/ChangeLog: PR c++/102609 C++23 P0847R7 (deducing this) - diagnostics. * g++.dg/cpp23/feat-cxx2b.C: Test existance and value of __cpp_explicit_this_parameter feature test macro. * g++.dg/cpp26/feat-cxx26.C: Likewise. * g++.dg/cpp23/explicit-obj-cxx-dialect-A.C: New test. * g++.dg/cpp23/explicit-obj-cxx-dialect-B.C: New test. * g++.dg/cpp23/explicit-obj-cxx-dialect-C.C: New test. * g++.dg/cpp23/explicit-obj-cxx-dialect-D.C: New test. * g++.dg/cpp23/explicit-obj-cxx-dialect-E.C: New test. * g++.dg/cpp23/explicit-obj-diagnostics1.C: New test. * g++.dg/cpp23/explicit-obj-diagnostics2.C: New test. * g++.dg/cpp23/explicit-obj-diagnostics3.C: New test. * g++.dg/cpp23/explicit-obj-diagnostics4.C: New test. * g++.dg/cpp23/explicit-obj-diagnostics5.C: New test. * g++.dg/cpp23/explicit-obj-diagnostics6.C: New test. * g++.dg/cpp23/explicit-obj-diagnostics7.C: New test. Signed-off-by: Waffl3x --- gcc/c-family/c-cppbuiltin.cc | 1 + gcc/cp/class.cc | 55 ++++- gcc/cp/cp-tree.h | 5 +- gcc/cp/decl.cc | 138 ++++++++++-- gcc/cp/error.cc | 24 +- gcc/cp/parser.cc | 38 +++- gcc/cp/search.cc | 14 +- gcc/cp/semantics.cc | 25 ++- gcc/cp/typeck.cc | 45 +++- .../g++.dg/cpp23/explicit-obj-cxx-dialect-A.C | 7 + .../g++.dg/cpp23/explicit-obj-cxx-dialect-B.C | 7 + .../g++.dg/cpp23/explicit-obj-cxx-dialect-C.C | 9 + .../g++.dg/cpp23/explicit-obj-cxx-dialect-D.C | 8 + .../g++.dg/cpp23/explicit-obj-cxx-dialect-E.C | 8 + .../g++.dg/cpp23/explicit-obj-diagnostics1.C | 139 ++++++++++++ .../g++.dg/cpp23/explicit-obj-diagnostics2.C | 26 +++ .../g++.dg/cpp23/explicit-obj-diagnostics3.C | 20 ++ .../g++.dg/cpp23/explicit-obj-diagnostics4.C | 16 ++ .../g++.dg/cpp23/explicit-obj-diagnostics5.C | 23 ++ .../g++.dg/cpp23/explicit-obj-diagnostics6.C | 206 ++++++++++++++++++ .../g++.dg/cpp23/explicit-obj-diagnostics7.C | 95 ++++++++ gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C | 6 + gcc/testsuite/g++.dg/cpp26/feat-cxx26.C | 6 + 23 files changed, 871 insertions(+), 50 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-A.C create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-B.C create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-C.C create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-D.C create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-E.C create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics1.C create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics2.C create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics3.C create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics4.C create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics5.C create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics6.C create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics7.C diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc index 2d1249f29ed..73c14f6d570 100644 --- a/gcc/c-family/c-cppbuiltin.cc +++ b/gcc/c-family/c-cppbuiltin.cc @@ -1082,6 +1082,7 @@ c_cpp_builtins (cpp_reader *pfile) cpp_define (pfile, "__cpp_named_character_escapes=202207L"); cpp_define (pfile, "__cpp_static_call_operator=202207L"); cpp_define (pfile, "__cpp_implicit_move=202207L"); + cpp_define (pfile, "__cpp_explicit_this_parameter=202110L"); } if (cxx_dialect > cxx23) { diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc index 4b37e1176cd..7322f10b8b1 100644 --- a/gcc/cp/class.cc +++ b/gcc/cp/class.cc @@ -8968,20 +8968,51 @@ resolve_address_of_overloaded_function (tree target_type, fn = TREE_PURPOSE (matches); if (DECL_OBJECT_MEMBER_FUNCTION_P (fn) - && !(complain & tf_ptrmem_ok) && !flag_ms_extensions) - { - static int explained; - - if (!(complain & tf_error)) + && !(complain & tf_ptrmem_ok)) + { + /* Previously we allowed this behavior for iobj member functions when the + -fms-extensions flag is passed as MSVC allows this as a language + extension. MSVC also allows this for xobj member functions, but the + documentation for -fms-extensions states it's purpose is to support + the use of microsoft headers. Until otherwise demonstrated, we should + assume xobj member functions are not used in this manner in microsoft + headers and indiscriminately forbid the incorrect syntax instead of + supporting it for non-legacy uses. This should hopefully encourage + conformance going forward. + This comment is referred to in typeck.cc:cp_build_addr_expr_1. */ + if (DECL_IOBJ_MEMBER_FUNCTION_P (fn) && flag_ms_extensions) + /* Early escape. */; + else if (!(complain & tf_error)) return error_mark_node; - - auto_diagnostic_group d; - if (permerror (input_location, "assuming pointer to member %qD", fn) - && !explained) + else if (DECL_XOBJ_MEMBER_FUNCTION_P (fn)) + { + auto_diagnostic_group d; + /* Should match the error in typeck.cc:cp_build_addr_expr_1. + We seem to lack the details here to match that diagnostic exactly, + perhaps this could be fixed in the future? See PR113075 bug 2. */ + error_at (input_location, + "ISO C++ forbids taking the address of an unqualified" + " or parenthesized non-static member function to form" + " a pointer to explicit object member function."); + /* This is incorrect, see PR113075 bug 3. */ + inform (input_location, + "a pointer to explicit object member function can only be " + "formed with %<&%E%>", fn); + } + else { - inform (input_location, "(a pointer to member can only be " - "formed with %<&%E%>)", fn); - explained = 1; + static int explained; + gcc_assert (DECL_IOBJ_MEMBER_FUNCTION_P (fn) && !flag_ms_extensions); + /* Is there a reason this error message doesn't match the one in + typeck.cc:cp_build_addr_expr_1? */ + auto_diagnostic_group d; + if (permerror (input_location, "assuming pointer to member %qD", fn) + && !explained) + { + inform (input_location, "(a pointer to member can only be " + "formed with %<&%E%>)", fn); + explained = 1; + } } } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index bdc4d7e3349..8f1e0df6f06 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6181,7 +6181,9 @@ enum auto_deduction_context identical to their defaults. TFF_NO_TEMPLATE_BINDINGS: do not print information about the template arguments for a function template specialization. - TFF_POINTER: we are printing a pointer type. */ + TFF_POINTER: we are printing a pointer type. + TFF_XOBJ_FUNC: we are printing an explicit object member function's + parameters. */ #define TFF_PLAIN_IDENTIFIER (0) #define TFF_SCOPE (1) @@ -6199,6 +6201,7 @@ enum auto_deduction_context #define TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS (1 << 12) #define TFF_NO_TEMPLATE_BINDINGS (1 << 13) #define TFF_POINTER (1 << 14) +#define TFF_XOBJ_FUNC (1 << 15) /* These constants can be used as bit flags to control strip_typedefs. diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 7b792ebc5c1..91d4cfa01f8 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -10676,24 +10676,30 @@ grokfndecl (tree ctype, TREE_TYPE (decl) = apply_memfn_quals (TREE_TYPE (decl), TYPE_UNQUALIFIED, REF_QUAL_NONE); - + auto_diagnostic_group d; if (quals) - { - error (ctype + error (!ctype + ? G_("non-member function %qD cannot have cv-qualifier") + : !xobj_func_p ? G_("static member function %qD cannot have cv-qualifier") - : G_("non-member function %qD cannot have cv-qualifier"), - decl); - quals = TYPE_UNQUALIFIED; - } - + : G_("explicit object member function " + "%qD cannot have cv-qualifier"), + decl); if (rqual) - { - error (ctype + error (!ctype + ? G_("non-member function %qD cannot have ref-qualifier") + : !xobj_func_p ? G_("static member function %qD cannot have ref-qualifier") - : G_("non-member function %qD cannot have ref-qualifier"), + : G_("explicit object member function " + "%qD cannot have ref-qualifier"), decl); - rqual = REF_QUAL_NONE; - } + + if (xobj_func_p && (quals || rqual)) + inform (DECL_SOURCE_LOCATION (DECL_ARGUMENTS (decl)), + "explicit object parameter declared here"); + quals = TYPE_UNQUALIFIED; + rqual = REF_QUAL_NONE; + } if (deduction_guide_p (decl)) @@ -13188,17 +13194,85 @@ grokdeclarator (const cp_declarator *declarator, /* There is no need to iterate over the list, only the first parm can be a valid xobj parm. */ if (!parm_list || TREE_PURPOSE (parm_list) != this_identifier) - return false; + return NULL_TREE; /* If we make it here, we are looking at an xobj parm. Non-null 'purpose' usually means the parm has a default argument, we don't want to violate this assumption. */ TREE_PURPOSE (parm_list) = NULL_TREE; - return true; + return TREE_VALUE (parm_list); }; - is_xobj_member_function + tree xobj_parm = find_xobj_parm (declarator->u.function.parameters); + is_xobj_member_function = xobj_parm; + + if (xobj_parm && cxx_dialect < cxx23) + pedwarn (DECL_SOURCE_LOCATION (xobj_parm), OPT_Wc__23_extensions, + "explicit object member function only available " + "with %<-std=c++23%> or %<-std=gnu++23%>"); + + if (xobj_parm && decl_context == TYPENAME) + { + /* We inform in every case, just differently depending on what + case it is. */ + auto_diagnostic_group d; + bool ptr_type = true; + /* If declarator->kind is cdk_function and we are at the end of + the declarator chain, we are looking at a function type. */ + if (!declarator->declarator) + { + error_at (DECL_SOURCE_LOCATION (xobj_parm), + "a function type cannot " + "have an explicit object parameter"); + ptr_type = false; + } + else if (declarator->declarator->kind == cdk_pointer) + error_at (DECL_SOURCE_LOCATION (xobj_parm), + "a pointer to function type cannot " + "have an explicit object parameter"); + else if (declarator->declarator->kind == cdk_ptrmem) + error_at (DECL_SOURCE_LOCATION (xobj_parm), + "a pointer to member function type " + "cannot have an explicit object parameter"); + else + gcc_unreachable (); + + /* The locations being used here are probably not correct. */ + if (ptr_type) + inform (DECL_SOURCE_LOCATION (xobj_parm), + "the type of a pointer to explicit object member " + "function is a regular pointer to function type"); + else + inform (DECL_SOURCE_LOCATION (xobj_parm), + "the type of an explicit object " + "member function is a regular function type"); + /* Ideally we should synthesize the correct syntax + for the user, perhaps this could be added later. */ + } + /* Since a valid xobj parm has its purpose cleared in find_xobj_parm + the first parm node will never erroneously be detected here. */ + { + auto_diagnostic_group d; + bool bad_xobj_parm_encountered = false; + for (tree parm = declarator->u.function.parameters; + parm && parm != void_list_node; + parm = TREE_CHAIN (parm)) + { + if (TREE_PURPOSE (parm) != this_identifier) + continue; + bad_xobj_parm_encountered = true; + gcc_rich_location bad_xobj_parm + (DECL_SOURCE_LOCATION (TREE_VALUE (parm))); + error_at (&bad_xobj_parm, + "Only the first parameter of a member function " + "can be declared as an explicit object parameter"); + } + if (bad_xobj_parm_encountered && xobj_parm) + inform (DECL_SOURCE_LOCATION (xobj_parm), + "Valid explicit object parameter declared here"); + } + if (reqs) error_at (location_of (reqs), "requires-clause on return type"); reqs = declarator->u.function.requires_clause; @@ -13486,6 +13560,38 @@ grokdeclarator (const cp_declarator *declarator, explicitp = 2; } + if (xobj_parm) + { + if (!ctype + && decl_context == NORMAL + && (in_namespace + || !declarator->declarator->u.id.qualifying_scope)) + error_at (DECL_SOURCE_LOCATION (xobj_parm), + "a non-member function cannot have " + "an explicit object parameter"); + else + { + if (virtualp) + { + auto_diagnostic_group d; + error_at (declspecs->locations[ds_virtual], + "an explicit object member function cannot " + "be %"); + inform (DECL_SOURCE_LOCATION (xobj_parm), + "explicit object parameter declared here"); + virtualp = false; + } + if (staticp >= 2) + { + auto_diagnostic_group d; + error_at (declspecs->locations[ds_storage_class], + "an explicit object member function cannot " + "be %"); + inform (DECL_SOURCE_LOCATION (xobj_parm), + "explicit object parameter declared here"); + } + } + } tree pushed_scope = NULL_TREE; if (funcdecl_p && decl_context != FIELD diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index 626f9cab9bd..27282ccae4a 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -840,10 +840,14 @@ dump_aggr_type (cxx_pretty_printer *pp, tree t, int flags) { /* A lambda's "type" is essentially its signature. */ pp_string (pp, M_("padding = pp_before; pp_c_ws_string (pp, "static"); @@ -1833,7 +1839,9 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) if (!(flags & TFF_NO_FUNCTION_ARGUMENTS)) { - dump_parameters (pp, parmtypes, flags); + int const parm_flags + = DECL_XOBJ_MEMBER_FUNCTION_P (t) ? TFF_XOBJ_FUNC | flags : flags; + dump_parameters (pp, parmtypes, parm_flags); if (TREE_CODE (fntype) == METHOD_TYPE) { @@ -1912,6 +1920,8 @@ dump_parameters (cxx_pretty_printer *pp, tree parmtypes, int flags) for (first = 1; parmtypes != void_list_node; parmtypes = TREE_CHAIN (parmtypes)) { + if (first && flags & TFF_XOBJ_FUNC) + pp_string (pp, "this "); if (!first) pp_separate_with_comma (pp); first = 0; @@ -3687,6 +3697,8 @@ function_category (tree fn) return _("In destructor %qD"); else if (LAMBDA_FUNCTION_P (fn)) return _("In lambda function"); + else if (DECL_XOBJ_MEMBER_FUNCTION_P (fn)) + return _("In explicit object member function %qD"); else return _("In member function %qD"); } diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 3f0a31b7407..f3b228d3251 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -16073,6 +16073,8 @@ cp_parser_decl_specifier_seq (cp_parser* parser, /* Assume no class or enumeration type is declared. */ *declares_class_or_enum = 0; + /* Keep a token that additionally will be used for diagnostics. */ + cp_token *first_specifier = NULL; /* Keep reading specifiers until there are no more to read. */ while (true) { @@ -16145,12 +16147,32 @@ cp_parser_decl_specifier_seq (cp_parser* parser, decl_specs->locations[ds_attribute] = token->location; continue; } + /* We know by this point that the token is not part of an attribute. */ + if (!first_specifier) + first_specifier = token; /* Special case for "this" specifier, indicating a parm is an xobj parm. The "this" specifier must be the first specifier in the declaration, after any attributes. */ if (token->keyword == RID_THIS) { cp_lexer_consume_token (parser->lexer); + if (token != first_specifier) + { + /* Don't emit diagnostics if we have already seen "this", + leave it for set_and_check_decl_spec_loc. */ + if (decl_specs->locations[ds_this] == 0) + { + auto_diagnostic_group d; + gcc_rich_location richloc (token->location); + /* Works, need to add tests for it though. */ + richloc.add_fixit_remove (); + richloc.add_fixit_insert_before (first_specifier->location, + "this "); + error_at (&richloc, + "% must be the first specifier " + "in a parameter declaration"); + } + } set_and_check_decl_spec_loc (decl_specs, ds_this, token); continue; } @@ -25542,12 +25564,14 @@ cp_parser_parameter_declaration (cp_parser *parser, /* The restriction on defining new types applies only to the type of the parameter, not to the default argument. */ parser->type_definition_forbidden_message = saved_message; - + cp_token *eq_token = NULL; /* If the next token is `=', then process a default argument. */ if (cp_lexer_next_token_is (parser->lexer, CPP_EQ)) { tree type = decl_specifiers.type; token = cp_lexer_peek_token (parser->lexer); + /* Used for diagnostics with an xobj parameter. */ + eq_token = token; if (declarator) declarator->init_loc = token->location; /* If we are defining a class, then the tokens that make up the @@ -25618,6 +25642,18 @@ cp_parser_parameter_declaration (cp_parser *parser, if (decl_spec_seq_has_spec_p (&decl_specifiers, ds_this)) { + if (default_argument) + { + /* If there is a default_argument, eq_token should always be set. */ + gcc_assert (eq_token); + location_t param_with_init_loc + = make_location (eq_token->location, + decl_spec_token_start->location, + input_location); + error_at (param_with_init_loc, + "an explicit object parameter " + "may not have a default argument"); + } /* Xobj parameters can not have default arguments, thus we can reuse the default argument field to flag the param as such. */ default_argument = this_identifier; diff --git a/gcc/cp/search.cc b/gcc/cp/search.cc index 3473d66b88c..d2ef93826e0 100644 --- a/gcc/cp/search.cc +++ b/gcc/cp/search.cc @@ -2224,10 +2224,13 @@ look_for_overrides_here (tree type, tree fndecl) /* Not a virtual. */; else if (DECL_CONTEXT (fn) != type) /* Introduced with a using declaration. */; - else if (DECL_STATIC_FUNCTION_P (fndecl)) + else if (DECL_STATIC_FUNCTION_P (fndecl) + || DECL_XOBJ_MEMBER_FUNCTION_P (fndecl)) { tree btypes = TYPE_ARG_TYPES (TREE_TYPE (fn)); tree dtypes = TYPE_ARG_TYPES (TREE_TYPE (fndecl)); + dtypes = DECL_XOBJ_MEMBER_FUNCTION_P (fndecl) ? TREE_CHAIN (dtypes) + : dtypes; if (compparms (TREE_CHAIN (btypes), dtypes)) return fn; } @@ -2255,6 +2258,15 @@ look_for_overrides_r (tree type, tree fndecl) error ("%q+#D cannot be declared", fndecl); error (" since %q+#D declared in base class", fn); } + else if (DECL_XOBJ_MEMBER_FUNCTION_P (fndecl)) + { + auto_diagnostic_group d; + error_at (DECL_SOURCE_LOCATION (fndecl), + "explicit object member function " + "overrides virtual function"); + inform (DECL_SOURCE_LOCATION (fn), + "virtual function declared here"); + } else { /* It's definitely virtual, even if not explicitly set. */ diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 3bc426fa130..c0c97600483 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -3091,7 +3091,30 @@ finish_this_expr (void) return rvalue (result); tree fn = current_nonlambda_function (); - if (fn && DECL_STATIC_FUNCTION_P (fn)) + if (fn && DECL_XOBJ_MEMBER_FUNCTION_P (fn)) + { + auto_diagnostic_group d; + error ("% is unavailable for explicit object member " + "functions"); + tree xobj_parm = DECL_ARGUMENTS (fn); + gcc_assert (xobj_parm); + tree parm_name = DECL_NAME (xobj_parm); + + static tree remembered_fn = NULL_TREE; + /* Only output this diagnostic once per function. */ + if (remembered_fn == fn) + /* Early escape. */; + else if (parm_name) + inform (DECL_SOURCE_LOCATION (xobj_parm), + "use explicit object parameter %qs instead", + IDENTIFIER_POINTER (parm_name)); + else + inform (DECL_SOURCE_LOCATION (xobj_parm), + "name the explicit object parameter"); + + remembered_fn = fn; + } + else if (fn && DECL_STATIC_FUNCTION_P (fn)) error ("% is unavailable for static member functions"); else if (fn && processing_contract_condition && DECL_CONSTRUCTOR_P (fn)) error ("invalid use of % before it is valid"); diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index ef5df6b404c..59a61c54f19 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -7069,26 +7069,47 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain) tree fn = get_first_fn (TREE_OPERAND (arg, 1)); if (!mark_used (fn, complain) && !(complain & tf_error)) return error_mark_node; - - if (! flag_ms_extensions) + /* Until microsoft headers are known to incorrectly take the address of + unqualified xobj member functions we should not support this + extension. + See comment in class.cc:resolve_address_of_overloaded_function for + the extended reasoning. */ + if (!flag_ms_extensions || DECL_XOBJ_MEMBER_FUNCTION_P (fn)) { + auto_diagnostic_group d; tree name = DECL_NAME (fn); if (!(complain & tf_error)) return error_mark_node; else if (current_class_type && TREE_OPERAND (arg, 0) == current_class_ref) /* An expression like &memfn. */ - permerror (loc, - "ISO C++ forbids taking the address of an unqualified" - " or parenthesized non-static member function to form" - " a pointer to member function. Say %<&%T::%D%>", - base, name); + if (!DECL_XOBJ_MEMBER_FUNCTION_P (fn)) + permerror (loc, + "ISO C++ forbids taking the address of an unqualified" + " or parenthesized non-static member function to form" + " a pointer to member function. Say %<&%T::%D%>", + base, name); + else + error_at (loc, + "ISO C++ forbids taking the address of an unqualified" + " or parenthesized non-static member function to form" + " a pointer to explicit object member function"); else - permerror (loc, - "ISO C++ forbids taking the address of a bound member" - " function to form a pointer to member function." - " Say %<&%T::%D%>", - base, name); + if (!DECL_XOBJ_MEMBER_FUNCTION_P (fn)) + permerror (loc, + "ISO C++ forbids taking the address of a bound member" + " function to form a pointer to member function." + " Say %<&%T::%D%>", + base, name); + else + error_at (loc, + "ISO C++ forbids taking the address of a bound member" + " function to form a pointer to explicit object member" + " function"); + if (DECL_XOBJ_MEMBER_FUNCTION_P (fn)) + inform (loc, + "a pointer to explicit object member function can only be " + "formed with %<&%T::%D%>", base, name); } arg = build_offset_ref (base, fn, /*address_p=*/true, complain); } diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-A.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-A.C new file mode 100644 index 00000000000..5043e91bb28 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-A.C @@ -0,0 +1,7 @@ +// P0847R7 +// { dg-do compile { target c++23 } } + +struct S { + void f(this S); // { dg-bogus {explicit object member function only available with '-std=c\+\+23' or '-std=gnu\+\+23'} } +}; + diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-B.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-B.C new file mode 100644 index 00000000000..fb2a6a0e41b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-B.C @@ -0,0 +1,7 @@ +// P0847R7 +// { dg-do compile { target c++20_down } } + +struct S { + void f(this S); // { dg-error {explicit object member function only available with '-std=c\+\+23' or '-std=gnu\+\+23'} } +}; + diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-C.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-C.C new file mode 100644 index 00000000000..182e294c883 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-C.C @@ -0,0 +1,9 @@ +// P0847R7 +// { dg-do compile { target c++20_down } } +// don't pass in -pedantic-errors +// { dg-options "" } + +struct S { + void f(this S); // { dg-warning {explicit object member function only available with '-std=c\+\+23' or '-std=gnu\+\+23'} } +}; + diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-D.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-D.C new file mode 100644 index 00000000000..49b7ea0df44 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-D.C @@ -0,0 +1,8 @@ +// P0847R7 +// { dg-do compile { target c++20_down } } +// { dg-options "-Wno-c++23-extensions" } + +struct S { + void f(this S); // { dg-bogus {explicit object member function only available with '-std=c\+\+23' or '-std=gnu\+\+23'} } +}; + diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-E.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-E.C new file mode 100644 index 00000000000..411b70c3d9d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-E.C @@ -0,0 +1,8 @@ +// P0847R7 +// { dg-do compile { target c++20_down } } +// { dg-options "-Wno-c++23-extensions -pedantic-errors" } + +struct S { + void f(this S); // { dg-bogus {explicit object member function only available with '-std=c\+\+23' or '-std=gnu\+\+23'} } +}; + diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics1.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics1.C new file mode 100644 index 00000000000..dfac1188fba --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics1.C @@ -0,0 +1,139 @@ +// P0847R7 +// { dg-do compile { target c++23 } } + +// rejection and diagnosis of xobj member functions that have member function qualifiers. + +struct S { + void f_value_0(this S) const; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_value_1(this S) volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_value_2(this S) const volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_value_3(this S) &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + void f_value_4(this S) &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + void f_value_5(this S) const &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_value_6(this S) const &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_value_7(this S) volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_value_8(this S) volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_value_9(this S) const volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_value_A(this S) const volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + + void f_ref_0(this S&) const; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_ref_1(this S&) volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_ref_2(this S&) const volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_ref_3(this S&) &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + void f_ref_4(this S&) &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + void f_ref_5(this S&) const &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_ref_6(this S&) const &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_ref_7(this S&) volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_ref_8(this S&) volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_ref_9(this S&) const volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_ref_A(this S&) const volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + + void f_refref_0(this S&&) const; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_refref_1(this S&&) volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_refref_2(this S&&) const volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_refref_3(this S&&) &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + void f_refref_4(this S&&) &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + void f_refref_5(this S&&) const &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_refref_6(this S&&) const &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_refref_7(this S&&) volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_refref_8(this S&&) volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_refref_9(this S&&) const volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_refref_A(this S&&) const volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + + void f_cref_0(this S const&) const; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_cref_1(this S const&) volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_cref_2(this S const&) const volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_cref_3(this S const&) &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + void f_cref_4(this S const&) &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + void f_cref_5(this S const&) const &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_cref_6(this S const&) const &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_cref_7(this S const&) volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_cref_8(this S const&) volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_cref_9(this S const&) const volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_cref_A(this S const&) const volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + + void f_crefref_0(this S const&&) const; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_crefref_1(this S const&&) volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_crefref_2(this S const&&) const volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_crefref_3(this S const&&) &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + void f_crefref_4(this S const&&) &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + void f_crefref_5(this S const&&) const &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_crefref_6(this S const&&) const &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_crefref_7(this S const&&) volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_crefref_8(this S const&&) volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_crefref_9(this S const&&) const volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_crefref_A(this S const&&) const volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + + void f_vref_0(this S volatile&) const; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_vref_1(this S volatile&) volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_vref_2(this S volatile&) const volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_vref_3(this S volatile&) &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + void f_vref_4(this S volatile&) &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + void f_vref_5(this S volatile&) const &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_vref_6(this S volatile&) const &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_vref_7(this S volatile&) volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_vref_8(this S volatile&) volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_vref_9(this S volatile&) const volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_vref_A(this S volatile&) const volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + + void f_vrefref_0(this S volatile&&) const; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_vrefref_1(this S volatile&&) volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_vrefref_2(this S volatile&&) const volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_vrefref_3(this S volatile&&) &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + void f_vrefref_4(this S volatile&&) &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + void f_vrefref_5(this S volatile&&) const &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_vrefref_6(this S volatile&&) const &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_vrefref_7(this S volatile&&) volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_vrefref_8(this S volatile&&) volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_vrefref_9(this S volatile&&) const volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_vrefref_A(this S volatile&&) const volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + + void f_cvref_0(this S const volatile&) const; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_cvref_1(this S const volatile&) volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_cvref_2(this S const volatile&) const volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_cvref_3(this S const volatile&) &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + void f_cvref_4(this S const volatile&) &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + void f_cvref_5(this S const volatile&) const &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_cvref_6(this S const volatile&) const &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_cvref_7(this S const volatile&) volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_cvref_8(this S const volatile&) volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_cvref_9(this S const volatile&) const volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_cvref_A(this S const volatile&) const volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + + void f_cvrefref_0(this S const volatile&&) const; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_cvrefref_1(this S const volatile&&) volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_cvrefref_2(this S const volatile&&) const volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void f_cvrefref_3(this S const volatile&&) &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + void f_cvrefref_4(this S const volatile&&) &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + void f_cvrefref_5(this S const volatile&&) const &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_cvrefref_6(this S const volatile&&) const &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_cvrefref_7(this S const volatile&&) volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_cvrefref_8(this S const volatile&&) volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_cvrefref_9(this S const volatile&&) const volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void f_cvrefref_A(this S const volatile&&) const volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + + template void d_templ_0(this Self&&) const; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + template void d_templ_1(this Self&&) volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + template void d_templ_2(this Self&&) const volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + template void d_templ_3(this Self&&) &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + template void d_templ_4(this Self&&) &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + template void d_templ_5(this Self&&) const &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + template void d_templ_6(this Self&&) const &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + template void d_templ_7(this Self&&) volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + template void d_templ_8(this Self&&) volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + template void d_templ_9(this Self&&) const volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + template void d_templ_A(this Self&&) const volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + + void d_auto_0(this auto&&) const; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void d_auto_1(this auto&&) volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void d_auto_2(this auto&&) const volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + void d_auto_3(this auto&&) &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + void d_auto_4(this auto&&) &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + void d_auto_5(this auto&&) const &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void d_auto_6(this auto&&) const &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void d_auto_7(this auto&&) volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void d_auto_8(this auto&&) volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void d_auto_9(this auto&&) const volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + void d_auto_A(this auto&&) const volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } +}; + diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics2.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics2.C new file mode 100644 index 00000000000..771200b839e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics2.C @@ -0,0 +1,26 @@ +// P0847R7 +// { dg-do compile { target c++23 } } + +// rejection and diagnosis of incorrect uses of 'this' in declarations and definitions + +using func_type = void(this int); // { dg-line func_type_line } +// { dg-error "a function type cannot have an explicit object parameter" "" { target *-*-* } func_type_line } +// { dg-note "the type of an explicit object member function is a regular function type" "" { target *-*-* } func_type_line } + +using func_ptr_type = void(*)(this int); // { dg-line func_ptr_type_line } +// { dg-error "a pointer to function type cannot have an explicit object parameter" "" { target *-*-* } func_ptr_type_line } +// { dg-note "the type of a pointer to explicit object member function is a regular pointer to function type" "" { target *-*-* } func_ptr_type_line } + +struct S { + static void f(this S) {} // { dg-line static_member_func_line } +}; +// { dg-error "an explicit object member function cannot be 'static'" "" { target *-*-* } static_member_func_line } +// { dg-note "explicit object parameter declared here" "" { target *-*-* } static_member_func_line } + +using mem_func_type = void (S::*)(this S&); // { dg-line mem_func_type_line } +// { dg-error "a pointer to member function type cannot have an explicit object parameter" "" { target *-*-* } mem_func_type_line } +// { dg-note "the type of a pointer to explicit object member function is a regular pointer to function type" "" { target *-*-* } mem_func_type_line } + +void f(this int); // { dg-error "a non-member function cannot have an explicit object parameter" } +void f(this int) {} // { dg-error "a non-member function cannot have an explicit object parameter" } + diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics3.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics3.C new file mode 100644 index 00000000000..ec091d6ca67 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics3.C @@ -0,0 +1,20 @@ +// P0847R7 +// { dg-do compile { target c++23 } } + +// rejection and diagnosis of an xobj parameter declared with a default argument + +struct S { + void f0(this S = {}) {} // { dg-error "an explicit object parameter may not have a default argument" } + void f1(this S = {}); // { dg-error "an explicit object parameter may not have a default argument" } + void f2(this S); + void f10(this S s = {}) {} // { dg-error "an explicit object parameter may not have a default argument" } + void f11(this S s = {}); // { dg-error "an explicit object parameter may not have a default argument" } + void f12(this S s); +}; + +void S::f1(this S) {} +void S::f2(this S = {}) {} // { dg-error "an explicit object parameter may not have a default argument" } + +void S::f11(this S s) {} +void S::f12(this S s = {}) {} // { dg-error "an explicit object parameter may not have a default argument" } + diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics4.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics4.C new file mode 100644 index 00000000000..1744b3f2299 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics4.C @@ -0,0 +1,16 @@ +// P0847R7 +// { dg-do compile { target c++23 } } + +// location diagnostic text when an error is emitted from an xobj member function +// this does not test for specific ill-formed code, just the additional diagnostic message + +// { dg-message "In explicit object member function" "" { target *-*-* } 0 } + +struct S { + void f(this S s) { + // The specific diagnosis issued here does not matter + // we just need to force an error to be emitted + +s; // { dg-error "" } + } +}; + diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics5.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics5.C new file mode 100644 index 00000000000..7ec43f641b5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics5.C @@ -0,0 +1,23 @@ +// P0847R7 +// { dg-do compile { target c++23 } } + +// rejection and diagnosis of invalid uses of 'this' in body of xobj member functions + +// { dg-message "In explicit object member function" "" { target *-*-* } 0 } + +struct S0 { + int _n; + void f(this S0& s) { // { dg-note {use explicit object parameter 's' instead} } + this->_n = 10; // { dg-error "'this' is unavailable for explicit object member functions" } + // suppress unused variable warning + static_cast(s); + } +}; + +struct S1 { + int _n; + void f(this S1&) { // { dg-note "name the explicit object parameter" } + this->_n = 10; // { dg-error "'this' is unavailable for explicit object member functions" } + } +}; + diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics6.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics6.C new file mode 100644 index 00000000000..77ace49b843 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics6.C @@ -0,0 +1,206 @@ +// P0847R7 +// { dg-do compile { target c++23 } } + +// rejection and diagnosis when taking address of an unqualified xobj member function + +// { dg-message "In explicit object member function" "" { target *-*-* } 0 } + +struct S { + void f(this S&) {} + + void g(this S&) {} + void g(this S&, int) {} + + void test0() { + void (*fp)(S&) = &f; // { dg-line line_sf } + // { dg-error {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "" { target *-*-* } line_sf } + // { dg-note {a pointer to explicit object member function can only be formed with '&S::f'} "" { target *-*-* } line_sf } + void (*gp)(S&) = &g; // { dg-line line_sg } + // { dg-error {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "" { target *-*-* } line_sg } + // { dg-note {a pointer to explicit object member function can only be formed with '&S::g'} "" { target *-*-* } line_sg } + } + + void test1(this S& self) { + void (*fp)(S&) = &self.f; // { dg-line s_test1_f } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "" { target *-*-* } s_test1_f } + // { dg-note {a pointer to explicit object member function can only be formed with '&S::f'} "" { target *-*-* } s_test1_f } + void (*gp)(S&) = &self.g; // { dg-line s_test1_g } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } s_test1_g } + // { dg-bogus {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } s_test1_g } + // { dg-note {a pointer to explicit object member function can only be formed with '&S::g'} "" { target *-*-* } s_test1_g } + } +}; + +void test0() +{ + S s{}; + + void (*fp)(S&) = &s.f; // { dg-line s_free_test0_f } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "" { target *-*-* } s_free_test0_f } + // { dg-note {a pointer to explicit object member function can only be formed with '&S::f'} "" { target *-*-* } s_free_test0_f } + void (*gp)(S&) = &s.g; // { dg-line s_free_test0_g } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } s_free_test0_g } + // { dg-bogus {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } s_free_test0_g } + // { dg-note {a pointer to explicit object member function can only be formed with '&S::g'} "" { target *-*-* } s_free_test0_g } +} + +struct D; + +struct B { + void fb(this B&) {} + + void gb(this B&) {} + void gb(this B&, int) {} + + void fd(this D&) {} + + void gd(this D&) {} + void gd(this D&, int) {} +}; + +struct D : B { + void fb2(this B&) {} + + void gb2(this B&) {} + void gb2(this B&, int) {} + + void fd2(this D&) {} + + void gd2(this D&) {} + void gd2(this D&, int) {} + + void test0() { + void (*fbp)(B&) = &fb; // { dg-line d_test0_fb } + // { dg-error {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "" { target *-*-* } d_test0_fb } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::fb'} "" { target *-*-* } d_test0_fb } + void (*gbp)(B&) = &gb; // { dg-line d_test0_gb } + // { dg-error {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "" { target *-*-* } d_test0_gb } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::gb'} "PR113075" { xfail *-*-* } d_test0_gb } + // { dg-bogus {a pointer to explicit object member function can only be formed with '&B::gb'} "PR113075" { xfail *-*-* } d_test0_gb } + + void (*fdp)(D&) = &fd; // { dg-line d_test0_fd } + // { dg-error {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "" { target *-*-* } d_test0_fd } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::fd'} "" { target *-*-* } d_test0_fd } + void (*gdp)(D&) = &gd; // { dg-line d_test0_gd } + // { dg-error {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "" { target *-*-* } d_test0_gd } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::gd'} "PR113075" { xfail *-*-* } d_test0_gd } + // { dg-bogus {a pointer to explicit object member function can only be formed with '&B::gd'} "PR113075" { xfail *-*-* } d_test0_gd } + } + + void test1(this B& self) { + void (*fbp)(B&) = &self.fb; // { dg-line d_test1_fb } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "" { target *-*-* } d_test1_fb } + // { dg-note {a pointer to explicit object member function can only be formed with '&B::fb'} "" { target *-*-* } d_test1_fb } + void (*gbp)(B&) = &self.gb; // { dg-line d_test1_gb } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } d_test1_gb } + // { dg-bogus {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } d_test1_gb } + // { dg-note {a pointer to explicit object member function can only be formed with '&B::gb'} "" { target *-*-* } d_test1_gb } + + void (*fdp)(D&) = &self.fd; // { dg-line d_test1_fd } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "" { target *-*-* } d_test1_fd } + // { dg-note {a pointer to explicit object member function can only be formed with '&B::fd'} "" { target *-*-* } d_test1_fd } + void (*gdp)(D&) = &self.gd; // { dg-line d_test1_gd } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } d_test1_gd } + // { dg-bogus {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } d_test1_gd } + // { dg-note {a pointer to explicit object member function can only be formed with '&B::gd'} "" { target *-*-* } d_test1_gd } + } + + void test2(this D& self) { + void (*fbp)(B&) = &self.fb; // { dg-line d_test2_fb } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "" { target *-*-* } d_test2_fb } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::fb'} "" { target *-*-* } d_test2_fb } + void (*gbp)(B&) = &self.gb; // { dg-line d_test2_gb } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } d_test2_gb } + // { dg-bogus {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } d_test2_gb } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::gb'} "PR113075" { xfail *-*-* } d_test2_gb } + // { dg-bogus {a pointer to explicit object member function can only be formed with '&B::gb'} "PR113075" { xfail *-*-* } d_test2_gb } + + void (*fdp)(D&) = &self.fd; // { dg-line d_test2_fd } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "" { target *-*-* } d_test2_fd } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::fd'} "" { target *-*-* } d_test2_fd } + void (*gdp)(D&) = &self.gd; // { dg-line d_test2_gd } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } d_test2_gd } + // { dg-bogus {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } d_test2_gd } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::gd'} "PR113075" { xfail *-*-* } d_test2_gd } + // { dg-bogus {a pointer to explicit object member function can only be formed with '&B::gd'} "PR113075" { xfail *-*-* } d_test2_gd } + } + + void test3() { + void (*fbp)(B&) = &fb2; // { dg-line d_test3_fb2 } + // { dg-error {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "" { target *-*-* } d_test3_fb2 } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::fb2'} "" { target *-*-* } d_test3_fb2 } + void (*gbp)(B&) = &gb2; // { dg-line d_test3_gb2 } + // { dg-error {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "" { target *-*-* } d_test3_gb2 } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::gb2'} "" { target *-*-* } d_test3_gb2 } + + void (*fdp)(D&) = &fd2; // { dg-line d_test3_fd2 } + // { dg-error {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "" { target *-*-* } d_test3_fd2 } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::fd2'} "" { target *-*-* } d_test3_fd2 } + void (*gdp)(D&) = &gd2; // { dg-line d_test3_gd2 } + // { dg-error {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "" { target *-*-* } d_test3_gd2 } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::gd2'} "" { target *-*-* } d_test3_gd2 } + } + + void test4(this D& self) { + void (*fbp)(B&) = &self.fb2; // { dg-line d_test4_fb2 } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "" { target *-*-* } d_test4_fb2 } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::fb2'} "" { target *-*-* } d_test4_fb2 } + void (*gbp)(B&) = &self.gb2; // { dg-line d_test4_gb2 } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } d_test4_gb2 } + // { dg-bogus {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } d_test4_gb2 } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::gb2'} "" { target *-*-* } d_test4_gb2 } + + void (*fdp)(D&) = &self.fd2; // { dg-line d_test4_fd2 } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "" { target *-*-* } d_test4_fd2 } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::fd2'} "" { target *-*-* } d_test4_fd2 } + void (*gdp)(D&) = &self.gd2; // { dg-line d_test4_gd2 } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } d_test4_gd2 } + // { dg-bogus {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } d_test4_gd2 } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::gd2'} "" { target *-*-* } d_test4_gd2 } + } +}; + +void test1() +{ + D d{}; + + void (*fbp)(B&) = &d.fb; // { dg-line d_free_test1_fb } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "" { target *-*-* } d_free_test1_fb } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::fb'} "" { target *-*-* } d_free_test1_fb } + void (*gbp)(B&) = &d.gb; // { dg-line d_free_test1_gb } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } d_free_test1_gb } + // { dg-bogus {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } d_free_test1_gb } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::gb'} "PR113075" { xfail *-*-* } d_free_test1_gb } + // { dg-bogus {a pointer to explicit object member function can only be formed with '&B::gb'} "PR113075" { xfail *-*-* } d_free_test1_gb } + + void (*fdp)(D&) = &d.fd; // { dg-line d_free_test1_fd } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "" { target *-*-* } d_free_test1_fd } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::fd'} "" { target *-*-* } d_free_test1_fd } + void (*gdp)(D&) = &d.gd; // { dg-line d_free_test1_gd } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } d_free_test1_gd } + // { dg-bogus {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } d_free_test1_gd } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::gd'} "PR113075" { xfail *-*-* } d_free_test1_gd } + // { dg-bogus {a pointer to explicit object member function can only be formed with '&B::gd'} "PR113075" { xfail *-*-* } d_free_test1_gd } +} + +void test2() +{ + D d{}; + + void (*fbp)(B&) = &d.fb2; // { dg-line d_free_test2_fb2 } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "" { target *-*-* } d_free_test2_fb2 } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::fb2'} "" { target *-*-* } d_free_test2_fb2 } + void (*gbp)(B&) = &d.gb2; // { dg-line d_free_test2_gb2 } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } d_free_test2_gb2 } + // { dg-bogus {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } d_free_test2_gb2 } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::gb2'} "" { target *-*-* } d_free_test2_gb2 } + + void (*fdp)(D&) = &d.fd2; // { dg-line d_free_test2_fd2 } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "" { target *-*-* } d_free_test2_fd2 } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::fd2'} "" { target *-*-* } d_free_test2_fd2 } + void (*gdp)(D&) = &d.gd2; // { dg-line d_free_test2_gd2 } + // { dg-error {ISO C\+\+ forbids taking the address of a bound member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } d_free_test2_gd2 } + // { dg-bogus {ISO C\+\+ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to explicit object member function} "PR113075" { xfail *-*-* } d_free_test2_gd2 } + // { dg-note {a pointer to explicit object member function can only be formed with '&D::gd2'} "" { target *-*-* } d_free_test2_gd2 } +} + diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics7.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics7.C new file mode 100644 index 00000000000..023cdc2e0fe --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics7.C @@ -0,0 +1,95 @@ +// P0847R7 +// { dg-do compile { target c++23 } } + +// diagnose xobj member functions that override +// or are declared as virtual, override, or final + +struct B { + virtual void f0() {} // { dg-note {virtual function declared here} } + virtual void f1() {} // { dg-note {virtual function declared here} } + virtual void f2() {} // { dg-note {virtual function declared here} } + virtual void f3() {} // { dg-note {virtual function declared here} } + virtual void f4() {} // { dg-note {virtual function declared here} } + virtual void f5() {} // { dg-note {virtual function declared here} } + virtual void f6() {} // { dg-note {virtual function declared here} } + virtual void f7() {} // { dg-note {virtual function declared here} } + virtual ~B() {} +}; + +struct S : B { + virtual void f0(this S&) {} // { dg-line line_f0 } + virtual void f1(this S&) override {} // { dg-line line_f1 } + virtual void f2(this S&) final {} // { dg-line line_f2 } + virtual void f3(this S&) override final {} // { dg-line line_f3 } + void f4(this S&) {} // { dg-line line_f4 } + void f5(this S&) override {} // { dg-line line_f5 } + void f6(this S&) final {} // { dg-line line_f6 } + void f7(this S&) override final {} // { dg-line line_f7 } +}; + +// { dg-error {an explicit object member function cannot be 'virtual'} "" { target *-*-* } line_f0 } +// { dg-error {an explicit object member function cannot be 'virtual'} "" { target *-*-* } line_f1 } +// { dg-error {an explicit object member function cannot be 'virtual'} "" { target *-*-* } line_f2 } +// { dg-error {an explicit object member function cannot be 'virtual'} "" { target *-*-* } line_f3 } + +// { dg-error {explicit object member function overrides virtual function} "" { target *-*-* } line_f0 } +// { dg-error {explicit object member function overrides virtual function} "" { target *-*-* } line_f1 } +// { dg-error {explicit object member function overrides virtual function} "" { target *-*-* } line_f2 } +// { dg-error {explicit object member function overrides virtual function} "" { target *-*-* } line_f3 } +// { dg-error {explicit object member function overrides virtual function} "" { target *-*-* } line_f4 } +// { dg-error {explicit object member function overrides virtual function} "" { target *-*-* } line_f5 } +// { dg-error {explicit object member function overrides virtual function} "" { target *-*-* } line_f6 } +// { dg-error {explicit object member function overrides virtual function} "" { target *-*-* } line_f7 } + +// these should be suppressed, the wording conflicts with the error +// the issue is not that they don't override, it's that they do override, and that isn't allowed +// { dg-bogus "marked 'override', but does not override" "" { xfail *-*-* } line_f1 } +// { dg-bogus "marked 'final', but is not virtual" "" { xfail *-*-* } line_f2 } +// { dg-bogus "marked '(override|final)'" "" { xfail *-*-* } line_f3 } + +// { dg-bogus "marked 'override', but does not override" "" { xfail *-*-* } line_f5 } +// { dg-bogus "marked 'final', but is not virtual" "" { xfail *-*-* } line_f6 } +// { dg-bogus "marked '(override|final)'" "" { xfail *-*-* } line_f7 } + +// { dg-note "explicit object parameter declared here" "" { target *-*-* } line_f0 } +// { dg-note "explicit object parameter declared here" "" { target *-*-* } line_f1 } +// { dg-note "explicit object parameter declared here" "" { target *-*-* } line_f2 } +// { dg-note "explicit object parameter declared here" "" { target *-*-* } line_f3 } +// { dg-note "explicit object parameter declared here" "" { xfail *-*-* } line_f4 } +// { dg-note "explicit object parameter declared here" "" { xfail *-*-* } line_f5 } +// { dg-note "explicit object parameter declared here" "" { xfail *-*-* } line_f6 } +// { dg-note "explicit object parameter declared here" "" { xfail *-*-* } line_f7 } + +struct S1 { + virtual void f0(this S&) {} // { dg-line line_S1_f0 } + virtual void f1(this S&) override {} // { dg-line line_S1_f1 } + virtual void f2(this S&) final {} // { dg-line line_S1_f2 } + virtual void f3(this S&) override final {} // { dg-line line_S1_f3 } + void f4(this S&) {} + void f5(this S&) override {} // { dg-line line_S1_f5 } + void f6(this S&) final {} // { dg-line line_S1_f6 } + void f7(this S&) override final {} // { dg-line line_S1_f7 } +}; + +// { dg-error "an explicit object member function cannot be 'virtual'" "" { target *-*-* } line_S1_f0 } +// { dg-error "an explicit object member function cannot be 'virtual'" "" { target *-*-* } line_S1_f1 } +// { dg-error "an explicit object member function cannot be 'virtual'" "" { target *-*-* } line_S1_f2 } +// { dg-error "an explicit object member function cannot be 'virtual'" "" { target *-*-* } line_S1_f3 } + +// { dg-note "explicit object parameter declared here" "" { target *-*-* } line_S1_f0 } +// { dg-note "explicit object parameter declared here" "" { target *-*-* } line_S1_f1 } +// { dg-note "explicit object parameter declared here" "" { target *-*-* } line_S1_f2 } +// { dg-note "explicit object parameter declared here" "" { target *-*-* } line_S1_f3 } + +// I think I want these suppressed, but theres a decent argument that they should stay +// theres arguably no reason the error about virtual should suppress these +// { dg-bogus "marked 'override', but does not override" "" { xfail *-*-* } line_S1_f1 } +// { dg-bogus "marked 'final', but is not virtual" "" { xfail *-*-* } line_S1_f2 } +// { dg-bogus "marked '(override|final)'" "" { xfail *-*-* } line_S1_f3 } + +// I don't want to suppress these, there is nothing that could possibly be overridden +// even if the xobj param was removed +// { dg-error "marked 'override', but does not override" "" { target *-*-* } line_S1_f5 } +// { dg-error "marked 'final', but is not virtual" "" { target *-*-* } line_S1_f6 } +// { dg-error "marked '(override|final)'" "" { target *-*-* } line_S1_f7 } + diff --git a/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C b/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C index 2b21bd1bc0d..d81aab75638 100644 --- a/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C +++ b/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C @@ -578,6 +578,12 @@ # error "__cpp_implicit_move != 202207" #endif +#ifndef __cpp_explicit_this_parameter +# error "__cpp_explicit_this_parameter" +#elif __cpp_explicit_this_parameter != 202110 +# error "__cpp_explicit_this_parameter != 202110" +#endif + #ifndef __cpp_auto_cast # error "__cpp_auto_cast" #elif __cpp_auto_cast != 202110 diff --git a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C index 4507ea07d1c..d19fca49995 100644 --- a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C +++ b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C @@ -578,6 +578,12 @@ # error "__cpp_implicit_move != 202207" #endif +#ifndef __cpp_explicit_this_parameter +# error "__cpp_explicit_this_parameter" +#elif __cpp_explicit_this_parameter != 202110 +# error "__cpp_explicit_this_parameter != 202110" +#endif + #ifndef __cpp_auto_cast # error "__cpp_auto_cast" #elif __cpp_auto_cast != 202110 -- 2.43.0