From 9a004410d9f64d658864a899ab911ae9a31c444c Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 10 Jan 2018 19:40:55 +0000 Subject: [PATCH] Preserving locations for variable-uses and constants (PR c++/43486) This patch implements location wrapper nodes, preserving source locations of the uses of variables and constants in various places in the C++ frontend: at the arguments at callsites, and for typeid, alignof, sizeof, and offsetof. For example, it allows the C++ FE to underline the pertinent argument for mismatching calls, for such expressions, improving: extern int callee (int one, const char *two, float three); int caller (int first, int second, float third) { return callee (first, second, third); } from test.cc: In function 'int caller(int, int, float)': test.cc:5:38: error: invalid conversion from 'int' to 'const char*' [-fpermissive] return callee (first, second, third); ^ test.cc:1:41: note: initializing argument 2 of 'int callee(int, const char*, float)' extern int callee (int one, const char *two, float three); ~~~~~~~~~~~~^~~ to: test.cc: In function 'int caller(int, int, float)': test.cc:5:25: error: invalid conversion from 'int' to 'const char*' [-fpermissive] return callee (first, second, third); ^~~~~~ test.cc:1:41: note: initializing argument 2 of 'int callee(int, const char*, float)' extern int callee (int one, const char *two, float three); ~~~~~~~~~~~~^~~ This is the combination of the following patches: "[PATCH 01/14] C++: preserve locations within build_address" https://gcc.gnu.org/ml/gcc-patches/2017-11/msg00883.html "[PATCH v2.4 of 02/14] Support for adding and stripping location_t wrapper nodes" https://gcc.gnu.org/ml/gcc-patches/2018-01/msg00591.html "[PATCH] Eliminate location wrappers in tree_nop_conversion/STRIP_NOPS" https://gcc.gnu.org/ml/gcc-patches/2017-12/msg01330.html "[PATCH v4 of 03/14] C++: add location_t wrapper nodes during parsing (minimal impl)" https://gcc.gnu.org/ml/gcc-patches/2018-01/msg00660.html "[PATCH 04/14] Update testsuite to show improvements" https://gcc.gnu.org/ml/gcc-patches/2017-11/msg00891.html "[v3 of 05/14] C++: handle locations wrappers when calling warn_for_memset" https://gcc.gnu.org/ml/gcc-patches/2017-12/msg01378.html "[PATCH 07/14] reject_gcc_builtin: strip any location wrappers" https://gcc.gnu.org/ml/gcc-patches/2017-11/msg00886.html "[v3 of PATCH 08/14] cp/tree.c: strip location wrappers in lvalue_kind" https://gcc.gnu.org/ml/gcc-patches/2017-12/msg01433.html "[PATCH 09/14] Strip location wrappers in null_ptr_cst_p" https://gcc.gnu.org/ml/gcc-patches/2017-11/msg00888.html "[PATCH 11/14] Handle location wrappers in string_conv_p" https://gcc.gnu.org/ml/gcc-patches/2017-11/msg00890.html "[PATCH 12/14] C++: introduce null_node_p" https://gcc.gnu.org/ml/gcc-patches/2017-11/msg00894.html "[v3 of PATCH 13/14] c-format.c: handle location wrappers" https://gcc.gnu.org/ml/gcc-patches/2017-12/msg01494.html "[PATCH 14/14] pp_c_cast_expression: don't print casts for location wrappers" https://gcc.gnu.org/ml/gcc-patches/2017-11/msg00893.html "[v3 of PATCH 15/14] Use fold_for_warn in get_atomic_generic_size" https://gcc.gnu.org/ml/gcc-patches/2017-12/msg01380.html "[PATCH] Add selftest for "fold_for_warn (error_mark_node)"" https://gcc.gnu.org/ml/gcc-patches/2017-12/msg01385.html gcc/c-family/ChangeLog: 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. gcc/cp/ChangeLog: 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. gcc/testsuite/ChangeLog: 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. gcc/ChangeLog: 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. From-SVN: r256448 --- gcc/ChangeLog | 17 ++ gcc/c-family/ChangeLog | 23 ++ gcc/c-family/c-common.c | 39 ++- gcc/c-family/c-common.h | 1 + gcc/c-family/c-format.c | 10 +- gcc/c-family/c-pretty-print.c | 66 ++++- gcc/c-family/c-warn.c | 3 + gcc/cp/ChangeLog | 52 ++++ gcc/cp/call.c | 6 +- gcc/cp/cp-gimplify.c | 5 +- gcc/cp/cp-lang.c | 2 + gcc/cp/cp-tree.h | 30 +- gcc/cp/cvt.c | 2 +- gcc/cp/error.c | 2 +- gcc/cp/except.c | 2 +- gcc/cp/mangle.c | 1 + gcc/cp/parser.c | 41 ++- gcc/cp/pt.c | 83 +++++- gcc/cp/tree.c | 66 +++++ gcc/cp/typeck.c | 6 +- gcc/testsuite/ChangeLog | 18 ++ .../g++.dg/diagnostic/param-type-mismatch.C | 27 +- .../plugin/diagnostic-test-expressions-1.C | 256 +++++++++++------- gcc/testsuite/g++.dg/warn/Wformat-1.C | 2 + gcc/tree-core.h | 3 + gcc/tree.c | 103 +++++++ gcc/tree.h | 47 ++++ 27 files changed, 749 insertions(+), 164 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index cacb95c58bf..a292768d13a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2018-01-10 David Malcolm + + 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 PR target/83735 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index e79d9858ac0..d6b60856eaf 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,26 @@ +2018-01-10 David Malcolm + + 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 Alan Hayward David Sherwood diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 87bd326b5e4..097d192c869 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see #include "gimplify.h" #include "substring-locations.h" #include "spellcheck.h" +#include "selftest.h" cpp_reader *parse_in; /* Declared in c-pragma.h. */ @@ -6737,8 +6738,15 @@ get_atomic_generic_size (location_t loc, tree function, 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 @@ -6748,14 +6756,7 @@ get_atomic_generic_size (location_t loc, tree function, "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; } @@ -7846,6 +7847,8 @@ reject_gcc_builtin (const_tree expr, location_t loc /* = UNKNOWN_LOCATION */) 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 @@ -8187,12 +8190,30 @@ maybe_suggest_missing_token_insertion (rich_location *richloc, 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 (); } diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 00bfe59a64a..d090881e95d 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1450,6 +1450,7 @@ namespace selftest { /* 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. */ diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c index e07114533eb..7a69d5a295c 100644 --- a/gcc/c-family/c-format.c +++ b/gcc/c-family/c-format.c @@ -1536,12 +1536,10 @@ check_format_arg (void *ctx, tree format_tree, 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)) { diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-print.c index 6e4f85c0a02..c9dd8aefff9 100644 --- a/gcc/c-family/c-pretty-print.c +++ b/gcc/c-family/c-pretty-print.c @@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see #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 @@ -1809,7 +1810,8 @@ pp_c_cast_expression (c_pretty_printer *pp, tree e) 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; @@ -2400,3 +2402,65 @@ pp_c_tree_decl_identifier (c_pretty_printer *pp, tree t) 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 */ diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c index 33cae8be7fd..7d87c455ec0 100644 --- a/gcc/c-family/c-warn.c +++ b/gcc/c-family/c-warn.c @@ -1868,6 +1868,9 @@ void 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 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d664bd26af9..d24c9343620 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,55 @@ +2018-01-10 David Malcolm + + 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 PR c++/82541 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 87bbf3c7991..c822a70a017 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -528,6 +528,8 @@ null_ptr_cst_p (tree t) 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) @@ -6531,7 +6533,7 @@ static void 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 = @@ -7865,7 +7867,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) func(NULL); } */ - if (arg == null_node + if (null_node_p (arg) && DECL_TEMPLATE_INFO (fn) && cand->template_decl && !(flags & LOOKUP_EXPLICIT_TMPL_ARGS)) diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index eda493a7bec..e97247c1384 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -2064,7 +2064,7 @@ clear_fold_cache (void) /* 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. */ @@ -2081,8 +2081,7 @@ cp_fold (tree x) 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. */ diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c index 9992bc2cbb9..6007094e0a6 100644 --- a/gcc/cp/cp-lang.c +++ b/gcc/cp/cp-lang.c @@ -247,6 +247,8 @@ run_cp_tests (void) c_family_tests (); /* Additional C++-specific tests. */ + cp_pt_c_tests (); + cp_tree_c_tests (); } } // namespace selftest diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index dff72a84e11..9c6c1791e1a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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; @@ -7422,12 +7428,6 @@ extern tree cp_ubsan_maybe_instrument_downcast (location_t, tree, tree, tree); 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 @@ -7458,6 +7458,24 @@ named_decl_hash::equal (const value_type existing, compare_type candidate) 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 */ diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 444a24f0708..7ed2aad6136 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -1642,7 +1642,7 @@ build_expr_type_conversion (int desires, tree expr, bool complain) tree conv = NULL_TREE; tree winner = NULL_TREE; - if (expr == null_node + if (null_node_p (expr) && (desires & WANT_INT) && !(desires & WANT_NULL)) { diff --git a/gcc/cp/error.c b/gcc/cp/error.c index d8fbbde8d63..cb1dcf36201 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -3230,7 +3230,7 @@ args_to_string (tree p, int verbose) 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); diff --git a/gcc/cp/except.c b/gcc/cp/except.c index b19276215c1..669bf9f6eaf 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -577,7 +577,7 @@ build_throw (tree exp) 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) diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index bd745432dc1..94c4bed2848 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -2890,6 +2890,7 @@ write_expression (tree expr) /* 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) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index f9181b7451e..b16597ce9b7 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -2047,7 +2047,8 @@ static tree cp_parser_postfix_open_square_expression static tree cp_parser_postfix_dot_deref_expression (cp_parser *, enum cpp_ttype, cp_expr, bool, cp_id_kind *, location_t); static vec *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 @@ -6620,6 +6621,16 @@ cp_parser_compound_literal_p (cp_parser *parser) 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: @@ -6831,6 +6842,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, 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; @@ -7088,7 +7100,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, (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 @@ -7164,10 +7177,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_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); } @@ -7621,6 +7632,10 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, 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 @@ -7640,7 +7655,8 @@ cp_parser_parenthesized_expression_list (cp_parser* parser, 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 *expression_list; bool fold_expr_p = is_attribute_list != non_attr; @@ -7663,12 +7679,12 @@ cp_parser_parenthesized_expression_list (cp_parser* parser, = 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 @@ -7722,11 +7738,14 @@ cp_parser_parenthesized_expression_list (cp_parser* parser, 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; @@ -7992,6 +8011,7 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk, cp_expr ret_expr (ret); ret_expr.set_location (compound_loc); + ret_expr = ret_expr.maybe_add_location_wrapper (); return ret_expr; } @@ -9831,6 +9851,7 @@ cp_parser_builtin_offsetof (cp_parser *parser) 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; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 2deccd822c2..bb5908fb853 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see #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. */ @@ -14924,6 +14925,18 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) /* 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: @@ -18291,6 +18304,16 @@ tsubst_copy_and_build (tree t, 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. */ { @@ -24982,6 +25005,7 @@ resolve_typename_type (tree type, bool only_current_p) 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 @@ -24998,6 +25022,8 @@ build_non_dependent_expr (tree expr) && !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; @@ -25009,36 +25035,36 @@ build_non_dependent_expr (tree 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, @@ -26601,4 +26627,47 @@ print_template_statistics (void) 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" diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 87b45e07eac..ed51c28858f 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,11 @@ lvalue_kind (const_tree ref) 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; @@ -5346,4 +5352,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 (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" diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index dc04b4bee84..669a2b45bfd 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -2202,6 +2202,8 @@ string_conv_p (const_tree totype, const_tree exp, int warn) && !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. */ @@ -4317,7 +4319,7 @@ cp_build_binary_op (location_t location, } /* 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 @@ -5734,7 +5736,7 @@ build_address (tree t) 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; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2ad59d66ff7..6091e59998b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,21 @@ +2018-01-10 David Malcolm + + 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 * gcc.target/i386/pr82618.c (dg-options): Add -mno-stv. diff --git a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C index bc3a93812f5..5fcde0b7755 100644 --- a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C +++ b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C @@ -1,9 +1,6 @@ // { 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. */ @@ -14,7 +11,7 @@ int test_1 (int first, int second, float third) 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 "" } @@ -32,7 +29,7 @@ int test_2 (int first, int second, float third) 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 "" } @@ -53,7 +50,7 @@ int test_3 (int first, int second, float third) 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 "" } @@ -71,7 +68,7 @@ int test_4 (int first, int second, float third) 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); }; @@ -89,7 +86,7 @@ int test_5 (int first, int second, float third) 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); }; @@ -106,7 +103,7 @@ int test_6 (int first, int second, float third, s6 *ptr) 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); }; @@ -128,7 +125,7 @@ int test_7 (int first, int second, float third) { dg-end-multiline-output "" } */ /* { dg-begin-multiline-output "" } return test_7 (first, second, third); - ^ + ^~~~~~ { dg-end-multiline-output "" } */ /* { dg-begin-multiline-output "" } int test_7 (int one, T two, float three); @@ -146,7 +143,7 @@ int test_8 (int first, int second, float third) return s8 ::member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" } /* { dg-begin-multiline-output "" } return s8 ::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); }; @@ -165,7 +162,7 @@ int test_9 (int first, int second, float third) 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); }; @@ -182,7 +179,7 @@ int test_10 (int first, int second, float third) 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 "" } @@ -200,7 +197,7 @@ int test_11 (int first, int second, float third) 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 "" } diff --git a/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C b/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C index 8b6afeb052a..c08fec4d019 100644 --- a/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C +++ b/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C @@ -19,6 +19,113 @@ extern void __emit_expression_range (int dummy, ...); 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" } */ @@ -103,67 +210,36 @@ void test_postfix_incdec (int i) 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); - ~~~~~~~~~~~~^~~ + __emit_expression_range (0, sizeof i ); + ^~~~~~~~ { dg-end-multiline-output "" } */ - __emit_expression_range (0, i + sizeof(int)); /* { dg-warning "range" } */ + __emit_expression_range (0, sizeof (char) ); /* { 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); - ~~~~~~~~~^~~ - { dg-end-multiline-output "" } */ - - __emit_expression_range (0, i + sizeof i); /* { 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" } */ + __emit_expression_range (0, alignof(int)); /* { dg-warning "range" } */ /* { dg-begin-multiline-output "" } - __emit_expression_range (0, alignof(int) + i); - ~~~~~~~~~~~~~^~~ + __emit_expression_range (0, alignof(int)); + ^~~~~~~~~~~~ { 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)); - ~~^~~~~~~~~~~~~~ + __emit_expression_range (0, __alignof__(int)); + ^~~~~~~~~~~~~~~~ { dg-end-multiline-output "" } */ - - __emit_expression_range (0, __alignof__(int) + i); /* { dg-warning "range" } */ + __emit_expression_range (0, __alignof__ 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)); - ~~^~~~~~~~~~~~~~~~~~ - { dg-end-multiline-output "" } */ - - __emit_expression_range (0, __alignof__ i + i); /* { dg-warning "range" } */ -/* { dg-begin-multiline-output "" } - __emit_expression_range (0, __alignof__ i + i); - ~~~~~~~~~~~~~~^~~ - { dg-end-multiline-output "" } */ - - __emit_expression_range (0, i + __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 "" } */ } @@ -200,6 +276,15 @@ void test_indirection (int *ptr) { 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" } */ @@ -471,53 +556,36 @@ void test_comma_operator (int a, int b) /* 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" } */ @@ -638,16 +706,10 @@ struct s { int i; float f; }; 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 "" } */ } @@ -856,28 +918,22 @@ namespace std 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)); - ^~~~~~~~~~ + __emit_expression_range (0, typeid(i)); + ^~~~~~~~~ { dg-end-multiline-output "" } */ - __emit_expression_range (0, &typeid(int)); /* { dg-warning "range" } */ + __emit_expression_range (0, typeid(int)); /* { dg-warning "range" } */ /* { dg-begin-multiline-output "" } - __emit_expression_range (0, &typeid(int)); - ^~~~~~~~~~~~ + __emit_expression_range (0, typeid(int)); + ^~~~~~~~~~~ { dg-end-multiline-output "" } */ - __emit_expression_range (0, &typeid(i * 2)); /* { dg-warning "range" } */ + __emit_expression_range (0, typeid(i * 2)); /* { dg-warning "range" } */ /* { dg-begin-multiline-output "" } - __emit_expression_range (0, &typeid(i * 2)); - ^~~~~~~~~~~~~~ - { dg-end-multiline-output "" } */ - - __emit_expression_range (0, typeid(int).foo); /* { 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 "" } */ } diff --git a/gcc/testsuite/g++.dg/warn/Wformat-1.C b/gcc/testsuite/g++.dg/warn/Wformat-1.C index 6094a9ca36b..f2e772aec95 100644 --- a/gcc/testsuite/g++.dg/warn/Wformat-1.C +++ b/gcc/testsuite/g++.dg/warn/Wformat-1.C @@ -7,4 +7,6 @@ foo (void) { const char *const msg = "abc"; bar (1, msg); + bar (1, msg + 1); + bar (1, 1 + msg); } diff --git a/gcc/tree-core.h b/gcc/tree-core.h index 76d2dfdc215..56acd10a653 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -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 diff --git a/gcc/tree.c b/gcc/tree.c index 63084ac2d4f..bed59d33bb2 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -12167,6 +12167,8 @@ tree_nop_conversion (const_tree exp) { 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; @@ -14093,6 +14095,42 @@ 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)); + + /* 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 * @@ -14464,6 +14502,70 @@ test_vector_cst_patterns () 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(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 @@ -14473,6 +14575,7 @@ tree_c_tests () test_identifiers (); test_labels (); test_vector_cst_patterns (); + test_location_wrappers (); } } // namespace selftest diff --git a/gcc/tree.h b/gcc/tree.h index 316dcfda0fa..f47e2338d2d 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -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) @@ -3726,6 +3734,45 @@ valid_vector_subparts_p (poly_uint64 subparts) 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]