public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 2/2] C++: improvements to binary operator diagnostics (PR c++/87504)
  2018-11-05 19:44 [PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486) David Malcolm
@ 2018-11-05 19:44 ` David Malcolm
  2018-11-19 16:51 ` [PING] Re: [PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486) David Malcolm
  2018-12-19 19:01 ` [PATCH 1/2] " Thomas Schwinge
  2 siblings, 0 replies; 34+ messages in thread
From: David Malcolm @ 2018-11-05 19:44 UTC (permalink / raw)
  To: gcc-patches, jason; +Cc: David Malcolm

The C frontend is able (where expression locations are available) to print
problems with binary operators in 3-location form, labelling the types of
the expressions:

  arg_0 op arg_1
  ~~~~~ ^~ ~~~~~
    |        |
    |        arg1 type
    arg0 type

The C++ frontend currently just shows the combined location:

  arg_0 op arg_1
  ~~~~~~^~~~~~~~

and fails to highlight where the subexpressions are, or their types.

This patch introduces a op_location_t struct for handling the above
operator-location vs combined-location split, and a new
class binary_op_rich_location for displaying the above, so that the
C++ frontend is able to use the more detailed 3-location form for
type mismatches in binary operators, and for -Wtautological-compare
(where types are not displayed).  Both forms can be seen in this
example:

bad-binary-ops.C:69:20: error: no match for 'operator&&' (operand types are
  's' and 't')
   69 |   return ns_4::foo && ns_4::inner::bar;
      |          ~~~~~~~~~ ^~ ~~~~~~~~~~~~~~~~
      |                |                   |
      |                s                   t
bad-binary-ops.C:69:20: note: candidate: 'operator&&(bool, bool)' <built-in>
   69 |   return ns_4::foo && ns_4::inner::bar;
      |          ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~

The patch also allows from some uses of macros in
-Wtautological-compare, where both sides of the comparison have
been spelled the same way, e.g.:

Wtautological-compare-ranges.c:23:11: warning: self-comparison always
   evaluates to true [-Wtautological-compare]
   23 |   if (FOO == FOO);
      |           ^~

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu, in
conjunction with the previous patch.

OK for trunk?
Dave

gcc/c-family/ChangeLog:
	PR c++/87504
	* c-common.h (warn_tautological_cmp): Convert 1st param from
	location_t to const op_location_t &.
	* c-warn.c (find_array_ref_with_const_idx_r): Strip location
	wrapper when testing for INTEGER_CST.
	(warn_tautological_bitwise_comparison): Convert 1st param from
	location_t to const op_location_t &; use it to build a
	binary_op_rich_location, and use this.
	(spelled_the_same_p): New function.
	(warn_tautological_cmp): Convert 1st param from location_t to
	const op_location_t &.  Warn for macro expansions if
	spelled_the_same_p.  Use binary_op_rich_location.

gcc/c/ChangeLog:
	PR c++/87504
	* c-typeck.c (class maybe_range_label_for_tree_type_mismatch):
	Move from here to gcc-rich-location.h and gcc-rich-location.c.
	(build_binary_op): Use struct op_location_t and
	class binary_op_rich_location.

gcc/cp/ChangeLog:
	PR c++/87504
	* call.c (op_error): Convert 1st param from location_t to
	const op_location_t &.  Use binary_op_rich_location for binary
	ops.
	(build_conditional_expr_1): Convert 1st param from location_t to
	const op_location_t &.
	(build_conditional_expr): Likewise.
	(build_new_op_1): Likewise.
	(build_new_op): Likewise.
	* cp-tree.h (build_conditional_expr): Likewise.
	(build_new_op): Likewise.
	(build_x_binary_op): Likewise.
	(cp_build_binary_op): Likewise.
	* parser.c (cp_parser_primary_expression): Build a location
	for id-expression nodes.
	(cp_parser_binary_expression): Use an op_location_t when
	calling build_x_binary_op.
	(cp_parser_operator): Build a location for user-defined literals.
	* typeck.c (build_x_binary_op): Convert 1st param from location_t
	to const op_location_t &.
	(cp_build_binary_op): Likewise.  Use binary_op_rich_location.

gcc/ChangeLog:
	PR c++/87504
	* gcc-rich-location.c
	(maybe_range_label_for_tree_type_mismatch::get_text): Move here from
	c/c-typeck.c.
	(binary_op_rich_location::binary_op_rich_location): New ctor.
	(binary_op_rich_location::use_operator_loc_p): New function.
	* gcc-rich-location.h
	(class maybe_range_label_for_tree_type_mismatch)): Move here from
	c/c-typeck.c.
	(struct op_location_t): New forward decl.
	(class binary_op_rich_location): New class.
	* tree.h (struct op_location_t): New struct.

gcc/testsuite/ChangeLog:
	* c-c++-common/Wtautological-compare-ranges.c: New test.
	* g++.dg/cpp0x/pr51420.C: Add -fdiagnostics-show-caret and update
	expected output.
	* g++.dg/cpp0x/udlit-declare-neg.C: Update expected columns in
	output.
	* g++.dg/cpp0x/udlit-member-neg.C: Likewise.
	* g++.dg/diagnostic/bad-binary-ops.C: Update expected output from
	1-location form to 3-location form, with labelling of ranges with
	types.  Add examples of id-expression nodes with namespaces.
	* g++.dg/diagnostic/param-type-mismatch-2.C: Likewise.
---
 gcc/c-family/c-common.h                            |  3 +-
 gcc/c-family/c-warn.c                              | 57 +++++++++++---
 gcc/c/c-typeck.c                                   | 41 +---------
 gcc/cp/call.c                                      | 28 ++++---
 gcc/cp/cp-tree.h                                   | 10 ++-
 gcc/cp/parser.c                                    | 31 +++++++-
 gcc/cp/typeck.c                                    | 14 ++--
 gcc/gcc-rich-location.c                            | 89 ++++++++++++++++++++++
 gcc/gcc-rich-location.h                            | 57 ++++++++++++++
 .../c-c++-common/Wtautological-compare-ranges.c    | 42 ++++++++++
 gcc/testsuite/g++.dg/cpp0x/pr51420.C               | 12 ++-
 gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C     |  8 +-
 gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C      |  2 +-
 gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C   | 57 +++++++++++++-
 .../g++.dg/diagnostic/param-type-mismatch-2.C      |  4 +-
 gcc/tree.h                                         | 49 ++++++++++++
 16 files changed, 424 insertions(+), 80 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/Wtautological-compare-ranges.c

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 641fe57..1e7ebb9 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1263,7 +1263,8 @@ extern void constant_expression_error (tree);
 extern void overflow_warning (location_t, tree, tree = NULL_TREE);
 extern void warn_logical_operator (location_t, enum tree_code, tree,
 				   enum tree_code, tree, enum tree_code, tree);
-extern void warn_tautological_cmp (location_t, enum tree_code, tree, tree);
+extern void warn_tautological_cmp (const op_location_t &, enum tree_code,
+				   tree, tree);
 extern void warn_logical_not_parentheses (location_t, enum tree_code, tree,
 					  tree);
 extern bool warn_if_unused_value (const_tree, location_t);
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index f2ed711..765b46d 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -322,7 +322,8 @@ find_array_ref_with_const_idx_r (tree *expr_p, int *, void *)
 
   if ((TREE_CODE (expr) == ARRAY_REF
        || TREE_CODE (expr) == ARRAY_RANGE_REF)
-      && TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST)
+      && (TREE_CODE (tree_strip_any_location_wrapper (TREE_OPERAND (expr, 1)))
+	  == INTEGER_CST))
     return integer_type_node;
 
   return NULL_TREE;
@@ -334,7 +335,7 @@ find_array_ref_with_const_idx_r (tree *expr_p, int *, void *)
    of this comparison.  */
 
 static void
-warn_tautological_bitwise_comparison (location_t loc, tree_code code,
+warn_tautological_bitwise_comparison (const op_location_t &loc, tree_code code,
 				      tree lhs, tree rhs)
 {
   if (code != EQ_EXPR && code != NE_EXPR)
@@ -389,29 +390,64 @@ warn_tautological_bitwise_comparison (location_t loc, tree_code code,
   if (res == cstw)
     return;
 
+  binary_op_rich_location richloc (loc, lhs, rhs, false);
   if (code == EQ_EXPR)
-    warning_at (loc, OPT_Wtautological_compare,
+    warning_at (&richloc, OPT_Wtautological_compare,
 		"bitwise comparison always evaluates to false");
   else
-    warning_at (loc, OPT_Wtautological_compare,
+    warning_at (&richloc, OPT_Wtautological_compare,
 		"bitwise comparison always evaluates to true");
 }
 
+/* Given LOC_A and LOC_B from macro expansions, return true if
+   they are "spelled the same" i.e. if they are both directly from
+   expansion of the same non-function-like macro.  */
+
+static bool
+spelled_the_same_p (location_t loc_a, location_t loc_b)
+{
+  gcc_assert (from_macro_expansion_at (loc_a));
+  gcc_assert (from_macro_expansion_at (loc_b));
+
+  const line_map_macro *map_a
+    = linemap_check_macro (linemap_lookup (line_table, loc_a));
+
+  const line_map_macro *map_b
+    = linemap_check_macro (linemap_lookup (line_table, loc_b));
+
+  if (map_a->macro == map_b->macro)
+    if (!cpp_fun_like_macro_p (map_a->macro))
+      return true;
+
+  return false;
+}
+
 /* Warn if a self-comparison always evaluates to true or false.  LOC
    is the location of the comparison with code CODE, LHS and RHS are
    operands of the comparison.  */
 
 void
-warn_tautological_cmp (location_t loc, enum tree_code code, tree lhs, tree rhs)
+warn_tautological_cmp (const op_location_t &loc, enum tree_code code,
+		       tree lhs, tree rhs)
 {
   if (TREE_CODE_CLASS (code) != tcc_comparison)
     return;
 
   /* Don't warn for various macro expansions.  */
-  if (from_macro_expansion_at (loc)
-      || from_macro_expansion_at (EXPR_LOCATION (lhs))
-      || from_macro_expansion_at (EXPR_LOCATION (rhs)))
+  if (from_macro_expansion_at (loc))
     return;
+  bool lhs_in_macro = from_macro_expansion_at (EXPR_LOCATION (lhs));
+  bool rhs_in_macro = from_macro_expansion_at (EXPR_LOCATION (rhs));
+  if (lhs_in_macro || rhs_in_macro)
+    {
+      /* Don't warn if exactly one is from a macro.  */
+      if (!(lhs_in_macro && rhs_in_macro))
+	return;
+
+      /* If both are in a macro, only warn if they're spelled the same.  */
+      if (!spelled_the_same_p (EXPR_LOCATION (lhs), EXPR_LOCATION (rhs)))
+	return;
+    }
 
   warn_tautological_bitwise_comparison (loc, code, lhs, rhs);
 
@@ -446,11 +482,12 @@ warn_tautological_cmp (location_t loc, enum tree_code code, tree lhs, tree rhs)
       const bool always_true = (code == EQ_EXPR || code == LE_EXPR
 				|| code == GE_EXPR || code == UNLE_EXPR
 				|| code == UNGE_EXPR || code == UNEQ_EXPR);
+      binary_op_rich_location richloc (loc, lhs, rhs, false);
       if (always_true)
-	warning_at (loc, OPT_Wtautological_compare,
+	warning_at (&richloc, OPT_Wtautological_compare,
 		    "self-comparison always evaluates to true");
       else
-	warning_at (loc, OPT_Wtautological_compare,
+	warning_at (&richloc, OPT_Wtautological_compare,
 		    "self-comparison always evaluates to false");
     }
 }
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 9d09b8d..76e533e 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -11044,38 +11044,6 @@ build_vec_cmp (tree_code code, tree type,
   return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec);
 }
 
-/* Subclass of range_label for labelling the type of EXPR when reporting
-   a type mismatch between EXPR and OTHER_EXPR.
-   Either or both of EXPR and OTHER_EXPR could be NULL.  */
-
-class maybe_range_label_for_tree_type_mismatch : public range_label
-{
- public:
-  maybe_range_label_for_tree_type_mismatch (tree expr, tree other_expr)
-  : m_expr (expr), m_other_expr (other_expr)
-  {
-  }
-
-  label_text get_text (unsigned range_idx) const FINAL OVERRIDE
-  {
-    if (m_expr == NULL_TREE
-	|| !EXPR_P (m_expr))
-      return label_text (NULL, false);
-    tree expr_type = TREE_TYPE (m_expr);
-
-    tree other_type = NULL_TREE;
-    if (m_other_expr && EXPR_P (m_other_expr))
-      other_type = TREE_TYPE (m_other_expr);
-
-   range_label_for_type_mismatch inner (expr_type, other_type);
-   return inner.get_text (range_idx);
-  }
-
- private:
-  tree m_expr;
-  tree m_other_expr;
-};
-
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
    LOCATION is the operator's location.
@@ -12206,12 +12174,9 @@ build_binary_op (location_t location, enum tree_code code,
 
   if (!result_type)
     {
-      gcc_rich_location richloc (location);
-      maybe_range_label_for_tree_type_mismatch
-	label_for_op0 (orig_op0, orig_op1),
-	label_for_op1 (orig_op1, orig_op0);
-      richloc.maybe_add_expr (orig_op0, &label_for_op0);
-      richloc.maybe_add_expr (orig_op1, &label_for_op1);
+      /* Favor showing any expression locations that are available. */
+      op_location_t oploc (location, UNKNOWN_LOCATION);
+      binary_op_rich_location richloc (oploc, orig_op0, orig_op1, true);
       binary_op_error (&richloc, code, TREE_TYPE (op0), TREE_TYPE (op1));
       return error_mark_node;
     }
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index d366d35..145ba8f 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -166,8 +166,8 @@ static tree build_over_call (struct z_candidate *, int, tsubst_flags_t);
 		     /*c_cast_p=*/false, (COMPLAIN))
 static tree convert_like_real (conversion *, tree, tree, int, bool,
 			       bool, tsubst_flags_t);
-static void op_error (location_t, enum tree_code, enum tree_code, tree,
-		      tree, tree, bool);
+static void op_error (const op_location_t &, enum tree_code, enum tree_code,
+		      tree, tree, tree, bool);
 static struct z_candidate *build_user_type_conversion_1 (tree, tree, int,
 							 tsubst_flags_t);
 static void print_z_candidate (location_t, const char *, struct z_candidate *);
@@ -4707,7 +4707,8 @@ op_error_string (const char *errmsg, int ntypes, bool match)
 }
 
 static void
-op_error (location_t loc, enum tree_code code, enum tree_code code2,
+op_error (const op_location_t &loc,
+	  enum tree_code code, enum tree_code code2,
 	  tree arg1, tree arg2, tree arg3, bool match)
 {
   bool assop = code == MODIFY_EXPR;
@@ -4761,8 +4762,12 @@ op_error (location_t loc, enum tree_code code, enum tree_code code2,
     default:
       if (arg2)
 	if (flag_diagnostics_show_caret)
-	  error_at (loc, op_error_string (G_("%<operator%s%>"), 2, match),
-		    opname, TREE_TYPE (arg1), TREE_TYPE (arg2));
+	  {
+	    binary_op_rich_location richloc (loc, arg1, arg2, true);
+	    error_at (&richloc,
+		      op_error_string (G_("%<operator%s%>"), 2, match),
+		      opname, TREE_TYPE (arg1), TREE_TYPE (arg2));
+	  }
 	else
 	  error_at (loc, op_error_string (G_("%<operator%s%> in %<%E %s %E%>"),
 					  2, match),
@@ -4861,7 +4866,8 @@ conditional_conversion (tree e1, tree e2, tsubst_flags_t complain)
    arguments to the conditional expression.  */
 
 static tree
-build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
+build_conditional_expr_1 (const op_location_t &loc,
+			  tree arg1, tree arg2, tree arg3,
                           tsubst_flags_t complain)
 {
   tree arg2_type;
@@ -5455,7 +5461,8 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
 /* Wrapper for above.  */
 
 tree
-build_conditional_expr (location_t loc, tree arg1, tree arg2, tree arg3,
+build_conditional_expr (const op_location_t &loc,
+			tree arg1, tree arg2, tree arg3,
                         tsubst_flags_t complain)
 {
   tree ret;
@@ -5644,8 +5651,9 @@ op_is_ordered (tree_code code)
 }
 
 static tree
-build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
-		tree arg2, tree arg3, tree *overload, tsubst_flags_t complain)
+build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
+		tree arg1, tree arg2, tree arg3, tree *overload,
+		tsubst_flags_t complain)
 {
   struct z_candidate *candidates = 0, *cand;
   vec<tree, va_gc> *arglist;
@@ -6124,7 +6132,7 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
 /* Wrapper for above.  */
 
 tree
-build_new_op (location_t loc, enum tree_code code, int flags,
+build_new_op (const op_location_t &loc, enum tree_code code, int flags,
 	      tree arg1, tree arg2, tree arg3,
 	      tree *overload, tsubst_flags_t complain)
 {
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 26ded3a..8bd8078 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6046,7 +6046,8 @@ extern int raw_dump_id;
 extern bool check_dtor_name			(tree, tree);
 int magic_varargs_p				(tree);
 
-extern tree build_conditional_expr		(location_t, tree, tree, tree, 
+extern tree build_conditional_expr		(const op_location_t &,
+						 tree, tree, tree,
                                                  tsubst_flags_t);
 extern tree build_addr_func			(tree, tsubst_flags_t);
 extern void set_flags_from_callee		(tree);
@@ -6071,7 +6072,8 @@ extern tree build_new_method_call		(tree, tree,
 extern tree build_special_member_call		(tree, tree,
 						 vec<tree, va_gc> **,
 						 tree, int, tsubst_flags_t);
-extern tree build_new_op			(location_t, enum tree_code,
+extern tree build_new_op			(const op_location_t &,
+						 enum tree_code,
 						 int, tree, tree, tree, tree *,
 						 tsubst_flags_t);
 extern tree build_op_call			(tree, vec<tree, va_gc> **,
@@ -7273,7 +7275,7 @@ extern tree cp_build_function_call_nary         (tree, tsubst_flags_t, ...)
 						ATTRIBUTE_SENTINEL;
 extern tree cp_build_function_call_vec		(tree, vec<tree, va_gc> **,
 						 tsubst_flags_t);
-extern tree build_x_binary_op			(location_t,
+extern tree build_x_binary_op			(const op_location_t &,
 						 enum tree_code, tree,
 						 enum tree_code, tree,
 						 enum tree_code, tree *,
@@ -7340,7 +7342,7 @@ extern tree composite_pointer_type		(tree, tree, tree, tree,
 extern tree merge_types				(tree, tree);
 extern tree strip_array_domain			(tree);
 extern tree check_return_expr			(tree, bool *);
-extern tree cp_build_binary_op                  (location_t,
+extern tree cp_build_binary_op                  (const op_location_t &,
 						 enum tree_code, tree, tree,
 						 tsubst_flags_t);
 extern tree build_x_vec_perm_expr               (location_t,
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index b3876e2..0103fae 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -5661,7 +5661,22 @@ cp_parser_primary_expression (cp_parser *parser,
 		 id_expression.get_location ()));
 	if (error_msg)
 	  cp_parser_error (parser, error_msg);
-	decl.set_location (id_expr_token->location);
+
+	/* Build a location for an id-expression of the form:
+	     ::ns::id
+             ~~~~~~^~
+	  or:
+	     id
+	     ^~
+	   i.e. from the start of the first token to the end of the final
+	   token, with the caret at the start of the unqualified-id.  */
+	location_t caret_loc = get_pure_location (id_expression.get_location ());
+	location_t start_loc = get_start (id_expr_token->location);
+	location_t finish_loc = get_finish (id_expression.get_location ());
+	location_t combined_loc
+	  = make_location (caret_loc, start_loc, finish_loc);
+
+	decl.set_location (combined_loc);
 	return decl;
       }
 
@@ -9371,7 +9386,8 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
 	}
       else
         {
-          current.lhs = build_x_binary_op (combined_loc, current.tree_type,
+	  op_location_t op_loc (current.loc, combined_loc);
+	  current.lhs = build_x_binary_op (op_loc, current.tree_type,
                                            current.lhs, current.lhs_type,
                                            rhs, rhs_type, &overload,
                                            complain_flags (decltype_p));
@@ -15087,7 +15103,16 @@ cp_parser_operator (cp_parser* parser)
 	    const char *name = IDENTIFIER_POINTER (id);
 	    id = cp_literal_operator_id (name);
 	  }
-	return id;
+	/* Generate a location of the form:
+	     "" _suffix_identifier
+	     ^~~~~~~~~~~~~~~~~~~~~
+	   with caret == start at the start token, finish at the end of the
+	   suffix identifier.  */
+	location_t finish_loc
+	  = get_finish (cp_lexer_previous_token (parser->lexer)->location);
+	location_t combined_loc
+	  = make_location (start_loc, start_loc, finish_loc);
+	return cp_expr (id, combined_loc);
       }
 
     default:
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index b97d3da..e62fee6 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -4109,7 +4109,7 @@ convert_arguments (tree typelist, vec<tree, va_gc> **values, tree fndecl,
    ARG2_CODE as ERROR_MARK.  */
 
 tree
-build_x_binary_op (location_t loc, enum tree_code code, tree arg1,
+build_x_binary_op (const op_location_t &loc, enum tree_code code, tree arg1,
 		   enum tree_code arg1_code, tree arg2,
 		   enum tree_code arg2_code, tree *overload_p,
 		   tsubst_flags_t complain)
@@ -4298,7 +4298,7 @@ warn_for_null_address (location_t location, tree op, tsubst_flags_t complain)
    multiple inheritance, and deal with pointer to member functions.  */
 
 tree
-cp_build_binary_op (location_t location,
+cp_build_binary_op (const op_location_t &location,
 		    enum tree_code code, tree orig_op0, tree orig_op1,
 		    tsubst_flags_t complain)
 {
@@ -5295,9 +5295,13 @@ cp_build_binary_op (location_t location,
   if (!result_type)
     {
       if (complain & tf_error)
-	error_at (location,
-		  "invalid operands of types %qT and %qT to binary %qO",
-		  TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
+	{
+	  binary_op_rich_location richloc (location,
+					   orig_op0, orig_op1, true);
+	  error_at (&richloc,
+		    "invalid operands of types %qT and %qT to binary %qO",
+		    TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
+	}
       return error_mark_node;
     }
 
diff --git a/gcc/gcc-rich-location.c b/gcc/gcc-rich-location.c
index 81beb61..25a604f 100644
--- a/gcc/gcc-rich-location.c
+++ b/gcc/gcc-rich-location.c
@@ -182,3 +182,92 @@ gcc_rich_location::add_fixit_insert_formatted (const char *content,
   else
     add_fixit_insert_before (insertion_point, content);
 }
+
+/* Implementation of range_label::get_text for
+   maybe_range_label_for_tree_type_mismatch.
+
+   If both expressions are non-NULL, then generate text describing
+   the first expression's type (using the other expression's type
+   for comparison, analogous to %H and %I in the C++ frontend, but
+   on expressions rather than types).  */
+
+label_text
+maybe_range_label_for_tree_type_mismatch::get_text (unsigned range_idx) const
+{
+  if (m_expr == NULL_TREE
+      || !EXPR_P (m_expr))
+    return label_text (NULL, false);
+  tree expr_type = TREE_TYPE (m_expr);
+
+  tree other_type = NULL_TREE;
+  if (m_other_expr && EXPR_P (m_other_expr))
+    other_type = TREE_TYPE (m_other_expr);
+
+  range_label_for_type_mismatch inner (expr_type, other_type);
+  return inner.get_text (range_idx);
+}
+
+/* binary_op_rich_location's ctor.
+
+   If use_operator_loc_p (LOC, ARG0, ARG1), then attempt to make a 3-location
+   rich_location of the form:
+
+     arg_0 op arg_1
+     ~~~~~ ^~ ~~~~~
+       |        |
+       |        arg1 type
+       arg0 type
+
+   labelling the types of the arguments if SHOW_TYPES is true.
+
+   Otherwise, make a 1-location rich_location using the compound
+   location within LOC:
+
+     arg_0 op arg_1
+     ~~~~~~^~~~~~~~
+
+   for which we can't label the types.  */
+
+binary_op_rich_location::binary_op_rich_location (const op_location_t &loc,
+						  tree arg0, tree arg1,
+						  bool show_types)
+: gcc_rich_location (loc.m_combined_loc),
+  m_label_for_arg0 (arg0, arg1),
+  m_label_for_arg1 (arg1, arg0)
+{
+  /* Default (above) to using the combined loc.
+     Potentially override it here: if we have location information for the
+     operator and for both arguments, then split them all out.
+     Alternatively, override it if we don't have the combined location.  */
+  if (use_operator_loc_p (loc, arg0, arg1))
+    {
+      set_range (0, loc.m_operator_loc, SHOW_RANGE_WITH_CARET);
+      maybe_add_expr (arg0, show_types ? &m_label_for_arg0 : NULL);
+      maybe_add_expr (arg1, show_types ? &m_label_for_arg1 : NULL);
+    }
+}
+
+/* Determine if binary_op_rich_location's ctor should attempt to make
+   a 3-location rich_location (the location of the operator and of
+   the 2 arguments), or fall back to a 1-location rich_location showing
+   just the combined location of the operation as a whole.  */
+
+bool
+binary_op_rich_location::use_operator_loc_p (const op_location_t &loc,
+					     tree arg0, tree arg1)
+{
+  /* If we don't have a combined location, then use the operator location,
+     and try to add ranges for the operators.  */
+  if (loc.m_combined_loc == UNKNOWN_LOCATION)
+    return true;
+
+  /* If we don't have the operator location, then use the
+     combined location.  */
+  if (loc.m_operator_loc == UNKNOWN_LOCATION)
+    return false;
+
+  /* We have both operator location and combined location: only use the
+     operator location if we have locations for both arguments.  */
+  return (EXPR_HAS_LOCATION (arg0)
+	  && EXPR_HAS_LOCATION (arg1));
+}
diff --git a/gcc/gcc-rich-location.h b/gcc/gcc-rich-location.h
index d282fd4..db35400 100644
--- a/gcc/gcc-rich-location.h
+++ b/gcc/gcc-rich-location.h
@@ -162,4 +162,61 @@ class range_label_for_type_mismatch : public range_label
   tree m_other_type;
 };
 
+/* Subclass of range_label for labelling the type of EXPR when reporting
+   a type mismatch between EXPR and OTHER_EXPR.
+   Either or both of EXPR and OTHER_EXPR could be NULL.  */
+
+class maybe_range_label_for_tree_type_mismatch : public range_label
+{
+ public:
+  maybe_range_label_for_tree_type_mismatch (tree expr, tree other_expr)
+  : m_expr (expr), m_other_expr (other_expr)
+  {
+  }
+
+  label_text get_text (unsigned range_idx) const FINAL OVERRIDE;
+
+ private:
+  tree m_expr;
+  tree m_other_expr;
+};
+
+struct op_location_t;
+
+/* A subclass of rich_location for showing problems with binary operations.
+
+   If enough location information is available, the ctor will make a
+   3-location rich_location of the form:
+
+     arg_0 op arg_1
+     ~~~~~ ^~ ~~~~~
+       |        |
+       |        arg1 type
+       arg0 type
+
+   labelling the types of the arguments if SHOW_TYPES is true.
+
+   Otherwise, it will fall back to a 1-location rich_location using the
+   compound location within LOC:
+
+     arg_0 op arg_1
+     ~~~~~~^~~~~~~~
+
+   for which we can't label the types.  */
+
+class binary_op_rich_location : public gcc_rich_location
+{
+ public:
+  binary_op_rich_location (const op_location_t &loc,
+			   tree arg0, tree arg1,
+			   bool show_types);
+
+ private:
+  static bool use_operator_loc_p (const op_location_t &loc,
+				  tree arg0, tree arg1);
+
+  maybe_range_label_for_tree_type_mismatch m_label_for_arg0;
+  maybe_range_label_for_tree_type_mismatch m_label_for_arg1;
+};
+
 #endif /* GCC_RICH_LOCATION_H */
diff --git a/gcc/testsuite/c-c++-common/Wtautological-compare-ranges.c b/gcc/testsuite/c-c++-common/Wtautological-compare-ranges.c
new file mode 100644
index 0000000..2634d27
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wtautological-compare-ranges.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-Wtautological-compare -fdiagnostics-show-caret" } */
+
+#define FOO foo
+
+void
+fn1 (int foo)
+{
+  if (foo == foo); /* { dg-warning "self-comparison always evaluates to true" } */
+  /* { dg-begin-multiline-output "" }
+   if (foo == foo);
+           ^~
+     { dg-end-multiline-output "" { target c } } */
+  /* { dg-begin-multiline-output "" }
+   if (foo == foo);
+       ~~~ ^~ ~~~
+     { dg-end-multiline-output "" { target c++ } } */
+}
+
+void
+fn2 (int foo)
+{
+  if (FOO == FOO); /* { dg-warning "self-comparison always evaluates to true" } */
+  /* { dg-begin-multiline-output "" }
+   if (FOO == FOO);
+           ^~
+     { dg-end-multiline-output "" } */
+}
+
+void
+fn3 (int foo)
+{
+  if ((foo & 16) == 10); /* { dg-warning "bitwise comparison always evaluates to false" } */
+  /* { dg-begin-multiline-output "" }
+   if ((foo & 16) == 10);
+                  ^~
+     { dg-end-multiline-output "" { target c } } */
+  /* { dg-begin-multiline-output "" }
+   if ((foo & 16) == 10);
+       ~~~~~~~~~~ ^~ ~~
+     { dg-end-multiline-output "" { target c++ } } */
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr51420.C b/gcc/testsuite/g++.dg/cpp0x/pr51420.C
index fc70d46..76cf77b 100644
--- a/gcc/testsuite/g++.dg/cpp0x/pr51420.C
+++ b/gcc/testsuite/g++.dg/cpp0x/pr51420.C
@@ -1,8 +1,18 @@
 // { dg-do compile { target c++11 } }
+// { dg-options "-fdiagnostics-show-caret" }
 
 void
 foo()
 {
-  float x = operator"" _F();  //  { dg-error  "13:'operator\"\"_F' was not declared in this scope" }
+  float x = operator"" _F();  //  { dg-error  "21:'operator\"\"_F' was not declared in this scope" }
+  /* { dg-begin-multiline-output "" }
+   float x = operator"" _F();
+             ~~~~~~~~^~~~~
+     { dg-end-multiline-output "" } */
+
   float y = 0_F;  //  { dg-error  "unable to find numeric literal operator" }
+  /* { dg-begin-multiline-output "" }
+   float y = 0_F;
+             ^~~
+     { dg-end-multiline-output "" } */
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C
index 721f87d..8458c1c 100644
--- a/gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-declare-neg.C
@@ -2,14 +2,14 @@
 
 //  Check that undeclared literal operator calls and literals give appropriate errors.
 
-int i = operator"" _Bar('x');  // { dg-error "9:'operator\"\"_Bar' was not declared in this scope" }
+int i = operator"" _Bar('x');  // { dg-error "17:'operator\"\"_Bar' was not declared in this scope" }
 int j = 'x'_Bar;  // { dg-error "unable to find character literal operator|with|argument" }
 
-int ii = operator"" _BarCharStr("Howdy, Pardner!");  // { dg-error "10:'operator\"\"_BarCharStr' was not declared in this scope" }
+int ii = operator"" _BarCharStr("Howdy, Pardner!");  // { dg-error "18:'operator\"\"_BarCharStr' was not declared in this scope" }
 int jj = "Howdy, Pardner!"_BarCharStr;  // { dg-error "unable to find string literal operator|Possible missing length argument" }
 
-unsigned long long iULL = operator"" _BarULL(666ULL);  // { dg-error "27:'operator\"\"_BarULL' was not declared in this scope" }
+unsigned long long iULL = operator"" _BarULL(666ULL);  // { dg-error "35:'operator\"\"_BarULL' was not declared in this scope" }
 unsigned long long jULL = 666_BarULL;  // { dg-error "unable to find numeric literal operator" }
 
-long double iLD = operator"" _BarLD(666.0L);  // { dg-error "19:'operator\"\"_BarLD' was not declared in this scope" }
+long double iLD = operator"" _BarLD(666.0L);  // { dg-error "27:'operator\"\"_BarLD' was not declared in this scope" }
 long double jLD = 666.0_BarLD;  // { dg-error "unable to find numeric literal operator" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C b/gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C
index f2eef0f..4d446f0 100644
--- a/gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-member-neg.C
@@ -7,7 +7,7 @@ public:
   int operator"" _Bar(char32_t);  // { dg-error "7:.int Foo::operator\"\"_Bar\\(char32_t\\). must be a non-member function" }
 };
 
-int i = operator"" _Bar(U'x');  // { dg-error "9:'operator\"\"_Bar' was not declared in this scope" }
+int i = operator"" _Bar(U'x');  // { dg-error "17:'operator\"\"_Bar' was not declared in this scope" }
 int j = U'x'_Bar;  // { dg-error "unable to find character literal operator" }
 
 int
diff --git a/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C b/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C
index 4ab7656..fab5849 100644
--- a/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C
+++ b/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C
@@ -11,7 +11,10 @@ void test_1 ()
 
 /* { dg-begin-multiline-output "" }
    myvec[1] / ptr;
-   ~~~~~~~~~^~~~~
+   ~~~~~~~~ ^ ~~~
+          |   |
+          |   const int*
+          __m128 {aka float}
    { dg-end-multiline-output "" } */
 }
 
@@ -28,8 +31,12 @@ int test_2 (void)
 /* { dg-begin-multiline-output "" }
    return (some_function ()
            ~~~~~~~~~~~~~~~~
+                         |
+                         s
     + some_other_function ());
-    ^~~~~~~~~~~~~~~~~~~~~~~~
+    ^ ~~~~~~~~~~~~~~~~~~~~~~
+                          |
+                          t
    { dg-end-multiline-output "" } */
 }
 
@@ -39,6 +46,52 @@ int test_3 (struct s param_s, struct t param_t)
 
 /* { dg-begin-multiline-output "" }
    return param_s && param_t;
+          ~~~~~~~ ^~ ~~~~~~~
+          |          |
+          s          t
+   { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
+   return param_s && param_t;
           ~~~~~~~~^~~~~~~~~~
    { dg-end-multiline-output "" } */
 }
+
+namespace ns_4
+{
+  struct s foo;
+  namespace inner {
+    struct t bar;
+  };
+};
+
+int test_4a (void)
+{
+  return ns_4::foo && ns_4::inner::bar; // { dg-error "no match for .operator" }
+  /* { dg-begin-multiline-output "" }
+   return ns_4::foo && ns_4::inner::bar;
+          ~~~~~~~~~ ^~ ~~~~~~~~~~~~~~~~
+                |                   |
+                s                   t
+     { dg-end-multiline-output "" } */
+
+  /* { dg-begin-multiline-output "" }
+   return ns_4::foo && ns_4::inner::bar;
+          ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+int test_4b (void)
+{
+  return ::ns_4::foo && ns_4::inner::bar; // { dg-error "no match for .operator" }
+  /* { dg-begin-multiline-output "" }
+   return ::ns_4::foo && ns_4::inner::bar;
+          ~~~~~~~~~~~ ^~ ~~~~~~~~~~~~~~~~
+                  |                   |
+                  s                   t
+     { dg-end-multiline-output "" } */
+
+  /* { dg-begin-multiline-output "" }
+   return ::ns_4::foo && ns_4::inner::bar;
+          ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
+     { dg-end-multiline-output "" } */
+}
diff --git a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
index f74f8d3..5f3c154 100644
--- a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
+++ b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
@@ -208,7 +208,9 @@ int test_10 ()
   return v10_a - v10_b; // { dg-error "no match for" }
   /* { dg-begin-multiline-output "" }
    return v10_a - v10_b;
-          ~~~~~~^~~~~~~
+          ~~~~~ ^ ~~~~~
+          |       |
+          s10     s10
      { dg-end-multiline-output "" } */
   // { dg-message "candidate" "" { target *-*-* } s10_operator }
   /* { dg-begin-multiline-output "" }
diff --git a/gcc/tree.h b/gcc/tree.h
index 311caa1..3b0772c 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5915,4 +5915,53 @@ fndecl_built_in_p (const_tree node, built_in_function name)
 	  && DECL_FUNCTION_CODE (node) == name);
 }
 
+/* A struct for encapsulating location information about an operator
+   and the operation built from it.
+
+   m_operator_loc is the location of the operator
+   m_combined_loc is the location of the compound expression.
+
+   For example, given "a && b" the, operator location is:
+      a && b
+        ^~
+   and the combined location is:
+      a && b
+      ~~^~~~
+   Capturing this information allows for class binary_op_rich_location
+   to provide detailed information about e.g. type mismatches in binary
+   operations where enough location information is available:
+
+     arg_0 op arg_1
+     ~~~~~ ^~ ~~~~~
+       |        |
+       |        arg1 type
+       arg0 type
+
+   falling back to just showing the combined location:
+
+     arg_0 op arg_1
+     ~~~~~~^~~~~~~~
+
+   where it is not.  */
+
+struct op_location_t
+{
+  location_t m_operator_loc;
+  location_t m_combined_loc;
+
+  /* 1-argument ctor, for constructing from a combined location.  */
+  op_location_t (location_t combined_loc)
+  : m_operator_loc (UNKNOWN_LOCATION), m_combined_loc (combined_loc)
+  {}
+
+  /* 2-argument ctor, for distinguishing between the operator's location
+     and the combined location.  */
+  op_location_t (location_t operator_loc, location_t combined_loc)
+  : m_operator_loc (operator_loc), m_combined_loc (combined_loc)
+  {}
+
+  /* Implicitly convert back to a location_t, using the combined location.  */
+  operator location_t () const { return m_combined_loc; }
+};
+
 #endif  /* GCC_TREE_H  */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
@ 2018-11-05 19:44 David Malcolm
  2018-11-05 19:44 ` [PATCH 2/2] C++: improvements to binary operator diagnostics (PR c++/87504) David Malcolm
                   ` (2 more replies)
  0 siblings, 3 replies; 34+ messages in thread
From: David Malcolm @ 2018-11-05 19:44 UTC (permalink / raw)
  To: gcc-patches, jason; +Cc: David Malcolm

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&chxr=1,58.26,61.79&chco=FF0000,0000FF&chdl=control|experiment&chds=58.26,61.79&chd=t:59.55,60.26,60.53,60.35,60.17,60.27,59.26,60.01,60.21,60.23,60.1,60.2,60.12,60.48,60.32,60.18,60.01,60.01,60.04,59.96,60.1,60.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=Compilation+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&chxr=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&chxr=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.72|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.78,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+kdecore.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=*/false,
 						     /*allow_expansion_p=*/true,
-						     /*non_constant_p=*/NULL);
+						     /*non_constant_p=*/NULL,
+						     /*close_paren_loc=*/NULL,
+						     /*wrap_locations_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=*/NULL,
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)
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PING] Re: [PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
  2018-11-05 19:44 [PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486) David Malcolm
  2018-11-05 19:44 ` [PATCH 2/2] C++: improvements to binary operator diagnostics (PR c++/87504) David Malcolm
@ 2018-11-19 16:51 ` David Malcolm
  2018-12-03 22:10   ` Jeff Law
  2018-12-19 19:01 ` [PATCH 1/2] " Thomas Schwinge
  2 siblings, 1 reply; 34+ messages in thread
From: David Malcolm @ 2018-11-19 16:51 UTC (permalink / raw)
  To: gcc-patches, jason

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)

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PING] Re: [PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
  2018-11-19 16:51 ` [PING] Re: [PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486) David Malcolm
@ 2018-12-03 22:10   ` Jeff Law
  2018-12-04 15:20     ` David Malcolm
                       ` (2 more replies)
  0 siblings, 3 replies; 34+ messages in thread
From: Jeff Law @ 2018-12-03 22:10 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jason

On 11/19/18 9:51 AM, David Malcolm wrote:
> 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
> 

>>
>> [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.
Well, you probably know my biggest worry with this -- the unwrappign
wack-a-mole problem.  It looks like additional memory usage is
measurable, but tiny.

Have you received any feedback from Jason on the C++ side?  That's the
bulk of this patch AFAICT.

I don't see anything objectionable in the c-family/ or generic bits.
But again I worry more about the need to sprinkle unwrapping all over
the place.



Jeff

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PING] Re: [PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
  2018-12-03 22:10   ` Jeff Law
@ 2018-12-04 15:20     ` David Malcolm
  2018-12-04 21:48     ` [PATCH 1/2] v2: " David Malcolm
  2018-12-04 23:31     ` [PING] Re: [PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486) Jason Merrill
  2 siblings, 0 replies; 34+ messages in thread
From: David Malcolm @ 2018-12-04 15:20 UTC (permalink / raw)
  To: Jeff Law, gcc-patches, jason

On Mon, 2018-12-03 at 15:10 -0700, Jeff Law wrote:
> On 11/19/18 9:51 AM, David Malcolm wrote:
> > 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
> > 
> > > 
> > > [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.
> 
> Well, you probably know my biggest worry with this -- the unwrappign
> wack-a-mole problem.  It looks like additional memory usage is
> measurable, but tiny.
> 
> Have you received any feedback from Jason on the C++ side?  That's
> the
> bulk of this patch AFAICT.

Not yet.

> I don't see anything objectionable in the c-family/ or generic bits.
> But again I worry more about the need to sprinkle unwrapping all over
> the place.

Thanks for looking at this.

FWIW, the patches have bit-rotted somewhat over the last month; I'm
working on fixing them.

Dave

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 2/2] v2: C++: improvements to binary operator diagnostics (PR c++/87504)
  2018-12-04 21:48     ` [PATCH 1/2] v2: " David Malcolm
@ 2018-12-04 21:48       ` David Malcolm
  2018-12-11 19:52         ` PING " David Malcolm
  2018-12-12 20:43         ` Jason Merrill
  0 siblings, 2 replies; 34+ messages in thread
From: David Malcolm @ 2018-12-04 21:48 UTC (permalink / raw)
  To: jason; +Cc: Jeff Law, gcc-patches, David Malcolm

The v1 patch:
  https://gcc.gnu.org/ml/gcc-patches/2018-11/msg00303.html
has bitrotten somewhat, so here's v2 of the patch, updated relative
to r266740.

Blurb from v1 patch follows:

The C frontend is able (where expression locations are available) to print
problems with binary operators in 3-location form, labelling the types of
the expressions:

  arg_0 op arg_1
  ~~~~~ ^~ ~~~~~
    |        |
    |        arg1 type
    arg0 type

The C++ frontend currently just shows the combined location:

  arg_0 op arg_1
  ~~~~~~^~~~~~~~

and fails to highlight where the subexpressions are, or their types.

This patch introduces a op_location_t struct for handling the above
operator-location vs combined-location split, and a new
class binary_op_rich_location for displaying the above, so that the
C++ frontend is able to use the more detailed 3-location form for
type mismatches in binary operators, and for -Wtautological-compare
(where types are not displayed).  Both forms can be seen in this
example:

bad-binary-ops.C:69:20: error: no match for 'operator&&' (operand types are
  's' and 't')
   69 |   return ns_4::foo && ns_4::inner::bar;
      |          ~~~~~~~~~ ^~ ~~~~~~~~~~~~~~~~
      |                |                   |
      |                s                   t
bad-binary-ops.C:69:20: note: candidate: 'operator&&(bool, bool)' <built-in>
   69 |   return ns_4::foo && ns_4::inner::bar;
      |          ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~

The patch also allows from some uses of macros in
-Wtautological-compare, where both sides of the comparison have
been spelled the same way, e.g.:

Wtautological-compare-ranges.c:23:11: warning: self-comparison always
   evaluates to true [-Wtautological-compare]
   23 |   if (FOO == FOO);
      |           ^~

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu, in
conjunction with the previous patch.

OK for trunk?
Dave

gcc/c-family/ChangeLog:
	PR c++/87504
	* c-common.h (warn_tautological_cmp): Convert 1st param from
	location_t to const op_location_t &.
	* c-warn.c (find_array_ref_with_const_idx_r): Strip location
	wrapper when testing for INTEGER_CST.
	(warn_tautological_bitwise_comparison): Convert 1st param from
	location_t to const op_location_t &; use it to build a
	binary_op_rich_location, and use this.
	(spelled_the_same_p): New function.
	(warn_tautological_cmp): Convert 1st param from location_t to
	const op_location_t &.  Warn for macro expansions if
	spelled_the_same_p.  Use binary_op_rich_location.

gcc/c/ChangeLog:
	PR c++/87504
	* c-typeck.c (class maybe_range_label_for_tree_type_mismatch):
	Move from here to gcc-rich-location.h and gcc-rich-location.c.
	(build_binary_op): Use struct op_location_t and
	class binary_op_rich_location.

gcc/cp/ChangeLog:
	PR c++/87504
	* call.c (op_error): Convert 1st param from location_t to
	const op_location_t &.  Use binary_op_rich_location for binary
	ops.
	(build_conditional_expr_1): Convert 1st param from location_t to
	const op_location_t &.
	(build_conditional_expr): Likewise.
	(build_new_op_1): Likewise.
	(build_new_op): Likewise.
	* cp-tree.h (build_conditional_expr): Likewise.
	(build_new_op): Likewise.
	(build_x_binary_op): Likewise.
	(cp_build_binary_op): Likewise.
	* parser.c (cp_parser_primary_expression): Build a location
	for id-expression nodes.
	(cp_parser_binary_expression): Use an op_location_t when
	calling build_x_binary_op.
	(cp_parser_operator): Build a location for user-defined literals.
	* typeck.c (build_x_binary_op): Convert 1st param from location_t
	to const op_location_t &.
	(cp_build_binary_op): Likewise.  Use binary_op_rich_location.

gcc/ChangeLog:
	PR c++/87504
	* gcc-rich-location.c
	(maybe_range_label_for_tree_type_mismatch::get_text): Move here from
	c/c-typeck.c.
	(binary_op_rich_location::binary_op_rich_location): New ctor.
	(binary_op_rich_location::use_operator_loc_p): New function.
	* gcc-rich-location.h
	(class maybe_range_label_for_tree_type_mismatch)): Move here from
	c/c-typeck.c.
	(struct op_location_t): New forward decl.
	(class binary_op_rich_location): New class.
	* tree.h (struct op_location_t): New struct.

gcc/testsuite/ChangeLog:
	* c-c++-common/Wtautological-compare-ranges.c: New test.
	* g++.dg/cpp0x/pr51420.C: Add -fdiagnostics-show-caret and update
	expected output.
	* g++.dg/diagnostic/bad-binary-ops.C: Update expected output from
	1-location form to 3-location form, with labelling of ranges with
	types.  Add examples of id-expression nodes with namespaces.
	* g++.dg/diagnostic/param-type-mismatch-2.C: Likewise.

This is the 2nd commit message:

FIXME: column and multiline fixes to * g++.dg/cpp0x/pr51420.C
---
 gcc/c-family/c-common.h                            |  3 +-
 gcc/c-family/c-warn.c                              | 57 +++++++++++---
 gcc/c/c-typeck.c                                   | 41 +---------
 gcc/cp/call.c                                      | 28 ++++---
 gcc/cp/cp-tree.h                                   | 10 ++-
 gcc/cp/parser.c                                    | 32 ++++++--
 gcc/cp/typeck.c                                    | 14 ++--
 gcc/gcc-rich-location.c                            | 89 ++++++++++++++++++++++
 gcc/gcc-rich-location.h                            | 57 ++++++++++++++
 .../c-c++-common/Wtautological-compare-ranges.c    | 42 ++++++++++
 gcc/testsuite/g++.dg/cpp0x/pr51420.C               | 10 +++
 gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C   | 57 +++++++++++++-
 .../g++.dg/diagnostic/param-type-mismatch-2.C      |  4 +-
 gcc/tree.h                                         | 49 ++++++++++++
 14 files changed, 417 insertions(+), 76 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/Wtautological-compare-ranges.c

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 4187343..0b9ddf6 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1268,7 +1268,8 @@ extern void constant_expression_error (tree);
 extern void overflow_warning (location_t, tree, tree = NULL_TREE);
 extern void warn_logical_operator (location_t, enum tree_code, tree,
 				   enum tree_code, tree, enum tree_code, tree);
-extern void warn_tautological_cmp (location_t, enum tree_code, tree, tree);
+extern void warn_tautological_cmp (const op_location_t &, enum tree_code,
+				   tree, tree);
 extern void warn_logical_not_parentheses (location_t, enum tree_code, tree,
 					  tree);
 extern bool warn_if_unused_value (const_tree, location_t);
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index fc7f87c..fce9d84 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -322,7 +322,8 @@ find_array_ref_with_const_idx_r (tree *expr_p, int *, void *)
 
   if ((TREE_CODE (expr) == ARRAY_REF
        || TREE_CODE (expr) == ARRAY_RANGE_REF)
-      && TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST)
+      && (TREE_CODE (tree_strip_any_location_wrapper (TREE_OPERAND (expr, 1)))
+	  == INTEGER_CST))
     return integer_type_node;
 
   return NULL_TREE;
@@ -334,7 +335,7 @@ find_array_ref_with_const_idx_r (tree *expr_p, int *, void *)
    of this comparison.  */
 
 static void
-warn_tautological_bitwise_comparison (location_t loc, tree_code code,
+warn_tautological_bitwise_comparison (const op_location_t &loc, tree_code code,
 				      tree lhs, tree rhs)
 {
   if (code != EQ_EXPR && code != NE_EXPR)
@@ -389,29 +390,64 @@ warn_tautological_bitwise_comparison (location_t loc, tree_code code,
   if (res == cstw)
     return;
 
+  binary_op_rich_location richloc (loc, lhs, rhs, false);
   if (code == EQ_EXPR)
-    warning_at (loc, OPT_Wtautological_compare,
+    warning_at (&richloc, OPT_Wtautological_compare,
 		"bitwise comparison always evaluates to false");
   else
-    warning_at (loc, OPT_Wtautological_compare,
+    warning_at (&richloc, OPT_Wtautological_compare,
 		"bitwise comparison always evaluates to true");
 }
 
+/* Given LOC_A and LOC_B from macro expansions, return true if
+   they are "spelled the same" i.e. if they are both directly from
+   expansion of the same non-function-like macro.  */
+
+static bool
+spelled_the_same_p (location_t loc_a, location_t loc_b)
+{
+  gcc_assert (from_macro_expansion_at (loc_a));
+  gcc_assert (from_macro_expansion_at (loc_b));
+
+  const line_map_macro *map_a
+    = linemap_check_macro (linemap_lookup (line_table, loc_a));
+
+  const line_map_macro *map_b
+    = linemap_check_macro (linemap_lookup (line_table, loc_b));
+
+  if (map_a->macro == map_b->macro)
+    if (!cpp_fun_like_macro_p (map_a->macro))
+      return true;
+
+  return false;
+}
+
 /* Warn if a self-comparison always evaluates to true or false.  LOC
    is the location of the comparison with code CODE, LHS and RHS are
    operands of the comparison.  */
 
 void
-warn_tautological_cmp (location_t loc, enum tree_code code, tree lhs, tree rhs)
+warn_tautological_cmp (const op_location_t &loc, enum tree_code code,
+		       tree lhs, tree rhs)
 {
   if (TREE_CODE_CLASS (code) != tcc_comparison)
     return;
 
   /* Don't warn for various macro expansions.  */
-  if (from_macro_expansion_at (loc)
-      || from_macro_expansion_at (EXPR_LOCATION (lhs))
-      || from_macro_expansion_at (EXPR_LOCATION (rhs)))
+  if (from_macro_expansion_at (loc))
     return;
+  bool lhs_in_macro = from_macro_expansion_at (EXPR_LOCATION (lhs));
+  bool rhs_in_macro = from_macro_expansion_at (EXPR_LOCATION (rhs));
+  if (lhs_in_macro || rhs_in_macro)
+    {
+      /* Don't warn if exactly one is from a macro.  */
+      if (!(lhs_in_macro && rhs_in_macro))
+	return;
+
+      /* If both are in a macro, only warn if they're spelled the same.  */
+      if (!spelled_the_same_p (EXPR_LOCATION (lhs), EXPR_LOCATION (rhs)))
+	return;
+    }
 
   warn_tautological_bitwise_comparison (loc, code, lhs, rhs);
 
@@ -446,11 +482,12 @@ warn_tautological_cmp (location_t loc, enum tree_code code, tree lhs, tree rhs)
       const bool always_true = (code == EQ_EXPR || code == LE_EXPR
 				|| code == GE_EXPR || code == UNLE_EXPR
 				|| code == UNGE_EXPR || code == UNEQ_EXPR);
+      binary_op_rich_location richloc (loc, lhs, rhs, false);
       if (always_true)
-	warning_at (loc, OPT_Wtautological_compare,
+	warning_at (&richloc, OPT_Wtautological_compare,
 		    "self-comparison always evaluates to true");
       else
-	warning_at (loc, OPT_Wtautological_compare,
+	warning_at (&richloc, OPT_Wtautological_compare,
 		    "self-comparison always evaluates to false");
     }
 }
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 8fbecfc..33aad1c 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -11310,38 +11310,6 @@ build_vec_cmp (tree_code code, tree type,
   return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec);
 }
 
-/* Subclass of range_label for labelling the type of EXPR when reporting
-   a type mismatch between EXPR and OTHER_EXPR.
-   Either or both of EXPR and OTHER_EXPR could be NULL.  */
-
-class maybe_range_label_for_tree_type_mismatch : public range_label
-{
- public:
-  maybe_range_label_for_tree_type_mismatch (tree expr, tree other_expr)
-  : m_expr (expr), m_other_expr (other_expr)
-  {
-  }
-
-  label_text get_text (unsigned range_idx) const FINAL OVERRIDE
-  {
-    if (m_expr == NULL_TREE
-	|| !EXPR_P (m_expr))
-      return label_text (NULL, false);
-    tree expr_type = TREE_TYPE (m_expr);
-
-    tree other_type = NULL_TREE;
-    if (m_other_expr && EXPR_P (m_other_expr))
-      other_type = TREE_TYPE (m_other_expr);
-
-   range_label_for_type_mismatch inner (expr_type, other_type);
-   return inner.get_text (range_idx);
-  }
-
- private:
-  tree m_expr;
-  tree m_other_expr;
-};
-
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
    LOCATION is the operator's location.
@@ -12472,12 +12440,9 @@ build_binary_op (location_t location, enum tree_code code,
 
   if (!result_type)
     {
-      gcc_rich_location richloc (location);
-      maybe_range_label_for_tree_type_mismatch
-	label_for_op0 (orig_op0, orig_op1),
-	label_for_op1 (orig_op1, orig_op0);
-      richloc.maybe_add_expr (orig_op0, &label_for_op0);
-      richloc.maybe_add_expr (orig_op1, &label_for_op1);
+      /* Favor showing any expression locations that are available. */
+      op_location_t oploc (location, UNKNOWN_LOCATION);
+      binary_op_rich_location richloc (oploc, orig_op0, orig_op1, true);
       binary_op_error (&richloc, code, TREE_TYPE (op0), TREE_TYPE (op1));
       return error_mark_node;
     }
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 6dd8744..ca8799d 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -166,8 +166,8 @@ static tree build_over_call (struct z_candidate *, int, tsubst_flags_t);
 		     /*c_cast_p=*/false, (COMPLAIN))
 static tree convert_like_real (conversion *, tree, tree, int, bool,
 			       bool, tsubst_flags_t);
-static void op_error (location_t, enum tree_code, enum tree_code, tree,
-		      tree, tree, bool);
+static void op_error (const op_location_t &, enum tree_code, enum tree_code,
+		      tree, tree, tree, bool);
 static struct z_candidate *build_user_type_conversion_1 (tree, tree, int,
 							 tsubst_flags_t);
 static void print_z_candidate (location_t, const char *, struct z_candidate *);
@@ -4713,7 +4713,8 @@ op_error_string (const char *errmsg, int ntypes, bool match)
 }
 
 static void
-op_error (location_t loc, enum tree_code code, enum tree_code code2,
+op_error (const op_location_t &loc,
+	  enum tree_code code, enum tree_code code2,
 	  tree arg1, tree arg2, tree arg3, bool match)
 {
   bool assop = code == MODIFY_EXPR;
@@ -4767,8 +4768,12 @@ op_error (location_t loc, enum tree_code code, enum tree_code code2,
     default:
       if (arg2)
 	if (flag_diagnostics_show_caret)
-	  error_at (loc, op_error_string (G_("%<operator%s%>"), 2, match),
-		    opname, TREE_TYPE (arg1), TREE_TYPE (arg2));
+	  {
+	    binary_op_rich_location richloc (loc, arg1, arg2, true);
+	    error_at (&richloc,
+		      op_error_string (G_("%<operator%s%>"), 2, match),
+		      opname, TREE_TYPE (arg1), TREE_TYPE (arg2));
+	  }
 	else
 	  error_at (loc, op_error_string (G_("%<operator%s%> in %<%E %s %E%>"),
 					  2, match),
@@ -4867,7 +4872,8 @@ conditional_conversion (tree e1, tree e2, tsubst_flags_t complain)
    arguments to the conditional expression.  */
 
 static tree
-build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
+build_conditional_expr_1 (const op_location_t &loc,
+			  tree arg1, tree arg2, tree arg3,
                           tsubst_flags_t complain)
 {
   tree arg2_type;
@@ -5461,7 +5467,8 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
 /* Wrapper for above.  */
 
 tree
-build_conditional_expr (location_t loc, tree arg1, tree arg2, tree arg3,
+build_conditional_expr (const op_location_t &loc,
+			tree arg1, tree arg2, tree arg3,
                         tsubst_flags_t complain)
 {
   tree ret;
@@ -5650,8 +5657,9 @@ op_is_ordered (tree_code code)
 }
 
 static tree
-build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
-		tree arg2, tree arg3, tree *overload, tsubst_flags_t complain)
+build_new_op_1 (const op_location_t &loc, enum tree_code code, int flags,
+		tree arg1, tree arg2, tree arg3, tree *overload,
+		tsubst_flags_t complain)
 {
   struct z_candidate *candidates = 0, *cand;
   vec<tree, va_gc> *arglist;
@@ -6130,7 +6138,7 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
 /* Wrapper for above.  */
 
 tree
-build_new_op (location_t loc, enum tree_code code, int flags,
+build_new_op (const op_location_t &loc, enum tree_code code, int flags,
 	      tree arg1, tree arg2, tree arg3,
 	      tree *overload, tsubst_flags_t complain)
 {
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 111a123..e80334a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6097,7 +6097,8 @@ extern int raw_dump_id;
 extern bool check_dtor_name			(tree, tree);
 int magic_varargs_p				(tree);
 
-extern tree build_conditional_expr		(location_t, tree, tree, tree, 
+extern tree build_conditional_expr		(const op_location_t &,
+						 tree, tree, tree,
                                                  tsubst_flags_t);
 extern tree build_addr_func			(tree, tsubst_flags_t);
 extern void set_flags_from_callee		(tree);
@@ -6122,7 +6123,8 @@ extern tree build_new_method_call		(tree, tree,
 extern tree build_special_member_call		(tree, tree,
 						 vec<tree, va_gc> **,
 						 tree, int, tsubst_flags_t);
-extern tree build_new_op			(location_t, enum tree_code,
+extern tree build_new_op			(const op_location_t &,
+						 enum tree_code,
 						 int, tree, tree, tree, tree *,
 						 tsubst_flags_t);
 extern tree build_op_call			(tree, vec<tree, va_gc> **,
@@ -7338,7 +7340,7 @@ extern tree cp_build_function_call_nary         (tree, tsubst_flags_t, ...)
 						ATTRIBUTE_SENTINEL;
 extern tree cp_build_function_call_vec		(tree, vec<tree, va_gc> **,
 						 tsubst_flags_t);
-extern tree build_x_binary_op			(location_t,
+extern tree build_x_binary_op			(const op_location_t &,
 						 enum tree_code, tree,
 						 enum tree_code, tree,
 						 enum tree_code, tree *,
@@ -7405,7 +7407,7 @@ extern tree composite_pointer_type		(tree, tree, tree, tree,
 extern tree merge_types				(tree, tree);
 extern tree strip_array_domain			(tree);
 extern tree check_return_expr			(tree, bool *);
-extern tree cp_build_binary_op                  (location_t,
+extern tree cp_build_binary_op                  (const op_location_t &,
 						 enum tree_code, tree, tree,
 						 tsubst_flags_t);
 extern tree build_x_vec_perm_expr               (location_t,
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 4acc79d..321ff39 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -5710,8 +5710,21 @@ cp_parser_primary_expression (cp_parser *parser,
 		 id_expression.get_location ()));
 	if (error_msg)
 	  cp_parser_error (parser, error_msg);
-	decl.set_location (id_expression.get_location ());
-	decl.set_range (id_expr_token->location, id_expression.get_finish ());
+	/* Build a location for an id-expression of the form:
+	     ::ns::id
+             ~~~~~~^~
+	  or:
+	     id
+	     ^~
+	   i.e. from the start of the first token to the end of the final
+	   token, with the caret at the start of the unqualified-id.  */
+	location_t caret_loc = get_pure_location (id_expression.get_location ());
+	location_t start_loc = get_start (id_expr_token->location);
+	location_t finish_loc = get_finish (id_expression.get_location ());
+	location_t combined_loc
+	  = make_location (caret_loc, start_loc, finish_loc);
+
+	decl.set_location (combined_loc);
 	return decl;
       }
 
@@ -9547,7 +9560,8 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
 	}
       else
         {
-          current.lhs = build_x_binary_op (combined_loc, current.tree_type,
+	  op_location_t op_loc (current.loc, combined_loc);
+	  current.lhs = build_x_binary_op (op_loc, current.tree_type,
                                            current.lhs, current.lhs_type,
                                            rhs, rhs_type, &overload,
                                            complain_flags (decltype_p));
@@ -15382,8 +15396,16 @@ cp_parser_operator (cp_parser* parser, location_t start_loc)
 	    const char *name = IDENTIFIER_POINTER (id);
 	    id = cp_literal_operator_id (name);
 	  }
-	start_loc = make_location (start_loc, start_loc, get_finish (end_loc));
-	return cp_expr (id, start_loc);
+	/* Generate a location of the form:
+	     "" _suffix_identifier
+	     ^~~~~~~~~~~~~~~~~~~~~
+	   with caret == start at the start token, finish at the end of the
+	   suffix identifier.  */
+	location_t finish_loc
+	  = get_finish (cp_lexer_previous_token (parser->lexer)->location);
+	location_t combined_loc
+	  = make_location (start_loc, start_loc, finish_loc);
+	return cp_expr (id, combined_loc);
       }
 
     default:
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 820cfc5..a2f75c8 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -4114,7 +4114,7 @@ convert_arguments (tree typelist, vec<tree, va_gc> **values, tree fndecl,
    ARG2_CODE as ERROR_MARK.  */
 
 tree
-build_x_binary_op (location_t loc, enum tree_code code, tree arg1,
+build_x_binary_op (const op_location_t &loc, enum tree_code code, tree arg1,
 		   enum tree_code arg1_code, tree arg2,
 		   enum tree_code arg2_code, tree *overload_p,
 		   tsubst_flags_t complain)
@@ -4303,7 +4303,7 @@ warn_for_null_address (location_t location, tree op, tsubst_flags_t complain)
    multiple inheritance, and deal with pointer to member functions.  */
 
 tree
-cp_build_binary_op (location_t location,
+cp_build_binary_op (const op_location_t &location,
 		    enum tree_code code, tree orig_op0, tree orig_op1,
 		    tsubst_flags_t complain)
 {
@@ -5300,9 +5300,13 @@ cp_build_binary_op (location_t location,
   if (!result_type)
     {
       if (complain & tf_error)
-	error_at (location,
-		  "invalid operands of types %qT and %qT to binary %qO",
-		  TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
+	{
+	  binary_op_rich_location richloc (location,
+					   orig_op0, orig_op1, true);
+	  error_at (&richloc,
+		    "invalid operands of types %qT and %qT to binary %qO",
+		    TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
+	}
       return error_mark_node;
     }
 
diff --git a/gcc/gcc-rich-location.c b/gcc/gcc-rich-location.c
index 81beb61..25a604f 100644
--- a/gcc/gcc-rich-location.c
+++ b/gcc/gcc-rich-location.c
@@ -182,3 +182,92 @@ gcc_rich_location::add_fixit_insert_formatted (const char *content,
   else
     add_fixit_insert_before (insertion_point, content);
 }
+
+/* Implementation of range_label::get_text for
+   maybe_range_label_for_tree_type_mismatch.
+
+   If both expressions are non-NULL, then generate text describing
+   the first expression's type (using the other expression's type
+   for comparison, analogous to %H and %I in the C++ frontend, but
+   on expressions rather than types).  */
+
+label_text
+maybe_range_label_for_tree_type_mismatch::get_text (unsigned range_idx) const
+{
+  if (m_expr == NULL_TREE
+      || !EXPR_P (m_expr))
+    return label_text (NULL, false);
+  tree expr_type = TREE_TYPE (m_expr);
+
+  tree other_type = NULL_TREE;
+  if (m_other_expr && EXPR_P (m_other_expr))
+    other_type = TREE_TYPE (m_other_expr);
+
+  range_label_for_type_mismatch inner (expr_type, other_type);
+  return inner.get_text (range_idx);
+}
+
+/* binary_op_rich_location's ctor.
+
+   If use_operator_loc_p (LOC, ARG0, ARG1), then attempt to make a 3-location
+   rich_location of the form:
+
+     arg_0 op arg_1
+     ~~~~~ ^~ ~~~~~
+       |        |
+       |        arg1 type
+       arg0 type
+
+   labelling the types of the arguments if SHOW_TYPES is true.
+
+   Otherwise, make a 1-location rich_location using the compound
+   location within LOC:
+
+     arg_0 op arg_1
+     ~~~~~~^~~~~~~~
+
+   for which we can't label the types.  */
+
+binary_op_rich_location::binary_op_rich_location (const op_location_t &loc,
+						  tree arg0, tree arg1,
+						  bool show_types)
+: gcc_rich_location (loc.m_combined_loc),
+  m_label_for_arg0 (arg0, arg1),
+  m_label_for_arg1 (arg1, arg0)
+{
+  /* Default (above) to using the combined loc.
+     Potentially override it here: if we have location information for the
+     operator and for both arguments, then split them all out.
+     Alternatively, override it if we don't have the combined location.  */
+  if (use_operator_loc_p (loc, arg0, arg1))
+    {
+      set_range (0, loc.m_operator_loc, SHOW_RANGE_WITH_CARET);
+      maybe_add_expr (arg0, show_types ? &m_label_for_arg0 : NULL);
+      maybe_add_expr (arg1, show_types ? &m_label_for_arg1 : NULL);
+    }
+}
+
+/* Determine if binary_op_rich_location's ctor should attempt to make
+   a 3-location rich_location (the location of the operator and of
+   the 2 arguments), or fall back to a 1-location rich_location showing
+   just the combined location of the operation as a whole.  */
+
+bool
+binary_op_rich_location::use_operator_loc_p (const op_location_t &loc,
+					     tree arg0, tree arg1)
+{
+  /* If we don't have a combined location, then use the operator location,
+     and try to add ranges for the operators.  */
+  if (loc.m_combined_loc == UNKNOWN_LOCATION)
+    return true;
+
+  /* If we don't have the operator location, then use the
+     combined location.  */
+  if (loc.m_operator_loc == UNKNOWN_LOCATION)
+    return false;
+
+  /* We have both operator location and combined location: only use the
+     operator location if we have locations for both arguments.  */
+  return (EXPR_HAS_LOCATION (arg0)
+	  && EXPR_HAS_LOCATION (arg1));
+}
diff --git a/gcc/gcc-rich-location.h b/gcc/gcc-rich-location.h
index 200bbb5..202d4f4 100644
--- a/gcc/gcc-rich-location.h
+++ b/gcc/gcc-rich-location.h
@@ -162,4 +162,61 @@ class range_label_for_type_mismatch : public range_label
   tree m_other_type;
 };
 
+/* Subclass of range_label for labelling the type of EXPR when reporting
+   a type mismatch between EXPR and OTHER_EXPR.
+   Either or both of EXPR and OTHER_EXPR could be NULL.  */
+
+class maybe_range_label_for_tree_type_mismatch : public range_label
+{
+ public:
+  maybe_range_label_for_tree_type_mismatch (tree expr, tree other_expr)
+  : m_expr (expr), m_other_expr (other_expr)
+  {
+  }
+
+  label_text get_text (unsigned range_idx) const FINAL OVERRIDE;
+
+ private:
+  tree m_expr;
+  tree m_other_expr;
+};
+
+struct op_location_t;
+
+/* A subclass of rich_location for showing problems with binary operations.
+
+   If enough location information is available, the ctor will make a
+   3-location rich_location of the form:
+
+     arg_0 op arg_1
+     ~~~~~ ^~ ~~~~~
+       |        |
+       |        arg1 type
+       arg0 type
+
+   labelling the types of the arguments if SHOW_TYPES is true.
+
+   Otherwise, it will fall back to a 1-location rich_location using the
+   compound location within LOC:
+
+     arg_0 op arg_1
+     ~~~~~~^~~~~~~~
+
+   for which we can't label the types.  */
+
+class binary_op_rich_location : public gcc_rich_location
+{
+ public:
+  binary_op_rich_location (const op_location_t &loc,
+			   tree arg0, tree arg1,
+			   bool show_types);
+
+ private:
+  static bool use_operator_loc_p (const op_location_t &loc,
+				  tree arg0, tree arg1);
+
+  maybe_range_label_for_tree_type_mismatch m_label_for_arg0;
+  maybe_range_label_for_tree_type_mismatch m_label_for_arg1;
+};
+
 #endif /* GCC_RICH_LOCATION_H */
diff --git a/gcc/testsuite/c-c++-common/Wtautological-compare-ranges.c b/gcc/testsuite/c-c++-common/Wtautological-compare-ranges.c
new file mode 100644
index 0000000..2634d27
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wtautological-compare-ranges.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-Wtautological-compare -fdiagnostics-show-caret" } */
+
+#define FOO foo
+
+void
+fn1 (int foo)
+{
+  if (foo == foo); /* { dg-warning "self-comparison always evaluates to true" } */
+  /* { dg-begin-multiline-output "" }
+   if (foo == foo);
+           ^~
+     { dg-end-multiline-output "" { target c } } */
+  /* { dg-begin-multiline-output "" }
+   if (foo == foo);
+       ~~~ ^~ ~~~
+     { dg-end-multiline-output "" { target c++ } } */
+}
+
+void
+fn2 (int foo)
+{
+  if (FOO == FOO); /* { dg-warning "self-comparison always evaluates to true" } */
+  /* { dg-begin-multiline-output "" }
+   if (FOO == FOO);
+           ^~
+     { dg-end-multiline-output "" } */
+}
+
+void
+fn3 (int foo)
+{
+  if ((foo & 16) == 10); /* { dg-warning "bitwise comparison always evaluates to false" } */
+  /* { dg-begin-multiline-output "" }
+   if ((foo & 16) == 10);
+                  ^~
+     { dg-end-multiline-output "" { target c } } */
+  /* { dg-begin-multiline-output "" }
+   if ((foo & 16) == 10);
+       ~~~~~~~~~~ ^~ ~~
+     { dg-end-multiline-output "" { target c++ } } */
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr51420.C b/gcc/testsuite/g++.dg/cpp0x/pr51420.C
index fc70d46..1612cef 100644
--- a/gcc/testsuite/g++.dg/cpp0x/pr51420.C
+++ b/gcc/testsuite/g++.dg/cpp0x/pr51420.C
@@ -1,8 +1,18 @@
 // { dg-do compile { target c++11 } }
+// { dg-options "-fdiagnostics-show-caret" }
 
 void
 foo()
 {
   float x = operator"" _F();  //  { dg-error  "13:'operator\"\"_F' was not declared in this scope" }
+  /* { dg-begin-multiline-output "" }
+   float x = operator"" _F();
+             ^~~~~~~~~~~~~
+     { dg-end-multiline-output "" } */
+
   float y = 0_F;  //  { dg-error  "unable to find numeric literal operator" }
+  /* { dg-begin-multiline-output "" }
+   float y = 0_F;
+             ^~~
+     { dg-end-multiline-output "" } */
 }
diff --git a/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C b/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C
index 4ab7656..fab5849 100644
--- a/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C
+++ b/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C
@@ -11,7 +11,10 @@ void test_1 ()
 
 /* { dg-begin-multiline-output "" }
    myvec[1] / ptr;
-   ~~~~~~~~~^~~~~
+   ~~~~~~~~ ^ ~~~
+          |   |
+          |   const int*
+          __m128 {aka float}
    { dg-end-multiline-output "" } */
 }
 
@@ -28,8 +31,12 @@ int test_2 (void)
 /* { dg-begin-multiline-output "" }
    return (some_function ()
            ~~~~~~~~~~~~~~~~
+                         |
+                         s
     + some_other_function ());
-    ^~~~~~~~~~~~~~~~~~~~~~~~
+    ^ ~~~~~~~~~~~~~~~~~~~~~~
+                          |
+                          t
    { dg-end-multiline-output "" } */
 }
 
@@ -39,6 +46,52 @@ int test_3 (struct s param_s, struct t param_t)
 
 /* { dg-begin-multiline-output "" }
    return param_s && param_t;
+          ~~~~~~~ ^~ ~~~~~~~
+          |          |
+          s          t
+   { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
+   return param_s && param_t;
           ~~~~~~~~^~~~~~~~~~
    { dg-end-multiline-output "" } */
 }
+
+namespace ns_4
+{
+  struct s foo;
+  namespace inner {
+    struct t bar;
+  };
+};
+
+int test_4a (void)
+{
+  return ns_4::foo && ns_4::inner::bar; // { dg-error "no match for .operator" }
+  /* { dg-begin-multiline-output "" }
+   return ns_4::foo && ns_4::inner::bar;
+          ~~~~~~~~~ ^~ ~~~~~~~~~~~~~~~~
+                |                   |
+                s                   t
+     { dg-end-multiline-output "" } */
+
+  /* { dg-begin-multiline-output "" }
+   return ns_4::foo && ns_4::inner::bar;
+          ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+int test_4b (void)
+{
+  return ::ns_4::foo && ns_4::inner::bar; // { dg-error "no match for .operator" }
+  /* { dg-begin-multiline-output "" }
+   return ::ns_4::foo && ns_4::inner::bar;
+          ~~~~~~~~~~~ ^~ ~~~~~~~~~~~~~~~~
+                  |                   |
+                  s                   t
+     { dg-end-multiline-output "" } */
+
+  /* { dg-begin-multiline-output "" }
+   return ::ns_4::foo && ns_4::inner::bar;
+          ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
+     { dg-end-multiline-output "" } */
+}
diff --git a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
index b19655d..de7570a 100644
--- a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
+++ b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
@@ -204,7 +204,9 @@ int test_10 ()
   return v10_a - v10_b; // { dg-error "no match for" }
   /* { dg-begin-multiline-output "" }
    return v10_a - v10_b;
-          ~~~~~~^~~~~~~
+          ~~~~~ ^ ~~~~~
+          |       |
+          s10     s10
      { dg-end-multiline-output "" } */
   // { dg-message "candidate" "" { target *-*-* } s10_operator }
   /* { dg-begin-multiline-output "" }
diff --git a/gcc/tree.h b/gcc/tree.h
index bf685ed..5527ef1 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5959,4 +5959,53 @@ fndecl_built_in_p (const_tree node, built_in_function name)
 	  && DECL_FUNCTION_CODE (node) == name);
 }
 
+/* A struct for encapsulating location information about an operator
+   and the operation built from it.
+
+   m_operator_loc is the location of the operator
+   m_combined_loc is the location of the compound expression.
+
+   For example, given "a && b" the, operator location is:
+      a && b
+        ^~
+   and the combined location is:
+      a && b
+      ~~^~~~
+   Capturing this information allows for class binary_op_rich_location
+   to provide detailed information about e.g. type mismatches in binary
+   operations where enough location information is available:
+
+     arg_0 op arg_1
+     ~~~~~ ^~ ~~~~~
+       |        |
+       |        arg1 type
+       arg0 type
+
+   falling back to just showing the combined location:
+
+     arg_0 op arg_1
+     ~~~~~~^~~~~~~~
+
+   where it is not.  */
+
+struct op_location_t
+{
+  location_t m_operator_loc;
+  location_t m_combined_loc;
+
+  /* 1-argument ctor, for constructing from a combined location.  */
+  op_location_t (location_t combined_loc)
+  : m_operator_loc (UNKNOWN_LOCATION), m_combined_loc (combined_loc)
+  {}
+
+  /* 2-argument ctor, for distinguishing between the operator's location
+     and the combined location.  */
+  op_location_t (location_t operator_loc, location_t combined_loc)
+  : m_operator_loc (operator_loc), m_combined_loc (combined_loc)
+  {}
+
+  /* Implicitly convert back to a location_t, using the combined location.  */
+  operator location_t () const { return m_combined_loc; }
+};
+
 #endif  /* GCC_TREE_H  */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 1/2] v2: C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
  2018-12-03 22:10   ` Jeff Law
  2018-12-04 15:20     ` David Malcolm
@ 2018-12-04 21:48     ` David Malcolm
  2018-12-04 21:48       ` [PATCH 2/2] v2: C++: improvements to binary operator diagnostics (PR c++/87504) David Malcolm
  2018-12-04 23:31     ` [PING] Re: [PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486) Jason Merrill
  2 siblings, 1 reply; 34+ messages in thread
From: David Malcolm @ 2018-12-04 21:48 UTC (permalink / raw)
  To: jason; +Cc: Jeff Law, gcc-patches, David Malcolm

The v1 patch:
  https://gcc.gnu.org/ml/gcc-patches/2018-11/msg00304.html 
has bitrotten somewhat, so here's v2 of the patch, updated relative
to r266740.

Blurb from v1 patch follows:

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&chxr=1,58.26,61.79&chco=FF0000,0000FF&chdl=control|experiment&chds=58.26,61.79&chd=t:59.55,60.26,60.53,60.35,60.17,60.27,59.26,60.01,60.21,60.23,60.1,60.2,60.12,60.48,60.32,60.18,60.01,60.01,60.04,59.96,60.1,60.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=Compilation+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&chxr=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&chxr=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.72|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.78,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+kdecore.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): Fold 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_has_attribute_expression): Strip any location wrapper
	from "oper".
	(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.
	(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/cpp0x/constexpr-47969.C: Update column of expected error.
	* g++.dg/cpp0x/constexpr-ex2.C: Likewise.
	* g++.dg/cpp0x/scoped_enum2.C: Likewise.
	* g++.dg/cpp1z/decomp48.C: Update expected location of warning
	for named local variables to use that of the local variable.
	* g++.dg/ext/vla1.C: Update column.
	* 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/new44.C: Add "-ftrack-macro-expansion=0".
	* 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/other/fold1.C: Update column of expected error.
	* g++.dg/parse/crash36.C: Likewise.
	* g++.dg/wrappers/Wparentheses.C: New test.
	* g++.old-deja/g++.bugs/900402_02.C: Update column of expected
	error.
---
 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                                    |  55 +++++++--
 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/cpp0x/constexpr-47969.C       |   2 +-
 gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C         |   2 +-
 gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C          |   2 +-
 gcc/testsuite/g++.dg/cpp1z/decomp48.C              |   8 +-
 gcc/testsuite/g++.dg/ext/vla1.C                    |   2 +-
 gcc/testsuite/g++.dg/init/array43.C                |   2 +-
 .../g++.dg/init/initializer-string-too-long.C      |   9 ++
 gcc/testsuite/g++.dg/init/new44.C                  |   1 +
 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/other/fold1.C                 |   2 +-
 gcc/testsuite/g++.dg/parse/crash36.C               |   2 +-
 gcc/testsuite/g++.dg/wrappers/Wparentheses.C       |  10 ++
 gcc/testsuite/g++.old-deja/g++.bugs/900402_02.C    |   8 +-
 gcc/tree.c                                         |  10 ++
 gcc/tree.h                                         |  19 +++
 42 files changed, 669 insertions(+), 178 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 4c90365..2282515 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -1250,6 +1250,8 @@ unsafe_conversion_p (location_t loc, tree type, tree expr, tree result,
 
     loc = expansion_point_location_if_in_system_header (loc);
 
+  expr = fold_for_warn (expr);
+
   if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST)
     {
       /* If type is complex, we are interested in compatibility with
@@ -1947,6 +1949,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.
@@ -3241,6 +3250,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:
@@ -3460,6 +3470,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;
     }
@@ -6279,6 +6297,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)
@@ -6357,6 +6376,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
@@ -7906,6 +7927,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 798ad1b..fc7f87c 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.
@@ -1529,6 +1538,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.  */
@@ -1669,15 +1679,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 ee099cc..6dd8744 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5347,9 +5347,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)
@@ -6681,8 +6684,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))
     {
-      location_t 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,
@@ -6697,12 +6700,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 5726151..26bba732 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -7386,6 +7386,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 92fd2b2..2709595 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -5711,13 +5711,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 eb16873..892f2af 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
@@ -800,10 +808,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 7d2c599..90bd587 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6005,14 +6005,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);
@@ -6042,16 +6044,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",
@@ -6111,20 +6113,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;
@@ -6139,24 +6143,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);
 	    }
 	}
@@ -16579,6 +16583,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 ffc0d0d..7b84beb 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1048,6 +1048,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 5a31486..22824bd 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1756,7 +1756,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
@@ -2604,6 +2605,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
@@ -2667,11 +2669,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)
@@ -2762,6 +2766,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 318671b..fbdf887 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -657,6 +657,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 cadf380..857435c 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -4990,6 +4990,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 ab6d237..4acc79d 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -5232,7 +5232,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:
@@ -5254,9 +5255,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
@@ -7169,8 +7171,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
@@ -8484,6 +8488,8 @@ cp_parser_has_attribute_expression (cp_parser *parser)
   if (!oper || oper == error_mark_node)
     oper = cp_parser_unary_expression (parser);
 
+  STRIP_ANY_LOCATION_WRAPPER (oper);
+
   /* Go back to evaluating expressions.  */
   --cp_unevaluated_operand;
   --c_inhibit_evaluation_warnings;
@@ -9503,7 +9509,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,
@@ -14405,6 +14411,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,
@@ -14918,7 +14925,9 @@ cp_parser_mem_initializer (cp_parser* parser)
       vec = cp_parser_parenthesized_expression_list (parser, non_attr,
 						     /*cast_p=*/false,
 						     /*allow_expansion_p=*/true,
-						     /*non_constant_p=*/NULL);
+						     /*non_constant_p=*/NULL,
+						     /*close_paren_loc=*/NULL,
+						     /*wrap_locations_p=*/true);
       if (vec == NULL)
 	return error_mark_node;
       expression_list = build_tree_list_vec (vec);
@@ -15459,6 +15468,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
@@ -16628,6 +16642,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
@@ -22267,6 +22284,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
@@ -25615,6 +25635,10 @@ cp_parser_gnu_attribute_list (cp_parser* parser, bool exactly_one /* = false */)
   tree attribute_list = NULL_TREE;
   bool save_translate_strings_p = parser->translate_strings_p;
 
+  /* Don't create wrapper nodes within attributes: the
+     handlers don't know how to handle them.  */
+  auto_suppress_location_wrappers sentinel;
+
   parser->translate_strings_p = false;
   while (true)
     {
@@ -28501,6 +28525,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.  */
@@ -34832,6 +34864,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;
@@ -36549,6 +36584,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;
@@ -39119,6 +39158,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=*/NULL,
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index a0d899f..cfd95b6 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6196,6 +6196,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)
@@ -27214,7 +27215,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 733c42f..1ce0708 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1741,7 +1741,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;
 
@@ -1804,8 +1805,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 ());
 
@@ -2298,19 +2300,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)
     {
@@ -2350,7 +2355,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
@@ -2381,6 +2386,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)
@@ -3522,20 +3529,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);
 
@@ -3839,6 +3846,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 97074df..ede290f 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -377,6 +377,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:
@@ -421,6 +422,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;
@@ -2369,6 +2371,8 @@ lookup_maybe_add (tree fns, tree lookup, bool deduping)
 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)
@@ -2417,6 +2421,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)
@@ -5527,6 +5533,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 f45c06e..820cfc5 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)))
@@ -3409,11 +3419,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)))
@@ -3426,9 +3438,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;
@@ -4547,20 +4559,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");
+		}
 	    }
 	}
 
@@ -4582,15 +4597,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;
 	}
@@ -4624,10 +4642,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;
@@ -4828,13 +4847,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
@@ -6066,8 +6089,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)
@@ -8277,7 +8301,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)
 	{
@@ -8795,8 +8820,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
@@ -9170,6 +9197,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)
@@ -9271,6 +9300,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
@@ -9297,6 +9328,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))
@@ -9590,6 +9622,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 64e36ef..c1fa4a9 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -460,14 +460,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.  */
 
@@ -1052,6 +1057,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.  */
@@ -1065,7 +1072,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)));
 
@@ -1113,6 +1120,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)))
 	    {
@@ -1123,12 +1138,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;
 		}
 	    }
@@ -1137,7 +1153,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)
@@ -1162,23 +1178,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 "
@@ -1188,12 +1204,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 45de94c..62ccf7a 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 6d65d24..27be70d 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -81,6 +81,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 2d7cc3b55..3b2298b 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -216,6 +216,7 @@ class test_runner
 extern void attribute_c_tests ();
 extern void bitmap_c_tests ();
 extern void cgraph_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/cpp0x/constexpr-47969.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
index bfd9d8f..9ff2157 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
@@ -9,4 +9,4 @@ struct A
 constexpr A a = A();
 
 int ar[a]; // { dg-error "could not convert" }
-// { dg-error "5:size of array .ar. has non-integral" "" { target c++11 } .-1 }
+// { dg-error "8:size of array .ar. has non-integral" "" { target c++11 } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
index e726a34..f697300 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
@@ -19,4 +19,4 @@ constexpr A a = 42;
 X<a> x;	    // OK: unique conversion to int
 int ar[X<a>::i]; // also OK
 int ary[a]; // { dg-error "could not convert" } ambiguous conversion
-// { dg-error "5:size of array .ary. has non-integral" "" { target c++11 } .-1 }
+// { dg-error "9:size of array .ary. has non-integral" "" { target c++11 } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C b/gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
index 0313c01..c4a869a 100644
--- a/gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
@@ -5,7 +5,7 @@ enum E2 { e2 = 10 };
 
 struct C {
   int arr[E::e];    // { dg-error "could not convert" }
-// { dg-error "7:size of array .arr. has non-integral" "" { target c++11 } .-1 }
+// { dg-error "14:size of array .arr. has non-integral" "" { target c++11 } .-1 }
   int arr2[E2::e2]; // OK
   int i: E::e;	    // { dg-error "could not convert|non-integral type" }
   int i2: E2::e2;   // OK
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/ext/vla1.C b/gcc/testsuite/g++.dg/ext/vla1.C
index d6df686..c017b6e 100644
--- a/gcc/testsuite/g++.dg/ext/vla1.C
+++ b/gcc/testsuite/g++.dg/ext/vla1.C
@@ -19,7 +19,7 @@ class B { B (int); };
 B::B (int i)
 {
   struct S {
-    int ar[1][i];  // { dg-error "9:size of array .ar. is not an integral" "" { target c++11 } }
+    int ar[1][i];  // { dg-error "15:size of array .ar. is not an integral" "" { target c++11 } }
 // { dg-error "array bound" "" { target c++98_only } .-1 }
   } s;
 
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/new44.C b/gcc/testsuite/g++.dg/init/new44.C
index 4ab7320..5c81c2c 100644
--- a/gcc/testsuite/g++.dg/init/new44.C
+++ b/gcc/testsuite/g++.dg/init/new44.C
@@ -1,4 +1,5 @@
 // { dg-do compile }
+// { dg-options "-ftrack-macro-expansion=0" }
 
 // Test for PR c++/67927 - array new expression with excessive number
 // of elements not diagnosed.
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/other/fold1.C b/gcc/testsuite/g++.dg/other/fold1.C
index 25f9acc..8d8df3d 100644
--- a/gcc/testsuite/g++.dg/other/fold1.C
+++ b/gcc/testsuite/g++.dg/other/fold1.C
@@ -4,5 +4,5 @@
 struct A
 {
     static const int i = i;  // { dg-error "not declared" }
-    int x[i];		     // { dg-error "9:size of array .x. is not an integral constant-expression" }
+    int x[i];		     // { dg-error "11:size of array .x. is not an integral constant-expression" }
 };
diff --git a/gcc/testsuite/g++.dg/parse/crash36.C b/gcc/testsuite/g++.dg/parse/crash36.C
index 14fcdd8..8a2b6f3 100644
--- a/gcc/testsuite/g++.dg/parse/crash36.C
+++ b/gcc/testsuite/g++.dg/parse/crash36.C
@@ -9,4 +9,4 @@ template <typename... T> struct A	// { dg-warning "variadic templates" }
   static const int i = sizeof (++t);	// { dg-error "was not declared in this scope" }
 };
 
-int x[A <int>::i];		// { dg-error "5:size of array .x. is not an integral constant-expression" }
+int x[A <int>::i];		// { dg-error "16:size of array .x. is not an integral constant-expression" }
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/testsuite/g++.old-deja/g++.bugs/900402_02.C b/gcc/testsuite/g++.old-deja/g++.bugs/900402_02.C
index 46a3ec3..21e2765 100644
--- a/gcc/testsuite/g++.old-deja/g++.bugs/900402_02.C
+++ b/gcc/testsuite/g++.old-deja/g++.bugs/900402_02.C
@@ -6,17 +6,17 @@
 
 // keywords: arrays, array bound, zero length
 
-typedef int array_type[0];		// { dg-error "13:ISO C\\+\\+ forbids zero-size array" }
+typedef int array_type[0];		// { dg-error "24:ISO C\\+\\+ forbids zero-size array" }
 
-int array_object_1[0];			// { dg-error "5:ISO C\\+\\+ forbids zero-size array" }
+int array_object_1[0];			// { dg-error "20:ISO C\\+\\+ forbids zero-size array" }
 
-void function_0 (int formal_array[0])	// { dg-error "22:ISO C\\+\\+ forbids zero-size array" }
+void function_0 (int formal_array[0])	// { dg-error "35:ISO C\\+\\+ forbids zero-size array" }
 {
 }
 
 void function_2 ()
 {
-  int local_object_array_0[0];		// { dg-error "7:ISO C\\+\\+ forbids zero-size array" }
+  int local_object_array_0[0];		// { dg-error "28:ISO C\\+\\+ forbids zero-size array" }
 }
 
 int main () { return 0; }
diff --git a/gcc/tree.c b/gcc/tree.c
index 170ef13..01b9ec3 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -7106,6 +7106,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))
@@ -14646,6 +14649,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)))
@@ -14656,6 +14664,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 960526d..bf685ed 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)
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PING] Re: [PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
  2018-12-03 22:10   ` Jeff Law
  2018-12-04 15:20     ` David Malcolm
  2018-12-04 21:48     ` [PATCH 1/2] v2: " David Malcolm
@ 2018-12-04 23:31     ` Jason Merrill
  2018-12-07 19:25       ` [PATCH 1/2] v3: " David Malcolm
  2 siblings, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2018-12-04 23:31 UTC (permalink / raw)
  To: Jeff Law, David Malcolm, gcc-patches

On 12/3/18 5:10 PM, Jeff Law wrote:
> On 11/19/18 9:51 AM, David Malcolm wrote:
>> 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
>>
> 
>>>
>>> [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.
> Well, you probably know my biggest worry with this -- the unwrappign
> wack-a-mole problem.  It looks like additional memory usage is
> measurable, but tiny.
> 
> Have you received any feedback from Jason on the C++ side?  That's the
> bulk of this patch AFAICT.
> 
> I don't see anything objectionable in the c-family/ or generic bits.
> But again I worry more about the need to sprinkle unwrapping all over
> the place.

If we're adding wrappers, any place that wants to look at particular 
tree codes will need to deal with unwrapping.  The question then is 
whether to just remove location wrappers or do fold_for_warn, which will 
remove location wrappers and also try to provide a constant value.  In 
general, the former is better for things that deal with the forms of the 
code, and the latter for things that deal with values.

>> @@ -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)

Why do the former here, when this function is interested in constants?

>  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%>");

Here you strip a location wrapper and then check whether the expression 
has a location, which will give suboptimal results if the expression is 
a variable.

> @@ -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;

I think recursion is probably right for some non-location-wrapper uses 
of VIEW_CONVERT_EXPR, as well, but for now let's just add a comment to 
that effect.

> +	    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");

This might be another place where folding is the right answer.

>  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));

Maybe use preserve_any_location_wrapper here?

> @@ -1058,6 +1058,9 @@ grokbitfield (const cp_declarator *declarator,
>        return NULL_TREE;
>      }
>  
> +  if (width)
> +    STRIP_ANY_LOCATION_WRAPPER (width);

Why is this needed?  We should already be reducing width to an unwrapped 
constant value somewhere along the line.

> @@ -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);

Why is this needed?  What cares about the tree codes of the capture 
initializer?

> @@ -14122,6 +14126,7 @@ cp_parser_decltype_expr (cp_parser *parser,
> +	  auto_suppress_location_wrappers sentinel;

Why do we want to suppress them in decltype?

> @@ -21832,6 +21847,9 @@ cp_parser_parameter_declaration (cp_parser *parser,
> +  if (default_argument)
> +    STRIP_ANY_LOCATION_WRAPPER (default_argument);
...
> +      /* 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);

Hmm, I imagine this is already an issue with default arguments that are 
location-carrying expressions.

It would be nice to avoid this unification, which I suppose would mean 
needing to distinguish better between identical and equivalent in 
various places.

But for now I guess this is fine.

> +  /* Don't create location wrapper nodes within a template-argument-list.  */
> +  auto_suppress_location_wrappers sentinel;

You probably also want to remove location wrappers in strip_typedefs_expr.

> @@ -6257,6 +6257,7 @@ convert_nontype_argument_function (tree type, tree expr,
> +  STRIP_ANY_LOCATION_WRAPPER (fn_no_ptr);

Is this necessary with the above suppression?

> +	      /* Don't create wrapper nodes within an attribute: the
> +		 handlers don't know how to handle them.  */
> +	      auto_suppress_location_wrappers sentinel;

Do we still need to strip them in handle_namespace_attrs, then?

> @@ -1682,6 +1682,8 @@ cxx_sizeof_expr (tree e, tsubst_flags_t complain)
> +  STRIP_ANY_LOCATION_WRAPPER (e);
> @@ -1754,6 +1756,8 @@ cxx_alignof_expr (tree e, tsubst_flags_t complain)
> +  STRIP_ANY_LOCATION_WRAPPER (e);

We should probably grab the location first, and use it in the later 
diagnostics.

> @@ -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);

Perhaps this should be maybe_constant_value, to avoid marking the array 
as addressable in more cases.

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 1/2] v3: C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
  2018-12-04 23:31     ` [PING] Re: [PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486) Jason Merrill
@ 2018-12-07 19:25       ` David Malcolm
  2018-12-12 20:37         ` Jason Merrill
  0 siblings, 1 reply; 34+ messages in thread
From: David Malcolm @ 2018-12-07 19:25 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jeff Law, gcc-patches, David Malcolm

On Tue, 2018-12-04 at 18:31 -0500, Jason Merrill wrote:
> On 12/3/18 5:10 PM, Jeff Law wrote:
> > On 11/19/18 9:51 AM, David Malcolm wrote:
[...]
> > Well, you probably know my biggest worry with this -- the
> > unwrappign
> > wack-a-mole problem.  It looks like additional memory usage is
> > measurable, but tiny.
> > 
> > Have you received any feedback from Jason on the C++ side?  That's
> > the
> > bulk of this patch AFAICT.
> > 
> > I don't see anything objectionable in the c-family/ or generic
> > bits.
> > But again I worry more about the need to sprinkle unwrapping all
> > over
> > the place.
> 
> If we're adding wrappers, any place that wants to look at particular 
> tree codes will need to deal with unwrapping.  The question then is 
> whether to just remove location wrappers or do fold_for_warn, which
> will 
> remove location wrappers and also try to provide a constant
> value.  In 
> general, the former is better for things that deal with the forms of
> the 
> code, and the latter for things that deal with values.

Thanks.

> > > @@ -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)
> 
> Why do the former here, when this function is interested in
> constants?

I've changed it to use fold_for_warn (in the v2 patch).

> >  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%>");
> 
> Here you strip a location wrapper and then check whether the
> expression 
> has a location, which will give suboptimal results if the expression
> is 
> a variable.

I've updated it in the v3 patch to extract any location from INDEX
first.

> > @@ -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;
> 
> I think recursion is probably right for some non-location-wrapper
> uses 
> of VIEW_CONVERT_EXPR, as well, but for now let's just add a comment
> to 
> that effect.

Do you mean something like:

    case VIEW_CONVERT_EXPR:
      if (location_wrapper_p (instance))
	return RECUR (TREE_OPERAND (instance, 0));
      else
	/* TODO: Recursion may be correct for some non-location-wrapper
	   uses of VIEW_CONVERT_EXPR.  */
	return NULL_TREE;

(I've done that in the v3 patch)

> > +	    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");
> 
> This might be another place where folding is the right answer.

I tried updating this to use fold_for_warn, but it caused this change:

 PASS -> FAIL : g++.dg/cpp0x/constexpr-nullptr-2.C  -std=c++14  (test for errors, line 197)
 PASS -> FAIL : g++.dg/cpp0x/constexpr-nullptr-2.C  -std=c++14  (test for errors, line 198)
 PASS -> FAIL : g++.dg/cpp0x/constexpr-nullptr-2.C  -std=c++14 (test for excess errors)
 PASS -> FAIL : g++.dg/cpp0x/constexpr-nullptr-2.C  -std=c++17  (test for errors, line 197)
 PASS -> FAIL : g++.dg/cpp0x/constexpr-nullptr-2.C  -std=c++17  (test for errors, line 198)
 PASS -> FAIL : g++.dg/cpp0x/constexpr-nullptr-2.C  -std=c++17 (test for excess errors)

With trunk, and with stripping, we get:
constexpr-nullptr-2.C:197:32: error: dereferencing a null pointer in '*0'
  197 | constexpr int* pj0 = &((S*)0)->j; // { dg-error "null pointer|not a constant" }
      |                                ^
constexpr-nullptr-2.C:198:38: error: dereferencing a null pointer in '*0'
  198 | constexpr int* pj1 = &((S*)nullptr)->j; // { dg-error "null pointer|not a constant" }
      |                                      ^

With fold_for_warn we get:
constexpr-nullptr-2.C:197:22: error: reinterpret_cast from integer to pointer
  197 | constexpr int* pj0 = &((S*)0)->j; // { dg-error "null pointer|not a constant" }
      |                      ^~~~~~~~~~~
constexpr-nullptr-2.C:198:22: error: reinterpret_cast from integer to pointer
  198 | constexpr int* pj1 = &((S*)nullptr)->j; // { dg-error "null pointer|not a constant" }
      |                      ^~~~~~~~~~~~~~~~~

The null pointer dereference error is more specific, and thus seems preferable to me.

With folding we also get this extra error:
array-size2.C: In function 'void foo()':
array-size2.C:17:40: warning: narrowing conversion of '((((char*)(&0->S::b))
  - 0) <unknown operator> 1)' from 'long int' to 'long unsigned int' [-Wnarrowing]
   17 |   char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error "40:size of array .g. is not an integral constant-expression" }
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~
array-size2.C:17:40: note:  the expression has a constant value but is not a C++ constant-expression

Given the above, and that this is already within a recursive walk of the
tree, I've kept this as stripping for the v3 patch.

> >  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));
> 
> Maybe use preserve_any_location_wrapper here?

Done.

> > @@ -1058,6 +1058,9 @@ grokbitfield (const cp_declarator
> > *declarator,
> >        return NULL_TREE;
> >      }
> >  
> > +  if (width)
> > +    STRIP_ANY_LOCATION_WRAPPER (width);
> 
> Why is this needed?  We should already be reducing width to an
> unwrapped 
> constant value somewhere along the line.

"width" is coming from cp_parser_member_declaration, from:

	      /* Get the width of the bitfield.  */
	      width = cp_parser_constant_expression (parser, false, NULL,
						     cxx_dialect >= cxx11);

and currently nothing is unwrapping the value.  We presumably need to
unwrap (or fold?) it before it is stashed in
  DECL_BIT_FIELD_REPRESENTATIVE (value).

Without stripping (or folding) here, we e.g. lose a warning and get this:
  FAIL: g++.dg/abi/empty22.C  -std=gnu++98  (test for warnings, line 15)

Maybe this should be a fold_for_warn?

> > @@ -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);
> 
> Why is this needed?  What cares about the tree codes of the capture 
> initializer?

This is used to populate LAMBDA_EXPR_CAPTURE_LIST.  Without stripping,
we end up with wrapped VAR_DECLs, rather than the VAR_DECLs themselves,
and this confuses things later on, for example leading to:

 PASS -> FAIL : g++.dg/cpp0x/lambda/lambda-type.C  -std=c++14 (test for excess errors)
 PASS -> FAIL : g++.dg/cpp0x/lambda/lambda-type.C  -std=c++17 (test for excess errors)

> > @@ -14122,6 +14126,7 @@ cp_parser_decltype_expr (cp_parser *parser,
> > +	  auto_suppress_location_wrappers sentinel;
> 
> Why do we want to suppress them in decltype?

This was an overzealous way for me to fix a failing test
(g++.dg/abi/mangle49.C).

finish_decltype_type uses the tree returned by cp_parser_decltype_expr,
and e.g. uses VAR_P on it, so we need to strip somewhere.

In v3 of the patch I've instead added a strip of the tree returned
by cp_parser_decltype_expr within cp_parser_decltype.


> > @@ -21832,6 +21847,9 @@ cp_parser_parameter_declaration (cp_parser
> > *parser,
> > +  if (default_argument)
> > +    STRIP_ANY_LOCATION_WRAPPER (default_argument);
> 
> ...
> > +      /* 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);
> 
> Hmm, I imagine this is already an issue with default arguments that
> are 
> location-carrying expressions.
> 
> It would be nice to avoid this unification, which I suppose would
> mean 
> needing to distinguish better between identical and equivalent in 
> various places.
> 
> But for now I guess this is fine.

Thanks.

> > +  /* Don't create location wrapper nodes within a template-
> > argument-list.  */
> > +  auto_suppress_location_wrappers sentinel;
> 
> You probably also want to remove location wrappers in
> strip_typedefs_expr.

Added in v3.

> > @@ -6257,6 +6257,7 @@ convert_nontype_argument_function (tree type,
> > tree expr,
> > +  STRIP_ANY_LOCATION_WRAPPER (fn_no_ptr);
> 
> Is this necessary with the above suppression?
> 
> > +	      /* Don't create wrapper nodes within an attribute:
> > the
> > +		 handlers don't know how to handle them.  */
> > +	      auto_suppress_location_wrappers sentinel;
> 
> Do we still need to strip them in handle_namespace_attrs, then?

I put that strip in handle_namespace_attrs to fix:
 PASS -> FAIL : g++.dg/cpp0x/gen-attrs-56.C  -std=c++14 (test for excess errors)
 PASS -> FAIL : g++.dg/cpp0x/gen-attrs-56.C  -std=c++17 (test for excess errors)
but that seems to me now to be papering things over; it looks like
the better fix is to put in an auto_suppress_location_wrappers
into:
  cp_parser_std_attribute_spec_seq
to suppress wrappers for C++11-style attributes.

I've done the latter in the v3 patch.

(I hope to properly handle attribute locations in GCC 10, for both
GNU-style and C++11-style attributes).

> > @@ -1682,6 +1682,8 @@ cxx_sizeof_expr (tree e, tsubst_flags_t
> > complain)
> > +  STRIP_ANY_LOCATION_WRAPPER (e);
> > @@ -1754,6 +1756,8 @@ cxx_alignof_expr (tree e, tsubst_flags_t
> > complain)
> > +  STRIP_ANY_LOCATION_WRAPPER (e);
> 
> We should probably grab the location first, and use it in the later 
> diagnostics.
> 
> > @@ -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);
> 
> Perhaps this should be maybe_constant_value, to avoid marking the
> array 
> as addressable in more cases.

Done

> Jason

Thanks for the review.

Here's the v3 of patch 1 of the kit.

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu, in
conjunction with the followup patch:
  [PATCH 2/2] v2: C++: improvements to binary operator diagnostics (PR c++/87504)
    https://gcc.gnu.org/ml/gcc-patches/2018-12/msg00236.html
(as noted in an earlier version of the 1/2 patch, 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).

OK for trunk, assuming that latter patch is also OK?

Thanks
Dave

gcc/c-family/ChangeLog:
	PR c++/43064
	PR c++/43486
	* c-common.c (unsafe_conversion_p): Fold 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/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.
	* convert.h (preserve_any_location_wrapper): New decl.
	* 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/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.
	* 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_has_attribute_expression): Strip any location wrapper
	from "oper".
	(cp_parser_binary_expression): Strip any location wrapper when
	checking for DECL_P on the lhs.
	(cp_parser_decltype): Strip any location wrapper from result of
	cp_parser_decltype_expr.
	(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.
	(cp_parser_std_attribute_spec_seq): Likewise.
	(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.
	(strip_typedefs_expr): Strip any location wrapper before checking
	for decls or constants.
	(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): Call maybe_constant_value on "idx".
	(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/cpp0x/constexpr-47969.C: Update column of expected error.
	* g++.dg/cpp0x/constexpr-ex2.C: Likewise.
	* g++.dg/cpp0x/scoped_enum2.C: Likewise.
	* g++.dg/cpp1z/decomp48.C: Update expected location of warning
	for named local variables to use that of the local variable.
	* g++.dg/ext/vla1.C: Update column.
	* 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/new44.C: Add "-ftrack-macro-expansion=0".
	* 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/other/fold1.C: Update column of expected error.
	* g++.dg/parse/crash36.C: Likewise.
	* g++.dg/wrappers/Wparentheses.C: New test.
	* g++.old-deja/g++.bugs/900402_02.C: Update column of expected
	error.
---
 gcc/c-family/c-common.c                            |  22 ++++
 gcc/c-family/c-pretty-print.c                      |  11 +-
 gcc/c-family/c-warn.c                              |  71 ++++++-----
 gcc/convert.c                                      | 132 +++++++++++++++++++--
 gcc/convert.h                                      |   2 +
 gcc/cp/call.c                                      |  19 +--
 gcc/cp/class.c                                     |   8 ++
 gcc/cp/constexpr.c                                 |  17 ++-
 gcc/cp/cvt.c                                       |  22 ++--
 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/parser.c                                    |  59 +++++++--
 gcc/cp/pt.c                                        |   4 +-
 gcc/cp/semantics.c                                 |  77 ++++++++----
 gcc/cp/tree.c                                      |  16 +++
 gcc/cp/typeck.c                                    | 104 ++++++++++------
 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/cpp0x/constexpr-47969.C       |   2 +-
 gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C         |   2 +-
 gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C          |   2 +-
 gcc/testsuite/g++.dg/cpp1z/decomp48.C              |   8 +-
 gcc/testsuite/g++.dg/ext/vla1.C                    |   2 +-
 gcc/testsuite/g++.dg/init/array43.C                |   2 +-
 .../g++.dg/init/initializer-string-too-long.C      |   9 ++
 gcc/testsuite/g++.dg/init/new44.C                  |   1 +
 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/other/fold1.C                 |   2 +-
 gcc/testsuite/g++.dg/parse/crash36.C               |   2 +-
 gcc/testsuite/g++.dg/wrappers/Wparentheses.C       |  10 ++
 gcc/testsuite/g++.old-deja/g++.bugs/900402_02.C    |   8 +-
 gcc/tree.c                                         |  10 ++
 gcc/tree.h                                         |  19 +++
 42 files changed, 672 insertions(+), 175 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 4c90365..2282515 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -1250,6 +1250,8 @@ unsafe_conversion_p (location_t loc, tree type, tree expr, tree result,
 
     loc = expansion_point_location_if_in_system_header (loc);
 
+  expr = fold_for_warn (expr);
+
   if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST)
     {
       /* If type is complex, we are interested in compatibility with
@@ -1947,6 +1949,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.
@@ -3241,6 +3250,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:
@@ -3460,6 +3470,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;
     }
@@ -6279,6 +6297,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)
@@ -6357,6 +6376,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
@@ -7906,6 +7927,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 798ad1b..4c0bdf9 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.
@@ -1529,6 +1538,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.  */
@@ -1669,15 +1679,22 @@ 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)
+    {
+      /* If INDEX has a location, use it; otherwise use LOC (the location
+	 of the subscripting expression as a whole).  */
+      loc = EXPR_LOC_OR_LOC (index, loc);
+      STRIP_ANY_LOCATION_WRAPPER (index);
+      if (TREE_CODE (index) != INTEGER_CST)
+	warning_at (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..1345d2a 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.  */
+
+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/convert.h b/gcc/convert.h
index 4ffa6ef..f3334f9 100644
--- a/gcc/convert.h
+++ b/gcc/convert.h
@@ -40,4 +40,6 @@ extern inline tree convert_to_real_nofold (tree t, tree x)
 extern inline tree convert_to_complex_nofold (tree t, tree x)
 { return convert_to_complex_maybe_fold (t, x, false); }
 
+extern tree preserve_any_location_wrapper (tree result, tree orig_expr);
+
 #endif /* GCC_CONVERT_H */
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index ee099cc..6dd8744 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5347,9 +5347,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)
@@ -6681,8 +6684,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))
     {
-      location_t 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,
@@ -6697,12 +6700,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 5726151..6a32ec3 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -7386,6 +7386,14 @@ 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
+	/* TODO: Recursion may be correct for some non-location-wrapper
+	   uses of VIEW_CONVERT_EXPR.  */
+	return NULL_TREE;
+
     default:
       return NULL_TREE;
     }
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 92fd2b2..2709595 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -5711,13 +5711,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 eb16873..f758f2d 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -582,15 +582,20 @@ 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;
+
+  return preserve_any_location_wrapper (stripped_expr, expr);
 }
 
 /* Fold away simple conversions, but make sure TREE_OVERFLOW is set
@@ -800,10 +805,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 7d2c599..90bd587 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6005,14 +6005,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);
@@ -6042,16 +6044,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",
@@ -6111,20 +6113,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;
@@ -6139,24 +6143,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);
 	    }
 	}
@@ -16579,6 +16583,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 ffc0d0d..7b84beb 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1048,6 +1048,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 5a31486..22824bd 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1756,7 +1756,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
@@ -2604,6 +2605,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
@@ -2667,11 +2669,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)
@@ -2762,6 +2766,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 318671b..fbdf887 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -657,6 +657,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/parser.c b/gcc/cp/parser.c
index ab6d237..2b79c04 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -5232,7 +5232,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:
@@ -5254,9 +5255,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
@@ -7169,8 +7171,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
@@ -8484,6 +8488,8 @@ cp_parser_has_attribute_expression (cp_parser *parser)
   if (!oper || oper == error_mark_node)
     oper = cp_parser_unary_expression (parser);
 
+  STRIP_ANY_LOCATION_WRAPPER (oper);
+
   /* Go back to evaluating expressions.  */
   --cp_unevaluated_operand;
   --c_inhibit_evaluation_warnings;
@@ -9503,7 +9509,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,
@@ -14541,6 +14547,7 @@ cp_parser_decltype (cp_parser *parser)
       ++c_inhibit_evaluation_warnings;
 
       expr = cp_parser_decltype_expr (parser, id_expression_or_member_access_p);
+      STRIP_ANY_LOCATION_WRAPPER (expr);
 
       /* Go back to evaluating expressions.  */
       --cp_unevaluated_operand;
@@ -14918,7 +14925,9 @@ cp_parser_mem_initializer (cp_parser* parser)
       vec = cp_parser_parenthesized_expression_list (parser, non_attr,
 						     /*cast_p=*/false,
 						     /*allow_expansion_p=*/true,
-						     /*non_constant_p=*/NULL);
+						     /*non_constant_p=*/NULL,
+						     /*close_paren_loc=*/NULL,
+						     /*wrap_locations_p=*/true);
       if (vec == NULL)
 	return error_mark_node;
       expression_list = build_tree_list_vec (vec);
@@ -15459,6 +15468,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
@@ -16628,6 +16642,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
@@ -22267,6 +22284,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
@@ -25615,6 +25635,10 @@ cp_parser_gnu_attribute_list (cp_parser* parser, bool exactly_one /* = false */)
   tree attribute_list = NULL_TREE;
   bool save_translate_strings_p = parser->translate_strings_p;
 
+  /* Don't create wrapper nodes within attributes: the
+     handlers don't know how to handle them.  */
+  auto_suppress_location_wrappers sentinel;
+
   parser->translate_strings_p = false;
   while (true)
     {
@@ -26060,6 +26084,10 @@ cp_parser_std_attribute_spec_seq (cp_parser *parser)
   tree attr_specs = NULL_TREE;
   tree attr_last = NULL_TREE;
 
+  /* Don't create wrapper nodes within attributes: the
+     handlers don't know how to handle them.  */
+  auto_suppress_location_wrappers sentinel;
+
   while (true)
     {
       tree attr_spec = cp_parser_std_attribute_spec (parser);
@@ -28501,6 +28529,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.  */
@@ -34832,6 +34868,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;
@@ -36549,6 +36588,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;
@@ -39119,6 +39162,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=*/NULL,
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index a0d899f..cfd95b6 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6196,6 +6196,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)
@@ -27214,7 +27215,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 733c42f..1ce0708 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1741,7 +1741,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;
 
@@ -1804,8 +1805,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 ());
 
@@ -2298,19 +2300,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)
     {
@@ -2350,7 +2355,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
@@ -2381,6 +2386,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)
@@ -3522,20 +3529,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);
 
@@ -3839,6 +3846,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 97074df..aac3ece 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -377,6 +377,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:
@@ -421,6 +422,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;
@@ -1715,6 +1717,8 @@ strip_typedefs_expr (tree t, bool *remove_attributes)
   if (t == NULL_TREE || t == error_mark_node)
     return t;
 
+  STRIP_ANY_LOCATION_WRAPPER (t);
+
   if (DECL_P (t) || CONSTANT_CLASS_P (t))
     return t;
 
@@ -2369,6 +2373,8 @@ lookup_maybe_add (tree fns, tree lookup, bool deduping)
 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)
@@ -2417,6 +2423,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)
@@ -5527,6 +5535,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 f45c06e..fa79f42 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)))
@@ -3409,6 +3419,8 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
 	 pointer arithmetic.)  */
       idx = cp_perform_integral_promotions (idx, complain);
 
+      idx = maybe_constant_value (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.
@@ -4547,20 +4559,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");
+		}
 	    }
 	}
 
@@ -4582,15 +4597,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;
 	}
@@ -4624,10 +4642,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;
@@ -4828,13 +4847,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
@@ -6066,8 +6089,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)
@@ -8277,7 +8301,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)
 	{
@@ -8795,8 +8820,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
@@ -9170,6 +9197,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)
@@ -9271,6 +9300,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
@@ -9297,6 +9328,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))
@@ -9590,6 +9622,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 64e36ef..c1fa4a9 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -460,14 +460,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.  */
 
@@ -1052,6 +1057,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.  */
@@ -1065,7 +1072,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)));
 
@@ -1113,6 +1120,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)))
 	    {
@@ -1123,12 +1138,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;
 		}
 	    }
@@ -1137,7 +1153,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)
@@ -1162,23 +1178,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 "
@@ -1188,12 +1204,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 45de94c..62ccf7a 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 6d65d24..27be70d 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -81,6 +81,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 2d7cc3b55..3b2298b 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -216,6 +216,7 @@ class test_runner
 extern void attribute_c_tests ();
 extern void bitmap_c_tests ();
 extern void cgraph_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/cpp0x/constexpr-47969.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
index bfd9d8f..9ff2157 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
@@ -9,4 +9,4 @@ struct A
 constexpr A a = A();
 
 int ar[a]; // { dg-error "could not convert" }
-// { dg-error "5:size of array .ar. has non-integral" "" { target c++11 } .-1 }
+// { dg-error "8:size of array .ar. has non-integral" "" { target c++11 } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
index e726a34..f697300 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
@@ -19,4 +19,4 @@ constexpr A a = 42;
 X<a> x;	    // OK: unique conversion to int
 int ar[X<a>::i]; // also OK
 int ary[a]; // { dg-error "could not convert" } ambiguous conversion
-// { dg-error "5:size of array .ary. has non-integral" "" { target c++11 } .-1 }
+// { dg-error "9:size of array .ary. has non-integral" "" { target c++11 } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C b/gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
index 0313c01..c4a869a 100644
--- a/gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
@@ -5,7 +5,7 @@ enum E2 { e2 = 10 };
 
 struct C {
   int arr[E::e];    // { dg-error "could not convert" }
-// { dg-error "7:size of array .arr. has non-integral" "" { target c++11 } .-1 }
+// { dg-error "14:size of array .arr. has non-integral" "" { target c++11 } .-1 }
   int arr2[E2::e2]; // OK
   int i: E::e;	    // { dg-error "could not convert|non-integral type" }
   int i2: E2::e2;   // OK
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/ext/vla1.C b/gcc/testsuite/g++.dg/ext/vla1.C
index d6df686..c017b6e 100644
--- a/gcc/testsuite/g++.dg/ext/vla1.C
+++ b/gcc/testsuite/g++.dg/ext/vla1.C
@@ -19,7 +19,7 @@ class B { B (int); };
 B::B (int i)
 {
   struct S {
-    int ar[1][i];  // { dg-error "9:size of array .ar. is not an integral" "" { target c++11 } }
+    int ar[1][i];  // { dg-error "15:size of array .ar. is not an integral" "" { target c++11 } }
 // { dg-error "array bound" "" { target c++98_only } .-1 }
   } s;
 
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/new44.C b/gcc/testsuite/g++.dg/init/new44.C
index 4ab7320..5c81c2c 100644
--- a/gcc/testsuite/g++.dg/init/new44.C
+++ b/gcc/testsuite/g++.dg/init/new44.C
@@ -1,4 +1,5 @@
 // { dg-do compile }
+// { dg-options "-ftrack-macro-expansion=0" }
 
 // Test for PR c++/67927 - array new expression with excessive number
 // of elements not diagnosed.
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/other/fold1.C b/gcc/testsuite/g++.dg/other/fold1.C
index 25f9acc..8d8df3d 100644
--- a/gcc/testsuite/g++.dg/other/fold1.C
+++ b/gcc/testsuite/g++.dg/other/fold1.C
@@ -4,5 +4,5 @@
 struct A
 {
     static const int i = i;  // { dg-error "not declared" }
-    int x[i];		     // { dg-error "9:size of array .x. is not an integral constant-expression" }
+    int x[i];		     // { dg-error "11:size of array .x. is not an integral constant-expression" }
 };
diff --git a/gcc/testsuite/g++.dg/parse/crash36.C b/gcc/testsuite/g++.dg/parse/crash36.C
index 14fcdd8..8a2b6f3 100644
--- a/gcc/testsuite/g++.dg/parse/crash36.C
+++ b/gcc/testsuite/g++.dg/parse/crash36.C
@@ -9,4 +9,4 @@ template <typename... T> struct A	// { dg-warning "variadic templates" }
   static const int i = sizeof (++t);	// { dg-error "was not declared in this scope" }
 };
 
-int x[A <int>::i];		// { dg-error "5:size of array .x. is not an integral constant-expression" }
+int x[A <int>::i];		// { dg-error "16:size of array .x. is not an integral constant-expression" }
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/testsuite/g++.old-deja/g++.bugs/900402_02.C b/gcc/testsuite/g++.old-deja/g++.bugs/900402_02.C
index 46a3ec3..21e2765 100644
--- a/gcc/testsuite/g++.old-deja/g++.bugs/900402_02.C
+++ b/gcc/testsuite/g++.old-deja/g++.bugs/900402_02.C
@@ -6,17 +6,17 @@
 
 // keywords: arrays, array bound, zero length
 
-typedef int array_type[0];		// { dg-error "13:ISO C\\+\\+ forbids zero-size array" }
+typedef int array_type[0];		// { dg-error "24:ISO C\\+\\+ forbids zero-size array" }
 
-int array_object_1[0];			// { dg-error "5:ISO C\\+\\+ forbids zero-size array" }
+int array_object_1[0];			// { dg-error "20:ISO C\\+\\+ forbids zero-size array" }
 
-void function_0 (int formal_array[0])	// { dg-error "22:ISO C\\+\\+ forbids zero-size array" }
+void function_0 (int formal_array[0])	// { dg-error "35:ISO C\\+\\+ forbids zero-size array" }
 {
 }
 
 void function_2 ()
 {
-  int local_object_array_0[0];		// { dg-error "7:ISO C\\+\\+ forbids zero-size array" }
+  int local_object_array_0[0];		// { dg-error "28:ISO C\\+\\+ forbids zero-size array" }
 }
 
 int main () { return 0; }
diff --git a/gcc/tree.c b/gcc/tree.c
index 170ef13..01b9ec3 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -7106,6 +7106,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))
@@ -14646,6 +14649,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)))
@@ -14656,6 +14664,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 960526d..bf685ed 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)
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 34+ messages in thread

* PING Re: [PATCH 2/2] v2: C++: improvements to binary operator diagnostics (PR c++/87504)
  2018-12-04 21:48       ` [PATCH 2/2] v2: C++: improvements to binary operator diagnostics (PR c++/87504) David Malcolm
@ 2018-12-11 19:52         ` David Malcolm
  2018-12-12 20:43         ` Jason Merrill
  1 sibling, 0 replies; 34+ messages in thread
From: David Malcolm @ 2018-12-11 19:52 UTC (permalink / raw)
  To: jason; +Cc: Jeff Law, gcc-patches

Ping re this patch:
  "[PATCH 2/2] v2: C++: improvements to binary operator diagnostics (PR
c++/87504)"
     https://gcc.gnu.org/ml/gcc-patches/2018-12/msg00236.html

(...which is dependent on:
  "[PATCH 1/2] v3: C++: more location wrapper nodes (PR c++/43064, PR
c++/43486)"
     https://gcc.gnu.org/ml/gcc-patches/2018-12/msg00500.html )

Thanks
Dave

On Tue, 2018-12-04 at 17:35 -0500, David Malcolm wrote:
> The v1 patch:
>   https://gcc.gnu.org/ml/gcc-patches/2018-11/msg00303.html
> has bitrotten somewhat, so here's v2 of the patch, updated relative
> to r266740.
> 
> Blurb from v1 patch follows:
> 
> The C frontend is able (where expression locations are available) to
> print
> problems with binary operators in 3-location form, labelling the
> types of
> the expressions:
> 
>   arg_0 op arg_1
>   ~~~~~ ^~ ~~~~~
>     |        |
>     |        arg1 type
>     arg0 type
> 
> The C++ frontend currently just shows the combined location:
> 
>   arg_0 op arg_1
>   ~~~~~~^~~~~~~~
> 
> and fails to highlight where the subexpressions are, or their types.
> 
> This patch introduces a op_location_t struct for handling the above
> operator-location vs combined-location split, and a new
> class binary_op_rich_location for displaying the above, so that the
> C++ frontend is able to use the more detailed 3-location form for
> type mismatches in binary operators, and for -Wtautological-compare
> (where types are not displayed).  Both forms can be seen in this
> example:
> 
> bad-binary-ops.C:69:20: error: no match for 'operator&&' (operand
> types are
>   's' and 't')
>    69 |   return ns_4::foo && ns_4::inner::bar;
>       |          ~~~~~~~~~ ^~ ~~~~~~~~~~~~~~~~
>       |                |                   |
>       |                s                   t
> bad-binary-ops.C:69:20: note: candidate: 'operator&&(bool, bool)'
> <built-in>
>    69 |   return ns_4::foo && ns_4::inner::bar;
>       |          ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
> 
> The patch also allows from some uses of macros in
> -Wtautological-compare, where both sides of the comparison have
> been spelled the same way, e.g.:
> 
> Wtautological-compare-ranges.c:23:11: warning: self-comparison always
>    evaluates to true [-Wtautological-compare]
>    23 |   if (FOO == FOO);
>       |           ^~
> 
> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu, in
> conjunction with the previous patch.
> 
> OK for trunk?
> Dave
> 
> gcc/c-family/ChangeLog:
> 	PR c++/87504
> 	* c-common.h (warn_tautological_cmp): Convert 1st param from
> 	location_t to const op_location_t &.
> 	* c-warn.c (find_array_ref_with_const_idx_r): Strip location
> 	wrapper when testing for INTEGER_CST.
> 	(warn_tautological_bitwise_comparison): Convert 1st param from
> 	location_t to const op_location_t &; use it to build a
> 	binary_op_rich_location, and use this.
> 	(spelled_the_same_p): New function.
> 	(warn_tautological_cmp): Convert 1st param from location_t to
> 	const op_location_t &.  Warn for macro expansions if
> 	spelled_the_same_p.  Use binary_op_rich_location.
> 
> gcc/c/ChangeLog:
> 	PR c++/87504
> 	* c-typeck.c (class maybe_range_label_for_tree_type_mismatch):
> 	Move from here to gcc-rich-location.h and gcc-rich-location.c.
> 	(build_binary_op): Use struct op_location_t and
> 	class binary_op_rich_location.
> 
> gcc/cp/ChangeLog:
> 	PR c++/87504
> 	* call.c (op_error): Convert 1st param from location_t to
> 	const op_location_t &.  Use binary_op_rich_location for binary
> 	ops.
> 	(build_conditional_expr_1): Convert 1st param from location_t
> to
> 	const op_location_t &.
> 	(build_conditional_expr): Likewise.
> 	(build_new_op_1): Likewise.
> 	(build_new_op): Likewise.
> 	* cp-tree.h (build_conditional_expr): Likewise.
> 	(build_new_op): Likewise.
> 	(build_x_binary_op): Likewise.
> 	(cp_build_binary_op): Likewise.
> 	* parser.c (cp_parser_primary_expression): Build a location
> 	for id-expression nodes.
> 	(cp_parser_binary_expression): Use an op_location_t when
> 	calling build_x_binary_op.
> 	(cp_parser_operator): Build a location for user-defined
> literals.
> 	* typeck.c (build_x_binary_op): Convert 1st param from
> location_t
> 	to const op_location_t &.
> 	(cp_build_binary_op): Likewise.  Use binary_op_rich_location.
> 
> gcc/ChangeLog:
> 	PR c++/87504
> 	* gcc-rich-location.c
> 	(maybe_range_label_for_tree_type_mismatch::get_text): Move here
> from
> 	c/c-typeck.c.
> 	(binary_op_rich_location::binary_op_rich_location): New ctor.
> 	(binary_op_rich_location::use_operator_loc_p): New function.
> 	* gcc-rich-location.h
> 	(class maybe_range_label_for_tree_type_mismatch)): Move here
> from
> 	c/c-typeck.c.
> 	(struct op_location_t): New forward decl.
> 	(class binary_op_rich_location): New class.
> 	* tree.h (struct op_location_t): New struct.
> 
> gcc/testsuite/ChangeLog:
> 	* c-c++-common/Wtautological-compare-ranges.c: New test.
> 	* g++.dg/cpp0x/pr51420.C: Add -fdiagnostics-show-caret and
> update
> 	expected output.
> 	* g++.dg/diagnostic/bad-binary-ops.C: Update expected output
> from
> 	1-location form to 3-location form, with labelling of ranges
> with
> 	types.  Add examples of id-expression nodes with namespaces.
> 	* g++.dg/diagnostic/param-type-mismatch-2.C: Likewise.
> 
> This is the 2nd commit message:
> 
> FIXME: column and multiline fixes to * g++.dg/cpp0x/pr51420.C
> ---
>  gcc/c-family/c-common.h                            |  3 +-
>  gcc/c-family/c-warn.c                              | 57 +++++++++++-
> --
>  gcc/c/c-typeck.c                                   | 41 +---------
>  gcc/cp/call.c                                      | 28 ++++---
>  gcc/cp/cp-tree.h                                   | 10 ++-
>  gcc/cp/parser.c                                    | 32 ++++++--
>  gcc/cp/typeck.c                                    | 14 ++--
>  gcc/gcc-rich-location.c                            | 89
> ++++++++++++++++++++++
>  gcc/gcc-rich-location.h                            | 57
> ++++++++++++++
>  .../c-c++-common/Wtautological-compare-ranges.c    | 42 ++++++++++
>  gcc/testsuite/g++.dg/cpp0x/pr51420.C               | 10 +++
>  gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C   | 57
> +++++++++++++-
>  .../g++.dg/diagnostic/param-type-mismatch-2.C      |  4 +-
>  gcc/tree.h                                         | 49 ++++++++++++
>  14 files changed, 417 insertions(+), 76 deletions(-)
>  create mode 100644 gcc/testsuite/c-c++-common/Wtautological-compare-
> ranges.c
> 
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 4187343..0b9ddf6 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -1268,7 +1268,8 @@ extern void constant_expression_error (tree);
>  extern void overflow_warning (location_t, tree, tree = NULL_TREE);
>  extern void warn_logical_operator (location_t, enum tree_code, tree,
>  				   enum tree_code, tree, enum
> tree_code, tree);
> -extern void warn_tautological_cmp (location_t, enum tree_code, tree,
> tree);
> +extern void warn_tautological_cmp (const op_location_t &, enum
> tree_code,
> +				   tree, tree);
>  extern void warn_logical_not_parentheses (location_t, enum
> tree_code, tree,
>  					  tree);
>  extern bool warn_if_unused_value (const_tree, location_t);
> diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
> index fc7f87c..fce9d84 100644
> --- a/gcc/c-family/c-warn.c
> +++ b/gcc/c-family/c-warn.c
> @@ -322,7 +322,8 @@ find_array_ref_with_const_idx_r (tree *expr_p,
> int *, void *)
>  
>    if ((TREE_CODE (expr) == ARRAY_REF
>         || TREE_CODE (expr) == ARRAY_RANGE_REF)
> -      && TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST)
> +      && (TREE_CODE (tree_strip_any_location_wrapper (TREE_OPERAND
> (expr, 1)))
> +	  == INTEGER_CST))
>      return integer_type_node;
>  
>    return NULL_TREE;
> @@ -334,7 +335,7 @@ find_array_ref_with_const_idx_r (tree *expr_p,
> int *, void *)
>     of this comparison.  */
>  
>  static void
> -warn_tautological_bitwise_comparison (location_t loc, tree_code
> code,
> +warn_tautological_bitwise_comparison (const op_location_t &loc,
> tree_code code,
>  				      tree lhs, tree rhs)
>  {
>    if (code != EQ_EXPR && code != NE_EXPR)
> @@ -389,29 +390,64 @@ warn_tautological_bitwise_comparison
> (location_t loc, tree_code code,
>    if (res == cstw)
>      return;
>  
> +  binary_op_rich_location richloc (loc, lhs, rhs, false);
>    if (code == EQ_EXPR)
> -    warning_at (loc, OPT_Wtautological_compare,
> +    warning_at (&richloc, OPT_Wtautological_compare,
>  		"bitwise comparison always evaluates to false");
>    else
> -    warning_at (loc, OPT_Wtautological_compare,
> +    warning_at (&richloc, OPT_Wtautological_compare,
>  		"bitwise comparison always evaluates to true");
>  }
>  
> +/* Given LOC_A and LOC_B from macro expansions, return true if
> +   they are "spelled the same" i.e. if they are both directly from
> +   expansion of the same non-function-like macro.  */
> +
> +static bool
> +spelled_the_same_p (location_t loc_a, location_t loc_b)
> +{
> +  gcc_assert (from_macro_expansion_at (loc_a));
> +  gcc_assert (from_macro_expansion_at (loc_b));
> +
> +  const line_map_macro *map_a
> +    = linemap_check_macro (linemap_lookup (line_table, loc_a));
> +
> +  const line_map_macro *map_b
> +    = linemap_check_macro (linemap_lookup (line_table, loc_b));
> +
> +  if (map_a->macro == map_b->macro)
> +    if (!cpp_fun_like_macro_p (map_a->macro))
> +      return true;
> +
> +  return false;
> +}
> +
>  /* Warn if a self-comparison always evaluates to true or false.  LOC
>     is the location of the comparison with code CODE, LHS and RHS are
>     operands of the comparison.  */
>  
>  void
> -warn_tautological_cmp (location_t loc, enum tree_code code, tree
> lhs, tree rhs)
> +warn_tautological_cmp (const op_location_t &loc, enum tree_code
> code,
> +		       tree lhs, tree rhs)
>  {
>    if (TREE_CODE_CLASS (code) != tcc_comparison)
>      return;
>  
>    /* Don't warn for various macro expansions.  */
> -  if (from_macro_expansion_at (loc)
> -      || from_macro_expansion_at (EXPR_LOCATION (lhs))
> -      || from_macro_expansion_at (EXPR_LOCATION (rhs)))
> +  if (from_macro_expansion_at (loc))
>      return;
> +  bool lhs_in_macro = from_macro_expansion_at (EXPR_LOCATION (lhs));
> +  bool rhs_in_macro = from_macro_expansion_at (EXPR_LOCATION (rhs));
> +  if (lhs_in_macro || rhs_in_macro)
> +    {
> +      /* Don't warn if exactly one is from a macro.  */
> +      if (!(lhs_in_macro && rhs_in_macro))
> +	return;
> +
> +      /* If both are in a macro, only warn if they're spelled the
> same.  */
> +      if (!spelled_the_same_p (EXPR_LOCATION (lhs), EXPR_LOCATION
> (rhs)))
> +	return;
> +    }
>  
>    warn_tautological_bitwise_comparison (loc, code, lhs, rhs);
>  
> @@ -446,11 +482,12 @@ warn_tautological_cmp (location_t loc, enum
> tree_code code, tree lhs, tree rhs)
>        const bool always_true = (code == EQ_EXPR || code == LE_EXPR
>  				|| code == GE_EXPR || code ==
> UNLE_EXPR
>  				|| code == UNGE_EXPR || code ==
> UNEQ_EXPR);
> +      binary_op_rich_location richloc (loc, lhs, rhs, false);
>        if (always_true)
> -	warning_at (loc, OPT_Wtautological_compare,
> +	warning_at (&richloc, OPT_Wtautological_compare,
>  		    "self-comparison always evaluates to true");
>        else
> -	warning_at (loc, OPT_Wtautological_compare,
> +	warning_at (&richloc, OPT_Wtautological_compare,
>  		    "self-comparison always evaluates to false");
>      }
>  }
> diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
> index 8fbecfc..33aad1c 100644
> --- a/gcc/c/c-typeck.c
> +++ b/gcc/c/c-typeck.c
> @@ -11310,38 +11310,6 @@ build_vec_cmp (tree_code code, tree type,
>    return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec);
>  }
>  
> -/* Subclass of range_label for labelling the type of EXPR when
> reporting
> -   a type mismatch between EXPR and OTHER_EXPR.
> -   Either or both of EXPR and OTHER_EXPR could be NULL.  */
> -
> -class maybe_range_label_for_tree_type_mismatch : public range_label
> -{
> - public:
> -  maybe_range_label_for_tree_type_mismatch (tree expr, tree
> other_expr)
> -  : m_expr (expr), m_other_expr (other_expr)
> -  {
> -  }
> -
> -  label_text get_text (unsigned range_idx) const FINAL OVERRIDE
> -  {
> -    if (m_expr == NULL_TREE
> -	|| !EXPR_P (m_expr))
> -      return label_text (NULL, false);
> -    tree expr_type = TREE_TYPE (m_expr);
> -
> -    tree other_type = NULL_TREE;
> -    if (m_other_expr && EXPR_P (m_other_expr))
> -      other_type = TREE_TYPE (m_other_expr);
> -
> -   range_label_for_type_mismatch inner (expr_type, other_type);
> -   return inner.get_text (range_idx);
> -  }
> -
> - private:
> -  tree m_expr;
> -  tree m_other_expr;
> -};
> -
>  /* Build a binary-operation expression without default conversions.
>     CODE is the kind of expression to build.
>     LOCATION is the operator's location.
> @@ -12472,12 +12440,9 @@ build_binary_op (location_t location, enum
> tree_code code,
>  
>    if (!result_type)
>      {
> -      gcc_rich_location richloc (location);
> -      maybe_range_label_for_tree_type_mismatch
> -	label_for_op0 (orig_op0, orig_op1),
> -	label_for_op1 (orig_op1, orig_op0);
> -      richloc.maybe_add_expr (orig_op0, &label_for_op0);
> -      richloc.maybe_add_expr (orig_op1, &label_for_op1);
> +      /* Favor showing any expression locations that are available.
> */
> +      op_location_t oploc (location, UNKNOWN_LOCATION);
> +      binary_op_rich_location richloc (oploc, orig_op0, orig_op1,
> true);
>        binary_op_error (&richloc, code, TREE_TYPE (op0), TREE_TYPE
> (op1));
>        return error_mark_node;
>      }
> diff --git a/gcc/cp/call.c b/gcc/cp/call.c
> index 6dd8744..ca8799d 100644
> --- a/gcc/cp/call.c
> +++ b/gcc/cp/call.c
> @@ -166,8 +166,8 @@ static tree build_over_call (struct z_candidate
> *, int, tsubst_flags_t);
>  		     /*c_cast_p=*/false, (COMPLAIN))
>  static tree convert_like_real (conversion *, tree, tree, int, bool,
>  			       bool, tsubst_flags_t);
> -static void op_error (location_t, enum tree_code, enum tree_code,
> tree,
> -		      tree, tree, bool);
> +static void op_error (const op_location_t &, enum tree_code, enum
> tree_code,
> +		      tree, tree, tree, bool);
>  static struct z_candidate *build_user_type_conversion_1 (tree, tree,
> int,
>  							 tsubst_flag
> s_t);
>  static void print_z_candidate (location_t, const char *, struct
> z_candidate *);
> @@ -4713,7 +4713,8 @@ op_error_string (const char *errmsg, int
> ntypes, bool match)
>  }
>  
>  static void
> -op_error (location_t loc, enum tree_code code, enum tree_code code2,
> +op_error (const op_location_t &loc,
> +	  enum tree_code code, enum tree_code code2,
>  	  tree arg1, tree arg2, tree arg3, bool match)
>  {
>    bool assop = code == MODIFY_EXPR;
> @@ -4767,8 +4768,12 @@ op_error (location_t loc, enum tree_code code,
> enum tree_code code2,
>      default:
>        if (arg2)
>  	if (flag_diagnostics_show_caret)
> -	  error_at (loc, op_error_string (G_("%<operator%s%>"), 2,
> match),
> -		    opname, TREE_TYPE (arg1), TREE_TYPE (arg2));
> +	  {
> +	    binary_op_rich_location richloc (loc, arg1, arg2, true);
> +	    error_at (&richloc,
> +		      op_error_string (G_("%<operator%s%>"), 2,
> match),
> +		      opname, TREE_TYPE (arg1), TREE_TYPE (arg2));
> +	  }
>  	else
>  	  error_at (loc, op_error_string (G_("%<operator%s%> in %<%E
> %s %E%>"),
>  					  2, match),
> @@ -4867,7 +4872,8 @@ conditional_conversion (tree e1, tree e2,
> tsubst_flags_t complain)
>     arguments to the conditional expression.  */
>  
>  static tree
> -build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree
> arg3,
> +build_conditional_expr_1 (const op_location_t &loc,
> +			  tree arg1, tree arg2, tree arg3,
>                            tsubst_flags_t complain)
>  {
>    tree arg2_type;
> @@ -5461,7 +5467,8 @@ build_conditional_expr_1 (location_t loc, tree
> arg1, tree arg2, tree arg3,
>  /* Wrapper for above.  */
>  
>  tree
> -build_conditional_expr (location_t loc, tree arg1, tree arg2, tree
> arg3,
> +build_conditional_expr (const op_location_t &loc,
> +			tree arg1, tree arg2, tree arg3,
>                          tsubst_flags_t complain)
>  {
>    tree ret;
> @@ -5650,8 +5657,9 @@ op_is_ordered (tree_code code)
>  }
>  
>  static tree
> -build_new_op_1 (location_t loc, enum tree_code code, int flags, tree
> arg1,
> -		tree arg2, tree arg3, tree *overload, tsubst_flags_t
> complain)
> +build_new_op_1 (const op_location_t &loc, enum tree_code code, int
> flags,
> +		tree arg1, tree arg2, tree arg3, tree *overload,
> +		tsubst_flags_t complain)
>  {
>    struct z_candidate *candidates = 0, *cand;
>    vec<tree, va_gc> *arglist;
> @@ -6130,7 +6138,7 @@ build_new_op_1 (location_t loc, enum tree_code
> code, int flags, tree arg1,
>  /* Wrapper for above.  */
>  
>  tree
> -build_new_op (location_t loc, enum tree_code code, int flags,
> +build_new_op (const op_location_t &loc, enum tree_code code, int
> flags,
>  	      tree arg1, tree arg2, tree arg3,
>  	      tree *overload, tsubst_flags_t complain)
>  {
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 111a123..e80334a 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -6097,7 +6097,8 @@ extern int raw_dump_id;
>  extern bool check_dtor_name			(tree, tree);
>  int magic_varargs_p				(tree);
>  
> -extern tree build_conditional_expr		(location_t, tree,
> tree, tree, 
> +extern tree build_conditional_expr		(const
> op_location_t &,
> +						 tree, tree, tree,
>                                                   tsubst_flags_t);
>  extern tree build_addr_func			(tree,
> tsubst_flags_t);
>  extern void set_flags_from_callee		(tree);
> @@ -6122,7 +6123,8 @@ extern tree build_new_method_call		
> (tree, tree,
>  extern tree build_special_member_call		(tree, tree,
>  						 vec<tree, va_gc>
> **,
>  						 tree, int,
> tsubst_flags_t);
> -extern tree build_new_op			(location_t, enum
> tree_code,
> +extern tree build_new_op			(const op_location_t
> &,
> +						 enum tree_code,
>  						 int, tree, tree,
> tree, tree *,
>  						 tsubst_flags_t);
>  extern tree build_op_call			(tree, vec<tree,
> va_gc> **,
> @@ -7338,7 +7340,7 @@ extern tree
> cp_build_function_call_nary         (tree, tsubst_flags_t, ...)
>  						ATTRIBUTE_SENTINEL;
>  extern tree cp_build_function_call_vec		(tree,
> vec<tree, va_gc> **,
>  						 tsubst_flags_t);
> -extern tree build_x_binary_op			(location_t,
> +extern tree build_x_binary_op			(const
> op_location_t &,
>  						 enum tree_code,
> tree,
>  						 enum tree_code,
> tree,
>  						 enum tree_code,
> tree *,
> @@ -7405,7 +7407,7 @@ extern tree composite_pointer_type		
> (tree, tree, tree, tree,
>  extern tree merge_types				(tree, tree);
>  extern tree strip_array_domain			(tree);
>  extern tree check_return_expr			(tree, bool *);
> -extern tree cp_build_binary_op                  (location_t,
> +extern tree cp_build_binary_op                  (const op_location_t
> &,
>  						 enum tree_code,
> tree, tree,
>  						 tsubst_flags_t);
>  extern tree build_x_vec_perm_expr               (location_t,
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index 4acc79d..321ff39 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -5710,8 +5710,21 @@ cp_parser_primary_expression (cp_parser
> *parser,
>  		 id_expression.get_location ()));
>  	if (error_msg)
>  	  cp_parser_error (parser, error_msg);
> -	decl.set_location (id_expression.get_location ());
> -	decl.set_range (id_expr_token->location,
> id_expression.get_finish ());
> +	/* Build a location for an id-expression of the form:
> +	     ::ns::id
> +             ~~~~~~^~
> +	  or:
> +	     id
> +	     ^~
> +	   i.e. from the start of the first token to the end of the
> final
> +	   token, with the caret at the start of the unqualified-
> id.  */
> +	location_t caret_loc = get_pure_location
> (id_expression.get_location ());
> +	location_t start_loc = get_start (id_expr_token->location);
> +	location_t finish_loc = get_finish
> (id_expression.get_location ());
> +	location_t combined_loc
> +	  = make_location (caret_loc, start_loc, finish_loc);
> +
> +	decl.set_location (combined_loc);
>  	return decl;
>        }
>  
> @@ -9547,7 +9560,8 @@ cp_parser_binary_expression (cp_parser* parser,
> bool cast_p,
>  	}
>        else
>          {
> -          current.lhs = build_x_binary_op (combined_loc,
> current.tree_type,
> +	  op_location_t op_loc (current.loc, combined_loc);
> +	  current.lhs = build_x_binary_op (op_loc,
> current.tree_type,
>                                             current.lhs,
> current.lhs_type,
>                                             rhs, rhs_type, &overload,
>                                             complain_flags
> (decltype_p));
> @@ -15382,8 +15396,16 @@ cp_parser_operator (cp_parser* parser,
> location_t start_loc)
>  	    const char *name = IDENTIFIER_POINTER (id);
>  	    id = cp_literal_operator_id (name);
>  	  }
> -	start_loc = make_location (start_loc, start_loc, get_finish
> (end_loc));
> -	return cp_expr (id, start_loc);
> +	/* Generate a location of the form:
> +	     "" _suffix_identifier
> +	     ^~~~~~~~~~~~~~~~~~~~~
> +	   with caret == start at the start token, finish at the end
> of the
> +	   suffix identifier.  */
> +	location_t finish_loc
> +	  = get_finish (cp_lexer_previous_token (parser->lexer)-
> >location);
> +	location_t combined_loc
> +	  = make_location (start_loc, start_loc, finish_loc);
> +	return cp_expr (id, combined_loc);
>        }
>  
>      default:
> diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
> index 820cfc5..a2f75c8 100644
> --- a/gcc/cp/typeck.c
> +++ b/gcc/cp/typeck.c
> @@ -4114,7 +4114,7 @@ convert_arguments (tree typelist, vec<tree,
> va_gc> **values, tree fndecl,
>     ARG2_CODE as ERROR_MARK.  */
>  
>  tree
> -build_x_binary_op (location_t loc, enum tree_code code, tree arg1,
> +build_x_binary_op (const op_location_t &loc, enum tree_code code,
> tree arg1,
>  		   enum tree_code arg1_code, tree arg2,
>  		   enum tree_code arg2_code, tree *overload_p,
>  		   tsubst_flags_t complain)
> @@ -4303,7 +4303,7 @@ warn_for_null_address (location_t location,
> tree op, tsubst_flags_t complain)
>     multiple inheritance, and deal with pointer to member
> functions.  */
>  
>  tree
> -cp_build_binary_op (location_t location,
> +cp_build_binary_op (const op_location_t &location,
>  		    enum tree_code code, tree orig_op0, tree
> orig_op1,
>  		    tsubst_flags_t complain)
>  {
> @@ -5300,9 +5300,13 @@ cp_build_binary_op (location_t location,
>    if (!result_type)
>      {
>        if (complain & tf_error)
> -	error_at (location,
> -		  "invalid operands of types %qT and %qT to binary
> %qO",
> -		  TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
> +	{
> +	  binary_op_rich_location richloc (location,
> +					   orig_op0, orig_op1,
> true);
> +	  error_at (&richloc,
> +		    "invalid operands of types %qT and %qT to binary
> %qO",
> +		    TREE_TYPE (orig_op0), TREE_TYPE (orig_op1),
> code);
> +	}
>        return error_mark_node;
>      }
>  
> diff --git a/gcc/gcc-rich-location.c b/gcc/gcc-rich-location.c
> index 81beb61..25a604f 100644
> --- a/gcc/gcc-rich-location.c
> +++ b/gcc/gcc-rich-location.c
> @@ -182,3 +182,92 @@ gcc_rich_location::add_fixit_insert_formatted
> (const char *content,
>    else
>      add_fixit_insert_before (insertion_point, content);
>  }
> +
> +/* Implementation of range_label::get_text for
> +   maybe_range_label_for_tree_type_mismatch.
> +
> +   If both expressions are non-NULL, then generate text describing
> +   the first expression's type (using the other expression's type
> +   for comparison, analogous to %H and %I in the C++ frontend, but
> +   on expressions rather than types).  */
> +
> +label_text
> +maybe_range_label_for_tree_type_mismatch::get_text (unsigned
> range_idx) const
> +{
> +  if (m_expr == NULL_TREE
> +      || !EXPR_P (m_expr))
> +    return label_text (NULL, false);
> +  tree expr_type = TREE_TYPE (m_expr);
> +
> +  tree other_type = NULL_TREE;
> +  if (m_other_expr && EXPR_P (m_other_expr))
> +    other_type = TREE_TYPE (m_other_expr);
> +
> +  range_label_for_type_mismatch inner (expr_type, other_type);
> +  return inner.get_text (range_idx);
> +}
> +
> +/* binary_op_rich_location's ctor.
> +
> +   If use_operator_loc_p (LOC, ARG0, ARG1), then attempt to make a
> 3-location
> +   rich_location of the form:
> +
> +     arg_0 op arg_1
> +     ~~~~~ ^~ ~~~~~
> +       |        |
> +       |        arg1 type
> +       arg0 type
> +
> +   labelling the types of the arguments if SHOW_TYPES is true.
> +
> +   Otherwise, make a 1-location rich_location using the compound
> +   location within LOC:
> +
> +     arg_0 op arg_1
> +     ~~~~~~^~~~~~~~
> +
> +   for which we can't label the types.  */
> +
> +binary_op_rich_location::binary_op_rich_location (const
> op_location_t &loc,
> +						  tree arg0, tree
> arg1,
> +						  bool show_types)
> +: gcc_rich_location (loc.m_combined_loc),
> +  m_label_for_arg0 (arg0, arg1),
> +  m_label_for_arg1 (arg1, arg0)
> +{
> +  /* Default (above) to using the combined loc.
> +     Potentially override it here: if we have location information
> for the
> +     operator and for both arguments, then split them all out.
> +     Alternatively, override it if we don't have the combined
> location.  */
> +  if (use_operator_loc_p (loc, arg0, arg1))
> +    {
> +      set_range (0, loc.m_operator_loc, SHOW_RANGE_WITH_CARET);
> +      maybe_add_expr (arg0, show_types ? &m_label_for_arg0 : NULL);
> +      maybe_add_expr (arg1, show_types ? &m_label_for_arg1 : NULL);
> +    }
> +}
> +
> +/* Determine if binary_op_rich_location's ctor should attempt to
> make
> +   a 3-location rich_location (the location of the operator and of
> +   the 2 arguments), or fall back to a 1-location rich_location
> showing
> +   just the combined location of the operation as a whole.  */
> +
> +bool
> +binary_op_rich_location::use_operator_loc_p (const op_location_t
> &loc,
> +					     tree arg0, tree arg1)
> +{
> +  /* If we don't have a combined location, then use the operator
> location,
> +     and try to add ranges for the operators.  */
> +  if (loc.m_combined_loc == UNKNOWN_LOCATION)
> +    return true;
> +
> +  /* If we don't have the operator location, then use the
> +     combined location.  */
> +  if (loc.m_operator_loc == UNKNOWN_LOCATION)
> +    return false;
> +
> +  /* We have both operator location and combined location: only use
> the
> +     operator location if we have locations for both arguments.  */
> +  return (EXPR_HAS_LOCATION (arg0)
> +	  && EXPR_HAS_LOCATION (arg1));
> +}
> diff --git a/gcc/gcc-rich-location.h b/gcc/gcc-rich-location.h
> index 200bbb5..202d4f4 100644
> --- a/gcc/gcc-rich-location.h
> +++ b/gcc/gcc-rich-location.h
> @@ -162,4 +162,61 @@ class range_label_for_type_mismatch : public
> range_label
>    tree m_other_type;
>  };
>  
> +/* Subclass of range_label for labelling the type of EXPR when
> reporting
> +   a type mismatch between EXPR and OTHER_EXPR.
> +   Either or both of EXPR and OTHER_EXPR could be NULL.  */
> +
> +class maybe_range_label_for_tree_type_mismatch : public range_label
> +{
> + public:
> +  maybe_range_label_for_tree_type_mismatch (tree expr, tree
> other_expr)
> +  : m_expr (expr), m_other_expr (other_expr)
> +  {
> +  }
> +
> +  label_text get_text (unsigned range_idx) const FINAL OVERRIDE;
> +
> + private:
> +  tree m_expr;
> +  tree m_other_expr;
> +};
> +
> +struct op_location_t;
> +
> +/* A subclass of rich_location for showing problems with binary
> operations.
> +
> +   If enough location information is available, the ctor will make a
> +   3-location rich_location of the form:
> +
> +     arg_0 op arg_1
> +     ~~~~~ ^~ ~~~~~
> +       |        |
> +       |        arg1 type
> +       arg0 type
> +
> +   labelling the types of the arguments if SHOW_TYPES is true.
> +
> +   Otherwise, it will fall back to a 1-location rich_location using
> the
> +   compound location within LOC:
> +
> +     arg_0 op arg_1
> +     ~~~~~~^~~~~~~~
> +
> +   for which we can't label the types.  */
> +
> +class binary_op_rich_location : public gcc_rich_location
> +{
> + public:
> +  binary_op_rich_location (const op_location_t &loc,
> +			   tree arg0, tree arg1,
> +			   bool show_types);
> +
> + private:
> +  static bool use_operator_loc_p (const op_location_t &loc,
> +				  tree arg0, tree arg1);
> +
> +  maybe_range_label_for_tree_type_mismatch m_label_for_arg0;
> +  maybe_range_label_for_tree_type_mismatch m_label_for_arg1;
> +};
> +
>  #endif /* GCC_RICH_LOCATION_H */
> diff --git a/gcc/testsuite/c-c++-common/Wtautological-compare-
> ranges.c b/gcc/testsuite/c-c++-common/Wtautological-compare-ranges.c
> new file mode 100644
> index 0000000..2634d27
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/Wtautological-compare-ranges.c
> @@ -0,0 +1,42 @@
> +/* { dg-do compile } */
> +/* { dg-options "-Wtautological-compare -fdiagnostics-show-caret" }
> */
> +
> +#define FOO foo
> +
> +void
> +fn1 (int foo)
> +{
> +  if (foo == foo); /* { dg-warning "self-comparison always evaluates
> to true" } */
> +  /* { dg-begin-multiline-output "" }
> +   if (foo == foo);
> +           ^~
> +     { dg-end-multiline-output "" { target c } } */
> +  /* { dg-begin-multiline-output "" }
> +   if (foo == foo);
> +       ~~~ ^~ ~~~
> +     { dg-end-multiline-output "" { target c++ } } */
> +}
> +
> +void
> +fn2 (int foo)
> +{
> +  if (FOO == FOO); /* { dg-warning "self-comparison always evaluates
> to true" } */
> +  /* { dg-begin-multiline-output "" }
> +   if (FOO == FOO);
> +           ^~
> +     { dg-end-multiline-output "" } */
> +}
> +
> +void
> +fn3 (int foo)
> +{
> +  if ((foo & 16) == 10); /* { dg-warning "bitwise comparison always
> evaluates to false" } */
> +  /* { dg-begin-multiline-output "" }
> +   if ((foo & 16) == 10);
> +                  ^~
> +     { dg-end-multiline-output "" { target c } } */
> +  /* { dg-begin-multiline-output "" }
> +   if ((foo & 16) == 10);
> +       ~~~~~~~~~~ ^~ ~~
> +     { dg-end-multiline-output "" { target c++ } } */
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp0x/pr51420.C
> b/gcc/testsuite/g++.dg/cpp0x/pr51420.C
> index fc70d46..1612cef 100644
> --- a/gcc/testsuite/g++.dg/cpp0x/pr51420.C
> +++ b/gcc/testsuite/g++.dg/cpp0x/pr51420.C
> @@ -1,8 +1,18 @@
>  // { dg-do compile { target c++11 } }
> +// { dg-options "-fdiagnostics-show-caret" }
>  
>  void
>  foo()
>  {
>    float x = operator"" _F();  //  { dg-error  "13:'operator\"\"_F'
> was not declared in this scope" }
> +  /* { dg-begin-multiline-output "" }
> +   float x = operator"" _F();
> +             ^~~~~~~~~~~~~
> +     { dg-end-multiline-output "" } */
> +
>    float y = 0_F;  //  { dg-error  "unable to find numeric literal
> operator" }
> +  /* { dg-begin-multiline-output "" }
> +   float y = 0_F;
> +             ^~~
> +     { dg-end-multiline-output "" } */
>  }
> diff --git a/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C
> b/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C
> index 4ab7656..fab5849 100644
> --- a/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C
> +++ b/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C
> @@ -11,7 +11,10 @@ void test_1 ()
>  
>  /* { dg-begin-multiline-output "" }
>     myvec[1] / ptr;
> -   ~~~~~~~~~^~~~~
> +   ~~~~~~~~ ^ ~~~
> +          |   |
> +          |   const int*
> +          __m128 {aka float}
>     { dg-end-multiline-output "" } */
>  }
>  
> @@ -28,8 +31,12 @@ int test_2 (void)
>  /* { dg-begin-multiline-output "" }
>     return (some_function ()
>             ~~~~~~~~~~~~~~~~
> +                         |
> +                         s
>      + some_other_function ());
> -    ^~~~~~~~~~~~~~~~~~~~~~~~
> +    ^ ~~~~~~~~~~~~~~~~~~~~~~
> +                          |
> +                          t
>     { dg-end-multiline-output "" } */
>  }
>  
> @@ -39,6 +46,52 @@ int test_3 (struct s param_s, struct t param_t)
>  
>  /* { dg-begin-multiline-output "" }
>     return param_s && param_t;
> +          ~~~~~~~ ^~ ~~~~~~~
> +          |          |
> +          s          t
> +   { dg-end-multiline-output "" } */
> +/* { dg-begin-multiline-output "" }
> +   return param_s && param_t;
>            ~~~~~~~~^~~~~~~~~~
>     { dg-end-multiline-output "" } */
>  }
> +
> +namespace ns_4
> +{
> +  struct s foo;
> +  namespace inner {
> +    struct t bar;
> +  };
> +};
> +
> +int test_4a (void)
> +{
> +  return ns_4::foo && ns_4::inner::bar; // { dg-error "no match for
> .operator" }
> +  /* { dg-begin-multiline-output "" }
> +   return ns_4::foo && ns_4::inner::bar;
> +          ~~~~~~~~~ ^~ ~~~~~~~~~~~~~~~~
> +                |                   |
> +                s                   t
> +     { dg-end-multiline-output "" } */
> +
> +  /* { dg-begin-multiline-output "" }
> +   return ns_4::foo && ns_4::inner::bar;
> +          ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
> +     { dg-end-multiline-output "" } */
> +}
> +
> +int test_4b (void)
> +{
> +  return ::ns_4::foo && ns_4::inner::bar; // { dg-error "no match
> for .operator" }
> +  /* { dg-begin-multiline-output "" }
> +   return ::ns_4::foo && ns_4::inner::bar;
> +          ~~~~~~~~~~~ ^~ ~~~~~~~~~~~~~~~~
> +                  |                   |
> +                  s                   t
> +     { dg-end-multiline-output "" } */
> +
> +  /* { dg-begin-multiline-output "" }
> +   return ::ns_4::foo && ns_4::inner::bar;
> +          ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
> +     { dg-end-multiline-output "" } */
> +}
> diff --git a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
> b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
> index b19655d..de7570a 100644
> --- a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
> +++ b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
> @@ -204,7 +204,9 @@ int test_10 ()
>    return v10_a - v10_b; // { dg-error "no match for" }
>    /* { dg-begin-multiline-output "" }
>     return v10_a - v10_b;
> -          ~~~~~~^~~~~~~
> +          ~~~~~ ^ ~~~~~
> +          |       |
> +          s10     s10
>       { dg-end-multiline-output "" } */
>    // { dg-message "candidate" "" { target *-*-* } s10_operator }
>    /* { dg-begin-multiline-output "" }
> diff --git a/gcc/tree.h b/gcc/tree.h
> index bf685ed..5527ef1 100644
> --- a/gcc/tree.h
> +++ b/gcc/tree.h
> @@ -5959,4 +5959,53 @@ fndecl_built_in_p (const_tree node,
> built_in_function name)
>  	  && DECL_FUNCTION_CODE (node) == name);
>  }
>  
> +/* A struct for encapsulating location information about an operator
> +   and the operation built from it.
> +
> +   m_operator_loc is the location of the operator
> +   m_combined_loc is the location of the compound expression.
> +
> +   For example, given "a && b" the, operator location is:
> +      a && b
> +        ^~
> +   and the combined location is:
> +      a && b
> +      ~~^~~~
> +   Capturing this information allows for class
> binary_op_rich_location
> +   to provide detailed information about e.g. type mismatches in
> binary
> +   operations where enough location information is available:
> +
> +     arg_0 op arg_1
> +     ~~~~~ ^~ ~~~~~
> +       |        |
> +       |        arg1 type
> +       arg0 type
> +
> +   falling back to just showing the combined location:
> +
> +     arg_0 op arg_1
> +     ~~~~~~^~~~~~~~
> +
> +   where it is not.  */
> +
> +struct op_location_t
> +{
> +  location_t m_operator_loc;
> +  location_t m_combined_loc;
> +
> +  /* 1-argument ctor, for constructing from a combined location.  */
> +  op_location_t (location_t combined_loc)
> +  : m_operator_loc (UNKNOWN_LOCATION), m_combined_loc (combined_loc)
> +  {}
> +
> +  /* 2-argument ctor, for distinguishing between the operator's
> location
> +     and the combined location.  */
> +  op_location_t (location_t operator_loc, location_t combined_loc)
> +  : m_operator_loc (operator_loc), m_combined_loc (combined_loc)
> +  {}
> +
> +  /* Implicitly convert back to a location_t, using the combined
> location.  */
> +  operator location_t () const { return m_combined_loc; }
> +};
> +
>  #endif  /* GCC_TREE_H  */

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 1/2] v3: C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
  2018-12-07 19:25       ` [PATCH 1/2] v3: " David Malcolm
@ 2018-12-12 20:37         ` Jason Merrill
  2018-12-13 19:24           ` [PATCH] v4: " David Malcolm
  0 siblings, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2018-12-12 20:37 UTC (permalink / raw)
  To: David Malcolm; +Cc: Jeff Law, gcc-patches

On 12/7/18 3:13 PM, David Malcolm wrote:
> On Tue, 2018-12-04 at 18:31 -0500, Jason Merrill wrote:
>> On 12/3/18 5:10 PM, Jeff Law wrote:
>>> On 11/19/18 9:51 AM, David Malcolm wrote:
> [...]
>>> @@ -1058,6 +1058,9 @@ grokbitfield (const cp_declarator
>>> *declarator,
>>>         return NULL_TREE;
>>>       }
>>>   
>>> +  if (width)
>>> +    STRIP_ANY_LOCATION_WRAPPER (width);
>>
>> Why is this needed?  We should already be reducing width to an
>> unwrapped
>> constant value somewhere along the line.
> 
> "width" is coming from cp_parser_member_declaration, from:
> 
> 	      /* Get the width of the bitfield.  */
> 	      width = cp_parser_constant_expression (parser, false, NULL,
> 						     cxx_dialect >= cxx11);
> 
> and currently nothing is unwrapping the value.  We presumably need to
> unwrap (or fold?) it before it is stashed in
>    DECL_BIT_FIELD_REPRESENTATIVE (value).
> 
> Without stripping (or folding) here, we e.g. lose a warning and get this:
>    FAIL: g++.dg/abi/empty22.C  -std=gnu++98  (test for warnings, line 15)

Why does that happen?  check_bitfield_decl ought to handle the location 
wrapper fine.  That's where it gets folded.

>>> @@ -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);
>>
>> Why is this needed?  What cares about the tree codes of the capture
>> initializer?
> 
> This is used to populate LAMBDA_EXPR_CAPTURE_LIST.  Without stripping,
> we end up with wrapped VAR_DECLs, rather than the VAR_DECLs themselves,

Sure, that sounds fine.

> and this confuses things later on, for example leading to:
> 
>   PASS -> FAIL : g++.dg/cpp0x/lambda/lambda-type.C  -std=c++14 (test for excess errors)
>   PASS -> FAIL : g++.dg/cpp0x/lambda/lambda-type.C  -std=c++17 (test for excess errors)

Confuses how?

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 2/2] v2: C++: improvements to binary operator diagnostics (PR c++/87504)
  2018-12-04 21:48       ` [PATCH 2/2] v2: C++: improvements to binary operator diagnostics (PR c++/87504) David Malcolm
  2018-12-11 19:52         ` PING " David Malcolm
@ 2018-12-12 20:43         ` Jason Merrill
  2018-12-19 23:28           ` Aaron Sawdey
  1 sibling, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2018-12-12 20:43 UTC (permalink / raw)
  To: David Malcolm; +Cc: Jeff Law, gcc-patches

On 12/4/18 5:35 PM, David Malcolm wrote:
> The v1 patch:
>    https://gcc.gnu.org/ml/gcc-patches/2018-11/msg00303.html
> has bitrotten somewhat, so here's v2 of the patch, updated relative
> to r266740.
> 
> Blurb from v1 patch follows:
> 
> The C frontend is able (where expression locations are available) to print
> problems with binary operators in 3-location form, labelling the types of
> the expressions:
> 
>    arg_0 op arg_1
>    ~~~~~ ^~ ~~~~~
>      |        |
>      |        arg1 type
>      arg0 type
> 
> The C++ frontend currently just shows the combined location:
> 
>    arg_0 op arg_1
>    ~~~~~~^~~~~~~~
> 
> and fails to highlight where the subexpressions are, or their types.
> 
> This patch introduces a op_location_t struct for handling the above
> operator-location vs combined-location split, and a new
> class binary_op_rich_location for displaying the above, so that the
> C++ frontend is able to use the more detailed 3-location form for
> type mismatches in binary operators, and for -Wtautological-compare
> (where types are not displayed).  Both forms can be seen in this
> example:
> 
> bad-binary-ops.C:69:20: error: no match for 'operator&&' (operand types are
>    's' and 't')
>     69 |   return ns_4::foo && ns_4::inner::bar;
>        |          ~~~~~~~~~ ^~ ~~~~~~~~~~~~~~~~
>        |                |                   |
>        |                s                   t
> bad-binary-ops.C:69:20: note: candidate: 'operator&&(bool, bool)' <built-in>
>     69 |   return ns_4::foo && ns_4::inner::bar;
>        |          ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
> 
> The patch also allows from some uses of macros in
> -Wtautological-compare, where both sides of the comparison have
> been spelled the same way, e.g.:
> 
> Wtautological-compare-ranges.c:23:11: warning: self-comparison always
>     evaluates to true [-Wtautological-compare]
>     23 |   if (FOO == FOO);
>        |           ^~
> 
> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu, in
> conjunction with the previous patch.
> 
> OK for trunk?
> Dave
> 
> gcc/c-family/ChangeLog:
> 	PR c++/87504
> 	* c-common.h (warn_tautological_cmp): Convert 1st param from
> 	location_t to const op_location_t &.
> 	* c-warn.c (find_array_ref_with_const_idx_r): Strip location
> 	wrapper when testing for INTEGER_CST.
> 	(warn_tautological_bitwise_comparison): Convert 1st param from
> 	location_t to const op_location_t &; use it to build a
> 	binary_op_rich_location, and use this.
> 	(spelled_the_same_p): New function.
> 	(warn_tautological_cmp): Convert 1st param from location_t to
> 	const op_location_t &.  Warn for macro expansions if
> 	spelled_the_same_p.  Use binary_op_rich_location.
> 
> gcc/c/ChangeLog:
> 	PR c++/87504
> 	* c-typeck.c (class maybe_range_label_for_tree_type_mismatch):
> 	Move from here to gcc-rich-location.h and gcc-rich-location.c.
> 	(build_binary_op): Use struct op_location_t and
> 	class binary_op_rich_location.
> 
> gcc/cp/ChangeLog:
> 	PR c++/87504
> 	* call.c (op_error): Convert 1st param from location_t to
> 	const op_location_t &.  Use binary_op_rich_location for binary
> 	ops.
> 	(build_conditional_expr_1): Convert 1st param from location_t to
> 	const op_location_t &.
> 	(build_conditional_expr): Likewise.
> 	(build_new_op_1): Likewise.
> 	(build_new_op): Likewise.
> 	* cp-tree.h (build_conditional_expr): Likewise.
> 	(build_new_op): Likewise.
> 	(build_x_binary_op): Likewise.
> 	(cp_build_binary_op): Likewise.
> 	* parser.c (cp_parser_primary_expression): Build a location
> 	for id-expression nodes.
> 	(cp_parser_binary_expression): Use an op_location_t when
> 	calling build_x_binary_op.
> 	(cp_parser_operator): Build a location for user-defined literals.
> 	* typeck.c (build_x_binary_op): Convert 1st param from location_t
> 	to const op_location_t &.
> 	(cp_build_binary_op): Likewise.  Use binary_op_rich_location.
> 
> gcc/ChangeLog:
> 	PR c++/87504
> 	* gcc-rich-location.c
> 	(maybe_range_label_for_tree_type_mismatch::get_text): Move here from
> 	c/c-typeck.c.
> 	(binary_op_rich_location::binary_op_rich_location): New ctor.
> 	(binary_op_rich_location::use_operator_loc_p): New function.
> 	* gcc-rich-location.h
> 	(class maybe_range_label_for_tree_type_mismatch)): Move here from
> 	c/c-typeck.c.
> 	(struct op_location_t): New forward decl.
> 	(class binary_op_rich_location): New class.
> 	* tree.h (struct op_location_t): New struct.
> 
> gcc/testsuite/ChangeLog:
> 	* c-c++-common/Wtautological-compare-ranges.c: New test.
> 	* g++.dg/cpp0x/pr51420.C: Add -fdiagnostics-show-caret and update
> 	expected output.
> 	* g++.dg/diagnostic/bad-binary-ops.C: Update expected output from
> 	1-location form to 3-location form, with labelling of ranges with
> 	types.  Add examples of id-expression nodes with namespaces.
> 	* g++.dg/diagnostic/param-type-mismatch-2.C: Likewise.
> 
> This is the 2nd commit message:
> 
> FIXME: column and multiline fixes to * g++.dg/cpp0x/pr51420.C
> ---
>   gcc/c-family/c-common.h                            |  3 +-
>   gcc/c-family/c-warn.c                              | 57 +++++++++++---
>   gcc/c/c-typeck.c                                   | 41 +---------
>   gcc/cp/call.c                                      | 28 ++++---
>   gcc/cp/cp-tree.h                                   | 10 ++-
>   gcc/cp/parser.c                                    | 32 ++++++--
>   gcc/cp/typeck.c                                    | 14 ++--
>   gcc/gcc-rich-location.c                            | 89 ++++++++++++++++++++++
>   gcc/gcc-rich-location.h                            | 57 ++++++++++++++
>   .../c-c++-common/Wtautological-compare-ranges.c    | 42 ++++++++++
>   gcc/testsuite/g++.dg/cpp0x/pr51420.C               | 10 +++
>   gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C   | 57 +++++++++++++-
>   .../g++.dg/diagnostic/param-type-mismatch-2.C      |  4 +-
>   gcc/tree.h                                         | 49 ++++++++++++
>   14 files changed, 417 insertions(+), 76 deletions(-)
>   create mode 100644 gcc/testsuite/c-c++-common/Wtautological-compare-ranges.c
> 
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 4187343..0b9ddf6 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -1268,7 +1268,8 @@ extern void constant_expression_error (tree);
>   extern void overflow_warning (location_t, tree, tree = NULL_TREE);
>   extern void warn_logical_operator (location_t, enum tree_code, tree,
>   				   enum tree_code, tree, enum tree_code, tree);
> -extern void warn_tautological_cmp (location_t, enum tree_code, tree, tree);
> +extern void warn_tautological_cmp (const op_location_t &, enum tree_code,
> +				   tree, tree);
>   extern void warn_logical_not_parentheses (location_t, enum tree_code, tree,
>   					  tree);
>   extern bool warn_if_unused_value (const_tree, location_t);
> diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
> index fc7f87c..fce9d84 100644
> --- a/gcc/c-family/c-warn.c
> +++ b/gcc/c-family/c-warn.c
> @@ -322,7 +322,8 @@ find_array_ref_with_const_idx_r (tree *expr_p, int *, void *)
>   
>     if ((TREE_CODE (expr) == ARRAY_REF
>          || TREE_CODE (expr) == ARRAY_RANGE_REF)
> -      && TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST)
> +      && (TREE_CODE (tree_strip_any_location_wrapper (TREE_OPERAND (expr, 1)))
> +	  == INTEGER_CST))
>       return integer_type_node;

I think we want fold_for_warn here.  OK with that change (assuming it 
passes).

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH] v4: C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
  2018-12-12 20:37         ` Jason Merrill
@ 2018-12-13 19:24           ` David Malcolm
  2018-12-13 20:38             ` Jason Merrill
  0 siblings, 1 reply; 34+ messages in thread
From: David Malcolm @ 2018-12-13 19:24 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jeff Law, gcc-patches, David Malcolm

On Wed, 2018-12-12 at 15:37 -0500, Jason Merrill wrote:
> On 12/7/18 3:13 PM, David Malcolm wrote:
> > On Tue, 2018-12-04 at 18:31 -0500, Jason Merrill wrote:
> > > On 12/3/18 5:10 PM, Jeff Law wrote:
> > > > On 11/19/18 9:51 AM, David Malcolm wrote:
> > 
> > [...]
> > > > @@ -1058,6 +1058,9 @@ grokbitfield (const cp_declarator
> > > > *declarator,
> > > >         return NULL_TREE;
> > > >       }
> > > >   
> > > > +  if (width)
> > > > +    STRIP_ANY_LOCATION_WRAPPER (width);
> > > 
> > > Why is this needed?  We should already be reducing width to an
> > > unwrapped
> > > constant value somewhere along the line.
> > 
> > "width" is coming from cp_parser_member_declaration, from:
> > 
> > 	      /* Get the width of the bitfield.  */
> > 	      width = cp_parser_constant_expression (parser, false,
> > NULL,
> > 						     cxx_dialect >=
> > cxx11);
> > 
> > and currently nothing is unwrapping the value.  We presumably need
> > to
> > unwrap (or fold?) it before it is stashed in
> >    DECL_BIT_FIELD_REPRESENTATIVE (value).
> > 
> > Without stripping (or folding) here, we e.g. lose a warning and get
> > this:
> >    FAIL: g++.dg/abi/empty22.C  -std=gnu++98  (test for warnings,
> > line 15)
> 
> Why does that happen?  check_bitfield_decl ought to handle the
> location 
> wrapper fine.  That's where it gets folded.

The unstripped location wrapper defeats this check for zero in
check_field_decls within cp/class.c:

3555	      if (DECL_C_BIT_FIELD (x)
3556		  && integer_zerop (DECL_BIT_FIELD_REPRESENTATIVE (x)))
3556		/* We don't treat zero-width bitfields as making a class
3557		   non-empty.  */
3558		;
3559	      else

leading it to erroneously use the "else" clause, which thus erroneously
clears CLASSTYPE_EMPTY_P, leading to the loss of:

g++.dg/abi/empty22.C:15:6: warning: empty class 'dummy' parameter passing
  ABI changes in -fabi-version=12 (GCC 8) [-Wabi]
   15 |   fun(d, f); // { dg-warning "empty" }
      |   ~~~^~~~~~

check_bitfield_decl is called *after* that check, so the folding there
doesn't help.

> > > > @@ -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);
> > > 
> > > Why is this needed?  What cares about the tree codes of the
> > > capture
> > > initializer?
> > 
> > This is used to populate LAMBDA_EXPR_CAPTURE_LIST.  Without
> > stripping,
> > we end up with wrapped VAR_DECLs, rather than the VAR_DECLs
> > themselves,
> 
> Sure, that sounds fine.
> 
> > and this confuses things later on, for example leading to:
> > 
> >   PASS -> FAIL : g++.dg/cpp0x/lambda/lambda-type.C  -std=c++14
> > (test for excess errors)
> >   PASS -> FAIL : g++.dg/cpp0x/lambda/lambda-type.C  -std=c++17
> > (test for excess errors)
> 
> Confuses how?

Without stripping, we get extra errors for decltype() on identifiers in
the capture-list, e.g.:

  [i] {
    same_type<decltype(i),int>();
    same_type<decltype((i)),int const&>();
  };

cpp0x/lambda/lambda-type.C: In lambda function:
cpp0x/lambda/lambda-type.C:48:27: error: 'i' is not captured
   48 |     same_type<decltype((i)),int const&>();
      |                           ^
cpp0x/lambda/lambda-type.C:48:39: error: template argument 1 is invalid
   48 |     same_type<decltype((i)),int const&>();
      |                                       ^

These occur because, in capture_decltype, when searching for the decl for
"i" here:

  tree cap = value_member (decl, LAMBDA_EXPR_CAPTURE_LIST (lam));

the LAMBDA_EXPR_CAPTURE_LIST contains a wrapper around "i" rather than "i"
itself, and so "i" isn't found by value_member; "cap" thus becomes NULL_TREE,
and thus the error.

Without the stripping, we also gain:

cpp0x/lambda/lambda-type.C: In lambda function:
cpp0x/lambda/lambda-type.C:52:41: error: invalid use of incomplete type
  'struct same_type<int&, const int&>'
   52 |     same_type<decltype((i)),int const&>();
      |                                         ^
cpp0x/lambda/lambda-type.C:17:8: note: declaration of 'struct same_type<int&,
  const int&>'
   17 | struct same_type;
      |        ^~~~~~~~~

> 
> Jason

Thanks for the feedback.

Here's version 4 of the patch, due to rebasing it against today's r267082.

As before, successfully bootstrapped & regrtested on x86_64-pc-linux-gnu, in
conjunction with the followup patch:
  [PATCH 2/2] v2: C++: improvements to binary operator diagnostics (PR c++/87504)
    https://gcc.gnu.org/ml/gcc-patches/2018-12/msg00236.html
updated per your comments (as noted in an earlier version of the 1/2 patch,
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).

OK for trunk?

Thanks
Dave

gcc/c-family/ChangeLog:
	PR c++/43064
	PR c++/43486
	* c-common.c (unsafe_conversion_p): Fold 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/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.
	* convert.h (preserve_any_location_wrapper): New decl.
	* 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/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.
	* 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_has_attribute_expression): Strip any location wrapper
	from "oper".
	(cp_parser_binary_expression): Strip any location wrapper when
	checking for DECL_P on the lhs.
	(cp_parser_decltype): Strip any location wrapper from result of
	cp_parser_decltype_expr.
	(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.
	(cp_parser_std_attribute_spec_seq): Likewise.
	(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.
	(strip_typedefs_expr): Strip any location wrapper before checking
	for decls or constants.
	(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): Call maybe_constant_value on "idx".
	(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/cpp0x/constexpr-47969.C: Update column of expected error.
	* g++.dg/cpp0x/constexpr-ex2.C: Likewise.
	* g++.dg/cpp0x/scoped_enum2.C: Likewise.
	* g++.dg/cpp1z/decomp48.C: Update expected location of warning
	for named local variables to use that of the local variable.
	* g++.dg/ext/vla1.C: Update column.
	* 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/new44.C: Add "-ftrack-macro-expansion=0".
	* 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/other/fold1.C: Update column of expected error.
	* g++.dg/parse/crash36.C: Likewise.
	* g++.dg/wrappers/Wparentheses.C: New test.
	* g++.old-deja/g++.bugs/900402_02.C: Update column of expected
	error.
---
 gcc/c-family/c-common.c                            |  22 ++++
 gcc/c-family/c-pretty-print.c                      |  11 +-
 gcc/c-family/c-warn.c                              |  71 ++++++-----
 gcc/convert.c                                      | 132 +++++++++++++++++++--
 gcc/convert.h                                      |   2 +
 gcc/cp/call.c                                      |   9 +-
 gcc/cp/class.c                                     |   8 ++
 gcc/cp/constexpr.c                                 |  17 ++-
 gcc/cp/cvt.c                                       |  22 ++--
 gcc/cp/decl.c                                      |  33 +++---
 gcc/cp/decl2.c                                     |   2 +
 gcc/cp/expr.c                                      |   2 +
 gcc/cp/init.c                                      |   9 +-
 gcc/cp/lambda.c                                    |   3 +
 gcc/cp/parser.c                                    |  59 +++++++--
 gcc/cp/pt.c                                        |   4 +-
 gcc/cp/semantics.c                                 |  77 ++++++++----
 gcc/cp/tree.c                                      |  16 +++
 gcc/cp/typeck.c                                    | 105 ++++++++++------
 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/cpp0x/constexpr-47969.C       |   2 +-
 gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C         |   2 +-
 gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C          |   2 +-
 gcc/testsuite/g++.dg/cpp1z/decomp48.C              |   8 +-
 gcc/testsuite/g++.dg/ext/vla1.C                    |   2 +-
 gcc/testsuite/g++.dg/init/array43.C                |   2 +-
 .../g++.dg/init/initializer-string-too-long.C      |   9 ++
 gcc/testsuite/g++.dg/init/new44.C                  |   1 +
 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/other/fold1.C                 |   2 +-
 gcc/testsuite/g++.dg/parse/crash36.C               |   2 +-
 gcc/testsuite/g++.dg/wrappers/Wparentheses.C       |  10 ++
 gcc/testsuite/g++.old-deja/g++.bugs/900402_02.C    |   8 +-
 gcc/tree.c                                         |  10 ++
 gcc/tree.h                                         |  19 +++
 42 files changed, 665 insertions(+), 172 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 4c90365..2282515 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -1250,6 +1250,8 @@ unsafe_conversion_p (location_t loc, tree type, tree expr, tree result,
 
     loc = expansion_point_location_if_in_system_header (loc);
 
+  expr = fold_for_warn (expr);
+
   if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST)
     {
       /* If type is complex, we are interested in compatibility with
@@ -1947,6 +1949,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.
@@ -3241,6 +3250,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:
@@ -3460,6 +3470,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;
     }
@@ -6279,6 +6297,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)
@@ -6357,6 +6376,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
@@ -7906,6 +7927,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 798ad1b..4c0bdf9 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.
@@ -1529,6 +1538,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.  */
@@ -1669,15 +1679,22 @@ 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)
+    {
+      /* If INDEX has a location, use it; otherwise use LOC (the location
+	 of the subscripting expression as a whole).  */
+      loc = EXPR_LOC_OR_LOC (index, loc);
+      STRIP_ANY_LOCATION_WRAPPER (index);
+      if (TREE_CODE (index) != INTEGER_CST)
+	warning_at (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..1345d2a 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.  */
+
+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/convert.h b/gcc/convert.h
index 4ffa6ef..f3334f9 100644
--- a/gcc/convert.h
+++ b/gcc/convert.h
@@ -40,4 +40,6 @@ extern inline tree convert_to_real_nofold (tree t, tree x)
 extern inline tree convert_to_complex_nofold (tree t, tree x)
 { return convert_to_complex_maybe_fold (t, x, false); }
 
+extern tree preserve_any_location_wrapper (tree result, tree orig_expr);
+
 #endif /* GCC_CONVERT_H */
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 6328a36..ef3a02c 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5347,9 +5347,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)
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index fec1c5d..28f4965 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -7387,6 +7387,14 @@ 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
+	/* TODO: Recursion may be correct for some non-location-wrapper
+	   uses of VIEW_CONVERT_EXPR.  */
+	return NULL_TREE;
+
     default:
       return NULL_TREE;
     }
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index f804946..517489a 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -5762,13 +5762,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 eb16873..f758f2d 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -582,15 +582,20 @@ 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;
+
+  return preserve_any_location_wrapper (stripped_expr, expr);
 }
 
 /* Fold away simple conversions, but make sure TREE_OVERFLOW is set
@@ -800,10 +805,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 5435ef2..7520ec2 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6005,14 +6005,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);
@@ -6042,16 +6044,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",
@@ -6111,20 +6113,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;
@@ -6139,24 +6143,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);
 	    }
 	}
@@ -16588,6 +16592,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 1b3e758..225c16e 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1051,6 +1051,8 @@ grokbitfield (const cp_declarator *declarator,
       return NULL_TREE;
     }
 
+  STRIP_ANY_LOCATION_WRAPPER (width);
+
   if (TYPE_WARN_IF_NOT_ALIGN (type))
     {
       error_at (DECL_SOURCE_LOCATION (value), "cannot declare bit-field "
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 5a31486..22824bd 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1756,7 +1756,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
@@ -2604,6 +2605,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
@@ -2667,11 +2669,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)
@@ -2762,6 +2766,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 318671b..fbdf887 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -657,6 +657,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/parser.c b/gcc/cp/parser.c
index 8b669a8..05f9efe 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -5232,7 +5232,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:
@@ -5254,9 +5255,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
@@ -7169,8 +7171,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
@@ -8484,6 +8488,8 @@ cp_parser_has_attribute_expression (cp_parser *parser)
   if (!oper || oper == error_mark_node)
     oper = cp_parser_unary_expression (parser);
 
+  STRIP_ANY_LOCATION_WRAPPER (oper);
+
   /* Go back to evaluating expressions.  */
   --cp_unevaluated_operand;
   --c_inhibit_evaluation_warnings;
@@ -9503,7 +9509,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,
@@ -14541,6 +14547,7 @@ cp_parser_decltype (cp_parser *parser)
       ++c_inhibit_evaluation_warnings;
 
       expr = cp_parser_decltype_expr (parser, id_expression_or_member_access_p);
+      STRIP_ANY_LOCATION_WRAPPER (expr);
 
       /* Go back to evaluating expressions.  */
       --cp_unevaluated_operand;
@@ -14918,7 +14925,9 @@ cp_parser_mem_initializer (cp_parser* parser)
       vec = cp_parser_parenthesized_expression_list (parser, non_attr,
 						     /*cast_p=*/false,
 						     /*allow_expansion_p=*/true,
-						     /*non_constant_p=*/NULL);
+						     /*non_constant_p=*/NULL,
+						     /*close_paren_loc=*/NULL,
+						     /*wrap_locations_p=*/true);
       if (vec == NULL)
 	return error_mark_node;
       expression_list = build_tree_list_vec (vec);
@@ -15459,6 +15468,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
@@ -16629,6 +16643,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
@@ -22306,6 +22323,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
@@ -25654,6 +25674,10 @@ cp_parser_gnu_attribute_list (cp_parser* parser, bool exactly_one /* = false */)
   tree attribute_list = NULL_TREE;
   bool save_translate_strings_p = parser->translate_strings_p;
 
+  /* Don't create wrapper nodes within attributes: the
+     handlers don't know how to handle them.  */
+  auto_suppress_location_wrappers sentinel;
+
   parser->translate_strings_p = false;
   while (true)
     {
@@ -26099,6 +26123,10 @@ cp_parser_std_attribute_spec_seq (cp_parser *parser)
   tree attr_specs = NULL_TREE;
   tree attr_last = NULL_TREE;
 
+  /* Don't create wrapper nodes within attributes: the
+     handlers don't know how to handle them.  */
+  auto_suppress_location_wrappers sentinel;
+
   while (true)
     {
       tree attr_spec = cp_parser_std_attribute_spec (parser);
@@ -28540,6 +28568,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.  */
@@ -34873,6 +34909,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;
@@ -36590,6 +36629,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;
@@ -39161,6 +39204,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=*/NULL,
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8560e58..6d2c7b8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6196,6 +6196,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)
@@ -27211,7 +27212,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 c1240cc..e5be33f 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1742,7 +1742,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;
 
@@ -1805,8 +1806,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 ());
 
@@ -2299,19 +2301,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)
     {
@@ -2351,7 +2356,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
@@ -2382,6 +2387,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)
@@ -3523,20 +3530,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 97074df..aac3ece 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -377,6 +377,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:
@@ -421,6 +422,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;
@@ -1715,6 +1717,8 @@ strip_typedefs_expr (tree t, bool *remove_attributes)
   if (t == NULL_TREE || t == error_mark_node)
     return t;
 
+  STRIP_ANY_LOCATION_WRAPPER (t);
+
   if (DECL_P (t) || CONSTANT_CLASS_P (t))
     return t;
 
@@ -2369,6 +2373,8 @@ lookup_maybe_add (tree fns, tree lookup, bool deduping)
 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)
@@ -2417,6 +2423,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)
@@ -5527,6 +5535,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 ac0c811..94bb036 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)))
@@ -3415,6 +3425,8 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
 	 pointer arithmetic.)  */
       idx = cp_perform_integral_promotions (idx, complain);
 
+      idx = maybe_constant_value (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.
@@ -4561,20 +4573,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");
+		}
 	    }
 	}
 
@@ -4596,15 +4611,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;
 	}
@@ -4638,10 +4656,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;
@@ -4842,13 +4861,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
@@ -6080,8 +6103,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)
@@ -8291,7 +8315,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)
 	{
@@ -8810,9 +8835,10 @@ convert_for_assignment (tree type, tree rhs,
   enum tree_code coder;
 
   location_t rhs_loc = EXPR_LOC_OR_LOC (rhs, input_location);
-
-  /* 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
@@ -9186,6 +9212,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)
@@ -9287,6 +9315,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
@@ -9313,6 +9343,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))
@@ -9606,6 +9637,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 64e36ef..c1fa4a9 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -460,14 +460,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.  */
 
@@ -1052,6 +1057,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.  */
@@ -1065,7 +1072,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)));
 
@@ -1113,6 +1120,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)))
 	    {
@@ -1123,12 +1138,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;
 		}
 	    }
@@ -1137,7 +1153,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)
@@ -1162,23 +1178,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 "
@@ -1188,12 +1204,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 45de94c..62ccf7a 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 6d65d24..27be70d 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -81,6 +81,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 2d7cc3b55..3b2298b 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -216,6 +216,7 @@ class test_runner
 extern void attribute_c_tests ();
 extern void bitmap_c_tests ();
 extern void cgraph_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/cpp0x/constexpr-47969.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
index bfd9d8f..9ff2157 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
@@ -9,4 +9,4 @@ struct A
 constexpr A a = A();
 
 int ar[a]; // { dg-error "could not convert" }
-// { dg-error "5:size of array .ar. has non-integral" "" { target c++11 } .-1 }
+// { dg-error "8:size of array .ar. has non-integral" "" { target c++11 } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
index e726a34..f697300 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
@@ -19,4 +19,4 @@ constexpr A a = 42;
 X<a> x;	    // OK: unique conversion to int
 int ar[X<a>::i]; // also OK
 int ary[a]; // { dg-error "could not convert" } ambiguous conversion
-// { dg-error "5:size of array .ary. has non-integral" "" { target c++11 } .-1 }
+// { dg-error "9:size of array .ary. has non-integral" "" { target c++11 } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C b/gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
index 0313c01..c4a869a 100644
--- a/gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
@@ -5,7 +5,7 @@ enum E2 { e2 = 10 };
 
 struct C {
   int arr[E::e];    // { dg-error "could not convert" }
-// { dg-error "7:size of array .arr. has non-integral" "" { target c++11 } .-1 }
+// { dg-error "14:size of array .arr. has non-integral" "" { target c++11 } .-1 }
   int arr2[E2::e2]; // OK
   int i: E::e;	    // { dg-error "could not convert|non-integral type" }
   int i2: E2::e2;   // OK
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/ext/vla1.C b/gcc/testsuite/g++.dg/ext/vla1.C
index d6df686..c017b6e 100644
--- a/gcc/testsuite/g++.dg/ext/vla1.C
+++ b/gcc/testsuite/g++.dg/ext/vla1.C
@@ -19,7 +19,7 @@ class B { B (int); };
 B::B (int i)
 {
   struct S {
-    int ar[1][i];  // { dg-error "9:size of array .ar. is not an integral" "" { target c++11 } }
+    int ar[1][i];  // { dg-error "15:size of array .ar. is not an integral" "" { target c++11 } }
 // { dg-error "array bound" "" { target c++98_only } .-1 }
   } s;
 
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/new44.C b/gcc/testsuite/g++.dg/init/new44.C
index 4ab7320..5c81c2c 100644
--- a/gcc/testsuite/g++.dg/init/new44.C
+++ b/gcc/testsuite/g++.dg/init/new44.C
@@ -1,4 +1,5 @@
 // { dg-do compile }
+// { dg-options "-ftrack-macro-expansion=0" }
 
 // Test for PR c++/67927 - array new expression with excessive number
 // of elements not diagnosed.
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/other/fold1.C b/gcc/testsuite/g++.dg/other/fold1.C
index 25f9acc..8d8df3d 100644
--- a/gcc/testsuite/g++.dg/other/fold1.C
+++ b/gcc/testsuite/g++.dg/other/fold1.C
@@ -4,5 +4,5 @@
 struct A
 {
     static const int i = i;  // { dg-error "not declared" }
-    int x[i];		     // { dg-error "9:size of array .x. is not an integral constant-expression" }
+    int x[i];		     // { dg-error "11:size of array .x. is not an integral constant-expression" }
 };
diff --git a/gcc/testsuite/g++.dg/parse/crash36.C b/gcc/testsuite/g++.dg/parse/crash36.C
index 14fcdd8..8a2b6f3 100644
--- a/gcc/testsuite/g++.dg/parse/crash36.C
+++ b/gcc/testsuite/g++.dg/parse/crash36.C
@@ -9,4 +9,4 @@ template <typename... T> struct A	// { dg-warning "variadic templates" }
   static const int i = sizeof (++t);	// { dg-error "was not declared in this scope" }
 };
 
-int x[A <int>::i];		// { dg-error "5:size of array .x. is not an integral constant-expression" }
+int x[A <int>::i];		// { dg-error "16:size of array .x. is not an integral constant-expression" }
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/testsuite/g++.old-deja/g++.bugs/900402_02.C b/gcc/testsuite/g++.old-deja/g++.bugs/900402_02.C
index 46a3ec3..21e2765 100644
--- a/gcc/testsuite/g++.old-deja/g++.bugs/900402_02.C
+++ b/gcc/testsuite/g++.old-deja/g++.bugs/900402_02.C
@@ -6,17 +6,17 @@
 
 // keywords: arrays, array bound, zero length
 
-typedef int array_type[0];		// { dg-error "13:ISO C\\+\\+ forbids zero-size array" }
+typedef int array_type[0];		// { dg-error "24:ISO C\\+\\+ forbids zero-size array" }
 
-int array_object_1[0];			// { dg-error "5:ISO C\\+\\+ forbids zero-size array" }
+int array_object_1[0];			// { dg-error "20:ISO C\\+\\+ forbids zero-size array" }
 
-void function_0 (int formal_array[0])	// { dg-error "22:ISO C\\+\\+ forbids zero-size array" }
+void function_0 (int formal_array[0])	// { dg-error "35:ISO C\\+\\+ forbids zero-size array" }
 {
 }
 
 void function_2 ()
 {
-  int local_object_array_0[0];		// { dg-error "7:ISO C\\+\\+ forbids zero-size array" }
+  int local_object_array_0[0];		// { dg-error "28:ISO C\\+\\+ forbids zero-size array" }
 }
 
 int main () { return 0; }
diff --git a/gcc/tree.c b/gcc/tree.c
index 170ef13..01b9ec3 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -7106,6 +7106,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))
@@ -14646,6 +14649,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)))
@@ -14656,6 +14664,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 761b508..ab928ca 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)
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] v4: C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
  2018-12-13 19:24           ` [PATCH] v4: " David Malcolm
@ 2018-12-13 20:38             ` Jason Merrill
  2018-12-14 23:29               ` [PATCH] v5: " David Malcolm
  0 siblings, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2018-12-13 20:38 UTC (permalink / raw)
  To: David Malcolm; +Cc: Jeff Law, gcc-patches

On 12/13/18 3:12 PM, David Malcolm wrote:
> On Wed, 2018-12-12 at 15:37 -0500, Jason Merrill wrote:
>> On 12/7/18 3:13 PM, David Malcolm wrote:
>>> On Tue, 2018-12-04 at 18:31 -0500, Jason Merrill wrote:
>>>> On 12/3/18 5:10 PM, Jeff Law wrote:
>>>>> On 11/19/18 9:51 AM, David Malcolm wrote:
>>>
>>> [...]
>>>>> @@ -1058,6 +1058,9 @@ grokbitfield (const cp_declarator
>>>>> *declarator,
>>>>>          return NULL_TREE;
>>>>>        }
>>>>>    
>>>>> +  if (width)
>>>>> +    STRIP_ANY_LOCATION_WRAPPER (width);
>>>>
>>>> Why is this needed?  We should already be reducing width to an
>>>> unwrapped
>>>> constant value somewhere along the line.
>>>
>>> "width" is coming from cp_parser_member_declaration, from:
>>>
>>> 	      /* Get the width of the bitfield.  */
>>> 	      width = cp_parser_constant_expression (parser, false,
>>> NULL,
>>> 						     cxx_dialect >=
>>> cxx11);
>>>
>>> and currently nothing is unwrapping the value.  We presumably need
>>> to
>>> unwrap (or fold?) it before it is stashed in
>>>     DECL_BIT_FIELD_REPRESENTATIVE (value).
>>>
>>> Without stripping (or folding) here, we e.g. lose a warning and get
>>> this:
>>>     FAIL: g++.dg/abi/empty22.C  -std=gnu++98  (test for warnings,
>>> line 15)
>>
>> Why does that happen?  check_bitfield_decl ought to handle the
>> location
>> wrapper fine.  That's where it gets folded.
> 
> The unstripped location wrapper defeats this check for zero in
> check_field_decls within cp/class.c:
> 
> 3555	      if (DECL_C_BIT_FIELD (x)
> 3556		  && integer_zerop (DECL_BIT_FIELD_REPRESENTATIVE (x)))
> 3556		/* We don't treat zero-width bitfields as making a class
> 3557		   non-empty.  */

Aha.  I wonder if integer_zerop should look through location wrappers? 
Or alternately, abort if it gets one?

On a tangent, perhaps we also want a macro like TREE_CODE that looks 
through wrappers.  TREE_CODE_WRAPPED?  _NO_WRAP?  Other name ideas?

> 3558		;
> 3559	      else
> 
> leading it to erroneously use the "else" clause, which thus erroneously
> clears CLASSTYPE_EMPTY_P, leading to the loss of:
> 
> g++.dg/abi/empty22.C:15:6: warning: empty class 'dummy' parameter passing
>    ABI changes in -fabi-version=12 (GCC 8) [-Wabi]
>     15 |   fun(d, f); // { dg-warning "empty" }
>        |   ~~~^~~~~~
> 
> check_bitfield_decl is called *after* that check, so the folding there
> doesn't help.
> 
>>>>> @@ -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);
>>>>
>>>> Why is this needed?  What cares about the tree codes of the
>>>> capture
>>>> initializer?
>>>
>>> This is used to populate LAMBDA_EXPR_CAPTURE_LIST.  Without
>>> stripping,
>>> we end up with wrapped VAR_DECLs, rather than the VAR_DECLs
>>> themselves,
>>
>> Sure, that sounds fine.
>>
>>> and this confuses things later on, for example leading to:
>>>
>>>    PASS -> FAIL : g++.dg/cpp0x/lambda/lambda-type.C  -std=c++14
>>> (test for excess errors)
>>>    PASS -> FAIL : g++.dg/cpp0x/lambda/lambda-type.C  -std=c++17
>>> (test for excess errors)
>>
>> Confuses how?
> 
> Without stripping, we get extra errors for decltype() on identifiers in
> the capture-list, e.g.:
> 
>    [i] {
>      same_type<decltype(i),int>();
>      same_type<decltype((i)),int const&>();
>    };
> 
> cpp0x/lambda/lambda-type.C: In lambda function:
> cpp0x/lambda/lambda-type.C:48:27: error: 'i' is not captured
>     48 |     same_type<decltype((i)),int const&>();
>        |                           ^
> cpp0x/lambda/lambda-type.C:48:39: error: template argument 1 is invalid
>     48 |     same_type<decltype((i)),int const&>();
>        |                                       ^
> 
> These occur because, in capture_decltype, when searching for the decl for
> "i" here:
> 
>    tree cap = value_member (decl, LAMBDA_EXPR_CAPTURE_LIST (lam));
> 
> the LAMBDA_EXPR_CAPTURE_LIST contains a wrapper around "i" rather than "i"
> itself, and so "i" isn't found by value_member; "cap" thus becomes NULL_TREE,
> and thus the error.

Ah.  Just above that I notice,

   /* FIXME do lookup instead of list walk? */

We could make that change, i.e.

tree cap = lookup_name_real (DECL_NAME (decl), /*type*/0, /*nonclass*/1,
                              /*block_p=*/true, /*ns*/0, LOOKUP_HIDDEN);
...
if (cap && is_capture_proxy (cap))

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH] v5: C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
  2018-12-13 20:38             ` Jason Merrill
@ 2018-12-14 23:29               ` David Malcolm
  2018-12-17 19:33                 ` Jason Merrill
  0 siblings, 1 reply; 34+ messages in thread
From: David Malcolm @ 2018-12-14 23:29 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jeff Law, gcc-patches, David Malcolm

On Thu, 2018-12-13 at 15:37 -0500, Jason Merrill wrote:
> On 12/13/18 3:12 PM, David Malcolm wrote:
> > On Wed, 2018-12-12 at 15:37 -0500, Jason Merrill wrote:
> > > On 12/7/18 3:13 PM, David Malcolm wrote:
> > > > On Tue, 2018-12-04 at 18:31 -0500, Jason Merrill wrote:
> > > > > On 12/3/18 5:10 PM, Jeff Law wrote:
> > > > > > On 11/19/18 9:51 AM, David Malcolm wrote:
> > > > 
> > > > [...]
> > > > > > @@ -1058,6 +1058,9 @@ grokbitfield (const cp_declarator
> > > > > > *declarator,
> > > > > >          return NULL_TREE;
> > > > > >        }
> > > > > >    
> > > > > > +  if (width)
> > > > > > +    STRIP_ANY_LOCATION_WRAPPER (width);
> > > > > 
> > > > > Why is this needed?  We should already be reducing width to
> > > > > an
> > > > > unwrapped
> > > > > constant value somewhere along the line.
> > > > 
> > > > "width" is coming from cp_parser_member_declaration, from:
> > > > 
> > > > 	      /* Get the width of the bitfield.  */
> > > > 	      width = cp_parser_constant_expression (parser,
> > > > false,
> > > > NULL,
> > > > 						     cxx_dialec
> > > > t >=
> > > > cxx11);
> > > > 
> > > > and currently nothing is unwrapping the value.  We presumably
> > > > need
> > > > to
> > > > unwrap (or fold?) it before it is stashed in
> > > >     DECL_BIT_FIELD_REPRESENTATIVE (value).
> > > > 
> > > > Without stripping (or folding) here, we e.g. lose a warning and
> > > > get
> > > > this:
> > > >     FAIL: g++.dg/abi/empty22.C  -std=gnu++98  (test for
> > > > warnings,
> > > > line 15)
> > > 
> > > Why does that happen?  check_bitfield_decl ought to handle the
> > > location
> > > wrapper fine.  That's where it gets folded.
> > 
> > The unstripped location wrapper defeats this check for zero in
> > check_field_decls within cp/class.c:
> > 
> > 3555	      if (DECL_C_BIT_FIELD (x)
> > 3556		  && integer_zerop
> > (DECL_BIT_FIELD_REPRESENTATIVE (x)))
> > 3556		/* We don't treat zero-width bitfields as
> > making a class
> > 3557		   non-empty.  */
> 
> Aha.  I wonder if integer_zerop should look through location
> wrappers? 
> Or alternately, abort if it gets one?
> 
> On a tangent, perhaps we also want a macro like TREE_CODE that looks 
> through wrappers.  TREE_CODE_WRAPPED?  _NO_WRAP?  Other name ideas?

Here's a v5 of the patch which makes integer_zerop (and various other
predicates) look through location wrappers.  I added a selftest for them
to tree.c (selftest::test_predicates).

There are a few places which do things like:

  if (integer_zerop (expr) && !TREE_OVERFLOW (expr))

so I converted these to:

  if (integer_zerop (expr)
      && !TREE_OVERFLOW (tree_strip_any_location_wrapper (expr)))

i.e. to use TREE_OVERFLOW on the constant, rather than on the wrapper.

[I first attempted the "abort if it gets one" approach, via:
  gcc_assert (!location_wrapper_p (expr))
but it led to numerous bootstrap and test failures, and lots of
stripping, so doing it within the predicates seemed cleaner]

> > 3558		;
> > 3559	      else
> > 
> > leading it to erroneously use the "else" clause, which thus
> > erroneously
> > clears CLASSTYPE_EMPTY_P, leading to the loss of:
> > 
> > g++.dg/abi/empty22.C:15:6: warning: empty class 'dummy' parameter
> > passing
> >    ABI changes in -fabi-version=12 (GCC 8) [-Wabi]
> >     15 |   fun(d, f); // { dg-warning "empty" }
> >        |   ~~~^~~~~~
> > 
> > check_bitfield_decl is called *after* that check, so the folding
> > there
> > doesn't help.

With the conversion of integer_zerop to look through location wrappers,
I removed the stripping from grokbitfield.  This turned up one other
site that uses DECL_BIT_FIELD_REPRESENTATIVE, in objc's
gen_declaration (for obj-c++), so the v5 patch looks through wrappers
there.

> > > > > > @@ -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);
> > > > > 
> > > > > Why is this needed?  What cares about the tree codes of the
> > > > > capture
> > > > > initializer?
> > > > 
> > > > This is used to populate LAMBDA_EXPR_CAPTURE_LIST.  Without
> > > > stripping,
> > > > we end up with wrapped VAR_DECLs, rather than the VAR_DECLs
> > > > themselves,
> > > 
> > > Sure, that sounds fine.
> > > 
> > > > and this confuses things later on, for example leading to:
> > > > 
> > > >    PASS -> FAIL : g++.dg/cpp0x/lambda/lambda-type.C  -std=c++14
> > > > (test for excess errors)
> > > >    PASS -> FAIL : g++.dg/cpp0x/lambda/lambda-type.C  -std=c++17
> > > > (test for excess errors)
> > > 
> > > Confuses how?
> > 
> > Without stripping, we get extra errors for decltype() on
> > identifiers in
> > the capture-list, e.g.:
> > 
> >    [i] {
> >      same_type<decltype(i),int>();
> >      same_type<decltype((i)),int const&>();
> >    };
> > 
> > cpp0x/lambda/lambda-type.C: In lambda function:
> > cpp0x/lambda/lambda-type.C:48:27: error: 'i' is not captured
> >     48 |     same_type<decltype((i)),int const&>();
> >        |                           ^
> > cpp0x/lambda/lambda-type.C:48:39: error: template argument 1 is
> > invalid
> >     48 |     same_type<decltype((i)),int const&>();
> >        |                                       ^
> > 
> > These occur because, in capture_decltype, when searching for the
> > decl for
> > "i" here:
> > 
> >    tree cap = value_member (decl, LAMBDA_EXPR_CAPTURE_LIST (lam));
> > 
> > the LAMBDA_EXPR_CAPTURE_LIST contains a wrapper around "i" rather
> > than "i"
> > itself, and so "i" isn't found by value_member; "cap" thus becomes
> > NULL_TREE,
> > and thus the error.
> 
> Ah.  Just above that I notice,
> 
>    /* FIXME do lookup instead of list walk? */
> 
> We could make that change, i.e.
> 
> tree cap = lookup_name_real (DECL_NAME (decl), /*type*/0,
> /*nonclass*/1,
>                               /*block_p=*/true, /*ns*/0,
> LOOKUP_HIDDEN);
> ...
> if (cap && is_capture_proxy (cap))

In the v5 patch I eliminated the stripping when adding initializers to
a LAMBDA_EXPR_CAPTURE_LIST, and made the change you proposed above,
to use lookup_name_real rather than list traversal in capture_decltype.

> Jason

Thanks for the feedback.

The v5 patch makes two other changes:

- it reinstates folding of negated constants in
  cp_parser_unary_expression so that "-1" is parsed as a
  location wrapper around INTEGER_CST(-1), rather than a
  NEGATE_EXPR (location_wrapper (INTEGER_CST(1)))

- it adds assertions to build_complex, to ensure that the real/imaginary
  arguments are actually constants (and not location wrappers).

As before, this was successfully bootstrapped & regrtested on
x86_64-pc-linux-gnu, in conjunction with the followup patch.

OK for trunk?
Dave

ChangeLog for v5:

gcc/c-family/ChangeLog:
	PR c++/43064
	PR c++/43486
	* c-common.c (unsafe_conversion_p): Fold 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/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): Strip expr when using TREE_OVERFLOW.
	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.
	* convert.h (preserve_any_location_wrapper): New decl.
	* fold-const.c (size_binop_loc): Strip location wrappers when
	using TREE_OVERFLOW.
	(operand_equal_p): Strip any location wrappers.
	(integer_valued_real_p): Strip any location wrapper.
	* selftest-run-tests.c (selftest::run_tests): Call
	selftest::convert_c_tests.
	* selftest.h (selftest::convert_c_tests): New decl.
	* tree.c (build_complex): Assert that REAL and IMAG are constants.
	(integer_zerop): Look through location wrappers.
	(integer_onep): Likewise.
	(integer_each_onep): Likewise.
	(integer_all_onesp): Likewise.
	(integer_minus_onep): Likewise.
	(integer_pow2p): Likewise.
	(integer_nonzerop): Likewise.
	(integer_truep): Likewise.
	(fixed_zerop): Likewise.
	(real_zerop): Likewise.
	(real_onep): Likewise.
	(real_minus_onep): Likewise.
	(tree_int_cst_equal): Likewise.
	(uniform_integer_cst_p): Likewise.
	(maybe_wrap_with_location): Don't create wrappers if any
	auto_suppress_location_wrappers are active.
	(suppress_location_wrappers): New variable.
	(selftest::test_predicates): New test.
	(selftest::tree_c_tests): Call it.
	* tree.h (CONSTANT_CLASS_OR_WRAPPER_P): New macro.
	(suppress_location_wrappers): New decl.
	(class auto_suppress_location_wrappers): New class.

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.
	* 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.
	* 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_unary_expression): Ensure that folding of NEGATE_EXPR
	around a constant happens in the presence of location wrappers and
	returns a wrapped result.
	(cp_parser_has_attribute_expression): Strip any location wrapper
	from "oper".
	(cp_parser_binary_expression): Strip any location wrapper when
	checking for DECL_P on the lhs.
	(cp_parser_decltype): Strip any location wrapper from result of
	cp_parser_decltype_expr.
	(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.
	(cp_parser_std_attribute_spec_seq): Likewise.
	(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.
	(capture_decltype): Use lookup_name_real rather than value_member
	when looking up decl within the capture-list.
	* tree.c (cp_stabilize_reference): Strip any location wrapper.
	(builtin_valid_in_constant_expr_p): Likewise.
	(strip_typedefs_expr): Strip any location wrapper before checking
	for decls or constants.
	(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): Call maybe_constant_value on "idx".
	(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.
	(gen_declaration): Strip location wrappers from "w".

gcc/testsuite/ChangeLog:
	PR c++/43064
	PR c++/43486
	* c-c++-common/pr51712.c (valid2): Mark xfail as passing on C++.
	* g++.dg/cpp0x/constexpr-47969.C: Update column of expected error.
	* g++.dg/cpp0x/constexpr-ex2.C: Likewise.
	* g++.dg/cpp0x/scoped_enum2.C: Likewise.
	* g++.dg/cpp1z/decomp48.C: Update expected location of warning
	for named local variables to use that of the local variable.
	* g++.dg/ext/vla1.C: Update column.
	* 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/new44.C: Add "-ftrack-macro-expansion=0".
	* 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/other/fold1.C: Update column of expected error.
	* g++.dg/parse/crash36.C: Likewise.
	* g++.dg/plugin/diagnostic-test-expressions-1.C: Add negative
	integer and float expressions.
	* g++.dg/wrappers/Wparentheses.C: New test.
	* g++.old-deja/g++.bugs/900402_02.C: Update column of expected
	error.
---
 gcc/c-family/c-common.c                            |  22 ++
 gcc/c-family/c-pretty-print.c                      |  11 +-
 gcc/c-family/c-warn.c                              |  71 ++--
 gcc/convert.c                                      | 135 ++++++-
 gcc/convert.h                                      |   2 +
 gcc/cp/call.c                                      |   9 +-
 gcc/cp/class.c                                     |   8 +
 gcc/cp/constexpr.c                                 |  17 +-
 gcc/cp/cvt.c                                       |  22 +-
 gcc/cp/decl.c                                      |  33 +-
 gcc/cp/expr.c                                      |   2 +
 gcc/cp/init.c                                      |   9 +-
 gcc/cp/parser.c                                    |  83 ++++-
 gcc/cp/pt.c                                        |   4 +-
 gcc/cp/semantics.c                                 |  85 +++--
 gcc/cp/tree.c                                      |  16 +
 gcc/cp/typeck.c                                    | 105 ++++--
 gcc/cp/typeck2.c                                   |  56 +--
 gcc/fold-const.c                                   |  17 +-
 gcc/objc/objc-act.c                                |  14 +-
 gcc/selftest-run-tests.c                           |   1 +
 gcc/selftest.h                                     |   1 +
 gcc/testsuite/c-c++-common/pr51712.c               |   2 +-
 gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C       |   2 +-
 gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C         |   2 +-
 gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C          |   2 +-
 gcc/testsuite/g++.dg/cpp1z/decomp48.C              |   8 +-
 gcc/testsuite/g++.dg/ext/vla1.C                    |   2 +-
 gcc/testsuite/g++.dg/init/array43.C                |   2 +-
 .../g++.dg/init/initializer-string-too-long.C      |   9 +
 gcc/testsuite/g++.dg/init/new44.C                  |   1 +
 gcc/testsuite/g++.dg/init/pr43064-1.C              |  37 ++
 gcc/testsuite/g++.dg/init/pr43064-2.C              |  34 ++
 gcc/testsuite/g++.dg/init/pr43064-3.C              |  32 ++
 gcc/testsuite/g++.dg/other/fold1.C                 |   2 +-
 gcc/testsuite/g++.dg/parse/crash36.C               |   2 +-
 .../g++.dg/plugin/diagnostic-test-expressions-1.C  |  14 +
 gcc/testsuite/g++.dg/wrappers/Wparentheses.C       |  10 +
 gcc/testsuite/g++.old-deja/g++.bugs/900402_02.C    |   8 +-
 gcc/tree.c                                         | 393 ++++++++++++++++++++-
 gcc/tree.h                                         |  19 +
 41 files changed, 1097 insertions(+), 207 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 4c90365..2282515 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -1250,6 +1250,8 @@ unsafe_conversion_p (location_t loc, tree type, tree expr, tree result,
 
     loc = expansion_point_location_if_in_system_header (loc);
 
+  expr = fold_for_warn (expr);
+
   if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST)
     {
       /* If type is complex, we are interested in compatibility with
@@ -1947,6 +1949,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.
@@ -3241,6 +3250,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:
@@ -3460,6 +3470,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;
     }
@@ -6279,6 +6297,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)
@@ -6357,6 +6376,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
@@ -7906,6 +7927,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 798ad1b..4c0bdf9 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.
@@ -1529,6 +1538,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.  */
@@ -1669,15 +1679,22 @@ 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)
+    {
+      /* If INDEX has a location, use it; otherwise use LOC (the location
+	 of the subscripting expression as a whole).  */
+      loc = EXPR_LOC_OR_LOC (index, loc);
+      STRIP_ANY_LOCATION_WRAPPER (index);
+      if (TREE_CODE (index) != INTEGER_CST)
+	warning_at (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..028497f 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.  */
+
+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
@@ -679,7 +705,8 @@ convert_to_integer_1 (tree type, tree expr, bool dofold)
     {
     case POINTER_TYPE:
     case REFERENCE_TYPE:
-      if (integer_zerop (expr) && !TREE_OVERFLOW (expr))
+      if (integer_zerop (expr)
+	  && !TREE_OVERFLOW (tree_strip_any_location_wrapper (expr)))
 	return build_int_cst (type, 0);
 
       /* Convert to an unsigned integer of the correct width first, and from
@@ -959,7 +986,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 +1044,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 +1131,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 +1204,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/convert.h b/gcc/convert.h
index 4ffa6ef..f3334f9 100644
--- a/gcc/convert.h
+++ b/gcc/convert.h
@@ -40,4 +40,6 @@ extern inline tree convert_to_real_nofold (tree t, tree x)
 extern inline tree convert_to_complex_nofold (tree t, tree x)
 { return convert_to_complex_maybe_fold (t, x, false); }
 
+extern tree preserve_any_location_wrapper (tree result, tree orig_expr);
+
 #endif /* GCC_CONVERT_H */
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 6328a36..ef3a02c 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5347,9 +5347,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)
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index fec1c5d..28f4965 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -7387,6 +7387,14 @@ 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
+	/* TODO: Recursion may be correct for some non-location-wrapper
+	   uses of VIEW_CONVERT_EXPR.  */
+	return NULL_TREE;
+
     default:
       return NULL_TREE;
     }
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index f804946..517489a 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -5762,13 +5762,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 eb16873..f758f2d 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -582,15 +582,20 @@ 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;
+
+  return preserve_any_location_wrapper (stripped_expr, expr);
 }
 
 /* Fold away simple conversions, but make sure TREE_OVERFLOW is set
@@ -800,10 +805,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 5435ef2..7520ec2 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6005,14 +6005,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);
@@ -6042,16 +6044,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",
@@ -6111,20 +6113,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;
@@ -6139,24 +6143,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);
 	    }
 	}
@@ -16588,6 +16592,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/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 5a31486..22824bd 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1756,7 +1756,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
@@ -2604,6 +2605,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
@@ -2667,11 +2669,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)
@@ -2762,6 +2766,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/parser.c b/gcc/cp/parser.c
index 8b669a8..4433f3b 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -5232,7 +5232,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:
@@ -5254,9 +5255,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
@@ -7169,8 +7171,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
@@ -8358,18 +8362,22 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
 	case NEGATE_EXPR:
 	  /* Immediately fold negation of a constant, unless the constant is 0
 	     (since -0 == 0) or it would overflow.  */
-	  if (unary_operator == NEGATE_EXPR && op_ttype == CPP_NUMBER
-	      && CONSTANT_CLASS_P (cast_expression)
-	      && !integer_zerop (cast_expression)
-	      && !TREE_OVERFLOW (cast_expression))
+	  if (unary_operator == NEGATE_EXPR && op_ttype == CPP_NUMBER)
 	    {
-	      tree folded = fold_build1 (unary_operator,
-					 TREE_TYPE (cast_expression),
-					 cast_expression);
-	      if (CONSTANT_CLASS_P (folded) && !TREE_OVERFLOW (folded))
+	      tree stripped_expr
+		= tree_strip_any_location_wrapper (cast_expression);
+	      if (CONSTANT_CLASS_P (stripped_expr)
+		  && !integer_zerop (stripped_expr)
+		  && !TREE_OVERFLOW (stripped_expr))
 		{
-		  expression = cp_expr (folded, loc);
-		  break;
+		  tree folded = fold_build1 (unary_operator,
+					     TREE_TYPE (stripped_expr),
+					     stripped_expr);
+		  if (CONSTANT_CLASS_P (folded) && !TREE_OVERFLOW (folded))
+		    {
+		      expression = maybe_wrap_with_location (folded, loc);
+		      break;
+		    }
 		}
 	    }
 	  /* Fall through.  */
@@ -8484,6 +8492,8 @@ cp_parser_has_attribute_expression (cp_parser *parser)
   if (!oper || oper == error_mark_node)
     oper = cp_parser_unary_expression (parser);
 
+  STRIP_ANY_LOCATION_WRAPPER (oper);
+
   /* Go back to evaluating expressions.  */
   --cp_unevaluated_operand;
   --c_inhibit_evaluation_warnings;
@@ -9503,7 +9513,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,
@@ -14541,6 +14551,7 @@ cp_parser_decltype (cp_parser *parser)
       ++c_inhibit_evaluation_warnings;
 
       expr = cp_parser_decltype_expr (parser, id_expression_or_member_access_p);
+      STRIP_ANY_LOCATION_WRAPPER (expr);
 
       /* Go back to evaluating expressions.  */
       --cp_unevaluated_operand;
@@ -14918,7 +14929,9 @@ cp_parser_mem_initializer (cp_parser* parser)
       vec = cp_parser_parenthesized_expression_list (parser, non_attr,
 						     /*cast_p=*/false,
 						     /*allow_expansion_p=*/true,
-						     /*non_constant_p=*/NULL);
+						     /*non_constant_p=*/NULL,
+						     /*close_paren_loc=*/NULL,
+						     /*wrap_locations_p=*/true);
       if (vec == NULL)
 	return error_mark_node;
       expression_list = build_tree_list_vec (vec);
@@ -15459,6 +15472,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
@@ -16629,6 +16647,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
@@ -22306,6 +22327,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
@@ -25654,6 +25678,10 @@ cp_parser_gnu_attribute_list (cp_parser* parser, bool exactly_one /* = false */)
   tree attribute_list = NULL_TREE;
   bool save_translate_strings_p = parser->translate_strings_p;
 
+  /* Don't create wrapper nodes within attributes: the
+     handlers don't know how to handle them.  */
+  auto_suppress_location_wrappers sentinel;
+
   parser->translate_strings_p = false;
   while (true)
     {
@@ -26099,6 +26127,10 @@ cp_parser_std_attribute_spec_seq (cp_parser *parser)
   tree attr_specs = NULL_TREE;
   tree attr_last = NULL_TREE;
 
+  /* Don't create wrapper nodes within attributes: the
+     handlers don't know how to handle them.  */
+  auto_suppress_location_wrappers sentinel;
+
   while (true)
     {
       tree attr_spec = cp_parser_std_attribute_spec (parser);
@@ -28540,6 +28572,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.  */
@@ -34873,6 +34913,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;
@@ -36590,6 +36633,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;
@@ -39161,6 +39208,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=*/NULL,
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8560e58..6d2c7b8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6196,6 +6196,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)
@@ -27211,7 +27212,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 c1240cc..792ea07 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1742,7 +1742,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;
 
@@ -1805,8 +1806,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 ());
 
@@ -2299,19 +2301,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)
     {
@@ -2351,7 +2356,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
@@ -2382,6 +2387,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)
@@ -3523,20 +3530,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.  */
 
@@ -9765,12 +9800,12 @@ static tree
 capture_decltype (tree decl)
 {
   tree lam = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (current_function_decl));
-  /* FIXME do lookup instead of list walk? */
-  tree cap = value_member (decl, LAMBDA_EXPR_CAPTURE_LIST (lam));
+  tree cap = lookup_name_real (DECL_NAME (decl), /*type*/0, /*nonclass*/1,
+			       /*block_p=*/true, /*ns*/0, LOOKUP_HIDDEN);
   tree type;
 
-  if (cap)
-    type = TREE_TYPE (TREE_PURPOSE (cap));
+  if (cap && is_capture_proxy (cap))
+    type = TREE_TYPE (cap);
   else
     switch (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam))
       {
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 97074df..aac3ece 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -377,6 +377,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:
@@ -421,6 +422,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;
@@ -1715,6 +1717,8 @@ strip_typedefs_expr (tree t, bool *remove_attributes)
   if (t == NULL_TREE || t == error_mark_node)
     return t;
 
+  STRIP_ANY_LOCATION_WRAPPER (t);
+
   if (DECL_P (t) || CONSTANT_CLASS_P (t))
     return t;
 
@@ -2369,6 +2373,8 @@ lookup_maybe_add (tree fns, tree lookup, bool deduping)
 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)
@@ -2417,6 +2423,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)
@@ -5527,6 +5535,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 ac0c811..94bb036 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)))
@@ -3415,6 +3425,8 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
 	 pointer arithmetic.)  */
       idx = cp_perform_integral_promotions (idx, complain);
 
+      idx = maybe_constant_value (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.
@@ -4561,20 +4573,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");
+		}
 	    }
 	}
 
@@ -4596,15 +4611,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;
 	}
@@ -4638,10 +4656,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;
@@ -4842,13 +4861,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
@@ -6080,8 +6103,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)
@@ -8291,7 +8315,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)
 	{
@@ -8810,9 +8835,10 @@ convert_for_assignment (tree type, tree rhs,
   enum tree_code coder;
 
   location_t rhs_loc = EXPR_LOC_OR_LOC (rhs, input_location);
-
-  /* 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
@@ -9186,6 +9212,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)
@@ -9287,6 +9315,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
@@ -9313,6 +9343,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))
@@ -9606,6 +9637,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 64e36ef..c1fa4a9 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -460,14 +460,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.  */
 
@@ -1052,6 +1057,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.  */
@@ -1065,7 +1072,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)));
 
@@ -1113,6 +1120,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)))
 	    {
@@ -1123,12 +1138,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;
 		}
 	    }
@@ -1137,7 +1153,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)
@@ -1162,23 +1178,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 "
@@ -1188,12 +1204,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 45de94c..1851a3d 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -1911,19 +1911,23 @@ size_binop_loc (location_t loc, enum tree_code code, tree arg0, tree arg1)
       /* And some specific cases even faster than that.  */
       if (code == PLUS_EXPR)
 	{
-	  if (integer_zerop (arg0) && !TREE_OVERFLOW (arg0))
+	  if (integer_zerop (arg0)
+	      && !TREE_OVERFLOW (tree_strip_any_location_wrapper (arg0)))
 	    return arg1;
-	  if (integer_zerop (arg1) && !TREE_OVERFLOW (arg1))
+	  if (integer_zerop (arg1)
+	      && !TREE_OVERFLOW (tree_strip_any_location_wrapper (arg1)))
 	    return arg0;
 	}
       else if (code == MINUS_EXPR)
 	{
-	  if (integer_zerop (arg1) && !TREE_OVERFLOW (arg1))
+	  if (integer_zerop (arg1)
+	      && !TREE_OVERFLOW (tree_strip_any_location_wrapper (arg1)))
 	    return arg0;
 	}
       else if (code == MULT_EXPR)
 	{
-	  if (integer_onep (arg0) && !TREE_OVERFLOW (arg0))
+	  if (integer_onep (arg0)
+	      && !TREE_OVERFLOW (tree_strip_any_location_wrapper (arg0)))
 	    return arg1;
 	}
 
@@ -2938,6 +2942,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.  */
@@ -13681,6 +13688,8 @@ integer_valued_real_p (tree t, int depth)
   if (t == error_mark_node)
     return false;
 
+  STRIP_ANY_LOCATION_WRAPPER (t);
+
   tree_code code = TREE_CODE (t);
   switch (TREE_CODE_CLASS (code))
     {
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index d086930..42b2fc2 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);
 
@@ -8906,9 +8910,13 @@ gen_declaration (tree decl)
 #else
       tree w = DECL_INITIAL (decl);
 #endif
-      if (w && TREE_CODE (w) == INTEGER_CST)
-	sprintf (errbuf + strlen (errbuf), ": " HOST_WIDE_INT_PRINT_DEC,
-		 TREE_INT_CST_LOW (w));
+      if (w)
+	{
+	  STRIP_ANY_LOCATION_WRAPPER (w);
+	  if (TREE_CODE (w) == INTEGER_CST)
+	    sprintf (errbuf + strlen (errbuf), ": " HOST_WIDE_INT_PRINT_DEC,
+		     TREE_INT_CST_LOW (w));
+	}
     }
 
   return errbuf;
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index 6d65d24..27be70d 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -81,6 +81,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 2d7cc3b55..3b2298b 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -216,6 +216,7 @@ class test_runner
 extern void attribute_c_tests ();
 extern void bitmap_c_tests ();
 extern void cgraph_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/cpp0x/constexpr-47969.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
index bfd9d8f..9ff2157 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
@@ -9,4 +9,4 @@ struct A
 constexpr A a = A();
 
 int ar[a]; // { dg-error "could not convert" }
-// { dg-error "5:size of array .ar. has non-integral" "" { target c++11 } .-1 }
+// { dg-error "8:size of array .ar. has non-integral" "" { target c++11 } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
index e726a34..f697300 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
@@ -19,4 +19,4 @@ constexpr A a = 42;
 X<a> x;	    // OK: unique conversion to int
 int ar[X<a>::i]; // also OK
 int ary[a]; // { dg-error "could not convert" } ambiguous conversion
-// { dg-error "5:size of array .ary. has non-integral" "" { target c++11 } .-1 }
+// { dg-error "9:size of array .ary. has non-integral" "" { target c++11 } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C b/gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
index 0313c01..c4a869a 100644
--- a/gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
@@ -5,7 +5,7 @@ enum E2 { e2 = 10 };
 
 struct C {
   int arr[E::e];    // { dg-error "could not convert" }
-// { dg-error "7:size of array .arr. has non-integral" "" { target c++11 } .-1 }
+// { dg-error "14:size of array .arr. has non-integral" "" { target c++11 } .-1 }
   int arr2[E2::e2]; // OK
   int i: E::e;	    // { dg-error "could not convert|non-integral type" }
   int i2: E2::e2;   // OK
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/ext/vla1.C b/gcc/testsuite/g++.dg/ext/vla1.C
index d6df686..c017b6e 100644
--- a/gcc/testsuite/g++.dg/ext/vla1.C
+++ b/gcc/testsuite/g++.dg/ext/vla1.C
@@ -19,7 +19,7 @@ class B { B (int); };
 B::B (int i)
 {
   struct S {
-    int ar[1][i];  // { dg-error "9:size of array .ar. is not an integral" "" { target c++11 } }
+    int ar[1][i];  // { dg-error "15:size of array .ar. is not an integral" "" { target c++11 } }
 // { dg-error "array bound" "" { target c++98_only } .-1 }
   } s;
 
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/new44.C b/gcc/testsuite/g++.dg/init/new44.C
index 4ab7320..5c81c2c 100644
--- a/gcc/testsuite/g++.dg/init/new44.C
+++ b/gcc/testsuite/g++.dg/init/new44.C
@@ -1,4 +1,5 @@
 // { dg-do compile }
+// { dg-options "-ftrack-macro-expansion=0" }
 
 // Test for PR c++/67927 - array new expression with excessive number
 // of elements not diagnosed.
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..171061b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/pr43064-1.C
@@ -0,0 +1,37 @@
+/* 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 "" } */
+};
+
+class Y {
+  Y() : bad(-1), // { dg-error "invalid conversion from 'int' to 'void\\*'" }
+	good(42)
+  { }
+  
+  void* bad;
+  int good;
+
+  /* { dg-begin-multiline-output "" }
+   Y() : bad(-1),
+             ^~
+             |
+             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/other/fold1.C b/gcc/testsuite/g++.dg/other/fold1.C
index 25f9acc..8d8df3d 100644
--- a/gcc/testsuite/g++.dg/other/fold1.C
+++ b/gcc/testsuite/g++.dg/other/fold1.C
@@ -4,5 +4,5 @@
 struct A
 {
     static const int i = i;  // { dg-error "not declared" }
-    int x[i];		     // { dg-error "9:size of array .x. is not an integral constant-expression" }
+    int x[i];		     // { dg-error "11:size of array .x. is not an integral constant-expression" }
 };
diff --git a/gcc/testsuite/g++.dg/parse/crash36.C b/gcc/testsuite/g++.dg/parse/crash36.C
index 14fcdd8..8a2b6f3 100644
--- a/gcc/testsuite/g++.dg/parse/crash36.C
+++ b/gcc/testsuite/g++.dg/parse/crash36.C
@@ -9,4 +9,4 @@ template <typename... T> struct A	// { dg-warning "variadic templates" }
   static const int i = sizeof (++t);	// { dg-error "was not declared in this scope" }
 };
 
-int x[A <int>::i];		// { dg-error "5:size of array .x. is not an integral constant-expression" }
+int x[A <int>::i];		// { dg-error "16:size of array .x. is not an integral constant-expression" }
diff --git a/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C b/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C
index c08fec4..288da2c 100644
--- a/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C
+++ b/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C
@@ -63,6 +63,13 @@ void test_integer_constants (void)
    __emit_expression_range (0, 0);
                                ^
    { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, -273); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, -273);
+                               ^~~~
+   { dg-end-multiline-output "" } */
+
 }
 
 void test_character_constants (void)
@@ -111,6 +118,13 @@ void test_floating_constants (void)
    __emit_expression_range (0, 6.022140857e23l );
                                ^~~~~~~~~~~~~~~
    { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, -273.15f); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, -273.15f);
+                               ^~~~~~~~
+   { dg-end-multiline-output "" } */
+
 }
 
 enum test_enum {
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/testsuite/g++.old-deja/g++.bugs/900402_02.C b/gcc/testsuite/g++.old-deja/g++.bugs/900402_02.C
index 46a3ec3..21e2765 100644
--- a/gcc/testsuite/g++.old-deja/g++.bugs/900402_02.C
+++ b/gcc/testsuite/g++.old-deja/g++.bugs/900402_02.C
@@ -6,17 +6,17 @@
 
 // keywords: arrays, array bound, zero length
 
-typedef int array_type[0];		// { dg-error "13:ISO C\\+\\+ forbids zero-size array" }
+typedef int array_type[0];		// { dg-error "24:ISO C\\+\\+ forbids zero-size array" }
 
-int array_object_1[0];			// { dg-error "5:ISO C\\+\\+ forbids zero-size array" }
+int array_object_1[0];			// { dg-error "20:ISO C\\+\\+ forbids zero-size array" }
 
-void function_0 (int formal_array[0])	// { dg-error "22:ISO C\\+\\+ forbids zero-size array" }
+void function_0 (int formal_array[0])	// { dg-error "35:ISO C\\+\\+ forbids zero-size array" }
 {
 }
 
 void function_2 ()
 {
-  int local_object_array_0[0];		// { dg-error "7:ISO C\\+\\+ forbids zero-size array" }
+  int local_object_array_0[0];		// { dg-error "28:ISO C\\+\\+ forbids zero-size array" }
 }
 
 int main () { return 0; }
diff --git a/gcc/tree.c b/gcc/tree.c
index 170ef13..022fc6d 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -2208,6 +2208,9 @@ build_string (int len, const char *str)
 tree
 build_complex (tree type, tree real, tree imag)
 {
+  gcc_assert (CONSTANT_CLASS_P (real));
+  gcc_assert (CONSTANT_CLASS_P (imag));
+
   tree t = make_node (COMPLEX_CST);
 
   TREE_REALPART (t) = real;
@@ -2506,11 +2509,13 @@ zerop (const_tree expr)
 }
 
 /* Return 1 if EXPR is the integer constant zero or a complex constant
-   of zero.  */
+   of zero, or a location wrapper for such a constant.  */
 
 bool
 integer_zerop (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   switch (TREE_CODE (expr))
     {
     case INTEGER_CST:
@@ -2528,11 +2533,13 @@ integer_zerop (const_tree expr)
 }
 
 /* Return 1 if EXPR is the integer constant one or the corresponding
-   complex constant.  */
+   complex constant, or a location wrapper for such a constant.  */
 
 bool
 integer_onep (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   switch (TREE_CODE (expr))
     {
     case INTEGER_CST:
@@ -2550,11 +2557,14 @@ integer_onep (const_tree expr)
 }
 
 /* Return 1 if EXPR is the integer constant one.  For complex and vector,
-   return 1 if every piece is the integer constant one.  */
+   return 1 if every piece is the integer constant one.
+   Also return 1 for location wrappers for such a constant.  */
 
 bool
 integer_each_onep (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   if (TREE_CODE (expr) == COMPLEX_CST)
     return (integer_onep (TREE_REALPART (expr))
 	    && integer_onep (TREE_IMAGPART (expr)));
@@ -2563,11 +2573,14 @@ integer_each_onep (const_tree expr)
 }
 
 /* Return 1 if EXPR is an integer containing all 1's in as much precision as
-   it contains, or a complex or vector whose subparts are such integers.  */
+   it contains, or a complex or vector whose subparts are such integers,
+   or a location wrapper for such a constant.  */
 
 bool
 integer_all_onesp (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   if (TREE_CODE (expr) == COMPLEX_CST
       && integer_all_onesp (TREE_REALPART (expr))
       && integer_all_onesp (TREE_IMAGPART (expr)))
@@ -2585,11 +2598,14 @@ integer_all_onesp (const_tree expr)
 	  == wi::to_wide (expr));
 }
 
-/* Return 1 if EXPR is the integer constant minus one.  */
+/* Return 1 if EXPR is the integer constant minus one, or a location wrapper
+   for such a constant.  */
 
 bool
 integer_minus_onep (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   if (TREE_CODE (expr) == COMPLEX_CST)
     return (integer_all_onesp (TREE_REALPART (expr))
 	    && integer_zerop (TREE_IMAGPART (expr)));
@@ -2598,11 +2614,13 @@ integer_minus_onep (const_tree expr)
 }
 
 /* Return 1 if EXPR is an integer constant that is a power of 2 (i.e., has only
-   one bit on).  */
+   one bit on), or a location wrapper for such a constant.  */
 
 bool
 integer_pow2p (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   if (TREE_CODE (expr) == COMPLEX_CST
       && integer_pow2p (TREE_REALPART (expr))
       && integer_zerop (TREE_IMAGPART (expr)))
@@ -2615,11 +2633,14 @@ integer_pow2p (const_tree expr)
 }
 
 /* Return 1 if EXPR is an integer constant other than zero or a
-   complex constant other than zero.  */
+   complex constant other than zero, or a location wrapper for such a
+   constant.  */
 
 bool
 integer_nonzerop (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   return ((TREE_CODE (expr) == INTEGER_CST
 	   && wi::to_wide (expr) != 0)
 	  || (TREE_CODE (expr) == COMPLEX_CST
@@ -2629,21 +2650,27 @@ integer_nonzerop (const_tree expr)
 
 /* Return 1 if EXPR is the integer constant one.  For vector,
    return 1 if every piece is the integer constant minus one
-   (representing the value TRUE).  */
+   (representing the value TRUE).
+   Also return 1 for location wrappers for such a constant.  */
 
 bool
 integer_truep (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   if (TREE_CODE (expr) == VECTOR_CST)
     return integer_all_onesp (expr);
   return integer_onep (expr);
 }
 
-/* Return 1 if EXPR is the fixed-point constant zero.  */
+/* Return 1 if EXPR is the fixed-point constant zero, or a location wrapper
+   for such a constant.  */
 
 bool
 fixed_zerop (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   return (TREE_CODE (expr) == FIXED_CST
 	  && TREE_FIXED_CST (expr).data.is_zero ());
 }
@@ -2784,11 +2811,14 @@ tree_ctz (const_tree expr)
 }
 
 /* Return 1 if EXPR is the real constant zero.  Trailing zeroes matter for
-   decimal float constants, so don't return 1 for them.  */
+   decimal float constants, so don't return 1 for them.
+   Also return 1 for location wrappers around such a constant.  */
 
 bool
 real_zerop (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   switch (TREE_CODE (expr))
     {
     case REAL_CST:
@@ -2814,11 +2844,14 @@ real_zerop (const_tree expr)
 
 /* Return 1 if EXPR is the real constant one in real or complex form.
    Trailing zeroes matter for decimal float constants, so don't return
-   1 for them.  */
+   1 for them.
+   Also return 1 for location wrappers around such a constant.  */
 
 bool
 real_onep (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   switch (TREE_CODE (expr))
     {
     case REAL_CST:
@@ -2837,11 +2870,14 @@ real_onep (const_tree expr)
 }
 
 /* Return 1 if EXPR is the real constant minus one.  Trailing zeroes
-   matter for decimal float constants, so don't return 1 for them.  */
+   matter for decimal float constants, so don't return 1 for them.
+   Also return 1 for location wrappers around such a constant.  */
 
 bool
 real_minus_onep (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   switch (TREE_CODE (expr))
     {
     case REAL_CST:
@@ -7106,6 +7142,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))
@@ -11226,11 +11265,14 @@ uniform_vector_p (const_tree vec)
 
 /* If the argument is INTEGER_CST, return it.  If the argument is vector
    with all elements the same INTEGER_CST, return that INTEGER_CST.  Otherwise
-   return NULL_TREE.  */
+   return NULL_TREE.
+   Look through location wrappers. */
 
 tree
 uniform_integer_cst_p (tree t)
 {
+  STRIP_ANY_LOCATION_WRAPPER (t);
+
   if (TREE_CODE (t) == INTEGER_CST)
     return t;
 
@@ -14646,6 +14688,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)))
@@ -14656,6 +14703,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 *
@@ -15146,6 +15195,323 @@ test_location_wrappers ()
   check_strip_nops (wrapped_int_var, int_var);
 }
 
+/* Test various tree predicates.  Verify that location wrappers don't
+   affect the results.  */
+
+static void
+test_predicates ()
+{
+  /* Build various constants and wrappers around them.  */
+
+  location_t loc = BUILTINS_LOCATION;
+
+  tree i_0 = build_int_cst (integer_type_node, 0);
+  tree wr_i_0 = maybe_wrap_with_location (i_0, loc);
+
+  tree i_1 = build_int_cst (integer_type_node, 1);
+  tree wr_i_1 = maybe_wrap_with_location (i_1, loc);
+
+  tree i_m1 = build_int_cst (integer_type_node, -1);
+  tree wr_i_m1 = maybe_wrap_with_location (i_m1, loc);
+
+  tree f_0 = build_real_from_int_cst (float_type_node, i_0);
+  tree wr_f_0 = maybe_wrap_with_location (f_0, loc);
+  tree f_1 = build_real_from_int_cst (float_type_node, i_1);
+  tree wr_f_1 = maybe_wrap_with_location (f_1, loc);
+  tree f_m1 = build_real_from_int_cst (float_type_node, i_m1);
+  tree wr_f_m1 = maybe_wrap_with_location (f_m1, loc);
+
+  tree c_i_0 = build_complex (NULL_TREE, i_0, i_0);
+  tree c_i_1 = build_complex (NULL_TREE, i_1, i_0);
+  tree c_i_m1 = build_complex (NULL_TREE, i_m1, i_0);
+
+  tree c_f_0 = build_complex (NULL_TREE, f_0, f_0);
+  tree c_f_1 = build_complex (NULL_TREE, f_1, f_0);
+  tree c_f_m1 = build_complex (NULL_TREE, f_m1, f_0);
+
+  /* TODO: vector constants.  */
+
+  /* Test integer_onep.  */
+  ASSERT_FALSE (integer_onep (i_0));
+  ASSERT_FALSE (integer_onep (wr_i_0));
+  ASSERT_TRUE (integer_onep (i_1));
+  ASSERT_TRUE (integer_onep (wr_i_1));
+  ASSERT_FALSE (integer_onep (i_m1));
+  ASSERT_FALSE (integer_onep (wr_i_m1));
+  ASSERT_FALSE (integer_onep (f_0));
+  ASSERT_FALSE (integer_onep (wr_f_0));
+  ASSERT_FALSE (integer_onep (f_1));
+  ASSERT_FALSE (integer_onep (wr_f_1));
+  ASSERT_FALSE (integer_onep (f_m1));
+  ASSERT_FALSE (integer_onep (wr_f_m1));
+  ASSERT_FALSE (integer_onep (c_i_0));
+  ASSERT_TRUE (integer_onep (c_i_1));
+  ASSERT_FALSE (integer_onep (c_i_m1));
+  ASSERT_FALSE (integer_onep (c_f_0));
+  ASSERT_FALSE (integer_onep (c_f_1));
+  ASSERT_FALSE (integer_onep (c_f_m1));
+
+  /* Test integer_zerop.  */
+  ASSERT_TRUE (integer_zerop (i_0));
+  ASSERT_TRUE (integer_zerop (wr_i_0));
+  ASSERT_FALSE (integer_zerop (i_1));
+  ASSERT_FALSE (integer_zerop (wr_i_1));
+  ASSERT_FALSE (integer_zerop (i_m1));
+  ASSERT_FALSE (integer_zerop (wr_i_m1));
+  ASSERT_FALSE (integer_zerop (f_0));
+  ASSERT_FALSE (integer_zerop (wr_f_0));
+  ASSERT_FALSE (integer_zerop (f_1));
+  ASSERT_FALSE (integer_zerop (wr_f_1));
+  ASSERT_FALSE (integer_zerop (f_m1));
+  ASSERT_FALSE (integer_zerop (wr_f_m1));
+  ASSERT_TRUE (integer_zerop (c_i_0));
+  ASSERT_FALSE (integer_zerop (c_i_1));
+  ASSERT_FALSE (integer_zerop (c_i_m1));
+  ASSERT_FALSE (integer_zerop (c_f_0));
+  ASSERT_FALSE (integer_zerop (c_f_1));
+  ASSERT_FALSE (integer_zerop (c_f_m1));
+
+  /* Test integer_all_onesp.  */
+  ASSERT_FALSE (integer_all_onesp (i_0));
+  ASSERT_FALSE (integer_all_onesp (wr_i_0));
+  ASSERT_FALSE (integer_all_onesp (i_1));
+  ASSERT_FALSE (integer_all_onesp (wr_i_1));
+  ASSERT_TRUE (integer_all_onesp (i_m1));
+  ASSERT_TRUE (integer_all_onesp (wr_i_m1));
+  ASSERT_FALSE (integer_all_onesp (f_0));
+  ASSERT_FALSE (integer_all_onesp (wr_f_0));
+  ASSERT_FALSE (integer_all_onesp (f_1));
+  ASSERT_FALSE (integer_all_onesp (wr_f_1));
+  ASSERT_FALSE (integer_all_onesp (f_m1));
+  ASSERT_FALSE (integer_all_onesp (wr_f_m1));
+  ASSERT_FALSE (integer_all_onesp (c_i_0));
+  ASSERT_FALSE (integer_all_onesp (c_i_1));
+  ASSERT_FALSE (integer_all_onesp (c_i_m1));
+  ASSERT_FALSE (integer_all_onesp (c_f_0));
+  ASSERT_FALSE (integer_all_onesp (c_f_1));
+  ASSERT_FALSE (integer_all_onesp (c_f_m1));
+
+  /* Test integer_minus_onep.  */
+  ASSERT_FALSE (integer_minus_onep (i_0));
+  ASSERT_FALSE (integer_minus_onep (wr_i_0));
+  ASSERT_FALSE (integer_minus_onep (i_1));
+  ASSERT_FALSE (integer_minus_onep (wr_i_1));
+  ASSERT_TRUE (integer_minus_onep (i_m1));
+  ASSERT_TRUE (integer_minus_onep (wr_i_m1));
+  ASSERT_FALSE (integer_minus_onep (f_0));
+  ASSERT_FALSE (integer_minus_onep (wr_f_0));
+  ASSERT_FALSE (integer_minus_onep (f_1));
+  ASSERT_FALSE (integer_minus_onep (wr_f_1));
+  ASSERT_FALSE (integer_minus_onep (f_m1));
+  ASSERT_FALSE (integer_minus_onep (wr_f_m1));
+  ASSERT_FALSE (integer_minus_onep (c_i_0));
+  ASSERT_FALSE (integer_minus_onep (c_i_1));
+  ASSERT_TRUE (integer_minus_onep (c_i_m1));
+  ASSERT_FALSE (integer_minus_onep (c_f_0));
+  ASSERT_FALSE (integer_minus_onep (c_f_1));
+  ASSERT_FALSE (integer_minus_onep (c_f_m1));
+
+  /* Test integer_each_onep.  */
+  ASSERT_FALSE (integer_each_onep (i_0));
+  ASSERT_FALSE (integer_each_onep (wr_i_0));
+  ASSERT_TRUE (integer_each_onep (i_1));
+  ASSERT_TRUE (integer_each_onep (wr_i_1));
+  ASSERT_FALSE (integer_each_onep (i_m1));
+  ASSERT_FALSE (integer_each_onep (wr_i_m1));
+  ASSERT_FALSE (integer_each_onep (f_0));
+  ASSERT_FALSE (integer_each_onep (wr_f_0));
+  ASSERT_FALSE (integer_each_onep (f_1));
+  ASSERT_FALSE (integer_each_onep (wr_f_1));
+  ASSERT_FALSE (integer_each_onep (f_m1));
+  ASSERT_FALSE (integer_each_onep (wr_f_m1));
+  ASSERT_FALSE (integer_each_onep (c_i_0));
+  ASSERT_FALSE (integer_each_onep (c_i_1));
+  ASSERT_FALSE (integer_each_onep (c_i_m1));
+  ASSERT_FALSE (integer_each_onep (c_f_0));
+  ASSERT_FALSE (integer_each_onep (c_f_1));
+  ASSERT_FALSE (integer_each_onep (c_f_m1));
+
+  /* Test integer_truep.  */
+  ASSERT_FALSE (integer_truep (i_0));
+  ASSERT_FALSE (integer_truep (wr_i_0));
+  ASSERT_TRUE (integer_truep (i_1));
+  ASSERT_TRUE (integer_truep (wr_i_1));
+  ASSERT_FALSE (integer_truep (i_m1));
+  ASSERT_FALSE (integer_truep (wr_i_m1));
+  ASSERT_FALSE (integer_truep (f_0));
+  ASSERT_FALSE (integer_truep (wr_f_0));
+  ASSERT_FALSE (integer_truep (f_1));
+  ASSERT_FALSE (integer_truep (wr_f_1));
+  ASSERT_FALSE (integer_truep (f_m1));
+  ASSERT_FALSE (integer_truep (wr_f_m1));
+  ASSERT_FALSE (integer_truep (c_i_0));
+  ASSERT_TRUE (integer_truep (c_i_1));
+  ASSERT_FALSE (integer_truep (c_i_m1));
+  ASSERT_FALSE (integer_truep (c_f_0));
+  ASSERT_FALSE (integer_truep (c_f_1));
+  ASSERT_FALSE (integer_truep (c_f_m1));
+
+  /* Test integer_nonzerop.  */
+  ASSERT_FALSE (integer_nonzerop (i_0));
+  ASSERT_FALSE (integer_nonzerop (wr_i_0));
+  ASSERT_TRUE (integer_nonzerop (i_1));
+  ASSERT_TRUE (integer_nonzerop (wr_i_1));
+  ASSERT_TRUE (integer_nonzerop (i_m1));
+  ASSERT_TRUE (integer_nonzerop (wr_i_m1));
+  ASSERT_FALSE (integer_nonzerop (f_0));
+  ASSERT_FALSE (integer_nonzerop (wr_f_0));
+  ASSERT_FALSE (integer_nonzerop (f_1));
+  ASSERT_FALSE (integer_nonzerop (wr_f_1));
+  ASSERT_FALSE (integer_nonzerop (f_m1));
+  ASSERT_FALSE (integer_nonzerop (wr_f_m1));
+  ASSERT_FALSE (integer_nonzerop (c_i_0));
+  ASSERT_TRUE (integer_nonzerop (c_i_1));
+  ASSERT_TRUE (integer_nonzerop (c_i_m1));
+  ASSERT_FALSE (integer_nonzerop (c_f_0));
+  ASSERT_FALSE (integer_nonzerop (c_f_1));
+  ASSERT_FALSE (integer_nonzerop (c_f_m1));
+
+  /* Test real_zerop.  */
+  ASSERT_FALSE (real_zerop (i_0));
+  ASSERT_FALSE (real_zerop (wr_i_0));
+  ASSERT_FALSE (real_zerop (i_1));
+  ASSERT_FALSE (real_zerop (wr_i_1));
+  ASSERT_FALSE (real_zerop (i_m1));
+  ASSERT_FALSE (real_zerop (wr_i_m1));
+  ASSERT_TRUE (real_zerop (f_0));
+  ASSERT_TRUE (real_zerop (wr_f_0));
+  ASSERT_FALSE (real_zerop (f_1));
+  ASSERT_FALSE (real_zerop (wr_f_1));
+  ASSERT_FALSE (real_zerop (f_m1));
+  ASSERT_FALSE (real_zerop (wr_f_m1));
+  ASSERT_FALSE (real_zerop (c_i_0));
+  ASSERT_FALSE (real_zerop (c_i_1));
+  ASSERT_FALSE (real_zerop (c_i_m1));
+  ASSERT_TRUE (real_zerop (c_f_0));
+  ASSERT_FALSE (real_zerop (c_f_1));
+  ASSERT_FALSE (real_zerop (c_f_m1));
+
+  /* Test real_onep.  */
+  ASSERT_FALSE (real_onep (i_0));
+  ASSERT_FALSE (real_onep (wr_i_0));
+  ASSERT_FALSE (real_onep (i_1));
+  ASSERT_FALSE (real_onep (wr_i_1));
+  ASSERT_FALSE (real_onep (i_m1));
+  ASSERT_FALSE (real_onep (wr_i_m1));
+  ASSERT_FALSE (real_onep (f_0));
+  ASSERT_FALSE (real_onep (wr_f_0));
+  ASSERT_TRUE (real_onep (f_1));
+  ASSERT_TRUE (real_onep (wr_f_1));
+  ASSERT_FALSE (real_onep (f_m1));
+  ASSERT_FALSE (real_onep (wr_f_m1));
+  ASSERT_FALSE (real_onep (c_i_0));
+  ASSERT_FALSE (real_onep (c_i_1));
+  ASSERT_FALSE (real_onep (c_i_m1));
+  ASSERT_FALSE (real_onep (c_f_0));
+  ASSERT_TRUE (real_onep (c_f_1));
+  ASSERT_FALSE (real_onep (c_f_m1));
+
+  /* Test real_minus_onep.  */
+  ASSERT_FALSE (real_minus_onep (i_0));
+  ASSERT_FALSE (real_minus_onep (wr_i_0));
+  ASSERT_FALSE (real_minus_onep (i_1));
+  ASSERT_FALSE (real_minus_onep (wr_i_1));
+  ASSERT_FALSE (real_minus_onep (i_m1));
+  ASSERT_FALSE (real_minus_onep (wr_i_m1));
+  ASSERT_FALSE (real_minus_onep (f_0));
+  ASSERT_FALSE (real_minus_onep (wr_f_0));
+  ASSERT_FALSE (real_minus_onep (f_1));
+  ASSERT_FALSE (real_minus_onep (wr_f_1));
+  ASSERT_TRUE (real_minus_onep (f_m1));
+  ASSERT_TRUE (real_minus_onep (wr_f_m1));
+  ASSERT_FALSE (real_minus_onep (c_i_0));
+  ASSERT_FALSE (real_minus_onep (c_i_1));
+  ASSERT_FALSE (real_minus_onep (c_i_m1));
+  ASSERT_FALSE (real_minus_onep (c_f_0));
+  ASSERT_FALSE (real_minus_onep (c_f_1));
+  ASSERT_TRUE (real_minus_onep (c_f_m1));
+
+  /* Test zerop.  */
+  ASSERT_TRUE (zerop (i_0));
+  ASSERT_TRUE (zerop (wr_i_0));
+  ASSERT_FALSE (zerop (i_1));
+  ASSERT_FALSE (zerop (wr_i_1));
+  ASSERT_FALSE (zerop (i_m1));
+  ASSERT_FALSE (zerop (wr_i_m1));
+  ASSERT_TRUE (zerop (f_0));
+  ASSERT_TRUE (zerop (wr_f_0));
+  ASSERT_FALSE (zerop (f_1));
+  ASSERT_FALSE (zerop (wr_f_1));
+  ASSERT_FALSE (zerop (f_m1));
+  ASSERT_FALSE (zerop (wr_f_m1));
+  ASSERT_TRUE (zerop (c_i_0));
+  ASSERT_FALSE (zerop (c_i_1));
+  ASSERT_FALSE (zerop (c_i_m1));
+  ASSERT_TRUE (zerop (c_f_0));
+  ASSERT_FALSE (zerop (c_f_1));
+  ASSERT_FALSE (zerop (c_f_m1));
+
+  /* Test tree_expr_nonnegative_p.  */
+  ASSERT_TRUE (tree_expr_nonnegative_p (i_0));
+  ASSERT_TRUE (tree_expr_nonnegative_p (wr_i_0));
+  ASSERT_TRUE (tree_expr_nonnegative_p (i_1));
+  ASSERT_TRUE (tree_expr_nonnegative_p (wr_i_1));
+  ASSERT_FALSE (tree_expr_nonnegative_p (i_m1));
+  ASSERT_FALSE (tree_expr_nonnegative_p (wr_i_m1));
+  ASSERT_TRUE (tree_expr_nonnegative_p (f_0));
+  ASSERT_TRUE (tree_expr_nonnegative_p (wr_f_0));
+  ASSERT_TRUE (tree_expr_nonnegative_p (f_1));
+  ASSERT_TRUE (tree_expr_nonnegative_p (wr_f_1));
+  ASSERT_FALSE (tree_expr_nonnegative_p (f_m1));
+  ASSERT_FALSE (tree_expr_nonnegative_p (wr_f_m1));
+  ASSERT_FALSE (tree_expr_nonnegative_p (c_i_0));
+  ASSERT_FALSE (tree_expr_nonnegative_p (c_i_1));
+  ASSERT_FALSE (tree_expr_nonnegative_p (c_i_m1));
+  ASSERT_FALSE (tree_expr_nonnegative_p (c_f_0));
+  ASSERT_FALSE (tree_expr_nonnegative_p (c_f_1));
+  ASSERT_FALSE (tree_expr_nonnegative_p (c_f_m1));
+
+  /* Test tree_expr_nonzero_p.  */
+  ASSERT_FALSE (tree_expr_nonzero_p (i_0));
+  ASSERT_FALSE (tree_expr_nonzero_p (wr_i_0));
+  ASSERT_TRUE (tree_expr_nonzero_p (i_1));
+  ASSERT_TRUE (tree_expr_nonzero_p (wr_i_1));
+  ASSERT_TRUE (tree_expr_nonzero_p (i_m1));
+  ASSERT_TRUE (tree_expr_nonzero_p (wr_i_m1));
+
+  /* Test integer_valued_real_p.  */
+  ASSERT_FALSE (integer_valued_real_p (i_0));
+  ASSERT_TRUE (integer_valued_real_p (f_0));
+  ASSERT_TRUE (integer_valued_real_p (wr_f_0));
+  ASSERT_TRUE (integer_valued_real_p (f_1));
+  ASSERT_TRUE (integer_valued_real_p (wr_f_1));
+
+  /* Test integer_pow2p.  */
+  ASSERT_FALSE (integer_pow2p (i_0));
+  ASSERT_TRUE (integer_pow2p (i_1));
+  ASSERT_TRUE (integer_pow2p (wr_i_1));
+
+  /* Test uniform_integer_cst_p.  */
+  ASSERT_TRUE (uniform_integer_cst_p (i_0));
+  ASSERT_TRUE (uniform_integer_cst_p (wr_i_0));
+  ASSERT_TRUE (uniform_integer_cst_p (i_1));
+  ASSERT_TRUE (uniform_integer_cst_p (wr_i_1));
+  ASSERT_TRUE (uniform_integer_cst_p (i_m1));
+  ASSERT_TRUE (uniform_integer_cst_p (wr_i_m1));
+  ASSERT_FALSE (uniform_integer_cst_p (f_0));
+  ASSERT_FALSE (uniform_integer_cst_p (wr_f_0));
+  ASSERT_FALSE (uniform_integer_cst_p (f_1));
+  ASSERT_FALSE (uniform_integer_cst_p (wr_f_1));
+  ASSERT_FALSE (uniform_integer_cst_p (f_m1));
+  ASSERT_FALSE (uniform_integer_cst_p (wr_f_m1));
+  ASSERT_FALSE (uniform_integer_cst_p (c_i_0));
+  ASSERT_FALSE (uniform_integer_cst_p (c_i_1));
+  ASSERT_FALSE (uniform_integer_cst_p (c_i_m1));
+  ASSERT_FALSE (uniform_integer_cst_p (c_f_0));
+  ASSERT_FALSE (uniform_integer_cst_p (c_f_1));
+  ASSERT_FALSE (uniform_integer_cst_p (c_f_m1));
+}
+
 /* Check that string escaping works correctly.  */
 
 static void
@@ -15199,6 +15565,7 @@ tree_c_tests ()
   test_labels ();
   test_vector_cst_patterns ();
   test_location_wrappers ();
+  test_predicates ();
   test_escaped_strings ();
 }
 
diff --git a/gcc/tree.h b/gcc/tree.h
index 761b508..ab928ca 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)
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] v5: C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
  2018-12-14 23:29               ` [PATCH] v5: " David Malcolm
@ 2018-12-17 19:33                 ` Jason Merrill
  2018-12-17 23:30                   ` David Malcolm
  0 siblings, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2018-12-17 19:33 UTC (permalink / raw)
  To: David Malcolm; +Cc: Jeff Law, gcc-patches

On 12/14/18 7:17 PM, David Malcolm wrote:
> +      /* 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).  */

Hmm, looking at this again, why would this happen?  I see that 
type_list_equal uses == to compare default arguments, so two function 
types with the same default argument but different location wrappers 
shouldn't be combined.

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] v5: C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
  2018-12-17 19:33                 ` Jason Merrill
@ 2018-12-17 23:30                   ` David Malcolm
  2018-12-18 20:23                     ` Jason Merrill
  2018-12-18 20:34                     ` [PATCH] v6: " David Malcolm
  0 siblings, 2 replies; 34+ messages in thread
From: David Malcolm @ 2018-12-17 23:30 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jeff Law, gcc-patches

On Mon, 2018-12-17 at 14:33 -0500, Jason Merrill wrote:
> On 12/14/18 7:17 PM, David Malcolm wrote:
> > +      /* 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).  */
> 
> Hmm, looking at this again, why would this happen?  I see that 
> type_list_equal uses == to compare default arguments, so two
> function 
> types with the same default argument but different location wrappers 
> shouldn't be combined.
> 
> Jason

Thanks.

I did some digging into this.  I added this strip to fix
  g++.dg/template/defarg6.C
but it looks like I was overzealous (the comment is correct, but it's
papering over a problem).

It turns out that type_list_equal is doing more than just pointer
equality; it's hitting the simple_cst_equal part of the && at line
7071:

7063	bool
7064	type_list_equal (const_tree l1, const_tree l2)
7065	{
7066	  const_tree t1, t2;
7067	
7068	  for (t1 = l1, t2 = l2; t1 && t2; t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
7069	    if (TREE_VALUE (t1) != TREE_VALUE (t2)
7070		|| (TREE_PURPOSE (t1) != TREE_PURPOSE (t2)
7071		    && ! (1 == simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2))
7072			  && (TREE_TYPE (TREE_PURPOSE (t1))
7073			      == TREE_TYPE (TREE_PURPOSE (t2))))))
7074	      return false;
7075	
7076	  return t1 == t2;
7077	}

What's happening is that there are two different functions with
identical types apart from the locations of their (equal) default
arguments: both of the TREE_PURPOSEs are NON_LVALUE_EXPR wrappers
around a CONST_DECL enum value (at different source locations).

simple_cst_equal is stripping the location wrappers here:

7311	  if (CONVERT_EXPR_CODE_P (code1) || code1 == NON_LVALUE_EXPR)
7312	    {
7313	      if (CONVERT_EXPR_CODE_P (code2)
7314		  || code2 == NON_LVALUE_EXPR)
7315		return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
7316	      else
7317		return simple_cst_equal (TREE_OPERAND (t1, 0), t2);
7318	    }

and thus finds them to be equal; the iteration in type_list_equal
continues, and runs out of parameters with t1 == t2 == NULL, and thus
returns true, and thus the two function types hash to the same slot,
and the two function types get treated as being the same.

It's not clear to me yet what the best solution to this is:
- should simple_cst_equal regard different source locations as being
different?
- should function-type hashing use a custom version of type_list_equal
when comparing params, and make different source locations of default
args be different?
- something else?

Dave

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] v5: C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
  2018-12-17 23:30                   ` David Malcolm
@ 2018-12-18 20:23                     ` Jason Merrill
  2018-12-18 20:34                     ` [PATCH] v6: " David Malcolm
  1 sibling, 0 replies; 34+ messages in thread
From: Jason Merrill @ 2018-12-18 20:23 UTC (permalink / raw)
  To: David Malcolm; +Cc: Jeff Law, gcc-patches

On 12/17/18 6:30 PM, David Malcolm wrote:
> On Mon, 2018-12-17 at 14:33 -0500, Jason Merrill wrote:
>> On 12/14/18 7:17 PM, David Malcolm wrote:
>>> +      /* 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).  */
>>
>> Hmm, looking at this again, why would this happen?  I see that
>> type_list_equal uses == to compare default arguments, so two
>> function
>> types with the same default argument but different location wrappers
>> shouldn't be combined.
>>
>> Jason
> 
> Thanks.
> 
> I did some digging into this.  I added this strip to fix
>    g++.dg/template/defarg6.C
> but it looks like I was overzealous (the comment is correct, but it's
> papering over a problem).
> 
> It turns out that type_list_equal is doing more than just pointer
> equality; it's hitting the simple_cst_equal part of the && at line
> 7071:
> 
> 7063	bool
> 7064	type_list_equal (const_tree l1, const_tree l2)
> 7065	{
> 7066	  const_tree t1, t2;
> 7067	
> 7068	  for (t1 = l1, t2 = l2; t1 && t2; t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
> 7069	    if (TREE_VALUE (t1) != TREE_VALUE (t2)
> 7070		|| (TREE_PURPOSE (t1) != TREE_PURPOSE (t2)
> 7071		    && ! (1 == simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2))
> 7072			  && (TREE_TYPE (TREE_PURPOSE (t1))
> 7073			      == TREE_TYPE (TREE_PURPOSE (t2))))))
> 7074	      return false;
> 7075	
> 7076	  return t1 == t2;
> 7077	}
> 
> What's happening is that there are two different functions with
> identical types apart from the locations of their (equal) default
> arguments: both of the TREE_PURPOSEs are NON_LVALUE_EXPR wrappers
> around a CONST_DECL enum value (at different source locations).
> 
> simple_cst_equal is stripping the location wrappers here:
> 
> 7311	  if (CONVERT_EXPR_CODE_P (code1) || code1 == NON_LVALUE_EXPR)
> 7312	    {
> 7313	      if (CONVERT_EXPR_CODE_P (code2)
> 7314		  || code2 == NON_LVALUE_EXPR)
> 7315		return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
> 7316	      else
> 7317		return simple_cst_equal (TREE_OPERAND (t1, 0), t2);
> 7318	    }
> 
> and thus finds them to be equal; the iteration in type_list_equal
> continues, and runs out of parameters with t1 == t2 == NULL, and thus
> returns true, and thus the two function types hash to the same slot,
> and the two function types get treated as being the same.
> 
> It's not clear to me yet what the best solution to this is:
> - should simple_cst_equal regard different source locations as being
> different?
> - should function-type hashing use a custom version of type_list_equal
> when comparing params, and make different source locations of default
> args be different?
> - something else?

I'd experiment with removing the simple_cst_equal bit in 
type_list_equal.  But I think that can wait, and you can go ahead and 
commit the v5 patch.

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH] v6: C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
  2018-12-17 23:30                   ` David Malcolm
  2018-12-18 20:23                     ` Jason Merrill
@ 2018-12-18 20:34                     ` David Malcolm
  2018-12-18 20:40                       ` Jason Merrill
  1 sibling, 1 reply; 34+ messages in thread
From: David Malcolm @ 2018-12-18 20:34 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jeff Law, gcc-patches, David Malcolm

On Mon, 2018-12-17 at 18:30 -0500, David Malcolm wrote:
> On Mon, 2018-12-17 at 14:33 -0500, Jason Merrill wrote:
> > On 12/14/18 7:17 PM, David Malcolm wrote:
> > > +      /* 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).  */
> > 
> > Hmm, looking at this again, why would this happen?  I see that 
> > type_list_equal uses == to compare default arguments, so two
> > function 
> > types with the same default argument but different location
> > wrappers 
> > shouldn't be combined.
> > 
> > Jason
> 
> Thanks.
> 
> I did some digging into this.  I added this strip to fix
>   g++.dg/template/defarg6.C
> but it looks like I was overzealous (the comment is correct, but it's
> papering over a problem).
> 
> It turns out that type_list_equal is doing more than just pointer
> equality; it's hitting the simple_cst_equal part of the && at line
> 7071:
> 
> 7063	bool
> 7064	type_list_equal (const_tree l1, const_tree l2)
> 7065	{
> 7066	  const_tree t1, t2;
> 7067	
> 7068	  for (t1 = l1, t2 = l2; t1 && t2; t1 = TREE_CHAIN (t1),
> t2 = TREE_CHAIN (t2))
> 7069	    if (TREE_VALUE (t1) != TREE_VALUE (t2)
> 7070		|| (TREE_PURPOSE (t1) != TREE_PURPOSE (t2)
> 7071		    && ! (1 == simple_cst_equal (TREE_PURPOSE
> (t1), TREE_PURPOSE (t2))
> 7072			  && (TREE_TYPE (TREE_PURPOSE (t1))
> 7073			      == TREE_TYPE (TREE_PURPOSE
> (t2))))))
> 7074	      return false;
> 7075	
> 7076	  return t1 == t2;
> 7077	}
> 
> What's happening is that there are two different functions with
> identical types apart from the locations of their (equal) default
> arguments: both of the TREE_PURPOSEs are NON_LVALUE_EXPR wrappers
> around a CONST_DECL enum value (at different source locations).
> 
> simple_cst_equal is stripping the location wrappers here:
> 
> 7311	  if (CONVERT_EXPR_CODE_P (code1) || code1 ==
> NON_LVALUE_EXPR)
> 7312	    {
> 7313	      if (CONVERT_EXPR_CODE_P (code2)
> 7314		  || code2 == NON_LVALUE_EXPR)
> 7315		return simple_cst_equal (TREE_OPERAND (t1, 0),
> TREE_OPERAND (t2, 0));
> 7316	      else
> 7317		return simple_cst_equal (TREE_OPERAND (t1, 0),
> t2);
> 7318	    }
> 
> and thus finds them to be equal; the iteration in type_list_equal
> continues, and runs out of parameters with t1 == t2 == NULL, and thus
> returns true, and thus the two function types hash to the same slot,
> and the two function types get treated as being the same.
> 
> It's not clear to me yet what the best solution to this is:
> - should simple_cst_equal regard different source locations as being
> different?
> - should function-type hashing use a custom version of
> type_list_equal
> when comparing params, and make different source locations of default
> args be different?
> - something else?
> 
> Dave

I tried both of the above approaches, and both work.

Here's v6 of the patch:

I removed the strip of wrappers in cp_parser_late_parsing_default_args
from earlier versions of the patch, in favor of fixing simple_cst_equal
so that it treats location wrappers with unequal source locations as
being unequal.  This ensures that function-types with default arguments
don't get merged when the default argument constants have different
spelling locations.  [I have an alternative patch which instead
introduces a different comparator for FUNCTION_TYPE's TYPE_ARG_TYPES
within type_cache_hasher::equal, almost identical to type_list_equal,
but adding the requirement that  location wrappers around default
arguments have equal source location for the params to be considered
equal; both patches pass bootstrap&regression testing]

Doing so leads to the reported location for the bad default argument
within a template in g++.dg/template/defarg6.C moving to the argument
location.  Previously, the callsite of the instantiation was identified
due to the use of input_location in convert_like_real here:

6816	  location_t loc = cp_expr_loc_or_loc (expr, input_location);

With a location wrapper, it uses the spelling location of the
default argument, but doesn't identify the location of the callsite
that's instantiating the template.

So I moved the note in tsubst_default_argument about which callsite
led to a diagnostic to after the check_default_argument call, so that
diagnostics within that receive notes, too.

As before, this was successfully bootstrapped & regrtested on
x86_64-pc-linux-gnu, in conjunction with the followup patch.

OK for trunk?
Dave


Blurb from v1:

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&chxr=1,58.26,61.79&chco=FF0000,0000FF&chdl=control|experiment&chds=58.26,61.79&chd=t:59.55,60.26,60.53,60.35,60.17,60.27,59.26,60.01,60.21,60.23,60.1,60.2,60.12,60.48,60.32,60.18,60.01,60.01,60.04,59.96,60.1,60.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=Compilation+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&chxr=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&chxr=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.72|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.78,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+kdecore.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.

****************************************************************************
ChangeLog for v6:

gcc/c-family/ChangeLog:
	PR c++/43064
	PR c++/43486
	* c-common.c (unsafe_conversion_p): Fold 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/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): Strip expr when using TREE_OVERFLOW.
	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.
	* convert.h (preserve_any_location_wrapper): New decl.
	* fold-const.c (size_binop_loc): Strip location wrappers when
	using TREE_OVERFLOW.
	(operand_equal_p): Strip any location wrappers.
	(integer_valued_real_p): Strip any location wrapper.
	* selftest-run-tests.c (selftest::run_tests): Call
	selftest::convert_c_tests.
	* selftest.h (selftest::convert_c_tests): New decl.
	* tree.c (build_complex): Assert that REAL and IMAG are constants.
	(integer_zerop): Look through location wrappers.
	(integer_onep): Likewise.
	(integer_each_onep): Likewise.
	(integer_all_onesp): Likewise.
	(integer_minus_onep): Likewise.
	(integer_pow2p): Likewise.
	(integer_nonzerop): Likewise.
	(integer_truep): Likewise.
	(fixed_zerop): Likewise.
	(real_zerop): Likewise.
	(real_onep): Likewise.
	(real_minus_onep): Likewise.
	(tree_int_cst_equal): Likewise.
	(simple_cst_equal): Treat location wrappers with non-equal source
	locations as being unequal.
	(uniform_integer_cst_p): Look through location wrappers.
	(maybe_wrap_with_location): Don't create wrappers if any
	auto_suppress_location_wrappers are active.
	(suppress_location_wrappers): New variable.
	(selftest::test_predicates): New test.
	(selftest::tree_c_tests): Call it.
	* tree.h (CONSTANT_CLASS_OR_WRAPPER_P): New macro.
	(suppress_location_wrappers): New decl.
	(class auto_suppress_location_wrappers): New class.

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.
	* 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.
	* 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_unary_expression): Ensure that folding of NEGATE_EXPR
	around a constant happens in the presence of location wrappers and
	returns a wrapped result.
	(cp_parser_has_attribute_expression): Strip any location wrapper
	from "oper".
	(cp_parser_binary_expression): Strip any location wrapper when
	checking for DECL_P on the lhs.
	(cp_parser_decltype): Strip any location wrapper from result of
	cp_parser_decltype_expr.
	(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.
	(cp_parser_std_attribute_spec_seq): Likewise.
	(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.
	(tsubst_default_argument): Move note about which callsite led to
	instantiation to after the check_default_argument call.
	(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.
	(capture_decltype): Use lookup_name_real rather than value_member
	when looking up decl within the capture-list.
	* tree.c (cp_stabilize_reference): Strip any location wrapper.
	(builtin_valid_in_constant_expr_p): Likewise.
	(strip_typedefs_expr): Strip any location wrapper before checking
	for decls or constants.
	(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): Call maybe_constant_value on "idx".
	(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.
	(gen_declaration): Strip location wrappers from "w".

gcc/testsuite/ChangeLog:
	PR c++/43064
	PR c++/43486
	* c-c++-common/pr51712.c (valid2): Mark xfail as passing on C++.
	* g++.dg/cpp0x/constexpr-47969.C: Update column of expected error.
	* g++.dg/cpp0x/constexpr-ex2.C: Likewise.
	* g++.dg/cpp0x/scoped_enum2.C: Likewise.
	* g++.dg/cpp1z/decomp48.C: Update expected location of warning
	for named local variables to use that of the local variable.
	* g++.dg/ext/vla1.C: Update column.
	* 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/new44.C: Add "-ftrack-macro-expansion=0".
	* 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/other/fold1.C: Update column of expected error.
	* g++.dg/parse/crash36.C: Likewise.
	* g++.dg/plugin/diagnostic-test-expressions-1.C: Add negative
	integer and float expressions.
	* g++.dg/template/defarg6.C: Move expected error to the default
	argument; add expected message about where instantiated.
	* g++.dg/wrappers/Wparentheses.C: New test.
	* g++.old-deja/g++.bugs/900402_02.C: Update column of expected
	error.
---
 gcc/c-family/c-common.c                            |  22 ++
 gcc/c-family/c-pretty-print.c                      |  11 +-
 gcc/c-family/c-warn.c                              |  71 ++--
 gcc/convert.c                                      | 135 ++++++-
 gcc/convert.h                                      |   2 +
 gcc/cp/call.c                                      |   9 +-
 gcc/cp/class.c                                     |   8 +
 gcc/cp/constexpr.c                                 |  17 +-
 gcc/cp/cvt.c                                       |  22 +-
 gcc/cp/decl.c                                      |  33 +-
 gcc/cp/expr.c                                      |   2 +
 gcc/cp/init.c                                      |   9 +-
 gcc/cp/parser.c                                    |  75 +++-
 gcc/cp/pt.c                                        |  10 +-
 gcc/cp/semantics.c                                 |  85 +++--
 gcc/cp/tree.c                                      |  16 +
 gcc/cp/typeck.c                                    | 105 ++++--
 gcc/cp/typeck2.c                                   |  56 ++-
 gcc/fold-const.c                                   |  17 +-
 gcc/objc/objc-act.c                                |  14 +-
 gcc/selftest-run-tests.c                           |   1 +
 gcc/selftest.h                                     |   1 +
 gcc/testsuite/c-c++-common/pr51712.c               |   2 +-
 gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C       |   2 +-
 gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C         |   2 +-
 gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C          |   2 +-
 gcc/testsuite/g++.dg/cpp1z/decomp48.C              |   8 +-
 gcc/testsuite/g++.dg/ext/vla1.C                    |   2 +-
 gcc/testsuite/g++.dg/init/array43.C                |   2 +-
 .../g++.dg/init/initializer-string-too-long.C      |   9 +
 gcc/testsuite/g++.dg/init/new44.C                  |   1 +
 gcc/testsuite/g++.dg/init/pr43064-1.C              |  37 ++
 gcc/testsuite/g++.dg/init/pr43064-2.C              |  34 ++
 gcc/testsuite/g++.dg/init/pr43064-3.C              |  32 ++
 gcc/testsuite/g++.dg/other/fold1.C                 |   2 +-
 gcc/testsuite/g++.dg/parse/crash36.C               |   2 +-
 .../g++.dg/plugin/diagnostic-test-expressions-1.C  |  14 +
 gcc/testsuite/g++.dg/template/defarg6.C            |   6 +-
 gcc/testsuite/g++.dg/wrappers/Wparentheses.C       |  10 +
 gcc/testsuite/g++.old-deja/g++.bugs/900402_02.C    |   8 +-
 gcc/tree.c                                         | 402 ++++++++++++++++++++-
 gcc/tree.h                                         |  19 +
 42 files changed, 1103 insertions(+), 214 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 4c90365..2282515 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -1250,6 +1250,8 @@ unsafe_conversion_p (location_t loc, tree type, tree expr, tree result,
 
     loc = expansion_point_location_if_in_system_header (loc);
 
+  expr = fold_for_warn (expr);
+
   if (TREE_CODE (expr) == REAL_CST || TREE_CODE (expr) == INTEGER_CST)
     {
       /* If type is complex, we are interested in compatibility with
@@ -1947,6 +1949,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.
@@ -3241,6 +3250,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:
@@ -3460,6 +3470,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;
     }
@@ -6279,6 +6297,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)
@@ -6357,6 +6376,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
@@ -7906,6 +7927,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 798ad1b..4c0bdf9 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.
@@ -1529,6 +1538,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.  */
@@ -1669,15 +1679,22 @@ 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)
+    {
+      /* If INDEX has a location, use it; otherwise use LOC (the location
+	 of the subscripting expression as a whole).  */
+      loc = EXPR_LOC_OR_LOC (index, loc);
+      STRIP_ANY_LOCATION_WRAPPER (index);
+      if (TREE_CODE (index) != INTEGER_CST)
+	warning_at (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..028497f 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.  */
+
+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
@@ -679,7 +705,8 @@ convert_to_integer_1 (tree type, tree expr, bool dofold)
     {
     case POINTER_TYPE:
     case REFERENCE_TYPE:
-      if (integer_zerop (expr) && !TREE_OVERFLOW (expr))
+      if (integer_zerop (expr)
+	  && !TREE_OVERFLOW (tree_strip_any_location_wrapper (expr)))
 	return build_int_cst (type, 0);
 
       /* Convert to an unsigned integer of the correct width first, and from
@@ -959,7 +986,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 +1044,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 +1131,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 +1204,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/convert.h b/gcc/convert.h
index 4ffa6ef..f3334f9 100644
--- a/gcc/convert.h
+++ b/gcc/convert.h
@@ -40,4 +40,6 @@ extern inline tree convert_to_real_nofold (tree t, tree x)
 extern inline tree convert_to_complex_nofold (tree t, tree x)
 { return convert_to_complex_maybe_fold (t, x, false); }
 
+extern tree preserve_any_location_wrapper (tree result, tree orig_expr);
+
 #endif /* GCC_CONVERT_H */
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 6328a36..ef3a02c 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5347,9 +5347,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)
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index fec1c5d..28f4965 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -7387,6 +7387,14 @@ 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
+	/* TODO: Recursion may be correct for some non-location-wrapper
+	   uses of VIEW_CONVERT_EXPR.  */
+	return NULL_TREE;
+
     default:
       return NULL_TREE;
     }
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index f804946..517489a 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -5762,13 +5762,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 eb16873..f758f2d 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -582,15 +582,20 @@ 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;
+
+  return preserve_any_location_wrapper (stripped_expr, expr);
 }
 
 /* Fold away simple conversions, but make sure TREE_OVERFLOW is set
@@ -800,10 +805,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 5435ef2..7520ec2 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6005,14 +6005,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);
@@ -6042,16 +6044,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",
@@ -6111,20 +6113,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;
@@ -6139,24 +6143,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);
 	    }
 	}
@@ -16588,6 +16592,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/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 5a31486..22824bd 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1756,7 +1756,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
@@ -2604,6 +2605,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
@@ -2667,11 +2669,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)
@@ -2762,6 +2766,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/parser.c b/gcc/cp/parser.c
index 8b669a8..7adc15e 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -5232,7 +5232,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:
@@ -5254,9 +5255,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
@@ -7169,8 +7171,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
@@ -8358,18 +8362,22 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
 	case NEGATE_EXPR:
 	  /* Immediately fold negation of a constant, unless the constant is 0
 	     (since -0 == 0) or it would overflow.  */
-	  if (unary_operator == NEGATE_EXPR && op_ttype == CPP_NUMBER
-	      && CONSTANT_CLASS_P (cast_expression)
-	      && !integer_zerop (cast_expression)
-	      && !TREE_OVERFLOW (cast_expression))
+	  if (unary_operator == NEGATE_EXPR && op_ttype == CPP_NUMBER)
 	    {
-	      tree folded = fold_build1 (unary_operator,
-					 TREE_TYPE (cast_expression),
-					 cast_expression);
-	      if (CONSTANT_CLASS_P (folded) && !TREE_OVERFLOW (folded))
+	      tree stripped_expr
+		= tree_strip_any_location_wrapper (cast_expression);
+	      if (CONSTANT_CLASS_P (stripped_expr)
+		  && !integer_zerop (stripped_expr)
+		  && !TREE_OVERFLOW (stripped_expr))
 		{
-		  expression = cp_expr (folded, loc);
-		  break;
+		  tree folded = fold_build1 (unary_operator,
+					     TREE_TYPE (stripped_expr),
+					     stripped_expr);
+		  if (CONSTANT_CLASS_P (folded) && !TREE_OVERFLOW (folded))
+		    {
+		      expression = maybe_wrap_with_location (folded, loc);
+		      break;
+		    }
 		}
 	    }
 	  /* Fall through.  */
@@ -8484,6 +8492,8 @@ cp_parser_has_attribute_expression (cp_parser *parser)
   if (!oper || oper == error_mark_node)
     oper = cp_parser_unary_expression (parser);
 
+  STRIP_ANY_LOCATION_WRAPPER (oper);
+
   /* Go back to evaluating expressions.  */
   --cp_unevaluated_operand;
   --c_inhibit_evaluation_warnings;
@@ -9503,7 +9513,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,
@@ -14541,6 +14551,7 @@ cp_parser_decltype (cp_parser *parser)
       ++c_inhibit_evaluation_warnings;
 
       expr = cp_parser_decltype_expr (parser, id_expression_or_member_access_p);
+      STRIP_ANY_LOCATION_WRAPPER (expr);
 
       /* Go back to evaluating expressions.  */
       --cp_unevaluated_operand;
@@ -14918,7 +14929,9 @@ cp_parser_mem_initializer (cp_parser* parser)
       vec = cp_parser_parenthesized_expression_list (parser, non_attr,
 						     /*cast_p=*/false,
 						     /*allow_expansion_p=*/true,
-						     /*non_constant_p=*/NULL);
+						     /*non_constant_p=*/NULL,
+						     /*close_paren_loc=*/NULL,
+						     /*wrap_locations_p=*/true);
       if (vec == NULL)
 	return error_mark_node;
       expression_list = build_tree_list_vec (vec);
@@ -15459,6 +15472,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
@@ -16629,6 +16647,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
@@ -22306,6 +22327,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
@@ -25654,6 +25678,10 @@ cp_parser_gnu_attribute_list (cp_parser* parser, bool exactly_one /* = false */)
   tree attribute_list = NULL_TREE;
   bool save_translate_strings_p = parser->translate_strings_p;
 
+  /* Don't create wrapper nodes within attributes: the
+     handlers don't know how to handle them.  */
+  auto_suppress_location_wrappers sentinel;
+
   parser->translate_strings_p = false;
   while (true)
     {
@@ -26099,6 +26127,10 @@ cp_parser_std_attribute_spec_seq (cp_parser *parser)
   tree attr_specs = NULL_TREE;
   tree attr_last = NULL_TREE;
 
+  /* Don't create wrapper nodes within attributes: the
+     handlers don't know how to handle them.  */
+  auto_suppress_location_wrappers sentinel;
+
   while (true)
     {
       tree attr_spec = cp_parser_std_attribute_spec (parser);
@@ -34873,6 +34905,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;
@@ -36590,6 +36625,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;
@@ -39161,6 +39200,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=*/NULL,
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8560e58..6672351 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6196,6 +6196,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)
@@ -12752,14 +12753,14 @@ tsubst_default_argument (tree fn, int parmnum, tree type, tree arg,
 
   finish_lambda_scope ();
 
+  /* Make sure the default argument is reasonable.  */
+  arg = check_default_argument (type, arg, complain);
+
   if (errorcount+sorrycount > errs
       && (complain & tf_warning_or_error))
     inform (input_location,
 	    "  when instantiating default argument for call to %qD", fn);
 
-  /* Make sure the default argument is reasonable.  */
-  arg = check_default_argument (type, arg, complain);
-
   pop_access_scope (fn);
   pop_from_top_level ();
 
@@ -27211,7 +27212,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 c1240cc..792ea07 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1742,7 +1742,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;
 
@@ -1805,8 +1806,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 ());
 
@@ -2299,19 +2301,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)
     {
@@ -2351,7 +2356,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
@@ -2382,6 +2387,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)
@@ -3523,20 +3530,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.  */
 
@@ -9765,12 +9800,12 @@ static tree
 capture_decltype (tree decl)
 {
   tree lam = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (current_function_decl));
-  /* FIXME do lookup instead of list walk? */
-  tree cap = value_member (decl, LAMBDA_EXPR_CAPTURE_LIST (lam));
+  tree cap = lookup_name_real (DECL_NAME (decl), /*type*/0, /*nonclass*/1,
+			       /*block_p=*/true, /*ns*/0, LOOKUP_HIDDEN);
   tree type;
 
-  if (cap)
-    type = TREE_TYPE (TREE_PURPOSE (cap));
+  if (cap && is_capture_proxy (cap))
+    type = TREE_TYPE (cap);
   else
     switch (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam))
       {
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 97074df..aac3ece 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -377,6 +377,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:
@@ -421,6 +422,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;
@@ -1715,6 +1717,8 @@ strip_typedefs_expr (tree t, bool *remove_attributes)
   if (t == NULL_TREE || t == error_mark_node)
     return t;
 
+  STRIP_ANY_LOCATION_WRAPPER (t);
+
   if (DECL_P (t) || CONSTANT_CLASS_P (t))
     return t;
 
@@ -2369,6 +2373,8 @@ lookup_maybe_add (tree fns, tree lookup, bool deduping)
 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)
@@ -2417,6 +2423,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)
@@ -5527,6 +5535,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 ac0c811..94bb036 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)))
@@ -3415,6 +3425,8 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
 	 pointer arithmetic.)  */
       idx = cp_perform_integral_promotions (idx, complain);
 
+      idx = maybe_constant_value (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.
@@ -4561,20 +4573,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");
+		}
 	    }
 	}
 
@@ -4596,15 +4611,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;
 	}
@@ -4638,10 +4656,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;
@@ -4842,13 +4861,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
@@ -6080,8 +6103,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)
@@ -8291,7 +8315,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)
 	{
@@ -8810,9 +8835,10 @@ convert_for_assignment (tree type, tree rhs,
   enum tree_code coder;
 
   location_t rhs_loc = EXPR_LOC_OR_LOC (rhs, input_location);
-
-  /* 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
@@ -9186,6 +9212,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)
@@ -9287,6 +9315,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
@@ -9313,6 +9343,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))
@@ -9606,6 +9637,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 64e36ef..c1fa4a9 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -460,14 +460,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.  */
 
@@ -1052,6 +1057,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.  */
@@ -1065,7 +1072,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)));
 
@@ -1113,6 +1120,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)))
 	    {
@@ -1123,12 +1138,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;
 		}
 	    }
@@ -1137,7 +1153,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)
@@ -1162,23 +1178,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 "
@@ -1188,12 +1204,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 45de94c..1851a3d 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -1911,19 +1911,23 @@ size_binop_loc (location_t loc, enum tree_code code, tree arg0, tree arg1)
       /* And some specific cases even faster than that.  */
       if (code == PLUS_EXPR)
 	{
-	  if (integer_zerop (arg0) && !TREE_OVERFLOW (arg0))
+	  if (integer_zerop (arg0)
+	      && !TREE_OVERFLOW (tree_strip_any_location_wrapper (arg0)))
 	    return arg1;
-	  if (integer_zerop (arg1) && !TREE_OVERFLOW (arg1))
+	  if (integer_zerop (arg1)
+	      && !TREE_OVERFLOW (tree_strip_any_location_wrapper (arg1)))
 	    return arg0;
 	}
       else if (code == MINUS_EXPR)
 	{
-	  if (integer_zerop (arg1) && !TREE_OVERFLOW (arg1))
+	  if (integer_zerop (arg1)
+	      && !TREE_OVERFLOW (tree_strip_any_location_wrapper (arg1)))
 	    return arg0;
 	}
       else if (code == MULT_EXPR)
 	{
-	  if (integer_onep (arg0) && !TREE_OVERFLOW (arg0))
+	  if (integer_onep (arg0)
+	      && !TREE_OVERFLOW (tree_strip_any_location_wrapper (arg0)))
 	    return arg1;
 	}
 
@@ -2938,6 +2942,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.  */
@@ -13681,6 +13688,8 @@ integer_valued_real_p (tree t, int depth)
   if (t == error_mark_node)
     return false;
 
+  STRIP_ANY_LOCATION_WRAPPER (t);
+
   tree_code code = TREE_CODE (t);
   switch (TREE_CODE_CLASS (code))
     {
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index d086930..42b2fc2 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);
 
@@ -8906,9 +8910,13 @@ gen_declaration (tree decl)
 #else
       tree w = DECL_INITIAL (decl);
 #endif
-      if (w && TREE_CODE (w) == INTEGER_CST)
-	sprintf (errbuf + strlen (errbuf), ": " HOST_WIDE_INT_PRINT_DEC,
-		 TREE_INT_CST_LOW (w));
+      if (w)
+	{
+	  STRIP_ANY_LOCATION_WRAPPER (w);
+	  if (TREE_CODE (w) == INTEGER_CST)
+	    sprintf (errbuf + strlen (errbuf), ": " HOST_WIDE_INT_PRINT_DEC,
+		     TREE_INT_CST_LOW (w));
+	}
     }
 
   return errbuf;
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index 6d65d24..27be70d 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -81,6 +81,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 2d7cc3b55..3b2298b 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -216,6 +216,7 @@ class test_runner
 extern void attribute_c_tests ();
 extern void bitmap_c_tests ();
 extern void cgraph_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/cpp0x/constexpr-47969.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
index bfd9d8f..9ff2157 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-47969.C
@@ -9,4 +9,4 @@ struct A
 constexpr A a = A();
 
 int ar[a]; // { dg-error "could not convert" }
-// { dg-error "5:size of array .ar. has non-integral" "" { target c++11 } .-1 }
+// { dg-error "8:size of array .ar. has non-integral" "" { target c++11 } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
index e726a34..f697300 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex2.C
@@ -19,4 +19,4 @@ constexpr A a = 42;
 X<a> x;	    // OK: unique conversion to int
 int ar[X<a>::i]; // also OK
 int ary[a]; // { dg-error "could not convert" } ambiguous conversion
-// { dg-error "5:size of array .ary. has non-integral" "" { target c++11 } .-1 }
+// { dg-error "9:size of array .ary. has non-integral" "" { target c++11 } .-1 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C b/gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
index 0313c01..c4a869a 100644
--- a/gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/scoped_enum2.C
@@ -5,7 +5,7 @@ enum E2 { e2 = 10 };
 
 struct C {
   int arr[E::e];    // { dg-error "could not convert" }
-// { dg-error "7:size of array .arr. has non-integral" "" { target c++11 } .-1 }
+// { dg-error "14:size of array .arr. has non-integral" "" { target c++11 } .-1 }
   int arr2[E2::e2]; // OK
   int i: E::e;	    // { dg-error "could not convert|non-integral type" }
   int i2: E2::e2;   // OK
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/ext/vla1.C b/gcc/testsuite/g++.dg/ext/vla1.C
index d6df686..c017b6e 100644
--- a/gcc/testsuite/g++.dg/ext/vla1.C
+++ b/gcc/testsuite/g++.dg/ext/vla1.C
@@ -19,7 +19,7 @@ class B { B (int); };
 B::B (int i)
 {
   struct S {
-    int ar[1][i];  // { dg-error "9:size of array .ar. is not an integral" "" { target c++11 } }
+    int ar[1][i];  // { dg-error "15:size of array .ar. is not an integral" "" { target c++11 } }
 // { dg-error "array bound" "" { target c++98_only } .-1 }
   } s;
 
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/new44.C b/gcc/testsuite/g++.dg/init/new44.C
index 4ab7320..5c81c2c 100644
--- a/gcc/testsuite/g++.dg/init/new44.C
+++ b/gcc/testsuite/g++.dg/init/new44.C
@@ -1,4 +1,5 @@
 // { dg-do compile }
+// { dg-options "-ftrack-macro-expansion=0" }
 
 // Test for PR c++/67927 - array new expression with excessive number
 // of elements not diagnosed.
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..171061b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/pr43064-1.C
@@ -0,0 +1,37 @@
+/* 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 "" } */
+};
+
+class Y {
+  Y() : bad(-1), // { dg-error "invalid conversion from 'int' to 'void\\*'" }
+	good(42)
+  { }
+  
+  void* bad;
+  int good;
+
+  /* { dg-begin-multiline-output "" }
+   Y() : bad(-1),
+             ^~
+             |
+             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/other/fold1.C b/gcc/testsuite/g++.dg/other/fold1.C
index 25f9acc..8d8df3d 100644
--- a/gcc/testsuite/g++.dg/other/fold1.C
+++ b/gcc/testsuite/g++.dg/other/fold1.C
@@ -4,5 +4,5 @@
 struct A
 {
     static const int i = i;  // { dg-error "not declared" }
-    int x[i];		     // { dg-error "9:size of array .x. is not an integral constant-expression" }
+    int x[i];		     // { dg-error "11:size of array .x. is not an integral constant-expression" }
 };
diff --git a/gcc/testsuite/g++.dg/parse/crash36.C b/gcc/testsuite/g++.dg/parse/crash36.C
index 14fcdd8..8a2b6f3 100644
--- a/gcc/testsuite/g++.dg/parse/crash36.C
+++ b/gcc/testsuite/g++.dg/parse/crash36.C
@@ -9,4 +9,4 @@ template <typename... T> struct A	// { dg-warning "variadic templates" }
   static const int i = sizeof (++t);	// { dg-error "was not declared in this scope" }
 };
 
-int x[A <int>::i];		// { dg-error "5:size of array .x. is not an integral constant-expression" }
+int x[A <int>::i];		// { dg-error "16:size of array .x. is not an integral constant-expression" }
diff --git a/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C b/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C
index c08fec4..288da2c 100644
--- a/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C
+++ b/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C
@@ -63,6 +63,13 @@ void test_integer_constants (void)
    __emit_expression_range (0, 0);
                                ^
    { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, -273); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, -273);
+                               ^~~~
+   { dg-end-multiline-output "" } */
+
 }
 
 void test_character_constants (void)
@@ -111,6 +118,13 @@ void test_floating_constants (void)
    __emit_expression_range (0, 6.022140857e23l );
                                ^~~~~~~~~~~~~~~
    { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, -273.15f); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, -273.15f);
+                               ^~~~~~~~
+   { dg-end-multiline-output "" } */
+
 }
 
 enum test_enum {
diff --git a/gcc/testsuite/g++.dg/template/defarg6.C b/gcc/testsuite/g++.dg/template/defarg6.C
index 15848a1..f5fd6b6 100644
--- a/gcc/testsuite/g++.dg/template/defarg6.C
+++ b/gcc/testsuite/g++.dg/template/defarg6.C
@@ -14,14 +14,12 @@ struct C
 template <typename T>
 struct D
 {
-  static void func (X &ref = a); // not an error at this point
+  static void func (X &ref = a); // { dg-error "cannot bind non-const lvalue reference" }
 };
 
 void Foo (X & obj)
 {
   D<int>::func (obj);
 
-  D<int>::func (); // { dg-error "" }
+  D<int>::func (); // { dg-message "when instantiating default argument for call" }
 }
-
-// { dg-prune-output "passing argument" }
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/testsuite/g++.old-deja/g++.bugs/900402_02.C b/gcc/testsuite/g++.old-deja/g++.bugs/900402_02.C
index 46a3ec3..21e2765 100644
--- a/gcc/testsuite/g++.old-deja/g++.bugs/900402_02.C
+++ b/gcc/testsuite/g++.old-deja/g++.bugs/900402_02.C
@@ -6,17 +6,17 @@
 
 // keywords: arrays, array bound, zero length
 
-typedef int array_type[0];		// { dg-error "13:ISO C\\+\\+ forbids zero-size array" }
+typedef int array_type[0];		// { dg-error "24:ISO C\\+\\+ forbids zero-size array" }
 
-int array_object_1[0];			// { dg-error "5:ISO C\\+\\+ forbids zero-size array" }
+int array_object_1[0];			// { dg-error "20:ISO C\\+\\+ forbids zero-size array" }
 
-void function_0 (int formal_array[0])	// { dg-error "22:ISO C\\+\\+ forbids zero-size array" }
+void function_0 (int formal_array[0])	// { dg-error "35:ISO C\\+\\+ forbids zero-size array" }
 {
 }
 
 void function_2 ()
 {
-  int local_object_array_0[0];		// { dg-error "7:ISO C\\+\\+ forbids zero-size array" }
+  int local_object_array_0[0];		// { dg-error "28:ISO C\\+\\+ forbids zero-size array" }
 }
 
 int main () { return 0; }
diff --git a/gcc/tree.c b/gcc/tree.c
index 170ef13..5d0d4d3 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -2208,6 +2208,9 @@ build_string (int len, const char *str)
 tree
 build_complex (tree type, tree real, tree imag)
 {
+  gcc_assert (CONSTANT_CLASS_P (real));
+  gcc_assert (CONSTANT_CLASS_P (imag));
+
   tree t = make_node (COMPLEX_CST);
 
   TREE_REALPART (t) = real;
@@ -2506,11 +2509,13 @@ zerop (const_tree expr)
 }
 
 /* Return 1 if EXPR is the integer constant zero or a complex constant
-   of zero.  */
+   of zero, or a location wrapper for such a constant.  */
 
 bool
 integer_zerop (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   switch (TREE_CODE (expr))
     {
     case INTEGER_CST:
@@ -2528,11 +2533,13 @@ integer_zerop (const_tree expr)
 }
 
 /* Return 1 if EXPR is the integer constant one or the corresponding
-   complex constant.  */
+   complex constant, or a location wrapper for such a constant.  */
 
 bool
 integer_onep (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   switch (TREE_CODE (expr))
     {
     case INTEGER_CST:
@@ -2550,11 +2557,14 @@ integer_onep (const_tree expr)
 }
 
 /* Return 1 if EXPR is the integer constant one.  For complex and vector,
-   return 1 if every piece is the integer constant one.  */
+   return 1 if every piece is the integer constant one.
+   Also return 1 for location wrappers for such a constant.  */
 
 bool
 integer_each_onep (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   if (TREE_CODE (expr) == COMPLEX_CST)
     return (integer_onep (TREE_REALPART (expr))
 	    && integer_onep (TREE_IMAGPART (expr)));
@@ -2563,11 +2573,14 @@ integer_each_onep (const_tree expr)
 }
 
 /* Return 1 if EXPR is an integer containing all 1's in as much precision as
-   it contains, or a complex or vector whose subparts are such integers.  */
+   it contains, or a complex or vector whose subparts are such integers,
+   or a location wrapper for such a constant.  */
 
 bool
 integer_all_onesp (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   if (TREE_CODE (expr) == COMPLEX_CST
       && integer_all_onesp (TREE_REALPART (expr))
       && integer_all_onesp (TREE_IMAGPART (expr)))
@@ -2585,11 +2598,14 @@ integer_all_onesp (const_tree expr)
 	  == wi::to_wide (expr));
 }
 
-/* Return 1 if EXPR is the integer constant minus one.  */
+/* Return 1 if EXPR is the integer constant minus one, or a location wrapper
+   for such a constant.  */
 
 bool
 integer_minus_onep (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   if (TREE_CODE (expr) == COMPLEX_CST)
     return (integer_all_onesp (TREE_REALPART (expr))
 	    && integer_zerop (TREE_IMAGPART (expr)));
@@ -2598,11 +2614,13 @@ integer_minus_onep (const_tree expr)
 }
 
 /* Return 1 if EXPR is an integer constant that is a power of 2 (i.e., has only
-   one bit on).  */
+   one bit on), or a location wrapper for such a constant.  */
 
 bool
 integer_pow2p (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   if (TREE_CODE (expr) == COMPLEX_CST
       && integer_pow2p (TREE_REALPART (expr))
       && integer_zerop (TREE_IMAGPART (expr)))
@@ -2615,11 +2633,14 @@ integer_pow2p (const_tree expr)
 }
 
 /* Return 1 if EXPR is an integer constant other than zero or a
-   complex constant other than zero.  */
+   complex constant other than zero, or a location wrapper for such a
+   constant.  */
 
 bool
 integer_nonzerop (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   return ((TREE_CODE (expr) == INTEGER_CST
 	   && wi::to_wide (expr) != 0)
 	  || (TREE_CODE (expr) == COMPLEX_CST
@@ -2629,21 +2650,27 @@ integer_nonzerop (const_tree expr)
 
 /* Return 1 if EXPR is the integer constant one.  For vector,
    return 1 if every piece is the integer constant minus one
-   (representing the value TRUE).  */
+   (representing the value TRUE).
+   Also return 1 for location wrappers for such a constant.  */
 
 bool
 integer_truep (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   if (TREE_CODE (expr) == VECTOR_CST)
     return integer_all_onesp (expr);
   return integer_onep (expr);
 }
 
-/* Return 1 if EXPR is the fixed-point constant zero.  */
+/* Return 1 if EXPR is the fixed-point constant zero, or a location wrapper
+   for such a constant.  */
 
 bool
 fixed_zerop (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   return (TREE_CODE (expr) == FIXED_CST
 	  && TREE_FIXED_CST (expr).data.is_zero ());
 }
@@ -2784,11 +2811,14 @@ tree_ctz (const_tree expr)
 }
 
 /* Return 1 if EXPR is the real constant zero.  Trailing zeroes matter for
-   decimal float constants, so don't return 1 for them.  */
+   decimal float constants, so don't return 1 for them.
+   Also return 1 for location wrappers around such a constant.  */
 
 bool
 real_zerop (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   switch (TREE_CODE (expr))
     {
     case REAL_CST:
@@ -2814,11 +2844,14 @@ real_zerop (const_tree expr)
 
 /* Return 1 if EXPR is the real constant one in real or complex form.
    Trailing zeroes matter for decimal float constants, so don't return
-   1 for them.  */
+   1 for them.
+   Also return 1 for location wrappers around such a constant.  */
 
 bool
 real_onep (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   switch (TREE_CODE (expr))
     {
     case REAL_CST:
@@ -2837,11 +2870,14 @@ real_onep (const_tree expr)
 }
 
 /* Return 1 if EXPR is the real constant minus one.  Trailing zeroes
-   matter for decimal float constants, so don't return 1 for them.  */
+   matter for decimal float constants, so don't return 1 for them.
+   Also return 1 for location wrappers around such a constant.  */
 
 bool
 real_minus_onep (const_tree expr)
 {
+  STRIP_ANY_LOCATION_WRAPPER (expr);
+
   switch (TREE_CODE (expr))
     {
     case REAL_CST:
@@ -7106,6 +7142,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))
@@ -7266,6 +7305,15 @@ simple_cst_equal (const_tree t1, const_tree t2)
   if (t1 == 0 || t2 == 0)
     return 0;
 
+  /* For location wrappers to be the same, they must be at the same
+     source location (and wrap the same thing).  */
+  if (location_wrapper_p (t1) && location_wrapper_p (t2))
+    {
+      if (EXPR_LOCATION (t1) != EXPR_LOCATION (t2))
+	return 0;
+      return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+    }
+
   code1 = TREE_CODE (t1);
   code2 = TREE_CODE (t2);
 
@@ -11226,11 +11274,14 @@ uniform_vector_p (const_tree vec)
 
 /* If the argument is INTEGER_CST, return it.  If the argument is vector
    with all elements the same INTEGER_CST, return that INTEGER_CST.  Otherwise
-   return NULL_TREE.  */
+   return NULL_TREE.
+   Look through location wrappers. */
 
 tree
 uniform_integer_cst_p (tree t)
 {
+  STRIP_ANY_LOCATION_WRAPPER (t);
+
   if (TREE_CODE (t) == INTEGER_CST)
     return t;
 
@@ -14646,6 +14697,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)))
@@ -14656,6 +14712,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 *
@@ -15146,6 +15204,323 @@ test_location_wrappers ()
   check_strip_nops (wrapped_int_var, int_var);
 }
 
+/* Test various tree predicates.  Verify that location wrappers don't
+   affect the results.  */
+
+static void
+test_predicates ()
+{
+  /* Build various constants and wrappers around them.  */
+
+  location_t loc = BUILTINS_LOCATION;
+
+  tree i_0 = build_int_cst (integer_type_node, 0);
+  tree wr_i_0 = maybe_wrap_with_location (i_0, loc);
+
+  tree i_1 = build_int_cst (integer_type_node, 1);
+  tree wr_i_1 = maybe_wrap_with_location (i_1, loc);
+
+  tree i_m1 = build_int_cst (integer_type_node, -1);
+  tree wr_i_m1 = maybe_wrap_with_location (i_m1, loc);
+
+  tree f_0 = build_real_from_int_cst (float_type_node, i_0);
+  tree wr_f_0 = maybe_wrap_with_location (f_0, loc);
+  tree f_1 = build_real_from_int_cst (float_type_node, i_1);
+  tree wr_f_1 = maybe_wrap_with_location (f_1, loc);
+  tree f_m1 = build_real_from_int_cst (float_type_node, i_m1);
+  tree wr_f_m1 = maybe_wrap_with_location (f_m1, loc);
+
+  tree c_i_0 = build_complex (NULL_TREE, i_0, i_0);
+  tree c_i_1 = build_complex (NULL_TREE, i_1, i_0);
+  tree c_i_m1 = build_complex (NULL_TREE, i_m1, i_0);
+
+  tree c_f_0 = build_complex (NULL_TREE, f_0, f_0);
+  tree c_f_1 = build_complex (NULL_TREE, f_1, f_0);
+  tree c_f_m1 = build_complex (NULL_TREE, f_m1, f_0);
+
+  /* TODO: vector constants.  */
+
+  /* Test integer_onep.  */
+  ASSERT_FALSE (integer_onep (i_0));
+  ASSERT_FALSE (integer_onep (wr_i_0));
+  ASSERT_TRUE (integer_onep (i_1));
+  ASSERT_TRUE (integer_onep (wr_i_1));
+  ASSERT_FALSE (integer_onep (i_m1));
+  ASSERT_FALSE (integer_onep (wr_i_m1));
+  ASSERT_FALSE (integer_onep (f_0));
+  ASSERT_FALSE (integer_onep (wr_f_0));
+  ASSERT_FALSE (integer_onep (f_1));
+  ASSERT_FALSE (integer_onep (wr_f_1));
+  ASSERT_FALSE (integer_onep (f_m1));
+  ASSERT_FALSE (integer_onep (wr_f_m1));
+  ASSERT_FALSE (integer_onep (c_i_0));
+  ASSERT_TRUE (integer_onep (c_i_1));
+  ASSERT_FALSE (integer_onep (c_i_m1));
+  ASSERT_FALSE (integer_onep (c_f_0));
+  ASSERT_FALSE (integer_onep (c_f_1));
+  ASSERT_FALSE (integer_onep (c_f_m1));
+
+  /* Test integer_zerop.  */
+  ASSERT_TRUE (integer_zerop (i_0));
+  ASSERT_TRUE (integer_zerop (wr_i_0));
+  ASSERT_FALSE (integer_zerop (i_1));
+  ASSERT_FALSE (integer_zerop (wr_i_1));
+  ASSERT_FALSE (integer_zerop (i_m1));
+  ASSERT_FALSE (integer_zerop (wr_i_m1));
+  ASSERT_FALSE (integer_zerop (f_0));
+  ASSERT_FALSE (integer_zerop (wr_f_0));
+  ASSERT_FALSE (integer_zerop (f_1));
+  ASSERT_FALSE (integer_zerop (wr_f_1));
+  ASSERT_FALSE (integer_zerop (f_m1));
+  ASSERT_FALSE (integer_zerop (wr_f_m1));
+  ASSERT_TRUE (integer_zerop (c_i_0));
+  ASSERT_FALSE (integer_zerop (c_i_1));
+  ASSERT_FALSE (integer_zerop (c_i_m1));
+  ASSERT_FALSE (integer_zerop (c_f_0));
+  ASSERT_FALSE (integer_zerop (c_f_1));
+  ASSERT_FALSE (integer_zerop (c_f_m1));
+
+  /* Test integer_all_onesp.  */
+  ASSERT_FALSE (integer_all_onesp (i_0));
+  ASSERT_FALSE (integer_all_onesp (wr_i_0));
+  ASSERT_FALSE (integer_all_onesp (i_1));
+  ASSERT_FALSE (integer_all_onesp (wr_i_1));
+  ASSERT_TRUE (integer_all_onesp (i_m1));
+  ASSERT_TRUE (integer_all_onesp (wr_i_m1));
+  ASSERT_FALSE (integer_all_onesp (f_0));
+  ASSERT_FALSE (integer_all_onesp (wr_f_0));
+  ASSERT_FALSE (integer_all_onesp (f_1));
+  ASSERT_FALSE (integer_all_onesp (wr_f_1));
+  ASSERT_FALSE (integer_all_onesp (f_m1));
+  ASSERT_FALSE (integer_all_onesp (wr_f_m1));
+  ASSERT_FALSE (integer_all_onesp (c_i_0));
+  ASSERT_FALSE (integer_all_onesp (c_i_1));
+  ASSERT_FALSE (integer_all_onesp (c_i_m1));
+  ASSERT_FALSE (integer_all_onesp (c_f_0));
+  ASSERT_FALSE (integer_all_onesp (c_f_1));
+  ASSERT_FALSE (integer_all_onesp (c_f_m1));
+
+  /* Test integer_minus_onep.  */
+  ASSERT_FALSE (integer_minus_onep (i_0));
+  ASSERT_FALSE (integer_minus_onep (wr_i_0));
+  ASSERT_FALSE (integer_minus_onep (i_1));
+  ASSERT_FALSE (integer_minus_onep (wr_i_1));
+  ASSERT_TRUE (integer_minus_onep (i_m1));
+  ASSERT_TRUE (integer_minus_onep (wr_i_m1));
+  ASSERT_FALSE (integer_minus_onep (f_0));
+  ASSERT_FALSE (integer_minus_onep (wr_f_0));
+  ASSERT_FALSE (integer_minus_onep (f_1));
+  ASSERT_FALSE (integer_minus_onep (wr_f_1));
+  ASSERT_FALSE (integer_minus_onep (f_m1));
+  ASSERT_FALSE (integer_minus_onep (wr_f_m1));
+  ASSERT_FALSE (integer_minus_onep (c_i_0));
+  ASSERT_FALSE (integer_minus_onep (c_i_1));
+  ASSERT_TRUE (integer_minus_onep (c_i_m1));
+  ASSERT_FALSE (integer_minus_onep (c_f_0));
+  ASSERT_FALSE (integer_minus_onep (c_f_1));
+  ASSERT_FALSE (integer_minus_onep (c_f_m1));
+
+  /* Test integer_each_onep.  */
+  ASSERT_FALSE (integer_each_onep (i_0));
+  ASSERT_FALSE (integer_each_onep (wr_i_0));
+  ASSERT_TRUE (integer_each_onep (i_1));
+  ASSERT_TRUE (integer_each_onep (wr_i_1));
+  ASSERT_FALSE (integer_each_onep (i_m1));
+  ASSERT_FALSE (integer_each_onep (wr_i_m1));
+  ASSERT_FALSE (integer_each_onep (f_0));
+  ASSERT_FALSE (integer_each_onep (wr_f_0));
+  ASSERT_FALSE (integer_each_onep (f_1));
+  ASSERT_FALSE (integer_each_onep (wr_f_1));
+  ASSERT_FALSE (integer_each_onep (f_m1));
+  ASSERT_FALSE (integer_each_onep (wr_f_m1));
+  ASSERT_FALSE (integer_each_onep (c_i_0));
+  ASSERT_FALSE (integer_each_onep (c_i_1));
+  ASSERT_FALSE (integer_each_onep (c_i_m1));
+  ASSERT_FALSE (integer_each_onep (c_f_0));
+  ASSERT_FALSE (integer_each_onep (c_f_1));
+  ASSERT_FALSE (integer_each_onep (c_f_m1));
+
+  /* Test integer_truep.  */
+  ASSERT_FALSE (integer_truep (i_0));
+  ASSERT_FALSE (integer_truep (wr_i_0));
+  ASSERT_TRUE (integer_truep (i_1));
+  ASSERT_TRUE (integer_truep (wr_i_1));
+  ASSERT_FALSE (integer_truep (i_m1));
+  ASSERT_FALSE (integer_truep (wr_i_m1));
+  ASSERT_FALSE (integer_truep (f_0));
+  ASSERT_FALSE (integer_truep (wr_f_0));
+  ASSERT_FALSE (integer_truep (f_1));
+  ASSERT_FALSE (integer_truep (wr_f_1));
+  ASSERT_FALSE (integer_truep (f_m1));
+  ASSERT_FALSE (integer_truep (wr_f_m1));
+  ASSERT_FALSE (integer_truep (c_i_0));
+  ASSERT_TRUE (integer_truep (c_i_1));
+  ASSERT_FALSE (integer_truep (c_i_m1));
+  ASSERT_FALSE (integer_truep (c_f_0));
+  ASSERT_FALSE (integer_truep (c_f_1));
+  ASSERT_FALSE (integer_truep (c_f_m1));
+
+  /* Test integer_nonzerop.  */
+  ASSERT_FALSE (integer_nonzerop (i_0));
+  ASSERT_FALSE (integer_nonzerop (wr_i_0));
+  ASSERT_TRUE (integer_nonzerop (i_1));
+  ASSERT_TRUE (integer_nonzerop (wr_i_1));
+  ASSERT_TRUE (integer_nonzerop (i_m1));
+  ASSERT_TRUE (integer_nonzerop (wr_i_m1));
+  ASSERT_FALSE (integer_nonzerop (f_0));
+  ASSERT_FALSE (integer_nonzerop (wr_f_0));
+  ASSERT_FALSE (integer_nonzerop (f_1));
+  ASSERT_FALSE (integer_nonzerop (wr_f_1));
+  ASSERT_FALSE (integer_nonzerop (f_m1));
+  ASSERT_FALSE (integer_nonzerop (wr_f_m1));
+  ASSERT_FALSE (integer_nonzerop (c_i_0));
+  ASSERT_TRUE (integer_nonzerop (c_i_1));
+  ASSERT_TRUE (integer_nonzerop (c_i_m1));
+  ASSERT_FALSE (integer_nonzerop (c_f_0));
+  ASSERT_FALSE (integer_nonzerop (c_f_1));
+  ASSERT_FALSE (integer_nonzerop (c_f_m1));
+
+  /* Test real_zerop.  */
+  ASSERT_FALSE (real_zerop (i_0));
+  ASSERT_FALSE (real_zerop (wr_i_0));
+  ASSERT_FALSE (real_zerop (i_1));
+  ASSERT_FALSE (real_zerop (wr_i_1));
+  ASSERT_FALSE (real_zerop (i_m1));
+  ASSERT_FALSE (real_zerop (wr_i_m1));
+  ASSERT_TRUE (real_zerop (f_0));
+  ASSERT_TRUE (real_zerop (wr_f_0));
+  ASSERT_FALSE (real_zerop (f_1));
+  ASSERT_FALSE (real_zerop (wr_f_1));
+  ASSERT_FALSE (real_zerop (f_m1));
+  ASSERT_FALSE (real_zerop (wr_f_m1));
+  ASSERT_FALSE (real_zerop (c_i_0));
+  ASSERT_FALSE (real_zerop (c_i_1));
+  ASSERT_FALSE (real_zerop (c_i_m1));
+  ASSERT_TRUE (real_zerop (c_f_0));
+  ASSERT_FALSE (real_zerop (c_f_1));
+  ASSERT_FALSE (real_zerop (c_f_m1));
+
+  /* Test real_onep.  */
+  ASSERT_FALSE (real_onep (i_0));
+  ASSERT_FALSE (real_onep (wr_i_0));
+  ASSERT_FALSE (real_onep (i_1));
+  ASSERT_FALSE (real_onep (wr_i_1));
+  ASSERT_FALSE (real_onep (i_m1));
+  ASSERT_FALSE (real_onep (wr_i_m1));
+  ASSERT_FALSE (real_onep (f_0));
+  ASSERT_FALSE (real_onep (wr_f_0));
+  ASSERT_TRUE (real_onep (f_1));
+  ASSERT_TRUE (real_onep (wr_f_1));
+  ASSERT_FALSE (real_onep (f_m1));
+  ASSERT_FALSE (real_onep (wr_f_m1));
+  ASSERT_FALSE (real_onep (c_i_0));
+  ASSERT_FALSE (real_onep (c_i_1));
+  ASSERT_FALSE (real_onep (c_i_m1));
+  ASSERT_FALSE (real_onep (c_f_0));
+  ASSERT_TRUE (real_onep (c_f_1));
+  ASSERT_FALSE (real_onep (c_f_m1));
+
+  /* Test real_minus_onep.  */
+  ASSERT_FALSE (real_minus_onep (i_0));
+  ASSERT_FALSE (real_minus_onep (wr_i_0));
+  ASSERT_FALSE (real_minus_onep (i_1));
+  ASSERT_FALSE (real_minus_onep (wr_i_1));
+  ASSERT_FALSE (real_minus_onep (i_m1));
+  ASSERT_FALSE (real_minus_onep (wr_i_m1));
+  ASSERT_FALSE (real_minus_onep (f_0));
+  ASSERT_FALSE (real_minus_onep (wr_f_0));
+  ASSERT_FALSE (real_minus_onep (f_1));
+  ASSERT_FALSE (real_minus_onep (wr_f_1));
+  ASSERT_TRUE (real_minus_onep (f_m1));
+  ASSERT_TRUE (real_minus_onep (wr_f_m1));
+  ASSERT_FALSE (real_minus_onep (c_i_0));
+  ASSERT_FALSE (real_minus_onep (c_i_1));
+  ASSERT_FALSE (real_minus_onep (c_i_m1));
+  ASSERT_FALSE (real_minus_onep (c_f_0));
+  ASSERT_FALSE (real_minus_onep (c_f_1));
+  ASSERT_TRUE (real_minus_onep (c_f_m1));
+
+  /* Test zerop.  */
+  ASSERT_TRUE (zerop (i_0));
+  ASSERT_TRUE (zerop (wr_i_0));
+  ASSERT_FALSE (zerop (i_1));
+  ASSERT_FALSE (zerop (wr_i_1));
+  ASSERT_FALSE (zerop (i_m1));
+  ASSERT_FALSE (zerop (wr_i_m1));
+  ASSERT_TRUE (zerop (f_0));
+  ASSERT_TRUE (zerop (wr_f_0));
+  ASSERT_FALSE (zerop (f_1));
+  ASSERT_FALSE (zerop (wr_f_1));
+  ASSERT_FALSE (zerop (f_m1));
+  ASSERT_FALSE (zerop (wr_f_m1));
+  ASSERT_TRUE (zerop (c_i_0));
+  ASSERT_FALSE (zerop (c_i_1));
+  ASSERT_FALSE (zerop (c_i_m1));
+  ASSERT_TRUE (zerop (c_f_0));
+  ASSERT_FALSE (zerop (c_f_1));
+  ASSERT_FALSE (zerop (c_f_m1));
+
+  /* Test tree_expr_nonnegative_p.  */
+  ASSERT_TRUE (tree_expr_nonnegative_p (i_0));
+  ASSERT_TRUE (tree_expr_nonnegative_p (wr_i_0));
+  ASSERT_TRUE (tree_expr_nonnegative_p (i_1));
+  ASSERT_TRUE (tree_expr_nonnegative_p (wr_i_1));
+  ASSERT_FALSE (tree_expr_nonnegative_p (i_m1));
+  ASSERT_FALSE (tree_expr_nonnegative_p (wr_i_m1));
+  ASSERT_TRUE (tree_expr_nonnegative_p (f_0));
+  ASSERT_TRUE (tree_expr_nonnegative_p (wr_f_0));
+  ASSERT_TRUE (tree_expr_nonnegative_p (f_1));
+  ASSERT_TRUE (tree_expr_nonnegative_p (wr_f_1));
+  ASSERT_FALSE (tree_expr_nonnegative_p (f_m1));
+  ASSERT_FALSE (tree_expr_nonnegative_p (wr_f_m1));
+  ASSERT_FALSE (tree_expr_nonnegative_p (c_i_0));
+  ASSERT_FALSE (tree_expr_nonnegative_p (c_i_1));
+  ASSERT_FALSE (tree_expr_nonnegative_p (c_i_m1));
+  ASSERT_FALSE (tree_expr_nonnegative_p (c_f_0));
+  ASSERT_FALSE (tree_expr_nonnegative_p (c_f_1));
+  ASSERT_FALSE (tree_expr_nonnegative_p (c_f_m1));
+
+  /* Test tree_expr_nonzero_p.  */
+  ASSERT_FALSE (tree_expr_nonzero_p (i_0));
+  ASSERT_FALSE (tree_expr_nonzero_p (wr_i_0));
+  ASSERT_TRUE (tree_expr_nonzero_p (i_1));
+  ASSERT_TRUE (tree_expr_nonzero_p (wr_i_1));
+  ASSERT_TRUE (tree_expr_nonzero_p (i_m1));
+  ASSERT_TRUE (tree_expr_nonzero_p (wr_i_m1));
+
+  /* Test integer_valued_real_p.  */
+  ASSERT_FALSE (integer_valued_real_p (i_0));
+  ASSERT_TRUE (integer_valued_real_p (f_0));
+  ASSERT_TRUE (integer_valued_real_p (wr_f_0));
+  ASSERT_TRUE (integer_valued_real_p (f_1));
+  ASSERT_TRUE (integer_valued_real_p (wr_f_1));
+
+  /* Test integer_pow2p.  */
+  ASSERT_FALSE (integer_pow2p (i_0));
+  ASSERT_TRUE (integer_pow2p (i_1));
+  ASSERT_TRUE (integer_pow2p (wr_i_1));
+
+  /* Test uniform_integer_cst_p.  */
+  ASSERT_TRUE (uniform_integer_cst_p (i_0));
+  ASSERT_TRUE (uniform_integer_cst_p (wr_i_0));
+  ASSERT_TRUE (uniform_integer_cst_p (i_1));
+  ASSERT_TRUE (uniform_integer_cst_p (wr_i_1));
+  ASSERT_TRUE (uniform_integer_cst_p (i_m1));
+  ASSERT_TRUE (uniform_integer_cst_p (wr_i_m1));
+  ASSERT_FALSE (uniform_integer_cst_p (f_0));
+  ASSERT_FALSE (uniform_integer_cst_p (wr_f_0));
+  ASSERT_FALSE (uniform_integer_cst_p (f_1));
+  ASSERT_FALSE (uniform_integer_cst_p (wr_f_1));
+  ASSERT_FALSE (uniform_integer_cst_p (f_m1));
+  ASSERT_FALSE (uniform_integer_cst_p (wr_f_m1));
+  ASSERT_FALSE (uniform_integer_cst_p (c_i_0));
+  ASSERT_FALSE (uniform_integer_cst_p (c_i_1));
+  ASSERT_FALSE (uniform_integer_cst_p (c_i_m1));
+  ASSERT_FALSE (uniform_integer_cst_p (c_f_0));
+  ASSERT_FALSE (uniform_integer_cst_p (c_f_1));
+  ASSERT_FALSE (uniform_integer_cst_p (c_f_m1));
+}
+
 /* Check that string escaping works correctly.  */
 
 static void
@@ -15199,6 +15574,7 @@ tree_c_tests ()
   test_labels ();
   test_vector_cst_patterns ();
   test_location_wrappers ();
+  test_predicates ();
   test_escaped_strings ();
 }
 
diff --git a/gcc/tree.h b/gcc/tree.h
index 761b508..ab928ca 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)
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] v6: C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
  2018-12-18 20:34                     ` [PATCH] v6: " David Malcolm
@ 2018-12-18 20:40                       ` Jason Merrill
  2018-12-19 15:35                         ` David Malcolm
  0 siblings, 1 reply; 34+ messages in thread
From: Jason Merrill @ 2018-12-18 20:40 UTC (permalink / raw)
  To: David Malcolm; +Cc: Jeff Law, gcc-patches

On 12/18/18 4:22 PM, David Malcolm wrote:
> On Mon, 2018-12-17 at 18:30 -0500, David Malcolm wrote:
>> On Mon, 2018-12-17 at 14:33 -0500, Jason Merrill wrote:
>>> On 12/14/18 7:17 PM, David Malcolm wrote:
>>>> +      /* 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).  */
>>>
>>> Hmm, looking at this again, why would this happen?  I see that
>>> type_list_equal uses == to compare default arguments, so two
>>> function
>>> types with the same default argument but different location
>>> wrappers
>>> shouldn't be combined.
>>>
>>> Jason
>>
>> Thanks.
>>
>> I did some digging into this.  I added this strip to fix
>>    g++.dg/template/defarg6.C
>> but it looks like I was overzealous (the comment is correct, but it's
>> papering over a problem).
>>
>> It turns out that type_list_equal is doing more than just pointer
>> equality; it's hitting the simple_cst_equal part of the && at line
>> 7071:
>>
>> 7063	bool
>> 7064	type_list_equal (const_tree l1, const_tree l2)
>> 7065	{
>> 7066	  const_tree t1, t2;
>> 7067	
>> 7068	  for (t1 = l1, t2 = l2; t1 && t2; t1 = TREE_CHAIN (t1),
>> t2 = TREE_CHAIN (t2))
>> 7069	    if (TREE_VALUE (t1) != TREE_VALUE (t2)
>> 7070		|| (TREE_PURPOSE (t1) != TREE_PURPOSE (t2)
>> 7071		    && ! (1 == simple_cst_equal (TREE_PURPOSE
>> (t1), TREE_PURPOSE (t2))
>> 7072			  && (TREE_TYPE (TREE_PURPOSE (t1))
>> 7073			      == TREE_TYPE (TREE_PURPOSE
>> (t2))))))
>> 7074	      return false;
>> 7075	
>> 7076	  return t1 == t2;
>> 7077	}
>>
>> What's happening is that there are two different functions with
>> identical types apart from the locations of their (equal) default
>> arguments: both of the TREE_PURPOSEs are NON_LVALUE_EXPR wrappers
>> around a CONST_DECL enum value (at different source locations).
>>
>> simple_cst_equal is stripping the location wrappers here:
>>
>> 7311	  if (CONVERT_EXPR_CODE_P (code1) || code1 ==
>> NON_LVALUE_EXPR)
>> 7312	    {
>> 7313	      if (CONVERT_EXPR_CODE_P (code2)
>> 7314		  || code2 == NON_LVALUE_EXPR)
>> 7315		return simple_cst_equal (TREE_OPERAND (t1, 0),
>> TREE_OPERAND (t2, 0));
>> 7316	      else
>> 7317		return simple_cst_equal (TREE_OPERAND (t1, 0),
>> t2);
>> 7318	    }
>>
>> and thus finds them to be equal; the iteration in type_list_equal
>> continues, and runs out of parameters with t1 == t2 == NULL, and thus
>> returns true, and thus the two function types hash to the same slot,
>> and the two function types get treated as being the same.
>>
>> It's not clear to me yet what the best solution to this is:
>> - should simple_cst_equal regard different source locations as being
>> different?
>> - should function-type hashing use a custom version of
>> type_list_equal
>> when comparing params, and make different source locations of default
>> args be different?
>> - something else?
>>
>> Dave
> 
> I tried both of the above approaches, and both work.
> 
> Here's v6 of the patch:
> 
> I removed the strip of wrappers in cp_parser_late_parsing_default_args
> from earlier versions of the patch, in favor of fixing simple_cst_equal
> so that it treats location wrappers with unequal source locations as
> being unequal.  This ensures that function-types with default arguments
> don't get merged when the default argument constants have different
> spelling locations.  [I have an alternative patch which instead
> introduces a different comparator for FUNCTION_TYPE's TYPE_ARG_TYPES
> within type_cache_hasher::equal, almost identical to type_list_equal,
> but adding the requirement that  location wrappers around default
> arguments have equal source location for the params to be considered
> equal; both patches pass bootstrap&regression testing]
> 
> Doing so leads to the reported location for the bad default argument
> within a template in g++.dg/template/defarg6.C moving to the argument
> location.  Previously, the callsite of the instantiation was identified
> due to the use of input_location in convert_like_real here:
> 
> 6816	  location_t loc = cp_expr_loc_or_loc (expr, input_location);
> 
> With a location wrapper, it uses the spelling location of the
> default argument, but doesn't identify the location of the callsite
> that's instantiating the template.
> 
> So I moved the note in tsubst_default_argument about which callsite
> led to a diagnostic to after the check_default_argument call, so that
> diagnostics within that receive notes, too.
> 
> As before, this was successfully bootstrapped & regrtested on
> x86_64-pc-linux-gnu, in conjunction with the followup patch.
> 
> OK for trunk?

Ah, I hadn't seen this before my last email.  Let's go with this version.

Jason

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] v6: C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
  2018-12-18 20:40                       ` Jason Merrill
@ 2018-12-19 15:35                         ` David Malcolm
  0 siblings, 0 replies; 34+ messages in thread
From: David Malcolm @ 2018-12-19 15:35 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jeff Law, gcc-patches

On Tue, 2018-12-18 at 15:40 -0500, Jason Merrill wrote:
> On 12/18/18 4:22 PM, David Malcolm wrote:
> > On Mon, 2018-12-17 at 18:30 -0500, David Malcolm wrote:
> > > On Mon, 2018-12-17 at 14:33 -0500, Jason Merrill wrote:
> > > > On 12/14/18 7:17 PM, David Malcolm wrote:
> > > > > +      /* 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).  */
> > > > 
> > > > Hmm, looking at this again, why would this happen?  I see that
> > > > type_list_equal uses == to compare default arguments, so two
> > > > function
> > > > types with the same default argument but different location
> > > > wrappers
> > > > shouldn't be combined.
> > > > 
> > > > Jason
> > > 
> > > Thanks.
> > > 
> > > I did some digging into this.  I added this strip to fix
> > >    g++.dg/template/defarg6.C
> > > but it looks like I was overzealous (the comment is correct, but
> > > it's
> > > papering over a problem).
> > > 
> > > It turns out that type_list_equal is doing more than just pointer
> > > equality; it's hitting the simple_cst_equal part of the && at
> > > line
> > > 7071:
> > > 
> > > 7063	bool
> > > 7064	type_list_equal (const_tree l1, const_tree l2)
> > > 7065	{
> > > 7066	  const_tree t1, t2;
> > > 7067	
> > > 7068	  for (t1 = l1, t2 = l2; t1 && t2; t1 = TREE_CHAIN
> > > (t1),
> > > t2 = TREE_CHAIN (t2))
> > > 7069	    if (TREE_VALUE (t1) != TREE_VALUE (t2)
> > > 7070		|| (TREE_PURPOSE (t1) != TREE_PURPOSE (t2)
> > > 7071		    && ! (1 == simple_cst_equal (TREE_PURPOSE
> > > (t1), TREE_PURPOSE (t2))
> > > 7072			  && (TREE_TYPE (TREE_PURPOSE (t1))
> > > 7073			      == TREE_TYPE (TREE_PURPOSE
> > > (t2))))))
> > > 7074	      return false;
> > > 7075	
> > > 7076	  return t1 == t2;
> > > 7077	}
> > > 
> > > What's happening is that there are two different functions with
> > > identical types apart from the locations of their (equal) default
> > > arguments: both of the TREE_PURPOSEs are NON_LVALUE_EXPR wrappers
> > > around a CONST_DECL enum value (at different source locations).
> > > 
> > > simple_cst_equal is stripping the location wrappers here:
> > > 
> > > 7311	  if (CONVERT_EXPR_CODE_P (code1) || code1 ==
> > > NON_LVALUE_EXPR)
> > > 7312	    {
> > > 7313	      if (CONVERT_EXPR_CODE_P (code2)
> > > 7314		  || code2 == NON_LVALUE_EXPR)
> > > 7315		return simple_cst_equal (TREE_OPERAND (t1,
> > > 0),
> > > TREE_OPERAND (t2, 0));
> > > 7316	      else
> > > 7317		return simple_cst_equal (TREE_OPERAND (t1,
> > > 0),
> > > t2);
> > > 7318	    }
> > > 
> > > and thus finds them to be equal; the iteration in type_list_equal
> > > continues, and runs out of parameters with t1 == t2 == NULL, and
> > > thus
> > > returns true, and thus the two function types hash to the same
> > > slot,
> > > and the two function types get treated as being the same.
> > > 
> > > It's not clear to me yet what the best solution to this is:
> > > - should simple_cst_equal regard different source locations as
> > > being
> > > different?
> > > - should function-type hashing use a custom version of
> > > type_list_equal
> > > when comparing params, and make different source locations of
> > > default
> > > args be different?
> > > - something else?
> > > 
> > > Dave
> > 
> > I tried both of the above approaches, and both work.
> > 
> > Here's v6 of the patch:
> > 
> > I removed the strip of wrappers in
> > cp_parser_late_parsing_default_args
> > from earlier versions of the patch, in favor of fixing
> > simple_cst_equal
> > so that it treats location wrappers with unequal source locations
> > as
> > being unequal.  This ensures that function-types with default
> > arguments
> > don't get merged when the default argument constants have different
> > spelling locations.  [I have an alternative patch which instead
> > introduces a different comparator for FUNCTION_TYPE's
> > TYPE_ARG_TYPES
> > within type_cache_hasher::equal, almost identical to
> > type_list_equal,
> > but adding the requirement that  location wrappers around default
> > arguments have equal source location for the params to be
> > considered
> > equal; both patches pass bootstrap&regression testing]
> > 
> > Doing so leads to the reported location for the bad default
> > argument
> > within a template in g++.dg/template/defarg6.C moving to the
> > argument
> > location.  Previously, the callsite of the instantiation was
> > identified
> > due to the use of input_location in convert_like_real here:
> > 
> > 6816	  location_t loc = cp_expr_loc_or_loc (expr,
> > input_location);
> > 
> > With a location wrapper, it uses the spelling location of the
> > default argument, but doesn't identify the location of the callsite
> > that's instantiating the template.
> > 
> > So I moved the note in tsubst_default_argument about which callsite
> > led to a diagnostic to after the check_default_argument call, so
> > that
> > diagnostics within that receive notes, too.
> > 
> > As before, this was successfully bootstrapped & regrtested on
> > x86_64-pc-linux-gnu, in conjunction with the followup patch.
> > 
> > OK for trunk?
> 
> Ah, I hadn't seen this before my last email.  Let's go with this
> version.

Thanks.

I've now committed the v6 patch, and the follow-ups that were already
approved (having rebased and retested them):

r267272:
  "C++: more location wrapper nodes (PR c++/43064, PR c++/43486)"

r267273:
  "C++: improvements to binary operator diagnostics (PR c++/87504)"

r267276:
  "C++: better locations for bogus initializations (PR c++/88375)"

Dave

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
  2018-11-05 19:44 [PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486) David Malcolm
  2018-11-05 19:44 ` [PATCH 2/2] C++: improvements to binary operator diagnostics (PR c++/87504) David Malcolm
  2018-11-19 16:51 ` [PING] Re: [PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486) David Malcolm
@ 2018-12-19 19:01 ` Thomas Schwinge
  2018-12-20  2:29   ` David Malcolm
  2020-03-26  5:02   ` [PATCH, OpenACC] Bug fix for processing OpenACC data clauses in C++ Sandra Loosemore
  2 siblings, 2 replies; 34+ messages in thread
From: Thomas Schwinge @ 2018-12-19 19:01 UTC (permalink / raw)
  To: David Malcolm; +Cc: gcc-patches, jason

Hi David!

I will admit that I don't have researched ;-/ what this is actually all
about, and how it's implemented, but...

On Mon,  5 Nov 2018 15:31:08 -0500, David Malcolm <dmalcolm@redhat.com> 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

... I did wonder why things applicable to OpenMP wouldn't likewise apply
to OpenACC, too?  That is:

> 	(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.

> @@ -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=*/NULL,

Shouldn't "cp_parser_oacc_all_clauses" (and "some" other functions?) be
adjusted in the same way?  How would I test that?  (I don't see any
OpenMP test cases added -- I have not yet tried whether any problems
would become apparent when temporarily removing the OpenMP changes cited
above.)


Grüße
 Thomas

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 2/2] v2: C++: improvements to binary operator diagnostics (PR c++/87504)
  2018-12-12 20:43         ` Jason Merrill
@ 2018-12-19 23:28           ` Aaron Sawdey
  2018-12-20  2:13             ` [PATCH] -Wtautological-compare: fix comparison of macro expansions David Malcolm
  0 siblings, 1 reply; 34+ messages in thread
From: Aaron Sawdey @ 2018-12-19 23:28 UTC (permalink / raw)
  To: gcc-patches, dmalcolm

Assuming you applied this as svn 267273, it causes bootstrap failure
on powerpc64le-unknown-linux-gnu. Stage 2 fails with multiple instances
of this error:

../../trunk-base/gcc/c-family/c-pragma.c: In function ‘void handle_pragma_scalar_storage_order(cpp_reader*)’:
../../trunk-base/gcc/c-family/c-pragma.c:417:24: error: self-comparison always evaluates to false [-Werror=tautological-compare]
  417 |   if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
      |                        ^~
../../trunk-base/gcc/c-family/c-attribs.c: In function ‘tree_node* handle_scalar_storage_order_attribute(tree_node**, tree, tree, int, bool*)’:
../../trunk-base/gcc/c-family/c-attribs.c:1401:24: error: self-comparison always evaluates to false [-Werror=tautological-compare]
 1401 |   if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
      |                        ^~
../../trunk-base/gcc/builtins.c: In function ‘rtx_def* c_readstr(const char*, scalar_int_mode)’:
../../trunk-base/gcc/builtins.c:830:28: error: self-comparison always evaluates to false [-Werror=tautological-compare]
  830 |       if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
      |                            ^~
../../trunk-base/gcc/combine.c: In function ‘int rtx_equal_for_field_assignment_p(rtx, rtx, bool)’:
../../trunk-base/gcc/combine.c:9668:28: error: self-comparison always evaluates to false [-Werror=tautological-compare]
 9668 |       if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
      |                            ^~

Aaron

On 12/12/18 2:42 PM, Jason Merrill wrote:
> On 12/4/18 5:35 PM, David Malcolm wrote:
>> The v1 patch:
>>    https://gcc.gnu.org/ml/gcc-patches/2018-11/msg00303.html
>> has bitrotten somewhat, so here's v2 of the patch, updated relative
>> to r266740.
>>
>> Blurb from v1 patch follows:
>>
>> The C frontend is able (where expression locations are available) to print
>> problems with binary operators in 3-location form, labelling the types of
>> the expressions:
>>
>>    arg_0 op arg_1
>>    ~~~~~ ^~ ~~~~~
>>      |        |
>>      |        arg1 type
>>      arg0 type
>>
>> The C++ frontend currently just shows the combined location:
>>
>>    arg_0 op arg_1
>>    ~~~~~~^~~~~~~~
>>
>> and fails to highlight where the subexpressions are, or their types.
>>
>> This patch introduces a op_location_t struct for handling the above
>> operator-location vs combined-location split, and a new
>> class binary_op_rich_location for displaying the above, so that the
>> C++ frontend is able to use the more detailed 3-location form for
>> type mismatches in binary operators, and for -Wtautological-compare
>> (where types are not displayed).  Both forms can be seen in this
>> example:
>>
>> bad-binary-ops.C:69:20: error: no match for 'operator&&' (operand types are
>>    's' and 't')
>>     69 |   return ns_4::foo && ns_4::inner::bar;
>>        |          ~~~~~~~~~ ^~ ~~~~~~~~~~~~~~~~
>>        |                |                   |
>>        |                s                   t
>> bad-binary-ops.C:69:20: note: candidate: 'operator&&(bool, bool)' <built-in>
>>     69 |   return ns_4::foo && ns_4::inner::bar;
>>        |          ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
>>
>> The patch also allows from some uses of macros in
>> -Wtautological-compare, where both sides of the comparison have
>> been spelled the same way, e.g.:
>>
>> Wtautological-compare-ranges.c:23:11: warning: self-comparison always
>>     evaluates to true [-Wtautological-compare]
>>     23 |   if (FOO == FOO);
>>        |           ^~
>>
>> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu, in
>> conjunction with the previous patch.
>>
>> OK for trunk?
>> Dave
>>
>> gcc/c-family/ChangeLog:
>>     PR c++/87504
>>     * c-common.h (warn_tautological_cmp): Convert 1st param from
>>     location_t to const op_location_t &.
>>     * c-warn.c (find_array_ref_with_const_idx_r): Strip location
>>     wrapper when testing for INTEGER_CST.
>>     (warn_tautological_bitwise_comparison): Convert 1st param from
>>     location_t to const op_location_t &; use it to build a
>>     binary_op_rich_location, and use this.
>>     (spelled_the_same_p): New function.
>>     (warn_tautological_cmp): Convert 1st param from location_t to
>>     const op_location_t &.  Warn for macro expansions if
>>     spelled_the_same_p.  Use binary_op_rich_location.
>>
>> gcc/c/ChangeLog:
>>     PR c++/87504
>>     * c-typeck.c (class maybe_range_label_for_tree_type_mismatch):
>>     Move from here to gcc-rich-location.h and gcc-rich-location.c.
>>     (build_binary_op): Use struct op_location_t and
>>     class binary_op_rich_location.
>>
>> gcc/cp/ChangeLog:
>>     PR c++/87504
>>     * call.c (op_error): Convert 1st param from location_t to
>>     const op_location_t &.  Use binary_op_rich_location for binary
>>     ops.
>>     (build_conditional_expr_1): Convert 1st param from location_t to
>>     const op_location_t &.
>>     (build_conditional_expr): Likewise.
>>     (build_new_op_1): Likewise.
>>     (build_new_op): Likewise.
>>     * cp-tree.h (build_conditional_expr): Likewise.
>>     (build_new_op): Likewise.
>>     (build_x_binary_op): Likewise.
>>     (cp_build_binary_op): Likewise.
>>     * parser.c (cp_parser_primary_expression): Build a location
>>     for id-expression nodes.
>>     (cp_parser_binary_expression): Use an op_location_t when
>>     calling build_x_binary_op.
>>     (cp_parser_operator): Build a location for user-defined literals.
>>     * typeck.c (build_x_binary_op): Convert 1st param from location_t
>>     to const op_location_t &.
>>     (cp_build_binary_op): Likewise.  Use binary_op_rich_location.
>>
>> gcc/ChangeLog:
>>     PR c++/87504
>>     * gcc-rich-location.c
>>     (maybe_range_label_for_tree_type_mismatch::get_text): Move here from
>>     c/c-typeck.c.
>>     (binary_op_rich_location::binary_op_rich_location): New ctor.
>>     (binary_op_rich_location::use_operator_loc_p): New function.
>>     * gcc-rich-location.h
>>     (class maybe_range_label_for_tree_type_mismatch)): Move here from
>>     c/c-typeck.c.
>>     (struct op_location_t): New forward decl.
>>     (class binary_op_rich_location): New class.
>>     * tree.h (struct op_location_t): New struct.
>>
>> gcc/testsuite/ChangeLog:
>>     * c-c++-common/Wtautological-compare-ranges.c: New test.
>>     * g++.dg/cpp0x/pr51420.C: Add -fdiagnostics-show-caret and update
>>     expected output.
>>     * g++.dg/diagnostic/bad-binary-ops.C: Update expected output from
>>     1-location form to 3-location form, with labelling of ranges with
>>     types.  Add examples of id-expression nodes with namespaces.
>>     * g++.dg/diagnostic/param-type-mismatch-2.C: Likewise.
>>
>> This is the 2nd commit message:
>>
>> FIXME: column and multiline fixes to * g++.dg/cpp0x/pr51420.C
>> ---
>>   gcc/c-family/c-common.h                            |  3 +-
>>   gcc/c-family/c-warn.c                              | 57 +++++++++++---
>>   gcc/c/c-typeck.c                                   | 41 +---------
>>   gcc/cp/call.c                                      | 28 ++++---
>>   gcc/cp/cp-tree.h                                   | 10 ++-
>>   gcc/cp/parser.c                                    | 32 ++++++--
>>   gcc/cp/typeck.c                                    | 14 ++--
>>   gcc/gcc-rich-location.c                            | 89 ++++++++++++++++++++++
>>   gcc/gcc-rich-location.h                            | 57 ++++++++++++++
>>   .../c-c++-common/Wtautological-compare-ranges.c    | 42 ++++++++++
>>   gcc/testsuite/g++.dg/cpp0x/pr51420.C               | 10 +++
>>   gcc/testsuite/g++.dg/diagnostic/bad-binary-ops.C   | 57 +++++++++++++-
>>   .../g++.dg/diagnostic/param-type-mismatch-2.C      |  4 +-
>>   gcc/tree.h                                         | 49 ++++++++++++
>>   14 files changed, 417 insertions(+), 76 deletions(-)
>>   create mode 100644 gcc/testsuite/c-c++-common/Wtautological-compare-ranges.c
>>
>> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
>> index 4187343..0b9ddf6 100644
>> --- a/gcc/c-family/c-common.h
>> +++ b/gcc/c-family/c-common.h
>> @@ -1268,7 +1268,8 @@ extern void constant_expression_error (tree);
>>   extern void overflow_warning (location_t, tree, tree = NULL_TREE);
>>   extern void warn_logical_operator (location_t, enum tree_code, tree,
>>                      enum tree_code, tree, enum tree_code, tree);
>> -extern void warn_tautological_cmp (location_t, enum tree_code, tree, tree);
>> +extern void warn_tautological_cmp (const op_location_t &, enum tree_code,
>> +                   tree, tree);
>>   extern void warn_logical_not_parentheses (location_t, enum tree_code, tree,
>>                         tree);
>>   extern bool warn_if_unused_value (const_tree, location_t);
>> diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
>> index fc7f87c..fce9d84 100644
>> --- a/gcc/c-family/c-warn.c
>> +++ b/gcc/c-family/c-warn.c
>> @@ -322,7 +322,8 @@ find_array_ref_with_const_idx_r (tree *expr_p, int *, void *)
>>       if ((TREE_CODE (expr) == ARRAY_REF
>>          || TREE_CODE (expr) == ARRAY_RANGE_REF)
>> -      && TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST)
>> +      && (TREE_CODE (tree_strip_any_location_wrapper (TREE_OPERAND (expr, 1)))
>> +      == INTEGER_CST))
>>       return integer_type_node;
> 
> I think we want fold_for_warn here.  OK with that change (assuming it passes).
> 
> Jason
> 

-- 
Aaron Sawdey, Ph.D.  acsawdey@linux.vnet.ibm.com
050-2/C113  (507) 253-7520 home: 507/263-0782
IBM Linux Technology Center - PPC Toolchain

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH] -Wtautological-compare: fix comparison of macro expansions
  2018-12-19 23:28           ` Aaron Sawdey
@ 2018-12-20  2:13             ` David Malcolm
  2018-12-20 14:29               ` David Malcolm
  0 siblings, 1 reply; 34+ messages in thread
From: David Malcolm @ 2018-12-20  2:13 UTC (permalink / raw)
  To: Aaron Sawdey, gcc-patches; +Cc: David Malcolm

On Wed, 2018-12-19 at 17:27 -0600, Aaron Sawdey wrote:
> Assuming you applied this as svn 267273, it causes bootstrap failure
> on powerpc64le-unknown-linux-gnu. Stage 2 fails with multiple
> instances
> of this error:
> 
> ../../trunk-base/gcc/c-family/c-pragma.c: In function ‘void
> handle_pragma_scalar_storage_order(cpp_reader*)’:
> ../../trunk-base/gcc/c-family/c-pragma.c:417:24: error: self-
> comparison always evaluates to false [-Werror=tautological-compare]
>   417 |   if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
>       |                        ^~
> ../../trunk-base/gcc/c-family/c-attribs.c: In function ‘tree_node*
> handle_scalar_storage_order_attribute(tree_node**, tree, tree, int,
> bool*)’:
> ../../trunk-base/gcc/c-family/c-attribs.c:1401:24: error: self-
> comparison always evaluates to false [-Werror=tautological-compare]
>  1401 |   if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
>       |                        ^~
> ../../trunk-base/gcc/builtins.c: In function ‘rtx_def*
> c_readstr(const char*, scalar_int_mode)’:
> ../../trunk-base/gcc/builtins.c:830:28: error: self-comparison always
> evaluates to false [-Werror=tautological-compare]
>   830 |       if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
>       |                            ^~
> ../../trunk-base/gcc/combine.c: In function ‘int
> rtx_equal_for_field_assignment_p(rtx, rtx, bool)’:
> ../../trunk-base/gcc/combine.c:9668:28: error: self-comparison always
> evaluates to false [-Werror=tautological-compare]
>  9668 |       if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
>       |                            ^~
> 
> Aaron

Sorry about that.

Does the following patch help?  (testing in progress here)

gcc/c-family/ChangeLog:
	* c-warn.c (get_outermost_macro_expansion): New function.
	(spelled_the_same_p): Use it to unwind the macro expansions, and
	compare the outermost macro in each nested expansion, rather than
	the innermost.

gcc/testsuite/ChangeLog:
	* c-c++-common/Wtautological-compare-8.c: New test.
---
 gcc/c-family/c-warn.c                              | 26 +++++++++++++----
 .../c-c++-common/Wtautological-compare-8.c         | 33 ++++++++++++++++++++++
 2 files changed, 54 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/Wtautological-compare-8.c

diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index b0f6da0..6013202 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -399,6 +399,25 @@ warn_tautological_bitwise_comparison (const op_location_t &loc, tree_code code,
 		"bitwise comparison always evaluates to true");
 }
 
+/* Given LOC from a macro expansion, return the map for the outermost
+   macro in the nest of expansions.  */
+
+static const line_map_macro *
+get_outermost_macro_expansion (location_t loc)
+{
+  gcc_assert (from_macro_expansion_at (loc));
+
+  const line_map *map = linemap_lookup (line_table, loc);
+  const line_map_macro *macro_map;
+  do
+    {
+      macro_map = linemap_check_macro (map);
+      loc = linemap_unwind_toward_expansion (line_table, loc, &map);
+    } while (linemap_macro_expansion_map_p (map));
+
+  return macro_map;
+}
+
 /* Given LOC_A and LOC_B from macro expansions, return true if
    they are "spelled the same" i.e. if they are both directly from
    expansion of the same non-function-like macro.  */
@@ -409,11 +428,8 @@ spelled_the_same_p (location_t loc_a, location_t loc_b)
   gcc_assert (from_macro_expansion_at (loc_a));
   gcc_assert (from_macro_expansion_at (loc_b));
 
-  const line_map_macro *map_a
-    = linemap_check_macro (linemap_lookup (line_table, loc_a));
-
-  const line_map_macro *map_b
-    = linemap_check_macro (linemap_lookup (line_table, loc_b));
+  const line_map_macro *map_a = get_outermost_macro_expansion (loc_a);
+  const line_map_macro *map_b = get_outermost_macro_expansion (loc_b);
 
   if (map_a->macro == map_b->macro)
     if (!cpp_fun_like_macro_p (map_a->macro))
diff --git a/gcc/testsuite/c-c++-common/Wtautological-compare-8.c b/gcc/testsuite/c-c++-common/Wtautological-compare-8.c
new file mode 100644
index 0000000..1adedad
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wtautological-compare-8.c
@@ -0,0 +1,33 @@
+/* { dg-options "-Wtautological-compare" } */
+
+int foo;
+#define INCOMING_FRAME_SP_OFFSET foo
+#define DEFAULT_INCOMING_FRAME_SP_OFFSET INCOMING_FRAME_SP_OFFSET
+
+int test (void)
+{
+  if (DEFAULT_INCOMING_FRAME_SP_OFFSET != INCOMING_FRAME_SP_OFFSET) /* { dg-warning "self-comparison" "" { target c } } */
+    return 1;
+  else
+    return 0;
+}
+
+#define BYTES_BIG_ENDIAN foo
+#define WORDS_BIG_ENDIAN foo
+
+int test_2 (void)
+{
+  if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN) /* { dg-warning "self-comparison" "" { target c } } */
+    return 1;
+  else
+    return 0;
+}
+
+#define COND DEFAULT_INCOMING_FRAME_SP_OFFSET != INCOMING_FRAME_SP_OFFSET
+int test_3 (void)
+{
+  if (COND)
+    return 1;
+  else
+    return 0;
+}
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486)
  2018-12-19 19:01 ` [PATCH 1/2] " Thomas Schwinge
@ 2018-12-20  2:29   ` David Malcolm
  2020-03-26  5:02   ` [PATCH, OpenACC] Bug fix for processing OpenACC data clauses in C++ Sandra Loosemore
  1 sibling, 0 replies; 34+ messages in thread
From: David Malcolm @ 2018-12-20  2:29 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: gcc-patches, jason

On Wed, 2018-12-19 at 20:00 +0100, Thomas Schwinge wrote:
> Hi David!
> 
> I will admit that I don't have researched ;-/ what this is actually
> all
> about, and how it's implemented, but...
> 
> On Mon,  5 Nov 2018 15:31:08 -0500, David Malcolm <dmalcolm@redhat.co
> m> 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

I suppressed the addition of wrapper nodes within OpenMP as a way to
reduce the scope of the patch.

> ... I did wonder why things applicable to OpenMP wouldn't likewise
> apply
> to OpenACC, too?  That is:

It might or might not be.  Maybe there's a gap in my test coverage? 
How should I be running the OpenACC tests?

> > 	(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.
> > @@ -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_dependen
> > cy_p=*/true,
> >  						  /*template_p=*/N
> > ULL,
> 
> Shouldn't "cp_parser_oacc_all_clauses" (and "some" other functions?)
> be
> adjusted in the same way?  How would I test that?  (I don't see any
> OpenMP test cases added -- I have not yet tried whether any problems
> would become apparent when temporarily removing the OpenMP changes
> cited
> above.)

Lots of pre-existing OpenMP test cases started failing when I added the
wrapper nodes to the C++ parser (e.g. for id-expressions and
constants); suppressing them in the given places was an easy way to get
them to pass again.

Dave

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] -Wtautological-compare: fix comparison of macro expansions
  2018-12-20  2:13             ` [PATCH] -Wtautological-compare: fix comparison of macro expansions David Malcolm
@ 2018-12-20 14:29               ` David Malcolm
  2018-12-20 23:35                 ` Aaron Sawdey
  0 siblings, 1 reply; 34+ messages in thread
From: David Malcolm @ 2018-12-20 14:29 UTC (permalink / raw)
  To: Aaron Sawdey, gcc-patches

On Wed, 2018-12-19 at 22:01 -0500, David Malcolm wrote:
> On Wed, 2018-12-19 at 17:27 -0600, Aaron Sawdey wrote:
> > Assuming you applied this as svn 267273, it causes bootstrap
> > failure
> > on powerpc64le-unknown-linux-gnu. Stage 2 fails with multiple
> > instances
> > of this error:
> > 
> > ../../trunk-base/gcc/c-family/c-pragma.c: In function ‘void
> > handle_pragma_scalar_storage_order(cpp_reader*)’:
> > ../../trunk-base/gcc/c-family/c-pragma.c:417:24: error: self-
> > comparison always evaluates to false [-Werror=tautological-compare]
> >   417 |   if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
> >       |                        ^~
> > ../../trunk-base/gcc/c-family/c-attribs.c: In function ‘tree_node*
> > handle_scalar_storage_order_attribute(tree_node**, tree, tree, int,
> > bool*)’:
> > ../../trunk-base/gcc/c-family/c-attribs.c:1401:24: error: self-
> > comparison always evaluates to false [-Werror=tautological-compare]
> >  1401 |   if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
> >       |                        ^~
> > ../../trunk-base/gcc/builtins.c: In function ‘rtx_def*
> > c_readstr(const char*, scalar_int_mode)’:
> > ../../trunk-base/gcc/builtins.c:830:28: error: self-comparison
> > always
> > evaluates to false [-Werror=tautological-compare]
> >   830 |       if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
> >       |                            ^~
> > ../../trunk-base/gcc/combine.c: In function ‘int
> > rtx_equal_for_field_assignment_p(rtx, rtx, bool)’:
> > ../../trunk-base/gcc/combine.c:9668:28: error: self-comparison
> > always
> > evaluates to false [-Werror=tautological-compare]
> >  9668 |       if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
> >       |                            ^~
> > 
> > Aaron
> 
> Sorry about that.
> 
> Does the following patch help?  (testing in progress here)
[...snip...]

According to comments within PR c++/87504, the patch fixes the
bootstrap on aarch64, and fixes a similar issue on Solaris/SPARC.

It also passed bootstrap&regrtesting on x86_64-pc-linux-gnu.

Given that, I've committed it to trunk as r267299.

Aaron, does this fix the issue you saw?

Thanks, and sorry again about the breakage.
Dave

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH] -Wtautological-compare: fix comparison of macro expansions
  2018-12-20 14:29               ` David Malcolm
@ 2018-12-20 23:35                 ` Aaron Sawdey
  0 siblings, 0 replies; 34+ messages in thread
From: Aaron Sawdey @ 2018-12-20 23:35 UTC (permalink / raw)
  To: David Malcolm, gcc-patches

On 12/20/18 8:25 AM, David Malcolm wrote:
> According to comments within PR c++/87504, the patch fixes the
> bootstrap on aarch64, and fixes a similar issue on Solaris/SPARC.
> 
> It also passed bootstrap&regrtesting on x86_64-pc-linux-gnu.
> 
> Given that, I've committed it to trunk as r267299.
> 
> Aaron, does this fix the issue you saw?
> 
> Thanks, and sorry again about the breakage.
> Dave
> 

Dave,
  Thanks for the quick response, the build issue is fixed with r267299.

  Aaron

-- 
Aaron Sawdey, Ph.D.  acsawdey@linux.vnet.ibm.com
050-2/C113  (507) 253-7520 home: 507/263-0782
IBM Linux Technology Center - PPC Toolchain

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH, OpenACC] Bug fix for processing OpenACC data clauses in C++
@ 2020-03-26  5:02   ` Sandra Loosemore
       [not found]     ` <4a68ec90-456a-cf49-036e-471ba275706c@codesourcery.com>
  0 siblings, 1 reply; 34+ messages in thread
From: Sandra Loosemore @ 2020-03-26  5:02 UTC (permalink / raw)
  To: gcc-patches; +Cc: Thomas Schwinge

[-- Attachment #1: Type: text/plain, Size: 1182 bytes --]

The attached patch fixes a bug I found in the C++ front end's handling 
of OpenACC data clauses.  The problem here is that the C++ front end 
wraps the array bounds expressions in NON_LVALUE_EXPR tree nodes, and 
the code here (which appears to have been copied from similar code in 
the C front end) was failing to strip those before checking to see if 
they were INTEGER_CST nodes, etc.

Sadly, I have no test case for this because it was only triggering an 
error in conjunction with some other OpenACC patches that are not yet on 
trunk, and the tree dumps don't show anything useful.  I confirmed that 
the problem exists on trunk without those other patches by examining 
things in the debugger.  This is the example I was using for my 
hand-testing:

void f (float a[16][16], float b[16][16], float c[16][16])
{
   int i, j, k;

#pragma acc kernels copyin(a[0:16][0:16], b[0:16][0:16]) 
copyout(c[0:16][0:16])
   {
     for (i = 0; i < 16; i++) {
       for (j = 0; j < 16; j++) {
         float t = 0;
         for (k = 0; k < 16; k++)
           t += a[i][k] * b[k][j];
         c[i][j] = t;
       }
     }
   }

}

Is this patch OK to commit now, or in Stage 1?

-Sandra

[-- Attachment #2: strip-nops.patch --]
[-- Type: text/x-patch, Size: 1943 bytes --]

commit 3d2cda1e758a54111af04e80ea3dbaa27b3387e7
Author: Sandra Loosemore <sandra@codesourcery.com>
Date:   Wed Mar 25 21:29:17 2020 -0700

    Bug fix for processing OpenACC data clauses in C++.
    
    The C++ front end wraps the values in OpenACC data clause array range
    specifications in NON_LVALUE_EXPR tree nodes.  The existing code was
    failing to strip these before checking for constant values.
    
    2020-03-25  Sandra Loosemore <sandra@codesourcery.com>
    
    	gcc/cp/
    	* semantics.c (handle_omp_array_sections_1): Call STRIP_NOPS
    	on length and low_bound to unwrap NON_LVALUE_EXPRs.
    	(handle_omp_array_sections): Likewise.

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 34ccb9f..8945939 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,9 @@
+2020-03-25  Sandra Loosemore <sandra@codesourcery.com>
+
+	* semantics.c (handle_omp_array_sections_1): Call STRIP_NOPS
+	on length and low_bound to unwrap NON_LVALUE_EXPRs.
+	(handle_omp_array_sections): Likewise.
+
 2020-03-25  Patrick Palka  <ppalka@redhat.com>
 
 	PR c++/94265
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 2721a55..2efc077 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -4861,6 +4861,10 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
     length = mark_rvalue_use (length);
   /* We need to reduce to real constant-values for checks below.  */
   if (length)
+    STRIP_NOPS (length);
+  if (low_bound)
+    STRIP_NOPS (low_bound);
+  if (length)
     length = fold_simple (length);
   if (low_bound)
     low_bound = fold_simple (low_bound);
@@ -5160,6 +5164,11 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort)
 	  tree low_bound = TREE_PURPOSE (t);
 	  tree length = TREE_VALUE (t);
 
+	  if (length)
+	    STRIP_NOPS (length);
+	  if (low_bound)
+	    STRIP_NOPS (low_bound);
+
 	  i--;
 	  if (low_bound
 	      && TREE_CODE (low_bound) == INTEGER_CST

^ permalink raw reply	[flat|nested] 34+ messages in thread

* C++ 'NON_LVALUE_EXPR' in OMP array section handling (was: [PATCH, OpenACC] Bug fix for processing OpenACC data clauses in C++)
       [not found]     ` <4a68ec90-456a-cf49-036e-471ba275706c@codesourcery.com>
@ 2020-03-26 14:27       ` Thomas Schwinge
  2020-03-26 15:09         ` C++ 'NON_LVALUE_EXPR' in OMP array section handling Sandra Loosemore
  0 siblings, 1 reply; 34+ messages in thread
From: Thomas Schwinge @ 2020-03-26 14:27 UTC (permalink / raw)
  To: Sandra Loosemore, Jakub Jelinek; +Cc: gcc-patches

Hi!

Note that as this code is shared between OpenACC/OpenMP, this might
affect OpenMP, too, as far as I can tell.  (Subject updated.)  Jakub, can
you please have a look, too?

On 2020-03-25T23:02:38-0600, Sandra Loosemore <sandra@codesourcery.com> wrote:
> The attached patch fixes a bug I found in the C++ front end's handling
> of OpenACC data clauses.  The problem here is that the C++ front end
> wraps the array bounds expressions in NON_LVALUE_EXPR tree nodes, and
> the code here (which appears to have been copied from similar code in
> the C front end) was failing to strip those before checking to see if
> they were INTEGER_CST nodes, etc.

So, I had a quick look.  I'm confirming the 'NON_LVALUE_EXPR' (C++ only,
not seen for C) difference, and that 'STRIP_NOPS' gets rid of these.
However, I also in some code paths see, for example, 'integer_nonzerop'
calls, which internally do 'STRIP_ANY_LOCATION_WRAPPER'.

I don't know if 'STRIP_NOPS' is the correct "hammer" to use here, I don't
know what the usual convention is: explicitly remove (via 'STRIP_NOPS' as
you suggested, or something else), or have the enquiry functions do it
('STRIP_ANY_LOCATION_WRAPPER' as 'integer_nonzerop' is doing, for
example).

Empirical data doesn't mean too much here, of course, I'm not seeing a
lot of explicit 'STRIP_*' calls in 'gcc/cp/semantics.c'.  ;-)

> Sadly, I have no test case for this because it was only triggering an
> error in conjunction with some other OpenACC patches that are not yet on
> trunk

So maybe the problem is actually that these "other OpenACC patches" are
not sufficiently sanitizing the input data they're doing checks on?

> and the tree dumps don't show anything useful.

Well, the 'original' tree dumps do show (C++) vs. don't show (C) the
'NON_LVALUE_EXPR's.

> I confirmed that
> the problem exists on trunk without those other patches by examining
> things in the debugger.  This is the example I was using for my
> hand-testing:
>
> void f (float a[16][16], float b[16][16], float c[16][16])
> {
>    int i, j, k;
>
> #pragma acc kernels copyin(a[0:16][0:16], b[0:16][0:16]) copyout(c[0:16][0:16])
>    {
>      for (i = 0; i < 16; i++) {
>        for (j = 0; j < 16; j++) {
>          float t = 0;
>          for (k = 0; k < 16; k++)
>            t += a[i][k] * b[k][j];
>          c[i][j] = t;
>        }
>      }
>    }
>
> }
>
> Is this patch OK to commit now, or in Stage 1?

First we need to figure out if this is an actual/current bug (which then
needs GCC PR filed, and later also backports to release branches), or
not.


Grüße
 Thomas


> commit 3d2cda1e758a54111af04e80ea3dbaa27b3387e7
> Author: Sandra Loosemore <sandra@codesourcery.com>
> Date:   Wed Mar 25 21:29:17 2020 -0700
>
>     Bug fix for processing OpenACC data clauses in C++.
>
>     The C++ front end wraps the values in OpenACC data clause array range
>     specifications in NON_LVALUE_EXPR tree nodes.  The existing code was
>     failing to strip these before checking for constant values.
>
>     2020-03-25  Sandra Loosemore <sandra@codesourcery.com>
>
>       gcc/cp/
>       * semantics.c (handle_omp_array_sections_1): Call STRIP_NOPS
>       on length and low_bound to unwrap NON_LVALUE_EXPRs.
>       (handle_omp_array_sections): Likewise.
>
> diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
> index 34ccb9f..8945939 100644
> --- a/gcc/cp/ChangeLog
> +++ b/gcc/cp/ChangeLog
> @@ -1,3 +1,9 @@
> +2020-03-25  Sandra Loosemore <sandra@codesourcery.com>
> +
> +     * semantics.c (handle_omp_array_sections_1): Call STRIP_NOPS
> +     on length and low_bound to unwrap NON_LVALUE_EXPRs.
> +     (handle_omp_array_sections): Likewise.
> +
>  2020-03-25  Patrick Palka  <ppalka@redhat.com>
>
>       PR c++/94265
> diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
> index 2721a55..2efc077 100644
> --- a/gcc/cp/semantics.c
> +++ b/gcc/cp/semantics.c
> @@ -4861,6 +4861,10 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
>      length = mark_rvalue_use (length);
>    /* We need to reduce to real constant-values for checks below.  */
>    if (length)
> +    STRIP_NOPS (length);
> +  if (low_bound)
> +    STRIP_NOPS (low_bound);
> +  if (length)
>      length = fold_simple (length);
>    if (low_bound)
>      low_bound = fold_simple (low_bound);
> @@ -5160,6 +5164,11 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort)
>         tree low_bound = TREE_PURPOSE (t);
>         tree length = TREE_VALUE (t);
>
> +       if (length)
> +         STRIP_NOPS (length);
> +       if (low_bound)
> +         STRIP_NOPS (low_bound);
> +
>         i--;
>         if (low_bound
>             && TREE_CODE (low_bound) == INTEGER_CST
-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ 'NON_LVALUE_EXPR' in OMP array section handling
  2020-03-26 14:27       ` C++ 'NON_LVALUE_EXPR' in OMP array section handling (was: [PATCH, OpenACC] Bug fix for processing OpenACC data clauses in C++) Thomas Schwinge
@ 2020-03-26 15:09         ` Sandra Loosemore
  2020-03-26 20:53           ` Thomas Schwinge
  0 siblings, 1 reply; 34+ messages in thread
From: Sandra Loosemore @ 2020-03-26 15:09 UTC (permalink / raw)
  To: Thomas Schwinge, Jakub Jelinek; +Cc: gcc-patches

On 3/26/20 8:27 AM, Thomas Schwinge wrote:
> Hi!
> 
> Note that as this code is shared between OpenACC/OpenMP, this might
> affect OpenMP, too, as far as I can tell.  (Subject updated.)  Jakub, can
> you please have a look, too?
> 
> On 2020-03-25T23:02:38-0600, Sandra Loosemore <sandra@codesourcery.com> wrote:
>> The attached patch fixes a bug I found in the C++ front end's handling
>> of OpenACC data clauses.  The problem here is that the C++ front end
>> wraps the array bounds expressions in NON_LVALUE_EXPR tree nodes, and
>> the code here (which appears to have been copied from similar code in
>> the C front end) was failing to strip those before checking to see if
>> they were INTEGER_CST nodes, etc.
> 
> So, I had a quick look.  I'm confirming the 'NON_LVALUE_EXPR' (C++ only,
> not seen for C) difference, and that 'STRIP_NOPS' gets rid of these.
> However, I also in some code paths see, for example, 'integer_nonzerop'
> calls, which internally do 'STRIP_ANY_LOCATION_WRAPPER'.
> 
> I don't know if 'STRIP_NOPS' is the correct "hammer" to use here, I don't
> know what the usual convention is: explicitly remove (via 'STRIP_NOPS' as
> you suggested, or something else), or have the enquiry functions do it
> ('STRIP_ANY_LOCATION_WRAPPER' as 'integer_nonzerop' is doing, for
> example).
> 
> Empirical data doesn't mean too much here, of course, I'm not seeing a
> lot of explicit 'STRIP_*' calls in 'gcc/cp/semantics.c'.  ;-)

I saw that STRIP_NOPS seem to be the preferred way to do things in e.g. 
fold-const.c.  I don't know if there's a reason to use some less general 
form of STRIP_* here?

>> Sadly, I have no test case for this because it was only triggering an
>> error in conjunction with some other OpenACC patches that are not yet on
>> trunk
> 
> So maybe the problem is actually that these "other OpenACC patches" are
> not sufficiently sanitizing the input data they're doing checks on?

No.  In the current code on trunk, both places that are being patched 
continue with checks like

TREE_CODE (low_bound) == INTEGER_CST

etc.  So when they're wrapped in NON_LVALUE_EXPRs, it's basically 
failing to detect constants in array dimension specifiers and falling 
through to other code.  (And it's patches to the "other code" that were 
diagnosing the bogus error I saw.)

-Sandra

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: C++ 'NON_LVALUE_EXPR' in OMP array section handling
  2020-03-26 15:09         ` C++ 'NON_LVALUE_EXPR' in OMP array section handling Sandra Loosemore
@ 2020-03-26 20:53           ` Thomas Schwinge
  2020-05-25 10:56             ` [WIP] Fold 'NON_LVALUE_EXPR' some more (was: C++ 'NON_LVALUE_EXPR' in OMP array section handling) Thomas Schwinge
  0 siblings, 1 reply; 34+ messages in thread
From: Thomas Schwinge @ 2020-03-26 20:53 UTC (permalink / raw)
  To: Sandra Loosemore, Jakub Jelinek, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 4245 bytes --]

Hi!

On 2020-03-26T09:09:01-0600, Sandra Loosemore <sandra@codesourcery.com> wrote:
> On 3/26/20 8:27 AM, Thomas Schwinge wrote:
>> Note that as this code is shared between OpenACC/OpenMP, this might
>> affect OpenMP, too, as far as I can tell.  (Subject updated.)  Jakub, can
>> you please have a look, too?
>>
>> On 2020-03-25T23:02:38-0600, Sandra Loosemore <sandra@codesourcery.com> wrote:
>>> The attached patch fixes a bug I found in the C++ front end's handling
>>> of OpenACC data clauses.  The problem here is that the C++ front end
>>> wraps the array bounds expressions in NON_LVALUE_EXPR tree nodes, and
>>> the code here (which appears to have been copied from similar code in
>>> the C front end) was failing to strip those before checking to see if
>>> they were INTEGER_CST nodes, etc.
>>
>> So, I had a quick look.  I'm confirming the 'NON_LVALUE_EXPR' (C++ only,
>> not seen for C) difference, and that 'STRIP_NOPS' gets rid of these.
>> However, I also in some code paths see, for example, 'integer_nonzerop'
>> calls, which internally do 'STRIP_ANY_LOCATION_WRAPPER'.
>>
>> I don't know if 'STRIP_NOPS' is the correct "hammer" to use here, I don't
>> know what the usual convention is: explicitly remove (via 'STRIP_NOPS' as
>> you suggested, or something else), or have the enquiry functions do it
>> ('STRIP_ANY_LOCATION_WRAPPER' as 'integer_nonzerop' is doing, for
>> example).
>>
>> Empirical data doesn't mean too much here, of course, I'm not seeing a
>> lot of explicit 'STRIP_*' calls in 'gcc/cp/semantics.c'.  ;-)
>
> I saw that STRIP_NOPS seem to be the preferred way to do things in e.g.
> fold-const.c.  I don't know if there's a reason to use some less general
> form of STRIP_* here?
>
>>> Sadly, I have no test case for this because it was only triggering an
>>> error in conjunction with some other OpenACC patches that are not yet on
>>> trunk
>>
>> So maybe the problem is actually that these "other OpenACC patches" are
>> not sufficiently sanitizing the input data they're doing checks on?
>
> No.  In the current code on trunk, both places that are being patched
> continue with checks like
>
> TREE_CODE (low_bound) == INTEGER_CST
>
> etc.  So when they're wrapped in NON_LVALUE_EXPRs, it's basically
> failing to detect constants in array dimension specifiers and falling
> through to other code.

Eh, indeed...  ;-\ (So we should be able to deduce some misbehavior from
that, to construct a test case.  I'll have a look.)

>>> and the tree dumps don't show anything useful.
>>
>> Well, the 'original' tree dumps do show (C++) vs. don't show (C) the
>> 'NON_LVALUE_EXPR's.

While true, that of course doesn't tell us anything what the OMP array
section handling is doing with these.

I guess I was half-asleep when I wrote my email...  ;-/

So.  I'm not objecting to handling 'NON_LVALUE_EXPR's locally here via
any kind of 'STRIP_*', but it somehow doesn't seem the general solution.
Another option seems to be to teach 'fold_simple' to handle
'NON_LVALUE_EXPR's, so that the existing code:

    /* We need to reduce to real constant-values for checks below.  */
    if (length)
      length = fold_simple (length);
    if (low_bound)
      low_bound = fold_simple (low_bound);
    if (low_bound
        && TREE_CODE (low_bound) == INTEGER_CST
        && [...])
      low_bound = fold_convert (sizetype, low_bound);
    if (length
        && TREE_CODE (length) == INTEGER_CST
        && [...])
      length = fold_convert (sizetype, length);

... would then just work.  But: I don't know if 'fold_simple' (and
others?) should handle 'NON_LVALUE_EXPR's, or if there's a reason why it
doesn't.  (Have not yet tried to figure that out.)  What I can tell is
that the attached patch does solve the issue in the C++ OMP array section
handling, and survives a powerpc64le-unknown-linux-gnu
'--enable-checking=yes' (will now re-run with 'fold' checking) bootstrap,
with no testsuite regressions.

Hmm.


Grüße
 Thomas


-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Fold-NON_LVALUE_EXPR-some-more.patch --]
[-- Type: text/x-diff, Size: 1027 bytes --]

From 611fbe24b7e459829c0a304a58963d4987c8de0a Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Thu, 26 Mar 2020 21:22:54 +0100
Subject: [PATCH] Fold 'NON_LVALUE_EXPR' some more

---
 gcc/cp/constexpr.c | 1 +
 gcc/fold-const.c   | 1 +
 2 files changed, 2 insertions(+)

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 192face9a3a..f31d61c1460 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -6650,6 +6650,7 @@ fold_simple_1 (tree t)
     case BIT_NOT_EXPR:
     case TRUTH_NOT_EXPR:
     case NOP_EXPR:
+    case NON_LVALUE_EXPR:
     case VIEW_CONVERT_EXPR:
     case CONVERT_EXPR:
     case FLOAT_EXPR:
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 71a1d3eb735..b6bc5080ff3 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -1739,6 +1739,7 @@ const_unop (enum tree_code code, tree type, tree arg0)
   switch (code)
     {
     CASE_CONVERT:
+    case NON_LVALUE_EXPR:
     case FLOAT_EXPR:
     case FIX_TRUNC_EXPR:
     case FIXED_CONVERT_EXPR:
-- 
2.17.1


^ permalink raw reply	[flat|nested] 34+ messages in thread

* [WIP] Fold 'NON_LVALUE_EXPR' some more (was: C++ 'NON_LVALUE_EXPR' in OMP array section handling)
  2020-03-26 20:53           ` Thomas Schwinge
@ 2020-05-25 10:56             ` Thomas Schwinge
  2020-11-26  9:36               ` Don't create location wrapper nodes within OpenACC clauses (was: [WIP] Fold 'NON_LVALUE_EXPR' some more (was: C++ 'NON_LVALUE_EXPR' in OMP array section handling)) Thomas Schwinge
  0 siblings, 1 reply; 34+ messages in thread
From: Thomas Schwinge @ 2020-05-25 10:56 UTC (permalink / raw)
  To: Jakub Jelinek, gcc-patches; +Cc: Sandra Loosemore

[-- Attachment #1: Type: text/plain, Size: 4099 bytes --]

Hi!

Anyone have any input here, especially whether something like the WIP
patch attached to generally "Fold 'NON_LVALUE_EXPR' some more" is
preferable over local 'STRIP_NOPS'?

On 2020-03-26T20:53:19+0100, I wrote:
> On 2020-03-26T09:09:01-0600, Sandra Loosemore <sandra@codesourcery.com> wrote:
>> On 3/26/20 8:27 AM, Thomas Schwinge wrote:
>>> Note that as this code is shared between OpenACC/OpenMP, this might
>>> affect OpenMP, too, as far as I can tell.  (Subject updated.)  Jakub, can
>>> you please have a look, too?
>>>
>>> On 2020-03-25T23:02:38-0600, Sandra Loosemore <sandra@codesourcery.com> wrote:
>>>> The attached patch fixes a bug I found in the C++ front end's handling
>>>> of OpenACC data clauses.  The problem here is that the C++ front end
>>>> wraps the array bounds expressions in NON_LVALUE_EXPR tree nodes, and
>>>> the code here (which appears to have been copied from similar code in
>>>> the C front end) was failing to strip those before checking to see if
>>>> they were INTEGER_CST nodes, etc.
>>>
>>> So, I had a quick look.  I'm confirming the 'NON_LVALUE_EXPR' (C++ only,
>>> not seen for C) difference, and that 'STRIP_NOPS' gets rid of these.
>>> However, I also in some code paths see, for example, 'integer_nonzerop'
>>> calls, which internally do 'STRIP_ANY_LOCATION_WRAPPER'.
>>>
>>> I don't know if 'STRIP_NOPS' is the correct "hammer" to use here, I don't
>>> know what the usual convention is: explicitly remove (via 'STRIP_NOPS' as
>>> you suggested, or something else), or have the enquiry functions do it
>>> ('STRIP_ANY_LOCATION_WRAPPER' as 'integer_nonzerop' is doing, for
>>> example).
>>>
>>> Empirical data doesn't mean too much here, of course, I'm not seeing a
>>> lot of explicit 'STRIP_*' calls in 'gcc/cp/semantics.c'.  ;-)
>>
>> I saw that STRIP_NOPS seem to be the preferred way to do things in e.g.
>> fold-const.c.  I don't know if there's a reason to use some less general
>> form of STRIP_* here?

>>>> Sadly, I have no test case for this because it was only triggering an
>>>> error in conjunction with some other OpenACC patches that are not yet on
>>>> trunk

>> In the current code [we have]
>> checks like
>>
>> TREE_CODE (low_bound) == INTEGER_CST
>>
>> etc.  So when they're wrapped in NON_LVALUE_EXPRs, it's basically
>> failing to detect constants in array dimension specifiers and falling
>> through to other code.
>
> Eh, indeed...  ;-\ (So we should be able to deduce some misbehavior from
> that, to construct a test case.  I'll have a look.)

(Have not yet been able to look into constructing any test cases.)


> So.  I'm not objecting to handling 'NON_LVALUE_EXPR's locally here via
> any kind of 'STRIP_*', but it somehow doesn't seem the general solution.
> Another option seems to be to teach 'fold_simple' to handle
> 'NON_LVALUE_EXPR's, so that the existing code:
>
>     /* We need to reduce to real constant-values for checks below.  */
>     if (length)
>       length = fold_simple (length);
>     if (low_bound)
>       low_bound = fold_simple (low_bound);
>     if (low_bound
>         && TREE_CODE (low_bound) == INTEGER_CST
>         && [...])
>       low_bound = fold_convert (sizetype, low_bound);
>     if (length
>         && TREE_CODE (length) == INTEGER_CST
>         && [...])
>       length = fold_convert (sizetype, length);
>
> ... would then just work.  But: I don't know if 'fold_simple' (and
> others?) should handle 'NON_LVALUE_EXPR's, or if there's a reason why it
> doesn't.  (Have not yet tried to figure that out.)  What I can tell is
> that the attached patch does solve the issue in the C++ OMP array section
> handling, and survives a powerpc64le-unknown-linux-gnu
> '--enable-checking=yes' (will now re-run with 'fold' checking) bootstrap,
> with no testsuite regressions.
>
> Hmm.


Grüße
 Thomas


-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Fold-NON_LVALUE_EXPR-some-more.patch --]
[-- Type: text/x-diff, Size: 1027 bytes --]

From 611fbe24b7e459829c0a304a58963d4987c8de0a Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Thu, 26 Mar 2020 21:22:54 +0100
Subject: [PATCH] Fold 'NON_LVALUE_EXPR' some more

---
 gcc/cp/constexpr.c | 1 +
 gcc/fold-const.c   | 1 +
 2 files changed, 2 insertions(+)

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 192face9a3a..f31d61c1460 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -6650,6 +6650,7 @@ fold_simple_1 (tree t)
     case BIT_NOT_EXPR:
     case TRUTH_NOT_EXPR:
     case NOP_EXPR:
+    case NON_LVALUE_EXPR:
     case VIEW_CONVERT_EXPR:
     case CONVERT_EXPR:
     case FLOAT_EXPR:
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 71a1d3eb735..b6bc5080ff3 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -1739,6 +1739,7 @@ const_unop (enum tree_code code, tree type, tree arg0)
   switch (code)
     {
     CASE_CONVERT:
+    case NON_LVALUE_EXPR:
     case FLOAT_EXPR:
     case FIX_TRUNC_EXPR:
     case FIXED_CONVERT_EXPR:
-- 
2.17.1


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Don't create location wrapper nodes within OpenACC clauses (was: [WIP] Fold 'NON_LVALUE_EXPR' some more (was: C++ 'NON_LVALUE_EXPR' in OMP array section handling))
  2020-05-25 10:56             ` [WIP] Fold 'NON_LVALUE_EXPR' some more (was: C++ 'NON_LVALUE_EXPR' in OMP array section handling) Thomas Schwinge
@ 2020-11-26  9:36               ` Thomas Schwinge
  2020-11-26 10:02                 ` Jakub Jelinek
  0 siblings, 1 reply; 34+ messages in thread
From: Thomas Schwinge @ 2020-11-26  9:36 UTC (permalink / raw)
  To: gcc-patches, Sandra Loosemore; +Cc: Jakub Jelinek, David Malcolm

[-- Attachment #1: Type: text/plain, Size: 7618 bytes --]

Hi!

On 2020-05-25T12:56:15+0200, I wrote:
> Anyone have any input here, especially whether something like the WIP
> patch attached to generally "Fold 'NON_LVALUE_EXPR' some more" is
> preferable over local 'STRIP_NOPS'?

Neither of these, actually...

> On 2020-03-26T20:53:19+0100, I wrote:
>> On 2020-03-26T09:09:01-0600, Sandra Loosemore <sandra@codesourcery.com> wrote:
>>> On 3/26/20 8:27 AM, Thomas Schwinge wrote:
>>>> Note that as this code is shared between OpenACC/OpenMP, this might
>>>> affect OpenMP, too, as far as I can tell.  (Subject updated.)  Jakub, can
>>>> you please have a look, too?

This is actually what made me think that something's "fishy" here: this
code path supposedly works fine for OpenMP, and now suddenly needs
adjustments for the very same OpenACC usage.

>>>> On 2020-03-25T23:02:38-0600, Sandra Loosemore <sandra@codesourcery.com> wrote:
>>>>> The attached patch fixes a bug I found in the C++ front end's handling
>>>>> of OpenACC data clauses.  The problem here is that the C++ front end
>>>>> wraps the array bounds expressions in NON_LVALUE_EXPR tree nodes, and
>>>>> the code here (which appears to have been copied from similar code in
>>>>> the C front end) was failing to strip those before checking to see if
>>>>> they were INTEGER_CST nodes, etc.
>>>>
>>>> So, I had a quick look.  I'm confirming the 'NON_LVALUE_EXPR' (C++ only,
>>>> not seen for C) difference, and that 'STRIP_NOPS' gets rid of these.
>>>> However, I also in some code paths see, for example, 'integer_nonzerop'
>>>> calls, which internally do 'STRIP_ANY_LOCATION_WRAPPER'.
>>>>
>>>> I don't know if 'STRIP_NOPS' is the correct "hammer" to use here, I don't
>>>> know what the usual convention is: explicitly remove (via 'STRIP_NOPS' as
>>>> you suggested, or something else), or have the enquiry functions do it
>>>> ('STRIP_ANY_LOCATION_WRAPPER' as 'integer_nonzerop' is doing, for
>>>> example).
>>>>
>>>> Empirical data doesn't mean too much here, of course, I'm not seeing a
>>>> lot of explicit 'STRIP_*' calls in 'gcc/cp/semantics.c'.  ;-)
>>>
>>> I saw that STRIP_NOPS seem to be the preferred way to do things in e.g.
>>> fold-const.c.  I don't know if there's a reason to use some less general
>>> form of STRIP_* here?
>
>>>>> Sadly, I have no test case for this because it was only triggering an
>>>>> error in conjunction with some other OpenACC patches that are not yet on
>>>>> trunk
>
>>> In the current code [we have]
>>> checks like
>>>
>>> TREE_CODE (low_bound) == INTEGER_CST
>>>
>>> etc.  So when they're wrapped in NON_LVALUE_EXPRs, it's basically
>>> failing to detect constants in array dimension specifiers and falling
>>> through to other code.
>>
>> Eh, indeed...  ;-\ (So we should be able to deduce some misbehavior from
>> that, to construct a test case.  I'll have a look.)
>
> (Have not yet been able to look into constructing any test cases.)

Now I have.

>> So.  I'm not objecting to handling 'NON_LVALUE_EXPR's locally here via
>> any kind of 'STRIP_*', but it somehow doesn't seem the general solution.
>> Another option seems to be to teach 'fold_simple' to handle
>> 'NON_LVALUE_EXPR's, so that the existing code:
>>
>>     /* We need to reduce to real constant-values for checks below.  */
>>     if (length)
>>       length = fold_simple (length);
>>     if (low_bound)
>>       low_bound = fold_simple (low_bound);
>>     if (low_bound
>>         && TREE_CODE (low_bound) == INTEGER_CST
>>         && [...])
>>       low_bound = fold_convert (sizetype, low_bound);
>>     if (length
>>         && TREE_CODE (length) == INTEGER_CST
>>         && [...])
>>       length = fold_convert (sizetype, length);
>>
>> ... would then just work.  But: I don't know if 'fold_simple' (and
>> others?) should handle 'NON_LVALUE_EXPR's, or if there's a reason why it
>> doesn't.  (Have not yet tried to figure that out.)  What I can tell is
>> that the attached patch does solve the issue in the C++ OMP array section
>> handling, and survives a powerpc64le-unknown-linux-gnu
>> '--enable-checking=yes' (will now re-run with 'fold' checking) bootstrap,
>> with no testsuite regressions.
>>
>> Hmm.

So, I understand, 'NON_LVALUE_EXPR's are primarily a C/C++ (only?) front
end construct to wrap nodes that must not be used as a lvalue (per the
programming language standards); rejecting code like 'int x; &(x + 0);',
I suppose.

Then, I'd assume, that after the front ends, they indeed can all be
stripped (assuming that they loose their special semantics after the
front ends, and the middle end, back ends don't (have to) care).  Thus,
it may indeed conceptually make sense to make them front end specific
nodes (and then later assert that such nodes aren't present anymore);
strip them in some "fold" functions as I had experimented/suggested:

> Subject: [PATCH] Fold 'NON_LVALUE_EXPR' some more

> --- a/gcc/cp/constexpr.c
> +++ b/gcc/cp/constexpr.c
> @@ -6650,6 +6650,7 @@ fold_simple_1 (tree t)
>      case BIT_NOT_EXPR:
>      case TRUTH_NOT_EXPR:
>      case NOP_EXPR:
> +    case NON_LVALUE_EXPR:
>      case VIEW_CONVERT_EXPR:
>      case CONVERT_EXPR:
>      case FLOAT_EXPR:
> --- a/gcc/fold-const.c
> +++ b/gcc/fold-const.c
> @@ -1739,6 +1739,7 @@ const_unop (enum tree_code code, tree type, tree arg0)
>    switch (code)
>      {
>      CASE_CONVERT:
> +    case NON_LVALUE_EXPR:
>      case FLOAT_EXPR:
>      case FIX_TRUNC_EXPR:
>      case FIXED_CONVERT_EXPR:

But: it's not clear to me which of the several "fold" functions work at
the front end level (and thus likely must preserve 'NON_LVALUE_EXPR's --
thus is it worrying that the 'gcc/cp/constexpr.c' change cited above
doesn't introduce any testsuite regressions?) and which work at the
middle end level (where stripping 'NON_LVALUE_EXPR's supposedly would be
fine, handling them like 'CASE_CONVERT': 'NOP_EXPR', 'CONVERT_EXPR').


But now, one step back: the other situation where 'NON_LVALUE_EXPR's
appear is as location wrappers (see 'gcc/tree.c:maybe_wrap_with_location'
etc.).  And this is what's the problem here.  I've just pushed "Don't
create location wrapper nodes within OpenACC clauses" to master branch in
commit c0c7270cc4efd896fe99f8ad5409dbef089a407f, and backported to
releases/gcc-10 branch in commit
e8e0357d129187b24085ce52172c87dbf6c2ecae, to releases/gcc-9 branch in
commit 25b61f935a8eca56c68c8587fc8915797250bb30, to releases/gcc-8 branch
in commit 23ec71d91e3044108a557dace573d3e60ff1c07e (testsuite changes
only), see attached.  Quoting myself from the commit log:

| This fixes a GCC 11, 10, 9 regression introduced by commit
| dfd7fdca2ac17d8b823a16700525824ca312ade0 (Subversion r267272) "C++: more
| location wrapper nodes (PR c++/43064, PR c++/43486)".  But: this isn't
| intending to blame David, because back then, the problem hasn't been visible in
| the testsuite (or else I'm sure would've been addressed right away) because of
| our all dear friend: missing testsuite coverage.  Thus, for GCC 8, I'm likewise
| enhancing the testsuite, without the C++ front end code changes.
|
| I actually had presumed that there may be an issue for OpenACC:
| <http://mid.mail-archive.com/874lb9qr2u.fsf@euler.schwinge.homeip.net>, so here
| we are, two years (and many "wasted" hours...) later...


Grüße
 Thomas


-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Don-t-create-location-wrapper-nodes-within-OpenACC-c.patch --]
[-- Type: text/x-diff, Size: 37884 bytes --]

From c0c7270cc4efd896fe99f8ad5409dbef089a407f Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Wed, 25 Nov 2020 20:36:55 +0100
Subject: [PATCH] Don't create location wrapper nodes within OpenACC clauses

This fixes a GCC 11, 10, 9 regression introduced by commit
dfd7fdca2ac17d8b823a16700525824ca312ade0 (Subversion r267272) "C++: more
location wrapper nodes (PR c++/43064, PR c++/43486)".  But: this isn't
intending to blame David, because back then, the problem hasn't been visible in
the testsuite (or else I'm sure would've been addressed right away) because of
our all dear friend: missing testsuite coverage.  Thus, for GCC 8, I'm likewise
enhancing the testsuite, without the C++ front end code changes.

I actually had presumed that there may be an issue for OpenACC:
<http://mid.mail-archive.com/874lb9qr2u.fsf@euler.schwinge.homeip.net>, so here
we are, two years (and many "wasted" hours...) later...

	gcc/cp/
	* parser.c (cp_parser_omp_var_list_no_open): Assert that array
	section's 'low_bound', 'length' are not location wrapper nodes.
	(cp_parser_oacc_all_clauses, cp_parser_oacc_cache): Instantiate
	'auto_suppress_location_wrappers'.
	gcc/testsuite/
	* c-c++-common/goacc/cache-3-1.c: New.
	* c-c++-common/goacc/cache-3-2.c: Likewise.
	* c-c++-common/goacc/data-clause-1.c: Likewise.
	* c-c++-common/goacc/data-clause-2.c: Likewise.
	* c-c++-common/gomp/map-1.c: Adjust.
	* c-c++-common/gomp/map-2.c: Likewise.
	* g++.dg/goacc/cache-3-1.C: New.
	* g++.dg/goacc/cache-3-2.C: Likewise.
	* g++.dg/goacc/data-clause-1.C: Likewise.
	* g++.dg/goacc/data-clause-2.C: Likewise.
	* g++.dg/gomp/map-1.C: Adjust.
	* g++.dg/gomp/map-2.C: Likewise.

Reported-by: Sandra Loosemore <sandra@codesourcery.com>
---
 gcc/cp/parser.c                               |  19 ++-
 gcc/testsuite/c-c++-common/goacc/cache-3-1.c  | 116 +++++++++++++++++
 gcc/testsuite/c-c++-common/goacc/cache-3-2.c  |  50 +++++++
 .../c-c++-common/goacc/data-clause-1.c        | 115 ++++++++++++++++
 .../c-c++-common/goacc/data-clause-2.c        |  49 +++++++
 gcc/testsuite/c-c++-common/gomp/map-1.c       |   4 +-
 gcc/testsuite/c-c++-common/gomp/map-2.c       |   4 +-
 gcc/testsuite/g++.dg/goacc/cache-3-1.C        | 123 ++++++++++++++++++
 gcc/testsuite/g++.dg/goacc/cache-3-2.C        |  57 ++++++++
 gcc/testsuite/g++.dg/goacc/data-clause-1.C    | 122 +++++++++++++++++
 gcc/testsuite/g++.dg/goacc/data-clause-2.C    |  56 ++++++++
 gcc/testsuite/g++.dg/gomp/map-1.C             |   6 +-
 gcc/testsuite/g++.dg/gomp/map-2.C             |   4 +-
 13 files changed, 718 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/goacc/cache-3-1.c
 create mode 100644 gcc/testsuite/c-c++-common/goacc/cache-3-2.c
 create mode 100644 gcc/testsuite/c-c++-common/goacc/data-clause-1.c
 create mode 100644 gcc/testsuite/c-c++-common/goacc/data-clause-2.c
 create mode 100644 gcc/testsuite/g++.dg/goacc/cache-3-1.C
 create mode 100644 gcc/testsuite/g++.dg/goacc/cache-3-2.C
 create mode 100644 gcc/testsuite/g++.dg/goacc/data-clause-1.C
 create mode 100644 gcc/testsuite/g++.dg/goacc/data-clause-2.C

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index d11900a7dd5..63a2c962d86 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -34837,7 +34837,11 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
 		  parser->colon_corrects_to_scope_p = false;
 		  cp_lexer_consume_token (parser->lexer);
 		  if (!cp_lexer_next_token_is (parser->lexer, CPP_COLON))
-		    low_bound = cp_parser_expression (parser);
+		    {
+		      low_bound = cp_parser_expression (parser);
+		      /* Later handling is not prepared to see through these.  */
+		      gcc_checking_assert (!location_wrapper_p (low_bound));
+		    }
 		  if (!colon)
 		    parser->colon_corrects_to_scope_p
 		      = saved_colon_corrects_to_scope_p;
@@ -34857,7 +34861,11 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
 			cp_parser_commit_to_tentative_parse (parser);
 		      if (!cp_lexer_next_token_is (parser->lexer,
 						   CPP_CLOSE_SQUARE))
-			length = cp_parser_expression (parser);
+			{
+			  length = cp_parser_expression (parser);
+			  /* Later handling is not prepared to see through these.  */
+			  gcc_checking_assert (!location_wrapper_p (length));
+			}
 		    }
 		  /* Look for the closing `]'.  */
 		  if (!cp_parser_require (parser, CPP_CLOSE_SQUARE,
@@ -37521,6 +37529,9 @@ cp_parser_oacc_all_clauses (cp_parser *parser, omp_clause_mask mask,
   tree clauses = NULL;
   bool first = true;
 
+  /* Don't create location wrapper nodes within OpenACC clauses.  */
+  auto_suppress_location_wrappers sentinel;
+
   while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL))
     {
       location_t here;
@@ -41444,6 +41455,10 @@ check_clauses:
 static tree
 cp_parser_oacc_cache (cp_parser *parser, cp_token *pragma_tok)
 {
+  /* Don't create location wrapper nodes within 'OMP_CLAUSE__CACHE_'
+     clauses.  */
+  auto_suppress_location_wrappers sentinel;
+
   tree stmt, clauses;
 
   clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE__CACHE_, NULL_TREE);
diff --git a/gcc/testsuite/c-c++-common/goacc/cache-3-1.c b/gcc/testsuite/c-c++-common/goacc/cache-3-1.c
new file mode 100644
index 00000000000..5318a57d51e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/goacc/cache-3-1.c
@@ -0,0 +1,116 @@
+/* Test 'cache' directive diagnostics.  */
+
+/* See also corresponding C++ variant: '../../g++.dg/goacc/cache-3-1.C'.  */
+
+/* See also corresponding C/C++ data clause variant: 'data-clause-1.c'.  */
+
+/* { dg-additional-options "-fopenmp" } for '#pragma omp threadprivate'.  */
+
+/* The current implementation doesn't restrict where a 'cache' directive may
+   appear, so we don't make any special arrangements.  */
+
+extern int a[][10], a2[][10];
+int b[10], c[10][2], d[10], e[10], f[10];
+int b2[10], c2[10][2], d2[10], e2[10], f2[10];
+int k[10], l[10], m[10], n[10], o;
+int *p;
+int **q;
+int r[4][4][4][4][4];
+extern struct s s1;
+extern struct s s2[1]; /* { dg-error "array type has incomplete element type" "" { target c } } */
+int t[10];
+#pragma omp threadprivate (t)
+#pragma acc routine
+void bar (int *);
+
+void
+foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
+     int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9])
+{
+  #pragma acc cache(bar[2:5]) /* { dg-error "is not a variable" } */
+    ;
+  #pragma acc cache(t[2:5]) /* { dg-error "is threadprivate variable" } */
+    ;
+  #pragma acc cache(k[0.5:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(m[p:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(n[:p]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(o[2:5]) /* { dg-error "does not have pointer or array type" } */
+    ;
+  #pragma acc cache(s1) /* { dg-error "expected '\\\['" } */
+    ;
+  #pragma acc cache(s2) /* { dg-error "expected '\\\['" } */
+    ;
+  #pragma acc cache(a[:][:]) /* { dg-error "array type length expression must be specified" } */
+    bar (&a[0][0]); /* { dg-bogus "referenced in target region does not have a mappable type" } */
+  #pragma acc cache(b[-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (b);
+  #pragma acc cache(c[:-3][:]) /* { dg-error "negative length in array section" } */
+    bar (&c[0][0]);
+  #pragma acc cache(d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (d);
+  #pragma acc cache(e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (e);
+  #pragma acc cache(f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (f);
+  #pragma acc cache(g[:][0:10]) /* { dg-error "for array function parameter length expression must be specified" } */
+    bar (&g[0][0]);
+  #pragma acc cache(h[2:1][-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (&h[0][0]);
+  #pragma acc cache(h[:1][:-3]) /* { dg-error "negative length in array section" } */
+    bar (&h[0][0]);
+  #pragma acc cache(i[:1][11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (&i[0][0]);
+  #pragma acc cache(j[3:1][:10]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc cache(j[30:1][5:5]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc cache(a2[:1][2:4])
+    bar (&a2[0][0]);
+  #pragma acc cache(a2[3:5][:])
+    bar (&a2[0][0]);
+  #pragma acc cache(a2[3:5][:10])
+    bar (&a2[0][0]);
+  #pragma acc cache(b2[0:])
+    bar (b2);
+  #pragma acc cache(c2[:3][:])
+    bar (&c2[0][0]);
+  #pragma acc cache(d2[9:])
+    bar (d2);
+  #pragma acc cache(e2[:10])
+    bar (e2);
+  #pragma acc cache(f2[1:9])
+    bar (f2);
+  #pragma acc cache(g2[:1][2:4])
+    bar (&g2[0][0]);
+  #pragma acc cache(h2[2:2][0:])
+    bar (&h2[0][0]);
+  #pragma acc cache(h2[:1][:3])
+    bar (&h2[0][0]);
+  #pragma acc cache(i2[:1][9:])
+    bar (&i2[0][0]);
+  #pragma acc cache(j2[3:4][:9])
+    bar (&j2[0][0]);
+  #pragma acc cache(j2[30:1][5:4])
+    bar (&j2[0][0]);
+  #pragma acc cache(q[1:2])
+    ;
+  #pragma acc cache(q[3:5][:10]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2])
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][0:4])
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][1:][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:3][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][1:]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][:3]) /* { dg-error "array section is not contiguous" } */
+    ;
+}
diff --git a/gcc/testsuite/c-c++-common/goacc/cache-3-2.c b/gcc/testsuite/c-c++-common/goacc/cache-3-2.c
new file mode 100644
index 00000000000..ea5222e7d0c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/goacc/cache-3-2.c
@@ -0,0 +1,50 @@
+/* Test 'cache' directive diagnostics.  */
+
+/* See also corresponding C++ variant: '../../g++.dg/goacc/cache-3-2.C'.  */
+
+/* See also corresponding C/C++ data clause variant: 'data-clause-2.c'.  */
+
+/* The current implementation doesn't restrict where a 'cache' directive may
+   appear, so we don't make any special arrangements.  */
+
+void
+foo (int *p, int (*q)[10], int r[10], int s[10][10])
+{
+  int a[10], b[10][10];
+  #pragma acc cache (p[-1:2])
+  ;
+  #pragma acc cache (q[-1:2][0:10])
+  ;
+  #pragma acc cache (q[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (r[-1:2])
+  ;
+  #pragma acc cache (s[-1:2][:])
+  ;
+  #pragma acc cache (s[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (a[-1:2])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (b[-1:2][0:])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (b[1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (p[2:-3])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (q[2:-3][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (q[2:3][0:-1])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (r[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (s[2:-5][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (s[2:5][0:-4])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (a[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (b[2:-5][0:10]) /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (b[2:5][0:-4]) /* { dg-error "negative length in array section in" } */
+  ;
+}
diff --git a/gcc/testsuite/c-c++-common/goacc/data-clause-1.c b/gcc/testsuite/c-c++-common/goacc/data-clause-1.c
new file mode 100644
index 00000000000..9952ac4fb4f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/goacc/data-clause-1.c
@@ -0,0 +1,115 @@
+/* Test data clause diagnostics.  */
+
+/* See also corresponding OpenACC C++ variant: '../../g++.dg/goacc/data-clause-1.C'.  */
+
+/* See also corresponding OpenACC 'cache' directive variant: 'cache-3-1.c'.  */
+
+/* See also corresponding OpenMP variant: '../gomp/map-1.c'.  */
+
+/* { dg-additional-options "-fopenmp" } for '#pragma omp threadprivate'.  */
+
+extern int a[][10], a2[][10];
+int b[10], c[10][2], d[10], e[10], f[10];
+int b2[10], c2[10][2], d2[10], e2[10], f2[10];
+int k[10], l[10], m[10], n[10], o;
+int *p;
+int **q;
+int r[4][4][4][4][4];
+extern struct s s1;
+extern struct s s2[1]; /* { dg-error "array type has incomplete element type" "" { target c } } */
+int t[10];
+#pragma omp threadprivate (t)
+#pragma acc routine
+void bar (int *);
+
+void
+foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
+     int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9])
+{
+  #pragma acc parallel copyin(bar[2:5]) /* { dg-error "is not a variable" } */
+    ;
+  #pragma acc parallel copyout(t[2:5]) /* { dg-error "is threadprivate variable" } */
+    ;
+  #pragma acc parallel copy(k[0.5:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyout(l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyin(m[p:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copy(n[:p]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyin(o[2:5]) /* { dg-error "does not have pointer or array type" } */
+    ;
+  #pragma acc parallel create(s1) /* { dg-error "'s1' does not have a mappable type in 'map' clause" } */
+    ;
+  #pragma acc parallel create(s2) /* { dg-error "'s2' does not have a mappable type in 'map' clause" } */
+    ;
+  #pragma acc parallel copyin(a[:][:]) /* { dg-error "array type length expression must be specified" } */
+    bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" } */
+  #pragma acc parallel copy(b[-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (b);
+  #pragma acc parallel copy(c[:-3][:]) /* { dg-error "negative length in array section" } */
+    bar (&c[0][0]);
+  #pragma acc parallel copyout(d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (d);
+  #pragma acc parallel copyin(e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (e);
+  #pragma acc parallel copyin(f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (f);
+  #pragma acc parallel copyout(g[:][0:10]) /* { dg-error "for array function parameter length expression must be specified" } */
+    bar (&g[0][0]);
+  #pragma acc parallel copyout(h[2:1][-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (&h[0][0]);
+  #pragma acc parallel copy(h[:1][:-3]) /* { dg-error "negative length in array section" } */
+    bar (&h[0][0]);
+  #pragma acc parallel copy(i[:1][11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (&i[0][0]);
+  #pragma acc parallel copyout(j[3:1][:10]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc parallel copyin(j[30:1][5:5]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc parallel copyin(a2[:1][2:4])
+    bar (&a2[0][0]);
+  #pragma acc parallel copy(a2[3:5][:])
+    bar (&a2[0][0]);
+  #pragma acc parallel copyin(a2[3:5][:10])
+    bar (&a2[0][0]);
+  #pragma acc parallel copy(b2[0:])
+    bar (b2);
+  #pragma acc parallel copy(c2[:3][:])
+    bar (&c2[0][0]);
+  #pragma acc parallel copyout(d2[9:])
+    bar (d2);
+  #pragma acc parallel copyin(e2[:10])
+    bar (e2);
+  #pragma acc parallel copyin(f2[1:9])
+    bar (f2);
+  #pragma acc parallel copy(g2[:1][2:4])
+    bar (&g2[0][0]);
+  #pragma acc parallel copyout(h2[2:2][0:])
+    bar (&h2[0][0]);
+  #pragma acc parallel copy(h2[:1][:3])
+    bar (&h2[0][0]);
+  #pragma acc parallel copyin(i2[:1][9:])
+    bar (&i2[0][0]);
+  #pragma acc parallel copyout(j2[3:4][:9])
+    bar (&j2[0][0]);
+  #pragma acc parallel copyin(j2[30:1][5:4])
+    bar (&j2[0][0]);
+  #pragma acc parallel copy(q[1:2])
+    ;
+  #pragma acc parallel copy(q[3:5][:10]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2])
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][0:4])
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][1:][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:3][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][1:]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][:3]) /* { dg-error "array section is not contiguous" } */
+    ;
+}
diff --git a/gcc/testsuite/c-c++-common/goacc/data-clause-2.c b/gcc/testsuite/c-c++-common/goacc/data-clause-2.c
new file mode 100644
index 00000000000..d4603b016dd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/goacc/data-clause-2.c
@@ -0,0 +1,49 @@
+/* Test data clause diagnostics.  */
+
+/* See also corresponding OpenACC C++ variant: '../../g++.dg/goacc/data-clause-2.C'.  */
+
+/* See also corresponding OpenACC 'cache' directive variant: 'cache-3-2.c'.  */
+
+/* See also corresponding OpenMP variant: '../gomp/map-2.c'.  */
+
+void
+foo (int *p, int (*q)[10], int r[10], int s[10][10])
+{
+  int a[10], b[10][10];
+  #pragma acc parallel copy (p[-1:2])
+  ;
+  #pragma acc parallel copy (q[-1:2][0:10])
+  ;
+  #pragma acc parallel copy (q[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (r[-1:2])
+  ;
+  #pragma acc parallel copy (s[-1:2][:])
+  ;
+  #pragma acc parallel copy (s[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (a[-1:2])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (b[-1:2][0:])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (b[1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (p[2:-3])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (q[2:-3][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (q[2:3][0:-1])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (r[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (s[2:-5][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (s[2:5][0:-4])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (a[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (b[2:-5][0:10]) /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (b[2:5][0:-4]) /* { dg-error "negative length in array section in" } */
+  ;
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/map-1.c b/gcc/testsuite/c-c++-common/gomp/map-1.c
index 31100b0396b..ed88944da7b 100644
--- a/gcc/testsuite/c-c++-common/gomp/map-1.c
+++ b/gcc/testsuite/c-c++-common/gomp/map-1.c
@@ -1,6 +1,8 @@
 /* Test 'map' clause diagnostics.  */
 
-/* See also corresponding C++ variant: '../../g++.dg/gomp/map-1.C'.  */
+/* See also corresponding OpenMP C++ variant: '../../g++.dg/gomp/map-1.C'.  */
+
+/* See also corresponding OpenACC variant: '../goacc/data-clause-1.c'.  */
 
 extern int a[][10], a2[][10];
 int b[10], c[10][2], d[10], e[10], f[10];
diff --git a/gcc/testsuite/c-c++-common/gomp/map-2.c b/gcc/testsuite/c-c++-common/gomp/map-2.c
index cd69f6b9a57..01fb4be869d 100644
--- a/gcc/testsuite/c-c++-common/gomp/map-2.c
+++ b/gcc/testsuite/c-c++-common/gomp/map-2.c
@@ -1,6 +1,8 @@
 /* Test 'map' clause diagnostics.  */
 
-/* See also corresponding C++ variant: '../../g++.dg/gomp/map-2.C'.  */
+/* See also corresponding OpenMP C++ variant: '../../g++.dg/gomp/map-2.C'.  */
+
+/* See also corresponding OpenACC variant: '../goacc/data-clause-2.c'.  */
 
 void
 foo (int *p, int (*q)[10], int r[10], int s[10][10])
diff --git a/gcc/testsuite/g++.dg/goacc/cache-3-1.C b/gcc/testsuite/g++.dg/goacc/cache-3-1.C
new file mode 100644
index 00000000000..ceafb38d267
--- /dev/null
+++ b/gcc/testsuite/g++.dg/goacc/cache-3-1.C
@@ -0,0 +1,123 @@
+/* Test 'cache' directive diagnostics.  */
+
+/* See also corresponding C/C++ variant: '../../c-c++-common/goacc/cache-3-1.c'.  */
+
+/* See also corresponding C++ data clause variant: 'data-clause-1.C'.  */
+
+/* { dg-additional-options "-fopenmp" } for '#pragma omp threadprivate'.  */
+
+/* The current implementation doesn't restrict where a 'cache' directive may
+   appear, so we don't make any special arrangements.  */
+
+extern int a[][10], a2[][10];
+int b[10], c[10][2], d[10], e[10], f[10];
+int b2[10], c2[10][2], d2[10], e2[10], f2[10];
+int k[10], l[10], m[10], n[10], o;
+int *p;
+int **q;
+int r[4][4][4][4][4];
+extern struct s s1;
+extern struct s s2[1]; /* { dg-error "array type has incomplete element type" "" { target c } } */
+int t[10];
+#pragma omp threadprivate (t)
+#pragma acc routine
+void bar (int *);
+
+template <int N>
+void
+foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
+     int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9])
+{
+  #pragma acc cache(bar[2:5]) /* { dg-error "is not a variable" } */
+    ;
+  #pragma acc cache(t[2:5]) /* { dg-error "is threadprivate variable" } */
+    ;
+  #pragma acc cache(k[0.5:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(m[p:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(n[:p]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(o[2:5]) /* { dg-error "does not have pointer or array type" } */
+    ;
+  #pragma acc cache(s1) /* { dg-error "expected '\\\['" } */
+    ;
+  #pragma acc cache(s2) /* { dg-error "expected '\\\['" } */
+    ;
+  #pragma acc cache(a[:][:]) /* { dg-error "array type length expression must be specified" } */
+    bar (&a[0][0]);
+  #pragma acc cache(b[-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (b);
+  #pragma acc cache(c[:-3][:]) /* { dg-error "negative length in array section" } */
+    bar (&c[0][0]);
+  #pragma acc cache(d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (d);
+  #pragma acc cache(e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (e);
+  #pragma acc cache(f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (f);
+  #pragma acc cache(g[:][0:10]) /* { dg-error "for array function parameter length expression must be specified" } */
+    bar (&g[0][0]);
+  #pragma acc cache(h[2:1][-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (&h[0][0]);
+  #pragma acc cache(h[:1][:-3]) /* { dg-error "negative length in array section" } */
+    bar (&h[0][0]);
+  #pragma acc cache(i[:1][11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (&i[0][0]);
+  #pragma acc cache(j[3:1][:10]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc cache(j[30:1][5:5]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc cache(a2[:1][2:4])
+    bar (&a2[0][0]);
+  #pragma acc cache(a2[3:5][:])
+    bar (&a2[0][0]);
+  #pragma acc cache(a2[3:5][:10])
+    bar (&a2[0][0]);
+  #pragma acc cache(b2[0:])
+    bar (b2);
+  #pragma acc cache(c2[:3][:])
+    bar (&c2[0][0]);
+  #pragma acc cache(d2[9:])
+    bar (d2);
+  #pragma acc cache(e2[:10])
+    bar (e2);
+  #pragma acc cache(f2[1:9])
+    bar (f2);
+  #pragma acc cache(g2[:1][2:4])
+    bar (&g2[0][0]);
+  #pragma acc cache(h2[2:2][0:])
+    bar (&h2[0][0]);
+  #pragma acc cache(h2[:1][:3])
+    bar (&h2[0][0]);
+  #pragma acc cache(i2[:1][9:])
+    bar (&i2[0][0]);
+  #pragma acc cache(j2[3:4][:9])
+    bar (&j2[0][0]);
+  #pragma acc cache(j2[30:1][5:4])
+    bar (&j2[0][0]);
+  #pragma acc cache(q[1:2])
+    ;
+  #pragma acc cache(q[3:5][:10]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2])
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][0:4])
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][1:][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:3][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][1:]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][:3]) /* { dg-error "array section is not contiguous" } */
+    ;
+}
+
+static void
+instantiate ()
+{
+  &foo<0>;
+}
diff --git a/gcc/testsuite/g++.dg/goacc/cache-3-2.C b/gcc/testsuite/g++.dg/goacc/cache-3-2.C
new file mode 100644
index 00000000000..5561e176a56
--- /dev/null
+++ b/gcc/testsuite/g++.dg/goacc/cache-3-2.C
@@ -0,0 +1,57 @@
+/* Test 'cache' directive diagnostics.  */
+
+/* See also corresponding C/C++ variant: '../../c-c++-common/goacc/cache-3-2.c'.  */
+
+/* See also corresponding C++ data clause variant: 'data-clause-2.C'.  */
+
+/* The current implementation doesn't restrict where a 'cache' directive may
+   appear, so we don't make any special arrangements.  */
+
+template <int N>
+void
+foo (int *p, int (*q)[10], int r[10], int s[10][10])
+{
+  int a[10], b[10][10];
+  #pragma acc cache (p[-1:2])
+  ;
+  #pragma acc cache (q[-1:2][0:10])
+  ;
+  #pragma acc cache (q[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (r[-1:2])
+  ;
+  #pragma acc cache (s[-1:2][:])
+  ;
+  #pragma acc cache (s[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (a[-1:2])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (b[-1:2][0:])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (b[1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (p[2:-3])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (q[2:-3][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (q[2:3][0:-1])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (r[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (s[2:-5][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (s[2:5][0:-4])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (a[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (b[2:-5][0:10]) /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (b[2:5][0:-4]) /* { dg-error "negative length in array section in" } */
+  ;
+}
+
+static void
+instantiate ()
+{
+  &foo<0>;
+}
diff --git a/gcc/testsuite/g++.dg/goacc/data-clause-1.C b/gcc/testsuite/g++.dg/goacc/data-clause-1.C
new file mode 100644
index 00000000000..07ef6aed788
--- /dev/null
+++ b/gcc/testsuite/g++.dg/goacc/data-clause-1.C
@@ -0,0 +1,122 @@
+/* Test data clause diagnostics.  */
+
+/* See also corresponding OpenACC C/C++ variant: '../../c-c++-common/goacc/data-clause-1.c'.  */
+
+/* See also corresponding OpenACC 'cache' directive variant: 'cache-3-1.C'.  */
+
+/* See also corresponding OpenMP variant: '../gomp/map-1.C'.  */
+
+/* { dg-additional-options "-fopenmp" } for '#pragma omp threadprivate'.  */
+
+extern int a[][10], a2[][10];
+int b[10], c[10][2], d[10], e[10], f[10];
+int b2[10], c2[10][2], d2[10], e2[10], f2[10];
+int k[10], l[10], m[10], n[10], o;
+int *p;
+int **q;
+int r[4][4][4][4][4];
+extern struct s s1;
+extern struct s s2[1]; /* { dg-error "array type has incomplete element type" "" { target c } } */
+int t[10];
+#pragma omp threadprivate (t)
+#pragma acc routine
+void bar (int *);
+
+template <int N>
+void
+foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
+     int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9])
+{
+  #pragma acc parallel copyin(bar[2:5]) /* { dg-error "is not a variable" } */
+    ;
+  #pragma acc parallel copyout(t[2:5]) /* { dg-error "is threadprivate variable" } */
+    ;
+  #pragma acc parallel copy(k[0.5:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyout(l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyin(m[p:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copy(n[:p]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyin(o[2:5]) /* { dg-error "does not have pointer or array type" } */
+    ;
+  #pragma acc parallel create(s1) /* { dg-error "'s1' does not have a mappable type in 'map' clause" } */
+    ;
+  #pragma acc parallel create(s2) /* { dg-error "'s2' does not have a mappable type in 'map' clause" } */
+    ;
+  #pragma acc parallel copyin(a[:][:]) /* { dg-error "array type length expression must be specified" } */
+    bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" "PR97996" { xfail *-*-* } } */
+  #pragma acc parallel copy(b[-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (b);
+  #pragma acc parallel copy(c[:-3][:]) /* { dg-error "negative length in array section" } */
+    bar (&c[0][0]);
+  #pragma acc parallel copyout(d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (d);
+  #pragma acc parallel copyin(e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (e);
+  #pragma acc parallel copyin(f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (f);
+  #pragma acc parallel copyout(g[:][0:10]) /* { dg-error "for array function parameter length expression must be specified" } */
+    bar (&g[0][0]);
+  #pragma acc parallel copyout(h[2:1][-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (&h[0][0]);
+  #pragma acc parallel copy(h[:1][:-3]) /* { dg-error "negative length in array section" } */
+    bar (&h[0][0]);
+  #pragma acc parallel copy(i[:1][11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (&i[0][0]);
+  #pragma acc parallel copyout(j[3:1][:10]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc parallel copyin(j[30:1][5:5]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc parallel copyin(a2[:1][2:4])
+    bar (&a2[0][0]);
+  #pragma acc parallel copy(a2[3:5][:])
+    bar (&a2[0][0]);
+  #pragma acc parallel copyin(a2[3:5][:10])
+    bar (&a2[0][0]);
+  #pragma acc parallel copy(b2[0:])
+    bar (b2);
+  #pragma acc parallel copy(c2[:3][:])
+    bar (&c2[0][0]);
+  #pragma acc parallel copyout(d2[9:])
+    bar (d2);
+  #pragma acc parallel copyin(e2[:10])
+    bar (e2);
+  #pragma acc parallel copyin(f2[1:9])
+    bar (f2);
+  #pragma acc parallel copy(g2[:1][2:4])
+    bar (&g2[0][0]);
+  #pragma acc parallel copyout(h2[2:2][0:])
+    bar (&h2[0][0]);
+  #pragma acc parallel copy(h2[:1][:3])
+    bar (&h2[0][0]);
+  #pragma acc parallel copyin(i2[:1][9:])
+    bar (&i2[0][0]);
+  #pragma acc parallel copyout(j2[3:4][:9])
+    bar (&j2[0][0]);
+  #pragma acc parallel copyin(j2[30:1][5:4])
+    bar (&j2[0][0]);
+  #pragma acc parallel copy(q[1:2])
+    ;
+  #pragma acc parallel copy(q[3:5][:10]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2])
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][0:4])
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][1:][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:3][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][1:]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][:3]) /* { dg-error "array section is not contiguous" } */
+    ;
+}
+
+static void
+instantiate ()
+{
+  &foo<0>;
+}
diff --git a/gcc/testsuite/g++.dg/goacc/data-clause-2.C b/gcc/testsuite/g++.dg/goacc/data-clause-2.C
new file mode 100644
index 00000000000..57d1823aede
--- /dev/null
+++ b/gcc/testsuite/g++.dg/goacc/data-clause-2.C
@@ -0,0 +1,56 @@
+/* Test data clause diagnostics.  */
+
+/* See also corresponding OpenACC C/C++ variant: '../../c-c++-common/goacc/data-clause-2.c'.  */
+
+/* See also corresponding OpenACC 'cache' directive variant: 'cache-3-2.C'.  */
+
+/* See also corresponding OpenMP variant: '../gomp/map-2.C'.  */
+
+template <int N>
+void
+foo (int *p, int (*q)[10], int r[10], int s[10][10])
+{
+  int a[10], b[10][10];
+  #pragma acc parallel copy (p[-1:2])
+  ;
+  #pragma acc parallel copy (q[-1:2][0:10])
+  ;
+  #pragma acc parallel copy (q[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (r[-1:2])
+  ;
+  #pragma acc parallel copy (s[-1:2][:])
+  ;
+  #pragma acc parallel copy (s[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (a[-1:2])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (b[-1:2][0:])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (b[1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (p[2:-3])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (q[2:-3][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (q[2:3][0:-1])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (r[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (s[2:-5][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (s[2:5][0:-4])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (a[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (b[2:-5][0:10]) /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (b[2:5][0:-4]) /* { dg-error "negative length in array section in" } */
+  ;
+}
+
+static void
+instantiate ()
+{
+  &foo<0>;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/map-1.C b/gcc/testsuite/g++.dg/gomp/map-1.C
index 11275efff4a..27dc7a551cb 100644
--- a/gcc/testsuite/g++.dg/gomp/map-1.C
+++ b/gcc/testsuite/g++.dg/gomp/map-1.C
@@ -1,6 +1,8 @@
 /* Test 'map' clause diagnostics.  */
 
-/* See also corresponding C/C++ variant: '../../c-c++-common/gomp/map-1.c'.  */
+/* See also corresponding OpenMP C/C++ variant: '../../c-c++-common/gomp/map-1.c'.  */
+
+/* See also corresponding OpenACC variant: '../goacc/data-clause-1.C'.  */
 
 extern int a[][10], a2[][10];
 int b[10], c[10][2], d[10], e[10], f[10];
@@ -41,7 +43,7 @@ foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
   #pragma omp target map(alloc: s2) /* { dg-error "'s2' does not have a mappable type in 'map' clause" } */
     ;
   #pragma omp target map(to: a[:][:]) /* { dg-error "array type length expression must be specified" } */
-    bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" "TODO" { xfail *-*-* } } */
+    bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" "PR97996" { xfail *-*-* } } */
   #pragma omp target map(tofrom: b[-1:]) /* { dg-error "negative low bound in array section" } */
     bar (b);
   #pragma omp target map(tofrom: c[:-3][:]) /* { dg-error "negative length in array section" } */
diff --git a/gcc/testsuite/g++.dg/gomp/map-2.C b/gcc/testsuite/g++.dg/gomp/map-2.C
index 10eaaa948b8..bbe26061fe3 100644
--- a/gcc/testsuite/g++.dg/gomp/map-2.C
+++ b/gcc/testsuite/g++.dg/gomp/map-2.C
@@ -1,6 +1,8 @@
 /* Test 'map' clause diagnostics.  */
 
-/* See also corresponding C/C++ variant: '../../c-c++-common/gomp/map-2.c'.  */
+/* See also corresponding OpenMP C/C++ variant: '../../c-c++-common/gomp/map-2.c'.  */
+
+/* See also corresponding OpenACC variant: '../goacc/data-clause-2.C'.  */
 
 template <int N>
 void
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0001-Don-t-create-location-wrapper-nodes-within-OpenA.g10.patch --]
[-- Type: text/x-diff, Size: 37905 bytes --]

From e8e0357d129187b24085ce52172c87dbf6c2ecae Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Wed, 25 Nov 2020 20:36:55 +0100
Subject: [PATCH] Don't create location wrapper nodes within OpenACC clauses

This fixes a GCC 11, 10, 9 regression introduced by commit
dfd7fdca2ac17d8b823a16700525824ca312ade0 (Subversion r267272) "C++: more
location wrapper nodes (PR c++/43064, PR c++/43486)".  But: this isn't
intending to blame David, because back then, the problem hasn't been visible in
the testsuite (or else I'm sure would've been addressed right away) because of
our all dear friend: missing testsuite coverage.  Thus, for GCC 8, I'm likewise
enhancing the testsuite, without the C++ front end code changes.

I actually had presumed that there may be an issue for OpenACC:
<http://mid.mail-archive.com/874lb9qr2u.fsf@euler.schwinge.homeip.net>, so here
we are, two years (and many "wasted" hours...) later...

	gcc/cp/
	* parser.c (cp_parser_omp_var_list_no_open): Assert that array
	section's 'low_bound', 'length' are not location wrapper nodes.
	(cp_parser_oacc_all_clauses, cp_parser_oacc_cache): Instantiate
	'auto_suppress_location_wrappers'.
	gcc/testsuite/
	* c-c++-common/goacc/cache-3-1.c: New.
	* c-c++-common/goacc/cache-3-2.c: Likewise.
	* c-c++-common/goacc/data-clause-1.c: Likewise.
	* c-c++-common/goacc/data-clause-2.c: Likewise.
	* c-c++-common/gomp/map-1.c: Adjust.
	* c-c++-common/gomp/map-2.c: Likewise.
	* g++.dg/goacc/cache-3-1.C: New.
	* g++.dg/goacc/cache-3-2.C: Likewise.
	* g++.dg/goacc/data-clause-1.C: Likewise.
	* g++.dg/goacc/data-clause-2.C: Likewise.
	* g++.dg/gomp/map-1.C: Adjust.
	* g++.dg/gomp/map-2.C: Likewise.

Reported-by: Sandra Loosemore <sandra@codesourcery.com>
(cherry picked from commit c0c7270cc4efd896fe99f8ad5409dbef089a407f)
---
 gcc/cp/parser.c                               |  19 ++-
 gcc/testsuite/c-c++-common/goacc/cache-3-1.c  | 116 +++++++++++++++++
 gcc/testsuite/c-c++-common/goacc/cache-3-2.c  |  50 +++++++
 .../c-c++-common/goacc/data-clause-1.c        | 115 ++++++++++++++++
 .../c-c++-common/goacc/data-clause-2.c        |  49 +++++++
 gcc/testsuite/c-c++-common/gomp/map-1.c       |   4 +-
 gcc/testsuite/c-c++-common/gomp/map-2.c       |   4 +-
 gcc/testsuite/g++.dg/goacc/cache-3-1.C        | 123 ++++++++++++++++++
 gcc/testsuite/g++.dg/goacc/cache-3-2.C        |  57 ++++++++
 gcc/testsuite/g++.dg/goacc/data-clause-1.C    | 122 +++++++++++++++++
 gcc/testsuite/g++.dg/goacc/data-clause-2.C    |  56 ++++++++
 gcc/testsuite/g++.dg/gomp/map-1.C             |   6 +-
 gcc/testsuite/g++.dg/gomp/map-2.C             |   4 +-
 13 files changed, 718 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/goacc/cache-3-1.c
 create mode 100644 gcc/testsuite/c-c++-common/goacc/cache-3-2.c
 create mode 100644 gcc/testsuite/c-c++-common/goacc/data-clause-1.c
 create mode 100644 gcc/testsuite/c-c++-common/goacc/data-clause-2.c
 create mode 100644 gcc/testsuite/g++.dg/goacc/cache-3-1.C
 create mode 100644 gcc/testsuite/g++.dg/goacc/cache-3-2.C
 create mode 100644 gcc/testsuite/g++.dg/goacc/data-clause-1.C
 create mode 100644 gcc/testsuite/g++.dg/goacc/data-clause-2.C

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 846d1aa2a3d..dada1359526 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -34328,7 +34328,11 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
 		  parser->colon_corrects_to_scope_p = false;
 		  cp_lexer_consume_token (parser->lexer);
 		  if (!cp_lexer_next_token_is (parser->lexer, CPP_COLON))
-		    low_bound = cp_parser_expression (parser);
+		    {
+		      low_bound = cp_parser_expression (parser);
+		      /* Later handling is not prepared to see through these.  */
+		      gcc_checking_assert (!location_wrapper_p (low_bound));
+		    }
 		  if (!colon)
 		    parser->colon_corrects_to_scope_p
 		      = saved_colon_corrects_to_scope_p;
@@ -34348,7 +34352,11 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
 			cp_parser_commit_to_tentative_parse (parser);
 		      if (!cp_lexer_next_token_is (parser->lexer,
 						   CPP_CLOSE_SQUARE))
-			length = cp_parser_expression (parser);
+			{
+			  length = cp_parser_expression (parser);
+			  /* Later handling is not prepared to see through these.  */
+			  gcc_checking_assert (!location_wrapper_p (length));
+			}
 		    }
 		  /* Look for the closing `]'.  */
 		  if (!cp_parser_require (parser, CPP_CLOSE_SQUARE,
@@ -36955,6 +36963,9 @@ cp_parser_oacc_all_clauses (cp_parser *parser, omp_clause_mask mask,
   tree clauses = NULL;
   bool first = true;
 
+  /* Don't create location wrapper nodes within OpenACC clauses.  */
+  auto_suppress_location_wrappers sentinel;
+
   while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL))
     {
       location_t here;
@@ -40846,6 +40857,10 @@ check_clauses:
 static tree
 cp_parser_oacc_cache (cp_parser *parser, cp_token *pragma_tok)
 {
+  /* Don't create location wrapper nodes within 'OMP_CLAUSE__CACHE_'
+     clauses.  */
+  auto_suppress_location_wrappers sentinel;
+
   tree stmt, clauses;
 
   clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE__CACHE_, NULL_TREE);
diff --git a/gcc/testsuite/c-c++-common/goacc/cache-3-1.c b/gcc/testsuite/c-c++-common/goacc/cache-3-1.c
new file mode 100644
index 00000000000..155de689dfa
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/goacc/cache-3-1.c
@@ -0,0 +1,116 @@
+/* Test 'cache' directive diagnostics.  */
+
+/* See also corresponding C++ variant: '../../g++.dg/goacc/cache-3-1.C'.  */
+
+/* See also corresponding C/C++ data clause variant: 'data-clause-1.c'.  */
+
+/* { dg-additional-options "-fopenmp" } for '#pragma omp threadprivate'.  */
+
+/* The current implementation doesn't restrict where a 'cache' directive may
+   appear, so we don't make any special arrangements.  */
+
+extern int a[][10], a2[][10];
+int b[10], c[10][2], d[10], e[10], f[10];
+int b2[10], c2[10][2], d2[10], e2[10], f2[10];
+int k[10], l[10], m[10], n[10], o;
+int *p;
+int **q;
+int r[4][4][4][4][4];
+extern struct s s1;
+extern struct s s2[1]; /* { dg-error "array type has incomplete element type" "" { target c } } */
+int t[10];
+#pragma omp threadprivate (t)
+#pragma acc routine
+void bar (int *);
+
+void
+foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
+     int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9])
+{
+  #pragma acc cache(bar[2:5]) /* { dg-error "is not a variable" } */
+    ;
+  #pragma acc cache(t[2:5]) /* { dg-error "is threadprivate variable" } */
+    ;
+  #pragma acc cache(k[0.5:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(m[p:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(n[:p]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(o[2:5]) /* { dg-error "does not have pointer or array type" } */
+    ;
+  #pragma acc cache(s1) /* { dg-error "expected '\\\['" } */
+    ;
+  #pragma acc cache(s2) /* { dg-error "expected '\\\['" } */
+    ;
+  #pragma acc cache(a[:][:]) /* { dg-error "array type length expression must be specified" } */
+    bar (&a[0][0]); /* { dg-bogus "referenced in target region does not have a mappable type" } */
+  #pragma acc cache(b[-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (b);
+  #pragma acc cache(c[:-3][:]) /* { dg-error "negative length in array section" } */
+    bar (&c[0][0]);
+  #pragma acc cache(d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (d);
+  #pragma acc cache(e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (e);
+  #pragma acc cache(f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (f);
+  #pragma acc cache(g[:][0:10]) /* { dg-error "for pointer type length expression must be specified" } */
+    bar (&g[0][0]);
+  #pragma acc cache(h[2:1][-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (&h[0][0]);
+  #pragma acc cache(h[:1][:-3]) /* { dg-error "negative length in array section" } */
+    bar (&h[0][0]);
+  #pragma acc cache(i[:1][11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (&i[0][0]);
+  #pragma acc cache(j[3:1][:10]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc cache(j[30:1][5:5]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc cache(a2[:1][2:4])
+    bar (&a2[0][0]);
+  #pragma acc cache(a2[3:5][:])
+    bar (&a2[0][0]);
+  #pragma acc cache(a2[3:5][:10])
+    bar (&a2[0][0]);
+  #pragma acc cache(b2[0:])
+    bar (b2);
+  #pragma acc cache(c2[:3][:])
+    bar (&c2[0][0]);
+  #pragma acc cache(d2[9:])
+    bar (d2);
+  #pragma acc cache(e2[:10])
+    bar (e2);
+  #pragma acc cache(f2[1:9])
+    bar (f2);
+  #pragma acc cache(g2[:1][2:4])
+    bar (&g2[0][0]);
+  #pragma acc cache(h2[2:2][0:])
+    bar (&h2[0][0]);
+  #pragma acc cache(h2[:1][:3])
+    bar (&h2[0][0]);
+  #pragma acc cache(i2[:1][9:])
+    bar (&i2[0][0]);
+  #pragma acc cache(j2[3:4][:9])
+    bar (&j2[0][0]);
+  #pragma acc cache(j2[30:1][5:4])
+    bar (&j2[0][0]);
+  #pragma acc cache(q[1:2])
+    ;
+  #pragma acc cache(q[3:5][:10]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2])
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][0:4])
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][1:][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:3][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][1:]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][:3]) /* { dg-error "array section is not contiguous" } */
+    ;
+}
diff --git a/gcc/testsuite/c-c++-common/goacc/cache-3-2.c b/gcc/testsuite/c-c++-common/goacc/cache-3-2.c
new file mode 100644
index 00000000000..ea5222e7d0c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/goacc/cache-3-2.c
@@ -0,0 +1,50 @@
+/* Test 'cache' directive diagnostics.  */
+
+/* See also corresponding C++ variant: '../../g++.dg/goacc/cache-3-2.C'.  */
+
+/* See also corresponding C/C++ data clause variant: 'data-clause-2.c'.  */
+
+/* The current implementation doesn't restrict where a 'cache' directive may
+   appear, so we don't make any special arrangements.  */
+
+void
+foo (int *p, int (*q)[10], int r[10], int s[10][10])
+{
+  int a[10], b[10][10];
+  #pragma acc cache (p[-1:2])
+  ;
+  #pragma acc cache (q[-1:2][0:10])
+  ;
+  #pragma acc cache (q[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (r[-1:2])
+  ;
+  #pragma acc cache (s[-1:2][:])
+  ;
+  #pragma acc cache (s[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (a[-1:2])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (b[-1:2][0:])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (b[1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (p[2:-3])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (q[2:-3][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (q[2:3][0:-1])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (r[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (s[2:-5][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (s[2:5][0:-4])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (a[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (b[2:-5][0:10]) /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (b[2:5][0:-4]) /* { dg-error "negative length in array section in" } */
+  ;
+}
diff --git a/gcc/testsuite/c-c++-common/goacc/data-clause-1.c b/gcc/testsuite/c-c++-common/goacc/data-clause-1.c
new file mode 100644
index 00000000000..20f822cbb99
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/goacc/data-clause-1.c
@@ -0,0 +1,115 @@
+/* Test data clause diagnostics.  */
+
+/* See also corresponding OpenACC C++ variant: '../../g++.dg/goacc/data-clause-1.C'.  */
+
+/* See also corresponding OpenACC 'cache' directive variant: 'cache-3-1.c'.  */
+
+/* See also corresponding OpenMP variant: '../gomp/map-1.c'.  */
+
+/* { dg-additional-options "-fopenmp" } for '#pragma omp threadprivate'.  */
+
+extern int a[][10], a2[][10];
+int b[10], c[10][2], d[10], e[10], f[10];
+int b2[10], c2[10][2], d2[10], e2[10], f2[10];
+int k[10], l[10], m[10], n[10], o;
+int *p;
+int **q;
+int r[4][4][4][4][4];
+extern struct s s1;
+extern struct s s2[1]; /* { dg-error "array type has incomplete element type" "" { target c } } */
+int t[10];
+#pragma omp threadprivate (t)
+#pragma acc routine
+void bar (int *);
+
+void
+foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
+     int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9])
+{
+  #pragma acc parallel copyin(bar[2:5]) /* { dg-error "is not a variable" } */
+    ;
+  #pragma acc parallel copyout(t[2:5]) /* { dg-error "is threadprivate variable" } */
+    ;
+  #pragma acc parallel copy(k[0.5:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyout(l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyin(m[p:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copy(n[:p]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyin(o[2:5]) /* { dg-error "does not have pointer or array type" } */
+    ;
+  #pragma acc parallel create(s1) /* { dg-error "'s1' does not have a mappable type in 'map' clause" } */
+    ;
+  #pragma acc parallel create(s2) /* { dg-error "'s2' does not have a mappable type in 'map' clause" } */
+    ;
+  #pragma acc parallel copyin(a[:][:]) /* { dg-error "array type length expression must be specified" } */
+    bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" } */
+  #pragma acc parallel copy(b[-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (b);
+  #pragma acc parallel copy(c[:-3][:]) /* { dg-error "negative length in array section" } */
+    bar (&c[0][0]);
+  #pragma acc parallel copyout(d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (d);
+  #pragma acc parallel copyin(e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (e);
+  #pragma acc parallel copyin(f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (f);
+  #pragma acc parallel copyout(g[:][0:10]) /* { dg-error "for pointer type length expression must be specified" } */
+    bar (&g[0][0]);
+  #pragma acc parallel copyout(h[2:1][-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (&h[0][0]);
+  #pragma acc parallel copy(h[:1][:-3]) /* { dg-error "negative length in array section" } */
+    bar (&h[0][0]);
+  #pragma acc parallel copy(i[:1][11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (&i[0][0]);
+  #pragma acc parallel copyout(j[3:1][:10]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc parallel copyin(j[30:1][5:5]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc parallel copyin(a2[:1][2:4])
+    bar (&a2[0][0]);
+  #pragma acc parallel copy(a2[3:5][:])
+    bar (&a2[0][0]);
+  #pragma acc parallel copyin(a2[3:5][:10])
+    bar (&a2[0][0]);
+  #pragma acc parallel copy(b2[0:])
+    bar (b2);
+  #pragma acc parallel copy(c2[:3][:])
+    bar (&c2[0][0]);
+  #pragma acc parallel copyout(d2[9:])
+    bar (d2);
+  #pragma acc parallel copyin(e2[:10])
+    bar (e2);
+  #pragma acc parallel copyin(f2[1:9])
+    bar (f2);
+  #pragma acc parallel copy(g2[:1][2:4])
+    bar (&g2[0][0]);
+  #pragma acc parallel copyout(h2[2:2][0:])
+    bar (&h2[0][0]);
+  #pragma acc parallel copy(h2[:1][:3])
+    bar (&h2[0][0]);
+  #pragma acc parallel copyin(i2[:1][9:])
+    bar (&i2[0][0]);
+  #pragma acc parallel copyout(j2[3:4][:9])
+    bar (&j2[0][0]);
+  #pragma acc parallel copyin(j2[30:1][5:4])
+    bar (&j2[0][0]);
+  #pragma acc parallel copy(q[1:2])
+    ;
+  #pragma acc parallel copy(q[3:5][:10]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2])
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][0:4])
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][1:][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:3][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][1:]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][:3]) /* { dg-error "array section is not contiguous" } */
+    ;
+}
diff --git a/gcc/testsuite/c-c++-common/goacc/data-clause-2.c b/gcc/testsuite/c-c++-common/goacc/data-clause-2.c
new file mode 100644
index 00000000000..d4603b016dd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/goacc/data-clause-2.c
@@ -0,0 +1,49 @@
+/* Test data clause diagnostics.  */
+
+/* See also corresponding OpenACC C++ variant: '../../g++.dg/goacc/data-clause-2.C'.  */
+
+/* See also corresponding OpenACC 'cache' directive variant: 'cache-3-2.c'.  */
+
+/* See also corresponding OpenMP variant: '../gomp/map-2.c'.  */
+
+void
+foo (int *p, int (*q)[10], int r[10], int s[10][10])
+{
+  int a[10], b[10][10];
+  #pragma acc parallel copy (p[-1:2])
+  ;
+  #pragma acc parallel copy (q[-1:2][0:10])
+  ;
+  #pragma acc parallel copy (q[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (r[-1:2])
+  ;
+  #pragma acc parallel copy (s[-1:2][:])
+  ;
+  #pragma acc parallel copy (s[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (a[-1:2])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (b[-1:2][0:])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (b[1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (p[2:-3])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (q[2:-3][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (q[2:3][0:-1])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (r[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (s[2:-5][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (s[2:5][0:-4])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (a[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (b[2:-5][0:10]) /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (b[2:5][0:-4]) /* { dg-error "negative length in array section in" } */
+  ;
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/map-1.c b/gcc/testsuite/c-c++-common/gomp/map-1.c
index cd026f1243f..a8549bc49d9 100644
--- a/gcc/testsuite/c-c++-common/gomp/map-1.c
+++ b/gcc/testsuite/c-c++-common/gomp/map-1.c
@@ -1,6 +1,8 @@
 /* Test 'map' clause diagnostics.  */
 
-/* See also corresponding C++ variant: '../../g++.dg/gomp/map-1.C'.  */
+/* See also corresponding OpenMP C++ variant: '../../g++.dg/gomp/map-1.C'.  */
+
+/* See also corresponding OpenACC variant: '../goacc/data-clause-1.c'.  */
 
 extern int a[][10], a2[][10];
 int b[10], c[10][2], d[10], e[10], f[10];
diff --git a/gcc/testsuite/c-c++-common/gomp/map-2.c b/gcc/testsuite/c-c++-common/gomp/map-2.c
index cd69f6b9a57..01fb4be869d 100644
--- a/gcc/testsuite/c-c++-common/gomp/map-2.c
+++ b/gcc/testsuite/c-c++-common/gomp/map-2.c
@@ -1,6 +1,8 @@
 /* Test 'map' clause diagnostics.  */
 
-/* See also corresponding C++ variant: '../../g++.dg/gomp/map-2.C'.  */
+/* See also corresponding OpenMP C++ variant: '../../g++.dg/gomp/map-2.C'.  */
+
+/* See also corresponding OpenACC variant: '../goacc/data-clause-2.c'.  */
 
 void
 foo (int *p, int (*q)[10], int r[10], int s[10][10])
diff --git a/gcc/testsuite/g++.dg/goacc/cache-3-1.C b/gcc/testsuite/g++.dg/goacc/cache-3-1.C
new file mode 100644
index 00000000000..d543db60a9d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/goacc/cache-3-1.C
@@ -0,0 +1,123 @@
+/* Test 'cache' directive diagnostics.  */
+
+/* See also corresponding C/C++ variant: '../../c-c++-common/goacc/cache-3-1.c'.  */
+
+/* See also corresponding C++ data clause variant: 'data-clause-1.C'.  */
+
+/* { dg-additional-options "-fopenmp" } for '#pragma omp threadprivate'.  */
+
+/* The current implementation doesn't restrict where a 'cache' directive may
+   appear, so we don't make any special arrangements.  */
+
+extern int a[][10], a2[][10];
+int b[10], c[10][2], d[10], e[10], f[10];
+int b2[10], c2[10][2], d2[10], e2[10], f2[10];
+int k[10], l[10], m[10], n[10], o;
+int *p;
+int **q;
+int r[4][4][4][4][4];
+extern struct s s1;
+extern struct s s2[1]; /* { dg-error "array type has incomplete element type" "" { target c } } */
+int t[10];
+#pragma omp threadprivate (t)
+#pragma acc routine
+void bar (int *);
+
+template <int N>
+void
+foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
+     int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9])
+{
+  #pragma acc cache(bar[2:5]) /* { dg-error "is not a variable" } */
+    ;
+  #pragma acc cache(t[2:5]) /* { dg-error "is threadprivate variable" } */
+    ;
+  #pragma acc cache(k[0.5:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(m[p:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(n[:p]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(o[2:5]) /* { dg-error "does not have pointer or array type" } */
+    ;
+  #pragma acc cache(s1) /* { dg-error "expected '\\\['" } */
+    ;
+  #pragma acc cache(s2) /* { dg-error "expected '\\\['" } */
+    ;
+  #pragma acc cache(a[:][:]) /* { dg-error "array type length expression must be specified" } */
+    bar (&a[0][0]);
+  #pragma acc cache(b[-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (b);
+  #pragma acc cache(c[:-3][:]) /* { dg-error "negative length in array section" } */
+    bar (&c[0][0]);
+  #pragma acc cache(d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (d);
+  #pragma acc cache(e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (e);
+  #pragma acc cache(f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (f);
+  #pragma acc cache(g[:][0:10]) /* { dg-error "for pointer type length expression must be specified" } */
+    bar (&g[0][0]);
+  #pragma acc cache(h[2:1][-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (&h[0][0]);
+  #pragma acc cache(h[:1][:-3]) /* { dg-error "negative length in array section" } */
+    bar (&h[0][0]);
+  #pragma acc cache(i[:1][11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (&i[0][0]);
+  #pragma acc cache(j[3:1][:10]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc cache(j[30:1][5:5]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc cache(a2[:1][2:4])
+    bar (&a2[0][0]);
+  #pragma acc cache(a2[3:5][:])
+    bar (&a2[0][0]);
+  #pragma acc cache(a2[3:5][:10])
+    bar (&a2[0][0]);
+  #pragma acc cache(b2[0:])
+    bar (b2);
+  #pragma acc cache(c2[:3][:])
+    bar (&c2[0][0]);
+  #pragma acc cache(d2[9:])
+    bar (d2);
+  #pragma acc cache(e2[:10])
+    bar (e2);
+  #pragma acc cache(f2[1:9])
+    bar (f2);
+  #pragma acc cache(g2[:1][2:4])
+    bar (&g2[0][0]);
+  #pragma acc cache(h2[2:2][0:])
+    bar (&h2[0][0]);
+  #pragma acc cache(h2[:1][:3])
+    bar (&h2[0][0]);
+  #pragma acc cache(i2[:1][9:])
+    bar (&i2[0][0]);
+  #pragma acc cache(j2[3:4][:9])
+    bar (&j2[0][0]);
+  #pragma acc cache(j2[30:1][5:4])
+    bar (&j2[0][0]);
+  #pragma acc cache(q[1:2])
+    ;
+  #pragma acc cache(q[3:5][:10]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2])
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][0:4])
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][1:][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:3][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][1:]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][:3]) /* { dg-error "array section is not contiguous" } */
+    ;
+}
+
+static void
+instantiate ()
+{
+  &foo<0>;
+}
diff --git a/gcc/testsuite/g++.dg/goacc/cache-3-2.C b/gcc/testsuite/g++.dg/goacc/cache-3-2.C
new file mode 100644
index 00000000000..5561e176a56
--- /dev/null
+++ b/gcc/testsuite/g++.dg/goacc/cache-3-2.C
@@ -0,0 +1,57 @@
+/* Test 'cache' directive diagnostics.  */
+
+/* See also corresponding C/C++ variant: '../../c-c++-common/goacc/cache-3-2.c'.  */
+
+/* See also corresponding C++ data clause variant: 'data-clause-2.C'.  */
+
+/* The current implementation doesn't restrict where a 'cache' directive may
+   appear, so we don't make any special arrangements.  */
+
+template <int N>
+void
+foo (int *p, int (*q)[10], int r[10], int s[10][10])
+{
+  int a[10], b[10][10];
+  #pragma acc cache (p[-1:2])
+  ;
+  #pragma acc cache (q[-1:2][0:10])
+  ;
+  #pragma acc cache (q[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (r[-1:2])
+  ;
+  #pragma acc cache (s[-1:2][:])
+  ;
+  #pragma acc cache (s[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (a[-1:2])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (b[-1:2][0:])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (b[1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (p[2:-3])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (q[2:-3][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (q[2:3][0:-1])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (r[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (s[2:-5][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (s[2:5][0:-4])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (a[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (b[2:-5][0:10]) /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (b[2:5][0:-4]) /* { dg-error "negative length in array section in" } */
+  ;
+}
+
+static void
+instantiate ()
+{
+  &foo<0>;
+}
diff --git a/gcc/testsuite/g++.dg/goacc/data-clause-1.C b/gcc/testsuite/g++.dg/goacc/data-clause-1.C
new file mode 100644
index 00000000000..3de3834efae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/goacc/data-clause-1.C
@@ -0,0 +1,122 @@
+/* Test data clause diagnostics.  */
+
+/* See also corresponding OpenACC C/C++ variant: '../../c-c++-common/goacc/data-clause-1.c'.  */
+
+/* See also corresponding OpenACC 'cache' directive variant: 'cache-3-1.C'.  */
+
+/* See also corresponding OpenMP variant: '../gomp/map-1.C'.  */
+
+/* { dg-additional-options "-fopenmp" } for '#pragma omp threadprivate'.  */
+
+extern int a[][10], a2[][10];
+int b[10], c[10][2], d[10], e[10], f[10];
+int b2[10], c2[10][2], d2[10], e2[10], f2[10];
+int k[10], l[10], m[10], n[10], o;
+int *p;
+int **q;
+int r[4][4][4][4][4];
+extern struct s s1;
+extern struct s s2[1]; /* { dg-error "array type has incomplete element type" "" { target c } } */
+int t[10];
+#pragma omp threadprivate (t)
+#pragma acc routine
+void bar (int *);
+
+template <int N>
+void
+foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
+     int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9])
+{
+  #pragma acc parallel copyin(bar[2:5]) /* { dg-error "is not a variable" } */
+    ;
+  #pragma acc parallel copyout(t[2:5]) /* { dg-error "is threadprivate variable" } */
+    ;
+  #pragma acc parallel copy(k[0.5:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyout(l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyin(m[p:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copy(n[:p]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyin(o[2:5]) /* { dg-error "does not have pointer or array type" } */
+    ;
+  #pragma acc parallel create(s1) /* { dg-error "'s1' does not have a mappable type in 'map' clause" } */
+    ;
+  #pragma acc parallel create(s2) /* { dg-error "'s2' does not have a mappable type in 'map' clause" } */
+    ;
+  #pragma acc parallel copyin(a[:][:]) /* { dg-error "array type length expression must be specified" } */
+    bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" "PR97996" { xfail *-*-* } } */
+  #pragma acc parallel copy(b[-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (b);
+  #pragma acc parallel copy(c[:-3][:]) /* { dg-error "negative length in array section" } */
+    bar (&c[0][0]);
+  #pragma acc parallel copyout(d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (d);
+  #pragma acc parallel copyin(e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (e);
+  #pragma acc parallel copyin(f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (f);
+  #pragma acc parallel copyout(g[:][0:10]) /* { dg-error "for pointer type length expression must be specified" } */
+    bar (&g[0][0]);
+  #pragma acc parallel copyout(h[2:1][-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (&h[0][0]);
+  #pragma acc parallel copy(h[:1][:-3]) /* { dg-error "negative length in array section" } */
+    bar (&h[0][0]);
+  #pragma acc parallel copy(i[:1][11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (&i[0][0]);
+  #pragma acc parallel copyout(j[3:1][:10]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc parallel copyin(j[30:1][5:5]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc parallel copyin(a2[:1][2:4])
+    bar (&a2[0][0]);
+  #pragma acc parallel copy(a2[3:5][:])
+    bar (&a2[0][0]);
+  #pragma acc parallel copyin(a2[3:5][:10])
+    bar (&a2[0][0]);
+  #pragma acc parallel copy(b2[0:])
+    bar (b2);
+  #pragma acc parallel copy(c2[:3][:])
+    bar (&c2[0][0]);
+  #pragma acc parallel copyout(d2[9:])
+    bar (d2);
+  #pragma acc parallel copyin(e2[:10])
+    bar (e2);
+  #pragma acc parallel copyin(f2[1:9])
+    bar (f2);
+  #pragma acc parallel copy(g2[:1][2:4])
+    bar (&g2[0][0]);
+  #pragma acc parallel copyout(h2[2:2][0:])
+    bar (&h2[0][0]);
+  #pragma acc parallel copy(h2[:1][:3])
+    bar (&h2[0][0]);
+  #pragma acc parallel copyin(i2[:1][9:])
+    bar (&i2[0][0]);
+  #pragma acc parallel copyout(j2[3:4][:9])
+    bar (&j2[0][0]);
+  #pragma acc parallel copyin(j2[30:1][5:4])
+    bar (&j2[0][0]);
+  #pragma acc parallel copy(q[1:2])
+    ;
+  #pragma acc parallel copy(q[3:5][:10]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2])
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][0:4])
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][1:][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:3][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][1:]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][:3]) /* { dg-error "array section is not contiguous" } */
+    ;
+}
+
+static void
+instantiate ()
+{
+  &foo<0>;
+}
diff --git a/gcc/testsuite/g++.dg/goacc/data-clause-2.C b/gcc/testsuite/g++.dg/goacc/data-clause-2.C
new file mode 100644
index 00000000000..57d1823aede
--- /dev/null
+++ b/gcc/testsuite/g++.dg/goacc/data-clause-2.C
@@ -0,0 +1,56 @@
+/* Test data clause diagnostics.  */
+
+/* See also corresponding OpenACC C/C++ variant: '../../c-c++-common/goacc/data-clause-2.c'.  */
+
+/* See also corresponding OpenACC 'cache' directive variant: 'cache-3-2.C'.  */
+
+/* See also corresponding OpenMP variant: '../gomp/map-2.C'.  */
+
+template <int N>
+void
+foo (int *p, int (*q)[10], int r[10], int s[10][10])
+{
+  int a[10], b[10][10];
+  #pragma acc parallel copy (p[-1:2])
+  ;
+  #pragma acc parallel copy (q[-1:2][0:10])
+  ;
+  #pragma acc parallel copy (q[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (r[-1:2])
+  ;
+  #pragma acc parallel copy (s[-1:2][:])
+  ;
+  #pragma acc parallel copy (s[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (a[-1:2])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (b[-1:2][0:])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (b[1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (p[2:-3])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (q[2:-3][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (q[2:3][0:-1])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (r[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (s[2:-5][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (s[2:5][0:-4])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (a[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (b[2:-5][0:10]) /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (b[2:5][0:-4]) /* { dg-error "negative length in array section in" } */
+  ;
+}
+
+static void
+instantiate ()
+{
+  &foo<0>;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/map-1.C b/gcc/testsuite/g++.dg/gomp/map-1.C
index 107b59ee87a..c314d55a621 100644
--- a/gcc/testsuite/g++.dg/gomp/map-1.C
+++ b/gcc/testsuite/g++.dg/gomp/map-1.C
@@ -1,6 +1,8 @@
 /* Test 'map' clause diagnostics.  */
 
-/* See also corresponding C/C++ variant: '../../c-c++-common/gomp/map-1.c'.  */
+/* See also corresponding OpenMP C/C++ variant: '../../c-c++-common/gomp/map-1.c'.  */
+
+/* See also corresponding OpenACC variant: '../goacc/data-clause-1.C'.  */
 
 extern int a[][10], a2[][10];
 int b[10], c[10][2], d[10], e[10], f[10];
@@ -41,7 +43,7 @@ foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
   #pragma omp target map(alloc: s2) /* { dg-error "'s2' does not have a mappable type in 'map' clause" } */
     ;
   #pragma omp target map(to: a[:][:]) /* { dg-error "array type length expression must be specified" } */
-    bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" "TODO" { xfail *-*-* } } */
+    bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" "PR97996" { xfail *-*-* } } */
   #pragma omp target map(tofrom: b[-1:]) /* { dg-error "negative low bound in array section" } */
     bar (b);
   #pragma omp target map(tofrom: c[:-3][:]) /* { dg-error "negative length in array section" } */
diff --git a/gcc/testsuite/g++.dg/gomp/map-2.C b/gcc/testsuite/g++.dg/gomp/map-2.C
index 10eaaa948b8..bbe26061fe3 100644
--- a/gcc/testsuite/g++.dg/gomp/map-2.C
+++ b/gcc/testsuite/g++.dg/gomp/map-2.C
@@ -1,6 +1,8 @@
 /* Test 'map' clause diagnostics.  */
 
-/* See also corresponding C/C++ variant: '../../c-c++-common/gomp/map-2.c'.  */
+/* See also corresponding OpenMP C/C++ variant: '../../c-c++-common/gomp/map-2.c'.  */
+
+/* See also corresponding OpenACC variant: '../goacc/data-clause-2.C'.  */
 
 template <int N>
 void
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0001-Don-t-create-location-wrapper-nodes-within-OpenAC.g9.patch --]
[-- Type: text/x-diff, Size: 37905 bytes --]

From 25b61f935a8eca56c68c8587fc8915797250bb30 Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Wed, 25 Nov 2020 20:36:55 +0100
Subject: [PATCH] Don't create location wrapper nodes within OpenACC clauses

This fixes a GCC 11, 10, 9 regression introduced by commit
dfd7fdca2ac17d8b823a16700525824ca312ade0 (Subversion r267272) "C++: more
location wrapper nodes (PR c++/43064, PR c++/43486)".  But: this isn't
intending to blame David, because back then, the problem hasn't been visible in
the testsuite (or else I'm sure would've been addressed right away) because of
our all dear friend: missing testsuite coverage.  Thus, for GCC 8, I'm likewise
enhancing the testsuite, without the C++ front end code changes.

I actually had presumed that there may be an issue for OpenACC:
<http://mid.mail-archive.com/874lb9qr2u.fsf@euler.schwinge.homeip.net>, so here
we are, two years (and many "wasted" hours...) later...

	gcc/cp/
	* parser.c (cp_parser_omp_var_list_no_open): Assert that array
	section's 'low_bound', 'length' are not location wrapper nodes.
	(cp_parser_oacc_all_clauses, cp_parser_oacc_cache): Instantiate
	'auto_suppress_location_wrappers'.
	gcc/testsuite/
	* c-c++-common/goacc/cache-3-1.c: New.
	* c-c++-common/goacc/cache-3-2.c: Likewise.
	* c-c++-common/goacc/data-clause-1.c: Likewise.
	* c-c++-common/goacc/data-clause-2.c: Likewise.
	* c-c++-common/gomp/map-1.c: Adjust.
	* c-c++-common/gomp/map-2.c: Likewise.
	* g++.dg/goacc/cache-3-1.C: New.
	* g++.dg/goacc/cache-3-2.C: Likewise.
	* g++.dg/goacc/data-clause-1.C: Likewise.
	* g++.dg/goacc/data-clause-2.C: Likewise.
	* g++.dg/gomp/map-1.C: Adjust.
	* g++.dg/gomp/map-2.C: Likewise.

Reported-by: Sandra Loosemore <sandra@codesourcery.com>
(cherry picked from commit c0c7270cc4efd896fe99f8ad5409dbef089a407f)
---
 gcc/cp/parser.c                               |  19 ++-
 gcc/testsuite/c-c++-common/goacc/cache-3-1.c  | 116 +++++++++++++++++
 gcc/testsuite/c-c++-common/goacc/cache-3-2.c  |  50 +++++++
 .../c-c++-common/goacc/data-clause-1.c        | 115 ++++++++++++++++
 .../c-c++-common/goacc/data-clause-2.c        |  49 +++++++
 gcc/testsuite/c-c++-common/gomp/map-1.c       |   4 +-
 gcc/testsuite/c-c++-common/gomp/map-2.c       |   4 +-
 gcc/testsuite/g++.dg/goacc/cache-3-1.C        | 123 ++++++++++++++++++
 gcc/testsuite/g++.dg/goacc/cache-3-2.C        |  57 ++++++++
 gcc/testsuite/g++.dg/goacc/data-clause-1.C    | 122 +++++++++++++++++
 gcc/testsuite/g++.dg/goacc/data-clause-2.C    |  56 ++++++++
 gcc/testsuite/g++.dg/gomp/map-1.C             |   6 +-
 gcc/testsuite/g++.dg/gomp/map-2.C             |   4 +-
 13 files changed, 718 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/goacc/cache-3-1.c
 create mode 100644 gcc/testsuite/c-c++-common/goacc/cache-3-2.c
 create mode 100644 gcc/testsuite/c-c++-common/goacc/data-clause-1.c
 create mode 100644 gcc/testsuite/c-c++-common/goacc/data-clause-2.c
 create mode 100644 gcc/testsuite/g++.dg/goacc/cache-3-1.C
 create mode 100644 gcc/testsuite/g++.dg/goacc/cache-3-2.C
 create mode 100644 gcc/testsuite/g++.dg/goacc/data-clause-1.C
 create mode 100644 gcc/testsuite/g++.dg/goacc/data-clause-2.C

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index aa64549698f..0a0b80a8388 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -32608,7 +32608,11 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
 		  parser->colon_corrects_to_scope_p = false;
 		  cp_lexer_consume_token (parser->lexer);
 		  if (!cp_lexer_next_token_is (parser->lexer, CPP_COLON))
-		    low_bound = cp_parser_expression (parser);
+		    {
+		      low_bound = cp_parser_expression (parser);
+		      /* Later handling is not prepared to see through these.  */
+		      gcc_checking_assert (!location_wrapper_p (low_bound));
+		    }
 		  if (!colon)
 		    parser->colon_corrects_to_scope_p
 		      = saved_colon_corrects_to_scope_p;
@@ -32628,7 +32632,11 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
 			cp_parser_commit_to_tentative_parse (parser);
 		      if (!cp_lexer_next_token_is (parser->lexer,
 						   CPP_CLOSE_SQUARE))
-			length = cp_parser_expression (parser);
+			{
+			  length = cp_parser_expression (parser);
+			  /* Later handling is not prepared to see through these.  */
+			  gcc_checking_assert (!location_wrapper_p (length));
+			}
 		    }
 		  /* Look for the closing `]'.  */
 		  if (!cp_parser_require (parser, CPP_CLOSE_SQUARE,
@@ -35079,6 +35087,9 @@ cp_parser_oacc_all_clauses (cp_parser *parser, omp_clause_mask mask,
   tree clauses = NULL;
   bool first = true;
 
+  /* Don't create location wrapper nodes within OpenACC clauses.  */
+  auto_suppress_location_wrappers sentinel;
+
   while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL))
     {
       location_t here;
@@ -38760,6 +38771,10 @@ check_clauses:
 static tree
 cp_parser_oacc_cache (cp_parser *parser, cp_token *pragma_tok)
 {
+  /* Don't create location wrapper nodes within 'OMP_CLAUSE__CACHE_'
+     clauses.  */
+  auto_suppress_location_wrappers sentinel;
+
   tree stmt, clauses;
 
   clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE__CACHE_, NULL_TREE);
diff --git a/gcc/testsuite/c-c++-common/goacc/cache-3-1.c b/gcc/testsuite/c-c++-common/goacc/cache-3-1.c
new file mode 100644
index 00000000000..155de689dfa
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/goacc/cache-3-1.c
@@ -0,0 +1,116 @@
+/* Test 'cache' directive diagnostics.  */
+
+/* See also corresponding C++ variant: '../../g++.dg/goacc/cache-3-1.C'.  */
+
+/* See also corresponding C/C++ data clause variant: 'data-clause-1.c'.  */
+
+/* { dg-additional-options "-fopenmp" } for '#pragma omp threadprivate'.  */
+
+/* The current implementation doesn't restrict where a 'cache' directive may
+   appear, so we don't make any special arrangements.  */
+
+extern int a[][10], a2[][10];
+int b[10], c[10][2], d[10], e[10], f[10];
+int b2[10], c2[10][2], d2[10], e2[10], f2[10];
+int k[10], l[10], m[10], n[10], o;
+int *p;
+int **q;
+int r[4][4][4][4][4];
+extern struct s s1;
+extern struct s s2[1]; /* { dg-error "array type has incomplete element type" "" { target c } } */
+int t[10];
+#pragma omp threadprivate (t)
+#pragma acc routine
+void bar (int *);
+
+void
+foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
+     int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9])
+{
+  #pragma acc cache(bar[2:5]) /* { dg-error "is not a variable" } */
+    ;
+  #pragma acc cache(t[2:5]) /* { dg-error "is threadprivate variable" } */
+    ;
+  #pragma acc cache(k[0.5:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(m[p:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(n[:p]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(o[2:5]) /* { dg-error "does not have pointer or array type" } */
+    ;
+  #pragma acc cache(s1) /* { dg-error "expected '\\\['" } */
+    ;
+  #pragma acc cache(s2) /* { dg-error "expected '\\\['" } */
+    ;
+  #pragma acc cache(a[:][:]) /* { dg-error "array type length expression must be specified" } */
+    bar (&a[0][0]); /* { dg-bogus "referenced in target region does not have a mappable type" } */
+  #pragma acc cache(b[-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (b);
+  #pragma acc cache(c[:-3][:]) /* { dg-error "negative length in array section" } */
+    bar (&c[0][0]);
+  #pragma acc cache(d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (d);
+  #pragma acc cache(e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (e);
+  #pragma acc cache(f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (f);
+  #pragma acc cache(g[:][0:10]) /* { dg-error "for pointer type length expression must be specified" } */
+    bar (&g[0][0]);
+  #pragma acc cache(h[2:1][-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (&h[0][0]);
+  #pragma acc cache(h[:1][:-3]) /* { dg-error "negative length in array section" } */
+    bar (&h[0][0]);
+  #pragma acc cache(i[:1][11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (&i[0][0]);
+  #pragma acc cache(j[3:1][:10]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc cache(j[30:1][5:5]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc cache(a2[:1][2:4])
+    bar (&a2[0][0]);
+  #pragma acc cache(a2[3:5][:])
+    bar (&a2[0][0]);
+  #pragma acc cache(a2[3:5][:10])
+    bar (&a2[0][0]);
+  #pragma acc cache(b2[0:])
+    bar (b2);
+  #pragma acc cache(c2[:3][:])
+    bar (&c2[0][0]);
+  #pragma acc cache(d2[9:])
+    bar (d2);
+  #pragma acc cache(e2[:10])
+    bar (e2);
+  #pragma acc cache(f2[1:9])
+    bar (f2);
+  #pragma acc cache(g2[:1][2:4])
+    bar (&g2[0][0]);
+  #pragma acc cache(h2[2:2][0:])
+    bar (&h2[0][0]);
+  #pragma acc cache(h2[:1][:3])
+    bar (&h2[0][0]);
+  #pragma acc cache(i2[:1][9:])
+    bar (&i2[0][0]);
+  #pragma acc cache(j2[3:4][:9])
+    bar (&j2[0][0]);
+  #pragma acc cache(j2[30:1][5:4])
+    bar (&j2[0][0]);
+  #pragma acc cache(q[1:2])
+    ;
+  #pragma acc cache(q[3:5][:10]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2])
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][0:4])
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][1:][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:3][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][1:]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][:3]) /* { dg-error "array section is not contiguous" } */
+    ;
+}
diff --git a/gcc/testsuite/c-c++-common/goacc/cache-3-2.c b/gcc/testsuite/c-c++-common/goacc/cache-3-2.c
new file mode 100644
index 00000000000..ea5222e7d0c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/goacc/cache-3-2.c
@@ -0,0 +1,50 @@
+/* Test 'cache' directive diagnostics.  */
+
+/* See also corresponding C++ variant: '../../g++.dg/goacc/cache-3-2.C'.  */
+
+/* See also corresponding C/C++ data clause variant: 'data-clause-2.c'.  */
+
+/* The current implementation doesn't restrict where a 'cache' directive may
+   appear, so we don't make any special arrangements.  */
+
+void
+foo (int *p, int (*q)[10], int r[10], int s[10][10])
+{
+  int a[10], b[10][10];
+  #pragma acc cache (p[-1:2])
+  ;
+  #pragma acc cache (q[-1:2][0:10])
+  ;
+  #pragma acc cache (q[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (r[-1:2])
+  ;
+  #pragma acc cache (s[-1:2][:])
+  ;
+  #pragma acc cache (s[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (a[-1:2])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (b[-1:2][0:])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (b[1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (p[2:-3])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (q[2:-3][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (q[2:3][0:-1])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (r[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (s[2:-5][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (s[2:5][0:-4])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (a[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (b[2:-5][0:10]) /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (b[2:5][0:-4]) /* { dg-error "negative length in array section in" } */
+  ;
+}
diff --git a/gcc/testsuite/c-c++-common/goacc/data-clause-1.c b/gcc/testsuite/c-c++-common/goacc/data-clause-1.c
new file mode 100644
index 00000000000..20f822cbb99
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/goacc/data-clause-1.c
@@ -0,0 +1,115 @@
+/* Test data clause diagnostics.  */
+
+/* See also corresponding OpenACC C++ variant: '../../g++.dg/goacc/data-clause-1.C'.  */
+
+/* See also corresponding OpenACC 'cache' directive variant: 'cache-3-1.c'.  */
+
+/* See also corresponding OpenMP variant: '../gomp/map-1.c'.  */
+
+/* { dg-additional-options "-fopenmp" } for '#pragma omp threadprivate'.  */
+
+extern int a[][10], a2[][10];
+int b[10], c[10][2], d[10], e[10], f[10];
+int b2[10], c2[10][2], d2[10], e2[10], f2[10];
+int k[10], l[10], m[10], n[10], o;
+int *p;
+int **q;
+int r[4][4][4][4][4];
+extern struct s s1;
+extern struct s s2[1]; /* { dg-error "array type has incomplete element type" "" { target c } } */
+int t[10];
+#pragma omp threadprivate (t)
+#pragma acc routine
+void bar (int *);
+
+void
+foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
+     int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9])
+{
+  #pragma acc parallel copyin(bar[2:5]) /* { dg-error "is not a variable" } */
+    ;
+  #pragma acc parallel copyout(t[2:5]) /* { dg-error "is threadprivate variable" } */
+    ;
+  #pragma acc parallel copy(k[0.5:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyout(l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyin(m[p:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copy(n[:p]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyin(o[2:5]) /* { dg-error "does not have pointer or array type" } */
+    ;
+  #pragma acc parallel create(s1) /* { dg-error "'s1' does not have a mappable type in 'map' clause" } */
+    ;
+  #pragma acc parallel create(s2) /* { dg-error "'s2' does not have a mappable type in 'map' clause" } */
+    ;
+  #pragma acc parallel copyin(a[:][:]) /* { dg-error "array type length expression must be specified" } */
+    bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" } */
+  #pragma acc parallel copy(b[-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (b);
+  #pragma acc parallel copy(c[:-3][:]) /* { dg-error "negative length in array section" } */
+    bar (&c[0][0]);
+  #pragma acc parallel copyout(d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (d);
+  #pragma acc parallel copyin(e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (e);
+  #pragma acc parallel copyin(f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (f);
+  #pragma acc parallel copyout(g[:][0:10]) /* { dg-error "for pointer type length expression must be specified" } */
+    bar (&g[0][0]);
+  #pragma acc parallel copyout(h[2:1][-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (&h[0][0]);
+  #pragma acc parallel copy(h[:1][:-3]) /* { dg-error "negative length in array section" } */
+    bar (&h[0][0]);
+  #pragma acc parallel copy(i[:1][11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (&i[0][0]);
+  #pragma acc parallel copyout(j[3:1][:10]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc parallel copyin(j[30:1][5:5]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc parallel copyin(a2[:1][2:4])
+    bar (&a2[0][0]);
+  #pragma acc parallel copy(a2[3:5][:])
+    bar (&a2[0][0]);
+  #pragma acc parallel copyin(a2[3:5][:10])
+    bar (&a2[0][0]);
+  #pragma acc parallel copy(b2[0:])
+    bar (b2);
+  #pragma acc parallel copy(c2[:3][:])
+    bar (&c2[0][0]);
+  #pragma acc parallel copyout(d2[9:])
+    bar (d2);
+  #pragma acc parallel copyin(e2[:10])
+    bar (e2);
+  #pragma acc parallel copyin(f2[1:9])
+    bar (f2);
+  #pragma acc parallel copy(g2[:1][2:4])
+    bar (&g2[0][0]);
+  #pragma acc parallel copyout(h2[2:2][0:])
+    bar (&h2[0][0]);
+  #pragma acc parallel copy(h2[:1][:3])
+    bar (&h2[0][0]);
+  #pragma acc parallel copyin(i2[:1][9:])
+    bar (&i2[0][0]);
+  #pragma acc parallel copyout(j2[3:4][:9])
+    bar (&j2[0][0]);
+  #pragma acc parallel copyin(j2[30:1][5:4])
+    bar (&j2[0][0]);
+  #pragma acc parallel copy(q[1:2])
+    ;
+  #pragma acc parallel copy(q[3:5][:10]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2])
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][0:4])
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][1:][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:3][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][1:]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][:3]) /* { dg-error "array section is not contiguous" } */
+    ;
+}
diff --git a/gcc/testsuite/c-c++-common/goacc/data-clause-2.c b/gcc/testsuite/c-c++-common/goacc/data-clause-2.c
new file mode 100644
index 00000000000..d4603b016dd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/goacc/data-clause-2.c
@@ -0,0 +1,49 @@
+/* Test data clause diagnostics.  */
+
+/* See also corresponding OpenACC C++ variant: '../../g++.dg/goacc/data-clause-2.C'.  */
+
+/* See also corresponding OpenACC 'cache' directive variant: 'cache-3-2.c'.  */
+
+/* See also corresponding OpenMP variant: '../gomp/map-2.c'.  */
+
+void
+foo (int *p, int (*q)[10], int r[10], int s[10][10])
+{
+  int a[10], b[10][10];
+  #pragma acc parallel copy (p[-1:2])
+  ;
+  #pragma acc parallel copy (q[-1:2][0:10])
+  ;
+  #pragma acc parallel copy (q[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (r[-1:2])
+  ;
+  #pragma acc parallel copy (s[-1:2][:])
+  ;
+  #pragma acc parallel copy (s[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (a[-1:2])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (b[-1:2][0:])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (b[1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (p[2:-3])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (q[2:-3][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (q[2:3][0:-1])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (r[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (s[2:-5][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (s[2:5][0:-4])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (a[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (b[2:-5][0:10]) /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (b[2:5][0:-4]) /* { dg-error "negative length in array section in" } */
+  ;
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/map-1.c b/gcc/testsuite/c-c++-common/gomp/map-1.c
index cd026f1243f..a8549bc49d9 100644
--- a/gcc/testsuite/c-c++-common/gomp/map-1.c
+++ b/gcc/testsuite/c-c++-common/gomp/map-1.c
@@ -1,6 +1,8 @@
 /* Test 'map' clause diagnostics.  */
 
-/* See also corresponding C++ variant: '../../g++.dg/gomp/map-1.C'.  */
+/* See also corresponding OpenMP C++ variant: '../../g++.dg/gomp/map-1.C'.  */
+
+/* See also corresponding OpenACC variant: '../goacc/data-clause-1.c'.  */
 
 extern int a[][10], a2[][10];
 int b[10], c[10][2], d[10], e[10], f[10];
diff --git a/gcc/testsuite/c-c++-common/gomp/map-2.c b/gcc/testsuite/c-c++-common/gomp/map-2.c
index cd69f6b9a57..01fb4be869d 100644
--- a/gcc/testsuite/c-c++-common/gomp/map-2.c
+++ b/gcc/testsuite/c-c++-common/gomp/map-2.c
@@ -1,6 +1,8 @@
 /* Test 'map' clause diagnostics.  */
 
-/* See also corresponding C++ variant: '../../g++.dg/gomp/map-2.C'.  */
+/* See also corresponding OpenMP C++ variant: '../../g++.dg/gomp/map-2.C'.  */
+
+/* See also corresponding OpenACC variant: '../goacc/data-clause-2.c'.  */
 
 void
 foo (int *p, int (*q)[10], int r[10], int s[10][10])
diff --git a/gcc/testsuite/g++.dg/goacc/cache-3-1.C b/gcc/testsuite/g++.dg/goacc/cache-3-1.C
new file mode 100644
index 00000000000..d543db60a9d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/goacc/cache-3-1.C
@@ -0,0 +1,123 @@
+/* Test 'cache' directive diagnostics.  */
+
+/* See also corresponding C/C++ variant: '../../c-c++-common/goacc/cache-3-1.c'.  */
+
+/* See also corresponding C++ data clause variant: 'data-clause-1.C'.  */
+
+/* { dg-additional-options "-fopenmp" } for '#pragma omp threadprivate'.  */
+
+/* The current implementation doesn't restrict where a 'cache' directive may
+   appear, so we don't make any special arrangements.  */
+
+extern int a[][10], a2[][10];
+int b[10], c[10][2], d[10], e[10], f[10];
+int b2[10], c2[10][2], d2[10], e2[10], f2[10];
+int k[10], l[10], m[10], n[10], o;
+int *p;
+int **q;
+int r[4][4][4][4][4];
+extern struct s s1;
+extern struct s s2[1]; /* { dg-error "array type has incomplete element type" "" { target c } } */
+int t[10];
+#pragma omp threadprivate (t)
+#pragma acc routine
+void bar (int *);
+
+template <int N>
+void
+foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
+     int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9])
+{
+  #pragma acc cache(bar[2:5]) /* { dg-error "is not a variable" } */
+    ;
+  #pragma acc cache(t[2:5]) /* { dg-error "is threadprivate variable" } */
+    ;
+  #pragma acc cache(k[0.5:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(m[p:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(n[:p]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(o[2:5]) /* { dg-error "does not have pointer or array type" } */
+    ;
+  #pragma acc cache(s1) /* { dg-error "expected '\\\['" } */
+    ;
+  #pragma acc cache(s2) /* { dg-error "expected '\\\['" } */
+    ;
+  #pragma acc cache(a[:][:]) /* { dg-error "array type length expression must be specified" } */
+    bar (&a[0][0]);
+  #pragma acc cache(b[-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (b);
+  #pragma acc cache(c[:-3][:]) /* { dg-error "negative length in array section" } */
+    bar (&c[0][0]);
+  #pragma acc cache(d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (d);
+  #pragma acc cache(e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (e);
+  #pragma acc cache(f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (f);
+  #pragma acc cache(g[:][0:10]) /* { dg-error "for pointer type length expression must be specified" } */
+    bar (&g[0][0]);
+  #pragma acc cache(h[2:1][-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (&h[0][0]);
+  #pragma acc cache(h[:1][:-3]) /* { dg-error "negative length in array section" } */
+    bar (&h[0][0]);
+  #pragma acc cache(i[:1][11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (&i[0][0]);
+  #pragma acc cache(j[3:1][:10]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc cache(j[30:1][5:5]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc cache(a2[:1][2:4])
+    bar (&a2[0][0]);
+  #pragma acc cache(a2[3:5][:])
+    bar (&a2[0][0]);
+  #pragma acc cache(a2[3:5][:10])
+    bar (&a2[0][0]);
+  #pragma acc cache(b2[0:])
+    bar (b2);
+  #pragma acc cache(c2[:3][:])
+    bar (&c2[0][0]);
+  #pragma acc cache(d2[9:])
+    bar (d2);
+  #pragma acc cache(e2[:10])
+    bar (e2);
+  #pragma acc cache(f2[1:9])
+    bar (f2);
+  #pragma acc cache(g2[:1][2:4])
+    bar (&g2[0][0]);
+  #pragma acc cache(h2[2:2][0:])
+    bar (&h2[0][0]);
+  #pragma acc cache(h2[:1][:3])
+    bar (&h2[0][0]);
+  #pragma acc cache(i2[:1][9:])
+    bar (&i2[0][0]);
+  #pragma acc cache(j2[3:4][:9])
+    bar (&j2[0][0]);
+  #pragma acc cache(j2[30:1][5:4])
+    bar (&j2[0][0]);
+  #pragma acc cache(q[1:2])
+    ;
+  #pragma acc cache(q[3:5][:10]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2])
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][0:4])
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][1:][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:3][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][1:]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][:3]) /* { dg-error "array section is not contiguous" } */
+    ;
+}
+
+static void
+instantiate ()
+{
+  &foo<0>;
+}
diff --git a/gcc/testsuite/g++.dg/goacc/cache-3-2.C b/gcc/testsuite/g++.dg/goacc/cache-3-2.C
new file mode 100644
index 00000000000..5561e176a56
--- /dev/null
+++ b/gcc/testsuite/g++.dg/goacc/cache-3-2.C
@@ -0,0 +1,57 @@
+/* Test 'cache' directive diagnostics.  */
+
+/* See also corresponding C/C++ variant: '../../c-c++-common/goacc/cache-3-2.c'.  */
+
+/* See also corresponding C++ data clause variant: 'data-clause-2.C'.  */
+
+/* The current implementation doesn't restrict where a 'cache' directive may
+   appear, so we don't make any special arrangements.  */
+
+template <int N>
+void
+foo (int *p, int (*q)[10], int r[10], int s[10][10])
+{
+  int a[10], b[10][10];
+  #pragma acc cache (p[-1:2])
+  ;
+  #pragma acc cache (q[-1:2][0:10])
+  ;
+  #pragma acc cache (q[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (r[-1:2])
+  ;
+  #pragma acc cache (s[-1:2][:])
+  ;
+  #pragma acc cache (s[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (a[-1:2])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (b[-1:2][0:])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (b[1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (p[2:-3])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (q[2:-3][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (q[2:3][0:-1])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (r[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (s[2:-5][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (s[2:5][0:-4])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (a[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (b[2:-5][0:10]) /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (b[2:5][0:-4]) /* { dg-error "negative length in array section in" } */
+  ;
+}
+
+static void
+instantiate ()
+{
+  &foo<0>;
+}
diff --git a/gcc/testsuite/g++.dg/goacc/data-clause-1.C b/gcc/testsuite/g++.dg/goacc/data-clause-1.C
new file mode 100644
index 00000000000..3de3834efae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/goacc/data-clause-1.C
@@ -0,0 +1,122 @@
+/* Test data clause diagnostics.  */
+
+/* See also corresponding OpenACC C/C++ variant: '../../c-c++-common/goacc/data-clause-1.c'.  */
+
+/* See also corresponding OpenACC 'cache' directive variant: 'cache-3-1.C'.  */
+
+/* See also corresponding OpenMP variant: '../gomp/map-1.C'.  */
+
+/* { dg-additional-options "-fopenmp" } for '#pragma omp threadprivate'.  */
+
+extern int a[][10], a2[][10];
+int b[10], c[10][2], d[10], e[10], f[10];
+int b2[10], c2[10][2], d2[10], e2[10], f2[10];
+int k[10], l[10], m[10], n[10], o;
+int *p;
+int **q;
+int r[4][4][4][4][4];
+extern struct s s1;
+extern struct s s2[1]; /* { dg-error "array type has incomplete element type" "" { target c } } */
+int t[10];
+#pragma omp threadprivate (t)
+#pragma acc routine
+void bar (int *);
+
+template <int N>
+void
+foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
+     int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9])
+{
+  #pragma acc parallel copyin(bar[2:5]) /* { dg-error "is not a variable" } */
+    ;
+  #pragma acc parallel copyout(t[2:5]) /* { dg-error "is threadprivate variable" } */
+    ;
+  #pragma acc parallel copy(k[0.5:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyout(l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyin(m[p:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copy(n[:p]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyin(o[2:5]) /* { dg-error "does not have pointer or array type" } */
+    ;
+  #pragma acc parallel create(s1) /* { dg-error "'s1' does not have a mappable type in 'map' clause" } */
+    ;
+  #pragma acc parallel create(s2) /* { dg-error "'s2' does not have a mappable type in 'map' clause" } */
+    ;
+  #pragma acc parallel copyin(a[:][:]) /* { dg-error "array type length expression must be specified" } */
+    bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" "PR97996" { xfail *-*-* } } */
+  #pragma acc parallel copy(b[-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (b);
+  #pragma acc parallel copy(c[:-3][:]) /* { dg-error "negative length in array section" } */
+    bar (&c[0][0]);
+  #pragma acc parallel copyout(d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (d);
+  #pragma acc parallel copyin(e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (e);
+  #pragma acc parallel copyin(f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (f);
+  #pragma acc parallel copyout(g[:][0:10]) /* { dg-error "for pointer type length expression must be specified" } */
+    bar (&g[0][0]);
+  #pragma acc parallel copyout(h[2:1][-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (&h[0][0]);
+  #pragma acc parallel copy(h[:1][:-3]) /* { dg-error "negative length in array section" } */
+    bar (&h[0][0]);
+  #pragma acc parallel copy(i[:1][11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (&i[0][0]);
+  #pragma acc parallel copyout(j[3:1][:10]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc parallel copyin(j[30:1][5:5]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc parallel copyin(a2[:1][2:4])
+    bar (&a2[0][0]);
+  #pragma acc parallel copy(a2[3:5][:])
+    bar (&a2[0][0]);
+  #pragma acc parallel copyin(a2[3:5][:10])
+    bar (&a2[0][0]);
+  #pragma acc parallel copy(b2[0:])
+    bar (b2);
+  #pragma acc parallel copy(c2[:3][:])
+    bar (&c2[0][0]);
+  #pragma acc parallel copyout(d2[9:])
+    bar (d2);
+  #pragma acc parallel copyin(e2[:10])
+    bar (e2);
+  #pragma acc parallel copyin(f2[1:9])
+    bar (f2);
+  #pragma acc parallel copy(g2[:1][2:4])
+    bar (&g2[0][0]);
+  #pragma acc parallel copyout(h2[2:2][0:])
+    bar (&h2[0][0]);
+  #pragma acc parallel copy(h2[:1][:3])
+    bar (&h2[0][0]);
+  #pragma acc parallel copyin(i2[:1][9:])
+    bar (&i2[0][0]);
+  #pragma acc parallel copyout(j2[3:4][:9])
+    bar (&j2[0][0]);
+  #pragma acc parallel copyin(j2[30:1][5:4])
+    bar (&j2[0][0]);
+  #pragma acc parallel copy(q[1:2])
+    ;
+  #pragma acc parallel copy(q[3:5][:10]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2])
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][0:4])
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][1:][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:3][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][1:]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][:3]) /* { dg-error "array section is not contiguous" } */
+    ;
+}
+
+static void
+instantiate ()
+{
+  &foo<0>;
+}
diff --git a/gcc/testsuite/g++.dg/goacc/data-clause-2.C b/gcc/testsuite/g++.dg/goacc/data-clause-2.C
new file mode 100644
index 00000000000..57d1823aede
--- /dev/null
+++ b/gcc/testsuite/g++.dg/goacc/data-clause-2.C
@@ -0,0 +1,56 @@
+/* Test data clause diagnostics.  */
+
+/* See also corresponding OpenACC C/C++ variant: '../../c-c++-common/goacc/data-clause-2.c'.  */
+
+/* See also corresponding OpenACC 'cache' directive variant: 'cache-3-2.C'.  */
+
+/* See also corresponding OpenMP variant: '../gomp/map-2.C'.  */
+
+template <int N>
+void
+foo (int *p, int (*q)[10], int r[10], int s[10][10])
+{
+  int a[10], b[10][10];
+  #pragma acc parallel copy (p[-1:2])
+  ;
+  #pragma acc parallel copy (q[-1:2][0:10])
+  ;
+  #pragma acc parallel copy (q[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (r[-1:2])
+  ;
+  #pragma acc parallel copy (s[-1:2][:])
+  ;
+  #pragma acc parallel copy (s[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (a[-1:2])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (b[-1:2][0:])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (b[1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (p[2:-3])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (q[2:-3][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (q[2:3][0:-1])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (r[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (s[2:-5][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (s[2:5][0:-4])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (a[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (b[2:-5][0:10]) /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (b[2:5][0:-4]) /* { dg-error "negative length in array section in" } */
+  ;
+}
+
+static void
+instantiate ()
+{
+  &foo<0>;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/map-1.C b/gcc/testsuite/g++.dg/gomp/map-1.C
index 107b59ee87a..c314d55a621 100644
--- a/gcc/testsuite/g++.dg/gomp/map-1.C
+++ b/gcc/testsuite/g++.dg/gomp/map-1.C
@@ -1,6 +1,8 @@
 /* Test 'map' clause diagnostics.  */
 
-/* See also corresponding C/C++ variant: '../../c-c++-common/gomp/map-1.c'.  */
+/* See also corresponding OpenMP C/C++ variant: '../../c-c++-common/gomp/map-1.c'.  */
+
+/* See also corresponding OpenACC variant: '../goacc/data-clause-1.C'.  */
 
 extern int a[][10], a2[][10];
 int b[10], c[10][2], d[10], e[10], f[10];
@@ -41,7 +43,7 @@ foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
   #pragma omp target map(alloc: s2) /* { dg-error "'s2' does not have a mappable type in 'map' clause" } */
     ;
   #pragma omp target map(to: a[:][:]) /* { dg-error "array type length expression must be specified" } */
-    bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" "TODO" { xfail *-*-* } } */
+    bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" "PR97996" { xfail *-*-* } } */
   #pragma omp target map(tofrom: b[-1:]) /* { dg-error "negative low bound in array section" } */
     bar (b);
   #pragma omp target map(tofrom: c[:-3][:]) /* { dg-error "negative length in array section" } */
diff --git a/gcc/testsuite/g++.dg/gomp/map-2.C b/gcc/testsuite/g++.dg/gomp/map-2.C
index 10eaaa948b8..bbe26061fe3 100644
--- a/gcc/testsuite/g++.dg/gomp/map-2.C
+++ b/gcc/testsuite/g++.dg/gomp/map-2.C
@@ -1,6 +1,8 @@
 /* Test 'map' clause diagnostics.  */
 
-/* See also corresponding C/C++ variant: '../../c-c++-common/gomp/map-2.c'.  */
+/* See also corresponding OpenMP C/C++ variant: '../../c-c++-common/gomp/map-2.c'.  */
+
+/* See also corresponding OpenACC variant: '../goacc/data-clause-2.C'.  */
 
 template <int N>
 void
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: 0001-Don-t-create-location-wrapper-nodes-within-OpenAC.g8.patch --]
[-- Type: text/x-diff, Size: 35639 bytes --]

From 23ec71d91e3044108a557dace573d3e60ff1c07e Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Wed, 25 Nov 2020 20:36:55 +0100
Subject: [PATCH] Don't create location wrapper nodes within OpenACC clauses
 (testsuite changes only)

This fixes a GCC 11, 10, 9 regression introduced by commit
dfd7fdca2ac17d8b823a16700525824ca312ade0 (Subversion r267272) "C++: more
location wrapper nodes (PR c++/43064, PR c++/43486)".  But: this isn't
intending to blame David, because back then, the problem hasn't been visible in
the testsuite (or else I'm sure would've been addressed right away) because of
our all dear friend: missing testsuite coverage.  Thus, for GCC 8, I'm likewise
enhancing the testsuite, without the C++ front end code changes.

I actually had presumed that there may be an issue for OpenACC:
<http://mid.mail-archive.com/874lb9qr2u.fsf@euler.schwinge.homeip.net>, so here
we are, two years (and many "wasted" hours...) later...

	gcc/testsuite/
	* c-c++-common/goacc/cache-3-1.c: New.
	* c-c++-common/goacc/cache-3-2.c: Likewise.
	* c-c++-common/goacc/data-clause-1.c: Likewise.
	* c-c++-common/goacc/data-clause-2.c: Likewise.
	* c-c++-common/gomp/map-1.c: Adjust.
	* c-c++-common/gomp/map-2.c: Likewise.
	* g++.dg/goacc/cache-3-1.C: New.
	* g++.dg/goacc/cache-3-2.C: Likewise.
	* g++.dg/goacc/data-clause-1.C: Likewise.
	* g++.dg/goacc/data-clause-2.C: Likewise.
	* g++.dg/gomp/map-1.C: Adjust.
	* g++.dg/gomp/map-2.C: Likewise.

Reported-by: Sandra Loosemore <sandra@codesourcery.com>
(cherry picked from commit c0c7270cc4efd896fe99f8ad5409dbef089a407f (testsuite changes only))
---
 gcc/testsuite/c-c++-common/goacc/cache-3-1.c  | 116 +++++++++++++++++
 gcc/testsuite/c-c++-common/goacc/cache-3-2.c  |  50 +++++++
 .../c-c++-common/goacc/data-clause-1.c        | 115 ++++++++++++++++
 .../c-c++-common/goacc/data-clause-2.c        |  49 +++++++
 gcc/testsuite/c-c++-common/gomp/map-1.c       |   4 +-
 gcc/testsuite/c-c++-common/gomp/map-2.c       |   4 +-
 gcc/testsuite/g++.dg/goacc/cache-3-1.C        | 123 ++++++++++++++++++
 gcc/testsuite/g++.dg/goacc/cache-3-2.C        |  57 ++++++++
 gcc/testsuite/g++.dg/goacc/data-clause-1.C    | 122 +++++++++++++++++
 gcc/testsuite/g++.dg/goacc/data-clause-2.C    |  56 ++++++++
 gcc/testsuite/g++.dg/gomp/map-1.C             |   6 +-
 gcc/testsuite/g++.dg/gomp/map-2.C             |   4 +-
 12 files changed, 701 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/goacc/cache-3-1.c
 create mode 100644 gcc/testsuite/c-c++-common/goacc/cache-3-2.c
 create mode 100644 gcc/testsuite/c-c++-common/goacc/data-clause-1.c
 create mode 100644 gcc/testsuite/c-c++-common/goacc/data-clause-2.c
 create mode 100644 gcc/testsuite/g++.dg/goacc/cache-3-1.C
 create mode 100644 gcc/testsuite/g++.dg/goacc/cache-3-2.C
 create mode 100644 gcc/testsuite/g++.dg/goacc/data-clause-1.C
 create mode 100644 gcc/testsuite/g++.dg/goacc/data-clause-2.C

diff --git a/gcc/testsuite/c-c++-common/goacc/cache-3-1.c b/gcc/testsuite/c-c++-common/goacc/cache-3-1.c
new file mode 100644
index 00000000000..155de689dfa
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/goacc/cache-3-1.c
@@ -0,0 +1,116 @@
+/* Test 'cache' directive diagnostics.  */
+
+/* See also corresponding C++ variant: '../../g++.dg/goacc/cache-3-1.C'.  */
+
+/* See also corresponding C/C++ data clause variant: 'data-clause-1.c'.  */
+
+/* { dg-additional-options "-fopenmp" } for '#pragma omp threadprivate'.  */
+
+/* The current implementation doesn't restrict where a 'cache' directive may
+   appear, so we don't make any special arrangements.  */
+
+extern int a[][10], a2[][10];
+int b[10], c[10][2], d[10], e[10], f[10];
+int b2[10], c2[10][2], d2[10], e2[10], f2[10];
+int k[10], l[10], m[10], n[10], o;
+int *p;
+int **q;
+int r[4][4][4][4][4];
+extern struct s s1;
+extern struct s s2[1]; /* { dg-error "array type has incomplete element type" "" { target c } } */
+int t[10];
+#pragma omp threadprivate (t)
+#pragma acc routine
+void bar (int *);
+
+void
+foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
+     int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9])
+{
+  #pragma acc cache(bar[2:5]) /* { dg-error "is not a variable" } */
+    ;
+  #pragma acc cache(t[2:5]) /* { dg-error "is threadprivate variable" } */
+    ;
+  #pragma acc cache(k[0.5:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(m[p:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(n[:p]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(o[2:5]) /* { dg-error "does not have pointer or array type" } */
+    ;
+  #pragma acc cache(s1) /* { dg-error "expected '\\\['" } */
+    ;
+  #pragma acc cache(s2) /* { dg-error "expected '\\\['" } */
+    ;
+  #pragma acc cache(a[:][:]) /* { dg-error "array type length expression must be specified" } */
+    bar (&a[0][0]); /* { dg-bogus "referenced in target region does not have a mappable type" } */
+  #pragma acc cache(b[-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (b);
+  #pragma acc cache(c[:-3][:]) /* { dg-error "negative length in array section" } */
+    bar (&c[0][0]);
+  #pragma acc cache(d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (d);
+  #pragma acc cache(e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (e);
+  #pragma acc cache(f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (f);
+  #pragma acc cache(g[:][0:10]) /* { dg-error "for pointer type length expression must be specified" } */
+    bar (&g[0][0]);
+  #pragma acc cache(h[2:1][-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (&h[0][0]);
+  #pragma acc cache(h[:1][:-3]) /* { dg-error "negative length in array section" } */
+    bar (&h[0][0]);
+  #pragma acc cache(i[:1][11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (&i[0][0]);
+  #pragma acc cache(j[3:1][:10]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc cache(j[30:1][5:5]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc cache(a2[:1][2:4])
+    bar (&a2[0][0]);
+  #pragma acc cache(a2[3:5][:])
+    bar (&a2[0][0]);
+  #pragma acc cache(a2[3:5][:10])
+    bar (&a2[0][0]);
+  #pragma acc cache(b2[0:])
+    bar (b2);
+  #pragma acc cache(c2[:3][:])
+    bar (&c2[0][0]);
+  #pragma acc cache(d2[9:])
+    bar (d2);
+  #pragma acc cache(e2[:10])
+    bar (e2);
+  #pragma acc cache(f2[1:9])
+    bar (f2);
+  #pragma acc cache(g2[:1][2:4])
+    bar (&g2[0][0]);
+  #pragma acc cache(h2[2:2][0:])
+    bar (&h2[0][0]);
+  #pragma acc cache(h2[:1][:3])
+    bar (&h2[0][0]);
+  #pragma acc cache(i2[:1][9:])
+    bar (&i2[0][0]);
+  #pragma acc cache(j2[3:4][:9])
+    bar (&j2[0][0]);
+  #pragma acc cache(j2[30:1][5:4])
+    bar (&j2[0][0]);
+  #pragma acc cache(q[1:2])
+    ;
+  #pragma acc cache(q[3:5][:10]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2])
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][0:4])
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][1:][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:3][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][1:]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][:3]) /* { dg-error "array section is not contiguous" } */
+    ;
+}
diff --git a/gcc/testsuite/c-c++-common/goacc/cache-3-2.c b/gcc/testsuite/c-c++-common/goacc/cache-3-2.c
new file mode 100644
index 00000000000..ea5222e7d0c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/goacc/cache-3-2.c
@@ -0,0 +1,50 @@
+/* Test 'cache' directive diagnostics.  */
+
+/* See also corresponding C++ variant: '../../g++.dg/goacc/cache-3-2.C'.  */
+
+/* See also corresponding C/C++ data clause variant: 'data-clause-2.c'.  */
+
+/* The current implementation doesn't restrict where a 'cache' directive may
+   appear, so we don't make any special arrangements.  */
+
+void
+foo (int *p, int (*q)[10], int r[10], int s[10][10])
+{
+  int a[10], b[10][10];
+  #pragma acc cache (p[-1:2])
+  ;
+  #pragma acc cache (q[-1:2][0:10])
+  ;
+  #pragma acc cache (q[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (r[-1:2])
+  ;
+  #pragma acc cache (s[-1:2][:])
+  ;
+  #pragma acc cache (s[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (a[-1:2])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (b[-1:2][0:])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (b[1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (p[2:-3])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (q[2:-3][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (q[2:3][0:-1])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (r[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (s[2:-5][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (s[2:5][0:-4])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (a[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (b[2:-5][0:10]) /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (b[2:5][0:-4]) /* { dg-error "negative length in array section in" } */
+  ;
+}
diff --git a/gcc/testsuite/c-c++-common/goacc/data-clause-1.c b/gcc/testsuite/c-c++-common/goacc/data-clause-1.c
new file mode 100644
index 00000000000..20f822cbb99
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/goacc/data-clause-1.c
@@ -0,0 +1,115 @@
+/* Test data clause diagnostics.  */
+
+/* See also corresponding OpenACC C++ variant: '../../g++.dg/goacc/data-clause-1.C'.  */
+
+/* See also corresponding OpenACC 'cache' directive variant: 'cache-3-1.c'.  */
+
+/* See also corresponding OpenMP variant: '../gomp/map-1.c'.  */
+
+/* { dg-additional-options "-fopenmp" } for '#pragma omp threadprivate'.  */
+
+extern int a[][10], a2[][10];
+int b[10], c[10][2], d[10], e[10], f[10];
+int b2[10], c2[10][2], d2[10], e2[10], f2[10];
+int k[10], l[10], m[10], n[10], o;
+int *p;
+int **q;
+int r[4][4][4][4][4];
+extern struct s s1;
+extern struct s s2[1]; /* { dg-error "array type has incomplete element type" "" { target c } } */
+int t[10];
+#pragma omp threadprivate (t)
+#pragma acc routine
+void bar (int *);
+
+void
+foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
+     int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9])
+{
+  #pragma acc parallel copyin(bar[2:5]) /* { dg-error "is not a variable" } */
+    ;
+  #pragma acc parallel copyout(t[2:5]) /* { dg-error "is threadprivate variable" } */
+    ;
+  #pragma acc parallel copy(k[0.5:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyout(l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyin(m[p:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copy(n[:p]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyin(o[2:5]) /* { dg-error "does not have pointer or array type" } */
+    ;
+  #pragma acc parallel create(s1) /* { dg-error "'s1' does not have a mappable type in 'map' clause" } */
+    ;
+  #pragma acc parallel create(s2) /* { dg-error "'s2' does not have a mappable type in 'map' clause" } */
+    ;
+  #pragma acc parallel copyin(a[:][:]) /* { dg-error "array type length expression must be specified" } */
+    bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" } */
+  #pragma acc parallel copy(b[-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (b);
+  #pragma acc parallel copy(c[:-3][:]) /* { dg-error "negative length in array section" } */
+    bar (&c[0][0]);
+  #pragma acc parallel copyout(d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (d);
+  #pragma acc parallel copyin(e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (e);
+  #pragma acc parallel copyin(f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (f);
+  #pragma acc parallel copyout(g[:][0:10]) /* { dg-error "for pointer type length expression must be specified" } */
+    bar (&g[0][0]);
+  #pragma acc parallel copyout(h[2:1][-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (&h[0][0]);
+  #pragma acc parallel copy(h[:1][:-3]) /* { dg-error "negative length in array section" } */
+    bar (&h[0][0]);
+  #pragma acc parallel copy(i[:1][11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (&i[0][0]);
+  #pragma acc parallel copyout(j[3:1][:10]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc parallel copyin(j[30:1][5:5]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc parallel copyin(a2[:1][2:4])
+    bar (&a2[0][0]);
+  #pragma acc parallel copy(a2[3:5][:])
+    bar (&a2[0][0]);
+  #pragma acc parallel copyin(a2[3:5][:10])
+    bar (&a2[0][0]);
+  #pragma acc parallel copy(b2[0:])
+    bar (b2);
+  #pragma acc parallel copy(c2[:3][:])
+    bar (&c2[0][0]);
+  #pragma acc parallel copyout(d2[9:])
+    bar (d2);
+  #pragma acc parallel copyin(e2[:10])
+    bar (e2);
+  #pragma acc parallel copyin(f2[1:9])
+    bar (f2);
+  #pragma acc parallel copy(g2[:1][2:4])
+    bar (&g2[0][0]);
+  #pragma acc parallel copyout(h2[2:2][0:])
+    bar (&h2[0][0]);
+  #pragma acc parallel copy(h2[:1][:3])
+    bar (&h2[0][0]);
+  #pragma acc parallel copyin(i2[:1][9:])
+    bar (&i2[0][0]);
+  #pragma acc parallel copyout(j2[3:4][:9])
+    bar (&j2[0][0]);
+  #pragma acc parallel copyin(j2[30:1][5:4])
+    bar (&j2[0][0]);
+  #pragma acc parallel copy(q[1:2])
+    ;
+  #pragma acc parallel copy(q[3:5][:10]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2])
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][0:4])
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][1:][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:3][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][1:]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][:3]) /* { dg-error "array section is not contiguous" } */
+    ;
+}
diff --git a/gcc/testsuite/c-c++-common/goacc/data-clause-2.c b/gcc/testsuite/c-c++-common/goacc/data-clause-2.c
new file mode 100644
index 00000000000..d4603b016dd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/goacc/data-clause-2.c
@@ -0,0 +1,49 @@
+/* Test data clause diagnostics.  */
+
+/* See also corresponding OpenACC C++ variant: '../../g++.dg/goacc/data-clause-2.C'.  */
+
+/* See also corresponding OpenACC 'cache' directive variant: 'cache-3-2.c'.  */
+
+/* See also corresponding OpenMP variant: '../gomp/map-2.c'.  */
+
+void
+foo (int *p, int (*q)[10], int r[10], int s[10][10])
+{
+  int a[10], b[10][10];
+  #pragma acc parallel copy (p[-1:2])
+  ;
+  #pragma acc parallel copy (q[-1:2][0:10])
+  ;
+  #pragma acc parallel copy (q[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (r[-1:2])
+  ;
+  #pragma acc parallel copy (s[-1:2][:])
+  ;
+  #pragma acc parallel copy (s[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (a[-1:2])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (b[-1:2][0:])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (b[1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (p[2:-3])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (q[2:-3][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (q[2:3][0:-1])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (r[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (s[2:-5][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (s[2:5][0:-4])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (a[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (b[2:-5][0:10]) /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (b[2:5][0:-4]) /* { dg-error "negative length in array section in" } */
+  ;
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/map-1.c b/gcc/testsuite/c-c++-common/gomp/map-1.c
index cd026f1243f..a8549bc49d9 100644
--- a/gcc/testsuite/c-c++-common/gomp/map-1.c
+++ b/gcc/testsuite/c-c++-common/gomp/map-1.c
@@ -1,6 +1,8 @@
 /* Test 'map' clause diagnostics.  */
 
-/* See also corresponding C++ variant: '../../g++.dg/gomp/map-1.C'.  */
+/* See also corresponding OpenMP C++ variant: '../../g++.dg/gomp/map-1.C'.  */
+
+/* See also corresponding OpenACC variant: '../goacc/data-clause-1.c'.  */
 
 extern int a[][10], a2[][10];
 int b[10], c[10][2], d[10], e[10], f[10];
diff --git a/gcc/testsuite/c-c++-common/gomp/map-2.c b/gcc/testsuite/c-c++-common/gomp/map-2.c
index cd69f6b9a57..01fb4be869d 100644
--- a/gcc/testsuite/c-c++-common/gomp/map-2.c
+++ b/gcc/testsuite/c-c++-common/gomp/map-2.c
@@ -1,6 +1,8 @@
 /* Test 'map' clause diagnostics.  */
 
-/* See also corresponding C++ variant: '../../g++.dg/gomp/map-2.C'.  */
+/* See also corresponding OpenMP C++ variant: '../../g++.dg/gomp/map-2.C'.  */
+
+/* See also corresponding OpenACC variant: '../goacc/data-clause-2.c'.  */
 
 void
 foo (int *p, int (*q)[10], int r[10], int s[10][10])
diff --git a/gcc/testsuite/g++.dg/goacc/cache-3-1.C b/gcc/testsuite/g++.dg/goacc/cache-3-1.C
new file mode 100644
index 00000000000..d543db60a9d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/goacc/cache-3-1.C
@@ -0,0 +1,123 @@
+/* Test 'cache' directive diagnostics.  */
+
+/* See also corresponding C/C++ variant: '../../c-c++-common/goacc/cache-3-1.c'.  */
+
+/* See also corresponding C++ data clause variant: 'data-clause-1.C'.  */
+
+/* { dg-additional-options "-fopenmp" } for '#pragma omp threadprivate'.  */
+
+/* The current implementation doesn't restrict where a 'cache' directive may
+   appear, so we don't make any special arrangements.  */
+
+extern int a[][10], a2[][10];
+int b[10], c[10][2], d[10], e[10], f[10];
+int b2[10], c2[10][2], d2[10], e2[10], f2[10];
+int k[10], l[10], m[10], n[10], o;
+int *p;
+int **q;
+int r[4][4][4][4][4];
+extern struct s s1;
+extern struct s s2[1]; /* { dg-error "array type has incomplete element type" "" { target c } } */
+int t[10];
+#pragma omp threadprivate (t)
+#pragma acc routine
+void bar (int *);
+
+template <int N>
+void
+foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
+     int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9])
+{
+  #pragma acc cache(bar[2:5]) /* { dg-error "is not a variable" } */
+    ;
+  #pragma acc cache(t[2:5]) /* { dg-error "is threadprivate variable" } */
+    ;
+  #pragma acc cache(k[0.5:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(m[p:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(n[:p]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc cache(o[2:5]) /* { dg-error "does not have pointer or array type" } */
+    ;
+  #pragma acc cache(s1) /* { dg-error "expected '\\\['" } */
+    ;
+  #pragma acc cache(s2) /* { dg-error "expected '\\\['" } */
+    ;
+  #pragma acc cache(a[:][:]) /* { dg-error "array type length expression must be specified" } */
+    bar (&a[0][0]);
+  #pragma acc cache(b[-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (b);
+  #pragma acc cache(c[:-3][:]) /* { dg-error "negative length in array section" } */
+    bar (&c[0][0]);
+  #pragma acc cache(d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (d);
+  #pragma acc cache(e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (e);
+  #pragma acc cache(f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (f);
+  #pragma acc cache(g[:][0:10]) /* { dg-error "for pointer type length expression must be specified" } */
+    bar (&g[0][0]);
+  #pragma acc cache(h[2:1][-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (&h[0][0]);
+  #pragma acc cache(h[:1][:-3]) /* { dg-error "negative length in array section" } */
+    bar (&h[0][0]);
+  #pragma acc cache(i[:1][11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (&i[0][0]);
+  #pragma acc cache(j[3:1][:10]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc cache(j[30:1][5:5]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc cache(a2[:1][2:4])
+    bar (&a2[0][0]);
+  #pragma acc cache(a2[3:5][:])
+    bar (&a2[0][0]);
+  #pragma acc cache(a2[3:5][:10])
+    bar (&a2[0][0]);
+  #pragma acc cache(b2[0:])
+    bar (b2);
+  #pragma acc cache(c2[:3][:])
+    bar (&c2[0][0]);
+  #pragma acc cache(d2[9:])
+    bar (d2);
+  #pragma acc cache(e2[:10])
+    bar (e2);
+  #pragma acc cache(f2[1:9])
+    bar (f2);
+  #pragma acc cache(g2[:1][2:4])
+    bar (&g2[0][0]);
+  #pragma acc cache(h2[2:2][0:])
+    bar (&h2[0][0]);
+  #pragma acc cache(h2[:1][:3])
+    bar (&h2[0][0]);
+  #pragma acc cache(i2[:1][9:])
+    bar (&i2[0][0]);
+  #pragma acc cache(j2[3:4][:9])
+    bar (&j2[0][0]);
+  #pragma acc cache(j2[30:1][5:4])
+    bar (&j2[0][0]);
+  #pragma acc cache(q[1:2])
+    ;
+  #pragma acc cache(q[3:5][:10]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2])
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][0:4])
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][1:][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:3][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][1:]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc cache(r[3:][2:1][1:2][:][:3]) /* { dg-error "array section is not contiguous" } */
+    ;
+}
+
+static void
+instantiate ()
+{
+  &foo<0>;
+}
diff --git a/gcc/testsuite/g++.dg/goacc/cache-3-2.C b/gcc/testsuite/g++.dg/goacc/cache-3-2.C
new file mode 100644
index 00000000000..5561e176a56
--- /dev/null
+++ b/gcc/testsuite/g++.dg/goacc/cache-3-2.C
@@ -0,0 +1,57 @@
+/* Test 'cache' directive diagnostics.  */
+
+/* See also corresponding C/C++ variant: '../../c-c++-common/goacc/cache-3-2.c'.  */
+
+/* See also corresponding C++ data clause variant: 'data-clause-2.C'.  */
+
+/* The current implementation doesn't restrict where a 'cache' directive may
+   appear, so we don't make any special arrangements.  */
+
+template <int N>
+void
+foo (int *p, int (*q)[10], int r[10], int s[10][10])
+{
+  int a[10], b[10][10];
+  #pragma acc cache (p[-1:2])
+  ;
+  #pragma acc cache (q[-1:2][0:10])
+  ;
+  #pragma acc cache (q[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (r[-1:2])
+  ;
+  #pragma acc cache (s[-1:2][:])
+  ;
+  #pragma acc cache (s[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (a[-1:2])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (b[-1:2][0:])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (b[1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc cache (p[2:-3])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (q[2:-3][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (q[2:3][0:-1])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (r[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (s[2:-5][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (s[2:5][0:-4])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (a[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (b[2:-5][0:10]) /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc cache (b[2:5][0:-4]) /* { dg-error "negative length in array section in" } */
+  ;
+}
+
+static void
+instantiate ()
+{
+  &foo<0>;
+}
diff --git a/gcc/testsuite/g++.dg/goacc/data-clause-1.C b/gcc/testsuite/g++.dg/goacc/data-clause-1.C
new file mode 100644
index 00000000000..3de3834efae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/goacc/data-clause-1.C
@@ -0,0 +1,122 @@
+/* Test data clause diagnostics.  */
+
+/* See also corresponding OpenACC C/C++ variant: '../../c-c++-common/goacc/data-clause-1.c'.  */
+
+/* See also corresponding OpenACC 'cache' directive variant: 'cache-3-1.C'.  */
+
+/* See also corresponding OpenMP variant: '../gomp/map-1.C'.  */
+
+/* { dg-additional-options "-fopenmp" } for '#pragma omp threadprivate'.  */
+
+extern int a[][10], a2[][10];
+int b[10], c[10][2], d[10], e[10], f[10];
+int b2[10], c2[10][2], d2[10], e2[10], f2[10];
+int k[10], l[10], m[10], n[10], o;
+int *p;
+int **q;
+int r[4][4][4][4][4];
+extern struct s s1;
+extern struct s s2[1]; /* { dg-error "array type has incomplete element type" "" { target c } } */
+int t[10];
+#pragma omp threadprivate (t)
+#pragma acc routine
+void bar (int *);
+
+template <int N>
+void
+foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
+     int g2[3][10], int h2[4][8], int i2[2][10], int j2[][9])
+{
+  #pragma acc parallel copyin(bar[2:5]) /* { dg-error "is not a variable" } */
+    ;
+  #pragma acc parallel copyout(t[2:5]) /* { dg-error "is threadprivate variable" } */
+    ;
+  #pragma acc parallel copy(k[0.5:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyout(l[:7.5f]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyin(m[p:]) /* { dg-error "low bound \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copy(n[:p]) /* { dg-error "length \[^\n\r]* of array section does not have integral type" } */
+    ;
+  #pragma acc parallel copyin(o[2:5]) /* { dg-error "does not have pointer or array type" } */
+    ;
+  #pragma acc parallel create(s1) /* { dg-error "'s1' does not have a mappable type in 'map' clause" } */
+    ;
+  #pragma acc parallel create(s2) /* { dg-error "'s2' does not have a mappable type in 'map' clause" } */
+    ;
+  #pragma acc parallel copyin(a[:][:]) /* { dg-error "array type length expression must be specified" } */
+    bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" "PR97996" { xfail *-*-* } } */
+  #pragma acc parallel copy(b[-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (b);
+  #pragma acc parallel copy(c[:-3][:]) /* { dg-error "negative length in array section" } */
+    bar (&c[0][0]);
+  #pragma acc parallel copyout(d[11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (d);
+  #pragma acc parallel copyin(e[:11]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (e);
+  #pragma acc parallel copyin(f[1:10]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (f);
+  #pragma acc parallel copyout(g[:][0:10]) /* { dg-error "for pointer type length expression must be specified" } */
+    bar (&g[0][0]);
+  #pragma acc parallel copyout(h[2:1][-1:]) /* { dg-error "negative low bound in array section" } */
+    bar (&h[0][0]);
+  #pragma acc parallel copy(h[:1][:-3]) /* { dg-error "negative length in array section" } */
+    bar (&h[0][0]);
+  #pragma acc parallel copy(i[:1][11:]) /* { dg-error "low bound \[^\n\r]* above array section size" } */
+    bar (&i[0][0]);
+  #pragma acc parallel copyout(j[3:1][:10]) /* { dg-error "length \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc parallel copyin(j[30:1][5:5]) /* { dg-error "high bound \[^\n\r]* above array section size" } */
+    bar (&j[0][0]);
+  #pragma acc parallel copyin(a2[:1][2:4])
+    bar (&a2[0][0]);
+  #pragma acc parallel copy(a2[3:5][:])
+    bar (&a2[0][0]);
+  #pragma acc parallel copyin(a2[3:5][:10])
+    bar (&a2[0][0]);
+  #pragma acc parallel copy(b2[0:])
+    bar (b2);
+  #pragma acc parallel copy(c2[:3][:])
+    bar (&c2[0][0]);
+  #pragma acc parallel copyout(d2[9:])
+    bar (d2);
+  #pragma acc parallel copyin(e2[:10])
+    bar (e2);
+  #pragma acc parallel copyin(f2[1:9])
+    bar (f2);
+  #pragma acc parallel copy(g2[:1][2:4])
+    bar (&g2[0][0]);
+  #pragma acc parallel copyout(h2[2:2][0:])
+    bar (&h2[0][0]);
+  #pragma acc parallel copy(h2[:1][:3])
+    bar (&h2[0][0]);
+  #pragma acc parallel copyin(i2[:1][9:])
+    bar (&i2[0][0]);
+  #pragma acc parallel copyout(j2[3:4][:9])
+    bar (&j2[0][0]);
+  #pragma acc parallel copyin(j2[30:1][5:4])
+    bar (&j2[0][0]);
+  #pragma acc parallel copy(q[1:2])
+    ;
+  #pragma acc parallel copy(q[3:5][:10]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2])
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][0:4])
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][1:][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:3][0:4]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][1:]) /* { dg-error "array section is not contiguous" } */
+    ;
+  #pragma acc parallel copy(r[3:][2:1][1:2][:][:3]) /* { dg-error "array section is not contiguous" } */
+    ;
+}
+
+static void
+instantiate ()
+{
+  &foo<0>;
+}
diff --git a/gcc/testsuite/g++.dg/goacc/data-clause-2.C b/gcc/testsuite/g++.dg/goacc/data-clause-2.C
new file mode 100644
index 00000000000..57d1823aede
--- /dev/null
+++ b/gcc/testsuite/g++.dg/goacc/data-clause-2.C
@@ -0,0 +1,56 @@
+/* Test data clause diagnostics.  */
+
+/* See also corresponding OpenACC C/C++ variant: '../../c-c++-common/goacc/data-clause-2.c'.  */
+
+/* See also corresponding OpenACC 'cache' directive variant: 'cache-3-2.C'.  */
+
+/* See also corresponding OpenMP variant: '../gomp/map-2.C'.  */
+
+template <int N>
+void
+foo (int *p, int (*q)[10], int r[10], int s[10][10])
+{
+  int a[10], b[10][10];
+  #pragma acc parallel copy (p[-1:2])
+  ;
+  #pragma acc parallel copy (q[-1:2][0:10])
+  ;
+  #pragma acc parallel copy (q[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (r[-1:2])
+  ;
+  #pragma acc parallel copy (s[-1:2][:])
+  ;
+  #pragma acc parallel copy (s[-1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (a[-1:2])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (b[-1:2][0:])	 /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (b[1:2][-2:10]) /* { dg-error "negative low bound in array section in" } */
+  ;
+  #pragma acc parallel copy (p[2:-3])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (q[2:-3][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (q[2:3][0:-1])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (r[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (s[2:-5][:])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (s[2:5][0:-4])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (a[2:-5])	 /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (b[2:-5][0:10]) /* { dg-error "negative length in array section in" } */
+  ;
+  #pragma acc parallel copy (b[2:5][0:-4]) /* { dg-error "negative length in array section in" } */
+  ;
+}
+
+static void
+instantiate ()
+{
+  &foo<0>;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/map-1.C b/gcc/testsuite/g++.dg/gomp/map-1.C
index 107b59ee87a..c314d55a621 100644
--- a/gcc/testsuite/g++.dg/gomp/map-1.C
+++ b/gcc/testsuite/g++.dg/gomp/map-1.C
@@ -1,6 +1,8 @@
 /* Test 'map' clause diagnostics.  */
 
-/* See also corresponding C/C++ variant: '../../c-c++-common/gomp/map-1.c'.  */
+/* See also corresponding OpenMP C/C++ variant: '../../c-c++-common/gomp/map-1.c'.  */
+
+/* See also corresponding OpenACC variant: '../goacc/data-clause-1.C'.  */
 
 extern int a[][10], a2[][10];
 int b[10], c[10][2], d[10], e[10], f[10];
@@ -41,7 +43,7 @@ foo (int g[3][10], int h[4][8], int i[2][10], int j[][9],
   #pragma omp target map(alloc: s2) /* { dg-error "'s2' does not have a mappable type in 'map' clause" } */
     ;
   #pragma omp target map(to: a[:][:]) /* { dg-error "array type length expression must be specified" } */
-    bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" "TODO" { xfail *-*-* } } */
+    bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" "PR97996" { xfail *-*-* } } */
   #pragma omp target map(tofrom: b[-1:]) /* { dg-error "negative low bound in array section" } */
     bar (b);
   #pragma omp target map(tofrom: c[:-3][:]) /* { dg-error "negative length in array section" } */
diff --git a/gcc/testsuite/g++.dg/gomp/map-2.C b/gcc/testsuite/g++.dg/gomp/map-2.C
index 10eaaa948b8..bbe26061fe3 100644
--- a/gcc/testsuite/g++.dg/gomp/map-2.C
+++ b/gcc/testsuite/g++.dg/gomp/map-2.C
@@ -1,6 +1,8 @@
 /* Test 'map' clause diagnostics.  */
 
-/* See also corresponding C/C++ variant: '../../c-c++-common/gomp/map-2.c'.  */
+/* See also corresponding OpenMP C/C++ variant: '../../c-c++-common/gomp/map-2.c'.  */
+
+/* See also corresponding OpenACC variant: '../goacc/data-clause-2.C'.  */
 
 template <int N>
 void
-- 
2.17.1


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: Don't create location wrapper nodes within OpenACC clauses (was: [WIP] Fold 'NON_LVALUE_EXPR' some more (was: C++ 'NON_LVALUE_EXPR' in OMP array section handling))
  2020-11-26  9:36               ` Don't create location wrapper nodes within OpenACC clauses (was: [WIP] Fold 'NON_LVALUE_EXPR' some more (was: C++ 'NON_LVALUE_EXPR' in OMP array section handling)) Thomas Schwinge
@ 2020-11-26 10:02                 ` Jakub Jelinek
  0 siblings, 0 replies; 34+ messages in thread
From: Jakub Jelinek @ 2020-11-26 10:02 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: gcc-patches, Sandra Loosemore, David Malcolm

On Thu, Nov 26, 2020 at 10:36:43AM +0100, Thomas Schwinge wrote:
> So, I understand, 'NON_LVALUE_EXPR's are primarily a C/C++ (only?) front
> end construct to wrap nodes that must not be used as a lvalue (per the
> programming language standards); rejecting code like 'int x; &(x + 0);',
> I suppose.

The NON_LVALUE_EXPRs serve two purposes, one is indeed to indicate something
is not an lvalue, even when its operand is, and another is holding location
info (I think currently only in the C++ FE), so that diagnostics can report
correct locations even for e.g. constants or uses of variables.
So, it is undesirable to avoid adding those location wrappers, but instead
when we want to look at the value of the expression we should be using
appropriate APIs (e.g. for_fold_warn, or maybe_constant_value).
And generally, cp_fold_function should be also stripping them away from
everything.

	Jakub


^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2020-11-26 10:02 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-05 19:44 [PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486) David Malcolm
2018-11-05 19:44 ` [PATCH 2/2] C++: improvements to binary operator diagnostics (PR c++/87504) David Malcolm
2018-11-19 16:51 ` [PING] Re: [PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486) David Malcolm
2018-12-03 22:10   ` Jeff Law
2018-12-04 15:20     ` David Malcolm
2018-12-04 21:48     ` [PATCH 1/2] v2: " David Malcolm
2018-12-04 21:48       ` [PATCH 2/2] v2: C++: improvements to binary operator diagnostics (PR c++/87504) David Malcolm
2018-12-11 19:52         ` PING " David Malcolm
2018-12-12 20:43         ` Jason Merrill
2018-12-19 23:28           ` Aaron Sawdey
2018-12-20  2:13             ` [PATCH] -Wtautological-compare: fix comparison of macro expansions David Malcolm
2018-12-20 14:29               ` David Malcolm
2018-12-20 23:35                 ` Aaron Sawdey
2018-12-04 23:31     ` [PING] Re: [PATCH 1/2] C++: more location wrapper nodes (PR c++/43064, PR c++/43486) Jason Merrill
2018-12-07 19:25       ` [PATCH 1/2] v3: " David Malcolm
2018-12-12 20:37         ` Jason Merrill
2018-12-13 19:24           ` [PATCH] v4: " David Malcolm
2018-12-13 20:38             ` Jason Merrill
2018-12-14 23:29               ` [PATCH] v5: " David Malcolm
2018-12-17 19:33                 ` Jason Merrill
2018-12-17 23:30                   ` David Malcolm
2018-12-18 20:23                     ` Jason Merrill
2018-12-18 20:34                     ` [PATCH] v6: " David Malcolm
2018-12-18 20:40                       ` Jason Merrill
2018-12-19 15:35                         ` David Malcolm
2018-12-19 19:01 ` [PATCH 1/2] " Thomas Schwinge
2018-12-20  2:29   ` David Malcolm
2020-03-26  5:02   ` [PATCH, OpenACC] Bug fix for processing OpenACC data clauses in C++ Sandra Loosemore
     [not found]     ` <4a68ec90-456a-cf49-036e-471ba275706c@codesourcery.com>
2020-03-26 14:27       ` C++ 'NON_LVALUE_EXPR' in OMP array section handling (was: [PATCH, OpenACC] Bug fix for processing OpenACC data clauses in C++) Thomas Schwinge
2020-03-26 15:09         ` C++ 'NON_LVALUE_EXPR' in OMP array section handling Sandra Loosemore
2020-03-26 20:53           ` Thomas Schwinge
2020-05-25 10:56             ` [WIP] Fold 'NON_LVALUE_EXPR' some more (was: C++ 'NON_LVALUE_EXPR' in OMP array section handling) Thomas Schwinge
2020-11-26  9:36               ` Don't create location wrapper nodes within OpenACC clauses (was: [WIP] Fold 'NON_LVALUE_EXPR' some more (was: C++ 'NON_LVALUE_EXPR' in OMP array section handling)) Thomas Schwinge
2020-11-26 10:02                 ` Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).