From c8e8155a635fab7f326d0ad32326da352d7c323e Mon Sep 17 00:00:00 2001 From: waffl3x Date: Sun, 5 Nov 2023 05:17:18 -0700 Subject: [PATCH 2/2] c++: Diagnostics for C++23 P0847R7 (Deducing this) [PR102609] This patch adds diagnostics for various ill-formed code related to xobj member functions. Some of the code in here leaves something to be desired, but the majority of cases should be handled. I opted to add a new TFF flag despite only using it in a single place, other solutions seemed non ideal and there are plenty of bits left. Some of the diagnostics are more scattered around than I would like, perhaps this could be refactored in the future, especially those in grokfndecl. PR c++/102609 gcc/cp/ChangeLog: PR c++/102609 Diagnostics for C++23 P0847R7 - Deducing this. * cp-tree.h (TFF_XOBJ_FUNC): Define. * decl.cc (grokfndecl): Diagnose cvref-qualifiers on an xobj member function. (grokdeclarator): Diagnostics * error.cc (dump_function_decl): For xobj member function add TFF_XOBJ_FUNC bit to dump_parameters flags argument. (dump_parameters): When printing xobj member function's params add "this" to the first param. (function_category): Say so when in an xobj member function. * parser.cc (cp_parser_decl_specifier_seq): Diagnose incorrectly positioned "this" specifier. (cp_parser_parameter_declaration): Diagnose default argument on xobj params. * semantics.cc (finish_this_expr): Diagnose uses of "this" in body of xobj member function. gcc/testsuite/ChangeLog: PR c++/102609 Diagnostics for C++23 P0847R7 - Deducing this. * 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/cp/cp-tree.h | 5 +- gcc/cp/decl.cc | 133 ++++++++++++++--- gcc/cp/error.cc | 8 +- gcc/cp/parser.cc | 45 ++++++ gcc/cp/semantics.cc | 28 +++- .../g++.dg/cpp23/explicit-obj-cxx-dialect-A.C | 6 + .../g++.dg/cpp23/explicit-obj-cxx-dialect-B.C | 7 + .../g++.dg/cpp23/explicit-obj-cxx-dialect-C.C | 7 + .../g++.dg/cpp23/explicit-obj-cxx-dialect-D.C | 7 + .../g++.dg/cpp23/explicit-obj-cxx-dialect-E.C | 7 + .../g++.dg/cpp23/explicit-obj-diagnostics1.C | 138 ++++++++++++++++++ .../g++.dg/cpp23/explicit-obj-diagnostics2.C | 25 ++++ .../g++.dg/cpp23/explicit-obj-diagnostics3.C | 84 +++++++++++ .../g++.dg/cpp23/explicit-obj-diagnostics4.C | 19 +++ .../g++.dg/cpp23/explicit-obj-diagnostics5.C | 15 ++ .../g++.dg/cpp23/explicit-obj-diagnostics6.C | 22 +++ .../g++.dg/cpp23/explicit-obj-diagnostics7.C | 24 +++ 17 files changed, 560 insertions(+), 20 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/cp/cp-tree.h b/gcc/cp/cp-tree.h index 901fb1f4616..1d118fdeb7e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6116,7 +6116,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) @@ -6134,6 +6136,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 c02d78b8102..26acf96322c 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -10607,24 +10607,29 @@ grokfndecl (tree ctype, TREE_TYPE (decl) = apply_memfn_quals (TREE_TYPE (decl), TYPE_UNQUALIFIED, REF_QUAL_NONE); - 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)) @@ -13117,19 +13122,113 @@ 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 || parm_list == void_list_node) - return false; + return NULL_TREE; if (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%>"); + + /* Error handling for explicit object member functions. */ + if (!xobj_parm) + /* Early escape. */; + else if (decl_context == TYPENAME) + { + bool ptr_type = true; + /* If */ + 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 function pointer type cannot " + "have an explicit object parameter"); + else if (declarator->declarator->kind == cdk_ptrmem) + error_at (DECL_SOURCE_LOCATION (xobj_parm), + "a member function pointer type " + "cannot have an explicit object parameter"); + else + gcc_unreachable (); + + 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. */ + } + /* Free function case, + surely there is a better way to identify it? */ + else if (decl_context == NORMAL + && (in_namespace + || !declarator->declarator->u.id.qualifying_scope)) + error_at (DECL_SOURCE_LOCATION (xobj_parm), + "a free function cannot have " + "an explicit object parameter"); + else /* if (xobj_parm) */ + { + if (virtualp) + { + 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) + { + 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"); + } + } + /* We don't need to skip over the first node even if it is an xobj + parm, find_xobj_parm clears the flag so it will be treated as a + normal parm, thus immediately going to the next node without + emitting an errant diagnosis. */ + 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))); + /* I'm keeping it more basic for now. */ + 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"); + /* End of explicit object member function diagnostics. */ if (reqs) error_at (location_of (reqs), "requires-clause on return type"); diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index 0ed69bca6fc..c9870d45706 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -1831,7 +1831,9 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) if (!(flags & TFF_NO_FUNCTION_ARGUMENTS)) { - dump_parameters (pp, parmtypes, flags); + dump_parameters (pp, parmtypes, + DECL_XOBJ_MEMBER_FUNC_P (t) ? TFF_XOBJ_FUNC | flags + : flags); if (TREE_CODE (fntype) == METHOD_TYPE) { @@ -1910,6 +1912,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; @@ -3685,6 +3689,8 @@ function_category (tree fn) return _("In destructor %qD"); else if (LAMBDA_FUNCTION_P (fn)) return _("In lambda function"); + else if (DECL_XOBJ_MEMBER_FUNC_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 4fbcc52c222..77e1f405c61 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -16019,6 +16019,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) { @@ -16091,12 +16093,42 @@ 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) + { + gcc_rich_location richloc (token->location); + /* Ideally we synthesize a full rewrite, at the moment + there are issues with it though. + It rewrites "f(S this & s)" correctly, + but fails to rewrite "f(const this S s)" correctly. + It also does not handle "f(S& this s)" correctly at all. + + It's also possible we want to wait and see if the parm + could even be a valid xobj parm as it might be confusing + to the user to see an error, fix it, and then see another + error for something new. + + In short, this area needs improvement. */ + richloc.add_fixit_insert_before + (first_specifier->location, "this "); + richloc.add_fixit_remove (); + error_at (&richloc, + "% must be the first specifier " + "in a parameter declaration"); + } + } set_and_check_decl_spec_loc (decl_specs, ds_this, token); continue; } @@ -25507,6 +25539,19 @@ cp_parser_parameter_declaration (cp_parser *parser, if (decl_spec_seq_has_spec_p (&decl_specifiers, ds_this)) { + if (default_argument) + { + /* If default_argument is non-null token should always be the + the location of the `=' token, this is brittle code though + and should be rectified in the future. */ + location_t param_with_init_loc + = make_location (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/semantics.cc b/gcc/cp/semantics.cc index 52044be7af8..0588ed25d2c 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -3085,7 +3085,33 @@ finish_this_expr (void) return rvalue (result); tree fn = current_nonlambda_function (); - if (fn && DECL_STATIC_FUNCTION_P (fn)) + if (fn && DECL_XOBJ_MEMBER_FUNC_P (fn)) + { + /* I can imagine doing a fixit here, suggesting replacing + this / *this / this-> with &name / name / "name." but it would be + very difficult to get it perfect and I've been advised against + making imperfect fixits. + Perhaps it would be as simple as the replacements listed, + even if one is move'ing/forward'ing, if the replacement is just + done in the same place, it will be exactly what the user wants? + Even if this is true though, there's still a problem of getting the + context of the expression to find which tokens to replace. + I would really like for this to be possible though. + I will decide whether or not to persue this after review. */ + tree xobj_parm = FUNCTION_DECL_CHECK (fn)->function_decl.arguments; + tree parm_name = DECL_MINIMAL_CHECK (xobj_parm)->decl_minimal.name; + error ("% is unavailable for explicit object member " + "functions"); + if (parm_name) + inform (DECL_SOURCE_LOCATION (xobj_parm), + "use explicit object parameter %qD instead", + parm_name); + else + inform (DECL_SOURCE_LOCATION (xobj_parm), + "name and use the explicit object parameter instead"); + /* Maybe suggest self as a name here? */ + } + 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/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..033745d5784 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-A.C @@ -0,0 +1,6 @@ +// 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..a427506b61e --- /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 } } +// { dg-options "-pedantic-errors" } + +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..ed6259b70cd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-C.C @@ -0,0 +1,7 @@ +// P0847R7 +// { dg-do compile { target c++20_down } } +// { dg-options "-Wno-error=pedantic" } + +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..dccb0cf07df --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-D.C @@ -0,0 +1,7 @@ +// 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..1924212fb23 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-cxx-dialect-E.C @@ -0,0 +1,7 @@ +// 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..7b94f7e9c12 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics1.C @@ -0,0 +1,138 @@ +// 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..f09f8dea5a8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics2.C @@ -0,0 +1,25 @@ +// 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 function pointer 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 member function pointer 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 free function cannot have an explicit object parameter" } +void f(this int) {} // { dg-error "a free 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..70c6a825f58 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics3.C @@ -0,0 +1,84 @@ +// P0847R7 +// { dg-do compile { target c++23 } } + +// rejection and diagnosis of equivalent redeclarations of member functions + +// xobj redeclared as iobj + +struct S0 { + void f0(this S0&); // { dg-note "previous declaration" } + void f0(); // { dg-error "cannot be overloaded with" } + + void f1(this S0 const&); // { dg-note "previous declaration" "detecting redeclarations of xobj member functions as iobj member functions without a ref qualifier is known to be broken" { xfail *-*-* } } + void f1() const; // { dg-error "cannot be overloaded with" "detecting redeclarations of xobj member functions as iobj member functions without a ref qualifier is known to be broken" { xfail *-*-* } } + + void f2(this S0 volatile&); // { dg-note "previous declaration" "detecting redeclarations of xobj member functions as iobj member functions without a ref qualifier is known to be broken" { xfail *-*-* } } + void f2() volatile; // { dg-error "cannot be overloaded with" "detecting redeclarations of xobj member functions as iobj member functions without a ref qualifier is known to be broken" { xfail *-*-* } } + + void f3(this S0 const volatile&); // { dg-note "previous declaration" "detecting redeclarations of xobj member functions as iobj member functions without a ref qualifier is known to be broken" { xfail *-*-* } } + void f3() const volatile; // { dg-error "cannot be overloaded with" "detecting redeclarations of xobj member functions as iobj member functions without a ref qualifier is known to be broken" { xfail *-*-* } } + + void f4(this S0&); // { dg-note "previous declaration" } + void f4() &; // { dg-error "cannot be overloaded with" } + + void f5(this S0&&); // { dg-note "previous declaration" } + void f5() &&; // { dg-error "cannot be overloaded with" } + + void f6(this S0 const&); // { dg-note "previous declaration" } + void f6() const&; // { dg-error "cannot be overloaded with" } + + void f7(this S0 const&&); // { dg-note "previous declaration" } + void f7() const&&; // { dg-error "cannot be overloaded with" } + + void f8(this S0 volatile&); // { dg-note "previous declaration" } + void f8() volatile&; // { dg-error "cannot be overloaded with" } + + void f9(this S0 volatile&&); // { dg-note "previous declaration" } + void f9() volatile&&; // { dg-error "cannot be overloaded with" } + + void fA(this S0 const volatile&); // { dg-note "previous declaration" } + void fA() const volatile&; // { dg-error "cannot be overloaded with" } + + void fB(this S0 const volatile&&); // { dg-note "previous declaration" } + void fB() const volatile&&; // { dg-error "cannot be overloaded with" } +}; + +// iobj redeclared as xobj + +struct S1 { + void f0(); // { dg-note "previous declaration" } + void f0(this S1&); // { dg-error "cannot be overloaded with" } + + void f1() const; // { dg-note "previous declaration" "detecting redeclarations of iobj member functions without a ref qualifier as xobj member functions is known to be broken" { xfail *-*-* } } + void f1(this S1 const&); // { dg-error "cannot be overloaded with" "detecting redeclarations of iobj member functions without a ref qualifier as xobj member functions is known to be broken" { xfail *-*-* } } + + void f2() volatile; // { dg-note "previous declaration" "detecting redeclarations of iobj member functions without a ref qualifier as xobj member functions is known to be broken" { xfail *-*-* } } + void f2(this S1 volatile&); // { dg-error "cannot be overloaded with" "detecting redeclarations of iobj member functions without a ref qualifier as xobj member functions is known to be broken" { xfail *-*-* } } + + void f3() const volatile; // { dg-note "previous declaration" "detecting redeclarations of iobj member functions without a ref qualifier as xobj member functions is known to be broken" { xfail *-*-* } } + void f3(this S1 const volatile&); // { dg-error "cannot be overloaded with" "detecting redeclarations of iobj member functions without a ref qualifier as xobj member functions is known to be broken" { xfail *-*-* } } + + void f4() &; // { dg-note "previous declaration" } + void f4(this S1&); // { dg-error "cannot be overloaded with" } + + void f5() &&; // { dg-note "previous declaration" } + void f5(this S1&&); // { dg-error "cannot be overloaded with" } + + void f6() const&; // { dg-note "previous declaration" } + void f6(this S1 const&); // { dg-error "cannot be overloaded with" } + + void f7() const&&; // { dg-note "previous declaration" } + void f7(this S1 const&&); // { dg-error "cannot be overloaded with" } + + void f8() volatile&; // { dg-note "previous declaration" } + void f8(this S1 volatile&); // { dg-error "cannot be overloaded with" } + + void f9() volatile&&; // { dg-note "previous declaration" } + void f9(this S1 volatile&&); // { dg-error "cannot be overloaded with" } + + void fA() const volatile&; // { dg-note "previous declaration" } + void fA(this S1 const volatile&); // { dg-error "cannot be overloaded with" } + + void fB() const volatile&&; // { dg-note "previous declaration" } + void fB(this S1 const volatile&&); // { dg-error "cannot be overloaded with" } +}; 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..1f743a8509f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics4.C @@ -0,0 +1,19 @@ +// 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-diagnostics5.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics5.C new file mode 100644 index 00000000000..65a5c63f20b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics5.C @@ -0,0 +1,15 @@ +// 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-diagnostics6.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics6.C new file mode 100644 index 00000000000..e56d6265ea1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics6.C @@ -0,0 +1,22 @@ +// 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 and use the explicit object parameter instead" } + this->_n = 10; // { dg-error "'this' is unavailable for explicit object member functions" } + } +}; 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..3c1d018cd68 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-diagnostics7.C @@ -0,0 +1,24 @@ +// P0847R7 +// { dg-do compile { target c++23 } } + +// rejection and diagnosis when taking address of an unqualified xobj member function + +struct S { + static void static_f(S&) {} + void iobj_member_f() {} + void xobj_member_f(this S&) {} + + void test() { + using func_ptr_type = void(*)(S&); + // using mem_func_ptr_type = void (S::*)(); + + // allowed (not testing for this) + // func_ptr_type static_f_ptr = &static_f; + + // not allowed (also not testing for this) + // mem_func_ptr_type iobj_mem_f_ptr = &iobj_member_f; + + // not allowed (this is what we are testing for) + func_ptr_type xobj_mem_f_ptr = &xobj_member_f; // { dg-error "undetermined error" "disallowing address of unqualified explicit object member function is not implemented yet" { xfail *-*-* } } + } +}; -- 2.42.0