On Tue, 2018-03-20 at 21:51 -0400, Jason Merrill wrote: > On Tue, Mar 20, 2018 at 7:37 PM, David Malcolm <dmalc...@redhat.com> > wrote: > > PR c++/84894 reports that the fix-it hints suggesting accessor > > calls for > > private fields doesn't work with -g for -O1 and above. > > > > The issue is that field_accessor_p requires DECL_SAVED_TREE (fn) to > > be > > a RETURN_EXPR, but the former is a STATEMENT_LIST, created in > > start_preparsed_function here: > > Would constexpr_fn_retval be useful here?
Aha! Indeed it is. Thanks; this simplifies things considerably. Here's an updated patch which uses constexpr_fn_retval, along with an indentation fix and a little more test coverage. Successfully bootstrapped and regression-tested on x86_64-pc-linux-gnu; adds 486 PASS results to g++.sum (mostly due to the tests moving to gcc+.dg/torture). OK for trunk? gcc/cp/ChangeLog: PR c++/84994 * constexpr.c (constexpr_fn_retval): Make non-"static". * cp-tree.h (constexpr_fn_retval): New decl. * search.c (direct_accessor_p): Update leading comment. (reference_accessor_p): Likewise. (field_accessor_p): Replace check that function body is a RETURN_EXPR with a call to constexpr_fn_retval. Fix indentation of "field_type" decl. gcc/testsuite/ChangeLog: PR c++/84994 * g++.dg/other/accessor-fixits-1.C: Move to... * g++.dg/torture/accessor-fixits-1.C: ...here. * g++.dg/other/accessor-fixits-2.C: Move to... * g++.dg/torture/accessor-fixits-2.C: ...here. * g++.dg/other/accessor-fixits-3.C: Move to... * g++.dg/torture/accessor-fixits-3.C: ...here. * g++.dg/other/accessor-fixits-4.C: Move to... * g++.dg/torture/accessor-fixits-4.C: ...here. * g++.dg/other/accessor-fixits-5.C: Move to... * g++.dg/torture/accessor-fixits-5.C: ...here. * g++.dg/torture/accessor-fixits-6.C: New testcase. * g++.dg/torture/accessor-fixits-7.C: New testcase. * g++.dg/torture/accessor-fixits-8.C: New testcase. --- gcc/cp/constexpr.c | 2 +- gcc/cp/cp-tree.h | 1 + gcc/cp/search.c | 21 ++- gcc/testsuite/g++.dg/other/accessor-fixits-1.C | 222 ----------------------- gcc/testsuite/g++.dg/other/accessor-fixits-2.C | 104 ----------- gcc/testsuite/g++.dg/other/accessor-fixits-3.C | 15 -- gcc/testsuite/g++.dg/other/accessor-fixits-4.C | 48 ----- gcc/testsuite/g++.dg/other/accessor-fixits-5.C | 33 ---- gcc/testsuite/g++.dg/torture/accessor-fixits-1.C | 222 +++++++++++++++++++++++ gcc/testsuite/g++.dg/torture/accessor-fixits-2.C | 104 +++++++++++ gcc/testsuite/g++.dg/torture/accessor-fixits-3.C | 15 ++ gcc/testsuite/g++.dg/torture/accessor-fixits-4.C | 48 +++++ gcc/testsuite/g++.dg/torture/accessor-fixits-5.C | 33 ++++ gcc/testsuite/g++.dg/torture/accessor-fixits-6.C | 22 +++ gcc/testsuite/g++.dg/torture/accessor-fixits-7.C | 22 +++ gcc/testsuite/g++.dg/torture/accessor-fixits-8.C | 31 ++++ 16 files changed, 510 insertions(+), 433 deletions(-) delete mode 100644 gcc/testsuite/g++.dg/other/accessor-fixits-1.C delete mode 100644 gcc/testsuite/g++.dg/other/accessor-fixits-2.C delete mode 100644 gcc/testsuite/g++.dg/other/accessor-fixits-3.C delete mode 100644 gcc/testsuite/g++.dg/other/accessor-fixits-4.C delete mode 100644 gcc/testsuite/g++.dg/other/accessor-fixits-5.C create mode 100644 gcc/testsuite/g++.dg/torture/accessor-fixits-1.C create mode 100644 gcc/testsuite/g++.dg/torture/accessor-fixits-2.C create mode 100644 gcc/testsuite/g++.dg/torture/accessor-fixits-3.C create mode 100644 gcc/testsuite/g++.dg/torture/accessor-fixits-4.C create mode 100644 gcc/testsuite/g++.dg/torture/accessor-fixits-5.C create mode 100644 gcc/testsuite/g++.dg/torture/accessor-fixits-6.C create mode 100644 gcc/testsuite/g++.dg/torture/accessor-fixits-7.C create mode 100644 gcc/testsuite/g++.dg/torture/accessor-fixits-8.C diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 941562e..02bfb8e 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -657,7 +657,7 @@ get_function_named_in_call (tree t) return value if suitable, error_mark_node for a statement not allowed in a constexpr function, or NULL_TREE if no return value was found. */ -static tree +tree constexpr_fn_retval (tree body) { switch (TREE_CODE (body)) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 17d8c6d..2293394 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7400,6 +7400,7 @@ extern bool literal_type_p (tree); extern tree register_constexpr_fundef (tree, tree); extern bool is_valid_constexpr_fn (tree, bool); extern bool check_constexpr_ctor_body (tree, tree, bool); +extern tree constexpr_fn_retval (tree); extern tree ensure_literal_type_for_constexpr_object (tree); extern bool potential_constant_expression (tree); extern bool is_constant_expression (tree); diff --git a/gcc/cp/search.c b/gcc/cp/search.c index ddcff69..b436610 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -1657,8 +1657,7 @@ field_access_p (tree component_ref, tree field_decl, tree field_type) Specifically, a simple accessor within struct S of the form: T get_field () { return m_field; } - should have a DECL_SAVED_TREE of the form: - <return_expr + should have a constexpr_fn_retval (saved_tree) of the form: <init_expr:T <result_decl:T <nop_expr:T @@ -1666,7 +1665,7 @@ field_access_p (tree component_ref, tree field_decl, tree field_type) <indirect_ref:S> <nop_expr:P* <parm_decl (this)> - <field_decl (FIELD_DECL)>>>. */ + <field_decl (FIELD_DECL)>>>>>. */ static bool direct_accessor_p (tree init_expr, tree field_decl, tree field_type) @@ -1690,8 +1689,7 @@ direct_accessor_p (tree init_expr, tree field_decl, tree field_type) Specifically, a simple accessor within struct S of the form: T& get_field () { return m_field; } - should have a DECL_SAVED_TREE of the form: - <return_expr + should have a constexpr_fn_retval (saved_tree) of the form: <init_expr:T& <result_decl:T& <nop_expr: T& @@ -1757,16 +1755,19 @@ field_accessor_p (tree fn, tree field_decl, bool const_p) if (saved_tree == NULL_TREE) return false; - if (TREE_CODE (saved_tree) != RETURN_EXPR) + /* Attempt to extract a single return value from the function, + if it has one. */ + tree retval = constexpr_fn_retval (saved_tree); + if (retval == NULL_TREE || retval == error_mark_node) return false; - - tree init_expr = TREE_OPERAND (saved_tree, 0); - if (TREE_CODE (init_expr) != INIT_EXPR) + /* Require an INIT_EXPR. */ + if (TREE_CODE (retval) != INIT_EXPR) return false; + tree init_expr = retval; /* Determine if this is a simple accessor within struct S of the form: T get_field () { return m_field; }. */ - tree field_type = TREE_TYPE (field_decl); + tree field_type = TREE_TYPE (field_decl); if (cxx_types_compatible_p (TREE_TYPE (init_expr), field_type)) return direct_accessor_p (init_expr, field_decl, field_type); diff --git a/gcc/testsuite/g++.dg/other/accessor-fixits-1.C b/gcc/testsuite/g++.dg/other/accessor-fixits-1.C deleted file mode 100644 index fd46a52..0000000 --- a/gcc/testsuite/g++.dg/other/accessor-fixits-1.C +++ /dev/null @@ -1,222 +0,0 @@ -// { dg-options "-fdiagnostics-show-caret" } - -class t1 -{ -public: - int get_color () const { return m_color; } - int get_shape () const { return m_shape; } - -private: - int m_color; - -protected: - int m_shape; -}; - -int test_access_t1_color (t1 &ref) -{ - return ref.m_color; // { dg-error ".int t1::m_color. is private within this context" } - /* { dg-begin-multiline-output "" } - return ref.m_color; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - // { dg-message "declared private here" "" { target *-*-* } 10 } - /* { dg-begin-multiline-output "" } - int m_color; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - // { dg-message "field .int t1::m_color. can be accessed via .int t1::get_color\\(\\) const." "" { target *-*-* } .-12 } - /* { dg-begin-multiline-output "" } - return ref.m_color; - ^~~~~~~ - get_color() - { dg-end-multiline-output "" } */ -} - -int test_access_const_t1_color (const t1 &ref) -{ - return ref.m_color; // { dg-error ".int t1::m_color. is private within this context" } - /* { dg-begin-multiline-output "" } - return ref.m_color; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - - /* { dg-begin-multiline-output "" } - int m_color; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - // { dg-message "field .int t1::m_color. can be accessed via .int t1::get_color\\(\\) const." "" { target *-*-* } .-12 } - /* { dg-begin-multiline-output "" } - return ref.m_color; - ^~~~~~~ - get_color() - { dg-end-multiline-output "" } */ -} - -int test_access_t1_shape (t1 &ref) -{ - return ref.m_shape; // { dg-error ".int t1::m_shape. is protected within this context" } - /* { dg-begin-multiline-output "" } - return ref.m_shape; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - // { dg-message "declared protected here" "" { target *-*-* } 13 } - /* { dg-begin-multiline-output "" } - int m_shape; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - // { dg-message "field .int t1::m_shape. can be accessed via .int t1::get_shape\\(\\) const." "" { target *-*-* } .-12 } - /* { dg-begin-multiline-output "" } - return ref.m_shape; - ^~~~~~~ - get_shape() - { dg-end-multiline-output "" } */ -} - -int test_deref_t1_color (t1 *ptr) -{ - return ptr->m_color; // { dg-error ".int t1::m_color. is private within this context" } - /* { dg-begin-multiline-output "" } - return ptr->m_color; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - - /* { dg-begin-multiline-output "" } - int m_color; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - // { dg-message "field .int t1::m_color. can be accessed via .int t1::get_color\\(\\) const." "" { target *-*-* } .-12 } - /* { dg-begin-multiline-output "" } - return ptr->m_color; - ^~~~~~~ - get_color() - { dg-end-multiline-output "" } */ -} - -int test_deref_const_t1_color (const t1 *ptr) -{ - return ptr->m_color; // { dg-error ".int t1::m_color. is private within this context" } - /* { dg-begin-multiline-output "" } - return ptr->m_color; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - - /* { dg-begin-multiline-output "" } - int m_color; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - // { dg-message "field .int t1::m_color. can be accessed via .int t1::get_color\\(\\) const." "" { target *-*-* } .-12 } - /* { dg-begin-multiline-output "" } - return ptr->m_color; - ^~~~~~~ - get_color() - { dg-end-multiline-output "" } */ -} - -int test_deref_t1_shape (t1 *ptr) -{ - return ptr->m_shape; // { dg-error ".int t1::m_shape. is protected within this context" } - /* { dg-begin-multiline-output "" } - return ptr->m_shape; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - - /* { dg-begin-multiline-output "" } - int m_shape; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - // { dg-message "field .int t1::m_shape. can be accessed via .int t1::get_shape\\(\\) const." "" { target *-*-* } .-12 } - /* { dg-begin-multiline-output "" } - return ptr->m_shape; - ^~~~~~~ - get_shape() - { dg-end-multiline-output "" } */ -} - -/* Example of public inheritance. */ - -class t2 : public t1 -{ -}; - -int test_deref_t2_color (t2 *ptr) -{ - return ptr->m_color; // { dg-error ".int t1::m_color. is private within this context" } - /* { dg-begin-multiline-output "" } - return ptr->m_color; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - - /* { dg-begin-multiline-output "" } - int m_color; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - // { dg-message "field .int t1::m_color. can be accessed via .int t1::get_color\\(\\) const." "" { target *-*-* } .-12 } - /* { dg-begin-multiline-output "" } - return ptr->m_color; - ^~~~~~~ - get_color() - { dg-end-multiline-output "" } */ -} - -/* Example of private inheritance. */ - -class t3 : private t1 -{ -}; - -int test_deref_t3_color (t3 *ptr) -{ - return ptr->m_color; // { dg-error ".int t1::m_color. is private within this context" } - /* { dg-begin-multiline-output "" } - return ptr->m_color; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - /* { dg-begin-multiline-output "" } - int m_color; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - /* We shouldn't provide a fix-it hint for this case due to the - private inheritance. */ -} - -/* Example of non-public "accessor". */ - -class t4 -{ - int m_field; - int get_field () { return m_field; } -}; - -int test_deref_t4_field (t4 *ptr) -{ - return ptr->m_field; // { dg-error ".int t4::m_field. is private within this context" } - /* { dg-begin-multiline-output "" } - return ptr->m_field; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - /* { dg-begin-multiline-output "" } - int m_field; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - /* We shouldn't provide a fix-it hint for this case, as the accessor is - itself private. */ -} diff --git a/gcc/testsuite/g++.dg/other/accessor-fixits-2.C b/gcc/testsuite/g++.dg/other/accessor-fixits-2.C deleted file mode 100644 index e1a2b78..0000000 --- a/gcc/testsuite/g++.dg/other/accessor-fixits-2.C +++ /dev/null @@ -1,104 +0,0 @@ -// { dg-options "-fdiagnostics-show-caret" } - -/* Test of accessors that return references. */ - -class t1 -{ -public: - int& get_color () { return m_color; } - int& get_shape () { return m_shape; } - -private: - int m_color; - -protected: - int m_shape; -}; - -int test_access_t1_color (t1 &ref) -{ - return ref.m_color; // { dg-error ".int t1::m_color. is private within this context" } - /* { dg-begin-multiline-output "" } - return ref.m_color; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - // { dg-message "declared private here" "" { target *-*-* } 12 } - /* { dg-begin-multiline-output "" } - int m_color; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - // { dg-message "field .int t1::m_color. can be accessed via .int& t1::get_color\\(\\)." "" { target *-*-* } .-12 } - /* { dg-begin-multiline-output "" } - return ref.m_color; - ^~~~~~~ - get_color() - { dg-end-multiline-output "" } */ -} - -int test_access_t1_shape (t1 &ref) -{ - return ref.m_shape; // { dg-error ".int t1::m_shape. is protected within this context" } - /* { dg-begin-multiline-output "" } - return ref.m_shape; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - // { dg-message "declared protected here" "" { target *-*-* } 15 } - /* { dg-begin-multiline-output "" } - int m_shape; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - // { dg-message "field .int t1::m_shape. can be accessed via .int& t1::get_shape\\(\\)." "" { target *-*-* } .-12 } - /* { dg-begin-multiline-output "" } - return ref.m_shape; - ^~~~~~~ - get_shape() - { dg-end-multiline-output "" } */ -} - -int test_deref_t1_color (t1 *ptr) -{ - return ptr->m_color; // { dg-error ".int t1::m_color. is private within this context" } - /* { dg-begin-multiline-output "" } - return ptr->m_color; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - - /* { dg-begin-multiline-output "" } - int m_color; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - // { dg-message "field .int t1::m_color. can be accessed via .int& t1::get_color\\(\\)." "" { target *-*-* } .-12 } - /* { dg-begin-multiline-output "" } - return ptr->m_color; - ^~~~~~~ - get_color() - { dg-end-multiline-output "" } */ -} - -int test_deref_t1_shape (t1 *ptr) -{ - return ptr->m_shape; // { dg-error ".int t1::m_shape. is protected within this context" } - /* { dg-begin-multiline-output "" } - return ptr->m_shape; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - - /* { dg-begin-multiline-output "" } - int m_shape; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - // { dg-message "field .int t1::m_shape. can be accessed via .int& t1::get_shape\\(\\)." "" { target *-*-* } .-12 } - /* { dg-begin-multiline-output "" } - return ptr->m_shape; - ^~~~~~~ - get_shape() - { dg-end-multiline-output "" } */ -} diff --git a/gcc/testsuite/g++.dg/other/accessor-fixits-3.C b/gcc/testsuite/g++.dg/other/accessor-fixits-3.C deleted file mode 100644 index 27d2eb4..0000000 --- a/gcc/testsuite/g++.dg/other/accessor-fixits-3.C +++ /dev/null @@ -1,15 +0,0 @@ -class foo -{ -public: - static foo& get_singleton () { return s_singleton; } - -private: - static foo s_singleton; -}; - -foo & test_access_singleton () -{ - return foo::s_singleton; // { dg-error ".foo foo::s_singleton. is private within this context" } - // { dg-message "declared private here" "" { target *-*-* } 7 } - // We don't yet support generating a fix-it hint for this case. -} diff --git a/gcc/testsuite/g++.dg/other/accessor-fixits-4.C b/gcc/testsuite/g++.dg/other/accessor-fixits-4.C deleted file mode 100644 index c03dd4e..0000000 --- a/gcc/testsuite/g++.dg/other/accessor-fixits-4.C +++ /dev/null @@ -1,48 +0,0 @@ -// { dg-options "-fdiagnostics-show-caret" } - -class t1 -{ -public: - int& get_color () { return m_color; } - int& get_shape () { return m_shape; } - -private: - int m_color; // { dg-line color_decl } - int m_shape; // { dg-line shape_decl } -}; - -int test_const_ptr (const t1 *ptr) -{ - return ptr->m_color; // { dg-error ".int t1::m_color. is private within this context" } - /* { dg-begin-multiline-output "" } - return ptr->m_color; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - // { dg-message "declared private here" "" { target *-*-* } color_decl } - /* { dg-begin-multiline-output "" } - int m_color; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - /* We shouldn't issue a suggestion: the accessor is non-const, and we - only have a const ptr. */ -} - -int test_const_reference (const t1 &ref) -{ - return ref.m_shape; // { dg-error ".int t1::m_shape. is private within this context" } - /* { dg-begin-multiline-output "" } - return ref.m_shape; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - // { dg-message "declared private here" "" { target *-*-* } shape_decl } - /* { dg-begin-multiline-output "" } - int m_shape; - ^~~~~~~ - { dg-end-multiline-output "" } */ - - /* We shouldn't issue a suggestion: the accessor is non-const, and we - only have a const ptr. */ -} diff --git a/gcc/testsuite/g++.dg/other/accessor-fixits-5.C b/gcc/testsuite/g++.dg/other/accessor-fixits-5.C deleted file mode 100644 index cf72d78..0000000 --- a/gcc/testsuite/g++.dg/other/accessor-fixits-5.C +++ /dev/null @@ -1,33 +0,0 @@ -// PR c++/84892 -// { dg-options "-fdiagnostics-show-caret" } - -class S { -private: - bool field; - -public: - bool get_field() const { - return field; - } -}; - -bool thingy(const S & s) { - return s.field; // { dg-error "'bool S::field' is private within this context" } - /* { dg-begin-multiline-output "" } - return s.field; - ^~~~~ - { dg-end-multiline-output "" } */ - - // { dg-message "declared private here" "" { target *-*-* } 6 } - /* { dg-begin-multiline-output "" } - bool field; - ^~~~~ - { dg-end-multiline-output "" } */ - - // { dg-message "field 'bool S::field' can be accessed via 'bool S::get_field\\(\\) const'" "" { target *-*-* } .-12 } - /* { dg-begin-multiline-output "" } - return s.field; - ^~~~~ - get_field() - { dg-end-multiline-output "" } */ -} diff --git a/gcc/testsuite/g++.dg/torture/accessor-fixits-1.C b/gcc/testsuite/g++.dg/torture/accessor-fixits-1.C new file mode 100644 index 0000000..fd46a52 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/accessor-fixits-1.C @@ -0,0 +1,222 @@ +// { dg-options "-fdiagnostics-show-caret" } + +class t1 +{ +public: + int get_color () const { return m_color; } + int get_shape () const { return m_shape; } + +private: + int m_color; + +protected: + int m_shape; +}; + +int test_access_t1_color (t1 &ref) +{ + return ref.m_color; // { dg-error ".int t1::m_color. is private within this context" } + /* { dg-begin-multiline-output "" } + return ref.m_color; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + // { dg-message "declared private here" "" { target *-*-* } 10 } + /* { dg-begin-multiline-output "" } + int m_color; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + // { dg-message "field .int t1::m_color. can be accessed via .int t1::get_color\\(\\) const." "" { target *-*-* } .-12 } + /* { dg-begin-multiline-output "" } + return ref.m_color; + ^~~~~~~ + get_color() + { dg-end-multiline-output "" } */ +} + +int test_access_const_t1_color (const t1 &ref) +{ + return ref.m_color; // { dg-error ".int t1::m_color. is private within this context" } + /* { dg-begin-multiline-output "" } + return ref.m_color; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + + /* { dg-begin-multiline-output "" } + int m_color; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + // { dg-message "field .int t1::m_color. can be accessed via .int t1::get_color\\(\\) const." "" { target *-*-* } .-12 } + /* { dg-begin-multiline-output "" } + return ref.m_color; + ^~~~~~~ + get_color() + { dg-end-multiline-output "" } */ +} + +int test_access_t1_shape (t1 &ref) +{ + return ref.m_shape; // { dg-error ".int t1::m_shape. is protected within this context" } + /* { dg-begin-multiline-output "" } + return ref.m_shape; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + // { dg-message "declared protected here" "" { target *-*-* } 13 } + /* { dg-begin-multiline-output "" } + int m_shape; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + // { dg-message "field .int t1::m_shape. can be accessed via .int t1::get_shape\\(\\) const." "" { target *-*-* } .-12 } + /* { dg-begin-multiline-output "" } + return ref.m_shape; + ^~~~~~~ + get_shape() + { dg-end-multiline-output "" } */ +} + +int test_deref_t1_color (t1 *ptr) +{ + return ptr->m_color; // { dg-error ".int t1::m_color. is private within this context" } + /* { dg-begin-multiline-output "" } + return ptr->m_color; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + + /* { dg-begin-multiline-output "" } + int m_color; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + // { dg-message "field .int t1::m_color. can be accessed via .int t1::get_color\\(\\) const." "" { target *-*-* } .-12 } + /* { dg-begin-multiline-output "" } + return ptr->m_color; + ^~~~~~~ + get_color() + { dg-end-multiline-output "" } */ +} + +int test_deref_const_t1_color (const t1 *ptr) +{ + return ptr->m_color; // { dg-error ".int t1::m_color. is private within this context" } + /* { dg-begin-multiline-output "" } + return ptr->m_color; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + + /* { dg-begin-multiline-output "" } + int m_color; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + // { dg-message "field .int t1::m_color. can be accessed via .int t1::get_color\\(\\) const." "" { target *-*-* } .-12 } + /* { dg-begin-multiline-output "" } + return ptr->m_color; + ^~~~~~~ + get_color() + { dg-end-multiline-output "" } */ +} + +int test_deref_t1_shape (t1 *ptr) +{ + return ptr->m_shape; // { dg-error ".int t1::m_shape. is protected within this context" } + /* { dg-begin-multiline-output "" } + return ptr->m_shape; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + + /* { dg-begin-multiline-output "" } + int m_shape; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + // { dg-message "field .int t1::m_shape. can be accessed via .int t1::get_shape\\(\\) const." "" { target *-*-* } .-12 } + /* { dg-begin-multiline-output "" } + return ptr->m_shape; + ^~~~~~~ + get_shape() + { dg-end-multiline-output "" } */ +} + +/* Example of public inheritance. */ + +class t2 : public t1 +{ +}; + +int test_deref_t2_color (t2 *ptr) +{ + return ptr->m_color; // { dg-error ".int t1::m_color. is private within this context" } + /* { dg-begin-multiline-output "" } + return ptr->m_color; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + + /* { dg-begin-multiline-output "" } + int m_color; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + // { dg-message "field .int t1::m_color. can be accessed via .int t1::get_color\\(\\) const." "" { target *-*-* } .-12 } + /* { dg-begin-multiline-output "" } + return ptr->m_color; + ^~~~~~~ + get_color() + { dg-end-multiline-output "" } */ +} + +/* Example of private inheritance. */ + +class t3 : private t1 +{ +}; + +int test_deref_t3_color (t3 *ptr) +{ + return ptr->m_color; // { dg-error ".int t1::m_color. is private within this context" } + /* { dg-begin-multiline-output "" } + return ptr->m_color; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + /* { dg-begin-multiline-output "" } + int m_color; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + /* We shouldn't provide a fix-it hint for this case due to the + private inheritance. */ +} + +/* Example of non-public "accessor". */ + +class t4 +{ + int m_field; + int get_field () { return m_field; } +}; + +int test_deref_t4_field (t4 *ptr) +{ + return ptr->m_field; // { dg-error ".int t4::m_field. is private within this context" } + /* { dg-begin-multiline-output "" } + return ptr->m_field; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + /* { dg-begin-multiline-output "" } + int m_field; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + /* We shouldn't provide a fix-it hint for this case, as the accessor is + itself private. */ +} diff --git a/gcc/testsuite/g++.dg/torture/accessor-fixits-2.C b/gcc/testsuite/g++.dg/torture/accessor-fixits-2.C new file mode 100644 index 0000000..e1a2b78 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/accessor-fixits-2.C @@ -0,0 +1,104 @@ +// { dg-options "-fdiagnostics-show-caret" } + +/* Test of accessors that return references. */ + +class t1 +{ +public: + int& get_color () { return m_color; } + int& get_shape () { return m_shape; } + +private: + int m_color; + +protected: + int m_shape; +}; + +int test_access_t1_color (t1 &ref) +{ + return ref.m_color; // { dg-error ".int t1::m_color. is private within this context" } + /* { dg-begin-multiline-output "" } + return ref.m_color; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + // { dg-message "declared private here" "" { target *-*-* } 12 } + /* { dg-begin-multiline-output "" } + int m_color; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + // { dg-message "field .int t1::m_color. can be accessed via .int& t1::get_color\\(\\)." "" { target *-*-* } .-12 } + /* { dg-begin-multiline-output "" } + return ref.m_color; + ^~~~~~~ + get_color() + { dg-end-multiline-output "" } */ +} + +int test_access_t1_shape (t1 &ref) +{ + return ref.m_shape; // { dg-error ".int t1::m_shape. is protected within this context" } + /* { dg-begin-multiline-output "" } + return ref.m_shape; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + // { dg-message "declared protected here" "" { target *-*-* } 15 } + /* { dg-begin-multiline-output "" } + int m_shape; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + // { dg-message "field .int t1::m_shape. can be accessed via .int& t1::get_shape\\(\\)." "" { target *-*-* } .-12 } + /* { dg-begin-multiline-output "" } + return ref.m_shape; + ^~~~~~~ + get_shape() + { dg-end-multiline-output "" } */ +} + +int test_deref_t1_color (t1 *ptr) +{ + return ptr->m_color; // { dg-error ".int t1::m_color. is private within this context" } + /* { dg-begin-multiline-output "" } + return ptr->m_color; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + + /* { dg-begin-multiline-output "" } + int m_color; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + // { dg-message "field .int t1::m_color. can be accessed via .int& t1::get_color\\(\\)." "" { target *-*-* } .-12 } + /* { dg-begin-multiline-output "" } + return ptr->m_color; + ^~~~~~~ + get_color() + { dg-end-multiline-output "" } */ +} + +int test_deref_t1_shape (t1 *ptr) +{ + return ptr->m_shape; // { dg-error ".int t1::m_shape. is protected within this context" } + /* { dg-begin-multiline-output "" } + return ptr->m_shape; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + + /* { dg-begin-multiline-output "" } + int m_shape; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + // { dg-message "field .int t1::m_shape. can be accessed via .int& t1::get_shape\\(\\)." "" { target *-*-* } .-12 } + /* { dg-begin-multiline-output "" } + return ptr->m_shape; + ^~~~~~~ + get_shape() + { dg-end-multiline-output "" } */ +} diff --git a/gcc/testsuite/g++.dg/torture/accessor-fixits-3.C b/gcc/testsuite/g++.dg/torture/accessor-fixits-3.C new file mode 100644 index 0000000..27d2eb4 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/accessor-fixits-3.C @@ -0,0 +1,15 @@ +class foo +{ +public: + static foo& get_singleton () { return s_singleton; } + +private: + static foo s_singleton; +}; + +foo & test_access_singleton () +{ + return foo::s_singleton; // { dg-error ".foo foo::s_singleton. is private within this context" } + // { dg-message "declared private here" "" { target *-*-* } 7 } + // We don't yet support generating a fix-it hint for this case. +} diff --git a/gcc/testsuite/g++.dg/torture/accessor-fixits-4.C b/gcc/testsuite/g++.dg/torture/accessor-fixits-4.C new file mode 100644 index 0000000..c03dd4e --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/accessor-fixits-4.C @@ -0,0 +1,48 @@ +// { dg-options "-fdiagnostics-show-caret" } + +class t1 +{ +public: + int& get_color () { return m_color; } + int& get_shape () { return m_shape; } + +private: + int m_color; // { dg-line color_decl } + int m_shape; // { dg-line shape_decl } +}; + +int test_const_ptr (const t1 *ptr) +{ + return ptr->m_color; // { dg-error ".int t1::m_color. is private within this context" } + /* { dg-begin-multiline-output "" } + return ptr->m_color; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + // { dg-message "declared private here" "" { target *-*-* } color_decl } + /* { dg-begin-multiline-output "" } + int m_color; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + /* We shouldn't issue a suggestion: the accessor is non-const, and we + only have a const ptr. */ +} + +int test_const_reference (const t1 &ref) +{ + return ref.m_shape; // { dg-error ".int t1::m_shape. is private within this context" } + /* { dg-begin-multiline-output "" } + return ref.m_shape; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + // { dg-message "declared private here" "" { target *-*-* } shape_decl } + /* { dg-begin-multiline-output "" } + int m_shape; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + /* We shouldn't issue a suggestion: the accessor is non-const, and we + only have a const ptr. */ +} diff --git a/gcc/testsuite/g++.dg/torture/accessor-fixits-5.C b/gcc/testsuite/g++.dg/torture/accessor-fixits-5.C new file mode 100644 index 0000000..cf72d78 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/accessor-fixits-5.C @@ -0,0 +1,33 @@ +// PR c++/84892 +// { dg-options "-fdiagnostics-show-caret" } + +class S { +private: + bool field; + +public: + bool get_field() const { + return field; + } +}; + +bool thingy(const S & s) { + return s.field; // { dg-error "'bool S::field' is private within this context" } + /* { dg-begin-multiline-output "" } + return s.field; + ^~~~~ + { dg-end-multiline-output "" } */ + + // { dg-message "declared private here" "" { target *-*-* } 6 } + /* { dg-begin-multiline-output "" } + bool field; + ^~~~~ + { dg-end-multiline-output "" } */ + + // { dg-message "field 'bool S::field' can be accessed via 'bool S::get_field\\(\\) const'" "" { target *-*-* } .-12 } + /* { dg-begin-multiline-output "" } + return s.field; + ^~~~~ + get_field() + { dg-end-multiline-output "" } */ +} diff --git a/gcc/testsuite/g++.dg/torture/accessor-fixits-6.C b/gcc/testsuite/g++.dg/torture/accessor-fixits-6.C new file mode 100644 index 0000000..ae2f180 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/accessor-fixits-6.C @@ -0,0 +1,22 @@ +// PR c++/84994 +/* Ensure that fix-it hints are offered at every optimization level, even when + "-g" is enabled (coverage for every optimization level without -g is given + by the other cases within g++.dg/torture/accessor-fixits-*.C). */ +// { dg-additional-options "-g" } + +class foo +{ +public: + double get_ratio() const { return m_ratio; } + +private: + double m_ratio; // { dg-line field_decl } +}; + +void test(foo *ptr) +{ + if (ptr->m_ratio >= 0.5) // { dg-error "'double foo::m_ratio' is private within this context" } + ; + // { dg-message "declared private here" "" { target *-*-* } field_decl } + // { dg-message "'double foo::m_ratio' can be accessed via 'double foo::get_ratio\\(\\) const'" "" { target *-*-* } .-3 } +} diff --git a/gcc/testsuite/g++.dg/torture/accessor-fixits-7.C b/gcc/testsuite/g++.dg/torture/accessor-fixits-7.C new file mode 100644 index 0000000..3b5babd --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/accessor-fixits-7.C @@ -0,0 +1,22 @@ +class foo +{ +public: + double get_ratio() const; + +private: + double m_ratio; // { dg-line field_decl } +}; + +double +foo::get_ratio() const +{ + return m_ratio; +} + +void test(foo *ptr) +{ + if (ptr->m_ratio >= 0.5) // { dg-error "'double foo::m_ratio' is private within this context" } + ; + // { dg-message "declared private here" "" { target *-*-* } field_decl } + // { dg-message "'double foo::m_ratio' can be accessed via 'double foo::get_ratio\\(\\) const'" "" { target *-*-* } .-3 } +} diff --git a/gcc/testsuite/g++.dg/torture/accessor-fixits-8.C b/gcc/testsuite/g++.dg/torture/accessor-fixits-8.C new file mode 100644 index 0000000..1338b7d --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/accessor-fixits-8.C @@ -0,0 +1,31 @@ +// { dg-options "-fdiagnostics-show-caret" } + +class t1 +{ +public: + int get_doubled_field () const { return m_field * 2; } + int get_guarded_field_1 () const { if (m_field) return m_field; else return 42; } + int get_guarded_field_2 () const { return m_field ? m_field : 42; } + int with_unreachable () const { __builtin_unreachable (); return m_field; } + void no_return () { } + +private: + int m_field; // { dg-line field_decl } +}; + +int test (t1 *ptr) +{ + return ptr->m_field; // { dg-error ".int t1::m_field. is private within this context" } + /* { dg-begin-multiline-output "" } + return ptr->m_field; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + // { dg-message "declared private here" "" { target *-*-* } field_decl } + /* { dg-begin-multiline-output "" } + int m_field; + ^~~~~~~ + { dg-end-multiline-output "" } */ + + /* We shouldn't issue a suggestion: none of the member functions are suitable returns. */ +} -- 1.8.5.3