From f9b55dbf6cded314625d474764858d9bd142ac02 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 3 Nov 2015 10:46:10 -0500
Subject: [PATCH 20/27] FIXME: more WIP on C++ expr ranges

---
 gcc/cp/cp-tree.h                                   |  55 +++-
 gcc/cp/parser.c                                    | 280 +++++++++++----------
 gcc/cp/semantics.c                                 |   4 +-
 gcc/cp/typeck.c                                    |   2 +-
 .../g++.dg/plugin/diagnostic-test-expressions-1.c  |  12 +
 gcc/tree.c                                         |  22 +-
 gcc/tree.h                                         |   5 +-
 7 files changed, 227 insertions(+), 153 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f650c76..895d89c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5440,6 +5440,59 @@ extern cp_parameter_declarator *no_parameters;
 /* True if we saw "#pragma GCC java_exceptions".  */
 extern bool pragma_java_exceptions;
 
+/* A tree node, together with a location, so that we can track locations
+   (and ranges) during parsing.
+
+   The location is redundant for node kinds that have locations,
+   but not all node kinds do (e.g. constants, and references to
+   params, locals, etc), so we stash a copy here.  */
+
+class cp_expr
+{
+public:
+  cp_expr () :
+    m_value (NULL), m_loc (UNKNOWN_LOCATION) {}
+
+  cp_expr (tree value) :
+    m_value (value), m_loc (EXPR_LOCATION (m_value)) {}
+
+  cp_expr (tree value, location_t loc):
+    m_value (value), m_loc (loc) {}
+
+  cp_expr (const cp_expr &other) :
+    m_value (other.m_value), m_loc (other.m_loc) {}
+
+  /* FIXME: should we use ctors, or have explicit conversion? */
+  static cp_expr build (tree value, location_t loc) { return cp_expr (value, loc); }
+  static cp_expr build (tree value) { return cp_expr (value); }
+
+  /* Implicit conversion to tree.  */
+  operator tree () const { return m_value; }
+
+  tree get_value () const { return m_value; }
+  location_t get_location () const { return EXPR_LOCATION (m_value); }
+  location_t get_start () const
+  {
+    source_range src_range = get_range_from_loc (line_table, m_loc);
+    return src_range.m_start;
+  }
+  location_t get_finish () const
+  {
+    source_range src_range = get_range_from_loc (line_table, m_loc);
+    return src_range.m_finish;
+  }
+
+ private:
+  tree m_value;
+  location_t m_loc;
+};
+
+inline bool
+operator == (const cp_expr &lhs, tree rhs)
+{
+  return lhs.get_value () == rhs;
+}
+
 /* in call.c */
 extern bool check_dtor_name			(tree, tree);
 bool magic_varargs_p                            (tree);
@@ -6272,7 +6325,7 @@ extern tree finish_base_specifier		(tree, tree, bool);
 extern void finish_member_declaration		(tree);
 extern bool outer_automatic_var_p		(tree);
 extern tree process_outer_var_ref		(tree, tsubst_flags_t);
-extern tree finish_id_expression		(tree, tree, tree,
+extern cp_expr finish_id_expression		(tree, tree, tree,
 						 cp_id_kind *,
 						 bool, bool, bool *,
 						 bool, bool, bool, bool,
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 4e119ad..6d0a471 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1782,9 +1782,12 @@ struct cp_parser_binary_operations_map_node
 
 struct cp_parser_expression_stack_entry
 {
+  cp_parser_expression_stack_entry ()
+    : lhs (NULL) {}
+
   /* Left hand side of the binary operation we are currently
      parsing.  */
-  tree lhs;
+  cp_expr lhs;
   /* Original tree code for left hand side, if it was a binary
      expression itself (used for -Wparentheses).  */
   enum tree_code lhs_type;
@@ -1794,8 +1797,6 @@ struct cp_parser_expression_stack_entry
   enum cp_parser_prec prec;
   /* Location of the binary operation we are parsing.  */
   location_t loc;
-  /* FIXME.  */
-  source_range src_range;
 };
 
 /* The stack for storing partial expressions.  We only need NUM_PREC_VALUES
@@ -1940,15 +1941,15 @@ static cp_parser *cp_parser_new
 
 /* Lexical conventions [gram.lex]  */
 
-static tree cp_parser_identifier
+static cp_expr cp_parser_identifier
   (cp_parser *);
-static tree cp_parser_string_literal
+static cp_expr cp_parser_string_literal
   (cp_parser *, bool, bool, bool);
-static tree cp_parser_userdef_char_literal
+static cp_expr cp_parser_userdef_char_literal
   (cp_parser *);
 static tree cp_parser_userdef_string_literal
   (tree);
-static tree cp_parser_userdef_numeric_literal
+static cp_expr cp_parser_userdef_numeric_literal
   (cp_parser *);
 
 /* Basic concepts [gram.basic]  */
@@ -1958,11 +1959,11 @@ static bool cp_parser_translation_unit
 
 /* Expressions [gram.expr]  */
 
-static tree cp_parser_primary_expression
+static cp_expr cp_parser_primary_expression
   (cp_parser *, bool, bool, bool, cp_id_kind *);
-static tree cp_parser_id_expression
+static cp_expr cp_parser_id_expression
   (cp_parser *, bool, bool, bool *, bool, bool);
-static tree cp_parser_unqualified_id
+static cp_expr cp_parser_unqualified_id
   (cp_parser *, bool, bool, bool, bool);
 static tree cp_parser_nested_name_specifier_opt
   (cp_parser *, bool, bool, bool, bool);
@@ -1970,7 +1971,7 @@ static tree cp_parser_nested_name_specifier
   (cp_parser *, bool, bool, bool, bool);
 static tree cp_parser_qualifying_entity
   (cp_parser *, bool, bool, bool, bool, bool);
-static tree cp_parser_postfix_expression
+static cp_expr cp_parser_postfix_expression
   (cp_parser *, bool, bool, bool, bool, cp_id_kind *);
 static tree cp_parser_postfix_open_square_expression
   (cp_parser *, tree, bool, bool);
@@ -1982,7 +1983,7 @@ static vec<tree, va_gc> *cp_parser_parenthesized_expression_list
 enum { non_attr = 0, normal_attr = 1, id_attr = 2 };
 static void cp_parser_pseudo_destructor_name
   (cp_parser *, tree, tree *, tree *);
-static tree cp_parser_unary_expression
+static cp_expr cp_parser_unary_expression
   (cp_parser *, cp_id_kind * = NULL, bool = false, bool = false, bool = false);
 static enum tree_code cp_parser_unary_operator
   (cp_token *);
@@ -2000,7 +2001,7 @@ static vec<tree, va_gc> *cp_parser_new_initializer
   (cp_parser *);
 static tree cp_parser_delete_expression
   (cp_parser *);
-static tree cp_parser_cast_expression
+static cp_expr cp_parser_cast_expression
   (cp_parser *, bool, bool, bool, cp_id_kind *);
 static tree cp_parser_binary_expression
   (cp_parser *, bool, bool, enum cp_parser_prec, cp_id_kind *);
@@ -2010,13 +2011,13 @@ static tree cp_parser_assignment_expression
   (cp_parser *, cp_id_kind * = NULL, bool = false, bool = false);
 static enum tree_code cp_parser_assignment_operator_opt
   (cp_parser *);
-static tree cp_parser_expression
+static cp_expr cp_parser_expression
   (cp_parser *, cp_id_kind * = NULL, bool = false, bool = false);
 static tree cp_parser_constant_expression
   (cp_parser *, bool = false, bool * = NULL);
 static tree cp_parser_builtin_offsetof
   (cp_parser *);
-static tree cp_parser_lambda_expression
+static cp_expr cp_parser_lambda_expression
   (cp_parser *);
 static void cp_parser_lambda_introducer
   (cp_parser *, tree);
@@ -2412,7 +2413,7 @@ static tree cp_parser_objc_struct_declaration
 
 /* Utility Routines */
 
-static tree cp_parser_lookup_name
+static cp_expr cp_parser_lookup_name
   (cp_parser *, tree, enum tag_types, bool, bool, bool, tree *, location_t);
 static tree cp_parser_lookup_name_simple
   (cp_parser *, tree, location_t);
@@ -2422,7 +2423,7 @@ static bool cp_parser_check_declarator_template_parameters
   (cp_parser *, cp_declarator *, location_t);
 static bool cp_parser_check_template_parameters
   (cp_parser *, unsigned, location_t, cp_declarator *);
-static tree cp_parser_simple_cast_expression
+static cp_expr cp_parser_simple_cast_expression
   (cp_parser *);
 static tree cp_parser_global_scope_opt
   (cp_parser *, bool);
@@ -3157,7 +3158,7 @@ cp_parser_parse_and_diagnose_invalid_type_name (cp_parser *parser)
 				/*check_dependency_p=*/true,
 				/*template_p=*/NULL,
 				/*declarator_p=*/true,
-				/*optional_p=*/false);
+				/*optional_p=*/false).get_value ();
   /* If the next token is a (, this is a function with no explicit return
      type, i.e. constructor, destructor or conversion op.  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)
@@ -3668,7 +3669,7 @@ cp_parser_pop_lexer (cp_parser *parser)
 /* Parse an identifier.  Returns an IDENTIFIER_NODE representing the
    identifier.  */
 
-static tree
+static cp_expr
 cp_parser_identifier (cp_parser* parser)
 {
   cp_token *token;
@@ -3676,7 +3677,10 @@ cp_parser_identifier (cp_parser* parser)
   /* Look for the identifier.  */
   token = cp_parser_require (parser, CPP_NAME, RT_NAME);
   /* Return the value.  */
-  return token ? token->u.value : error_mark_node;
+  if (token)
+    return cp_expr::build (token->u.value, token->location);
+  else
+    return cp_expr::build (error_mark_node);
 }
 
 /* Parse a sequence of adjacent string constants.  Returns a
@@ -3693,7 +3697,7 @@ cp_parser_identifier (cp_parser* parser)
    This code is largely lifted from lex_string() in c-lex.c.
 
    FUTURE: ObjC++ will need to handle @-strings here.  */
-static tree
+static cp_expr
 cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
 			  bool lookup_udlit = true)
 {
@@ -3712,7 +3716,7 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
   if (!cp_parser_is_string_literal (tok))
     {
       cp_parser_error (parser, "expected string-literal");
-      return error_mark_node;
+      return cp_expr::build (error_mark_node);
     }
 
   if (cpp_userdef_string_p (tok->type))
@@ -3863,7 +3867,7 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
   if (count > 1)
     obstack_free (&str_ob, 0);
 
-  return value;
+  return cp_expr::build (value);
 }
 
 /* Look up a literal operator with the name and the exact arguments.  */
@@ -3914,7 +3918,7 @@ lookup_literal_operator (tree name, vec<tree, va_gc> *args)
 /* Parse a user-defined char constant.  Returns a call to a user-defined
    literal operator taking the character as an argument.  */
 
-static tree
+static cp_expr
 cp_parser_userdef_char_literal (cp_parser *parser)
 {
   cp_token *token = cp_lexer_consume_token (parser->lexer);
@@ -3934,11 +3938,11 @@ cp_parser_userdef_char_literal (cp_parser *parser)
       error ("unable to find character literal operator %qD with %qT argument",
 	     name, TREE_TYPE (value));
       release_tree_vector (args);
-      return error_mark_node;
+      return cp_expr::build (error_mark_node);
     }
   result = finish_call_expr (decl, &args, false, true, tf_warning_or_error);
   release_tree_vector (args);
-  return result;
+  return cp_expr::build (result);
 }
 
 /* A subroutine of cp_parser_userdef_numeric_literal to
@@ -4006,7 +4010,7 @@ make_string_pack (tree value)
 /* Parse a user-defined numeric constant.  returns a call to a user-defined
    literal operator.  */
 
-static tree
+static cp_expr
 cp_parser_userdef_numeric_literal (cp_parser *parser)
 {
   cp_token *token = cp_lexer_consume_token (parser->lexer);
@@ -4047,7 +4051,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser)
 	}
 
       release_tree_vector (args);
-      return result;
+      return cp_expr::build (result);
     }
   release_tree_vector (args);
 
@@ -4062,7 +4066,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser)
       result = finish_call_expr (decl, &args, false, true,
 				 tf_warning_or_error);
       release_tree_vector (args);
-      return result;
+      return cp_expr::build (result);
     }
   release_tree_vector (args);
 
@@ -4078,7 +4082,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser)
       result = finish_call_expr (decl, &args, false, true,
 				 tf_warning_or_error);
       release_tree_vector (args);
-      return result;
+      return cp_expr::build (result);
     }
 
   release_tree_vector (args);
@@ -4087,7 +4091,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser)
   if (!cpp_get_options (parse_in)->ext_numeric_literals)
     inform (token->location, "use -std=gnu++11 or -fext-numeric-literals "
 	    "to enable more built-in suffixes");
-  return error_mark_node;
+  return cp_expr::build (error_mark_node);
 }
 
 /* Parse a user-defined string constant.  Returns a call to a user-defined
@@ -4407,7 +4411,7 @@ cp_parser_fold_operator (cp_parser *parser)
 
    Note that the '(' and ')' are matched in primary expression. */
 
-static tree
+static cp_expr
 cp_parser_fold_expression (cp_parser *parser, tree expr1)
 {
   cp_id_kind pidk;
@@ -4420,14 +4424,14 @@ cp_parser_fold_expression (cp_parser *parser, tree expr1)
       if (op == ERROR_MARK)
         {
           cp_parser_error (parser, "expected binary operator");
-          return error_mark_node;
+          return cp_expr::build (error_mark_node);
         }
 
       tree expr = cp_parser_cast_expression (parser, false, false,
-					     false, &pidk);
+					     false, &pidk).get_value ();
       if (expr == error_mark_node)
-        return error_mark_node;
-      return finish_left_unary_fold_expr (expr, op);
+        return cp_expr::build (error_mark_node);
+      return cp_expr::build (finish_left_unary_fold_expr (expr, op));
     }
 
   const cp_token* token = cp_lexer_peek_token (parser->lexer);
@@ -4435,13 +4439,13 @@ cp_parser_fold_expression (cp_parser *parser, tree expr1)
   if (op == ERROR_MARK)
     {
       cp_parser_error (parser, "expected binary operator");
-      return error_mark_node;
+      return cp_expr::build (error_mark_node);
     }
 
   if (cp_lexer_next_token_is_not (parser->lexer, CPP_ELLIPSIS))
     {
       cp_parser_error (parser, "expected ...");
-      return error_mark_node;
+      return cp_expr::build (error_mark_node);
     }
   cp_lexer_consume_token (parser->lexer);
 
@@ -4457,20 +4461,21 @@ cp_parser_fold_expression (cp_parser *parser, tree expr1)
 
   // Right fold.
   if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
-    return finish_right_unary_fold_expr (expr1, op);
+    return cp_expr::build (finish_right_unary_fold_expr (expr1, op));
 
   if (cp_lexer_next_token_is_not (parser->lexer, token->type))
     {
       cp_parser_error (parser, "mismatched operator in fold-expression");
-      return error_mark_node;
+      return cp_expr::build (error_mark_node);
     }
   cp_lexer_consume_token (parser->lexer);
 
   // Binary left or right fold.
-  tree expr2 = cp_parser_cast_expression (parser, false, false, false, &pidk);
+  tree expr2 = cp_parser_cast_expression (parser, false, false, false,
+                                          &pidk).get_value ();
   if (expr2 == error_mark_node)
-    return error_mark_node;
-  return finish_binary_fold_expr (expr1, expr2, op);
+    return cp_expr::build (error_mark_node);
+  return cp_expr::build (finish_binary_fold_expr (expr1, expr2, op));
 }
 
 /* Parse a primary-expression.
@@ -4527,7 +4532,7 @@ cp_parser_fold_expression (cp_parser *parser, tree expr1)
    Returns a representation of the expression.  Upon return, *IDK
    indicates what kind of id-expression (if any) was present.  */
 
-static tree
+static cp_expr
 cp_parser_primary_expression (cp_parser *parser,
 			      bool address_p,
 			      bool cast_p,
@@ -4566,7 +4571,7 @@ cp_parser_primary_expression (cp_parser *parser,
 	{
 	  error_at (token->location,
 		    "fixed-point types not supported in C++");
-	  return error_mark_node;
+	  return cp_expr::build (error_mark_node);
 	}
       /* Floating-point literals are only allowed in an integral
 	 constant expression if they are cast to an integral or
@@ -4612,7 +4617,7 @@ cp_parser_primary_expression (cp_parser *parser,
 	  if (!cast_p)
 	    cp_parser_non_integral_constant_expression (parser, NIC_FLOAT);
 	}
-      return token->u.value;
+      return cp_expr::build (token->u.value, token->location);
 
     case CPP_CHAR_USERDEF:
     case CPP_CHAR16_USERDEF:
@@ -4663,14 +4668,14 @@ cp_parser_primary_expression (cp_parser *parser,
 	      cp_parser_skip_to_end_of_block_or_statement (parser);
 	      if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
 		cp_lexer_consume_token (parser->lexer);
-	      return error_mark_node;
+	      return cp_expr::build (error_mark_node);
 	    }
 	  else
-	    return cp_parser_statement_expr (parser);
+	    return cp_expr::build (cp_parser_statement_expr (parser));
 	}
       /* Otherwise it's a normal parenthesized expression.  */
       {
-	tree expr;
+	cp_expr expr (NULL);
 	bool saved_greater_than_is_operator_p;
 
 	/* Consume the `('.  */
@@ -4683,7 +4688,7 @@ cp_parser_primary_expression (cp_parser *parser,
 
 	if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
 	  /* Left fold expression. */
-	  expr = NULL_TREE;
+	  expr = cp_expr::build (NULL_TREE);
 	else
 	  /* Parse the parenthesized expression.  */
 	  expr = cp_parser_expression (parser, idk, cast_p, decltype_p);
@@ -4691,8 +4696,8 @@ cp_parser_primary_expression (cp_parser *parser,
 	token = cp_lexer_peek_token (parser->lexer);
 	if (token->type == CPP_ELLIPSIS || cp_parser_fold_operator (token))
 	  {
-	    expr = cp_parser_fold_expression (parser, expr);
-	    if (expr != error_mark_node
+	    expr = cp_parser_fold_expression (parser, expr.get_value ());
+	    if (expr.get_value () != error_mark_node
 		&& cxx_dialect < cxx1z
 		&& !in_system_header_at (input_location))
 	      pedwarn (input_location, 0, "fold-expressions only available "
@@ -4704,7 +4709,7 @@ cp_parser_primary_expression (cp_parser *parser,
 	     example, the expression is of the form `A::B', since
 	     `&A::B' might be a pointer-to-member, but `&(A::B)' is
 	     not.  */
-	  expr = finish_parenthesized_expr (expr);
+	  expr = finish_parenthesized_expr (expr.get_value ());
 
 	/* DR 705: Wrapping an unqualified name in parentheses
 	   suppresses arg-dependent lookup.  We want to pass back
@@ -4737,10 +4742,10 @@ cp_parser_primary_expression (cp_parser *parser,
 	      return msg;
 	    /* ... else, fall though to see if it's a lambda.  */
 	  }
-	tree lam = cp_parser_lambda_expression (parser);
+	cp_expr lam = cp_parser_lambda_expression (parser);
 	/* Don't warn about a failed tentative parse.  */
 	if (cp_parser_error_occurred (parser))
-	  return error_mark_node;
+	  return cp_expr::build (error_mark_node);
 	maybe_warn_cpp0x (CPP0X_LAMBDA_EXPR);
 	return lam;
       }
@@ -4750,7 +4755,7 @@ cp_parser_primary_expression (cp_parser *parser,
 	/* We have an Objective-C++ string literal. */
         return cp_parser_objc_expression (parser);
       cp_parser_error (parser, "expected primary-expression");
-      return error_mark_node;
+      return cp_expr::build (error_mark_node);
 
     case CPP_KEYWORD:
       switch (token->keyword)
@@ -4758,20 +4763,20 @@ cp_parser_primary_expression (cp_parser *parser,
 	  /* These two are the boolean literals.  */
 	case RID_TRUE:
 	  cp_lexer_consume_token (parser->lexer);
-	  return boolean_true_node;
+	  return cp_expr (boolean_true_node, token->location);
 	case RID_FALSE:
 	  cp_lexer_consume_token (parser->lexer);
-	  return boolean_false_node;
+	  return cp_expr (boolean_false_node, token->location);
 
 	  /* The `__null' literal.  */
 	case RID_NULL:
 	  cp_lexer_consume_token (parser->lexer);
-	  return null_node;
+	  return cp_expr (null_node, token->location);
 
 	  /* The `nullptr' literal.  */
 	case RID_NULLPTR:
 	  cp_lexer_consume_token (parser->lexer);
-	  return nullptr_node;
+	  return cp_expr (nullptr_node, token->location);
 
 	  /* Recognize the `this' keyword.  */
 	case RID_THIS:
@@ -4904,11 +4909,11 @@ cp_parser_primary_expression (cp_parser *parser,
 	      error_at (token->location,
 			"a template declaration cannot appear at block scope");
 	      cp_parser_skip_to_end_of_block_or_statement (parser);
-	      return error_mark_node;
+	      return cp_expr::build (error_mark_node);
 	    }
 	default:
 	  cp_parser_error (parser, "expected primary-expression");
-	  return error_mark_node;
+	  return cp_expr::build (error_mark_node);
 	}
 
       /* An id-expression can start with either an identifier, a
@@ -4919,14 +4924,14 @@ cp_parser_primary_expression (cp_parser *parser,
     case CPP_TEMPLATE_ID:
     case CPP_NESTED_NAME_SPECIFIER:
       {
-	tree id_expression;
-	tree decl;
+      id_expression:
+	cp_expr id_expression (NULL);
+	cp_expr decl (NULL);
 	const char *error_msg;
 	bool template_p;
 	bool done;
 	cp_token *id_expr_token;
 
-      id_expression:
 	/* Parse the id-expression.  */
 	id_expression
 	  = cp_parser_id_expression (parser,
@@ -4948,8 +4953,8 @@ cp_parser_primary_expression (cp_parser *parser,
 	/* If we have a template-id, then no further lookup is
 	   required.  If the template-id was for a template-class, we
 	   will sometimes have a TYPE_DECL at this point.  */
-	if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR
-		 || TREE_CODE (id_expression) == TYPE_DECL)
+	if (TREE_CODE (id_expression.get_value ()) == TEMPLATE_ID_EXPR
+            || TREE_CODE (id_expression.get_value ()) == TYPE_DECL)
 	  decl = id_expression;
 	/* Look up the name.  */
 	else
@@ -4966,7 +4971,7 @@ cp_parser_primary_expression (cp_parser *parser,
 		return error_mark_node;
 	      }
 
-	    decl = cp_parser_lookup_name (parser, id_expression,
+	    decl = cp_parser_lookup_name (parser, id_expression.get_value (),
 					  none_type,
 					  template_p,
 					  /*is_namespace=*/false,
@@ -4982,25 +4987,29 @@ cp_parser_primary_expression (cp_parser *parser,
 	       dot-syntax for classes here.  */
 	    if (c_dialect_objc ()
 		&& cp_lexer_peek_token (parser->lexer)->type == CPP_DOT
-		&& TREE_CODE (decl) == TYPE_DECL
-		&& objc_is_class_name (decl))
+		&& TREE_CODE (decl.get_value ()) == TYPE_DECL
+		&& objc_is_class_name (decl.get_value ()))
 	      {
 		tree component;
 		cp_lexer_consume_token (parser->lexer);
-		component = cp_parser_identifier (parser);
+		component = cp_parser_identifier (parser).get_value ();
 		if (component == error_mark_node)
 		  return error_mark_node;
 
 		return objc_build_class_component_ref (id_expression, component);
 	      }
 
+            /* FIXME: disabling for now, as it strips location info, and I'd
+               prefer not to expose cp_expr to c-family for now.  */
+#if 0
 	    /* In Objective-C++, an instance variable (ivar) may be preferred
 	       to whatever cp_parser_lookup_name() found.  */
 	    decl = objc_lookup_ivar (decl, id_expression);
+#endif
 
 	    /* If name lookup gives us a SCOPE_REF, then the
 	       qualifying scope was dependent.  */
-	    if (TREE_CODE (decl) == SCOPE_REF)
+	    if (TREE_CODE (decl.get_value ()) == SCOPE_REF)
 	      {
 		/* At this point, we do not know if DECL is a valid
 		   integral constant expression.  We assume that it is
@@ -5037,7 +5046,7 @@ cp_parser_primary_expression (cp_parser *parser,
 		  {
 		    error_at (id_expr_token->location,
 			      "local variable %qD may not appear in this context",
-			      decl);
+			      decl.get_value ());
 		    return error_mark_node;
 		  }
 	      }
@@ -5065,7 +5074,7 @@ cp_parser_primary_expression (cp_parser *parser,
     }
 }
 
-static inline tree
+static inline cp_expr
 cp_parser_primary_expression (cp_parser *parser,
 			      bool address_p,
 			      bool cast_p,
@@ -5110,7 +5119,7 @@ cp_parser_primary_expression (cp_parser *parser,
    If DECLARATOR_P is true, the id-expression is appearing as part of
    a declarator, rather than as part of an expression.  */
 
-static tree
+static cp_expr
 cp_parser_id_expression (cp_parser *parser,
 			 bool template_keyword_p,
 			 bool check_dependency_p,
@@ -5245,7 +5254,7 @@ cp_parser_id_expression (cp_parser *parser,
    is true, the unqualified-id is appearing as part of a declarator,
    rather than as part of an expression.  */
 
-static tree
+static cp_expr
 cp_parser_unqualified_id (cp_parser* parser,
 			  bool template_keyword_p,
 			  bool check_dependency_p,
@@ -6098,7 +6107,7 @@ cp_parser_compound_literal_p (cp_parser *parser)
 
    Returns a representation of the expression.  */
 
-static tree
+static cp_expr
 cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
                               bool member_access_only_p, bool decltype_p,
 			      cp_id_kind * pidk_return)
@@ -6107,7 +6116,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
   location_t loc;
   enum rid keyword;
   cp_id_kind idk = CP_ID_KIND_NONE;
-  tree postfix_expression = NULL_TREE;
+  cp_expr postfix_expression (NULL_TREE);
   bool is_member_access = false;
   int saved_in_statement = -1;
 
@@ -6712,7 +6721,9 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 	  if (pidk_return != NULL)
 	    * pidk_return = idk;
           if (member_access_only_p)
-            return is_member_access? postfix_expression : error_mark_node;
+            return is_member_access
+              ? postfix_expression
+              : cp_expr (error_mark_node);
           else
             return postfix_expression;
 	}
@@ -7438,7 +7449,7 @@ cp_parser_pseudo_destructor_name (cp_parser* parser,
 
    Returns a representation of the expression.  */
 
-static tree
+static cp_expr
 cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
 			    bool address_p, bool cast_p, bool decltype_p)
 {
@@ -7520,7 +7531,7 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
 	    /* Save away the PEDANTIC flag.  */
 	    cp_parser_extension_opt (parser, &saved_pedantic);
 	    /* Parse the cast-expression.  */
-	    expr = cp_parser_simple_cast_expression (parser);
+	    expr = cp_parser_simple_cast_expression (parser).get_value ();
 	    /* Restore the PEDANTIC flag.  */
 	    pedantic = saved_pedantic;
 
@@ -7535,7 +7546,7 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
 	    /* Consume the `__real__' or `__imag__' token.  */
 	    cp_lexer_consume_token (parser->lexer);
 	    /* Parse the cast-expression.  */
-	    expression = cp_parser_simple_cast_expression (parser);
+	    expression = cp_parser_simple_cast_expression (parser).get_value ();
 	    /* Create the complete representation.  */
 	    return build_x_unary_op (token->location,
 				     (keyword == RID_REALPART
@@ -7666,7 +7677,7 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
 				     unary_operator == ADDR_EXPR,
 				     /*cast_p=*/false,
 				     /*decltype*/false,
-				     pidk);
+				     pidk).get_value ();
       /* Now, build an appropriate representation.  */
       switch (unary_operator)
 	{
@@ -8127,7 +8138,7 @@ cp_parser_delete_expression (cp_parser* parser)
     array_p = false;
 
   /* Parse the cast-expression.  */
-  expression = cp_parser_simple_cast_expression (parser);
+  expression = cp_parser_simple_cast_expression (parser).get_value ();
 
   /* A delete-expression may not appear in an integral constant
      expression.  */
@@ -8231,7 +8242,7 @@ cp_parser_tokens_start_cast_expression (cp_parser *parser)
 
    Returns a representation of the expression.  */
 
-static tree
+static cp_expr
 cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p,
 			   bool decltype_p, cp_id_kind * pidk)
 {
@@ -8335,7 +8346,7 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p,
 					    /*address_p=*/false,
 					    /*cast_p=*/true,
 					    /*decltype_p=*/false,
-					    pidk);
+					    pidk).get_value ();
 
 	  if (cp_parser_parse_definitely (parser))
 	    {
@@ -8457,7 +8468,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
   cp_parser_expression_stack stack;
   cp_parser_expression_stack_entry *sp = &stack[0];
   cp_parser_expression_stack_entry current;
-  tree rhs;
+  cp_expr rhs (NULL);
   cp_token *token;
   enum tree_code rhs_type;
   enum cp_parser_prec new_prec, lookahead_prec;
@@ -8467,7 +8478,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
   current.lhs_type = (cp_lexer_next_token_is (parser->lexer, CPP_NOT)
 		      ? TRUTH_NOT_EXPR : ERROR_MARK);
   current.lhs = cp_parser_cast_expression (parser, /*address_p=*/false,
-					   cast_p, decltype_p, pidk);
+                                           cast_p, decltype_p, pidk);
   current.prec = prec;
 
   if (cp_parser_error_occurred (parser))
@@ -8521,9 +8532,11 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
       /* For "false && x" or "true || x", x will never be executed;
 	 disable warnings while evaluating it.  */
       if (current.tree_type == TRUTH_ANDIF_EXPR)
-	c_inhibit_evaluation_warnings += current.lhs == truthvalue_false_node;
+	c_inhibit_evaluation_warnings +=
+          current.lhs.get_value () == truthvalue_false_node;
       else if (current.tree_type == TRUTH_ORIF_EXPR)
-	c_inhibit_evaluation_warnings += current.lhs == truthvalue_true_node;
+	c_inhibit_evaluation_warnings +=
+          current.lhs.get_value () == truthvalue_true_node;
 
       /* Extract another operand.  It may be the RHS of this expression
 	 or the LHS of a new, higher priority expression.  */
@@ -8570,30 +8583,45 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
 
       /* Undo the disabling of warnings done above.  */
       if (current.tree_type == TRUTH_ANDIF_EXPR)
-	c_inhibit_evaluation_warnings -= current.lhs == truthvalue_false_node;
+	c_inhibit_evaluation_warnings -=
+          current.lhs.get_value () == truthvalue_false_node;
       else if (current.tree_type == TRUTH_ORIF_EXPR)
-	c_inhibit_evaluation_warnings -= current.lhs == truthvalue_true_node;
+	c_inhibit_evaluation_warnings -=
+          current.lhs.get_value () == truthvalue_true_node;
 
+      tree current_lhs = current.lhs.get_value ();
       if (warn_logical_not_paren
 	  && TREE_CODE_CLASS (current.tree_type) == tcc_comparison
 	  && current.lhs_type == TRUTH_NOT_EXPR
 	  /* Avoid warning for !!x == y.  */
-	  && (TREE_CODE (current.lhs) != NE_EXPR
-	      || !integer_zerop (TREE_OPERAND (current.lhs, 1)))
-	  && (TREE_CODE (current.lhs) != TRUTH_NOT_EXPR
-	      || (TREE_CODE (TREE_OPERAND (current.lhs, 0)) != TRUTH_NOT_EXPR
+	  && (TREE_CODE (current_lhs) != NE_EXPR
+	      || !integer_zerop (TREE_OPERAND (current_lhs, 1)))
+	  && (TREE_CODE (current_lhs) != TRUTH_NOT_EXPR
+	      || (TREE_CODE (TREE_OPERAND (current_lhs, 0)) != TRUTH_NOT_EXPR
 		  /* Avoid warning for !b == y where b is boolean.  */
-		  && (TREE_TYPE (TREE_OPERAND (current.lhs, 0)) == NULL_TREE
-		      || (TREE_CODE (TREE_TYPE (TREE_OPERAND (current.lhs, 0)))
+		  && (TREE_TYPE (TREE_OPERAND (current_lhs, 0)) == NULL_TREE
+		      || (TREE_CODE (TREE_TYPE (TREE_OPERAND (current_lhs, 0)))
 			  != BOOLEAN_TYPE))))
 	  /* Avoid warning for !!b == y where b is boolean.  */
-	  && (!DECL_P (current.lhs)
-	      || TREE_TYPE (current.lhs) == NULL_TREE
-	      || TREE_CODE (TREE_TYPE (current.lhs)) != BOOLEAN_TYPE))
+	  && (!DECL_P (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,
-				      maybe_constant_value (rhs));
+				      maybe_constant_value (rhs.get_value ()));
 
       overload = NULL;
+
+      source_range src_range;
+      inform (current.lhs.get_location (), "current.lhs");
+      src_range.m_start = current.lhs.get_start ();
+      src_range.m_finish = rhs.get_finish ();
+      inform (rhs.get_location (), "rhs");
+      location_t pure_loc = get_pure_location (current.loc);
+      location_t combined_loc = COMBINE_LOCATION_DATA (line_table,
+                                                       pure_loc,
+                                                       src_range,
+                                                       NULL);
+
       /* ??? Currently we pass lhs_type == ERROR_MARK and rhs_type ==
 	 ERROR_MARK for everything that is not a binary expression.
 	 This makes warn_about_parentheses miss some warnings that
@@ -8604,23 +8632,23 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
       if (no_toplevel_fold_p
 	  && lookahead_prec <= current.prec
 	  && sp == stack)
-	current.lhs = build2 (current.tree_type,
-			      TREE_CODE_CLASS (current.tree_type)
-			      == tcc_comparison
-			      ? boolean_type_node : TREE_TYPE (current.lhs),
-			      current.lhs, rhs);
+        current.lhs = build2_loc (combined_loc,
+                                  current.tree_type,
+                                  TREE_CODE_CLASS (current.tree_type)
+                                  == tcc_comparison
+                                  ? boolean_type_node : TREE_TYPE (current.lhs.get_value ()),
+                                  current.lhs.get_value (), rhs.get_value ());
       else
-	current.lhs = build_x_binary_op (current.loc, current.tree_type,
-					 current.lhs, current.lhs_type,
-					 rhs, rhs_type, &overload,
-					 complain_flags (decltype_p));
+        current.lhs = build_x_binary_op (combined_loc,
+                                         current.tree_type,
+                                         current.lhs.get_value (),
+                                         current.lhs_type,
+                                         rhs.get_value (),
+                                         rhs_type, &overload,
+                                         complain_flags (decltype_p));
       current.lhs_type = current.tree_type;
-      /* FIXME: this isn't going to be quite right yet:  */
-      if (EXPR_HAS_LOCATION (rhs))
-        protected_set_expr_location_with_range (current.lhs, current.loc,
-                                                current.loc, EXPR_LOCATION (rhs));
-      else
-        protected_set_expr_location (current.lhs, current.loc);
+
+      inform (current.lhs.get_location (), "current.lhs.get_location ()");
 
       /* If the binary operator required the use of an overloaded operator,
 	 then this expression cannot be an integral constant-expression.
@@ -8634,7 +8662,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
 	return error_mark_node;
     }
 
-  return current.lhs;
+  return current.lhs.get_value ();
 }
 
 static tree
@@ -8882,7 +8910,7 @@ cp_parser_assignment_operator_opt (cp_parser* parser)
 
    Returns a representation of the expression.  */
 
-static tree
+static cp_expr
 cp_parser_expression (cp_parser* parser, cp_id_kind * pidk,
 		      bool cast_p, bool decltype_p)
 {
@@ -9320,7 +9348,7 @@ finish_lambda_scope (void)
 
    Returns a representation of the expression.  */
 
-static tree
+static cp_expr
 cp_parser_lambda_expression (cp_parser* parser)
 {
   tree lambda_expr = build_lambda_expr ();
@@ -24096,7 +24124,7 @@ cp_parser_nested_requirement (cp_parser *parser)
    TREE_LIST of candidates if name-lookup results in an ambiguity, and
    NULL_TREE otherwise.  */
 
-static tree
+static cp_expr
 cp_parser_lookup_name (cp_parser *parser, tree name,
 		       enum tag_types tag_type,
 		       bool is_template,
@@ -24338,7 +24366,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
 
   maybe_record_typedef_use (decl);
 
-  return decl;
+  return cp_expr (decl, name_location);
 }
 
 /* Like cp_parser_lookup_name, but for use in the typical case where
@@ -25340,7 +25368,7 @@ cp_parser_single_declaration (cp_parser* parser,
 
 /* Parse a cast-expression that is not the operand of a unary "&".  */
 
-static tree
+static cp_expr
 cp_parser_simple_cast_expression (cp_parser *parser)
 {
   return cp_parser_cast_expression (parser, /*address_p=*/false,
@@ -25980,7 +26008,7 @@ cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword)
   /* If the type-id production did not work out, then we must be
      looking at the unary-expression production.  */
   if (!expr)
-    expr = cp_parser_unary_expression (parser);
+    expr = cp_parser_unary_expression (parser).get_value ();
 
   /* Go back to evaluating expressions.  */
   --cp_unevaluated_operand;
@@ -31334,7 +31362,7 @@ restart:
 	  cp_token *token;
 	  cp_lexer_consume_token (parser->lexer);
 	  cp_parser_parse_tentatively (parser);
-	  rhs1 = cp_parser_simple_cast_expression (parser);
+	  rhs1 = cp_parser_simple_cast_expression (parser).get_value ();
 	  if (rhs1 == error_mark_node)
 	    {
 	      cp_parser_abort_tentative_parse (parser);
@@ -31631,7 +31659,7 @@ cp_parser_omp_for_incr (cp_parser *parser, tree decl)
       op = (token->type == CPP_PLUS_PLUS
 	    ? PREINCREMENT_EXPR : PREDECREMENT_EXPR);
       cp_lexer_consume_token (parser->lexer);
-      lhs = cp_parser_simple_cast_expression (parser);
+      lhs = cp_parser_simple_cast_expression (parser).get_value ();
       if (lhs != decl)
 	return error_mark_node;
       return build2 (op, TREE_TYPE (decl), decl, NULL_TREE);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index c1f4330..602f01c 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -3302,7 +3302,7 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain)
    the use of "this" explicit.
 
    Upon return, *IDK will be filled in appropriately.  */
-tree
+cp_expr
 finish_id_expression (tree id_expression,
 		      tree decl,
 		      tree scope,
@@ -3647,7 +3647,7 @@ finish_id_expression (tree id_expression,
 	}
     }
 
-  return decl;
+  return cp_expr (decl, location);
 }
 
 /* Implement the __typeof keyword: Return the type of EXPR, suitable for
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 9e6f949..7c948c6 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -5108,7 +5108,7 @@ cp_build_binary_op (location_t location,
 	instrument_expr = ubsan_instrument_shift (location, code, op0, op1);
     }
 
-  result = build2 (resultcode, build_type, op0, op1);
+  result = build2_loc (location, resultcode, build_type, op0, op1);
   result = fold_if_not_in_template (result);
   if (final_type != 0)
     result = cp_convert (final_type, result, complain);
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 5485aaf..aef7d29 100644
--- a/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.c
+++ b/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.c
@@ -420,3 +420,15 @@ void test_quadratic (double a, double b, double c)
    { dg-end-multiline-output "" } */
 
 }
+#endif
+
+/* FIXME: C++-specific expresssions. */
+void test_literal_keyworkds (int a, int b)
+{
+  __emit_expression_range (0, true ); /* { dg-warning "range" } */
+  __emit_expression_range (0, false ); /* { dg-warning "range" } */
+  __emit_expression_range (0, __null ); /* { dg-warning "range" } */
+  __emit_expression_range (0, nullptr ); /* { dg-warning "range" } */
+  // FIXME:
+  __emit_expression_range (0, this ); /* { dg-warning "range" } */
+}
diff --git a/gcc/tree.c b/gcc/tree.c
index e091425..3bce113 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -4737,26 +4737,6 @@ protected_set_expr_location (tree t, location_t loc)
     SET_EXPR_LOCATION (t, loc);
 }
 
-/* FIXME.  */
-
-void
-protected_set_expr_location_with_range (tree t, location_t caret_loc,
-					location_t start, location_t finish)
-{
-  if (CAN_HAVE_LOCATION_P (t))
-    {
-      source_range src_range;
-      src_range.m_start = start;
-      src_range.m_finish = finish;
-
-      location_t combined = COMBINE_LOCATION_DATA (line_table,
-						   caret_loc,
-						   src_range,
-						   NULL);
-      SET_EXPR_LOCATION (t, combined);
-    }
-}
-
 
 /* Return a declaration like DDECL except that its DECL_ATTRIBUTES
    is ATTRIBUTE.  */
@@ -13674,7 +13654,7 @@ nonnull_arg_p (const_tree arg)
   return false;
 }
 
-static location_t
+location_t
 get_pure_location (location_t loc)
 {
   if (IS_ADHOC_LOC (loc))
diff --git a/gcc/tree.h b/gcc/tree.h
index f3c20c3..3e10ae9 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1090,8 +1090,6 @@ get_expr_source_range (tree expr)
 }
 
 extern void protected_set_expr_location (tree, location_t);
-extern void protected_set_expr_location_with_range (tree, location_t,
-						    location_t, location_t);
 
 /* In a TARGET_EXPR node.  */
 #define TARGET_EXPR_SLOT(NODE) TREE_OPERAND_CHECK_CODE (NODE, TARGET_EXPR, 0)
@@ -5160,6 +5158,9 @@ type_with_alias_set_p (const_tree t)
 }
 
 extern location_t
+get_pure_location (location_t loc);
+
+extern location_t
 set_block (location_t loc, tree block);
 
 extern void gt_ggc_mx (tree &);
-- 
1.8.5.3

