From d82a34432364b391abde44a23ceacb3c398a519d Mon Sep 17 00:00:00 2001
From: Waffl3x <waffl3x@protonmail.com>
Date: Thu, 31 Aug 2023 02:13:52 -0400
Subject: [PATCH 2/2] P0847R7 (deducing this) Extended diagnostics
gcc/cp/ChangeLog:
* cp-tree.h (TFF_XOBJ_FUNC): new flag to identify that an explicit object member function's parameters are being printed
* decl.cc (grokdeclarator): diagnose type declarations using 'this', diagnose function declarations using this
(grokparms): diagnose an explicit object parameter with a default argument
* error.cc (dump_function_decl): prevent explicit object member functions from being pretty printed with 'static', communicate to dump_parameters that the current function is an explicit object member function
(dump_parameters): pretty print the explicit object parameter with a leading 'this'
(function_category): support reporting that the current context is within an explicit object member function
* parser.cc (cp_parser_decl_specifier_seq): diagnose uses of 'this' when it is not the first specifier of a decl-specifier-seq
(cp_parser_parameter_declaration_list): diagnose when an explicit object parameter is not the first parameter
* semantics.cc (finish_this_expr): diagnose when 'this' is used in the body of an explicit object member function
gcc/testsuite/ChangeLog:
* g++.dg/cpp23/explicit-object-param-ill-formed1.C: New test.
* g++.dg/cpp23/explicit-object-param-ill-formed2.C: New test.
* g++.dg/cpp23/explicit-object-param-ill-formed3.C: New test.
* g++.dg/cpp23/explicit-object-param-ill-formed4.C: New test.
* g++.dg/cpp23/explicit-object-param-ill-formed5.C: New test.
* g++.dg/cpp23/explicit-object-param-ill-formed6.C: New test.
* g++.dg/cpp23/explicit-object-param-no-cxx23.C: New test.
Signed-off-by: Waffl3x <waffl3x@protonmail.com>
---
gcc/cp/cp-tree.h | 5 +-
gcc/cp/decl.cc | 71 +++++++++
gcc/cp/error.cc | 12 +-
gcc/cp/parser.cc | 62 ++++++++
gcc/cp/semantics.cc | 24 ++-
.../cpp23/explicit-object-param-ill-formed1.C | 141 ++++++++++++++++++
.../cpp23/explicit-object-param-ill-formed2.C | 25 ++++
.../cpp23/explicit-object-param-ill-formed3.C | 102 +++++++++++++
.../cpp23/explicit-object-param-ill-formed4.C | 42 ++++++
.../cpp23/explicit-object-param-ill-formed5.C | 9 ++
.../cpp23/explicit-object-param-ill-formed6.C | 22 +++
.../cpp23/explicit-object-param-no-cxx23.C | 7 +
12 files changed, 517 insertions(+), 5 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-object-param-ill-formed1.C
create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-object-param-ill-formed2.C
create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-object-param-ill-formed3.C
create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-object-param-ill-formed4.C
create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-object-param-ill-formed5.C
create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-object-param-ill-formed6.C
create mode 100644 gcc/testsuite/g++.dg/cpp23/explicit-object-param-no-cxx23.C
@@ -6111,7 +6111,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)
@@ -6129,6 +6131,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.
@@ -13080,6 +13080,67 @@ grokdeclarator (const cp_declarator *declarator,
tree xobj_parm
= get_xobj_parm (declarator->u.function.parameters);
is_xobj_member_function = xobj_parm;
+ if (!xobj_parm)
+ /* early escape */;
+ else if (decl_context == TYPENAME)
+ {
+ bool ptr_type = true;
+ 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");
+
+ 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 can synthesize the correct syntax
+ and display it, perhaps it can be added later */
+ }
+ /* I am unsure if this is the best way of determining this
+ but I don't like it either way, it should be improved on*/
+ 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 "
+ "%<virtual%>");
+ inform (DECL_SOURCE_LOCATION (xobj_parm),
+ "explicit object parameter declared here");
+ virtualp = false;
+ }
+ else if (staticp >= 2)
+ {
+ 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 arg_types;
int funcdecl_p;
@@ -15156,6 +15217,11 @@ grokparms (tree parmlist, tree *parms)
tree parm;
int any_error = 0;
+ /* If any parm other than the first is an xobj parm, it should have
+ been diagnosed already, so don't bother diagnosing a default argument
+ on any other parms */
+ bool first_parm = true;
+
for (parm = parmlist; parm != NULL_TREE; parm = TREE_CHAIN (parm))
{
tree type = NULL_TREE;
@@ -15170,6 +15236,11 @@ grokparms (tree parmlist, tree *parms)
any_error = 1;
continue;
}
+ if (first_parm && !any_error && DECL_PARM_XOBJ_FLAG (decl) && init)
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "an explicit object parameter "
+ "may not have a default argument");
+ first_parm = false;
type = TREE_TYPE (decl);
if (VOID_TYPE_P (type))
@@ -1790,7 +1790,7 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
if (flags & TFF_DECL_SPECIFIERS)
{
- if (DECL_STATIC_FUNCTION_P (t))
+ if (DECL_STATIC_FUNCTION_P (t) && !DECL_IS_XOBJ_MEMBER_FUNC (t))
pp_cxx_ws_string (pp, "static");
else if (DECL_VIRTUAL_P (t))
pp_cxx_ws_string (pp, "virtual");
@@ -1835,7 +1835,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_IS_XOBJ_MEMBER_FUNC (t) ? TFF_XOBJ_FUNC | flags
+ : flags);
if (TREE_CODE (fntype) == METHOD_TYPE)
{
@@ -1914,6 +1916,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;
@@ -3683,7 +3687,9 @@ function_category (tree fn)
if (DECL_LANG_SPECIFIC (STRIP_TEMPLATE (fn))
&& DECL_FUNCTION_MEMBER_P (fn))
{
- if (DECL_STATIC_FUNCTION_P (fn))
+ if (DECL_IS_XOBJ_MEMBER_FUNC (fn))
+ return G_("In explicit object member function %qD");
+ else if (DECL_STATIC_FUNCTION_P (fn))
return _("In static member function %qD");
else if (DECL_COPY_CONSTRUCTOR_P (fn))
return _("In copy constructor %qD");
@@ -15803,6 +15803,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
/* Assume no class or enumeration type is declared. */
*declares_class_or_enum = 0;
+ cp_token *first_non_attribute = NULL;
/* Keep reading specifiers until there are no more to read. */
while (true)
{
@@ -15875,6 +15876,9 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
decl_specs->locations[ds_attribute] = token->location;
continue;
}
+ /* to properly place fixit diagnostic for xobj parm specifier */
+ if (!first_non_attribute)
+ first_non_attribute = token;
/* Special case for xobj parm, doesn't really belong up here
(it applies to parm decls and those are mostly handled below
the following specifiers) but I intend to refactor this function
@@ -15883,6 +15887,27 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
if (token->keyword == RID_THIS)
{
cp_lexer_consume_token (parser->lexer);
+ if (token != first_non_attribute)
+ {
+ /* let set_and_check_decl_spec_loc
+ report the diagnostic for duplicates */
+ if (decl_specs->locations[ds_this] == 0)
+ {
+ gcc_rich_location richloc (token->location);
+ /* we can do better than this, it doesn't show a full
+ rewrite when there are keywords between it and the start
+ 'f(const this S s)' for example, but it will properly
+ rewrite 'f(S this & s)'
+ Also fails to give a proper diagnostic
+ for 'f(S& this s)' this case*/
+ richloc.add_fixit_insert_before
+ (first_non_attribute->location, "this ");
+ richloc.add_fixit_remove ();
+ 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;
}
@@ -24833,6 +24858,10 @@ cp_parser_parameter_declaration_list (cp_parser* parser,
= parser->in_unbraced_linkage_specification_p;
parser->in_unbraced_linkage_specification_p = false;
+ /* Check if anything but the first parm is declared as an xobj parm.
+ I want to come back and refactor this with a better solution later. */
+ cp_parameter_declarator *first_parm = nullptr;
+
/* Look for more parameters. */
while (true)
{
@@ -24845,6 +24874,39 @@ cp_parser_parameter_declaration_list (cp_parser* parser,
= cp_parser_parameter_declaration (parser, flags,
/*template_parm_p=*/false,
&parenthesized_p);
+ if (!first_parm)
+ first_parm = parameter;
+ /* this has to go here (as opposed to grokdeclarator)
+ to emit the best possible diagnostics */
+ if (parameter && first_parm != parameter
+ && parameter->decl_specifiers.locations[ds_this] != 0)
+ {
+ gcc_rich_location bad_this
+ (parameter->decl_specifiers.locations[ds_this]);
+ /* this is unneccesary if the order of fixit/inform/error
+ does not matter, but I am under the impression that it does */
+ auto emit_error = [&bad_this]()
+ {
+ error_at (&bad_this,
+ "Only the first parameter of a member function "
+ "can be declared as an explicit object parameter");
+ };
+ if (first_parm->decl_specifiers.locations[ds_this] == 0)
+ {
+ /* We should probably check if the type of the first parm would
+ be sane as an xobj parm before making this suggestion */
+ /* I couldn't figure out how to get this quite the way I wanted.
+ It should definitely be improved on */
+ bad_this.add_fixit_insert_before (first_parm->loc, "this ");
+ emit_error ();
+ }
+ else
+ {
+ emit_error ();
+ inform (first_parm->loc,
+ "Valid explicit object parameter declared here");
+ }
+ }
/* We don't know yet if the enclosing context is unavailable or deprecated,
so wait and deal with it in grokparms if appropriate. */
@@ -3063,7 +3063,29 @@ finish_this_expr (void)
return rvalue (result);
tree fn = current_nonlambda_function ();
- if (fn && DECL_STATIC_FUNCTION_P (fn))
+ if (fn && DECL_IS_XOBJ_MEMBER_FUNC (fn))
+ {
+ /* I want to move this to an earlier
+ function to have access to the full expr */
+ tree xobj_parm = FUNCTION_DECL_CHECK (fn)->function_decl.arguments;
+ tree parm_name = DECL_MINIMAL_CHECK (xobj_parm)->decl_minimal.name;
+ if (parm_name)
+ {
+ error ("%<this%> is unavailable for explicit object member "
+ "functions");
+ inform (DECL_SOURCE_LOCATION (xobj_parm),
+ "use explicit object parameter %qD instead",
+ parm_name);
+ }
+ else
+ {
+ error ("%<this%> is unavailable for explicit object member "
+ "functions");
+ inform (DECL_SOURCE_LOCATION (xobj_parm),
+ "name and use the explicit object parameter instead");
+ }
+ }
+ 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");
new file mode 100644
@@ -0,0 +1,141 @@
+// P0847R7
+// { dg-do compile { target c++23 } }
+
+// I want to do better than what these currently are, but where the code is currently makes it impossible
+// they should at least be grouped or something
+
+// should at least note to apply qualifiers to the explicit object parameter instead (fixit should be possible)
+
+struct S {
+ void f_value_0(this S) const; // { dg-error "cannot have cv-qualifier" }
+ void f_value_1(this S) volatile; // { dg-error "cannot have cv-qualifier" }
+ void f_value_2(this S) const volatile; // { dg-error "cannot have cv-qualifier" }
+ void f_value_3(this S) &; // { dg-error "cannot have ref-qualifier" }
+ void f_value_4(this S) &&; // { dg-error "cannot have ref-qualifier" }
+ void f_value_5(this S) const &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_value_6(this S) const &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_value_7(this S) volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_value_8(this S) volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_value_9(this S) const volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_value_A(this S) const volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+
+ void f_ref_0(this S&) const; // { dg-error "cannot have cv-qualifier" }
+ void f_ref_1(this S&) volatile; // { dg-error "cannot have cv-qualifier" }
+ void f_ref_2(this S&) const volatile; // { dg-error "cannot have cv-qualifier" }
+ void f_ref_3(this S&) &; // { dg-error "cannot have ref-qualifier" }
+ void f_ref_4(this S&) &&; // { dg-error "cannot have ref-qualifier" }
+ void f_ref_5(this S&) const &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_ref_6(this S&) const &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_ref_7(this S&) volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_ref_8(this S&) volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_ref_9(this S&) const volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_ref_A(this S&) const volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+
+ void f_refref_0(this S&&) const; // { dg-error "cannot have cv-qualifier" }
+ void f_refref_1(this S&&) volatile; // { dg-error "cannot have cv-qualifier" }
+ void f_refref_2(this S&&) const volatile; // { dg-error "cannot have cv-qualifier" }
+ void f_refref_3(this S&&) &; // { dg-error "cannot have ref-qualifier" }
+ void f_refref_4(this S&&) &&; // { dg-error "cannot have ref-qualifier" }
+ void f_refref_5(this S&&) const &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_refref_6(this S&&) const &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_refref_7(this S&&) volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_refref_8(this S&&) volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_refref_9(this S&&) const volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_refref_A(this S&&) const volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+
+ void f_cref_0(this S const&) const; // { dg-error "cannot have cv-qualifier" }
+ void f_cref_1(this S const&) volatile; // { dg-error "cannot have cv-qualifier" }
+ void f_cref_2(this S const&) const volatile; // { dg-error "cannot have cv-qualifier" }
+ void f_cref_3(this S const&) &; // { dg-error "cannot have ref-qualifier" }
+ void f_cref_4(this S const&) &&; // { dg-error "cannot have ref-qualifier" }
+ void f_cref_5(this S const&) const &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_cref_6(this S const&) const &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_cref_7(this S const&) volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_cref_8(this S const&) volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_cref_9(this S const&) const volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_cref_A(this S const&) const volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+
+ void f_crefref_0(this S const&&) const; // { dg-error "cannot have cv-qualifier" }
+ void f_crefref_1(this S const&&) volatile; // { dg-error "cannot have cv-qualifier" }
+ void f_crefref_2(this S const&&) const volatile; // { dg-error "cannot have cv-qualifier" }
+ void f_crefref_3(this S const&&) &; // { dg-error "cannot have ref-qualifier" }
+ void f_crefref_4(this S const&&) &&; // { dg-error "cannot have ref-qualifier" }
+ void f_crefref_5(this S const&&) const &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_crefref_6(this S const&&) const &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_crefref_7(this S const&&) volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_crefref_8(this S const&&) volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_crefref_9(this S const&&) const volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_crefref_A(this S const&&) const volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+
+ void f_vref_0(this S volatile&) const; // { dg-error "cannot have cv-qualifier" }
+ void f_vref_1(this S volatile&) volatile; // { dg-error "cannot have cv-qualifier" }
+ void f_vref_2(this S volatile&) const volatile; // { dg-error "cannot have cv-qualifier" }
+ void f_vref_3(this S volatile&) &; // { dg-error "cannot have ref-qualifier" }
+ void f_vref_4(this S volatile&) &&; // { dg-error "cannot have ref-qualifier" }
+ void f_vref_5(this S volatile&) const &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_vref_6(this S volatile&) const &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_vref_7(this S volatile&) volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_vref_8(this S volatile&) volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_vref_9(this S volatile&) const volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_vref_A(this S volatile&) const volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+
+ void f_vrefref_0(this S volatile&&) const; // { dg-error "cannot have cv-qualifier" }
+ void f_vrefref_1(this S volatile&&) volatile; // { dg-error "cannot have cv-qualifier" }
+ void f_vrefref_2(this S volatile&&) const volatile; // { dg-error "cannot have cv-qualifier" }
+ void f_vrefref_3(this S volatile&&) &; // { dg-error "cannot have ref-qualifier" }
+ void f_vrefref_4(this S volatile&&) &&; // { dg-error "cannot have ref-qualifier" }
+ void f_vrefref_5(this S volatile&&) const &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_vrefref_6(this S volatile&&) const &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_vrefref_7(this S volatile&&) volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_vrefref_8(this S volatile&&) volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_vrefref_9(this S volatile&&) const volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_vrefref_A(this S volatile&&) const volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+
+ void f_cvref_0(this S const volatile&) const; // { dg-error "cannot have cv-qualifier" }
+ void f_cvref_1(this S const volatile&) volatile; // { dg-error "cannot have cv-qualifier" }
+ void f_cvref_2(this S const volatile&) const volatile; // { dg-error "cannot have cv-qualifier" }
+ void f_cvref_3(this S const volatile&) &; // { dg-error "cannot have ref-qualifier" }
+ void f_cvref_4(this S const volatile&) &&; // { dg-error "cannot have ref-qualifier" }
+ void f_cvref_5(this S const volatile&) const &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_cvref_6(this S const volatile&) const &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_cvref_7(this S const volatile&) volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_cvref_8(this S const volatile&) volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_cvref_9(this S const volatile&) const volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_cvref_A(this S const volatile&) const volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+
+ void f_cvrefref_0(this S const volatile&&) const; // { dg-error "cannot have cv-qualifier" }
+ void f_cvrefref_1(this S const volatile&&) volatile; // { dg-error "cannot have cv-qualifier" }
+ void f_cvrefref_2(this S const volatile&&) const volatile; // { dg-error "cannot have cv-qualifier" }
+ void f_cvrefref_3(this S const volatile&&) &; // { dg-error "cannot have ref-qualifier" }
+ void f_cvrefref_4(this S const volatile&&) &&; // { dg-error "cannot have ref-qualifier" }
+ void f_cvrefref_5(this S const volatile&&) const &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_cvrefref_6(this S const volatile&&) const &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_cvrefref_7(this S const volatile&&) volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_cvrefref_8(this S const volatile&&) volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_cvrefref_9(this S const volatile&&) const volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void f_cvrefref_A(this S const volatile&&) const volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+
+ template<typename Self> void d_templ_0(this Self&&) const; // { dg-error "cannot have cv-qualifier" }
+ template<typename Self> void d_templ_1(this Self&&) volatile; // { dg-error "cannot have cv-qualifier" }
+ template<typename Self> void d_templ_2(this Self&&) const volatile; // { dg-error "cannot have cv-qualifier" }
+ template<typename Self> void d_templ_3(this Self&&) &; // { dg-error "cannot have ref-qualifier" }
+ template<typename Self> void d_templ_4(this Self&&) &&; // { dg-error "cannot have ref-qualifier" }
+ template<typename Self> void d_templ_5(this Self&&) const &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ template<typename Self> void d_templ_6(this Self&&) const &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ template<typename Self> void d_templ_7(this Self&&) volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ template<typename Self> void d_templ_8(this Self&&) volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ template<typename Self> void d_templ_9(this Self&&) const volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ template<typename Self> void d_templ_A(this Self&&) const volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+
+ void d_auto_0(this auto&&) const; // { dg-error "cannot have cv-qualifier" }
+ void d_auto_1(this auto&&) volatile; // { dg-error "cannot have cv-qualifier" }
+ void d_auto_2(this auto&&) const volatile; // { dg-error "cannot have cv-qualifier" }
+ void d_auto_3(this auto&&) &; // { dg-error "cannot have ref-qualifier" }
+ void d_auto_4(this auto&&) &&; // { dg-error "cannot have ref-qualifier" }
+ void d_auto_5(this auto&&) const &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void d_auto_6(this auto&&) const &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void d_auto_7(this auto&&) volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void d_auto_8(this auto&&) volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void d_auto_9(this auto&&) const volatile &; // { dg-error "cannot have (ref|cv)-qualifier" }
+ void d_auto_A(this auto&&) const volatile &&; // { dg-error "cannot have (ref|cv)-qualifier" }
+};
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,25 @@
+// P0847R7
+// { dg-do compile { target c++23 } }
+
+// diagnose some incorrect uses of 'this' keyword 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" }
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,102 @@
+// P0847R7
+// { dg-do compile { target c++23 } }
+// { dg-additional-options -Woverloaded-virtual }
+
+// invalid specifiers
+
+struct B {
+ virtual void f0() {} // { dg-line line_base_f0 }
+ virtual void f1() {} // { dg-line line_base_f1 }
+ virtual void f2() {} // { dg-line line_base_f2 }
+ virtual void f3() {} // { dg-line line_base_f3 }
+ virtual void f4() {} // { dg-line line_base_f4 }
+ virtual void f5() {} // { dg-line line_base_f5 }
+ virtual void f6() {} // { dg-line line_base_f6 }
+ virtual void f7() {} // { dg-line line_base_f7 }
+ 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 }
+};
+
+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_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-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-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 }
+
+// { dg-bogus "an explicit object member function cannot be 'virtual'" "Surely this will never happen, but this test is here just in case it does" { target *-*-* } line_f4 }
+
+// I want to change the diagnostics below, the tests are check for the current error, and should be changed if the error is changed
+// (the following diagnostic should still take lower priority and thus be suppressed)
+
+// { dg-bogus "marked 'override', but does not override" "previous error should silence diagnostics about virt-specifiers (not implemented yet)" { xfail *-*-* } line_f1 }
+// { dg-bogus "marked 'final', but is not virtual" "previous error should silence diagnostics about virt-specifiers (not implemented yet)" { xfail *-*-* } line_f2 }
+// { dg-bogus "marked '(override|final)'" "previous error should silence diagnostics about virt-specifiers (not implemented yet)" { xfail *-*-* } line_f3 }
+
+// { dg-bogus "marked 'override', but does not override" "previous error should silence diagnostics about virt-specifiers (not implemented yet)" { xfail *-*-* } line_S1_f1 }
+// { dg-bogus "marked 'final', but is not virtual" "previous error should silence diagnostics about virt-specifiers (not implemented yet)" { xfail *-*-* } line_S1_f2 }
+// { dg-bogus "marked '(override|final)'" "previous error should silence diagnostics about virt-specifiers (not implemented yet)" { xfail *-*-* } line_S1_f3 }
+
+// { dg-error "marked 'override', but does not override" "" { target *-*-* } line_f5 }
+// { dg-error "marked 'final', but is not virtual" "" { target *-*-* } line_f6 }
+// { dg-error "marked '(override|final)'" "" { target *-*-* } line_f7 }
+
+// { 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 }
+
+// for now, these all stay active, I want to discuss with others on whether the warnings should be suppressed by other errors (I think they should be)
+
+// { dg-warning "was hidden" "" { target *-*-* } line_base_f0 }
+// { dg-warning "was hidden" "" { target *-*-* } line_base_f1 }
+// { dg-warning "was hidden" "" { target *-*-* } line_base_f2 }
+// { dg-warning "was hidden" "" { target *-*-* } line_base_f3 }
+// { dg-warning "was hidden" "" { target *-*-* } line_base_f4 }
+// { dg-warning "was hidden" "" { target *-*-* } line_base_f5 }
+// { dg-warning "was hidden" "" { target *-*-* } line_base_f6 }
+// { dg-warning "was hidden" "" { target *-*-* } line_base_f7 }
+
+// { dg-note "by '" "" { target *-*-* } line_f0 }
+// { dg-note "by '" "" { target *-*-* } line_f1 }
+// { dg-note "by '" "" { target *-*-* } line_f2 }
+// { dg-note "by '" "" { target *-*-* } line_f3 }
+// { dg-note "by '" "" { target *-*-* } line_f4 }
+// { dg-note "by '" "" { target *-*-* } line_f5 }
+// { dg-note "by '" "" { target *-*-* } line_f6 }
+// { dg-note "by '" "" { target *-*-* } line_f7 }
+
+
new file mode 100644
@@ -0,0 +1,42 @@
+// P0847R7
+// { dg-do compile { target c++23 } }
+
+// redeclarations
+
+struct S {
+ void f0(this S&); // { dg-note "previous declaration" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+ void f0(); // { dg-error "cannot be overloaded with" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+
+ void f1(this S const&); // { dg-note "previous declaration" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+ void f1() const; // { dg-error "cannot be overloaded with" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+
+ void f2(this S volatile&); // { dg-note "previous declaration" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+ void f2() volatile; // { dg-error "cannot be overloaded with" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+
+ void f3(this S const volatile&); // { dg-note "previous declaration" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+ void f3() const volatile; // { dg-error "cannot be overloaded with" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+
+ void f4(this S&); // { dg-note "previous declaration" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+ void f4() &; // { dg-error "cannot be overloaded with" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+
+ void f5(this S&&); // { dg-note "previous declaration" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+ void f5() &&; // { dg-error "cannot be overloaded with" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+
+ void f6(this S const&); // { dg-note "previous declaration" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+ void f6() const&; // { dg-error "cannot be overloaded with" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+
+ void f7(this S const&&); // { dg-note "previous declaration" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+ void f7() const&&; // { dg-error "cannot be overloaded with" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+
+ void f8(this S volatile&); // { dg-note "previous declaration" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+ void f8() volatile&; // { dg-error "cannot be overloaded with" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+
+ void f9(this S volatile&&); // { dg-note "previous declaration" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+ void f9() volatile&&; // { dg-error "cannot be overloaded with" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+
+ void fA(this S const volatile&); // { dg-note "previous declaration" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+ void fA() const volatile&; // { dg-error "cannot be overloaded with" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+
+ void fB(this S const volatile&&); // { dg-note "previous declaration" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+ void fB() const volatile&&; // { dg-error "cannot be overloaded with" "detecting redeclarations not implemented yet" { xfail *-*-* } }
+};
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,9 @@
+// P0847R7
+// { dg-do compile { target c++23 } }
+
+struct S {
+ void f0(this S = {}) {} // { dg-error "an explicit object parameter may not have a default argument" }
+ void f1(this S);
+};
+
+void S::f1(this S = {}) {} // { dg-error "an explicit object parameter may not have a default argument" }
new file mode 100644
@@ -0,0 +1,22 @@
+// P0847R7
+// { dg-do compile { target c++23 } }
+
+// using 'this' in body disabled
+
+// { 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" }
+ // solely for suppressing a potential warning
+ static_cast<void>(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" }
+ }
+};
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,7 @@
+// P0847R7
+// { dg-do compile { target c++20_down } }
+
+struct S {
+ void f(this S); // { dg-error "explicit object parameter requires" }
+ void g(this S self); // { dg-error "explicit object parameter requires" }
+};
\ No newline at end of file
--
2.41.0