From a8a3b6a0513cd3aeb340443128543171024c44d5 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 31 Oct 2018 18:54:07 -0400
Subject: [PATCH 51/83] FIXME: a different fix for the wrapper thing

---
 gcc/convert.c            | 108 +++++++++++++++++++++++++++++++++++++++++++----
 gcc/cp/constexpr.c       |  15 ++++---
 gcc/selftest-run-tests.c |   1 +
 gcc/selftest.h           |   1 +
 gcc/tree.h               |   6 +++
 5 files changed, 117 insertions(+), 14 deletions(-)

diff --git a/gcc/convert.c b/gcc/convert.c
index 68705f3..99a04c4 100644
--- a/gcc/convert.c
+++ b/gcc/convert.c
@@ -36,6 +36,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "stringpool.h"
 #include "attribs.h"
 #include "asan.h"
+#include "selftest.h"
 
 #define maybe_fold_build1_loc(FOLD_P, LOC, CODE, TYPE, EXPR) \
   ((FOLD_P) ? fold_build1_loc (LOC, CODE, TYPE, EXPR)	     \
@@ -98,6 +99,25 @@ convert_to_pointer_1 (tree type, tree expr, bool fold_p)
     }
 }
 
+/* Subroutine of the various convert_to_*_maybe_fold routines.
+
+   If a location wrapper has been folded to a constant (presumably of
+   a different type), re-wrap the new constant with a location wrapper.  */
+
+static tree
+preserve_any_location_wrapper (tree result, tree orig_expr)
+{
+  if (CONSTANT_CLASS_P (result) && location_wrapper_p (orig_expr))
+    {
+      if (result == TREE_OPERAND (orig_expr, 0))
+	return orig_expr;
+      else
+	return maybe_wrap_with_location (result, EXPR_LOCATION (orig_expr));
+    }
+
+  return result;
+}
+
 /* A wrapper around convert_to_pointer_1 that always folds the
    expression.  */
 
@@ -108,12 +128,15 @@ convert_to_pointer (tree type, tree expr)
 }
 
 /* A wrapper around convert_to_pointer_1 that only folds the
-   expression if DOFOLD, or if it is CONSTANT_CLASS_P.  */
+   expression if DOFOLD, or if it is CONSTANT_CLASS_OR_WRAPPER_P.  */
 
 tree
 convert_to_pointer_maybe_fold (tree type, tree expr, bool dofold)
 {
-  return convert_to_pointer_1 (type, expr, dofold || CONSTANT_CLASS_P (expr));
+  tree result
+    = convert_to_pointer_1 (type, expr,
+			    dofold || CONSTANT_CLASS_OR_WRAPPER_P (expr));
+  return preserve_any_location_wrapper (result, expr);
 }
 
 /* Convert EXPR to some floating-point type TYPE.
@@ -408,12 +431,15 @@ convert_to_real (tree type, tree expr)
 }
 
 /* A wrapper around convert_to_real_1 that only folds the
-   expression if DOFOLD, or if it is CONSTANT_CLASS_P.  */
+   expression if DOFOLD, or if it is CONSTANT_CLASS_OR_WRAPPER_P.  */
 
 tree
 convert_to_real_maybe_fold (tree type, tree expr, bool dofold)
 {
-  return convert_to_real_1 (type, expr, dofold || CONSTANT_CLASS_P (expr));
+  tree result
+    = convert_to_real_1 (type, expr,
+			 dofold || CONSTANT_CLASS_OR_WRAPPER_P (expr));
+  return preserve_any_location_wrapper (result, expr);
 }
 
 /* Try to narrow EX_FORM ARG0 ARG1 in narrowed arg types producing a
@@ -1017,12 +1043,15 @@ convert_to_integer (tree type, tree expr)
 }
 
 /* A wrapper around convert_to_complex_1 that only folds the
-   expression if DOFOLD, or if it is CONSTANT_CLASS_P.  */
+   expression if DOFOLD, or if it is CONSTANT_CLASS_OR_WRAPPER_P.  */
 
 tree
 convert_to_integer_maybe_fold (tree type, tree expr, bool dofold)
 {
-  return convert_to_integer_1 (type, expr, dofold || CONSTANT_CLASS_P (expr));
+  tree result
+    = convert_to_integer_1 (type, expr,
+			    dofold || CONSTANT_CLASS_OR_WRAPPER_P (expr));
+  return preserve_any_location_wrapper (result, expr);
 }
 
 /* Convert EXPR to the complex type TYPE in the usual ways.  If FOLD_P is
@@ -1101,12 +1130,15 @@ convert_to_complex (tree type, tree expr)
 }
 
 /* A wrapper around convert_to_complex_1 that only folds the
-   expression if DOFOLD, or if it is CONSTANT_CLASS_P.  */
+   expression if DOFOLD, or if it is CONSTANT_CLASS_OR_WRAPPER_P.  */
 
 tree
 convert_to_complex_maybe_fold (tree type, tree expr, bool dofold)
 {
-  return convert_to_complex_1 (type, expr, dofold || CONSTANT_CLASS_P (expr));
+  tree result
+    = convert_to_complex_1 (type, expr,
+			    dofold || CONSTANT_CLASS_OR_WRAPPER_P (expr));
+  return preserve_any_location_wrapper (result, expr);
 }
 
 /* Convert EXPR to the vector type TYPE in the usual ways.  */
@@ -1171,3 +1203,63 @@ convert_to_fixed (tree type, tree expr)
       return error_mark_node;
     }
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests for conversions.  */
+
+/* Verify that convert_to_integer_maybe_fold preserves locations.  */
+
+static void
+test_convert_to_integer_maybe_fold ()
+{
+  location_t loc = BUILTINS_LOCATION;
+
+  /* char -> long.
+     Verify that convert_to_integer_maybe_fold on a constant returns a new
+     constant of the new type.   */
+  tree int_cst = build_int_cst (char_type_node, 42);
+  tree result = convert_to_integer_maybe_fold (long_integer_type_node,
+					       int_cst, false);
+  ASSERT_EQ (TREE_TYPE (result), long_integer_type_node);
+  ASSERT_EQ (TREE_CODE (result), INTEGER_CST);
+
+  /* char -> long.
+     Verify that convert_to_integer_maybe_fold on a location wrapper
+     around a constant returns a new location wrapper around an equivalent
+     constant, both of the new type.   */
+  tree wrapped_int_cst = maybe_wrap_with_location (int_cst, loc);
+  result = convert_to_integer_maybe_fold (long_integer_type_node,
+					  wrapped_int_cst, false);
+  ASSERT_EQ (TREE_TYPE (result), long_integer_type_node);
+  ASSERT_EQ (EXPR_LOCATION (result), loc);
+  ASSERT_TRUE (location_wrapper_p (result));
+  ASSERT_EQ (TREE_TYPE (TREE_OPERAND (result, 0)), long_integer_type_node);
+  ASSERT_EQ (TREE_CODE (TREE_OPERAND (result, 0)), INTEGER_CST);
+
+  /* char -> char.
+     Verify that a no-op conversion on a constant is indeed a no-op.  */
+  result = convert_to_integer_maybe_fold (char_type_node,
+					  int_cst, false);
+  ASSERT_EQ (result, int_cst);
+
+  /* char -> char.
+     Verify that a no-op conversion on a wrapped constant is indeed a no-op.  */
+  result = convert_to_integer_maybe_fold (char_type_node,
+					  wrapped_int_cst, false);
+  ASSERT_EQ (result, wrapped_int_cst);
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+convert_c_tests ()
+{
+  test_convert_to_integer_maybe_fold ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 7a5f4cc..00f639b 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -5700,13 +5700,16 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
         tree from = TREE_OPERAND (t, 0);
 	if (location_wrapper_p (t))
 	  return (RECUR (from, want_rval));
-	if (INDIRECT_TYPE_P (TREE_TYPE (t))
-	    && TREE_CODE (from) == INTEGER_CST
-	    && !integer_zerop (from))
+	if (INDIRECT_TYPE_P (TREE_TYPE (t)))
 	  {
-	    if (flags & tf_error)
-	      error_at (loc, "reinterpret_cast from integer to pointer");
-	    return false;
+	    STRIP_ANY_LOCATION_WRAPPER (from);
+	    if (TREE_CODE (from) == INTEGER_CST
+		&& !integer_zerop (from))
+	      {
+		if (flags & tf_error)
+		  error_at (loc, "reinterpret_cast from integer to pointer");
+		return false;
+	      }
 	  }
         return (RECUR (from, TREE_CODE (t) != VIEW_CONVERT_EXPR));
       }
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index 562ada7..8149b90 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -80,6 +80,7 @@ selftest::run_tests ()
   input_c_tests ();
   vec_perm_indices_c_tests ();
   tree_c_tests ();
+  convert_c_tests ();
   gimple_c_tests ();
   rtl_tests_c_tests ();
   read_rtl_function_c_tests ();
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 8da7c4a..74be3b7 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -215,6 +215,7 @@ class test_runner
    alphabetical order.  */
 extern void attribute_c_tests ();
 extern void bitmap_c_tests ();
+extern void convert_c_tests ();
 extern void diagnostic_c_tests ();
 extern void diagnostic_show_locus_c_tests ();
 extern void dumpfile_c_tests ();
diff --git a/gcc/tree.h b/gcc/tree.h
index 6dce26c..b259322 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -131,6 +131,12 @@ as_internal_fn (combined_fn code)
 #define CONSTANT_CLASS_P(NODE)\
 	(TREE_CODE_CLASS (TREE_CODE (NODE)) == tcc_constant)
 
+/* Nonzero if NODE represents a constant, or is a location wrapper
+   around such a node.  */
+
+#define CONSTANT_CLASS_OR_WRAPPER_P(NODE)\
+	(CONSTANT_CLASS_P (tree_strip_any_location_wrapper (NODE)))
+
 /* Nonzero if NODE represents a type.  */
 
 #define TYPE_P(NODE)\
-- 
1.8.5.3

