diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc index 9553b1382afe4b08a8f74cf9b8c86d9073447b7e..38f320329829d6f7777ee418ed7107cb83137f01 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 6f924d51d27392b13d7ad0894b54665ae7a84a55..f3cfa9f0f23acb875654039e038d795ae55685ba 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 ce5771692fba603f39ebb27a93e3a46c44b6a160..dbc71776be3c71fe3366f9911deef85769dda6f7 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 16ccdb37aa64276aa0141b390d9ba14f483e5a44..7f267055c29ff81e5995a755835607434762030c 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -10805,24 +10805,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)) @@ -13317,17 +13323,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; @@ -13615,6 +13689,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 %<virtual%>"); + 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 %<static%>"); + 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 a384f6273980fb38f8a29e932ad7d7a10a408acc..52e24fb086ca52e86737eae5a59bed23a70bf030 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_("<lambda")); - if (lambda_function (t)) - dump_parameters (pp, - FUNCTION_FIRST_USER_PARMTYPE (lambda_function (t)), - flags); + tree const fn = lambda_function (t); + if (fn) + { + int const parm_flags + = DECL_XOBJ_MEMBER_FUNCTION_P (fn) ? TFF_XOBJ_FUNC | flags + : flags; + dump_parameters (pp, FUNCTION_FIRST_USER_PARMTYPE (fn), parm_flags); + } pp_greater (pp); } else if (!decl || IDENTIFIER_ANON_P (DECL_NAME (decl))) @@ -1712,7 +1716,9 @@ dump_lambda_function (cxx_pretty_printer *pp, { /* A lambda's signature is essentially its "type". */ dump_type (pp, DECL_CONTEXT (fn), flags); - if (TREE_CODE (TREE_TYPE (fn)) == FUNCTION_TYPE) + if (DECL_XOBJ_MEMBER_FUNCTION_P (fn)) + /* Early escape. */; + else if (TREE_CODE (TREE_TYPE (fn)) == FUNCTION_TYPE) { pp->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; @@ -3696,6 +3706,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 046c48d5552b3619b29865aa2750df1f0a1b42b0..b0c08cf8ad0245a74c0747d7b9c2a7ec4dd26784 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -16188,6 +16188,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) { @@ -16260,12 +16262,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, + "%<this%> must be the first specifier " + "in a parameter declaration"); + } + } set_and_check_decl_spec_loc (decl_specs, ds_this, token); continue; } @@ -25657,12 +25679,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 @@ -25733,6 +25757,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 f7be4a1c9b2f840d1607658bf53f39bc1e2a10aa..dc76714351f9e33c40318d4d1acf2ab56a289b0b 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 8ff69622bd4f09c1a8eef01d710cadb236ad686d..3253ceeff8008b37afc38272eb6b960a7b56eeef 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -3169,7 +3169,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 ("%<this%> 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 ("%<this%> is unavailable for static member functions"); else if (fn && processing_contract_condition && DECL_CONSTRUCTOR_P (fn)) error ("invalid use of %<this%> before it is valid"); diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index 7e66913ae39d115bfb9390fc90d5f03eb3d7590d..a15eda3f5f8c4f627c1bc92e4155b40372c5e1fc 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -7129,26 +7129,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 0000000000000000000000000000000000000000..5043e91bb28d046c4050dffeceadfe75a278a6a9 --- /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 0000000000000000000000000000000000000000..fb2a6a0e41b94947ebb861f51a862c60bb7aeb05 --- /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 0000000000000000000000000000000000000000..182e294c883319b25e1bd4499170d75a1f56b02a --- /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 0000000000000000000000000000000000000000..49b7ea0df44a5ec717673b993cc2758fe7548970 --- /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 0000000000000000000000000000000000000000..411b70c3d9d15b481089b64984430d29b18bb91e --- /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 0000000000000000000000000000000000000000..dfac1188fbaa46cb3c4dc8035f727d7e89b5fb9b --- /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<typename Self> void d_templ_0(this Self&&) const; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + template<typename Self> void d_templ_1(this Self&&) volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + template<typename Self> void d_templ_2(this Self&&) const volatile; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have cv-qualifier" } + template<typename Self> void d_templ_3(this Self&&) &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + template<typename Self> void d_templ_4(this Self&&) &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have ref-qualifier" } + template<typename Self> void d_templ_5(this Self&&) const &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + template<typename Self> void d_templ_6(this Self&&) const &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + template<typename Self> void d_templ_7(this Self&&) volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + template<typename Self> void d_templ_8(this Self&&) volatile &&; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + template<typename Self> void d_templ_9(this Self&&) const volatile &; // { dg-error "explicit object member function '(?!static)\[^\n\r\]+' cannot have (ref|cv)-qualifier" } + template<typename Self> 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 0000000000000000000000000000000000000000..771200b839e3cd4f101a537983efe02183d9b08f --- /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 0000000000000000000000000000000000000000..ec091d6ca6743ddab2a96201dc1ae7bda1d453cd --- /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 0000000000000000000000000000000000000000..1744b3f2299623dc0fb5013117deb3cd9d1ced5a --- /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 0000000000000000000000000000000000000000..7ec43f641b54d0116c3c37ae530ae422e59eb654 --- /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<void>(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 0000000000000000000000000000000000000000..77ace49b843b434b2be107fca040620a86824c84 --- /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 0000000000000000000000000000000000000000..023cdc2e0fea218476be5622b1fe4779b95b420f --- /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 2b21bd1bc0d635332aae44a81a57483afbde1bd3..d81aab756382d8367a85fda7d32136c6868c21d8 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 4507ea07d1ca0a6238439416e90783969aa82de4..d19fca49995a656eac50deb55180aad0269ffffc 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