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: 15060 /* Start the statement-tree, start the tree now. */ 15061 DECL_SAVED_TREE (decl1) = push_stmt_list (); This works for -O0 and without -g since cp/decl.c: finish_function modifies it here: 15636 /* If we're saving up tree structure, tie off the function now. */ 15637 DECL_SAVED_TREE (fndecl) = pop_stmt_list (DECL_SAVED_TREE (fndecl)); which strips away the stmt list, giving the RETURN_EXPR, but for -g with -O1 and above, the STATEMENT_LIST is preserved. This patch fixes the issue by introducing a new function: get_any_single_nondebug_stmt_in_list to extract the single non-debug stmt from a STATEMENT_LIST, if there is one, using it within field_accessor_p. It moves the existing testcases to the g++.dg/torture subdirectory, so that they are run for a variety of debug and optimization combinations. Successfully bootstrapped and regression-tested on x86_64-pc-linux-gnu. OK for trunk? (not technically a regression, but affects a new feature) gcc/c-family/ChangeLog: PR c++/84994 * c-common.h (get_any_single_nondebug_stmt_in_list): New decl. * c-semantics.c (get_any_single_nondebug_stmt_in_list): New function. gcc/cp/ChangeLog: PR c++/84994 * search.c (field_accessor_p): Call get_any_single_nondebug_stmt_in_list on DECL_SAVED_TREE (fn). gcc/testsuite/ChangeLog: * 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/c-family/c-common.h | 1 + gcc/c-family/c-semantics.c | 34 ++++ gcc/cp/search.c | 5 + 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 | 29 +++ 16 files changed, 535 insertions(+), 422 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/c-family/c-common.h b/gcc/c-family/c-common.h index 95bb0fd..67d0ed2 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -581,6 +581,7 @@ extern tree push_stmt_list (void); extern tree pop_stmt_list (tree); extern tree add_stmt (tree); extern void push_cleanup (tree, tree, bool); +extern tree get_any_single_nondebug_stmt_in_list (tree); extern tree build_modify_expr (location_t, tree, tree, enum tree_code, location_t, tree, tree); diff --git a/gcc/c-family/c-semantics.c b/gcc/c-family/c-semantics.c index 322b26b..fbe204a 100644 --- a/gcc/c-family/c-semantics.c +++ b/gcc/c-family/c-semantics.c @@ -126,6 +126,40 @@ pop_stmt_list (tree t) return t; } +/* If T is a statement_list, and it contains a single non-debug-statement, + then return that non-debug-statement. + Otherwise return T. */ + +tree +get_any_single_nondebug_stmt_in_list (tree t) +{ + if (TREE_CODE (t) != STATEMENT_LIST) + return t; + + /* Locate first non-debug stmt in T. */ + tree_stmt_iterator i; + for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) + { + tree u = tsi_stmt (i); + if (TREE_CODE (u) == DEBUG_BEGIN_STMT) + continue; + /* First non-debug stmt. */ + break; + } + + if (tsi_end_p (i)) + return t; + + tree first_non_debug = tsi_stmt (i); + gcc_assert (TREE_CODE (first_non_debug) != DEBUG_BEGIN_STMT); + + /* Are there any other non-debug stmts? */ + if (only_debug_stmts_after_p (i)) + return first_non_debug; + else + return t; +} + /* Build a generic statement based on the given type of node and arguments. Similar to `build_nt', except that we set EXPR_LOCATION to LOC. */ diff --git a/gcc/cp/search.c b/gcc/cp/search.c index ddcff69..a910c22 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -1757,6 +1757,11 @@ field_accessor_p (tree fn, tree field_decl, bool const_p) if (saved_tree == NULL_TREE) return false; + /* Attempt to extract a single RETURN_EXPR from within the + STATEMENT_LIST. pop_stmt_list may already have done this + when -g or optimization are off. */ + saved_tree = get_any_single_nondebug_stmt_in_list (saved_tree); + if (TREE_CODE (saved_tree) != RETURN_EXPR) return false; 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..2a129e2 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/accessor-fixits-8.C @@ -0,0 +1,29 @@ +// { 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; } + +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