From 1b4455d00e16f22a0210a48c68cdd5f0e1f146a8 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 23 Nov 2015 12:24:26 -0500
Subject: [PATCH 10/35] FIXME: start adding LOCATION_EXPR

---
 gcc/cp/constexpr.c                                 |  4 +++
 gcc/cp/cp-gimplify.c                               |  7 ++++
 gcc/cp/cp-objcp-common.c                           |  2 ++
 gcc/cp/cp-tree.def                                 |  6 ++++
 gcc/cp/cp-tree.h                                   | 10 ++++--
 gcc/cp/parser.c                                    | 39 +++++++++++-----------
 gcc/cp/tree.c                                      |  4 +--
 .../diagnostic_plugin_test_tree_expression_range.c |  2 ++
 8 files changed, 50 insertions(+), 24 deletions(-)

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 459173d..9e4da1d 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -3563,6 +3563,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case VIEW_CONVERT_EXPR:
     case NOP_EXPR:
     case UNARY_PLUS_EXPR:
+    case LOCATION_EXPR:
       {
 	enum tree_code tcode = TREE_CODE (t);
 	tree oldop = TREE_OPERAND (t, 0);
@@ -4753,6 +4754,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
     case EMPTY_CLASS_EXPR:
       return false;
 
+    case LOCATION_EXPR:
+      return RECUR (TREE_OPERAND (t, 0), want_rval);
+
     default:
       if (objc_is_property_ref (t))
 	return false;
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index 99d0cfb..84fd1b7 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -1356,6 +1356,13 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
 	   || TREE_CODE (stmt) == OMP_DISTRIBUTE
 	   || TREE_CODE (stmt) == OMP_TASKLOOP)
     genericize_omp_for_stmt (stmt_p, walk_subtrees, data);
+  else if (TREE_CODE (stmt) == LOCATION_EXPR)
+    {
+      //inform (EXPR_LOCATION (stmt), "would genericize");
+      *stmt_p = TREE_OPERAND (stmt, 0);
+      /* *stmt_p has changed, tail recurse to handle it again.  */
+      return cp_genericize_r (stmt_p, walk_subtrees, data);
+    }
   else if ((flag_sanitize
 	    & (SANITIZE_NULL | SANITIZE_ALIGNMENT | SANITIZE_VPTR))
 	   && !wtd->no_sanitize_p)
diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c
index 2758252..412957f 100644
--- a/gcc/cp/cp-objcp-common.c
+++ b/gcc/cp/cp-objcp-common.c
@@ -306,6 +306,8 @@ cp_common_init_ts (void)
   MARK_TS_TYPED (UNARY_RIGHT_FOLD_EXPR);
   MARK_TS_TYPED (BINARY_LEFT_FOLD_EXPR);
   MARK_TS_TYPED (BINARY_RIGHT_FOLD_EXPR);
+
+  MARK_TS_TYPED (LOCATION_EXPR);
 }
 
 #include "gt-cp-cp-objcp-common.h"
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 7df72c5..20e6b11 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -582,6 +582,12 @@ DEFTREECODE (PARM_CONSTR, "parm_constr", tcc_expression, 2)
 DEFTREECODE (CONJ_CONSTR, "conj_constr", tcc_expression, 2)
 DEFTREECODE (DISJ_CONSTR, "disj_constr", tcc_expression, 2)
 
+/* Wrapper used by the C++ frontend during parsing to add a source code
+   location to an expression, either one that doesn't have one (such as
+   an INTEGER_CST), or to a usage of a variable (e.g. PARAM_DECL or
+   VAR_DECL), where we want to record the site in the source where the
+   variable was *used* rather than where it was declared.  */
+DEFTREECODE (LOCATION_EXPR, "location_expr", tcc_unary, 1)
 
 /*
 Local variables:
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 30002dd..4482112 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -256,6 +256,13 @@ c-common.h, not after.
 #define THUNK_FUNCTION_CHECK(NODE) (NODE)
 #endif
 
+/* Language-dependent macro for stripping away location wrapper nodes.  */
+
+#define STRIP_LOCATION_EXPRS(EXP) \
+  while (TREE_CODE (EXP) == LOCATION_EXPR) \
+    (EXP) = TREE_OPERAND ((EXP), 0)
+
+
 /* Language-dependent contents of an identifier.  */
 
 struct GTY(()) lang_identifier {
@@ -271,8 +278,7 @@ struct GTY(()) lang_identifier {
 inline lang_identifier*
 identifier_p (tree t)
 {
-  if (TREE_CODE (t) == NOP_EXPR)
-    t = TREE_OPERAND (t, 0);
+  STRIP_LOCATION_EXPRS (t);
   if (TREE_CODE (t) == IDENTIFIER_NODE)
     return (lang_identifier*) t;
   return NULL;
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 845f315..0cfca35 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1414,8 +1414,7 @@ make_id_declarator (tree qualifying_scope, tree unqualified_name,
   if (qualifying_scope && TYPE_P (qualifying_scope))
     qualifying_scope = TYPE_MAIN_VARIANT (qualifying_scope);
 
-  if (TREE_CODE (unqualified_name) == NOP_EXPR)
-    unqualified_name = TREE_OPERAND (unqualified_name, 0);
+  STRIP_LOCATION_EXPRS (unqualified_name);
 
   gcc_assert (identifier_p (unqualified_name)
 	      || TREE_CODE (unqualified_name) == BIT_NOT_EXPR
@@ -3670,18 +3669,14 @@ cp_parser_pop_lexer (cp_parser *parser)
 
 /* FIXME.  */
 static tree
-use_as_lvalue (tree value, location_t loc)
+wrap_with_location (tree value, location_t loc)
 {
-  tree wrapper = build1_loc (loc, VIEW_CONVERT_EXPR, TREE_TYPE (value), value);
+#if 1
+  tree wrapper = build1_loc (loc, LOCATION_EXPR, TREE_TYPE (value), value);
   return wrapper;
-}
-
-/* FIXME.  */
-static tree
-use_as_rvalue (tree value, location_t loc)
-{
-  tree nop = build1_loc (loc, NOP_EXPR, TREE_TYPE (value), value);
-  return nop;
+#else
+  return value;
+#endif
 }
 
 /* Lexical conventions [gram.lex]  */
@@ -3898,7 +3893,7 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
   if (count > 1)
     obstack_free (&str_ob, 0);
 
-  return use_as_lvalue (value, loc);
+  return wrap_with_location (value, loc);
 }
 
 /* Look up a literal operator with the name and the exact arguments.  */
@@ -4647,7 +4642,7 @@ cp_parser_primary_expression (cp_parser *parser,
 	  if (!cast_p)
 	    cp_parser_non_integral_constant_expression (parser, NIC_FLOAT);
 	}
-      return use_as_rvalue (token->u.value, token->location);
+      return wrap_with_location (token->u.value, token->location);
 
     case CPP_CHAR_USERDEF:
     case CPP_CHAR16_USERDEF:
@@ -4799,20 +4794,20 @@ cp_parser_primary_expression (cp_parser *parser,
 	  /* These two are the boolean literals.  */
 	case RID_TRUE:
 	  cp_lexer_consume_token (parser->lexer);
-	  return use_as_rvalue (boolean_true_node, token->location);
+	  return wrap_with_location (boolean_true_node, token->location);
 	case RID_FALSE:
 	  cp_lexer_consume_token (parser->lexer);
-	  return use_as_rvalue (boolean_false_node, token->location);
+	  return wrap_with_location (boolean_false_node, token->location);
 
 	  /* The `__null' literal.  */
 	case RID_NULL:
 	  cp_lexer_consume_token (parser->lexer);
-	  return use_as_rvalue (null_node, token->location);
+	  return wrap_with_location (null_node, token->location);
 
 	  /* The `nullptr' literal.  */
 	case RID_NULLPTR:
 	  cp_lexer_consume_token (parser->lexer);
-	  return use_as_rvalue (nullptr_node, token->location);
+	  return wrap_with_location (nullptr_node, token->location);
 
 	  /* Recognize the `this' keyword.  */
 	case RID_THIS:
@@ -20832,6 +20827,7 @@ cp_parser_class_name (cp_parser *parser,
     }
 
   decl = cp_parser_maybe_treat_template_as_class (decl, class_head_p);
+  STRIP_LOCATION_EXPRS (decl);
 
   /* If this is a typename, create a TYPENAME_TYPE.  */
   if (typename_p && decl != error_mark_node)
@@ -24453,7 +24449,12 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
 
   maybe_record_typedef_use (decl);
 
-  return use_as_rvalue (decl, name_location);
+  if (TREE_CODE (decl) == TYPE_DECL)
+    /* We don't want to wrap DECL_TYPE with a LOCATION_EXPR, as this
+       confuses cp_parser_new_placement.  */
+    return decl;
+  else
+    return wrap_with_location (decl, name_location);
 }
 
 /* Like cp_parser_lookup_name, but for use in the typical case where
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 3f60b24..92eb511 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -56,9 +56,7 @@ lvalue_kind (const_tree ref)
   cp_lvalue_kind op1_lvalue_kind = clk_none;
   cp_lvalue_kind op2_lvalue_kind = clk_none;
 
-  /* FIXME.  */
-  if (TREE_CODE (ref) == VIEW_CONVERT_EXPR)
-    ref = TREE_OPERAND (ref, 0);
+  STRIP_LOCATION_EXPRS (ref);
 
   /* Expressions of reference type are sometimes wrapped in
      INDIRECT_REFs.  INDIRECT_REFs are just internal compiler
diff --git a/gcc/testsuite/g++.dg/plugin/diagnostic_plugin_test_tree_expression_range.c b/gcc/testsuite/g++.dg/plugin/diagnostic_plugin_test_tree_expression_range.c
index 3f8821d..0e98702 100644
--- a/gcc/testsuite/g++.dg/plugin/diagnostic_plugin_test_tree_expression_range.c
+++ b/gcc/testsuite/g++.dg/plugin/diagnostic_plugin_test_tree_expression_range.c
@@ -8,6 +8,7 @@
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
+#include "cp/cp-tree.h"
 #include "stringpool.h"
 #include "toplev.h"
 #include "basic-block.h"
@@ -57,6 +58,7 @@ cb_walk_tree_fn (tree * tp, int * walk_subtrees,
   if (TREE_CODE (fn) != ADDR_EXPR)
     return NULL_TREE;
   fn = TREE_OPERAND (fn, 0);
+  STRIP_LOCATION_EXPRS (fn);
   if (TREE_CODE (fn) != FUNCTION_DECL)
     return NULL_TREE;
   if (strcmp (IDENTIFIER_POINTER (DECL_NAME (fn)), "__emit_expression_range"))
-- 
1.8.5.3

