+2018-01-10 David Malcolm <dmalcolm@redhat.com>
+
+ PR c++/43486
+ * tree-core.h: Document EXPR_LOCATION_WRAPPER_P's usage of
+ "public_flag".
+ * tree.c (tree_nop_conversion): Return true for location wrapper
+ nodes.
+ (maybe_wrap_with_location): New function.
+ (selftest::check_strip_nops): New function.
+ (selftest::test_location_wrappers): New function.
+ (selftest::tree_c_tests): Call it.
+ * tree.h (STRIP_ANY_LOCATION_WRAPPER): New macro.
+ (maybe_wrap_with_location): New decl.
+ (EXPR_LOCATION_WRAPPER_P): New macro.
+ (location_wrapper_p): New inline function.
+ (tree_strip_any_location_wrapper): New inline function.
+
2018-01-10 H.J. Lu <hongjiu.lu@intel.com>
PR target/83735
+2018-01-10 David Malcolm <dmalcolm@redhat.com>
+
+ PR c++/43486
+ * c-common.c: Include "selftest.h".
+ (get_atomic_generic_size): Perform the test for integral type
+ before the range test for any integer constant, fixing indentation
+ of braces. Call fold_for_warn before testing for an INTEGER_CST.
+ (reject_gcc_builtin): Strip any location wrapper from EXPR.
+ (selftest::test_fold_for_warn): New function.
+ (selftest::c_common_c_tests): New function.
+ (selftest::c_family_tests): Call it, and
+ selftest::c_pretty_print_c_tests.
+ * c-common.h (selftest::c_pretty_print_c_tests): New decl.
+ * c-format.c (check_format_arg): Convert VAR_P check to a
+ fold_for_warn.
+ * c-pretty-print.c: Include "selftest.h".
+ (pp_c_cast_expression): Don't print casts for location wrappers.
+ (selftest::assert_c_pretty_printer_output): New function.
+ (ASSERT_C_PRETTY_PRINTER_OUTPUT): New macro.
+ (selftest::test_location_wrappers): New function.
+ (selftest::c_pretty_print_c_tests): New function.
+ * c-warn.c (warn_for_memset): Call fold_for_warn on the arguments.
+
2018-01-03 Richard Sandiford <richard.sandiford@linaro.org>
Alan Hayward <alan.hayward@arm.com>
David Sherwood <david.sherwood@arm.com>
#include "gimplify.h"
#include "substring-locations.h"
#include "spellcheck.h"
+#include "selftest.h"
cpp_reader *parse_in; /* Declared in c-pragma.h. */
for (x = n_param - n_model ; x < n_param; x++)
{
tree p = (*params)[x];
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (p)))
+ {
+ error_at (loc, "non-integer memory model argument %d of %qE", x + 1,
+ function);
+ return 0;
+ }
+ p = fold_for_warn (p);
if (TREE_CODE (p) == INTEGER_CST)
- {
+ {
/* memmodel_base masks the low 16 bits, thus ignore any bits above
it by using TREE_INT_CST_LOW instead of tree_to_*hwi. Those high
bits will be checked later during expansion in target specific
"invalid memory model argument %d of %qE", x + 1,
function);
}
- else
- if (!INTEGRAL_TYPE_P (TREE_TYPE (p)))
- {
- error_at (loc, "non-integer memory model argument %d of %qE", x + 1,
- function);
- return 0;
- }
- }
+ }
return size_0;
}
if (TREE_CODE (expr) == ADDR_EXPR)
expr = TREE_OPERAND (expr, 0);
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+
if (TREE_TYPE (expr)
&& TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE
&& TREE_CODE (expr) == FUNCTION_DECL
namespace selftest {
+/* Verify that fold_for_warn on error_mark_node is safe. */
+
+static void
+test_fold_for_warn ()
+{
+ ASSERT_EQ (error_mark_node, fold_for_warn (error_mark_node));
+}
+
+/* Run all of the selftests within this file. */
+
+static void
+c_common_c_tests ()
+{
+ test_fold_for_warn ();
+}
+
/* Run all of the tests within c-family. */
void
c_family_tests (void)
{
+ c_common_c_tests ();
c_format_c_tests ();
+ c_pretty_print_c_tests ();
c_spellcheck_cc_tests ();
}
/* Declarations for specific families of tests within c-family,
by source file, in alphabetical order. */
extern void c_format_c_tests (void);
+ extern void c_pretty_print_c_tests (void);
extern void c_spellcheck_cc_tests (void);
/* The entrypoint for running all of the above tests. */
location_t fmt_param_loc = EXPR_LOC_OR_LOC (format_tree, input_location);
- if (VAR_P (format_tree))
- {
- /* Pull out a constant value if the front end didn't. */
- format_tree = decl_constant_value (format_tree);
- STRIP_NOPS (format_tree);
- }
+ /* Pull out a constant value if the front end didn't, and handle location
+ wrappers. */
+ format_tree = fold_for_warn (format_tree);
+ STRIP_NOPS (format_tree);
if (integer_zerop (format_tree))
{
#include "attribs.h"
#include "intl.h"
#include "tree-pretty-print.h"
+#include "selftest.h"
/* The pretty-printer code is primarily designed to closely follow
(GNU) C and C++ grammars. That is to be contrasted with spaghetti
case FIX_TRUNC_EXPR:
CASE_CONVERT:
case VIEW_CONVERT_EXPR:
- pp_c_type_cast (pp, TREE_TYPE (e));
+ if (!location_wrapper_p (e))
+ pp_c_type_cast (pp, TREE_TYPE (e));
pp_c_cast_expression (pp, TREE_OPERAND (e, 0));
break;
pp_c_identifier (pp, name);
}
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests for pretty-printing trees. */
+
+/* Verify that EXPR printed by c_pretty_printer is EXPECTED, using
+ LOC as the effective location for any failures. */
+
+static void
+assert_c_pretty_printer_output (const location &loc, const char *expected,
+ tree expr)
+{
+ c_pretty_printer pp;
+ pp.expression (expr);
+ ASSERT_STREQ_AT (loc, expected, pp_formatted_text (&pp));
+}
+
+/* Helper function for calling assert_c_pretty_printer_output.
+ This is to avoid having to write SELFTEST_LOCATION. */
+
+#define ASSERT_C_PRETTY_PRINTER_OUTPUT(EXPECTED, EXPR) \
+ SELFTEST_BEGIN_STMT \
+ assert_c_pretty_printer_output ((SELFTEST_LOCATION), \
+ (EXPECTED), \
+ (EXPR)); \
+ SELFTEST_END_STMT
+
+/* Verify that location wrappers don't show up in pretty-printed output. */
+
+static void
+test_location_wrappers ()
+{
+ /* VAR_DECL. */
+ tree id = get_identifier ("foo");
+ tree decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, id,
+ integer_type_node);
+ tree wrapped_decl = maybe_wrap_with_location (decl, BUILTINS_LOCATION);
+ ASSERT_NE (wrapped_decl, decl);
+ ASSERT_C_PRETTY_PRINTER_OUTPUT ("foo", decl);
+ ASSERT_C_PRETTY_PRINTER_OUTPUT ("foo", wrapped_decl);
+
+ /* INTEGER_CST. */
+ tree int_cst = build_int_cst (integer_type_node, 42);
+ tree wrapped_cst = maybe_wrap_with_location (int_cst, BUILTINS_LOCATION);
+ ASSERT_NE (wrapped_cst, int_cst);
+ ASSERT_C_PRETTY_PRINTER_OUTPUT ("42", int_cst);
+ ASSERT_C_PRETTY_PRINTER_OUTPUT ("42", wrapped_cst);
+}
+
+/* Run all of the selftests within this file. */
+
+void
+c_pretty_print_c_tests ()
+{
+ test_location_wrappers ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
warn_for_memset (location_t loc, tree arg0, tree arg2,
int literal_zero_mask)
{
+ arg0 = fold_for_warn (arg0);
+ arg2 = fold_for_warn (arg2);
+
if (warn_memset_transposed_args
&& integer_zerop (arg2)
&& (literal_zero_mask & (1 << 2)) != 0
+2018-01-10 David Malcolm <dmalcolm@redhat.com>
+
+ PR c++/43486
+ * call.c (null_ptr_cst_p): Strip location wrappers when
+ converting from '0' to a pointer type in C++11 onwards.
+ (conversion_null_warnings): Replace comparison with null_node with
+ call to null_node_p.
+ (build_over_call): Likewise.
+ * cp-gimplify.c (cp_fold): Remove the early bailout when
+ processing_template_decl.
+ * cp-lang.c (selftest::run_cp_tests): Call
+ selftest::cp_pt_c_tests and selftest::cp_tree_c_tests.
+ * cp-tree.h (cp_expr::maybe_add_location_wrapper): New method.
+ (selftest::run_cp_tests): Move decl to bottom of file.
+ (null_node_p): New inline function.
+ (selftest::cp_pt_c_tests): New decl.
+ (selftest::cp_tree_c_tests): New decl.
+ * cvt.c (build_expr_type_conversion): Replace comparison with
+ null_node with call to null_node_p.
+ * error.c (args_to_string): Likewise.
+ * except.c (build_throw): Likewise.
+ * mangle.c (write_expression): Skip location wrapper nodes.
+ * parser.c (literal_integer_zerop): New function.
+ (cp_parser_postfix_expression): Call maybe_add_location_wrapper on
+ the result for RID_TYPEID. Pass true for new "wrap_locations_p"
+ param of cp_parser_parenthesized_expression_list. When calling
+ warn_for_memset, replace integer_zerop calls with
+ literal_integer_zerop, eliminating the double logical negation
+ cast to bool. Eliminate the special-casing for CONST_DECL in
+ favor of the fold_for_warn within warn_for_memset.
+ (cp_parser_parenthesized_expression_list): Add "wrap_locations_p"
+ param, defaulting to false. Convert "expr" to a cp_expr, and call
+ maybe_add_location_wrapper on it when wrap_locations_p is true.
+ (cp_parser_unary_expression): Call maybe_add_location_wrapper on
+ the result for RID_ALIGNOF and RID_SIZEOF.
+ (cp_parser_builtin_offsetof): Likewise.
+ * pt.c: Include "selftest.h".
+ (tsubst_copy): Handle location wrappers.
+ (tsubst_copy_and_build): Likewise.
+ (build_non_dependent_expr): Likewise.
+ (selftest::test_build_non_dependent_expr): New function.
+ (selftest::cp_pt_c_tests): New function.
+ * tree.c: Include "selftest.h".
+ (lvalue_kind): Handle VIEW_CONVERT_EXPR location wrapper nodes.
+ (selftest::test_lvalue_kind): New function.
+ (selftest::cp_tree_c_tests): New function.
+ * typeck.c (string_conv_p): Strip any location wrapper from "exp".
+ (cp_build_binary_op): Replace comparison with null_node with call
+ to null_node_p.
+ (build_address): Use location of operand when building address
+ expression.
+
2018-01-10 Marek Polacek <polacek@redhat.com>
PR c++/82541
if (cxx_dialect >= cxx11)
{
+ STRIP_ANY_LOCATION_WRAPPER (t);
+
/* Core issue 903 says only literal 0 is a null pointer constant. */
if (TREE_CODE (type) == INTEGER_TYPE
&& !char_type_p (type)
conversion_null_warnings (tree totype, tree expr, tree fn, int argnum)
{
/* Issue warnings about peculiar, but valid, uses of NULL. */
- if (expr == null_node && TREE_CODE (totype) != BOOLEAN_TYPE
+ if (null_node_p (expr) && TREE_CODE (totype) != BOOLEAN_TYPE
&& ARITHMETIC_TYPE_P (totype))
{
source_location loc =
func(NULL);
}
*/
- if (arg == null_node
+ if (null_node_p (arg)
&& DECL_TEMPLATE_INFO (fn)
&& cand->template_decl
&& !(flags & LOOKUP_EXPLICIT_TMPL_ARGS))
/* This function tries to fold an expression X.
To avoid combinatorial explosion, folding results are kept in fold_cache.
- If we are processing a template or X is invalid, we don't fold at all.
+ If X is invalid, we don't fold at all.
For performance reasons we don't cache expressions representing a
declaration or constant.
Function returns X or its folded variant. */
if (!x || x == error_mark_node)
return x;
- if (processing_template_decl
- || (EXPR_P (x) && (!TREE_TYPE (x) || TREE_TYPE (x) == error_mark_node)))
+ if (EXPR_P (x) && (!TREE_TYPE (x) || TREE_TYPE (x) == error_mark_node))
return x;
/* Don't bother to cache DECLs or constants. */
c_family_tests ();
/* Additional C++-specific tests. */
+ cp_pt_c_tests ();
+ cp_tree_c_tests ();
}
} // namespace selftest
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;
extern tree cp_ubsan_maybe_instrument_cast_to_vbase (location_t, tree, tree);
extern void cp_ubsan_maybe_initialize_vtbl_ptrs (tree);
-#if CHECKING_P
-namespace selftest {
- extern void run_cp_tests (void);
-} // namespace selftest
-#endif /* #if CHECKING_P */
-
/* Inline bodies. */
inline tree
return candidate == name;
}
+inline bool
+null_node_p (const_tree expr)
+{
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+ return expr == null_node;
+}
+
+#if CHECKING_P
+namespace selftest {
+ extern void run_cp_tests (void);
+
+ /* Declarations for specific families of tests within cp,
+ by source file, in alphabetical order. */
+ extern void cp_pt_c_tests ();
+ extern void cp_tree_c_tests (void);
+} // namespace selftest
+#endif /* #if CHECKING_P */
+
/* -- end of C++ */
#endif /* ! GCC_CP_TREE_H */
tree conv = NULL_TREE;
tree winner = NULL_TREE;
- if (expr == null_node
+ if (null_node_p (expr)
&& (desires & WANT_INT)
&& !(desires & WANT_NULL))
{
reinit_cxx_pp ();
for (; p; p = TREE_CHAIN (p))
{
- if (TREE_VALUE (p) == null_node)
+ if (null_node_p (TREE_VALUE (p)))
pp_cxx_ws_string (cxx_pp, "NULL");
else
dump_type (cxx_pp, error_type (TREE_VALUE (p)), flags);
return exp;
}
- if (exp == null_node)
+ if (exp && null_node_p (exp))
warning (0, "throwing NULL, which has integral, not pointer type");
if (exp != NULL_TREE)
/* Skip NOP_EXPR and CONVERT_EXPR. They can occur when (say) a pointer
argument is converted (via qualification conversions) to another type. */
while (CONVERT_EXPR_CODE_P (code)
+ || location_wrapper_p (expr)
/* Parentheses aren't mangled. */
|| code == PAREN_EXPR
|| code == NON_LVALUE_EXPR)
static tree cp_parser_postfix_dot_deref_expression
(cp_parser *, enum cpp_ttype, cp_expr, bool, cp_id_kind *, location_t);
static vec<tree, va_gc> *cp_parser_parenthesized_expression_list
- (cp_parser *, int, bool, bool, bool *, location_t * = NULL);
+ (cp_parser *, int, bool, bool, bool *, location_t * = NULL,
+ bool = false);
/* Values for the second parameter of cp_parser_parenthesized_expression_list. */
enum { non_attr = 0, normal_attr = 1, id_attr = 2 };
static void cp_parser_pseudo_destructor_name
return compound_literal_p;
}
+/* Return true if EXPR is the integer constant zero or a complex constant
+ of zero, without any folding, but ignoring location wrappers. */
+
+static bool
+literal_integer_zerop (const_tree expr)
+{
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+ return integer_zerop (expr);
+}
+
/* Parse a postfix-expression.
postfix-expression:
location_t typeid_loc
= make_location (start_loc, start_loc, close_paren->location);
postfix_expression.set_location (typeid_loc);
+ postfix_expression.maybe_add_location_wrapper ();
}
}
break;
(parser, non_attr,
/*cast_p=*/false, /*allow_expansion_p=*/true,
/*non_constant_p=*/NULL,
- /*close_paren_loc=*/&close_paren_loc));
+ /*close_paren_loc=*/&close_paren_loc,
+ /*wrap_locations_p=*/true));
if (is_builtin_constant_p)
{
parser->integral_constant_expression_p
tree arg0 = (*args)[0];
tree arg1 = (*args)[1];
tree arg2 = (*args)[2];
- int literal_mask = ((!!integer_zerop (arg1) << 1)
- | (!!integer_zerop (arg2) << 2));
- if (TREE_CODE (arg2) == CONST_DECL)
- arg2 = DECL_INITIAL (arg2);
+ int literal_mask = ((literal_integer_zerop (arg1) << 1)
+ | (literal_integer_zerop (arg2) << 2));
warn_for_memset (input_location, arg0, arg2, literal_mask);
}
ALLOW_EXPANSION_P is true if this expression allows expansion of an
argument pack.
+ WRAP_LOCATIONS_P is true if expressions within this list for which
+ CAN_HAVE_LOCATION_P is false should be wrapped with nodes expressing
+ their source locations.
+
Returns a vector of trees. Each element is a representation of an
assignment-expression. NULL is returned if the ( and or ) are
missing. An empty, but allocated, vector is returned on no
bool cast_p,
bool allow_expansion_p,
bool *non_constant_p,
- location_t *close_paren_loc)
+ location_t *close_paren_loc,
+ bool wrap_locations_p)
{
vec<tree, va_gc> *expression_list;
bool fold_expr_p = is_attribute_list != non_attr;
= parser->greater_than_is_operator_p;
parser->greater_than_is_operator_p = true;
+ cp_expr expr (NULL_TREE);
+
/* Consume expressions until there are no more. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
while (true)
{
- tree expr;
-
/* At the beginning of attribute lists, check to see if the
next token is an identifier. */
if (is_attribute_list == id_attr
expr = make_pack_expansion (expr);
}
+ if (wrap_locations_p)
+ expr.maybe_add_location_wrapper ();
+
/* Add it to the list. We add error_mark_node
expressions to the list, so that we can still tell if
the correct form for a parenthesized expression-list
is found. That gives better errors. */
- vec_safe_push (expression_list, expr);
+ vec_safe_push (expression_list, expr.get_value ());
if (expr == error_mark_node)
goto skip_comma;
cp_expr ret_expr (ret);
ret_expr.set_location (compound_loc);
+ ret_expr = ret_expr.maybe_add_location_wrapper ();
return ret_expr;
}
parser->integral_constant_expression_p = save_ice_p;
parser->non_integral_constant_expression_p = save_non_ice_p;
+ expr = expr.maybe_add_location_wrapper ();
return expr;
}
#include "type-utils.h"
#include "gimplify.h"
#include "gcc-rich-location.h"
+#include "selftest.h"
/* The type of functions taking a tree, and some additional data, and
returning an int. */
/* Ordinary template template argument. */
return t;
+ case NON_LVALUE_EXPR:
+ case VIEW_CONVERT_EXPR:
+ {
+ /* Handle location wrappers by substituting the wrapped node
+ first, *then* reusing the resulting type. Doing the type
+ first ensures that we handle template parameters and
+ parameter pack expansions. */
+ gcc_assert (location_wrapper_p (t));
+ tree op0 = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
+ return maybe_wrap_with_location (op0, EXPR_LOCATION (t));
+ }
+
case CAST_EXPR:
case REINTERPRET_CAST_EXPR:
case CONST_CAST_EXPR:
case REQUIRES_EXPR:
RETURN (tsubst_requires_expr (t, args, complain, in_decl));
+ case NON_LVALUE_EXPR:
+ case VIEW_CONVERT_EXPR:
+ /* We should only see these for location wrapper nodes, or within
+ instantiate_non_dependent_expr (when args is NULL_TREE). */
+ gcc_assert (location_wrapper_p (t) || args == NULL_TREE);
+ if (location_wrapper_p (t))
+ RETURN (maybe_wrap_with_location (RECUR (TREE_OPERAND (t, 0)),
+ EXPR_LOCATION (t)));
+ /* fallthrough. */
+
default:
/* Handle Objective-C++ constructs, if appropriate. */
{
tree
build_non_dependent_expr (tree expr)
{
+ tree orig_expr = expr;
tree inner_expr;
/* When checking, try to get a constant value for all non-dependent
&& !expanding_concept ())
fold_non_dependent_expr (expr);
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+
/* Preserve OVERLOADs; the functions must be available to resolve
types. */
inner_expr = expr;
inner_expr = TREE_OPERAND (inner_expr, 1);
if (is_overloaded_fn (inner_expr)
|| TREE_CODE (inner_expr) == OFFSET_REF)
- return expr;
+ return orig_expr;
/* There is no need to return a proxy for a variable. */
if (VAR_P (expr))
- return expr;
+ return orig_expr;
/* Preserve string constants; conversions from string constants to
"char *" are allowed, even though normally a "const char *"
cannot be used to initialize a "char *". */
if (TREE_CODE (expr) == STRING_CST)
- return expr;
+ return orig_expr;
/* Preserve void and arithmetic constants, as an optimization -- there is no
reason to create a new node. */
if (TREE_CODE (expr) == VOID_CST
|| TREE_CODE (expr) == INTEGER_CST
|| TREE_CODE (expr) == REAL_CST)
- return expr;
+ return orig_expr;
/* Preserve THROW_EXPRs -- all throw-expressions have type "void".
There is at least one place where we want to know that a
particular expression is a throw-expression: when checking a ?:
expression, there are special rules if the second or third
argument is a throw-expression. */
if (TREE_CODE (expr) == THROW_EXPR)
- return expr;
+ return orig_expr;
/* Don't wrap an initializer list, we need to be able to look inside. */
if (BRACE_ENCLOSED_INITIALIZER_P (expr))
- return expr;
+ return orig_expr;
/* Don't wrap a dummy object, we need to be able to test for it. */
if (is_dummy_object (expr))
- return expr;
+ return orig_expr;
if (TREE_CODE (expr) == COND_EXPR)
return build3 (COND_EXPR,
type_specializations->collisions ());
}
+#if CHECKING_P
+
+namespace selftest {
+
+/* Verify that build_non_dependent_expr () works, for various expressions,
+ and that location wrappers don't affect the results. */
+
+static void
+test_build_non_dependent_expr ()
+{
+ location_t loc = BUILTINS_LOCATION;
+
+ /* Verify constants, without and with location wrappers. */
+ tree int_cst = build_int_cst (integer_type_node, 42);
+ ASSERT_EQ (int_cst, build_non_dependent_expr (int_cst));
+
+ tree wrapped_int_cst = maybe_wrap_with_location (int_cst, loc);
+ ASSERT_TRUE (location_wrapper_p (wrapped_int_cst));
+ ASSERT_EQ (wrapped_int_cst, build_non_dependent_expr (wrapped_int_cst));
+
+ tree string_lit = build_string (4, "foo");
+ TREE_TYPE (string_lit) = char_array_type_node;
+ string_lit = fix_string_type (string_lit);
+ ASSERT_EQ (string_lit, build_non_dependent_expr (string_lit));
+
+ tree wrapped_string_lit = maybe_wrap_with_location (string_lit, loc);
+ ASSERT_TRUE (location_wrapper_p (wrapped_string_lit));
+ ASSERT_EQ (wrapped_string_lit,
+ build_non_dependent_expr (wrapped_string_lit));
+}
+
+/* Run all of the selftests within this file. */
+
+void
+cp_pt_c_tests ()
+{
+ test_build_non_dependent_expr ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
+
#include "gt-cp-pt.h"
#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 *);
case NON_DEPENDENT_EXPR:
return lvalue_kind (TREE_OPERAND (ref, 0));
+ 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;
}
#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 (int_cst));
+
+ 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 (wrapped_int_cst));
+
+ tree string_lit = build_string (4, "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 (wrapped_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"
&& !same_type_p (t, wchar_type_node))
return 0;
+ STRIP_ANY_LOCATION_WRAPPER (exp);
+
if (TREE_CODE (exp) == STRING_CST)
{
/* Make sure that we don't try to convert between char and wide chars. */
}
/* Issue warnings about peculiar, but valid, uses of NULL. */
- if ((orig_op0 == null_node || orig_op1 == null_node)
+ if ((null_node_p (orig_op0) || null_node_p (orig_op1))
/* It's reasonable to use pointer values as operands of &&
and ||, so NULL is no exception. */
&& code != TRUTH_ANDIF_EXPR && code != TRUTH_ORIF_EXPR
if (error_operand_p (t) || !cxx_mark_addressable (t))
return error_mark_node;
gcc_checking_assert (TREE_CODE (t) != CONSTRUCTOR);
- t = build_fold_addr_expr (t);
+ t = build_fold_addr_expr_loc (EXPR_LOCATION (t), t);
if (TREE_CODE (t) != ADDR_EXPR)
t = rvalue (t);
return t;
+2018-01-10 David Malcolm <dmalcolm@redhat.com>
+
+ PR c++/43486
+ * g++.dg/diagnostic/param-type-mismatch.C: Update expected results
+ to reflect that the arguments are correctly underlined.
+ * g++.dg/plugin/diagnostic-test-expressions-1.C: Add test coverage
+ for globals, params, locals and literals.
+ (test_sizeof): Directly test the location of "sizeof", rather than
+ when used in compound expressions.
+ (test_alignof): Likewise for "alignof".
+ (test_string_literals): Likewise for string literals.
+ (test_numeric_literals): Likewise for numeric literals.
+ (test_builtin_offsetof): Likewise for "__builtin_offsetof".
+ (test_typeid): Likewise for typeid.
+ (test_unary_plus): New.
+ * g++.dg/warn/Wformat-1.C: Add tests of pointer arithmetic on
+ format strings.
+
2018-01-10 Uros Bizjak <ubizjak@gmail.com>
* gcc.target/i386/pr82618.c (dg-options): Add -mno-stv.
// { dg-options "-fdiagnostics-show-caret" }
-/* A collection of calls where argument 2 is of the wrong type.
-
- TODO: we should put the caret and underline for the diagnostic
- at the second argument, rather than the close paren. */
+/* A collection of calls where argument 2 is of the wrong type. */
/* decl, with argname. */
return callee_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
/* { dg-begin-multiline-output "" }
return callee_1 (first, second, third);
- ^
+ ^~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "initializing argument 2 of 'int callee_1\\(int, const char\\*, float\\)'" "" { target *-*-* } callee_1 }
/* { dg-begin-multiline-output "" }
return callee_2 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
/* { dg-begin-multiline-output "" }
return callee_2 (first, second, third);
- ^
+ ^~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "initializing argument 2 of 'int callee_2\\(int, const char\\*, float\\)'" "" { target *-*-* } callee_2 }
/* { dg-begin-multiline-output "" }
return callee_3 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
/* { dg-begin-multiline-output "" }
return callee_3 (first, second, third);
- ^
+ ^~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "initializing argument 2 of 'int callee_3\\(int, const char\\*, float\\)'" "" { target *-*-* } callee_3 }
/* { dg-begin-multiline-output "" }
return s4::member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
/* { dg-begin-multiline-output "" }
return s4::member_1 (first, second, third);
- ^
+ ^~~~~~
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
struct s4 { static int member_1 (int one, const char *two, float three); };
return inst.member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
/* { dg-begin-multiline-output "" }
return inst.member_1 (first, second, third);
- ^
+ ^~~~~~
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
struct s5 { int member_1 (int one, const char *two, float three); };
return ptr->member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
/* { dg-begin-multiline-output "" }
return ptr->member_1 (first, second, third);
- ^
+ ^~~~~~
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
struct s6 { int member_1 (int one, const char *two, float three); };
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
return test_7 <const char *> (first, second, third);
- ^
+ ^~~~~~
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
int test_7 (int one, T two, float three);
return s8 <const char *>::member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
/* { dg-begin-multiline-output "" }
return s8 <const char *>::member_1 (first, second, third);
- ^
+ ^~~~~~
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
struct s8 { static int member_1 (int one, T two, float three); };
return inst.member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
/* { dg-begin-multiline-output "" }
return inst.member_1 (first, second, third);
- ^
+ ^~~~~~
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
struct s9 { int member_1 (int one, T two, float three); };
return callee_10 (first, second, third); // { dg-error "invalid conversion from 'int' to 'int \\(\\*\\)\\(int, int\\)'" }
/* { dg-begin-multiline-output "" }
return callee_10 (first, second, third);
- ^
+ ^~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "initializing argument 2 of 'int callee_10\\(int, int \\(\\*\\)\\(int, int\\), float\\)'" "" { target *-*-* } callee_10 }
/* { dg-begin-multiline-output "" }
return callee_11 (first, second, third); // { dg-error "invalid conversion from 'int' to 'int \\(\\*\\)\\(int, int\\)'" }
/* { dg-begin-multiline-output "" }
return callee_11 (first, second, third);
- ^
+ ^~~~~~
{ dg-end-multiline-output "" } */
// { dg-message "initializing argument 2 of 'int callee_11\\(int, int \\(\\*\\)\\(int, int\\), float\\)'" "" { target *-*-* } callee_11 }
/* { dg-begin-multiline-output "" }
int global;
+void test_global (void)
+{
+ __emit_expression_range (0, global); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, global);
+ ^~~~~~
+ { dg-end-multiline-output "" } */
+}
+
+void test_param (int param)
+{
+ __emit_expression_range (0, param); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, param);
+ ^~~~~
+ { dg-end-multiline-output "" } */
+}
+
+void test_local (void)
+{
+ int local = 5;
+
+ __emit_expression_range (0, local); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, local);
+ ^~~~~
+ { dg-end-multiline-output "" } */
+}
+
+void test_integer_constants (void)
+{
+ __emit_expression_range (0, 1234); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, 1234);
+ ^~~~
+ { dg-end-multiline-output "" } */
+
+ /* Ensure that zero works. */
+
+ __emit_expression_range (0, 0); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, 0);
+ ^
+ { dg-end-multiline-output "" } */
+}
+
+void test_character_constants (void)
+{
+ __emit_expression_range (0, 'a'); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, 'a');
+ ^~~
+ { dg-end-multiline-output "" } */
+}
+
+void test_floating_constants (void)
+{
+ __emit_expression_range (0, 98.6); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, 98.6);
+ ^~~~
+ { dg-end-multiline-output "" } */
+
+ __emit_expression_range (0, .6); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, .6);
+ ^~
+ { dg-end-multiline-output "" } */
+
+ __emit_expression_range (0, 98.); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, 98.);
+ ^~~
+ { dg-end-multiline-output "" } */
+
+ __emit_expression_range (0, 6.022140857e23 ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, 6.022140857e23 );
+ ^~~~~~~~~~~~~~
+ { dg-end-multiline-output "" } */
+
+ __emit_expression_range (0, 98.6f ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, 98.6f );
+ ^~~~~
+ { dg-end-multiline-output "" } */
+
+ __emit_expression_range (0, 6.022140857e23l ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, 6.022140857e23l );
+ ^~~~~~~~~~~~~~~
+ { dg-end-multiline-output "" } */
+}
+
+enum test_enum {
+ TEST_ENUM_VALUE
+};
+
+void test_enumeration_constant (void)
+{
+ __emit_expression_range (0, TEST_ENUM_VALUE ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, TEST_ENUM_VALUE );
+ ^~~~~~~~~~~~~~~
+ { dg-end-multiline-output "" } */
+}
+
void test_parentheses (int a, int b)
{
__emit_expression_range (0, (a + b) ); /* { dg-warning "range" } */
void test_sizeof (int i)
{
- __emit_expression_range (0, sizeof(int) + i); /* { dg-warning "range" } */
+ __emit_expression_range (0, sizeof i ); /* { dg-warning "range" } */
/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, sizeof(int) + i);
- ~~~~~~~~~~~~^~~
- { dg-end-multiline-output "" } */
-
- __emit_expression_range (0, i + sizeof(int)); /* { dg-warning "range" } */
-/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, i + sizeof(int));
- ~~^~~~~~~~~~~~~
- { dg-end-multiline-output "" } */
-
- __emit_expression_range (0, sizeof i + i); /* { dg-warning "range" } */
-/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, sizeof i + i);
- ~~~~~~~~~^~~
+ __emit_expression_range (0, sizeof i );
+ ^~~~~~~~
{ dg-end-multiline-output "" } */
- __emit_expression_range (0, i + sizeof i); /* { dg-warning "range" } */
+ __emit_expression_range (0, sizeof (char) ); /* { dg-warning "range" } */
/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, i + sizeof i);
- ~~^~~~~~~~~~
+ __emit_expression_range (0, sizeof (char) );
+ ^~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
}
void test_alignof (int i)
{
- __emit_expression_range (0, alignof(int) + i); /* { dg-warning "range" } */
-/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, alignof(int) + i);
- ~~~~~~~~~~~~~^~~
- { dg-end-multiline-output "" } */
-
- __emit_expression_range (0, i + alignof(int)); /* { dg-warning "range" } */
+ __emit_expression_range (0, alignof(int)); /* { dg-warning "range" } */
/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, i + alignof(int));
- ~~^~~~~~~~~~~~~~
- { dg-end-multiline-output "" } */
-
- __emit_expression_range (0, __alignof__(int) + i); /* { dg-warning "range" } */
-/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, __alignof__(int) + i);
- ~~~~~~~~~~~~~~~~~^~~
- { dg-end-multiline-output "" } */
-
- __emit_expression_range (0, i + __alignof__(int)); /* { dg-warning "range" } */
-/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, i + __alignof__(int));
- ~~^~~~~~~~~~~~~~~~~~
+ __emit_expression_range (0, alignof(int));
+ ^~~~~~~~~~~~
{ dg-end-multiline-output "" } */
- __emit_expression_range (0, __alignof__ i + i); /* { dg-warning "range" } */
+ __emit_expression_range (0, __alignof__(int)); /* { dg-warning "range" } */
/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, __alignof__ i + i);
- ~~~~~~~~~~~~~~^~~
+ __emit_expression_range (0, __alignof__(int));
+ ^~~~~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
-
- __emit_expression_range (0, i + __alignof__ i); /* { dg-warning "range" } */
+ __emit_expression_range (0, __alignof__ i); /* { dg-warning "range" } */
/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, i + __alignof__ i);
- ~~^~~~~~~~~~~~~~~
+ __emit_expression_range (0, __alignof__ i);
+ ^~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
}
{ dg-end-multiline-output "" } */
}
+void test_unary_plus (int i)
+{
+ __emit_expression_range (0, +i ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+ __emit_expression_range (0, +i );
+ ^~
+ { dg-end-multiline-output "" } */
+}
+
void test_unary_minus (int i)
{
__emit_expression_range (0, -i ); /* { dg-warning "range" } */
/* Literals. **************************************************/
-/* We can't test the ranges of literals directly, since the underlying
- tree nodes don't retain a location. However, we can test that they
- have ranges during parsing by building compound expressions using
- them, and verifying the ranges of the compound expressions. */
-
-void test_string_literals (int i)
+void test_string_literals ()
{
- __emit_expression_range (0, "foo"[i] ); /* { dg-warning "range" } */
+ __emit_expression_range (0, "0123456789"); /* { dg-warning "range" } */
/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, "foo"[i] );
- ~~~~~~~^
+ __emit_expression_range (0, "0123456789");
+ ^~~~~~~~~~~~
{ dg-end-multiline-output "" } */
- __emit_expression_range (0, &"foo" "bar" ); /* { dg-warning "range" } */
+ __emit_expression_range (0, "foo" "bar" ); /* { dg-warning "range" } */
/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, &"foo" "bar" );
- ^~~~~~~~~~~~
+ __emit_expression_range (0, "foo" "bar" );
+ ^~~~~~~~~~~
{ dg-end-multiline-output "" } */
}
void test_numeric_literals (int i)
{
- __emit_expression_range (0, 42 + i ); /* { dg-warning "range" } */
+ __emit_expression_range (0, 42 ); /* { dg-warning "range" } */
/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, 42 + i );
- ~~~^~~
- { dg-end-multiline-output "" } */
-
- __emit_expression_range (0, i + 42 ); /* { dg-warning "range" } */
-/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, i + 42 );
- ~~^~~~
+ __emit_expression_range (0, 42 );
+ ^~
{ dg-end-multiline-output "" } */
/* Verify locations of negative literals (via folding of
unary negation). */
- __emit_expression_range (0, -42 + i ); /* { dg-warning "range" } */
+ __emit_expression_range (0, -42 ); /* { dg-warning "range" } */
/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, -42 + i );
- ~~~~^~~
- { dg-end-multiline-output "" } */
-
- __emit_expression_range (0, i + -42 ); /* { dg-warning "range" } */
-/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, i + -42 );
- ~~^~~~~
+ __emit_expression_range (0, -42 );
+ ^~~
{ dg-end-multiline-output "" } */
__emit_expression_range (0, i ? 0 : -1 ); /* { dg-warning "range" } */
void test_builtin_offsetof (int i)
{
- __emit_expression_range (0, i + __builtin_offsetof (struct s, f) ); /* { dg-warning "range" } */
+ __emit_expression_range (0, __builtin_offsetof (struct s, f) ); /* { dg-warning "range" } */
/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, i + __builtin_offsetof (struct s, f) );
- ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- { dg-end-multiline-output "" } */
-
- __emit_expression_range (0, __builtin_offsetof (struct s, f) + i ); /* { dg-warning "range" } */
-/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, __builtin_offsetof (struct s, f) + i );
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~
+ __emit_expression_range (0, __builtin_offsetof (struct s, f) );
+ ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~
{ dg-end-multiline-output "" } */
}
void test_typeid (int i)
{
- __emit_expression_range (0, &typeid(i)); /* { dg-warning "range" } */
+ __emit_expression_range (0, typeid(i)); /* { dg-warning "range" } */
/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, &typeid(i));
- ^~~~~~~~~~
- { dg-end-multiline-output "" } */
-
- __emit_expression_range (0, &typeid(int)); /* { dg-warning "range" } */
-/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, &typeid(int));
- ^~~~~~~~~~~~
+ __emit_expression_range (0, typeid(i));
+ ^~~~~~~~~
{ dg-end-multiline-output "" } */
- __emit_expression_range (0, &typeid(i * 2)); /* { dg-warning "range" } */
+ __emit_expression_range (0, typeid(int)); /* { dg-warning "range" } */
/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, &typeid(i * 2));
- ^~~~~~~~~~~~~~
+ __emit_expression_range (0, typeid(int));
+ ^~~~~~~~~~~
{ dg-end-multiline-output "" } */
- __emit_expression_range (0, typeid(int).foo); /* { dg-warning "range" } */
+ __emit_expression_range (0, typeid(i * 2)); /* { dg-warning "range" } */
/* { dg-begin-multiline-output "" }
- __emit_expression_range (0, typeid(int).foo);
- ~~~~~~~~~~~~^~~
+ __emit_expression_range (0, typeid(i * 2));
+ ^~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
}
{
const char *const msg = "abc";
bar (1, msg);
+ bar (1, msg + 1);
+ bar (1, 1 + msg);
}
SSA_NAME_IS_VIRTUAL_OPERAND in
SSA_NAME
+ EXPR_LOCATION_WRAPPER_P in
+ NON_LVALUE_EXPR, VIEW_CONVERT_EXPR
+
private_flag:
TREE_PRIVATE in
{
tree outer_type, inner_type;
+ if (location_wrapper_p (exp))
+ return true;
if (!CONVERT_EXPR_P (exp)
&& TREE_CODE (exp) != NON_LVALUE_EXPR)
return false;
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));
+
+ /* For now, don't add wrappers to exceptional tree nodes, to minimize
+ any impact of the wrapper nodes. */
+ 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 *
check_vector_cst_fill (elements, build_vector (vector_type, elements), 4);
}
+/* Verify that STRIP_NOPS (NODE) is EXPECTED.
+ Helper function for test_location_wrappers, to deal with STRIP_NOPS
+ modifying its argument in-place. */
+
+static void
+check_strip_nops (tree node, tree expected)
+{
+ STRIP_NOPS (node);
+ ASSERT_EQ (expected, node);
+}
+
+/* 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));
+
+ /* Verify that STRIP_NOPS removes wrappers. */
+ check_strip_nops (wrapped_int_cst, int_cst);
+ check_strip_nops (wrapped_string_cst, string_cst);
+ check_strip_nops (wrapped_int_var, int_var);
+}
+
/* Run all of the selftests within this file. */
void
test_identifiers ();
test_labels ();
test_vector_cst_patterns ();
+ test_location_wrappers ();
}
} // namespace selftest
#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)
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)
return true;
}
+/* 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]