[PING] Re: [PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486)

David Malcolm dmalcolm@redhat.com
Mon Nov 19 16:51:00 GMT 2018


Ping, for these patches:

[PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
  https://gcc.gnu.org/ml/gcc-patches/2018-11/msg00304.html

[PATCH 2/2] C++: improvements to binary operator diagnostics (PR c++/87504)
  https://gcc.gnu.org/ml/gcc-patches/2018-11/msg00303.html


Thanks
Dave

On Mon, 2018-11-05 at 15:31 -0500, David Malcolm wrote:
> The C++ frontend gained various location wrapper nodes in r256448
> (GCC 8).
> That patch:
>   https://gcc.gnu.org/ml/gcc-patches/2018-01/msg00799.html
> added wrapper nodes around all nodes with !CAN_HAVE_LOCATION_P for:
> 
> * arguments at callsites, and for
> 
> * typeid, alignof, sizeof, and offsetof.
> 
> This is a followup to that patch, adding many more location wrappers
> to the C++ frontend.  It adds location wrappers for nodes with
> !CAN_HAVE_LOCATION_P to:
> 
> * all literal nodes (in cp_parser_primary_expression)
> 
> * all id-expression nodes (in finish_id_expression), except within a
>   decltype.
> 
> * all mem-initializer nodes within a mem-initializer-list
>   (in cp_parser_mem_initializer)
> 
> However, the patch also adds some suppressions: regions in the parser
> for which wrapper nodes will not be created:
> 
> * within a template-parameter-list or template-argument-list (in
>   cp_parser_template_parameter_list and
> cp_parser_template_argument_list
>   respectively), to avoid encoding the spelling location of the nodes
>   in types.  For example, "array<10>" and "array<10>" are the same
> type,
>   despite the fact that the two different "10" tokens are spelled in
>   different locations in the source.
> 
> * within a gnu-style attribute (none of are handlers are set up to
> cope
>   with location wrappers yet)
> 
> * within various OpenMP clauses
> 
> The patch enables various improvements to locations for bad
> initializations, for -Wchar-subscripts, and enables various other
> improvements in the followup patch.
> 
> For example, given the followup buggy mem-initializer:
> 
> class X {
>   X() : bad(42),
>         good(42)
>   { }
>   void* bad;
>   int good;
> };
> 
> previously, our diagnostic was on the final close parenthesis of the
> mem-initializer-list, leaving it unclear where the problem is:
> 
> t.cc: In constructor 'X::X()':
> t.cc:3:16: error: invalid conversion from 'int' to 'void*' [-
> fpermissive]
>     3 |         good(42)
>       |                ^
>       |                |
>       |                int
> 
> whereas with the patch we highlight which expression is bogus:
> 
> t.cc: In constructor 'X::X()':
> t.cc:2:13: error: invalid conversion from 'int' to 'void*' [-
> fpermissive]
>     2 |   X() : bad(42),
>       |             ^~
>       |             |
>       |             int
> 
> Similarly, the diagnostic for this bogus initialization:
> 
> i.cc:1:44: error: initializer-string for array of chars is too long
> [-fpermissive]
>     1 | char test[3][4] = { "ok", "too long", "ok" };
>       |                                            ^
> 
> is improved by the patch so that it indicates which string is too
> long:
> 
> i.cc:1:27: error: initializer-string for array of chars is too long
> [-fpermissive]
>     1 | char test[3][4] = { "ok", "too long", "ok" };
>       |                           ^~~~~~~~~~
> 
> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu, in
> conjunction with the followup patch [1]
> 
> I did some light performance testing, comparing release builds with
> and
> without the patch on kdecore.cc (preprocessed all-of-KDE) and a test
> file
> that includes all of the C++ stdlib (but does nothing) with it, in
> both
> cases compiling at -O3 -g.  In both cases there was no significant
> difference in the overall wallclock time for all of compilation:
> 
> kdecode.c total wallclock time:
> 
> http://chart.apis.google.com/chart?cht=lc&chs=700x400&chxt=x,y,x,y&ch
> xr=1,58.26,61.79&chco=FF0000,0000FF&chdl=control|experiment&chds=58.2
> 6,61.79&chd=t:59.55,60.26,60.53,60.35,60.17,60.27,59.26,60.01,60.21,6
> 0.23,60.1,60.2,60.12,60.48,60.32,60.18,60.01,60.01,60.04,59.96,60.1,6
> 0.11,60.21,60.36,60.08,60.1,60.16,60.01,60.21,60.15,60.12,60.09,59.96
> ,60.12,60.06,60.12,60.05,60.11,59.93,59.99|59.6,59.3,60.03,60.1,60.49
> ,60.35,60.03,60.1,59.87,60.39,60.1,59.96,60.19,60.45,59.97,59.91,60.0
> ,59.99,60.09,60.15,60.79,59.98,60.16,60.09,60.02,60.05,60.32,60.01,59
> .95,59.88,60.1,60.07,60.22,59.87,60.04,60.11,60.01,60.09,59.86,59.86&
> chxl=0:|1|8|16|24|32|40|2:||Iteration|3:||Time+(secs)&chtt=Compilatio
> n+of+kdecore.cc+at+-O3+with+-g+for+x86_64-pc-linux-gnu:+total:+wall
> 
> cp-stdlib.cc total wallclock time:
> 
> http://chart.apis.google.com/chart?cht=lc&chs=700x400&chxt=x,y,x,y&ch
> xr=1,1.88,4.59&chco=FF0000,0000FF&chdl=control|experiment&chds=1.88,4
> .59&chd=t:3.59,2.94,2.95,2.94,2.94,2.93,2.92,2.94,2.93,2.94,2.94,2.88
> ,2.94,2.9,2.94,2.9,2.94,2.93,2.94,2.93,2.95,2.93,2.9,2.9,2.94,2.99,2.
> 95,3.0,2.94,3.0,2.94,2.99,2.95,2.95,2.9,2.99,2.94,2.99,2.94,2.96|3.54
> ,2.92,2.93,2.88,2.94,2.92,2.93,2.92,2.9,2.93,2.89,2.93,2.9,2.93,2.89,
> 2.91,2.93,2.92,2.89,2.93,2.93,2.92,2.93,2.92,2.93,2.92,2.88,2.92,2.89
> ,2.93,2.94,2.92,2.9,2.92,2.92,2.91,2.94,2.92,2.98,2.88&chxl=0:|1|8|16
> |24|32|40|2:||Iteration|3:||Time+(secs)&chtt=Compilation+of+cp-
> stdlib.cc+at+-O3+with+-g+for+x86_64-pc-linux-gnu:+total:+wall
> 
> -ftime-report did show that kdecode.cc's "phase parsing" was 3%
> slower
> by wallclock:
> 
> http://chart.apis.google.com/chart?cht=lc&chs=700x400&chxt=x,y,x,y&ch
> xr=1,1.71,3.95&chco=FF0000,0000FF&chdl=control|experiment&chds=1.71,3
> .95&chd=t:2.74,2.72,2.73,2.8,2.72,2.73,2.72,2.74,2.73,2.73,2.73,2.73,
> 2.73,2.72,2.72,2.72,2.73,2.72,2.72,2.72,2.73,2.73,2.73,2.71,2.72,2.72
> ,2.73,2.73,2.72,2.73,2.73,2.72,2.73,2.73,2.73,2.72,2.73,2.72,2.72,2.7
> 2|2.81,2.78,2.78,2.79,2.78,2.78,2.78,2.79,2.78,2.79,2.8,2.79,2.78,2.7
> 8,2.79,2.78,2.79,2.79,2.8,2.79,2.79,2.78,2.79,2.8,2.79,2.79,2.78,2.79
> ,2.79,2.78,2.78,2.8,2.95,2.78,2.79,2.79,2.79,2.79,2.79,2.79&chxl=0:|1
> |8|16|24|32|40|2:||Iteration|3:||Time+(secs)&chtt=Compilation+of+kdec
> ore.cc+at+-O3+with+-g+for+x86_64-pc-linux-gnu:+phase+parsing:+wall
> 
> but this time was lost in the noise when optimizing.
> There was no significant change for the other test's "phase parsing"
> timing.
> 
> "mem max" ggc usage for both workloads increased by roughly half a
> percent larger. (kdecore.cc went up from 1295533.000 to 1301373.000;
> cp-stdlib.cc from 189535.000 to 190580.000).
> 
> OK for trunk?
> Dave
> 
> [1] I've split them up for ease of review; they could be reworked to
> be
> fully independent, but there's some churn in the results for
> -Wtautological-compare introduced by the 1st patch which the 2nd
> patch addresses.
> 
> gcc/ChangeLog:
> 	PR c++/43064
> 	PR c++/43486
> 	* convert.c: Include "selftest.h".
> 	(preserve_any_location_wrapper): New function.
> 	(convert_to_pointer_maybe_fold): Update to handle location
> 	wrappers.
> 	(convert_to_real_maybe_fold): Likewise.
> 	(convert_to_integer_1): Handle location wrappers when checking
> for
> 	INTEGER_CST.
> 	(convert_to_integer_maybe_fold): Update to handle location
> 	wrappers.
> 	(convert_to_complex_maybe_fold): Likewise.
> 	(selftest::test_convert_to_integer_maybe_fold): New functions.
> 	(selftest::convert_c_tests): New function.
> 	* fold-const.c (operand_equal_p): Strip any location wrappers.
> 	* selftest-run-tests.c (selftest::run_tests): Call
> 	selftest::convert_c_tests.
> 	* selftest.h (selftest::convert_c_tests): New decl.
> 	* tree.c (tree_int_cst_equal): Strip any location wrappers.
> 	(maybe_wrap_with_location): Don't create wrappers if any
> 	auto_suppress_location_wrappers are active.
> 	(suppress_location_wrappers): New variable.
> 	* tree.h (CONSTANT_CLASS_OR_WRAPPER_P): New macro.
> 	(suppress_location_wrappers): New decl.
> 	(class auto_suppress_location_wrappers): New class.
> 
> gcc/c-family/ChangeLog:
> 	PR c++/43064
> 	PR c++/43486
> 	* c-common.c (unsafe_conversion_p): Strip any location wrapper.
> 	(verify_tree): Handle location wrappers.
> 	(c_common_truthvalue_conversion): Strip any location wrapper.
> 	Handle CONST_DECL.
> 	(fold_offsetof): Strip any location wrapper.
> 	(complete_array_type): Likewise for initial_value.
> 	(convert_vector_to_array_for_subscript): Call fold_for_warn on
> the
> 	index before checking for INTEGER_CST.
> 	* c-pretty-print.c (c_pretty_printer::primary_expression):
> Don't
> 	print parentheses around location wrappers.
> 	* c-warn.c (warn_logical_operator): Call fold_for_warn on
> op_right
> 	before checking for INTEGER_CST.
> 	(warn_tautological_bitwise_comparison): Call
> 	tree_strip_any_location_wrapper on lhs, rhs, and bitop's
> operand
> 	before checking for INTEGER_CST.
> 	(readonly_error): Strip any location wrapper.
> 	(warn_array_subscript_with_type_char): Strip location wrappers
> 	before checking for INTEGER_CST.  Use the location of the index
> if
> 	available.
> 
> gcc/cp/ChangeLog:
> 	PR c++/43064
> 	PR c++/43486
> 	* call.c (build_conditional_expr_1): Strip location wrappers
> when
> 	checking for CONST_DECL.
> 	(conversion_null_warnings): Use location of "expr" if
> available.
> 	* class.c (fixed_type_or_null): Handle location wrappers.
> 	* constexpr.c (potential_constant_expression_1): Likewise.
> 	* cvt.c (ignore_overflows): Strip location wrappers when
> 	checking for INTEGER_CST, and re-wrap the result if present.
> 	(ocp_convert): Call fold_for_warn before checking for
> INTEGER_CST.
> 	* decl.c (reshape_init_r): Strip any location wrapper.
> 	(undeduced_auto_decl): Likewise.
> 	* decl2.c (grokbitfield): Likewise for width.
> 	* expr.c (mark_discarded_use): Likewise for expr.
> 	* init.c (build_aggr_init): Likewise before checking init for
> 	DECL_P.
> 	(warn_placement_new_too_small): Call fold_for_warn on adj
> before
> 	checking for CONSTANT_CLASS_P, and on nelts.  Strip any
> location
> 	wrapper from op0 and on oper before checking for VAR_P.
> 	* lambda.c (add_capture): Strip any location from initializer.
> 	* name-lookup.c (handle_namespace_attrs): Strip any location
> from
> 	x before checking for STRING_CST.
> 	* parser.c (cp_parser_primary_expression): Call
> 	maybe_add_location_wrapper on numeric and string literals.
> 	(cp_parser_postfix_expression): Strip any location wrapper when
> 	checking for DECL_IS_BUILTIN_CONSTANT_P.
> 	(cp_parser_binary_expression): Strip any location wrapper when
> 	checking for DECL_P on the lhs.
> 	(cp_parser_decltype_expr): Suppress location wrappers in the
> 	id-expression.
> 	(cp_parser_mem_initializer): Add location wrappers to the
> 	parenthesized expression list.
> 	(cp_parser_template_parameter_list): Don't create wrapper nodes
> 	within a template-parameter-list.
> 	(cp_parser_template_argument_list): Don't create wrapper nodes
> 	within a template-argument-list.
> 	(cp_parser_parameter_declaration): Strip location wrappers from
> 	default arguments.
> 	(cp_parser_gnu_attribute_list): Don't create wrapper nodes
> within
> 	an attribute.
> 	(cp_parser_late_parsing_default_args): Strip location wrappers
> 	from default arguments.
> 	(cp_parser_omp_all_clauses): Don't create wrapper nodes within
> 	OpenMP clauses.
> 	(cp_parser_omp_for_loop): Likewise.
> 	(cp_parser_omp_declare_reduction_exprs): Likewise.
> 	* pt.c (convert_nontype_argument_function): Strip location
> 	wrappers from fn_no_ptr before checking for FUNCTION_DECL.
> 	(do_auto_deduction): Likewise from init before checking for
> 	DECL_P.
> 	* semantics.c (force_paren_expr): Likewise from expr before
> 	checking for DECL_P.
> 	(finish_parenthesized_expr): Likewise from expr before
> 	checking for STRING_CST.
> 	(perform_koenig_lookup): Likewise from fn.
> 	(finish_call_expr): Likewise.
> 	(finish_id_expression): Rename to...
> 	(finish_id_expression_1): ...this, calling
> 	maybe_add_location_wrapper on the result.
> 	* tree.c (cp_stabilize_reference): Strip any location wrapper.
> 	(builtin_valid_in_constant_expr_p): Likewise.
> 	(is_overloaded_fn): Likewise.
> 	(maybe_get_fns): Likewise.
> 	(selftest::test_lvalue_kind): Verify lvalue_p.
> 	* typeck.c (cxx_sizeof_expr): Strip any location wrapper.
> 	(cxx_alignof_expr): Likewise.
> 	(is_bitfield_expr_with_lowered_type): Handle location wrappers.
> 	(cp_build_array_ref): Strip location wrappers from idx before
> 	checking for INTEGER_CST.
> 	(cp_build_binary_op): Strip location wrapper from first_arg
> before
> 	checking for PARM_DECL.  Likewise for op1 before checking for
> 	INTEGER_CST in two places.  Likewise for orig_op0 and orig_op1
> 	when checking for STRING_CST.
> 	(cp_build_addr_expr_1): Likewise for arg when checking for
> 	FUNCTION_DECL.
> 	(cp_build_modify_expr): Likewise for newrhs when checking for
> 	STRING_CST.
> 	(convert_for_assignment): Don't strip location wrappers when
> 	stripping NON_LVALUE_EXPR.
> 	(maybe_warn_about_returning_address_of_local): Strip location
> 	wrapper from whats_returned before checking for DECL_P.
> 	(can_do_nrvo_p): Strip location wrapper from retval.
> 	(treat_lvalue_as_rvalue_p): Likewise.
> 	(check_return_expr): Likewise.
> 	* typeck2.c (cxx_incomplete_type_diagnostic): Strip location
> 	wrapper from value before checking for VAR_P or PARM_DECL.
> 	(digest_init_r): Strip location wrapper from init.  When
> 	copying "init", also copy the wrapped node.
> 
> gcc/objc/ChangeLog:
> 	PR c++/43064
> 	PR c++/43486
> 	* objc-act.c (objc_maybe_build_component_ref): Strip any
> location
> 	wrapper before checking for UOBJC_SUPER_decl and self_decl.
> 	(objc_finish_message_expr): Strip any location wrapper.
> 
> gcc/testsuite/ChangeLog:
> 	PR c++/43064
> 	PR c++/43486
> 	* c-c++-common/pr51712.c (valid2): Mark xfail as passing on
> C++.
> 	* g++.dg/cpp1z/decomp48.C: Update expected location of warning
> 	for named local variables to use that of the local variable.
> 	* g++.dg/init/array43.C: Update expected column to be that of
> the
> 	initializer.
> 	* g++.dg/init/initializer-string-too-long.C: New test.
> 	* g++.dg/init/pr43064-1.C: New test.
> 	* g++.dg/init/pr43064-2.C: New test.
> 	* g++.dg/init/pr43064-3.C: New test.
> 	* g++.dg/wrappers/Wparentheses.C: New test.
> ---
>  gcc/c-family/c-common.c                            |  22 ++++
>  gcc/c-family/c-pretty-print.c                      |  11 +-
>  gcc/c-family/c-warn.c                              |  70 ++++++-----
>  gcc/convert.c                                      | 132
> +++++++++++++++++++--
>  gcc/cp/call.c                                      |  19 +--
>  gcc/cp/class.c                                     |   6 +
>  gcc/cp/constexpr.c                                 |  17 ++-
>  gcc/cp/cvt.c                                       |  25 ++--
>  gcc/cp/decl.c                                      |  33 +++---
>  gcc/cp/decl2.c                                     |   3 +
>  gcc/cp/expr.c                                      |   2 +
>  gcc/cp/init.c                                      |   9 +-
>  gcc/cp/lambda.c                                    |   3 +
>  gcc/cp/name-lookup.c                               |   2 +
>  gcc/cp/parser.c                                    |  52 ++++++--
>  gcc/cp/pt.c                                        |   4 +-
>  gcc/cp/semantics.c                                 |  77 ++++++++---
> -
>  gcc/cp/tree.c                                      |  14 +++
>  gcc/cp/typeck.c                                    | 110
> +++++++++++------
>  gcc/cp/typeck2.c                                   |  56 +++++----
>  gcc/fold-const.c                                   |   3 +
>  gcc/objc/objc-act.c                                |   4 +
>  gcc/selftest-run-tests.c                           |   1 +
>  gcc/selftest.h                                     |   1 +
>  gcc/testsuite/c-c++-common/pr51712.c               |   2 +-
>  gcc/testsuite/g++.dg/cpp1z/decomp48.C              |   8 +-
>  gcc/testsuite/g++.dg/init/array43.C                |   2 +-
>  .../g++.dg/init/initializer-string-too-long.C      |   9 ++
>  gcc/testsuite/g++.dg/init/pr43064-1.C              |  21 ++++
>  gcc/testsuite/g++.dg/init/pr43064-2.C              |  34 ++++++
>  gcc/testsuite/g++.dg/init/pr43064-3.C              |  32 +++++
>  gcc/testsuite/g++.dg/wrappers/Wparentheses.C       |  10 ++
>  gcc/tree.c                                         |  10 ++
>  gcc/tree.h                                         |  19 +++
>  34 files changed, 655 insertions(+), 168 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/init/initializer-string-too-
> long.C
>  create mode 100644 gcc/testsuite/g++.dg/init/pr43064-1.C
>  create mode 100644 gcc/testsuite/g++.dg/init/pr43064-2.C
>  create mode 100644 gcc/testsuite/g++.dg/init/pr43064-3.C
>  create mode 100644 gcc/testsuite/g++.dg/wrappers/Wparentheses.C
> 
> diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
> index f10cf89..0386045 100644
> --- a/gcc/c-family/c-common.c
> +++ b/gcc/c-family/c-common.c
> @@ -1236,6 +1236,8 @@ unsafe_conversion_p (location_t loc, tree type,
> tree expr, tree result,
>  
>      loc = expansion_point_location_if_in_system_header (loc);
>  
> +  STRIP_ANY_LOCATION_WRAPPER (expr);
> +
>    if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) ==
> INTEGER_CST)
>      {
>        /* If type is complex, we are interested in compatibility with
> @@ -1933,6 +1935,13 @@ verify_tree (tree x, struct tlist
> **pbefore_sp, struct tlist **pno_sp,
>        writer = 0;
>        goto restart;
>  
> +    case VIEW_CONVERT_EXPR:
> +      if (location_wrapper_p (x))
> +	{
> +	  x = TREE_OPERAND (x, 0);
> +	  goto restart;
> +	}
> +      gcc_fallthrough ();
>      default:
>        /* For other expressions, simply recurse on their operands.
>  	 Manual tail recursion for unary expressions.
> @@ -3227,6 +3236,7 @@ decl_with_nonnull_addr_p (const_tree expr)
>  tree
>  c_common_truthvalue_conversion (location_t location, tree expr)
>  {
> +  STRIP_ANY_LOCATION_WRAPPER (expr);
>    switch (TREE_CODE (expr))
>      {
>      case EQ_EXPR:   case NE_EXPR:   case UNEQ_EXPR: case LTGT_EXPR:
> @@ -3446,6 +3456,14 @@ c_common_truthvalue_conversion (location_t
> location, tree expr)
>  	}
>        break;
>  
> +    case CONST_DECL:
> +      {
> +	tree folded_expr = fold_for_warn (expr);
> +	if (folded_expr != expr)
> +	  return c_common_truthvalue_conversion (location,
> folded_expr);
> +      }
> +      break;
> +
>      default:
>        break;
>      }
> @@ -6226,6 +6244,7 @@ fold_offsetof (tree expr, tree type, enum
> tree_code ctx)
>  	return base;
>  
>        t = TREE_OPERAND (expr, 1);
> +      STRIP_ANY_LOCATION_WRAPPER (t);
>  
>        /* Check if the offset goes beyond the upper bound of the
> array.  */
>        if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) >= 0)
> @@ -6304,6 +6323,8 @@ complete_array_type (tree *ptype, tree
> initial_value, bool do_default)
>    maxindex = size_zero_node;
>    if (initial_value)
>      {
> +      STRIP_ANY_LOCATION_WRAPPER (initial_value);
> +
>        if (TREE_CODE (initial_value) == STRING_CST)
>  	{
>  	  int eltsize
> @@ -7853,6 +7874,7 @@ convert_vector_to_array_for_subscript
> (location_t loc,
>  
>        ret = !lvalue_p (*vecp);
>  
> +      index = fold_for_warn (index);
>        if (TREE_CODE (index) == INTEGER_CST)
>          if (!tree_fits_uhwi_p (index)
>  	    || maybe_ge (tree_to_uhwi (index), TYPE_VECTOR_SUBPARTS
> (type)))
> diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-
> print.c
> index a13cd84..5a55440 100644
> --- a/gcc/c-family/c-pretty-print.c
> +++ b/gcc/c-family/c-pretty-print.c
> @@ -1260,9 +1260,14 @@ c_pretty_printer::primary_expression (tree e)
>  
>      default:
>        /* FIXME:  Make sure we won't get into an infinite loop.  */
> -      pp_c_left_paren (this);
> -      expression (e);
> -      pp_c_right_paren (this);
> +      if (location_wrapper_p (e))
> +	expression (e);
> +      else
> +	{
> +	  pp_c_left_paren (this);
> +	  expression (e);
> +	  pp_c_right_paren (this);
> +	}
>        break;
>      }
>  }
> diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
> index a1a7f93..f2ed711 100644
> --- a/gcc/c-family/c-warn.c
> +++ b/gcc/c-family/c-warn.c
> @@ -208,19 +208,22 @@ warn_logical_operator (location_t location,
> enum tree_code code, tree type,
>    if (!truth_value_p (code_left)
>        && INTEGRAL_TYPE_P (TREE_TYPE (op_left))
>        && !CONSTANT_CLASS_P (op_left)
> -      && !TREE_NO_WARNING (op_left)
> -      && TREE_CODE (op_right) == INTEGER_CST
> -      && !integer_zerop (op_right)
> -      && !integer_onep (op_right))
> +      && !TREE_NO_WARNING (op_left))
>      {
> -      if (or_op)
> -	warning_at (location, OPT_Wlogical_op, "logical %<or%>"
> -		    " applied to non-boolean constant");
> -      else
> -	warning_at (location, OPT_Wlogical_op, "logical %<and%>"
> -		    " applied to non-boolean constant");
> -      TREE_NO_WARNING (op_left) = true;
> -      return;
> +      tree folded_op_right = fold_for_warn (op_right);
> +      if (TREE_CODE (folded_op_right) == INTEGER_CST
> +	  && !integer_zerop (folded_op_right)
> +	  && !integer_onep (folded_op_right))
> +	{
> +	  if (or_op)
> +	    warning_at (location, OPT_Wlogical_op, "logical %<or%>"
> +			" applied to non-boolean constant");
> +	  else
> +	    warning_at (location, OPT_Wlogical_op, "logical %<and%>"
> +			" applied to non-boolean constant");
> +	  TREE_NO_WARNING (op_left) = true;
> +	  return;
> +	}
>      }
>  
>    /* We do not warn for constants because they are typical of macro
> @@ -340,24 +343,30 @@ warn_tautological_bitwise_comparison
> (location_t loc, tree_code code,
>    /* Extract the operands from e.g. (x & 8) == 4.  */
>    tree bitop;
>    tree cst;
> +  tree stripped_lhs = tree_strip_any_location_wrapper (lhs);
> +  tree stripped_rhs = tree_strip_any_location_wrapper (rhs);
>    if ((TREE_CODE (lhs) == BIT_AND_EXPR
>         || TREE_CODE (lhs) == BIT_IOR_EXPR)
> -      && TREE_CODE (rhs) == INTEGER_CST)
> -    bitop = lhs, cst = rhs;
> +      && TREE_CODE (stripped_rhs) == INTEGER_CST)
> +    bitop = lhs, cst = stripped_rhs;
>    else if ((TREE_CODE (rhs) == BIT_AND_EXPR
>  	    || TREE_CODE (rhs) == BIT_IOR_EXPR)
> -	   && TREE_CODE (lhs) == INTEGER_CST)
> -    bitop = rhs, cst = lhs;
> +	   && TREE_CODE (stripped_lhs) == INTEGER_CST)
> +    bitop = rhs, cst = stripped_lhs;
>    else
>      return;
>  
>    tree bitopcst;
> -  if (TREE_CODE (TREE_OPERAND (bitop, 0)) == INTEGER_CST)
> -    bitopcst = TREE_OPERAND (bitop, 0);
> -  else if (TREE_CODE (TREE_OPERAND (bitop, 1)) == INTEGER_CST)
> -    bitopcst = TREE_OPERAND (bitop, 1);
> -  else
> -    return;
> +  tree bitop_op0 = fold_for_warn (TREE_OPERAND (bitop, 0));
> +  if (TREE_CODE (bitop_op0) == INTEGER_CST)
> +    bitopcst = bitop_op0;
> +  else {
> +    tree bitop_op1 = fold_for_warn (TREE_OPERAND (bitop, 1));
> +    if (TREE_CODE (bitop_op1) == INTEGER_CST)
> +      bitopcst = bitop_op1;
> +    else
> +      return;
> +  }
>  
>    /* Note that the two operands are from before the usual integer
>       conversions, so their types might not be the same.
> @@ -1524,6 +1533,7 @@ readonly_error (location_t loc, tree arg, enum
> lvalue_use use)
>  {
>    gcc_assert (use == lv_assign || use == lv_increment || use ==
> lv_decrement
>  	      || use == lv_asm);
> +  STRIP_ANY_LOCATION_WRAPPER (arg);
>    /* Using this macro rather than (for example) arrays of messages
>       ensures that all the format strings are checked at compile
>       time.  */
> @@ -1664,15 +1674,21 @@ invalid_indirection_error (location_t loc,
> tree type, ref_operator errstring)
>     warn for unsigned char since that type is safe.  Don't warn for
>     signed char because anyone who uses that must have done so
>     deliberately. Furthermore, we reduce the false positive load by
> -   warning only for non-constant value of type char.  */
> +   warning only for non-constant value of type char.
> +   LOC is the location of the subscripting expression.  */
>  
>  void
>  warn_array_subscript_with_type_char (location_t loc, tree index)
>  {
> -  if (TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node
> -      && TREE_CODE (index) != INTEGER_CST)
> -    warning_at (loc, OPT_Wchar_subscripts,
> -		"array subscript has type %<char%>");
> +  if (TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node)
> +    {
> +      STRIP_ANY_LOCATION_WRAPPER (index);
> +      if (TREE_CODE (index) != INTEGER_CST)
> +	/* If INDEX has a location, use it; otherwise use LOC (the
> location
> +	   of the subscripting expression as a whole).  */
> +	warning_at (EXPR_LOC_OR_LOC (index, loc),
> OPT_Wchar_subscripts,
> +		    "array subscript has type %<char%>");
> +    }
>  }
>  
>  /* Implement -Wparentheses for the unexpected C precedence rules, to
> diff --git a/gcc/convert.c b/gcc/convert.c
> index 68705f3..043a5d0 100644
> --- a/gcc/convert.c
> +++ b/gcc/convert.c
> @@ -36,6 +36,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "stringpool.h"
>  #include "attribs.h"
>  #include "asan.h"
> +#include "selftest.h"
>  
>  #define maybe_fold_build1_loc(FOLD_P, LOC, CODE, TYPE, EXPR) \
>    ((FOLD_P) ? fold_build1_loc (LOC, CODE, TYPE, EXPR)	     \
> @@ -98,6 +99,25 @@ convert_to_pointer_1 (tree type, tree expr, bool
> fold_p)
>      }
>  }
>  
> +/* Subroutine of the various convert_to_*_maybe_fold routines.
> +
> +   If a location wrapper has been folded to a constant (presumably
> of
> +   a different type), re-wrap the new constant with a location
> wrapper.  */
> +
> +static tree
> +preserve_any_location_wrapper (tree result, tree orig_expr)
> +{
> +  if (CONSTANT_CLASS_P (result) && location_wrapper_p (orig_expr))
> +    {
> +      if (result == TREE_OPERAND (orig_expr, 0))
> +	return orig_expr;
> +      else
> +	return maybe_wrap_with_location (result, EXPR_LOCATION
> (orig_expr));
> +    }
> +
> +  return result;
> +}
> +
>  /* A wrapper around convert_to_pointer_1 that always folds the
>     expression.  */
>  
> @@ -108,12 +128,15 @@ convert_to_pointer (tree type, tree expr)
>  }
>  
>  /* A wrapper around convert_to_pointer_1 that only folds the
> -   expression if DOFOLD, or if it is CONSTANT_CLASS_P.  */
> +   expression if DOFOLD, or if it is
> CONSTANT_CLASS_OR_WRAPPER_P.  */
>  
>  tree
>  convert_to_pointer_maybe_fold (tree type, tree expr, bool dofold)
>  {
> -  return convert_to_pointer_1 (type, expr, dofold ||
> CONSTANT_CLASS_P (expr));
> +  tree result
> +    = convert_to_pointer_1 (type, expr,
> +			    dofold || CONSTANT_CLASS_OR_WRAPPER_P
> (expr));
> +  return preserve_any_location_wrapper (result, expr);
>  }
>  
>  /* Convert EXPR to some floating-point type TYPE.
> @@ -408,12 +431,15 @@ convert_to_real (tree type, tree expr)
>  }
>  
>  /* A wrapper around convert_to_real_1 that only folds the
> -   expression if DOFOLD, or if it is CONSTANT_CLASS_P.  */
> +   expression if DOFOLD, or if it is
> CONSTANT_CLASS_OR_WRAPPER_P.  */
>  
>  tree
>  convert_to_real_maybe_fold (tree type, tree expr, bool dofold)
>  {
> -  return convert_to_real_1 (type, expr, dofold || CONSTANT_CLASS_P
> (expr));
> +  tree result
> +    = convert_to_real_1 (type, expr,
> +			 dofold || CONSTANT_CLASS_OR_WRAPPER_P
> (expr));
> +  return preserve_any_location_wrapper (result, expr);
>  }
>  
>  /* Try to narrow EX_FORM ARG0 ARG1 in narrowed arg types producing a
> @@ -959,7 +985,7 @@ convert_to_integer_1 (tree type, tree expr, bool
> dofold)
>  
>        /* When parsing long initializers, we might end up with a lot
> of casts.
>  	 Shortcut this.  */
> -      if (TREE_CODE (expr) == INTEGER_CST)
> +      if (TREE_CODE (tree_strip_any_location_wrapper (expr)) ==
> INTEGER_CST)
>  	return fold_convert (type, expr);
>        return build1 (CONVERT_EXPR, type, expr);
>  
> @@ -1017,12 +1043,15 @@ convert_to_integer (tree type, tree expr)
>  }
>  
>  /* A wrapper around convert_to_complex_1 that only folds the
> -   expression if DOFOLD, or if it is CONSTANT_CLASS_P.  */
> +   expression if DOFOLD, or if it is
> CONSTANT_CLASS_OR_WRAPPER_P.  */
>  
>  tree
>  convert_to_integer_maybe_fold (tree type, tree expr, bool dofold)
>  {
> -  return convert_to_integer_1 (type, expr, dofold ||
> CONSTANT_CLASS_P (expr));
> +  tree result
> +    = convert_to_integer_1 (type, expr,
> +			    dofold || CONSTANT_CLASS_OR_WRAPPER_P
> (expr));
> +  return preserve_any_location_wrapper (result, expr);
>  }
>  
>  /* Convert EXPR to the complex type TYPE in the usual ways.  If
> FOLD_P is
> @@ -1101,12 +1130,15 @@ convert_to_complex (tree type, tree expr)
>  }
>  
>  /* A wrapper around convert_to_complex_1 that only folds the
> -   expression if DOFOLD, or if it is CONSTANT_CLASS_P.  */
> +   expression if DOFOLD, or if it is
> CONSTANT_CLASS_OR_WRAPPER_P.  */
>  
>  tree
>  convert_to_complex_maybe_fold (tree type, tree expr, bool dofold)
>  {
> -  return convert_to_complex_1 (type, expr, dofold ||
> CONSTANT_CLASS_P (expr));
> +  tree result
> +    = convert_to_complex_1 (type, expr,
> +			    dofold || CONSTANT_CLASS_OR_WRAPPER_P
> (expr));
> +  return preserve_any_location_wrapper (result, expr);
>  }
>  
>  /* Convert EXPR to the vector type TYPE in the usual ways.  */
> @@ -1171,3 +1203,85 @@ convert_to_fixed (tree type, tree expr)
>        return error_mark_node;
>      }
>  }
> +
> +#if CHECKING_P
> +
> +namespace selftest {
> +
> +/* Selftests for conversions.  */
> +
> +static void
> +test_convert_to_integer_maybe_fold (tree orig_type, tree new_type)
> +{
> +  /* Calling convert_to_integer_maybe_fold on an INTEGER_CST.  */
> +
> +  tree orig_cst = build_int_cst (orig_type, 42);
> +
> +  /* Verify that convert_to_integer_maybe_fold on a constant returns
> a new
> +     constant of the new type, unless the types are the same, in
> which
> +     case verify it's a no-op.  */
> +  {
> +    tree result = convert_to_integer_maybe_fold (new_type,
> +						 orig_cst, false);
> +    if (orig_type != new_type)
> +      {
> +	ASSERT_EQ (TREE_TYPE (result), new_type);
> +	ASSERT_EQ (TREE_CODE (result), INTEGER_CST);
> +      }
> +    else
> +      ASSERT_EQ (result, orig_cst);
> +  }
> +
> +  /* Calling convert_to_integer_maybe_fold on a location wrapper
> around
> +     an INTEGER_CST.
> +
> +     Verify that convert_to_integer_maybe_fold on a location wrapper
> +     around a constant returns a new location wrapper around an
> equivalent
> +     constant, both of the new type, unless the types are the same,
> +     in which case the original wrapper should be returned.   */
> +  {
> +    const location_t loc = BUILTINS_LOCATION;
> +    tree wrapped_orig_cst = maybe_wrap_with_location (orig_cst,
> loc);
> +    tree result
> +      = convert_to_integer_maybe_fold (new_type, wrapped_orig_cst,
> false);
> +    ASSERT_EQ (TREE_TYPE (result), new_type);
> +    ASSERT_EQ (EXPR_LOCATION (result), loc);
> +    ASSERT_TRUE (location_wrapper_p (result));
> +    ASSERT_EQ (TREE_TYPE (TREE_OPERAND (result, 0)), new_type);
> +    ASSERT_EQ (TREE_CODE (TREE_OPERAND (result, 0)), INTEGER_CST);
> +
> +    if (orig_type == new_type)
> +      ASSERT_EQ (result, wrapped_orig_cst);
> +  }
> +}
> +
> +/* Verify that convert_to_integer_maybe_fold preserves
> locations.  */
> +
> +static void
> +test_convert_to_integer_maybe_fold ()
> +{
> +  /* char -> long.  */
> +  test_convert_to_integer_maybe_fold (char_type_node,
> long_integer_type_node);
> +
> +  /* char -> char.  */
> +  test_convert_to_integer_maybe_fold (char_type_node,
> char_type_node);
> +
> +  /* long -> char.  */
> +  test_convert_to_integer_maybe_fold (char_type_node,
> long_integer_type_node);
> +
> +  /* long -> long.  */
> +  test_convert_to_integer_maybe_fold (long_integer_type_node,
> +				      long_integer_type_node);
> +}
> +
> +/* Run all of the selftests within this file.  */
> +
> +void
> +convert_c_tests ()
> +{
> +  test_convert_to_integer_maybe_fold ();
> +}
> +
> +} // namespace selftest
> +
> +#endif /* CHECKING_P */
> diff --git a/gcc/cp/call.c b/gcc/cp/call.c
> index cd0c0f6..d366d35 100644
> --- a/gcc/cp/call.c
> +++ b/gcc/cp/call.c
> @@ -5341,9 +5341,12 @@ build_conditional_expr_1 (location_t loc, tree
> arg1, tree arg2, tree arg3,
>        if (TREE_CODE (arg2_type) == ENUMERAL_TYPE
>  	  && TREE_CODE (arg3_type) == ENUMERAL_TYPE)
>          {
> -	  if (TREE_CODE (orig_arg2) == CONST_DECL
> -	      && TREE_CODE (orig_arg3) == CONST_DECL
> -	      && DECL_CONTEXT (orig_arg2) == DECL_CONTEXT
> (orig_arg3))
> +	  tree stripped_orig_arg2 = tree_strip_any_location_wrapper
> (orig_arg2);
> +	  tree stripped_orig_arg3 = tree_strip_any_location_wrapper
> (orig_arg3);
> +	  if (TREE_CODE (stripped_orig_arg2) == CONST_DECL
> +	      && TREE_CODE (stripped_orig_arg3) == CONST_DECL
> +	      && (DECL_CONTEXT (stripped_orig_arg2)
> +		  == DECL_CONTEXT (stripped_orig_arg3)))
>  	    /* Two enumerators from the same enumeration can have
> different
>  	       types when the enumeration is still being
> defined.  */;
>            else if (complain & tf_warning)
> @@ -6630,8 +6633,8 @@ conversion_null_warnings (tree totype, tree
> expr, tree fn, int argnum)
>    if (null_node_p (expr) && TREE_CODE (totype) != BOOLEAN_TYPE
>        && ARITHMETIC_TYPE_P (totype))
>      {
> -      source_location loc =
> -	expansion_point_location_if_in_system_header
> (input_location);
> +      location_t loc = EXPR_LOC_OR_LOC (expr, input_location);
> +      loc = expansion_point_location_if_in_system_header (loc);
>  
>        if (fn)
>  	warning_at (loc, OPT_Wconversion_null,
> @@ -6646,12 +6649,14 @@ conversion_null_warnings (tree totype, tree
> expr, tree fn, int argnum)
>    else if (TREE_CODE (TREE_TYPE (expr)) == BOOLEAN_TYPE
>  	   && TYPE_PTR_P (totype))
>      {
> +      location_t loc = EXPR_LOC_OR_LOC (expr, input_location);
> +
>        if (fn)
> -	warning_at (input_location, OPT_Wconversion_null,
> +	warning_at (loc, OPT_Wconversion_null,
>  		    "converting %<false%> to pointer type for
> argument %P "
>  		    "of %qD", argnum, fn);
>        else
> -	warning_at (input_location, OPT_Wconversion_null,
> +	warning_at (loc, OPT_Wconversion_null,
>  		    "converting %<false%> to pointer type %qT",
> totype);
>      }
>    /* Handle zero as null pointer warnings for cases other
> diff --git a/gcc/cp/class.c b/gcc/cp/class.c
> index 1789d1e..8b36e30 100644
> --- a/gcc/cp/class.c
> +++ b/gcc/cp/class.c
> @@ -7375,6 +7375,12 @@ fixed_type_or_null (tree instance, int
> *nonnull, int *cdtorp)
>  	}
>        return NULL_TREE;
>  
> +    case VIEW_CONVERT_EXPR:
> +      if (location_wrapper_p (instance))
> +	return RECUR (TREE_OPERAND (instance, 0));
> +      else
> +	return NULL_TREE;
> +
>      default:
>        return NULL_TREE;
>      }
> diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
> index 4fa8c96..00f639b 100644
> --- a/gcc/cp/constexpr.c
> +++ b/gcc/cp/constexpr.c
> @@ -5698,13 +5698,18 @@ potential_constant_expression_1 (tree t, bool
> want_rval, bool strict, bool now,
>  	 may change to something more specific to type-punning (DR
> 1312).  */
>        {
>          tree from = TREE_OPERAND (t, 0);
> -	if (INDIRECT_TYPE_P (TREE_TYPE (t))
> -	    && TREE_CODE (from) == INTEGER_CST
> -	    && !integer_zerop (from))
> +	if (location_wrapper_p (t))
> +	  return (RECUR (from, want_rval));
> +	if (INDIRECT_TYPE_P (TREE_TYPE (t)))
>  	  {
> -	    if (flags & tf_error)
> -	      error_at (loc, "reinterpret_cast from integer to
> pointer");
> -	    return false;
> +	    STRIP_ANY_LOCATION_WRAPPER (from);
> +	    if (TREE_CODE (from) == INTEGER_CST
> +		&& !integer_zerop (from))
> +	      {
> +		if (flags & tf_error)
> +		  error_at (loc, "reinterpret_cast from integer to
> pointer");
> +		return false;
> +	      }
>  	  }
>          return (RECUR (from, TREE_CODE (t) != VIEW_CONVERT_EXPR));
>        }
> diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
> index 315b0d6..82ac296 100644
> --- a/gcc/cp/cvt.c
> +++ b/gcc/cp/cvt.c
> @@ -582,15 +582,23 @@ force_rvalue (tree expr, tsubst_flags_t
> complain)
>  static tree
>  ignore_overflows (tree expr, tree orig)
>  {
> -  if (TREE_CODE (expr) == INTEGER_CST
> -      && TREE_CODE (orig) == INTEGER_CST
> -      && TREE_OVERFLOW (expr) != TREE_OVERFLOW (orig))
> +  tree stripped_expr = tree_strip_any_location_wrapper (expr);
> +  tree stripped_orig = tree_strip_any_location_wrapper (orig);
> +
> +  if (TREE_CODE (stripped_expr) == INTEGER_CST
> +      && TREE_CODE (stripped_orig) == INTEGER_CST
> +      && TREE_OVERFLOW (stripped_expr) != TREE_OVERFLOW
> (stripped_orig))
>      {
> -      gcc_assert (!TREE_OVERFLOW (orig));
> +      gcc_assert (!TREE_OVERFLOW (stripped_orig));
>        /* Ensure constant sharing.  */
> -      expr = wide_int_to_tree (TREE_TYPE (expr), wi::to_wide
> (expr));
> +      stripped_expr = wide_int_to_tree (TREE_TYPE (stripped_expr),
> +					wi::to_wide
> (stripped_expr));
>      }
> -  return expr;
> +
> +  if (location_wrapper_p (expr))
> +    return maybe_wrap_with_location (stripped_expr, EXPR_LOCATION
> (expr));
> +
> +  return stripped_expr;
>  }
>  
>  /* Fold away simple conversions, but make sure TREE_OVERFLOW is set
> @@ -792,10 +800,11 @@ ocp_convert (tree type, tree expr, int
> convtype, int flags,
>  	     the original value is within the range of the
> enumeration
>  	     values. Otherwise, the resulting enumeration value is
>  	     unspecified.  */
> +	  tree val = fold_for_warn (e);
>  	  if ((complain & tf_warning)
> -	      && TREE_CODE (e) == INTEGER_CST
> +	      && TREE_CODE (val) == INTEGER_CST
>  	      && ENUM_UNDERLYING_TYPE (type)
> -	      && !int_fits_type_p (e, ENUM_UNDERLYING_TYPE (type)))
> +	      && !int_fits_type_p (val, ENUM_UNDERLYING_TYPE
> (type)))
>  	    warning_at (loc, OPT_Wconversion, 
>  			"the result of the conversion is unspecified
> because "
>  			"%qE is outside the range of type %qT",
> diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
> index 5ebfaaf..aea8089 100644
> --- a/gcc/cp/decl.c
> +++ b/gcc/cp/decl.c
> @@ -6000,14 +6000,16 @@ reshape_init_r (tree type, reshape_iter *d,
> bool first_initializer_p,
>        && has_designator_problem (d, complain))
>      return error_mark_node;
>  
> +  tree stripped_init = tree_strip_any_location_wrapper (init);
> +
>    if (TREE_CODE (type) == COMPLEX_TYPE)
>      {
>        /* A complex type can be initialized from one or two
> initializers,
>  	 but braces are not elided.  */
>        d->cur++;
> -      if (BRACE_ENCLOSED_INITIALIZER_P (init))
> +      if (BRACE_ENCLOSED_INITIALIZER_P (stripped_init))
>  	{
> -	  if (CONSTRUCTOR_NELTS (init) > 2)
> +	  if (CONSTRUCTOR_NELTS (stripped_init) > 2)
>  	    {
>  	      if (complain & tf_error)
>  		error ("too many initializers for %qT", type);
> @@ -6037,16 +6039,16 @@ reshape_init_r (tree type, reshape_iter *d,
> bool first_initializer_p,
>  	 We need to check for BRACE_ENCLOSED_INITIALIZER_P here
> because
>  	 of g++.old-deja/g++.mike/p7626.C: a pointer-to-member
> constant is
>  	 a CONSTRUCTOR (with a record type).  */
> -      if (TREE_CODE (init) == CONSTRUCTOR
> +      if (TREE_CODE (stripped_init) == CONSTRUCTOR
>  	  /* Don't complain about a capture-init.  */
> -	  && !CONSTRUCTOR_IS_DIRECT_INIT (init)
> -	  && BRACE_ENCLOSED_INITIALIZER_P (init))  /* p7626.C */
> +	  && !CONSTRUCTOR_IS_DIRECT_INIT (stripped_init)
> +	  && BRACE_ENCLOSED_INITIALIZER_P (stripped_init))  /*
> p7626.C */
>  	{
>  	  if (SCALAR_TYPE_P (type))
>  	    {
>  	      if (cxx_dialect < cxx11
>  		  /* Isn't value-initialization.  */
> -		  || CONSTRUCTOR_NELTS (init) > 0)
> +		  || CONSTRUCTOR_NELTS (stripped_init) > 0)
>  		{
>  		  if (complain & tf_error)
>  		    error ("braces around scalar initializer for
> type %qT",
> @@ -6106,20 +6108,22 @@ reshape_init_r (tree type, reshape_iter *d,
> bool first_initializer_p,
>        && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type))))
>      {
>        tree str_init = init;
> +      tree stripped_str_init = stripped_init;
>  
>        /* Strip one level of braces if and only if they enclose a
> single
>  	 element (as allowed by [dcl.init.string]).  */
>        if (!first_initializer_p
> -	  && TREE_CODE (str_init) == CONSTRUCTOR
> -	  && CONSTRUCTOR_NELTS (str_init) == 1)
> +	  && TREE_CODE (stripped_str_init) == CONSTRUCTOR
> +	  && CONSTRUCTOR_NELTS (stripped_str_init) == 1)
>  	{
> -	  str_init = (*CONSTRUCTOR_ELTS (str_init))[0].value;
> +	  str_init = (*CONSTRUCTOR_ELTS
> (stripped_str_init))[0].value;
> +	  stripped_str_init = tree_strip_any_location_wrapper
> (str_init);
>  	}
>  
>        /* If it's a string literal, then it's the initializer for the
> array
>  	 as a whole. Otherwise, continue with normal initialization
> for
>  	 array types (one value per array element).  */
> -      if (TREE_CODE (str_init) == STRING_CST)
> +      if (TREE_CODE (stripped_str_init) == STRING_CST)
>  	{
>  	  if (has_designator_problem (d, complain))
>  	    return error_mark_node;
> @@ -6134,24 +6138,24 @@ reshape_init_r (tree type, reshape_iter *d,
> bool first_initializer_p,
>       which reshape_init exists).  */
>    if (!first_initializer_p)
>      {
> -      if (TREE_CODE (init) == CONSTRUCTOR)
> +      if (TREE_CODE (stripped_init) == CONSTRUCTOR)
>  	{
>  	  if (TREE_TYPE (init) && TYPE_PTRMEMFUNC_P (TREE_TYPE
> (init)))
>  	    /* There is no need to reshape pointer-to-member
> function
>  	       initializers, as they are always constructed
> correctly
>  	       by the front end.  */
>             ;
> -	  else if (COMPOUND_LITERAL_P (init))
> +	  else if (COMPOUND_LITERAL_P (stripped_init))
>  	  /* For a nested compound literal, there is no need to
> reshape since
>  	     brace elision is not allowed. Even if we decided to
> allow it,
>  	     we should add a call to reshape_init in
> finish_compound_literal,
>  	     before calling digest_init, so changing this code would
> still
>  	     not be necessary.  */
> -	    gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (init));
> +	    gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P
> (stripped_init));
>  	  else
>  	    {
>  	      ++d->cur;
> -	      gcc_assert (BRACE_ENCLOSED_INITIALIZER_P (init));
> +	      gcc_assert (BRACE_ENCLOSED_INITIALIZER_P
> (stripped_init));
>  	      return reshape_init (type, init, complain);
>  	    }
>  	}
> @@ -16541,6 +16545,7 @@ undeduced_auto_decl (tree decl)
>  {
>    if (cxx_dialect < cxx11)
>      return false;
> +  STRIP_ANY_LOCATION_WRAPPER (decl);
>    return ((VAR_OR_FUNCTION_DECL_P (decl)
>  	   || TREE_CODE (decl) == TEMPLATE_DECL)
>  	  && type_uses_auto (TREE_TYPE (decl)));
> diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
> index a5ad0ee..a0dd9a3 100644
> --- a/gcc/cp/decl2.c
> +++ b/gcc/cp/decl2.c
> @@ -1058,6 +1058,9 @@ grokbitfield (const cp_declarator *declarator,
>        return NULL_TREE;
>      }
>  
> +  if (width)
> +    STRIP_ANY_LOCATION_WRAPPER (width);
> +
>    if (width && TYPE_WARN_IF_NOT_ALIGN (TREE_TYPE (value)))
>      {
>        error ("cannot declare bit-field %qD with
> %<warn_if_not_aligned%> type",
> diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c
> index 93477bc..8163866 100644
> --- a/gcc/cp/expr.c
> +++ b/gcc/cp/expr.c
> @@ -263,6 +263,8 @@ mark_discarded_use (tree expr)
>    if (expr == NULL_TREE)
>      return expr;
>  
> +  STRIP_ANY_LOCATION_WRAPPER (expr);
> +
>    switch (TREE_CODE (expr))
>      {
>      case COND_EXPR:
> diff --git a/gcc/cp/init.c b/gcc/cp/init.c
> index 15046b4..8f5a155 100644
> --- a/gcc/cp/init.c
> +++ b/gcc/cp/init.c
> @@ -1758,7 +1758,8 @@ build_aggr_init (tree exp, tree init, int
> flags, tsubst_flags_t complain)
>  	{
>  	  from_array = 1;
>  	  init = mark_rvalue_use (init);
> -	  if (init && DECL_P (init)
> +	  if (init
> +	      && DECL_P (tree_strip_any_location_wrapper (init))
>  	      && !(flags & LOOKUP_ONLYCONVERTING))
>  	    {
>  	      /* Wrap the initializer in a CONSTRUCTOR so that
> build_vec_init
> @@ -2606,6 +2607,7 @@ warn_placement_new_too_small (tree type, tree
> nelts, tree size, tree oper)
>  	 Otherwise, use the size of the entire array as an
> optimistic
>  	 estimate (this may lead to false negatives).  */
>        tree adj = TREE_OPERAND (oper, 1);
> +      adj = fold_for_warn (adj);
>        if (CONSTANT_CLASS_P (adj))
>  	adjust += wi::to_offset (convert (ssizetype, adj));
>        else
> @@ -2669,11 +2671,13 @@ warn_placement_new_too_small (tree type, tree
> nelts, tree size, tree oper)
>  
>        tree op0 = oper;
>        while (TREE_CODE (op0 = TREE_OPERAND (op0, 0)) ==
> COMPONENT_REF);
> +      STRIP_ANY_LOCATION_WRAPPER (op0);
>        if (VAR_P (op0))
>  	var_decl = op0;
>        oper = TREE_OPERAND (oper, 1);
>      }
>  
> +  STRIP_ANY_LOCATION_WRAPPER (oper);
>    tree opertype = TREE_TYPE (oper);
>    if ((addr_expr || !INDIRECT_TYPE_P (opertype))
>        && (VAR_P (oper)
> @@ -2764,6 +2768,9 @@ warn_placement_new_too_small (tree type, tree
> nelts, tree size, tree oper)
>  	 others.  */
>        offset_int bytes_need;
>  
> +      if (nelts)
> +	nelts = fold_for_warn (nelts);
> +
>        if (CONSTANT_CLASS_P (size))
>  	bytes_need = wi::to_offset (size);
>        else if (nelts && CONSTANT_CLASS_P (nelts))
> diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
> index 297327f..ad88a0d 100644
> --- a/gcc/cp/lambda.c
> +++ b/gcc/cp/lambda.c
> @@ -656,6 +656,9 @@ add_capture (tree lambda, tree id, tree
> orig_init, bool by_reference_p,
>        listmem = make_pack_expansion (member);
>        initializer = orig_init;
>      }
> +
> +  STRIP_ANY_LOCATION_WRAPPER (initializer);
> +
>    LAMBDA_EXPR_CAPTURE_LIST (lambda)
>      = tree_cons (listmem, initializer, LAMBDA_EXPR_CAPTURE_LIST
> (lambda));
>  
> diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
> index 08632c3..aea4d43 100644
> --- a/gcc/cp/name-lookup.c
> +++ b/gcc/cp/name-lookup.c
> @@ -4985,6 +4985,8 @@ handle_namespace_attrs (tree ns, tree
> attributes)
>  	     rather than the namespace as a whole, so we don't touch
> the
>  	     NAMESPACE_DECL at all.  */
>  	  tree x = args ? TREE_VALUE (args) : NULL_TREE;
> +	  if (x)
> +	    STRIP_ANY_LOCATION_WRAPPER (x);
>  	  if (x == NULL_TREE || TREE_CODE (x) != STRING_CST ||
> TREE_CHAIN (args))
>  	    {
>  	      warning (OPT_Wattributes,
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index ebe326e..b3876e2 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -5175,7 +5175,8 @@ cp_parser_primary_expression (cp_parser
> *parser,
>  	  if (!cast_p)
>  	    cp_parser_non_integral_constant_expression (parser,
> NIC_FLOAT);
>  	}
> -      return cp_expr (token->u.value, token->location);
> +      return (cp_expr (token->u.value, token->location)
> +	      .maybe_add_location_wrapper ());
>  
>      case CPP_CHAR_USERDEF:
>      case CPP_CHAR16_USERDEF:
> @@ -5197,9 +5198,10 @@ cp_parser_primary_expression (cp_parser
> *parser,
>        /* ??? Should wide strings be allowed when parser-
> >translate_strings_p
>  	 is false (i.e. in attributes)?  If not, we can kill the
> third
>  	 argument to cp_parser_string_literal.  */
> -      return cp_parser_string_literal (parser,
> -				       parser->translate_strings_p,
> -				       true);
> +      return (cp_parser_string_literal (parser,
> +					parser->translate_strings_p,
> +					true)
> +	      .maybe_add_location_wrapper ());
>  
>      case CPP_OPEN_PAREN:
>        /* If we see `( { ' then we are looking at the beginning of
> @@ -7118,8 +7120,10 @@ cp_parser_postfix_expression (cp_parser
> *parser, bool address_p, bool cast_p,
>  
>              is_member_access = false;
>  
> +	    tree stripped_expression
> +	      = tree_strip_any_location_wrapper
> (postfix_expression);
>  	    is_builtin_constant_p
> -	      = DECL_IS_BUILTIN_CONSTANT_P (postfix_expression);
> +	      = DECL_IS_BUILTIN_CONSTANT_P (stripped_expression);
>  	    if (is_builtin_constant_p)
>  	      {
>  		/* The whole point of __builtin_constant_p is to
> allow
> @@ -9329,7 +9333,7 @@ cp_parser_binary_expression (cp_parser* parser,
> bool cast_p,
>  		      || (TREE_CODE (TREE_TYPE (TREE_OPERAND
> (current.lhs, 0)))
>  			  != BOOLEAN_TYPE))))
>  	  /* Avoid warning for !!b == y where b is boolean.  */
> -	  && (!DECL_P (current.lhs)
> +	  && (!DECL_P (tree_strip_any_location_wrapper
> (current.lhs))
>  	      || TREE_TYPE (current.lhs) == NULL_TREE
>  	      || TREE_CODE (TREE_TYPE (current.lhs)) !=
> BOOLEAN_TYPE))
>  	warn_logical_not_parentheses (current.loc,
> current.tree_type,
> @@ -14122,6 +14126,7 @@ cp_parser_decltype_expr (cp_parser *parser,
>            && cp_lexer_peek_token (parser->lexer)->type ==
> CPP_CLOSE_PAREN)
>          {
>            /* Complete lookup of the id-expression.  */
> +	  auto_suppress_location_wrappers sentinel;
>            expr = (finish_id_expression
>                    (id_expression, expr, parser->scope, &idk,
>                     /*integral_constant_expression_p=*/false,
> @@ -14634,7 +14639,9 @@ cp_parser_mem_initializer (cp_parser* parser)
>        vec = cp_parser_parenthesized_expression_list (parser,
> non_attr,
>  						     /*cast_p=*/fals
> e,
>  						     /*allow_expansi
> on_p=*/true,
> -						     /*non_constant_
> p=*/NULL);
> +						     /*non_constant_
> p=*/NULL,
> +						     /*close_paren_l
> oc=*/NULL,
> +						     /*wrap_location
> s_p=*/true);
>        if (vec == NULL)
>  	return error_mark_node;
>        expression_list = build_tree_list_vec (vec);
> @@ -15164,6 +15171,11 @@ cp_parser_template_parameter_list
> (cp_parser* parser)
>  {
>    tree parameter_list = NULL_TREE;
>  
> +  /* Don't create wrapper nodes within a template-parameter-list,
> +     since we don't want to have different types based on the
> +     spelling location of constants and decls within them.  */
> +  auto_suppress_location_wrappers sentinel;
> +
>    begin_template_parm_list ();
>  
>    /* The loop below parses the template parms.  We first need to
> know
> @@ -16281,6 +16293,9 @@ cp_parser_template_argument_list (cp_parser*
> parser)
>    bool saved_ice_p;
>    bool saved_non_ice_p;
>  
> +  /* Don't create location wrapper nodes within a template-argument-
> list.  */
> +  auto_suppress_location_wrappers sentinel;
> +
>    saved_in_template_argument_list_p = parser-
> >in_template_argument_list_p;
>    parser->in_template_argument_list_p = true;
>    /* Even if the template-id appears in an integral
> @@ -21832,6 +21847,9 @@ cp_parser_parameter_declaration (cp_parser
> *parser,
>    else
>      default_argument = NULL_TREE;
>  
> +  if (default_argument)
> +    STRIP_ANY_LOCATION_WRAPPER (default_argument);
> +
>    /* Generate a location for the parameter, ranging from the start
> of the
>       initial token to the end of the final token (using
> input_location for
>       the latter, set up by cp_lexer_set_source_position_from_token
> when
> @@ -25199,6 +25217,9 @@ cp_parser_gnu_attribute_list (cp_parser*
> parser)
>  	      vec<tree, va_gc> *vec;
>  	      int attr_flag = (attribute_takes_identifier_p
> (identifier)
>  			       ? id_attr : normal_attr);
> +	      /* Don't create wrapper nodes within an attribute: the
> +		 handlers don't know how to handle them.  */
> +	      auto_suppress_location_wrappers sentinel;
>  	      vec = cp_parser_parenthesized_expression_list 
>  		    (parser, attr_flag, /*cast_p=*/false, 
>  		    /*allow_expansion_p=*/false, 
> @@ -28029,6 +28050,14 @@ cp_parser_late_parsing_default_args
> (cp_parser *parser, tree fn)
>  	= cp_parser_late_parse_one_default_arg (parser, parmdecl,
>  						default_arg,
>  						TREE_VALUE (parm));
> +
> +      /* Since default args are effectively part of the function
> type,
> +	 strip location wrappers here, since otherwise the location
> of
> +	 one function's default arguments is arbitrarily chosen for
> +	 all functions with similar signature (due to
> canonicalization
> +	 of function types).  */
> +      STRIP_ANY_LOCATION_WRAPPER (parsed_arg);
> +
>        TREE_PURPOSE (parm) = parsed_arg;
>  
>        /* Update any instantiations we've already created.  */
> @@ -33939,6 +33968,9 @@ cp_parser_omp_all_clauses (cp_parser *parser,
> omp_clause_mask mask,
>    bool first = true;
>    cp_token *token = NULL;
>  
> +  /* Don't create location wrapper nodes within OpenMP clauses.  */
> +  auto_suppress_location_wrappers sentinel;
> +
>    while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL))
>      {
>        pragma_omp_clause c_kind;
> @@ -35223,6 +35255,10 @@ cp_parser_omp_for_loop (cp_parser *parser,
> enum tree_code code, tree clauses,
>  	}
>        loc = cp_lexer_consume_token (parser->lexer)->location;
>  
> +      /* Don't create location wrapper nodes within an OpenMP "for"
> +	 statement.  */
> +      auto_suppress_location_wrappers sentinel;
> +
>        matching_parens parens;
>        if (!parens.require_open (parser))
>  	return NULL;
> @@ -37592,6 +37628,8 @@ cp_parser_omp_declare_reduction_exprs (tree
> fndecl, cp_parser *parser)
>        else
>  	{
>  	  cp_parser_parse_tentatively (parser);
> +	  /* Don't create location wrapper nodes here.  */
> +	  auto_suppress_location_wrappers sentinel;
>  	  tree fn_name = cp_parser_id_expression (parser,
> /*template_p=*/false,
>  						  /*check_dependency
> _p=*/true,
>  						  /*template_p=*/NUL
> L,
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index f290cb3..bce0abe 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -6257,6 +6257,7 @@ convert_nontype_argument_function (tree type,
> tree expr,
>       -- the address of an object or function with external [C++11:
> or
>          internal] linkage.  */
>  
> +  STRIP_ANY_LOCATION_WRAPPER (fn_no_ptr);
>    if (TREE_CODE (fn_no_ptr) != FUNCTION_DECL)
>      {
>        if (complain & tf_error)
> @@ -26830,7 +26831,8 @@ do_auto_deduction (tree type, tree init, tree
> auto_node,
>  					 complain);
>    else if (AUTO_IS_DECLTYPE (auto_node))
>      {
> -      bool id = (DECL_P (init)
> +      tree stripped_init = tree_strip_any_location_wrapper (init);
> +      bool id = (DECL_P (stripped_init)
>  		 || ((TREE_CODE (init) == COMPONENT_REF
>  		      || TREE_CODE (init) == SCOPE_REF)
>  		     && !REF_PARENTHESIZED_P (init)));
> diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
> index 4c05365..cb97bec 100644
> --- a/gcc/cp/semantics.c
> +++ b/gcc/cp/semantics.c
> @@ -1740,7 +1740,8 @@ force_paren_expr (tree expr)
>    if (cp_unevaluated_operand)
>      return expr;
>  
> -  if (!DECL_P (expr) && TREE_CODE (expr) != COMPONENT_REF
> +  if (!DECL_P (tree_strip_any_location_wrapper (expr))
> +      && TREE_CODE (expr) != COMPONENT_REF
>        && TREE_CODE (expr) != SCOPE_REF)
>      return expr;
>  
> @@ -1803,8 +1804,9 @@ finish_parenthesized_expr (cp_expr expr)
>         enclosed in parentheses.  */
>      PTRMEM_OK_P (expr) = 0;
>  
> -  if (TREE_CODE (expr) == STRING_CST)
> -    PAREN_STRING_LITERAL_P (expr) = 1;
> +  tree stripped_expr = tree_strip_any_location_wrapper (expr);
> +  if (TREE_CODE (stripped_expr) == STRING_CST)
> +    PAREN_STRING_LITERAL_P (stripped_expr) = 1;
>  
>    expr = cp_expr (force_paren_expr (expr), expr.get_location ());
>  
> @@ -2297,19 +2299,22 @@ empty_expr_stmt_p (tree expr_stmt)
>    return false;
>  }
>  
> -/* Perform Koenig lookup.  FN is the postfix-expression representing
> +/* Perform Koenig lookup.  FN_EXPR is the postfix-expression
> representing
>     the function (or functions) to call; ARGS are the arguments to
> the
>     call.  Returns the functions to be considered by overload
> resolution.  */
>  
>  cp_expr
> -perform_koenig_lookup (cp_expr fn, vec<tree, va_gc> *args,
> +perform_koenig_lookup (cp_expr fn_expr, vec<tree, va_gc> *args,
>  		       tsubst_flags_t complain)
>  {
>    tree identifier = NULL_TREE;
>    tree functions = NULL_TREE;
>    tree tmpl_args = NULL_TREE;
>    bool template_id = false;
> -  location_t loc = fn.get_location ();
> +  location_t loc = fn_expr.get_location ();
> +  tree fn = fn_expr.get_value ();
> +
> +  STRIP_ANY_LOCATION_WRAPPER (fn);
>  
>    if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
>      {
> @@ -2354,7 +2359,7 @@ perform_koenig_lookup (cp_expr fn, vec<tree,
> va_gc> *args,
>    if (fn && template_id && fn != error_mark_node)
>      fn = build2 (TEMPLATE_ID_EXPR, unknown_type_node, fn,
> tmpl_args);
>    
> -  return fn;
> +  return cp_expr (fn, loc);
>  }
>  
>  /* Generate an expression for `FN (ARGS)'.  This may change the
> @@ -2385,6 +2390,8 @@ finish_call_expr (tree fn, vec<tree, va_gc>
> **args, bool disallow_virtual,
>       it so that we can tell this is a call to a known function.  */
>    fn = maybe_undo_parenthesized_ref (fn);
>  
> +  STRIP_ANY_LOCATION_WRAPPER (fn);
> +
>    orig_fn = fn;
>  
>    if (processing_template_decl)
> @@ -3532,20 +3539,20 @@ process_outer_var_ref (tree decl,
> tsubst_flags_t complain, bool odr_use)
>     the use of "this" explicit.
>  
>     Upon return, *IDK will be filled in appropriately.  */
> -cp_expr
> -finish_id_expression (tree id_expression,
> -		      tree decl,
> -		      tree scope,
> -		      cp_id_kind *idk,
> -		      bool integral_constant_expression_p,
> -		      bool allow_non_integral_constant_expression_p,
> -		      bool *non_integral_constant_expression_p,
> -		      bool template_p,
> -		      bool done,
> -		      bool address_p,
> -		      bool template_arg_p,
> -		      const char **error_msg,
> -		      location_t location)
> +static cp_expr
> +finish_id_expression_1 (tree id_expression,
> +			tree decl,
> +			tree scope,
> +			cp_id_kind *idk,
> +			bool integral_constant_expression_p,
> +			bool
> allow_non_integral_constant_expression_p,
> +			bool *non_integral_constant_expression_p,
> +			bool template_p,
> +			bool done,
> +			bool address_p,
> +			bool template_arg_p,
> +			const char **error_msg,
> +			location_t location)
>  {
>    decl = strip_using_decl (decl);
>  
> @@ -3840,6 +3847,34 @@ finish_id_expression (tree id_expression,
>    return cp_expr (decl, location);
>  }
>  
> +/* As per finish_id_expression_1, but adding a wrapper node
> +   around the result if needed to express LOCATION.  */
> +
> +cp_expr
> +finish_id_expression (tree id_expression,
> +		      tree decl,
> +		      tree scope,
> +		      cp_id_kind *idk,
> +		      bool integral_constant_expression_p,
> +		      bool allow_non_integral_constant_expression_p,
> +		      bool *non_integral_constant_expression_p,
> +		      bool template_p,
> +		      bool done,
> +		      bool address_p,
> +		      bool template_arg_p,
> +		      const char **error_msg,
> +		      location_t location)
> +{
> +  cp_expr result
> +    = finish_id_expression_1 (id_expression, decl, scope, idk,
> +			      integral_constant_expression_p,
> +			      allow_non_integral_constant_expression
> _p,
> +			      non_integral_constant_expression_p,
> +			      template_p, done, address_p,
> template_arg_p,
> +			      error_msg, location);
> +  return result.maybe_add_location_wrapper ();
> +}
> +
>  /* Implement the __typeof keyword: Return the type of EXPR, suitable
> for
>     use as a type-specifier.  */
>  
> diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
> index 251c344..58614e7 100644
> --- a/gcc/cp/tree.c
> +++ b/gcc/cp/tree.c
> @@ -371,6 +371,7 @@ bitfield_p (const_tree ref)
>  tree
>  cp_stabilize_reference (tree ref)
>  {
> +  STRIP_ANY_LOCATION_WRAPPER (ref);
>    switch (TREE_CODE (ref))
>      {
>      case NON_DEPENDENT_EXPR:
> @@ -415,6 +416,7 @@ cp_stabilize_reference (tree ref)
>  bool
>  builtin_valid_in_constant_expr_p (const_tree decl)
>  {
> +  STRIP_ANY_LOCATION_WRAPPER (decl);
>    if (TREE_CODE (decl) != FUNCTION_DECL)
>      /* Not a function.  */
>      return false;
> @@ -2428,6 +2430,8 @@ lookup_keep (tree lookup)
>  int
>  is_overloaded_fn (tree x)
>  {
> +  STRIP_ANY_LOCATION_WRAPPER (x);
> +
>    /* A baselink is also considered an overloaded function.  */
>    if (TREE_CODE (x) == OFFSET_REF
>        || TREE_CODE (x) == COMPONENT_REF)
> @@ -2476,6 +2480,8 @@ really_overloaded_fn (tree x)
>  tree
>  maybe_get_fns (tree from)
>  {
> +  STRIP_ANY_LOCATION_WRAPPER (from);
> +
>    /* A baselink is also considered an overloaded function.  */
>    if (TREE_CODE (from) == OFFSET_REF
>        || TREE_CODE (from) == COMPONENT_REF)
> @@ -5550,6 +5556,14 @@ test_lvalue_kind ()
>    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));
> +
> +  /* Verify lvalue_p.  */
> +  ASSERT_FALSE (lvalue_p (int_cst));
> +  ASSERT_FALSE (lvalue_p (wrapped_int_cst));
> +  ASSERT_TRUE (lvalue_p (parm));
> +  ASSERT_TRUE (lvalue_p (wrapped_parm));
> +  ASSERT_FALSE (lvalue_p (rvalue_ref_of_parm));
> +  ASSERT_FALSE (lvalue_p (rvalue_ref_of_wrapped_parm));
>  }
>  
>  /* Run all of the selftests within this file.  */
> diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
> index c921096..b97d3da 100644
> --- a/gcc/cp/typeck.c
> +++ b/gcc/cp/typeck.c
> @@ -1682,6 +1682,8 @@ cxx_sizeof_expr (tree e, tsubst_flags_t
> complain)
>        return e;
>      }
>  
> +  STRIP_ANY_LOCATION_WRAPPER (e);
> +
>    /* To get the size of a static data member declared as an array of
>       unknown bound, we need to instantiate it.  */
>    if (VAR_P (e)
> @@ -1754,6 +1756,8 @@ cxx_alignof_expr (tree e, tsubst_flags_t
> complain)
>        return e;
>      }
>  
> +  STRIP_ANY_LOCATION_WRAPPER (e);
> +
>    e = mark_type_use (e);
>  
>    if (VAR_P (e))
> @@ -1944,6 +1948,12 @@ is_bitfield_expr_with_lowered_type (const_tree
> exp)
>  						   (CONST_CAST_TREE
> (exp)));
>        return NULL_TREE;
>  
> +    case VIEW_CONVERT_EXPR:
> +      if (location_wrapper_p (exp))
> +	return is_bitfield_expr_with_lowered_type (TREE_OPERAND
> (exp, 0));
> +      else
> +	return NULL_TREE;
> +
>      CASE_CONVERT:
>        if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (exp, 0)))
>  	  == TYPE_MAIN_VARIANT (TREE_TYPE (exp)))
> @@ -3404,11 +3414,13 @@ cp_build_array_ref (location_t loc, tree
> array, tree idx,
>  	 pointer arithmetic.)  */
>        idx = cp_perform_integral_promotions (idx, complain);
>  
> +      tree stripped_idx = tree_strip_any_location_wrapper (idx);
> +
>        /* An array that is indexed by a non-constant
>  	 cannot be stored in a register; we must be able to do
>  	 address arithmetic on its address.
>  	 Likewise an array of elements of variable size.  */
> -      if (TREE_CODE (idx) != INTEGER_CST
> +      if (TREE_CODE (stripped_idx) != INTEGER_CST
>  	  || (COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (array)))
>  	      && (TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE
> (array))))
>  		  != INTEGER_CST)))
> @@ -3421,9 +3433,9 @@ cp_build_array_ref (location_t loc, tree array,
> tree idx,
>  	 the array bounds cannot be stored in a register either;
> because we
>  	 would get a crash in store_bit_field/extract_bit_field when
> trying
>  	 to access a non-existent part of the register.  */
> -      if (TREE_CODE (idx) == INTEGER_CST
> +      if (TREE_CODE (stripped_idx) == INTEGER_CST
>  	  && TYPE_DOMAIN (TREE_TYPE (array))
> -	  && ! int_fits_type_p (idx, TYPE_DOMAIN (TREE_TYPE
> (array))))
> +	  && ! int_fits_type_p (stripped_idx, TYPE_DOMAIN (TREE_TYPE
> (array))))
>  	{
>  	  if (!cxx_mark_addressable (array))
>  	    return error_mark_node;
> @@ -4542,20 +4554,23 @@ cp_build_binary_op (location_t location,
>  	    type0 = TREE_TYPE (type0);
>  	  if (!TYPE_P (type1))
>  	    type1 = TREE_TYPE (type1);
> -	  if (INDIRECT_TYPE_P (type0) && same_type_p (TREE_TYPE
> (type0), type1)
> -	      && !(TREE_CODE (first_arg) == PARM_DECL
> -		   && DECL_ARRAY_PARAMETER_P (first_arg)
> -		   && warn_sizeof_array_argument)
> -	      && (complain & tf_warning))
> +	  if (INDIRECT_TYPE_P (type0) && same_type_p (TREE_TYPE
> (type0), type1))
>  	    {
> -	      auto_diagnostic_group d;
> -	      if (warning_at (location, OPT_Wsizeof_pointer_div,
> -				"division %<sizeof (%T) / sizeof
> (%T)%> does "
> -				"not compute the number of array
> elements",
> -			    type0, type1))
> -		if (DECL_P (first_arg))
> -		  inform (DECL_SOURCE_LOCATION (first_arg),
> -			    "first %<sizeof%> operand was declared
> here");
> +	      STRIP_ANY_LOCATION_WRAPPER (first_arg);
> +	      if (!(TREE_CODE (first_arg) == PARM_DECL
> +		    && DECL_ARRAY_PARAMETER_P (first_arg)
> +		    && warn_sizeof_array_argument)
> +		  && (complain & tf_warning))
> +		{
> +		  auto_diagnostic_group d;
> +		  if (warning_at (location, OPT_Wsizeof_pointer_div,
> +				  "division %<sizeof (%T) / sizeof
> (%T)%> does "
> +				  "not compute the number of array
> elements",
> +				  type0, type1))
> +		    if (DECL_P (first_arg))
> +		      inform (DECL_SOURCE_LOCATION (first_arg),
> +			      "first %<sizeof%> operand was declared
> here");
> +		}
>  	    }
>  	}
>  
> @@ -4577,15 +4592,18 @@ cp_build_binary_op (location_t location,
>  	  if (!(tcode0 == INTEGER_TYPE && tcode1 == INTEGER_TYPE))
>  	    resultcode = RDIV_EXPR;
>  	  else
> -	    /* When dividing two signed integers, we have to promote
> to int.
> -	       unless we divide by a constant != -1.  Note that
> default
> -	       conversion will have been performed on the operands
> at this
> -	       point, so we have to dig out the original type to
> find out if
> -	       it was unsigned.  */
> -	    shorten = ((TREE_CODE (op0) == NOP_EXPR
> -			&& TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND
> (op0, 0))))
> -		       || (TREE_CODE (op1) == INTEGER_CST
> -			   && ! integer_all_onesp (op1)));
> +	    {
> +	      /* When dividing two signed integers, we have to
> promote to int.
> +		 unless we divide by a constant != -1.  Note that
> default
> +		 conversion will have been performed on the operands
> at this
> +		 point, so we have to dig out the original type to
> find out if
> +		 it was unsigned.  */
> +	      tree stripped_op1 = tree_strip_any_location_wrapper
> (op1);
> +	      shorten = ((TREE_CODE (op0) == NOP_EXPR
> +			  && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND
> (op0, 0))))
> +			 || (TREE_CODE (stripped_op1) == INTEGER_CST
> +			     && ! integer_all_onesp
> (stripped_op1)));
> +	    }
>  
>  	  common = 1;
>  	}
> @@ -4619,10 +4637,11 @@ cp_build_binary_op (location_t location,
>  	     on some targets, since the modulo instruction is
> undefined if the
>  	     quotient can't be represented in the computation
> mode.  We shorten
>  	     only if unsigned or if dividing by something we know !=
> -1.  */
> +	  tree stripped_op1 = tree_strip_any_location_wrapper (op1);
>  	  shorten = ((TREE_CODE (op0) == NOP_EXPR
>  		      && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND
> (op0, 0))))
> -		     || (TREE_CODE (op1) == INTEGER_CST
> -			 && ! integer_all_onesp (op1)));
> +		     || (TREE_CODE (stripped_op1) == INTEGER_CST
> +			 && ! integer_all_onesp (stripped_op1)));
>  	  common = 1;
>  	}
>        break;
> @@ -4823,13 +4842,17 @@ cp_build_binary_op (location_t location,
>  	  && (FLOAT_TYPE_P (type0) || FLOAT_TYPE_P (type1)))
>  	warning (OPT_Wfloat_equal,
>  		 "comparing floating point with == or != is
> unsafe");
> -      if ((complain & tf_warning)
> -	  && ((TREE_CODE (orig_op0) == STRING_CST
> +      if (complain & tf_warning)
> +	{
> +	  tree stripped_orig_op0 = tree_strip_any_location_wrapper
> (orig_op0);
> +	  tree stripped_orig_op1 = tree_strip_any_location_wrapper
> (orig_op1);
> +	  if ((TREE_CODE (stripped_orig_op0) == STRING_CST
>  	       && !integer_zerop (cp_fully_fold (op1)))
> -	      || (TREE_CODE (orig_op1) == STRING_CST
> -		  && !integer_zerop (cp_fully_fold (op0)))))
> -	warning (OPT_Waddress, "comparison with string literal
> results "
> -			       "in unspecified behavior");
> +	      || (TREE_CODE (stripped_orig_op1) == STRING_CST
> +		  && !integer_zerop (cp_fully_fold (op0))))
> +	    warning (OPT_Waddress, "comparison with string literal
> results "
> +		     "in unspecified behavior");
> +	}
>  
>        build_type = boolean_type_node;
>        if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
> @@ -6061,8 +6084,9 @@ cp_build_addr_expr_1 (tree arg, bool
> strict_lvalue, tsubst_flags_t complain)
>       so we can just form an ADDR_EXPR with the correct type.  */
>    if (processing_template_decl || TREE_CODE (arg) != COMPONENT_REF)
>      {
> -      if (TREE_CODE (arg) == FUNCTION_DECL
> -	  && !mark_used (arg, complain) && !(complain & tf_error))
> +      tree stripped_arg = tree_strip_any_location_wrapper (arg);
> +      if (TREE_CODE (stripped_arg) == FUNCTION_DECL
> +	  && !mark_used (stripped_arg, complain) && !(complain &
> tf_error))
>  	return error_mark_node;
>        val = build_address (arg);
>        if (TREE_CODE (arg) == OFFSET_REF)
> @@ -8272,7 +8296,8 @@ cp_build_modify_expr (location_t loc, tree lhs,
> enum tree_code modifycode,
>        /* C++11 8.5/17: "If the destination type is an array of
> characters,
>  	 an array of char16_t, an array of char32_t, or an array of
> wchar_t,
>  	 and the initializer is a string literal...".  */
> -      else if (TREE_CODE (newrhs) == STRING_CST
> +      else if ((TREE_CODE (tree_strip_any_location_wrapper (newrhs))
> +		== STRING_CST)
>  	       && char_type_p (TREE_TYPE (TYPE_MAIN_VARIANT
> (lhstype)))
>  	       && modifycode == INIT_EXPR)
>  	{
> @@ -8790,8 +8815,10 @@ convert_for_assignment (tree type, tree rhs,
>    tree rhstype;
>    enum tree_code coder;
>  
> -  /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
> -  if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
> +  /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue,
> +     but preserve location wrappers.  */
> +  if (TREE_CODE (rhs) == NON_LVALUE_EXPR
> +      && !location_wrapper_p (rhs))
>      rhs = TREE_OPERAND (rhs, 0);
>  
>    /* Handle [dcl.init.list] direct-list-initialization from
> @@ -9165,6 +9192,8 @@ maybe_warn_about_returning_address_of_local
> (tree retval)
>        return true;
>      }
>  
> +  STRIP_ANY_LOCATION_WRAPPER (whats_returned);
> +
>    if (DECL_P (whats_returned)
>        && DECL_NAME (whats_returned)
>        && DECL_FUNCTION_SCOPE_P (whats_returned)
> @@ -9266,6 +9295,8 @@ is_std_move_p (tree fn)
>  static bool
>  can_do_nrvo_p (tree retval, tree functype)
>  {
> +  if (retval)
> +    STRIP_ANY_LOCATION_WRAPPER (retval);
>    tree result = DECL_RESULT (current_function_decl);
>    return (retval != NULL_TREE
>  	  && !processing_template_decl
> @@ -9292,6 +9323,7 @@ can_do_nrvo_p (tree retval, tree functype)
>  bool
>  treat_lvalue_as_rvalue_p (tree retval, bool parm_ok)
>  {
> +  STRIP_ANY_LOCATION_WRAPPER (retval);
>    return ((cxx_dialect != cxx98)
>  	  && ((VAR_P (retval) && !DECL_HAS_VALUE_EXPR_P (retval))
>  	      || (parm_ok && TREE_CODE (retval) == PARM_DECL))
> @@ -9585,6 +9617,8 @@ check_return_expr (tree retval, bool
> *no_warning)
>       this restriction, anyway.  (jason 2000-11-19)
>  
>       See finish_function and finalize_nrv for the rest of this
> optimization.  */
> +  if (retval)
> +    STRIP_ANY_LOCATION_WRAPPER (retval);
>  
>    bool named_return_value_okay_p = can_do_nrvo_p (retval, functype);
>    if (fn_returns_value_p && flag_elide_constructors)
> diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
> index fec1db0..9034362 100644
> --- a/gcc/cp/typeck2.c
> +++ b/gcc/cp/typeck2.c
> @@ -459,14 +459,19 @@ cxx_incomplete_type_diagnostic (location_t loc,
> const_tree value,
>    if (TREE_CODE (type) == ERROR_MARK)
>      return;
>  
> -  if (value != 0 && (VAR_P (value)
> -		     || TREE_CODE (value) == PARM_DECL
> -		     || TREE_CODE (value) == FIELD_DECL))
> +  if (value)
>      {
> -      complained = emit_diagnostic (diag_kind, DECL_SOURCE_LOCATION
> (value), 0,
> -				    "%qD has incomplete type",
> value);
> -      is_decl = true;
> -    } 
> +      STRIP_ANY_LOCATION_WRAPPER (value);
> +
> +      if (VAR_P (value)
> +	  || TREE_CODE (value) == PARM_DECL
> +	  || TREE_CODE (value) == FIELD_DECL)
> +	{
> +	  complained = emit_diagnostic (diag_kind,
> DECL_SOURCE_LOCATION (value), 0,
> +					"%qD has incomplete type",
> value);
> +	  is_decl = true;
> +	}
> +    }
>   retry:
>    /* We must print an error message.  Be clever about what it
> says.  */
>  
> @@ -1044,6 +1049,8 @@ digest_init_r (tree type, tree init, int
> nested, int flags,
>  
>    location_t loc = cp_expr_loc_or_loc (init, input_location);
>  
> +  tree stripped_init = tree_strip_any_location_wrapper (init);
> +
>    /* Initialization of an array of chars from a string constant. The
> initializer
>       can be optionally enclosed in braces, but reshape_init has
> already removed
>       them if they were present.  */
> @@ -1057,7 +1064,7 @@ digest_init_r (tree type, tree init, int
> nested, int flags,
>        tree typ1 = TYPE_MAIN_VARIANT (TREE_TYPE (type));
>        if (char_type_p (typ1)
>  	  /*&& init */
> -	  && TREE_CODE (init) == STRING_CST)
> +	  && TREE_CODE (stripped_init) == STRING_CST)
>  	{
>  	  tree char_type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE
> (init)));
>  
> @@ -1101,6 +1108,14 @@ digest_init_r (tree type, tree init, int
> nested, int flags,
>  	    {
>  	      init = copy_node (init);
>  	      TREE_TYPE (init) = type;
> +	      /* If we have a location wrapper, then also copy the
> wrapped
> +		 node, and update the copy's type.  */
> +	      if (location_wrapper_p (init))
> +		{
> +		  stripped_init = copy_node (stripped_init);
> +		  TREE_OPERAND (init, 0) = stripped_init;
> +		  TREE_TYPE (stripped_init) = type;
> +		}
>  	    }
>  	  if (TYPE_DOMAIN (type) && TREE_CONSTANT (TYPE_SIZE
> (type)))
>  	    {
> @@ -1111,12 +1126,13 @@ digest_init_r (tree type, tree init, int
> nested, int flags,
>  		 because it's ok to ignore the terminating null char
> that is
>  		 counted in the length of the constant, but in C++
> this would
>  		 be invalid.  */
> -	      if (size < TREE_STRING_LENGTH (init))
> +	      if (size < TREE_STRING_LENGTH (stripped_init))
>  		{
>  		  permerror (loc, "initializer-string for array "
>  			     "of chars is too long");
>  
> -		  init = build_string (size, TREE_STRING_POINTER
> (init));
> +		  init = build_string (size,
> +				       TREE_STRING_POINTER
> (stripped_init));
>  		  TREE_TYPE (init) = type;
>  		}
>  	    }
> @@ -1125,7 +1141,7 @@ digest_init_r (tree type, tree init, int
> nested, int flags,
>      }
>  
>    /* Handle scalar types (including conversions) and references.  */
> -  if ((code != COMPLEX_TYPE || BRACE_ENCLOSED_INITIALIZER_P (init))
> +  if ((code != COMPLEX_TYPE || BRACE_ENCLOSED_INITIALIZER_P
> (stripped_init))
>        && (SCALAR_TYPE_P (type) || code == REFERENCE_TYPE))
>      {
>        if (nested)
> @@ -1150,23 +1166,23 @@ digest_init_r (tree type, tree init, int
> nested, int flags,
>       the object is initialized from that element."  */
>    if (flag_checking
>        && cxx_dialect >= cxx11
> -      && BRACE_ENCLOSED_INITIALIZER_P (init)
> -      && CONSTRUCTOR_NELTS (init) == 1
> +      && BRACE_ENCLOSED_INITIALIZER_P (stripped_init)
> +      && CONSTRUCTOR_NELTS (stripped_init) == 1
>        && ((CLASS_TYPE_P (type) && !CLASSTYPE_NON_AGGREGATE (type))
>  	  || VECTOR_TYPE_P (type)))
>      {
> -      tree elt = CONSTRUCTOR_ELT (init, 0)->value;
> +      tree elt = CONSTRUCTOR_ELT (stripped_init, 0)->value;
>        if (reference_related_p (type, TREE_TYPE (elt)))
>  	/* We should have fixed this in reshape_init.  */
>  	gcc_unreachable ();
>      }
>  
> -  if (BRACE_ENCLOSED_INITIALIZER_P (init)
> +  if (BRACE_ENCLOSED_INITIALIZER_P (stripped_init)
>        && !TYPE_NON_AGGREGATE_CLASS (type))
> -    return process_init_constructor (type, init, nested, complain);
> +    return process_init_constructor (type, stripped_init, nested,
> complain);
>    else
>      {
> -      if (COMPOUND_LITERAL_P (init) && code == ARRAY_TYPE)
> +      if (COMPOUND_LITERAL_P (stripped_init) && code == ARRAY_TYPE)
>  	{
>  	  if (complain & tf_error)
>  	    error_at (loc, "cannot initialize aggregate of type %qT
> with "
> @@ -1176,12 +1192,12 @@ digest_init_r (tree type, tree init, int
> nested, int flags,
>  	}
>  
>        if (code == ARRAY_TYPE
> -	  && !BRACE_ENCLOSED_INITIALIZER_P (init))
> +	  && !BRACE_ENCLOSED_INITIALIZER_P (stripped_init))
>  	{
>  	  /* Allow the result of build_array_copy and of
>  	     build_value_init_noctor.  */
> -	  if ((TREE_CODE (init) == VEC_INIT_EXPR
> -	       || TREE_CODE (init) == CONSTRUCTOR)
> +	  if ((TREE_CODE (stripped_init) == VEC_INIT_EXPR
> +	       || TREE_CODE (stripped_init) == CONSTRUCTOR)
>  	      && (same_type_ignoring_top_level_qualifiers_p
>  		  (type, TREE_TYPE (init))))
>  	    return init;
> diff --git a/gcc/fold-const.c b/gcc/fold-const.c
> index 5399288..b982608 100644
> --- a/gcc/fold-const.c
> +++ b/gcc/fold-const.c
> @@ -2938,6 +2938,9 @@ combine_comparisons (location_t loc,
>  int
>  operand_equal_p (const_tree arg0, const_tree arg1, unsigned int
> flags)
>  {
> +  STRIP_ANY_LOCATION_WRAPPER (arg0);
> +  STRIP_ANY_LOCATION_WRAPPER (arg1);
> +
>    /* When checking, verify at the outermost operand_equal_p call
> that
>       if operand_equal_p returns non-zero then ARG0 and ARG1 has the
> same
>       hash value.  */
> diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
> index d086930..e5237d6 100644
> --- a/gcc/objc/objc-act.c
> +++ b/gcc/objc/objc-act.c
> @@ -1455,6 +1455,8 @@ objc_maybe_build_component_ref (tree object,
> tree property_ident)
>  		 || TREE_CODE (t) == COMPONENT_REF)
>  	    t = TREE_OPERAND (t, 0);
>  
> +	  STRIP_ANY_LOCATION_WRAPPER (t);
> +
>  	  if (t == UOBJC_SUPER_decl)
>  	    interface_type = lookup_interface (CLASS_SUPER_NAME
> (implementation_template));
>  	  else if (t == self_decl)
> @@ -5339,6 +5341,8 @@ objc_finish_message_expr (tree receiver, tree
> sel_name, tree method_params,
>    tree retval, class_tree;
>    int self, super, have_cast;
>  
> +  STRIP_ANY_LOCATION_WRAPPER (receiver);
> +
>    /* We have used the receiver, so mark it as read.  */
>    mark_exp_read (receiver);
>  
> diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
> index 562ada7..8149b90 100644
> --- a/gcc/selftest-run-tests.c
> +++ b/gcc/selftest-run-tests.c
> @@ -80,6 +80,7 @@ selftest::run_tests ()
>    input_c_tests ();
>    vec_perm_indices_c_tests ();
>    tree_c_tests ();
> +  convert_c_tests ();
>    gimple_c_tests ();
>    rtl_tests_c_tests ();
>    read_rtl_function_c_tests ();
> diff --git a/gcc/selftest.h b/gcc/selftest.h
> index 8da7c4a..74be3b7 100644
> --- a/gcc/selftest.h
> +++ b/gcc/selftest.h
> @@ -215,6 +215,7 @@ class test_runner
>     alphabetical order.  */
>  extern void attribute_c_tests ();
>  extern void bitmap_c_tests ();
> +extern void convert_c_tests ();
>  extern void diagnostic_c_tests ();
>  extern void diagnostic_show_locus_c_tests ();
>  extern void dumpfile_c_tests ();
> diff --git a/gcc/testsuite/c-c++-common/pr51712.c b/gcc/testsuite/c-
> c++-common/pr51712.c
> index 69e316d..1ff36c4 100644
> --- a/gcc/testsuite/c-c++-common/pr51712.c
> +++ b/gcc/testsuite/c-c++-common/pr51712.c
> @@ -15,5 +15,5 @@ int valid(enum test_enum arg)
>  
>  int valid2(unsigned int arg2)
>  {
> -  return arg2 >= FOO && arg2 <= BAR; /* { dg-bogus "comparison of
> unsigned expression" "" { xfail *-*-* } } */
> +  return arg2 >= FOO && arg2 <= BAR; /* { dg-bogus "comparison of
> unsigned expression" "" { xfail c } } */
>  }
> diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp48.C
> b/gcc/testsuite/g++.dg/cpp1z/decomp48.C
> index 35413c7..3c50b02 100644
> --- a/gcc/testsuite/g++.dg/cpp1z/decomp48.C
> +++ b/gcc/testsuite/g++.dg/cpp1z/decomp48.C
> @@ -18,7 +18,7 @@ f2 ()
>  {
>    S v {1, 2};
>    auto& [s, t] = v;	// { dg-warning "structured bindings only
> available with" "" { target c++14_down } }
> -  return s;		// { dg-warning "reference to local
> variable 'v' returned" }
> +  return s;		// { dg-warning "reference to local
> variable 'v' returned" "" { target *-*-* } .-1 }
>  }
>  
>  int &
> @@ -33,7 +33,7 @@ f4 ()
>  {
>    int a[3] = {1, 2, 3};
>    auto& [s, t, u] = a;	// { dg-warning "structured bindings
> only available with" "" { target c++14_down } }
> -  return s;		// { dg-warning "reference to local
> variable 'a' returned" }
> +  return s;		// { dg-warning "reference to local
> variable 'a' returned" "" { target *-*-* } .-1 }
>  }
>  
>  int &
> @@ -78,7 +78,7 @@ f10 ()
>  {
>    S v {1, 2};
>    auto& [s, t] = v;	// { dg-warning "structured bindings only
> available with" "" { target c++14_down } }
> -  return &s;		// { dg-warning "address of local
> variable 'v' returned" }
> +  return &s;		// { dg-warning "address of local
> variable 'v' returned" "" { target *-*-* } .-1 }
>  }
>  
>  int *
> @@ -93,7 +93,7 @@ f12 ()
>  {
>    int a[3] = {1, 2, 3};
>    auto& [s, t, u] = a;	// { dg-warning "structured bindings
> only available with" "" { target c++14_down } }
> -  return &s;		// { dg-warning "address of local
> variable 'a' returned" }
> +  return &s;		// { dg-warning "address of local
> variable 'a' returned" "" { target *-*-* } .-1 }
>  }
>  
>  int *
> diff --git a/gcc/testsuite/g++.dg/init/array43.C
> b/gcc/testsuite/g++.dg/init/array43.C
> index b4e6512..0078784 100644
> --- a/gcc/testsuite/g++.dg/init/array43.C
> +++ b/gcc/testsuite/g++.dg/init/array43.C
> @@ -1,2 +1,2 @@
> -int a[] = 0;  // { dg-error "5:initializer fails to determine size"
> }
> +int a[] = 0;  // { dg-error "11:initializer fails to determine size"
> }
>  // { dg-error "11:array must be initialized" "" { target *-*-* } .-1 
> }
> diff --git a/gcc/testsuite/g++.dg/init/initializer-string-too-long.C
> b/gcc/testsuite/g++.dg/init/initializer-string-too-long.C
> new file mode 100644
> index 0000000..c4ce468
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/init/initializer-string-too-long.C
> @@ -0,0 +1,9 @@
> +// { dg-options "-fdiagnostics-show-caret" }
> +
> +/* Verify that we highlight *which* string is too long.  */
> +
> +char test[3][4] = { "ok", "too long", "ok" }; // { dg-error
> "initializer-string for array of chars is too long" }
> +/* { dg-begin-multiline-output "" }
> + char test[3][4] = { "ok", "too long", "ok" };
> +                           ^~~~~~~~~~
> +   { dg-end-multiline-output "" } */
> diff --git a/gcc/testsuite/g++.dg/init/pr43064-1.C
> b/gcc/testsuite/g++.dg/init/pr43064-1.C
> new file mode 100644
> index 0000000..8ba396b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/init/pr43064-1.C
> @@ -0,0 +1,21 @@
> +/* Verify that errors about member initializers appear at the bad
> value,
> +   rather than on the last token of the final initializer.  */
> +
> +// { dg-do compile }
> +// { dg-options "-fdiagnostics-show-caret" }
> +
> +class X {
> +  X() : bad(42), // { dg-error "invalid conversion from 'int' to
> 'void\\*'" }
> +	good(42)
> +  { }
> +  
> +  void* bad;
> +  int good;
> +
> +  /* { dg-begin-multiline-output "" }
> +   X() : bad(42),
> +             ^~
> +             |
> +             int
> +     { dg-end-multiline-output "" } */
> +};
> diff --git a/gcc/testsuite/g++.dg/init/pr43064-2.C
> b/gcc/testsuite/g++.dg/init/pr43064-2.C
> new file mode 100644
> index 0000000..bc87947
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/init/pr43064-2.C
> @@ -0,0 +1,34 @@
> +/* Verify that warnings about member initializers appear at the bad
> value,
> +   rather than on the last token of the final initializer.  */
> +
> +// { dg-do compile }
> +// { dg-options "-Wconversion-null -fdiagnostics-show-caret" }
> +
> +#define NULL ((void *)0) // { dg-error "invalid conversion from
> 'void\\*' to 'int'" }
> +/* { dg-begin-multiline-output "" }
> + #define NULL ((void *)0)
> +              ~^~~~~~~~~~
> +               |
> +               void*
> +   { dg-end-multiline-output "" } */
> +
> +class A
> +{
> +public:
> +  A();
> +  bool m_bool;
> +  int m_int;
> +  void *m_ptr;
> +};
> +
> +A::A()
> +  : m_bool(NULL),
> +    m_int(NULL), // { dg-message "in expansion of macro 'NULL'" }
> +    m_ptr(NULL)
> +{
> +}
> +
> +/* { dg-begin-multiline-output "" }
> +     m_int(NULL),
> +           ^~~~
> +   { dg-end-multiline-output "" } */
> diff --git a/gcc/testsuite/g++.dg/init/pr43064-3.C
> b/gcc/testsuite/g++.dg/init/pr43064-3.C
> new file mode 100644
> index 0000000..36726a8
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/init/pr43064-3.C
> @@ -0,0 +1,32 @@
> +/* Verify that warnings about member initializers appear at the bad
> value,
> +   rather than on the last token of the final initializer.  */
> +
> +// { dg-do compile }
> +// { dg-options "-Wconversion-null -fdiagnostics-show-caret" }
> +
> +#define NULL __null // { dg-warning "converting to non-pointer type
> 'int' from NULL" }
> +/* { dg-begin-multiline-output "" }
> + #define NULL __null
> +              ^~~~~~
> +   { dg-end-multiline-output "" } */
> +
> +class A
> +{
> +public:
> +  A();
> +  bool m_bool;
> +  int m_int;
> +  void *m_ptr;
> +};
> +
> +A::A()
> +  : m_bool(NULL),
> +    m_int(NULL), // { dg-message "in expansion of macro 'NULL'" }
> +    m_ptr(NULL)
> +{
> +}
> +
> +/* { dg-begin-multiline-output "" }
> +     m_int(NULL),
> +           ^~~~
> +   { dg-end-multiline-output "" } */
> diff --git a/gcc/testsuite/g++.dg/wrappers/Wparentheses.C
> b/gcc/testsuite/g++.dg/wrappers/Wparentheses.C
> new file mode 100644
> index 0000000..c6157dd
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/wrappers/Wparentheses.C
> @@ -0,0 +1,10 @@
> +// { dg-options "-Wparentheses" }
> +
> +extern char read_skip_spaces ();
> +
> +void test ()
> +{
> +  char c;
> +  while ((c = read_skip_spaces ()) && c != ']')
> +    ;
> +}
> diff --git a/gcc/tree.c b/gcc/tree.c
> index 593ef1a..e4761ec 100644
> --- a/gcc/tree.c
> +++ b/gcc/tree.c
> @@ -6761,6 +6761,9 @@ tree_int_cst_equal (const_tree t1, const_tree
> t2)
>    if (t1 == 0 || t2 == 0)
>      return 0;
>  
> +  STRIP_ANY_LOCATION_WRAPPER (t1);
> +  STRIP_ANY_LOCATION_WRAPPER (t2);
> +
>    if (TREE_CODE (t1) == INTEGER_CST
>        && TREE_CODE (t2) == INTEGER_CST
>        && wi::to_widest (t1) == wi::to_widest (t2))
> @@ -14229,6 +14232,11 @@ maybe_wrap_with_location (tree expr,
> location_t loc)
>    if (EXCEPTIONAL_CLASS_P (expr))
>      return expr;
>  
> +  /* If any auto_suppress_location_wrappers are active, don't create
> +     wrappers.  */
> +  if (suppress_location_wrappers > 0)
> +    return expr;
> +
>    tree_code code
>      = (((CONSTANT_CLASS_P (expr) && TREE_CODE (expr) != STRING_CST)
>  	|| (TREE_CODE (expr) == CONST_DECL && !TREE_STATIC (expr)))
> @@ -14239,6 +14247,8 @@ maybe_wrap_with_location (tree expr,
> location_t loc)
>    return wrapper;
>  }
>  
> +int suppress_location_wrappers;
> +
>  /* Return the name of combined function FN, for debugging
> purposes.  */
>  
>  const char *
> diff --git a/gcc/tree.h b/gcc/tree.h
> index 0ef96ba..311caa1 100644
> --- a/gcc/tree.h
> +++ b/gcc/tree.h
> @@ -131,6 +131,12 @@ as_internal_fn (combined_fn code)
>  #define CONSTANT_CLASS_P(NODE)\
>  	(TREE_CODE_CLASS (TREE_CODE (NODE)) == tcc_constant)
>  
> +/* Nonzero if NODE represents a constant, or is a location wrapper
> +   around such a node.  */
> +
> +#define CONSTANT_CLASS_OR_WRAPPER_P(NODE)\
> +	(CONSTANT_CLASS_P (tree_strip_any_location_wrapper (NODE)))
> +
>  /* Nonzero if NODE represents a type.  */
>  
>  #define TYPE_P(NODE)\
> @@ -1175,6 +1181,19 @@ extern void protected_set_expr_location (tree,
> location_t);
>  
>  extern tree maybe_wrap_with_location (tree, location_t);
>  
> +extern int suppress_location_wrappers;
> +
> +/* A class for suppressing the creation of location wrappers.
> +   Location wrappers will not be created during the lifetime
> +   of an instance of this class.  */
> +
> +class auto_suppress_location_wrappers
> +{
> + public:
> +  auto_suppress_location_wrappers () { ++suppress_location_wrappers;
> }
> +  ~auto_suppress_location_wrappers () { --
> suppress_location_wrappers; }
> +};
> +
>  /* 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)



More information about the Gcc-patches mailing list