Preserving locations for variable-uses and constants (PR c++/43486)
authorDavid Malcolm <dmalcolm@redhat.com>
Wed, 10 Jan 2018 19:40:55 +0000 (19:40 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Wed, 10 Jan 2018 19:40:55 +0000 (19:40 +0000)
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

27 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c-family/c-format.c
gcc/c-family/c-pretty-print.c
gcc/c-family/c-warn.c
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-gimplify.c
gcc/cp/cp-lang.c
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/error.c
gcc/cp/except.c
gcc/cp/mangle.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C
gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C
gcc/testsuite/g++.dg/warn/Wformat-1.C
gcc/tree-core.h
gcc/tree.c
gcc/tree.h

index cacb95c58bf4a28d2c074165ec5ae4c4f184ad27..a292768d13a23e1edc614863b65fa024dc721984 100644 (file)
@@ -1,3 +1,20 @@
+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
index e79d9858ac06c7ddc0fe4dd4ac97620dcb566069..d6b60856eaf61b720ad183ae22bb01ad2dc30747 100644 (file)
@@ -1,3 +1,26 @@
+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>
index 87bd326b5e41fec20615a2891648c71d00a9c648..097d192c8691c9339cdd24599a77466277926046 100644 (file)
@@ -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 ();
 }
 
index 00bfe59a64acea8d27883fcda2e93c4d159adf44..d090881e95d5f66ba65aae12d606c08b54719950 100644 (file)
@@ -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.  */
index e07114533ebb3d920a48de083b6cb8157ea8d7c8..7a69d5a295cf639875258128029170cd00829bf1 100644 (file)
@@ -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))
     {
index 6e4f85c0a0269f3da8b62c860656e01fb0145e03..c9dd8aefff9beaadf54350b0a5be99c6a45954ba 100644 (file)
@@ -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 */
index 33cae8be7fdde4496862404450fef4712398c6f7..7d87c455ec0c7dacd6774b41c362a5bb6a37c6a5 100644 (file)
@@ -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
index d664bd26af93f1eedec5fb6ee79039b513960171..d24c9343620a668275bde875640863479e025257 100644 (file)
@@ -1,3 +1,55 @@
+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
index 87bbf3c7991812f763968474b53716d0ae700b0c..c822a70a017668b3aedff2dfa50eba3962bfa02b 100644 (file)
@@ -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))
index eda493a7bec11c922ef38dda2a7ba20647bc122e..e97247c13843aba91591626f977288b45af6dc17 100644 (file)
@@ -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.  */
index 9992bc2cbb998e9863d86974b8ad7b94f3d00afe..6007094e0a6f7446dbc36436a421b9a1a2ace593 100644 (file)
@@ -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
index dff72a84e11541e82425c8d64e7325c27d477662..9c6c1791e1acc31db3775c0c702579f6ec11f18d 100644 (file)
@@ -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 */
index 444a24f0708a23989f09e3f41157b125793d0c57..7ed2aad613606c45ce1e4b6a985cf55a753bc3e3 100644 (file)
@@ -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))
     {
index d8fbbde8d63e30c29149d8e8d6e09d2baae4213b..cb1dcf362013eed259bae0890986f363471b334e 100644 (file)
@@ -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);
index b19276215c1ad0767662d3fbc5402dd061473a00..669bf9f6eaf5c6f2c8e02ea2293134c6ae5ad1c5 100644 (file)
@@ -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)
index bd745432dc1bbe20be7bce7ea7c6c4b2d5244efa..94c4bed2848690352ad9308794c8bfd9c9ccf2bf 100644 (file)
@@ -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)
index f9181b7451e24ca8bf16cf8d4b77d1f0e6b3e3aa..b16597ce9b78af2ca906b50fb6a37686bb5c27e0 100644 (file)
@@ -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<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
@@ -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<tree, va_gc> *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;
 }
 
index 2deccd822c26e6c9ed811dedca59e8f16aecbd21..bb5908fb85319203e3f33677454a6b41d63e628a 100644 (file)
@@ -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"
index 87b45e07eacadc7a27c9cdd2080c6c7eb55d72bb..ed51c28858f951ec1ca587620e2d4458b94c64bd 100644 (file)
@@ -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"
index dc04b4bee848f93b72acb6f2d5942a50f9258e4b..669a2b45bfdddcfdfff11979a9396bf971e046ff 100644 (file)
@@ -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;
index 2ad59d66ff7d238ec8e552b3ab8dd8cd34a7ef9d..6091e59998b46304d9a736bf3a68a5fe922801d4 100644 (file)
@@ -1,3 +1,21 @@
+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.
index bc3a93812f5f39d0d4c63bd412c67638bba2d9a0..5fcde0b7755465e3fb4c0b3af1e1f9e43c68bd20 100644 (file)
@@ -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 <const char *> (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 <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); };
@@ -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 "" }
index 8b6afeb052ad6f78a249d40cae8c96bd2fe729b0..c08fec4d019dd18957e95b003e862610093002a2 100644 (file)
@@ -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);
-                               ~~~~~~~~~~~~^~~
-   { 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 "" } */
 }
 
@@ -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));
-                               ^~~~~~~~~~
-   { 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 "" } */
 }
 
index 6094a9ca36b90448c9ec15c2a4435c4d164d5851..f2e772aec950a32dec221d9fc5defd8d61275794 100644 (file)
@@ -7,4 +7,6 @@ foo (void)
 {
   const char *const msg = "abc";
   bar (1, msg);
+  bar (1, msg + 1);
+  bar (1, 1 + msg);
 }
index 76d2dfdc215ac3942b23ec278d21a267ecfede4d..56acd10a6535884f9b6591338f48a25ad81e9a6d 100644 (file)
@@ -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
index 63084ac2d4f8e14c1d7759f9ea91ffd7c7a7a169..bed59d33bb2c72ec5882c7367e44389f90e98593 100644 (file)
@@ -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<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
@@ -14473,6 +14575,7 @@ tree_c_tests ()
   test_identifiers ();
   test_labels ();
   test_vector_cst_patterns ();
+  test_location_wrappers ();
 }
 
 } // namespace selftest
index 316dcfda0fa4c3305ecaa4ed4166516df5b8e966..f47e2338d2d9ac9dc949d5ce863cba5d065a843d 100644 (file)
@@ -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]