[PATCH v2] C++: show private field accessor hints with -g and optimization (PR c++/84994)

David Malcolm dmalcolm@redhat.com
Wed Mar 21 17:02:00 GMT 2018


On Tue, 2018-03-20 at 21:51 -0400, Jason Merrill wrote:
> On Tue, Mar 20, 2018 at 7:37 PM, David Malcolm <dmalcolm@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



More information about the Gcc-patches mailing list