@@ -93,6 +93,12 @@ public:
set_location (make_location (m_loc, start, finish));
}
+ cp_expr& maybe_add_location_wrapper ()
+ {
+ m_value = maybe_wrap_with_location (m_value, m_loc);
+ return *this;
+ }
+
private:
tree m_value;
location_t m_loc;
@@ -1116,6 +1116,9 @@ struct GTY(()) tree_base {
SSA_NAME_IS_VIRTUAL_OPERAND in
SSA_NAME
+ EXPR_LOCATION_WRAPPER_P in
+ NON_LVALUE_EXPR, VIEW_CONVERT_EXPR
+
private_flag:
TREE_PRIVATE in
@@ -14066,6 +14066,40 @@ set_source_range (tree expr, source_range src_range)
return adhoc;
}
+/* Return EXPR, potentially wrapped with a node expression LOC,
+ if !CAN_HAVE_LOCATION_P (expr).
+
+ NON_LVALUE_EXPR is used for wrapping constants, apart from STRING_CST.
+ VIEW_CONVERT_EXPR is used for wrapping non-constants and STRING_CST.
+
+ Wrapper nodes can be identified using location_wrapper_p. */
+
+tree
+maybe_wrap_with_location (tree expr, location_t loc)
+{
+ if (expr == NULL)
+ return NULL;
+ if (loc == UNKNOWN_LOCATION)
+ return expr;
+ if (CAN_HAVE_LOCATION_P (expr))
+ return expr;
+ /* We should only be adding wrappers for constants and for decls,
+ or for some exceptional tree nodes (e.g. BASELINK in the C++ FE). */
+ gcc_assert (CONSTANT_CLASS_P (expr)
+ || DECL_P (expr)
+ || EXCEPTIONAL_CLASS_P (expr));
+
+ if (EXCEPTIONAL_CLASS_P (expr))
+ return expr;
+
+ tree_code code = (CONSTANT_CLASS_P (expr) && TREE_CODE (expr) != STRING_CST
+ ? NON_LVALUE_EXPR : VIEW_CONVERT_EXPR);
+ tree wrapper = build1_loc (loc, code, TREE_TYPE (expr), expr);
+ /* Mark this node as being a wrapper. */
+ EXPR_LOCATION_WRAPPER_P (wrapper) = 1;
+ return wrapper;
+}
+
/* Return the name of combined function FN, for debugging purposes. */
const char *
@@ -14436,6 +14470,54 @@ test_vector_cst_patterns ()
check_vector_cst_fill (elements, build_vector (vector_type, elements), 4);
}
+/* Verify location wrappers. */
+
+static void
+test_location_wrappers ()
+{
+ location_t loc = BUILTINS_LOCATION;
+
+ /* Wrapping a constant. */
+ tree int_cst = build_int_cst (integer_type_node, 42);
+ ASSERT_FALSE (CAN_HAVE_LOCATION_P (int_cst));
+ ASSERT_FALSE (location_wrapper_p (int_cst));
+
+ tree wrapped_int_cst = maybe_wrap_with_location (int_cst, loc);
+ ASSERT_TRUE (location_wrapper_p (wrapped_int_cst));
+ ASSERT_EQ (loc, EXPR_LOCATION (wrapped_int_cst));
+ ASSERT_EQ (int_cst, tree_strip_any_location_wrapper (wrapped_int_cst));
+
+ /* Wrapping a STRING_CST. */
+ tree string_cst = build_string (4, "foo");
+ ASSERT_FALSE (CAN_HAVE_LOCATION_P (string_cst));
+ ASSERT_FALSE (location_wrapper_p (string_cst));
+
+ tree wrapped_string_cst = maybe_wrap_with_location (string_cst, loc);
+ ASSERT_TRUE (location_wrapper_p (wrapped_string_cst));
+ ASSERT_EQ (VIEW_CONVERT_EXPR, TREE_CODE (wrapped_string_cst));
+ ASSERT_EQ (loc, EXPR_LOCATION (wrapped_string_cst));
+ ASSERT_EQ (string_cst, tree_strip_any_location_wrapper (wrapped_string_cst));
+
+
+ /* Wrapping a variable. */
+ tree int_var = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier ("some_int_var"),
+ integer_type_node);
+ ASSERT_FALSE (CAN_HAVE_LOCATION_P (int_var));
+ ASSERT_FALSE (location_wrapper_p (int_var));
+
+ tree wrapped_int_var = maybe_wrap_with_location (int_var, loc);
+ ASSERT_TRUE (location_wrapper_p (wrapped_int_var));
+ ASSERT_EQ (loc, EXPR_LOCATION (wrapped_int_var));
+ ASSERT_EQ (int_var, tree_strip_any_location_wrapper (wrapped_int_var));
+
+ /* Verify that "reinterpret_cast<int>(some_int_var)" is not a location
+ wrapper. */
+ tree r_cast = build1 (NON_LVALUE_EXPR, integer_type_node, int_var);
+ ASSERT_FALSE (location_wrapper_p (r_cast));
+ ASSERT_EQ (r_cast, tree_strip_any_location_wrapper (r_cast));
+}
+
/* Run all of the selftests within this file. */
void
@@ -14445,6 +14527,7 @@ tree_c_tests ()
test_identifiers ();
test_labels ();
test_vector_cst_patterns ();
+ test_location_wrappers ();
}
} // namespace selftest
@@ -483,6 +483,12 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
#define STRIP_USELESS_TYPE_CONVERSION(EXP) \
(EXP) = tree_ssa_strip_useless_type_conversions (EXP)
+/* Remove any VIEW_CONVERT_EXPR or NON_LVALUE_EXPR that's purely
+ in use to provide a location_t. */
+
+#define STRIP_ANY_LOCATION_WRAPPER(EXP) \
+ (EXP) = tree_strip_any_location_wrapper (CONST_CAST_TREE (EXP))
+
/* Nonzero if TYPE represents a vector type. */
#define VECTOR_TYPE_P(TYPE) (TREE_CODE (TYPE) == VECTOR_TYPE)
@@ -1180,6 +1186,8 @@ get_expr_source_range (tree expr)
extern void protected_set_expr_location (tree, location_t);
+extern tree maybe_wrap_with_location (tree, location_t);
+
/* In a TARGET_EXPR node. */
#define TARGET_EXPR_SLOT(NODE) TREE_OPERAND_CHECK_CODE (NODE, TARGET_EXPR, 0)
#define TARGET_EXPR_INITIAL(NODE) TREE_OPERAND_CHECK_CODE (NODE, TARGET_EXPR, 1)
@@ -3677,6 +3685,45 @@ id_equal (const char *str, const_tree id)
return !strcmp (str, IDENTIFIER_POINTER (id));
}
+/* In NON_LVALUE_EXPR and VIEW_CONVERT_EXPR, set when this node is merely a
+ wrapper added to express a location_t on behalf of the node's child
+ (e.g. by maybe_wrap_with_location). */
+
+#define EXPR_LOCATION_WRAPPER_P(NODE) \
+ (TREE_CHECK2(NODE, NON_LVALUE_EXPR, VIEW_CONVERT_EXPR)->base.public_flag)
+
+/* Test if EXP is merely a wrapper node, added to express a location_t
+ on behalf of the node's child (e.g. by maybe_wrap_with_location). */
+
+inline bool
+location_wrapper_p (const_tree exp)
+{
+ /* A wrapper node has code NON_LVALUE_EXPR or VIEW_CONVERT_EXPR, and
+ the flag EXPR_LOCATION_WRAPPER_P is set.
+ It normally has the same type as its operand, but it can have a
+ different one if the type of the operand has changed (e.g. when
+ merging duplicate decls).
+
+ NON_LVALUE_EXPR is used for wrapping constants, apart from STRING_CST.
+ VIEW_CONVERT_EXPR is used for wrapping non-constants and STRING_CST. */
+ if ((TREE_CODE (exp) == NON_LVALUE_EXPR
+ || TREE_CODE (exp) == VIEW_CONVERT_EXPR)
+ && EXPR_LOCATION_WRAPPER_P (exp))
+ return true;
+ return false;
+}
+
+/* Implementation of STRIP_ANY_LOCATION_WRAPPER. */
+
+inline tree
+tree_strip_any_location_wrapper (tree exp)
+{
+ if (location_wrapper_p (exp))
+ return TREE_OPERAND (exp, 0);
+ else
+ return exp;
+}
+
#define error_mark_node global_trees[TI_ERROR_MARK]
#define intQI_type_node global_trees[TI_INTQI_TYPE]