diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 438ef8a48e4..d09edd8a73f 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -10815,8 +10815,7 @@ maybe_warn_class_memaccess (location_t loc, tree fndecl, be more permissive. */ if (current_function_decl && DECL_OBJECT_MEMBER_FUNCTION_P (current_function_decl) - /* ??? is_object_parameter? */ - && is_this_parameter (tree_strip_nop_conversions (dest))) + && is_object_parameter (tree_strip_nop_conversions (dest))) { tree ctx = DECL_CONTEXT (current_function_decl); bool special = same_type_ignoring_top_level_qualifiers_p (ctx, desttype); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 674d015f5cf..fef5ce40919 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7781,6 +7781,7 @@ extern void finish_handler_parms (tree, tree); extern void finish_handler (tree); extern void finish_cleanup (tree, tree); extern bool is_this_parameter (tree); +extern bool is_object_parameter (tree); enum { BCS_NORMAL = 0, diff --git a/gcc/cp/search.cc b/gcc/cp/search.cc index d2ef93826e0..99c364d7290 100644 --- a/gcc/cp/search.cc +++ b/gcc/cp/search.cc @@ -1737,8 +1737,7 @@ field_access_p (tree component_ref, tree field_decl, tree field_type) return false; tree ptr = STRIP_NOPS (TREE_OPERAND (indirect_ref, 0)); - /* ??? is_object_parameter? */ - if (!is_this_parameter (ptr)) + if (!is_object_parameter (ptr)) return false; /* Must access the correct field. */ @@ -1818,6 +1817,17 @@ reference_accessor_p (tree init_expr, tree field_decl, tree field_type, return true; } +/* Return the class of the `this' or explicit object parameter of FN. */ + +static tree +class_of_object_parm (const_tree fn) +{ + tree fntype = TREE_TYPE (fn); + if (DECL_XOBJ_MEMBER_FUNCTION_P (fn)) + return non_reference (TREE_VALUE (TYPE_ARG_TYPES (fntype))); + return class_of_this_parm (fntype); +} + /* Return true if FN is an accessor method for FIELD_DECL. i.e. a method of the form { return FIELD; }, with no conversions. @@ -1835,15 +1845,14 @@ field_accessor_p (tree fn, tree field_decl, bool const_p) if (TREE_CODE (field_decl) != FIELD_DECL) return false; - tree fntype = TREE_TYPE (fn); - if (TREE_CODE (fntype) != METHOD_TYPE) + if (!DECL_OBJECT_MEMBER_FUNCTION_P (fn)) return false; /* If the field is accessed via a const "this" argument, verify that the "this" parameter is const. */ if (const_p) { - tree this_class = class_of_this_parm (fntype); + tree this_class = class_of_object_parm (fn); if (!TYPE_READONLY (this_class)) return false; } diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 873f00aad0e..5106ea71b90 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -12835,6 +12835,20 @@ is_this_parameter (tree t) return true; } +/* As above, or a C++23 explicit object parameter. */ + +bool +is_object_parameter (tree t) +{ + if (is_this_parameter (t)) + return true; + if (TREE_CODE (t) != PARM_DECL) + return false; + tree ctx = DECL_CONTEXT (t); + return (ctx && DECL_XOBJ_MEMBER_FUNCTION_P (ctx) + && t == DECL_ARGUMENTS (ctx)); +} + /* Insert the deduced return type for an auto function. */ void diff --git a/gcc/testsuite/g++.dg/torture/accessor-fixits-9-xobj.C b/gcc/testsuite/g++.dg/torture/accessor-fixits-9-xobj.C new file mode 100644 index 00000000000..89be978ae8e --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/accessor-fixits-9-xobj.C @@ -0,0 +1,119 @@ +// PR c++/84993 +// { dg-options "-fdiagnostics-show-caret -std=c++23" } + +/* Misspelling (by omitting a leading "m_") of a private member for which + there's a public accessor. + + We expect a fix-it hint suggesting the accessor. */ + +class t1 +{ +public: + int get_ratio (this const t1& x) { return x.m_ratio; } + +private: + int m_ratio; +}; + +int test (t1 *ptr_1) +{ + return ptr_1->ratio; // { dg-error "'class t1' has no member named 'ratio'; did you mean 'int t1::m_ratio'\\? \\(accessible via 'int t1::get_ratio\\(this const t1&\\)'\\)" } + /* { dg-begin-multiline-output "" } + return ptr_1->ratio; + ^~~~~ + get_ratio() + { dg-end-multiline-output "" } */ +} + + +/* Misspelling of a private member for which there's a public accessor. + + We expect a fix-it hint suggesting the accessor. */ + +class t2 +{ +public: + int get_color (this const t2& x) { return x.m_color; } + +private: + int m_color; +}; + +int test (t2 *ptr_2) +{ + return ptr_2->m_colour; // { dg-error "'class t2' has no member named 'm_colour'; did you mean 'int t2::m_color'\\? \\(accessible via 'int t2::get_color\\(this const t2&\\)'\\)" } + /* { dg-begin-multiline-output "" } + return ptr_2->m_colour; + ^~~~~~~~ + get_color() + { dg-end-multiline-output "" } */ +} + + +/* Misspelling of a private member via a subclass pointer, for which there's + a public accessor in the base class. + + We expect a fix-it hint suggesting the accessor. */ + +class t3 : public t2 {}; + +int test (t3 *ptr_3) +{ + return ptr_3->m_colour; // { dg-error "'class t3' has no member named 'm_colour'; did you mean 'int t2::m_color'\\? \\(accessible via 'int t2::get_color\\(this const t2&\\)'\\)" } + /* { dg-begin-multiline-output "" } + return ptr_3->m_colour; + ^~~~~~~~ + get_color() + { dg-end-multiline-output "" } */ +} + + +/* Misspelling of a protected member, for which there's isn't a public + accessor. + + We expect no fix-it hint; instead a message identifying where the + data member was declared. */ + +class t4 +{ +protected: + int m_color; // { dg-message "declared protected here" } +}; + +int test (t4 *ptr_4) +{ + return ptr_4->m_colour; // { dg-error "'class t4' has no member named 'm_colour'; did you mean 'int t4::m_color'\\? \\(not accessible from this context\\)" } + /* { dg-begin-multiline-output "" } + return ptr_4->m_colour; + ^~~~~~~~ + { dg-end-multiline-output "" } */ + /* { dg-begin-multiline-output "" } + int m_color; + ^~~~~~~ + { dg-end-multiline-output "" } */ +} + + +/* Misspelling of a private member, for which the accessor is also private. + + We expect no fix-it hint; instead a message identifying where the + data member was declared. */ + +class t5 +{ + int get_color (this const t5& x) { return x.m_color; } + int m_color; // { dg-message "declared private here" } +}; + +int test (t5 *ptr_5) +{ + return ptr_5->m_colour; // { dg-error "'class t5' has no member named 'm_colour'; did you mean 'int t5::m_color'\\? \\(not accessible from this context\\)" } + /* { dg-begin-multiline-output "" } + return ptr_5->m_colour; + ^~~~~~~~ + { dg-end-multiline-output "" } */ + /* { dg-begin-multiline-output "" } + int m_color; + ^~~~~~~ + { dg-end-multiline-output "" } */ +}