[v2,of,08/14] cp/tree.c: strip location wrappers in lvalue_kind

Message ID 1513808092-23811-1-git-send-email-dmalcolm@redhat.com
State New
Headers show
Series
  • Untitled series #252
Related show

Commit Message

David Malcolm Dec. 20, 2017, 10:14 p.m.
On Mon, 2017-12-11 at 18:39 -0500, Jason Merrill wrote:
> On 11/10/2017 04:45 PM, David Malcolm wrote:

> > Without this, then lvalue_p returns false for decls, and hence

> > e.g. uses of them for references fail.

> > 

> > Stripping location wrappers in lvalue_kind restores the correct

> > behavior of lvalue_p etc.

> > 

> > gcc/cp/ChangeLog:

> > 	* tree.c (lvalue_kind): Strip any location wrapper.

> 

> Rather, lvalue_kind should learn to handle VIEW_CONVERT_EXPR.

> 

> Jason


Thanks.

This patch does so, using:

    case NON_LVALUE_EXPR:
    case VIEW_CONVERT_EXPR:
      if (location_wrapper_p (ref))
	return lvalue_kind (TREE_OPERAND (ref, 0));

As well as the VIEW_CONVERT_EXPR, lvalue_kind needs to handle
NON_LVALUE_EXPR, otherwise a location-wrapped string literal
hits this clause in the "default" case:

      if (CLASS_TYPE_P (TREE_TYPE (ref))
	  || TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE)
	return clk_class;

when it should have hit this one (after removing the
location wrapper):

    case STRING_CST:
    case COMPOUND_LITERAL_EXPR:
      return clk_ordinary;

The patch adds selftest coverage for this case (and others).

Seen in e.g. libstdc++.sum's 21_strings/basic_string/cons/char/8.cc, which
would otherwise fail with this bogus error:

8.cc: In instantiation of 'std::size_t construct(Args&& ...)
  [with Args = {const char [9], int}; std::size_t = long unsigned int]':
8.cc:63:   required from here
8.cc:38: error: invalid static_cast from type 'const char [9]' to type 'const char [9]'
   TestBaseObjCtor as_base_obj( static_cast<Args>(args)... );
                                ^~~~~~~~~~~~~~~~~~~~~~~

Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu, as
part of the kit.
Also, manually tested with "make s-selftest-c++" (since we don't run
the selftests for cc1plus by default).

OK for trunk once the rest of the kit is approved?

gcc/cp/ChangeLog:
	* cp-lang.c (selftest::run_cp_tests): Call
	selftest::cp_tree_c_tests.
	* cp-tree.h (selftest::cp_tree_c_tests): New decl.
	* tree.c: Include "selftest.h".
	(lvalue_kind): Handle location wrapper nodes.
	(selftest::test_lvalue_kind): New function.
	(selftest::cp_tree_c_tests): New function.
---
 gcc/cp/cp-lang.c |  1 +
 gcc/cp/cp-tree.h |  8 +++++++
 gcc/cp/tree.c    | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 76 insertions(+)

-- 
1.8.5.3

Comments

Jason Merrill Dec. 21, 2017, 4:56 a.m. | #1
On Wed, Dec 20, 2017 at 5:14 PM, David Malcolm <dmalcolm@redhat.com> wrote:
> On Mon, 2017-12-11 at 18:39 -0500, Jason Merrill wrote:

>> On 11/10/2017 04:45 PM, David Malcolm wrote:

>> > Without this, then lvalue_p returns false for decls, and hence

>> > e.g. uses of them for references fail.

>> >

>> > Stripping location wrappers in lvalue_kind restores the correct

>> > behavior of lvalue_p etc.

>> >

>> > gcc/cp/ChangeLog:

>> >     * tree.c (lvalue_kind): Strip any location wrapper.

>>

>> Rather, lvalue_kind should learn to handle VIEW_CONVERT_EXPR.


> This patch does so, using:

>

>     case NON_LVALUE_EXPR:

>     case VIEW_CONVERT_EXPR:

>       if (location_wrapper_p (ref))

>         return lvalue_kind (TREE_OPERAND (ref, 0));

>

> As well as the VIEW_CONVERT_EXPR, lvalue_kind needs to handle

> NON_LVALUE_EXPR, otherwise a location-wrapped string literal

> hits this clause in the "default" case:

>

>       if (CLASS_TYPE_P (TREE_TYPE (ref))

>           || TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE)

>         return clk_class;

>

> when it should have hit this one (after removing the

> location wrapper):

>

>     case STRING_CST:

>     case COMPOUND_LITERAL_EXPR:

>       return clk_ordinary;


Ah, the issue is that string literals should use VIEW_CONVERT_EXPR
rather than NON_LVALUE_EXPR, since they are lvalues.  With that
change, we shouldn't need to handle NON_LVALUE_EXPR specifically.

Jason

Patch

diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c
index 805319a..9bb4ce7 100644
--- a/gcc/cp/cp-lang.c
+++ b/gcc/cp/cp-lang.c
@@ -247,6 +247,7 @@  run_cp_tests (void)
   c_family_tests ();
 
   /* Additional C++-specific tests.  */
+  cp_tree_c_tests ();
 }
 
 } // namespace selftest
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 9879e16..6d4a2b8a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7451,6 +7451,14 @@  named_decl_hash::equal (const value_type existing, compare_type candidate)
   return candidate == name;
 }
 
+#if CHECKING_P
+namespace selftest {
+  /* Declarations for specific families of tests within cp,
+     by source file, in alphabetical order.  */
+  extern void cp_tree_c_tests (void);
+} // namespace selftest
+#endif /* #if CHECKING_P */
+
 /* -- end of C++ */
 
 #endif /* ! GCC_CP_TREE_H */
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 0ae2eff..ad8884c 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -35,6 +35,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "stringpool.h"
 #include "attribs.h"
 #include "flags.h"
+#include "selftest.h"
 
 static tree bot_manip (tree *, int *, void *);
 static tree bot_replace (tree *, int *, void *);
@@ -240,6 +241,12 @@  lvalue_kind (const_tree ref)
     case NON_DEPENDENT_EXPR:
       return lvalue_kind (TREE_OPERAND (ref, 0));
 
+    case NON_LVALUE_EXPR:
+    case VIEW_CONVERT_EXPR:
+      if (location_wrapper_p (ref))
+	return lvalue_kind (TREE_OPERAND (ref, 0));
+      /* Fallthrough.  */
+
     default:
       if (!TREE_TYPE (ref))
 	return clk_none;
@@ -5339,4 +5346,64 @@  lang_check_failed (const char* file, int line, const char* function)
 }
 #endif /* ENABLE_TREE_CHECKING */
 
+#if CHECKING_P
+
+namespace selftest {
+
+/* Verify that lvalue_kind () works, for various expressions,
+   and that location wrappers don't affect the results.  */
+
+static void
+test_lvalue_kind ()
+{
+  location_t loc = BUILTINS_LOCATION;
+
+  /* Verify constants and parameters, without and with
+     location wrappers.  */
+  tree int_cst = build_int_cst (integer_type_node, 42);
+  ASSERT_EQ (clk_none, lvalue_kind (integer_zero_node));
+
+  tree wrapped_int_cst = maybe_wrap_with_location (int_cst, loc);
+  ASSERT_TRUE (location_wrapper_p (wrapped_int_cst));
+  ASSERT_EQ (clk_none, lvalue_kind (integer_zero_node));
+
+  tree string_lit = build_string (3, "foo");
+  TREE_TYPE (string_lit) = char_array_type_node;
+  string_lit = fix_string_type (string_lit);
+  ASSERT_EQ (clk_ordinary, lvalue_kind (string_lit));
+
+  tree wrapped_string_lit = maybe_wrap_with_location (string_lit, loc);
+  ASSERT_TRUE (location_wrapper_p (wrapped_string_lit));
+  ASSERT_EQ (clk_ordinary, lvalue_kind (wrapped_string_lit));
+
+  tree parm = build_decl (UNKNOWN_LOCATION, PARM_DECL,
+			  get_identifier ("some_parm"),
+			  integer_type_node);
+  ASSERT_EQ (clk_ordinary, lvalue_kind (parm));
+
+  tree wrapped_parm = maybe_wrap_with_location (parm, loc);
+  ASSERT_TRUE (location_wrapper_p (wrapped_parm));
+  ASSERT_EQ (clk_ordinary, lvalue_kind (parm));
+
+  /* Verify that lvalue_kind of std::move on a parm isn't
+     affected by location wrappers.  */
+  tree rvalue_ref_of_parm = move (parm);
+  ASSERT_EQ (clk_rvalueref, lvalue_kind (rvalue_ref_of_parm));
+  tree rvalue_ref_of_wrapped_parm = move (wrapped_parm);
+  ASSERT_EQ (clk_rvalueref, lvalue_kind (rvalue_ref_of_wrapped_parm));
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+cp_tree_c_tests ()
+{
+  test_lvalue_kind ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
+
+
 #include "gt-cp-tree.h"