This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH 2/2] C++: show private field accessor hints with -g and optimization (PR c++/84994)
- From: David Malcolm <dmalcolm at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: David Malcolm <dmalcolm at redhat dot com>
- Date: Tue, 20 Mar 2018 19:37:12 -0400
- Subject: [PATCH 2/2] C++: show private field accessor hints with -g and optimization (PR c++/84994)
- References: <1521589032-55200-1-git-send-email-dmalcolm@redhat.com>
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