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)
{
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;
+ }
}
}
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)
#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.
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))
/* 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;
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
{
/* 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)))
{
/* 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");
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)
{
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;
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");
}
/* 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)
{
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;
}
/* 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
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;
/* 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;
}
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. */
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");
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);
}
--- /dev/null
+// 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'} }
+};
+
--- /dev/null
+// 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'} }
+};
+
--- /dev/null
+// 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'} }
+};
+
--- /dev/null
+// 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'} }
+};
+
--- /dev/null
+// 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'} }
+};
+
--- /dev/null
+// 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" }
+};
+
--- /dev/null
+// 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" }
+
--- /dev/null
+// 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" }
+
--- /dev/null
+// 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 "" }
+ }
+};
+
--- /dev/null
+// 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" }
+ }
+};
+
--- /dev/null
+// 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 }
+}
+
--- /dev/null
+// 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 }
+
# 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
# 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