C++ FE: expression ranges
authorDavid Malcolm <dmalcolm@redhat.com>
Fri, 4 Dec 2015 18:09:54 +0000 (18:09 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Fri, 4 Dec 2015 18:09:54 +0000 (18:09 +0000)
gcc/ChangeLog:
* convert.c (convert_to_real_1): When converting from a
REAL_TYPE, preserve the location of EXPR in the result.
* tree.c (get_pure_location): Make non-static.
(set_source_range): Return the resulting location_t.
(make_location): New function.
* tree.h (get_pure_location): New decl.
(get_finish): New inline function.
(set_source_range): Convert return type from void to location_t.
(make_location): New decl.

gcc/cp/ChangeLog:
* cp-tree.h (class cp_expr): New class.
(finish_parenthesized_expr): Convert return type and param to
cp_expr.
(perform_koenig_lookup): Convert return type and param from tree
to cp_expr.
(finish_increment_expr): Likewise.
(finish_unary_op_expr): Likewise.
(finish_id_expression): Likewise for return type.
(build_class_member_access_expr): Likewise for param.
(finish_class_member_access_expr): Likewise.
(build_x_unary_op): Likewise.
(build_c_cast): New decl.
(build_x_modify_expr): Convert return type from tree to cp_expr.
* cvt.c (cp_convert_and_check): When warning about conversions,
attempt to use the location of "expr" if available, otherwise
falling back to the old behavior of using input_location.
* name-lookup.c (lookup_arg_dependent_1): Convert return type from
tree to cp_expr.
(lookup_arg_dependent): Likewise; also for local "ret".
* name-lookup.h (lookup_arg_dependent): Likewise for return type.
* parser.c (cp_lexer_previous_token): Skip past purged tokens.
(struct cp_parser_expression_stack_entry): Convert field "lhs" to
cp_expr.
(cp_parser_identifier): Likewise for return type.  Use cp_expr
ctor to preserve the token's location.
(cp_parser_string_literal): Likewise, building up a meaningful
location for the case where a compound string literal is built by
concatentation.
(cp_parser_userdef_char_literal): Likewise for return type.
(cp_parser_userdef_numeric_literal): Likewise.
(cp_parser_statement_expr): Convert return type to cp_expr.
Generate a suitable location for the expr and return it via the
cp_expr ctor.
(cp_parser_fold_expression): Convert return type to cp_expr.
(cp_parser_primary_expression): Likewise, and for locals "expr",
"lam", "id_expression", "decl".
Use cp_expr ctor when parsing literals, to preserve the spelling
location of the token.  Preserve the locations of parentheses.
Preserve location when calling objc_lookup_ivar.
Preserve the location for "this" tokens.  Generate suitable
locations for "__builtin_va_arg" constructs and for
Objective C 2.0 dot-syntax.  Set the location for the result of
finish_id_expression.
(cp_parser_primary_expression): Convert return type from tree to
cp_expr.
(cp_parser_id_expression): Likewise.
(cp_parser_unqualified_id): Likewise.  Also for local "id".
(cp_parser_postfix_expression): Likewise, also for local
"postfix_expression".  Generate suitable locations for
C++-style casts, "_Cilk_spawn" constructs.  Convert local
"initializer" to cp_expr and use it to preserve the location of
compound literals.  Capture the location of the closing
parenthesis of a call site via
cp_parser_parenthesized_expression_list, and use it to build
a source range for a call.  Use cp_expr in ternary expression.
(cp_parser_postfix_dot_deref_expression): Convert param from tree to
cp_expr.  Generate and set a location.
(cp_parser_parenthesized_expression_list): Add "close_paren_loc"
out-param, and write back to it.
(cp_parser_unary_expression): Convert return type from tree to
cp_expr.  Also for locals "cast_expression" and "expression".
Generate and use suitable locations for addresses of
labels and for cast expressions.  Call cp_expr::set_location where
necessary.  Preserve the locations of negated numeric literals.
(cp_parser_new_expression): Generate meaningful locations/ranges.
(cp_parser_cast_expression): Convert return type from tree to
cp_expr; also for local "expr".  Use the paren location to generate a
meaningful range for the expression.
(cp_parser_binary_expression): Convert return type from tree to
cp_expr; also for local "rhs".  Generate a meaningful location
for the expression, and use it.  Replace call to
protected_set_expr_location by converting a build2 to a build2_loc
and using the location in the call to build_x_binary_op, adding a
cp_expr::set_location to the latter case.
(cp_parser_question_colon_clause): Convert param from tree to
cp_expr; also for local "assignment_expr".  Set the spelling range
of the expression.
(cp_parser_assignment_expression): Likewise for return type and
locals "expr" and "rhs".  Build a meaningful spelling range for
the expression.  Remove saving of input_location in favor of a
call to cp_expr::set_location.
(cp_parser_expression): Convert return type and locals
"expression" and "assignment_expression" to cp_expr.  Build a
meaningful spelling range for assignment expressions.
(cp_parser_constant_expression): Likewise for return type and
local "expression".
(cp_parser_builtin_offsetof): Convert return type and local "expr"
to cp_expr.  Generate suitable locations.
(cp_parser_lambda_expression): Convert return return type to
cp_expr.
(cp_parser_operator_function_id): Likewise.
(cp_parser_operator): Likewise.  Generate a meaningful range,
using cp_expr's ctor to return it.
(cp_parser_template_id): When converting a token to
CPP_TEMPLATE_ID, update the location.
(cp_parser_initializer_clause): Convert return type and local
"initializer" to cp_expr.
(cp_parser_braced_list): Likewise for return type.  Generate
suitable locations.
(cp_parser_lookup_name): Likewise for return type.  Use cp_expr's
ctor to preserve the location_t of the name.
(cp_parser_simple_cast_expression): Likewise for return type.
(cp_parser_functional_cast): Convert return type and local "cast"
to cp_expr.  Generate suitable locations.
(cp_parser_objc_expression): Convert return type to cp_expr.k  Generate
(cp_parser_objc_message_expression): Generate suitable locations.
(cp_parser_objc_encode_expression): Convert return type to
cp_expr.  Generate suitable locations.
(cp_parser_objc_protocol_expression): Generate suitable locations.
(cp_parser_objc_selector_expression): Generate suitable locations.
(cp_parser_omp_for_cond): Attempt to use the location
of "cond" for the binary op.
(cp_parser_transaction_expression): Issue the tm-not-enabled error
at the location of the __transaction_foo token, rather than at
input_location.
* semantics.c (finish_parenthesized_expr): Convert return type and
param to cp_expr.  Preserve location.
(perform_koenig_lookup): Likewise for return type
and param.
(finish_increment_expr): Likewise.  Generate suitable locations.
(finish_unary_op_expr): Likewise for return type and local "result".
Generate suitable locations.
(finish_id_expression): Convert return type to cp_expr and use
cp_expr ctor to preserve location information.
* typeck.c (build_class_member_access_expr): Convert param to
cp_expr.
(finish_class_member_access_expr): Likewise.
(cp_build_binary_op): Convert a build2 to a build2_loc.
(build_x_unary_op): Convert param from tree to cp_expr.
(build_nop): Preserve the location of EXPR.
(build_c_cast): Provide an overloaded variant that takes a cp_expr
and returns a cp_expr.
(build_x_modify_expr): Convert return type from tree to cp_expr.

gcc/testsuite/ChangeLog:
* g++.dg/cpp0x/nsdmi-template14.C: Move dg-error directive.
* g++.dg/gomp/loop-1.C: Update dg-error locations.
* g++.dg/plugin/diagnostic-test-expressions-1.C: New file, adapted
from gcc.dg/plugin/diagnostic-test-expressions-1.c.
* g++.dg/plugin/plugin.exp (plugin_test_list): Add the above.
* g++.dg/template/crash55.C: Update dg-error directives.
* g++.dg/template/pseudodtor3.C: Update column numbers in dg-error
directives.
* g++.dg/template/pr64100.C: Update location of dg-error
directive.
* g++.dg/template/ref3.C: Add XFAIL (PR c++/68699).
* g++.dg/ubsan/pr63956.C: Update dg directives to reflect
improved location information.
* g++.dg/warn/pr35635.C (func3): Update location of a
dg-warning.
* g++.dg/warn/Wconversion-real-integer2.C: Update location of
dg-warning; add a dg-message.
* obj-c++.dg/plugin/diagnostic-test-expressions-1.mm: New file,
based on objc.dg/plugin/diagnostic-test-expressions-1.m.
* obj-c++.dg/plugin/plugin.exp: New file, based on
objc.dg/plugin/plugin.exp.

From-SVN: r231293

26 files changed:
gcc/ChangeLog
gcc/convert.c
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/name-lookup.c
gcc/cp/name-lookup.h
gcc/cp/parser.c
gcc/cp/semantics.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/nsdmi-template14.C
gcc/testsuite/g++.dg/gomp/loop-1.C
gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/plugin/plugin.exp
gcc/testsuite/g++.dg/template/crash55.C
gcc/testsuite/g++.dg/template/pr64100.C
gcc/testsuite/g++.dg/template/pseudodtor3.C
gcc/testsuite/g++.dg/template/ref3.C
gcc/testsuite/g++.dg/ubsan/pr63956.C
gcc/testsuite/g++.dg/warn/Wconversion-real-integer2.C
gcc/testsuite/g++.dg/warn/pr35635.C
gcc/testsuite/obj-c++.dg/plugin/diagnostic-test-expressions-1.mm [new file with mode: 0644]
gcc/testsuite/obj-c++.dg/plugin/plugin.exp [new file with mode: 0644]
gcc/tree.c
gcc/tree.h

index 5ff2fbf315cb0bfdf2e1a8edf873bd0b2f243cc6..9aba352870c1c983a78f8d584c99521647433128 100644 (file)
@@ -1,3 +1,15 @@
+2015-12-04  David Malcolm  <dmalcolm@redhat.com>
+
+       * convert.c (convert_to_real_1): When converting from a
+       REAL_TYPE, preserve the location of EXPR in the result.
+       * tree.c (get_pure_location): Make non-static.
+       (set_source_range): Return the resulting location_t.
+       (make_location): New function.
+       * tree.h (get_pure_location): New decl.
+       (get_finish): New inline function.
+       (set_source_range): Convert return type from void to location_t.
+       (make_location): New decl.
+
 2015-12-04  Jakub Jelinek  <jakub@redhat.com>
 
        PR c/68656
index e27a6feeda5ecfce80dc74f2fab0fefe326a42dc..8fb86240189103b3d51415bd5b3f274ce77db967 100644 (file)
@@ -362,10 +362,11 @@ convert_to_real_1 (tree type, tree expr, bool fold_p)
     case REAL_TYPE:
       /* Ignore the conversion if we don't need to store intermediate
         results and neither type is a decimal float.  */
-      return build1 ((flag_float_store
-                    || DECIMAL_FLOAT_TYPE_P (type)
-                    || DECIMAL_FLOAT_TYPE_P (itype))
-                    ? CONVERT_EXPR : NOP_EXPR, type, expr);
+      return build1_loc (loc,
+                        (flag_float_store
+                         || DECIMAL_FLOAT_TYPE_P (type)
+                         || DECIMAL_FLOAT_TYPE_P (itype))
+                        ? CONVERT_EXPR : NOP_EXPR, type, expr);
 
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
index 711169e8f02592a9671f32cefdc50c88712a1f5a..dd56155b3499662ba5ec30c289724e3b3ebdf251 100644 (file)
@@ -1,3 +1,139 @@
+2015-12-04  David Malcolm  <dmalcolm@redhat.com>
+
+       * cp-tree.h (class cp_expr): New class.
+       (finish_parenthesized_expr): Convert return type and param to
+       cp_expr.
+       (perform_koenig_lookup): Convert return type and param from tree
+       to cp_expr.
+       (finish_increment_expr): Likewise.
+       (finish_unary_op_expr): Likewise.
+       (finish_id_expression): Likewise for return type.
+       (build_class_member_access_expr): Likewise for param.
+       (finish_class_member_access_expr): Likewise.
+       (build_x_unary_op): Likewise.
+       (build_c_cast): New decl.
+       (build_x_modify_expr): Convert return type from tree to cp_expr.
+       * cvt.c (cp_convert_and_check): When warning about conversions,
+       attempt to use the location of "expr" if available, otherwise
+       falling back to the old behavior of using input_location.
+       * name-lookup.c (lookup_arg_dependent_1): Convert return type from
+       tree to cp_expr.
+       (lookup_arg_dependent): Likewise; also for local "ret".
+       * name-lookup.h (lookup_arg_dependent): Likewise for return type.
+       * parser.c (cp_lexer_previous_token): Skip past purged tokens.
+       (struct cp_parser_expression_stack_entry): Convert field "lhs" to
+       cp_expr.
+       (cp_parser_identifier): Likewise for return type.  Use cp_expr
+       ctor to preserve the token's location.
+       (cp_parser_string_literal): Likewise, building up a meaningful
+       location for the case where a compound string literal is built by
+       concatentation.
+       (cp_parser_userdef_char_literal): Likewise for return type.
+       (cp_parser_userdef_numeric_literal): Likewise.
+       (cp_parser_statement_expr): Convert return type to cp_expr.
+       Generate a suitable location for the expr and return it via the
+       cp_expr ctor.
+       (cp_parser_fold_expression): Convert return type to cp_expr.
+       (cp_parser_primary_expression): Likewise, and for locals "expr",
+       "lam", "id_expression", "decl".
+       Use cp_expr ctor when parsing literals, to preserve the spelling
+       location of the token.  Preserve the locations of parentheses.
+       Preserve location when calling objc_lookup_ivar.
+       Preserve the location for "this" tokens.  Generate suitable
+       locations for "__builtin_va_arg" constructs and for
+       Objective C 2.0 dot-syntax.  Set the location for the result of
+       finish_id_expression.
+       (cp_parser_primary_expression): Convert return type from tree to
+       cp_expr.
+       (cp_parser_id_expression): Likewise.
+       (cp_parser_unqualified_id): Likewise.  Also for local "id".
+       (cp_parser_postfix_expression): Likewise, also for local
+       "postfix_expression".  Generate suitable locations for
+       C++-style casts, "_Cilk_spawn" constructs.  Convert local
+       "initializer" to cp_expr and use it to preserve the location of
+       compound literals.  Capture the location of the closing
+       parenthesis of a call site via
+       cp_parser_parenthesized_expression_list, and use it to build
+       a source range for a call.  Use cp_expr in ternary expression.
+       (cp_parser_postfix_dot_deref_expression): Convert param from tree to
+       cp_expr.  Generate and set a location.
+       (cp_parser_parenthesized_expression_list): Add "close_paren_loc"
+       out-param, and write back to it.
+       (cp_parser_unary_expression): Convert return type from tree to
+       cp_expr.  Also for locals "cast_expression" and "expression".
+       Generate and use suitable locations for addresses of
+       labels and for cast expressions.  Call cp_expr::set_location where
+       necessary.  Preserve the locations of negated numeric literals.
+       (cp_parser_new_expression): Generate meaningful locations/ranges.
+       (cp_parser_cast_expression): Convert return type from tree to
+       cp_expr; also for local "expr".  Use the paren location to generate a
+       meaningful range for the expression.
+       (cp_parser_binary_expression): Convert return type from tree to
+       cp_expr; also for local "rhs".  Generate a meaningful location
+       for the expression, and use it.  Replace call to
+       protected_set_expr_location by converting a build2 to a build2_loc
+       and using the location in the call to build_x_binary_op, adding a
+       cp_expr::set_location to the latter case.
+       (cp_parser_question_colon_clause): Convert param from tree to
+       cp_expr; also for local "assignment_expr".  Set the spelling range
+       of the expression.
+       (cp_parser_assignment_expression): Likewise for return type and
+       locals "expr" and "rhs".  Build a meaningful spelling range for
+       the expression.  Remove saving of input_location in favor of a
+       call to cp_expr::set_location.
+       (cp_parser_expression): Convert return type and locals
+       "expression" and "assignment_expression" to cp_expr.  Build a
+       meaningful spelling range for assignment expressions.
+       (cp_parser_constant_expression): Likewise for return type and
+       local "expression".
+       (cp_parser_builtin_offsetof): Convert return type and local "expr"
+       to cp_expr.  Generate suitable locations.
+       (cp_parser_lambda_expression): Convert return return type to
+       cp_expr.
+       (cp_parser_operator_function_id): Likewise.
+       (cp_parser_operator): Likewise.  Generate a meaningful range,
+       using cp_expr's ctor to return it.
+       (cp_parser_template_id): When converting a token to
+       CPP_TEMPLATE_ID, update the location.
+       (cp_parser_initializer_clause): Convert return type and local
+       "initializer" to cp_expr.
+       (cp_parser_braced_list): Likewise for return type.  Generate
+       suitable locations.
+       (cp_parser_lookup_name): Likewise for return type.  Use cp_expr's
+       ctor to preserve the location_t of the name.
+       (cp_parser_simple_cast_expression): Likewise for return type.
+       (cp_parser_functional_cast): Convert return type and local "cast"
+       to cp_expr.  Generate suitable locations.
+       (cp_parser_objc_expression): Convert return type to cp_expr.k  Generate
+       (cp_parser_objc_message_expression): Generate suitable locations.
+       (cp_parser_objc_encode_expression): Convert return type to
+       cp_expr.  Generate suitable locations.
+       (cp_parser_objc_protocol_expression): Generate suitable locations.
+       (cp_parser_objc_selector_expression): Generate suitable locations.
+       (cp_parser_omp_for_cond): Attempt to use the location
+       of "cond" for the binary op.
+       (cp_parser_transaction_expression): Issue the tm-not-enabled error
+       at the location of the __transaction_foo token, rather than at
+       input_location.
+       * semantics.c (finish_parenthesized_expr): Convert return type and
+       param to cp_expr.  Preserve location.
+       (perform_koenig_lookup): Likewise for return type
+       and param.
+       (finish_increment_expr): Likewise.  Generate suitable locations.
+       (finish_unary_op_expr): Likewise for return type and local "result".
+       Generate suitable locations.
+       (finish_id_expression): Convert return type to cp_expr and use
+       cp_expr ctor to preserve location information.
+       * typeck.c (build_class_member_access_expr): Convert param to
+       cp_expr.
+       (finish_class_member_access_expr): Likewise.
+       (cp_build_binary_op): Convert a build2 to a build2_loc.
+       (build_x_unary_op): Convert param from tree to cp_expr.
+       (build_nop): Preserve the location of EXPR.
+       (build_c_cast): Provide an overloaded variant that takes a cp_expr
+       and returns a cp_expr.
+       (build_x_modify_expr): Convert return type from tree to cp_expr.
+
 2015-12-03  Cesar Philippidis  <cesar@codesourcery.com>
 
        * parser.c (cp_ensure_no_oacc_routine): Update error message.
index 38ae70f74612c0f1305e9891ad0815e729c5584f..6ddab8a57cf9d2d59d1541187fed61bf9ede6421 100644 (file)
@@ -40,6 +40,68 @@ c-common.h, not after.
 #include "c-family/c-common.h"
 #include "diagnostic.h"
 
+/* 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) {}
+
+  /* Implicit conversions to tree.  */
+  operator tree () const { return m_value; }
+  tree & operator* () { return m_value; }
+  tree & operator-> () { return m_value; }
+
+  tree get_value () const { return m_value; }
+  location_t get_location () const { return m_loc; }
+  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;
+  }
+
+  void set_location (location_t loc)
+  {
+    protected_set_expr_location (m_value, loc);
+    m_loc = loc;
+  }
+
+  void set_range (location_t start, location_t finish)
+  {
+    set_location (make_location (m_loc, start, finish));
+  }
+
+ private:
+  tree m_value;
+  location_t m_loc;
+};
+
+inline bool
+operator == (const cp_expr &lhs, tree rhs)
+{
+  return lhs.get_value () == rhs;
+}
+
 #include "name-lookup.h"
 
 /* Usage of TREE_LANG_FLAG_?:
@@ -6291,7 +6353,7 @@ extern tree finish_asm_stmt                       (int, tree, tree, tree, tree,
                                                 tree);
 extern tree finish_label_stmt                  (tree);
 extern void finish_label_decl                  (tree);
-extern tree finish_parenthesized_expr          (tree);
+extern cp_expr finish_parenthesized_expr       (cp_expr);
 extern tree force_paren_expr                   (tree);
 extern tree finish_non_static_data_member       (tree, tree, tree);
 extern tree begin_stmt_expr                    (void);
@@ -6299,15 +6361,15 @@ extern tree finish_stmt_expr_expr               (tree, tree);
 extern tree finish_stmt_expr                   (tree, bool);
 extern tree stmt_expr_value_expr               (tree);
 bool empty_expr_stmt_p                         (tree);
-extern tree perform_koenig_lookup              (tree, vec<tree, va_gc> *,
+extern cp_expr perform_koenig_lookup           (cp_expr, vec<tree, va_gc> *,
                                                 tsubst_flags_t);
 extern tree finish_call_expr                   (tree, vec<tree, va_gc> **, bool,
                                                 bool, tsubst_flags_t);
 extern tree finish_template_variable           (tree, tsubst_flags_t = tf_warning_or_error);
-extern tree finish_increment_expr              (tree, enum tree_code);
+extern cp_expr finish_increment_expr           (cp_expr, enum tree_code);
 extern tree finish_this_expr                   (void);
 extern tree finish_pseudo_destructor_expr       (tree, tree, tree, location_t);
-extern tree finish_unary_op_expr               (location_t, enum tree_code, tree,
+extern cp_expr finish_unary_op_expr            (location_t, enum tree_code, cp_expr,
                                                 tsubst_flags_t);
 extern tree finish_compound_literal            (tree, tree, tsubst_flags_t);
 extern tree finish_fname                       (tree);
@@ -6321,7 +6383,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,
@@ -6564,9 +6626,9 @@ extern tree unlowered_expr_type                 (const_tree);
 extern tree decay_conversion                   (tree,
                                                  tsubst_flags_t,
                                                  bool = true);
-extern tree build_class_member_access_expr      (tree, tree, tree, bool,
+extern tree build_class_member_access_expr      (cp_expr, tree, tree, bool,
                                                 tsubst_flags_t);
-extern tree finish_class_member_access_expr     (tree, tree, bool, 
+extern tree finish_class_member_access_expr     (cp_expr, tree, bool,
                                                 tsubst_flags_t);
 extern tree build_x_indirect_ref               (location_t, tree,
                                                 ref_operator, tsubst_flags_t);
@@ -6588,7 +6650,7 @@ extern tree build_x_binary_op                     (location_t,
 extern tree build_x_array_ref                  (location_t, tree, tree,
                                                 tsubst_flags_t);
 extern tree build_x_unary_op                   (location_t,
-                                                enum tree_code, tree,
+                                                enum tree_code, cp_expr,
                                                  tsubst_flags_t);
 extern tree cp_build_addr_expr                 (tree, tsubst_flags_t);
 extern tree cp_build_unary_op                   (enum tree_code, tree, int, 
@@ -6608,8 +6670,10 @@ extern tree build_static_cast                    (tree, tree, tsubst_flags_t);
 extern tree build_reinterpret_cast             (tree, tree, tsubst_flags_t);
 extern tree build_const_cast                   (tree, tree, tsubst_flags_t);
 extern tree build_c_cast                       (location_t, tree, tree);
+extern cp_expr build_c_cast                    (location_t loc, tree type,
+                                                cp_expr expr);
 extern tree cp_build_c_cast                    (tree, tree, tsubst_flags_t);
-extern tree build_x_modify_expr                        (location_t, tree,
+extern cp_expr build_x_modify_expr             (location_t, tree,
                                                 enum tree_code, tree,
                                                 tsubst_flags_t);
 extern tree cp_build_modify_expr               (tree, enum tree_code, tree,
index ebca00497e1d8f187db0054f0f1a5713325649f0..f24f28059ba44505f937527e1f275e186495edbd 100644 (file)
@@ -650,8 +650,8 @@ cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
       folded_result = fold_simple (folded_result);
       if (!TREE_OVERFLOW_P (folded)
          && folded_result != error_mark_node)
-       warnings_for_convert_and_check (input_location, type, folded,
-                                       folded_result);
+       warnings_for_convert_and_check (EXPR_LOC_OR_LOC (expr, input_location),
+                                       type, folded, folded_result);
     }
 
   return result;
index cebe57ead7756d12f3445a4818ed25a2f2eb7f9d..86c07ef02b2ff2ca855b8374d12ade5685e5aa6f 100644 (file)
@@ -5659,7 +5659,7 @@ arg_assoc (struct arg_lookup *k, tree n)
 /* Performs Koenig lookup depending on arguments, where fns
    are the functions found in normal lookup.  */
 
-static tree
+static cp_expr
 lookup_arg_dependent_1 (tree name, tree fns, vec<tree, va_gc> *args)
 {
   struct arg_lookup k;
@@ -5720,10 +5720,10 @@ lookup_arg_dependent_1 (tree name, tree fns, vec<tree, va_gc> *args)
 
 /* Wrapper for lookup_arg_dependent_1.  */
 
-tree
+cp_expr
 lookup_arg_dependent (tree name, tree fns, vec<tree, va_gc> *args)
 {
-  tree ret;
+  cp_expr ret;
   bool subtime;
   subtime = timevar_cond_start (TV_NAME_LOOKUP);
   ret = lookup_arg_dependent_1 (name, fns, args);
index d430edb73b74d4fa98266c0058feca1b5dcc05ac..d2453e95ec504338691990da324a0cd45f8b410b 100644 (file)
@@ -347,7 +347,7 @@ extern void do_toplevel_using_decl (tree, tree, tree);
 extern void do_local_using_decl (tree, tree, tree);
 extern tree do_class_using_decl (tree, tree);
 extern void do_using_directive (tree);
-extern tree lookup_arg_dependent (tree, tree, vec<tree, va_gc> *);
+extern cp_expr lookup_arg_dependent (tree, tree, vec<tree, va_gc> *);
 extern bool is_associated_namespace (tree, tree);
 extern void parse_using_directive (tree, tree);
 extern tree innermost_non_namespace_value (tree);
index 1c14354104518666908b1c95eef4fc91d7c344f6..17dba0d0dc66c97a6a13aa8172eaffe9717d784e 100644 (file)
@@ -733,6 +733,13 @@ cp_lexer_previous_token (cp_lexer *lexer)
 {
   cp_token_position tp = cp_lexer_previous_token_position (lexer);
 
+  /* Skip past purged tokens.  */
+  while (tp->purged_p)
+    {
+      gcc_assert (tp != lexer->buffer->address ());
+      tp--;
+    }
+
   return cp_lexer_token_at (lexer, tp);
 }
 
@@ -1793,7 +1800,7 @@ struct cp_parser_expression_stack_entry
 {
   /* 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;
@@ -1947,15 +1954,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]  */
@@ -1965,11 +1972,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);
@@ -1977,19 +1984,19 @@ 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);
 static tree cp_parser_postfix_dot_deref_expression
-  (cp_parser *, enum cpp_ttype, tree, bool, cp_id_kind *, location_t);
+  (cp_parser *, enum cpp_ttype, cp_expr, bool, cp_id_kind *, location_t);
 static vec<tree, va_gc> *cp_parser_parenthesized_expression_list
-  (cp_parser *, int, bool, bool, bool *);
+  (cp_parser *, int, bool, bool, bool *, location_t * = NULL);
 /* Values for the second parameter of cp_parser_parenthesized_expression_list.  */
 enum { non_attr = 0, normal_attr = 1, id_attr = 2 };
 static void cp_parser_pseudo_destructor_name
   (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 *);
@@ -2007,23 +2014,23 @@ 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
+static cp_expr cp_parser_binary_expression
   (cp_parser *, bool, bool, enum cp_parser_prec, cp_id_kind *);
 static tree cp_parser_question_colon_clause
-  (cp_parser *, tree);
-static tree cp_parser_assignment_expression
+  (cp_parser *, cp_expr);
+static cp_expr 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
+static cp_expr cp_parser_constant_expression
   (cp_parser *, bool = false, bool * = NULL);
-static tree cp_parser_builtin_offsetof
+static cp_expr 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);
@@ -2178,9 +2185,9 @@ static void cp_parser_function_body
   (cp_parser *, bool);
 static tree cp_parser_initializer
   (cp_parser *, bool *, bool *);
-static tree cp_parser_initializer_clause
+static cp_expr cp_parser_initializer_clause
   (cp_parser *, bool *);
-static tree cp_parser_braced_list
+static cp_expr cp_parser_braced_list
   (cp_parser*, bool*);
 static vec<constructor_elt, va_gc> *cp_parser_initializer_list
   (cp_parser *, bool *);
@@ -2249,9 +2256,9 @@ static tree cp_parser_mem_initializer_id
 
 /* Overloading [gram.over] */
 
-static tree cp_parser_operator_function_id
+static cp_expr cp_parser_operator_function_id
   (cp_parser *);
-static tree cp_parser_operator
+static cp_expr cp_parser_operator
   (cp_parser *);
 
 /* Templates [gram.temp] */
@@ -2389,7 +2396,7 @@ static tree cp_parser_objc_message_args
   (cp_parser *);
 static tree cp_parser_objc_message_expression
   (cp_parser *);
-static tree cp_parser_objc_encode_expression
+static cp_expr cp_parser_objc_encode_expression
   (cp_parser *);
 static tree cp_parser_objc_defs_expression
   (cp_parser *);
@@ -2397,7 +2404,7 @@ static tree cp_parser_objc_protocol_expression
   (cp_parser *);
 static tree cp_parser_objc_selector_expression
   (cp_parser *);
-static tree cp_parser_objc_expression
+static cp_expr cp_parser_objc_expression
   (cp_parser *);
 static bool cp_parser_objc_selector_p
   (enum cpp_ttype);
@@ -2422,7 +2429,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);
@@ -2432,7 +2439,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);
@@ -2448,7 +2455,7 @@ static void cp_parser_perform_template_parameter_access_checks
   (vec<deferred_access_check, va_gc> *);
 static tree cp_parser_single_declaration
   (cp_parser *, vec<deferred_access_check, va_gc> *, bool, bool, bool *);
-static tree cp_parser_functional_cast
+static cp_expr cp_parser_functional_cast
   (cp_parser *, tree);
 static tree cp_parser_save_member_function_body
   (cp_parser *, cp_decl_specifier_seq *, cp_declarator *, tree);
@@ -3681,7 +3688,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;
@@ -3689,7 +3696,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 (token->u.value, token->location);
+  else
+    return error_mark_node;
 }
 
 /* Parse a sequence of adjacent string constants.  Returns a
@@ -3706,7 +3716,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)
 {
@@ -3728,6 +3738,8 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
       return error_mark_node;
     }
 
+  location_t loc = tok->location;
+
   if (cpp_userdef_string_p (tok->type))
     {
       string_tree = USERDEF_LITERAL_VALUE (tok->u.value);
@@ -3765,11 +3777,13 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
     }
   else
     {
+      location_t last_tok_loc;
       gcc_obstack_init (&str_ob);
       count = 0;
 
       do
        {
+         last_tok_loc = tok->location;
          cp_lexer_consume_token (parser->lexer);
          count++;
          str.text = (const unsigned char *)TREE_STRING_POINTER (string_tree);
@@ -3824,6 +3838,11 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok,
        }
       while (cp_parser_is_string_literal (tok));
 
+      /* A string literal built by concatenation has its caret=start at
+        the start of the initial string, and its finish at the finish of
+        the final string literal.  */
+      loc = make_location (loc, loc, get_finish (last_tok_loc));
+
       strs = (cpp_string *) obstack_finish (&str_ob);
     }
 
@@ -3876,7 +3895,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 (value, loc);
 }
 
 /* Look up a literal operator with the name and the exact arguments.  */
@@ -3927,7 +3946,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);
@@ -4019,7 +4038,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);
@@ -4272,12 +4291,13 @@ cp_parser_end_tentative_firewall (cp_parser *parser, cp_token_position start,
 /* Parse a GNU statement-expression, i.e. ({ stmts }), except for the
    enclosing parentheses.  */
 
-static tree
+static cp_expr
 cp_parser_statement_expr (cp_parser *parser)
 {
   cp_token_position start = cp_parser_start_tentative_firewall (parser);
 
   /* Consume the '('.  */
+  location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
   cp_lexer_consume_token (parser->lexer);
   /* Start the statement-expression.  */
   tree expr = begin_stmt_expr ();
@@ -4286,11 +4306,13 @@ cp_parser_statement_expr (cp_parser *parser)
   /* Finish up.  */
   expr = finish_stmt_expr (expr, false);
   /* Consume the ')'.  */
+  location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
   if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
     cp_parser_skip_to_end_of_statement (parser);
 
   cp_parser_end_tentative_firewall (parser, start, expr);
-  return expr;
+  location_t combined_loc = make_location (start_loc, start_loc, finish_loc);
+  return cp_expr (expr, combined_loc);
 }
 
 /* Expressions [gram.expr] */
@@ -4420,7 +4442,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;
@@ -4540,7 +4562,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,
@@ -4625,7 +4647,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 (token->u.value, token->location);
 
     case CPP_CHAR_USERDEF:
     case CPP_CHAR16_USERDEF:
@@ -4683,9 +4705,11 @@ cp_parser_primary_expression (cp_parser *parser,
        }
       /* Otherwise it's a normal parenthesized expression.  */
       {
-       tree expr;
+       cp_expr expr;
        bool saved_greater_than_is_operator_p;
 
+       location_t open_paren_loc = token->location;
+
        /* Consume the `('.  */
        cp_lexer_consume_token (parser->lexer);
        /* Within a parenthesized expression, a `>' token is always
@@ -4730,7 +4754,11 @@ cp_parser_primary_expression (cp_parser *parser,
           template-parameter-list now.  */
        parser->greater_than_is_operator_p
          = saved_greater_than_is_operator_p;
+
        /* Consume the `)'.  */
+       token = cp_lexer_peek_token (parser->lexer);
+       location_t close_paren_loc = token->location;
+       expr.set_range (open_paren_loc, close_paren_loc);
        if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)
            && !cp_parser_uncommitted_to_tentative_parse_p (parser))
          cp_parser_skip_to_end_of_statement (parser);
@@ -4750,7 +4778,7 @@ 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;
@@ -4771,20 +4799,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:
@@ -4798,7 +4826,7 @@ cp_parser_primary_expression (cp_parser *parser,
          /* Pointers cannot appear in constant-expressions.  */
          if (cp_parser_non_integral_constant_expression (parser, NIC_THIS))
            return error_mark_node;
-         return finish_this_expr ();
+         return cp_expr (finish_this_expr (), token->location);
 
          /* The `operator' keyword can be the beginning of an
             id-expression.  */
@@ -4847,7 +4875,8 @@ cp_parser_primary_expression (cp_parser *parser,
            tree expression;
            tree type;
            source_location type_location;
-
+           location_t start_loc
+             = cp_lexer_peek_token (parser->lexer)->location;
            /* The `__builtin_va_arg' construct is used to handle
               `va_arg'.  Consume the `__builtin_va_arg' token.  */
            cp_lexer_consume_token (parser->lexer);
@@ -4861,13 +4890,22 @@ cp_parser_primary_expression (cp_parser *parser,
            /* Parse the type-id.  */
            type = cp_parser_type_id (parser);
            /* Look for the closing `)'.  */
+           location_t finish_loc
+             = cp_lexer_peek_token (parser->lexer)->location;
            cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
            /* Using `va_arg' in a constant-expression is not
               allowed.  */
            if (cp_parser_non_integral_constant_expression (parser,
                                                            NIC_VA_ARG))
              return error_mark_node;
-           return build_x_va_arg (type_location, expression, type);
+           /* Construct a location of the form:
+                __builtin_va_arg (v, int)
+                ~~~~~~~~~~~~~~~~~~~~~^~~~
+              with the caret at the type, ranging from the start of the
+              "__builtin_va_arg" token to the close paren.  */
+           location_t combined_loc
+             = make_location (type_location, start_loc, finish_loc);
+           return build_x_va_arg (combined_loc, expression, type);
          }
 
        case RID_OFFSETOF:
@@ -4932,14 +4970,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;
+       cp_expr decl;
        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,
@@ -5004,12 +5042,36 @@ cp_parser_primary_expression (cp_parser *parser,
                if (component == error_mark_node)
                  return error_mark_node;
 
-               return objc_build_class_component_ref (id_expression, component);
+               tree result = objc_build_class_component_ref (id_expression,
+                                                             component);
+               /* Build a location of the form:
+                    expr.component
+                    ~~~~~^~~~~~~~~
+                  with caret at the start of the component name (at
+                  input_location), ranging from the start of the id_expression
+                  to the end of the component name.  */
+               location_t combined_loc
+                 = make_location (input_location, id_expression.get_start (),
+                                  get_finish (input_location));
+               protected_set_expr_location (result, combined_loc);
+               return result;
              }
 
            /* In Objective-C++, an instance variable (ivar) may be preferred
-              to whatever cp_parser_lookup_name() found.  */
-           decl = objc_lookup_ivar (decl, id_expression);
+              to whatever cp_parser_lookup_name() found.
+              Call objc_lookup_ivar.  To avoid exposing cp_expr to the
+              rest of c-family, we have to do a little extra work to preserve
+              any location information in cp_expr "decl".  Given that
+              objc_lookup_ivar is implemented in "c-family" and "objc", we
+              have a trip through the pure "tree" type, rather than cp_expr.
+              Naively copying it back to "decl" would implicitly give the
+              new cp_expr value an UNKNOWN_LOCATION for nodes that don't
+              store an EXPR_LOCATION.  Hence we only update "decl" (and
+              hence its location_t) if we get back a different tree node.  */
+           tree decl_tree = objc_lookup_ivar (decl.get_value (),
+                                              id_expression);
+           if (decl_tree != decl.get_value ())
+             decl = cp_expr (decl_tree);
 
            /* If name lookup gives us a SCOPE_REF, then the
               qualifying scope was dependent.  */
@@ -5050,7 +5112,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;
                  }
              }
@@ -5068,6 +5130,7 @@ cp_parser_primary_expression (cp_parser *parser,
                  id_expr_token->location));
        if (error_msg)
          cp_parser_error (parser, error_msg);
+       decl.set_location (id_expr_token->location);
        return decl;
       }
 
@@ -5078,7 +5141,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,
@@ -5123,7 +5186,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,
@@ -5258,7 +5321,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,
@@ -5521,7 +5584,7 @@ cp_parser_unqualified_id (cp_parser* parser,
     case CPP_KEYWORD:
       if (token->keyword == RID_OPERATOR)
        {
-         tree id;
+         cp_expr id;
 
          /* This could be a template-id, so we try that first.  */
          cp_parser_parse_tentatively (parser);
@@ -6111,7 +6174,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)
@@ -6120,13 +6183,15 @@ 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;
 
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
   loc = token->location;
+  location_t start_loc = get_range_from_loc (line_table, loc).m_start;
+
   /* Some of the productions are determined by keywords.  */
   keyword = token->keyword;
   switch (keyword)
@@ -6137,7 +6202,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
     case RID_CONSTCAST:
       {
        tree type;
-       tree expression;
+       cp_expr expression;
        const char *saved_message;
        bool saved_in_type_id_in_expr_p;
 
@@ -6170,7 +6235,10 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
        /* And the expression which is being cast.  */
        cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
        expression = cp_parser_expression (parser, & idk, /*cast_p=*/true);
-       cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
+       cp_token *close_paren = cp_parser_require (parser, CPP_CLOSE_PAREN,
+                                                  RT_CLOSE_PAREN);
+       location_t end_loc = close_paren ?
+         close_paren->location : UNKNOWN_LOCATION;
 
        parser->greater_than_is_operator_p
          = saved_greater_than_is_operator_p;
@@ -6203,6 +6271,14 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
          default:
            gcc_unreachable ();
          }
+
+       /* Construct a location e.g. :
+            reinterpret_cast <int *> (expr)
+            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+          ranging from the start of the "*_cast" token to the final closing
+          paren, with the caret at the start.  */
+       location_t cp_cast_loc = make_location (start_loc, start_loc, end_loc);
+       postfix_expression.set_location (cp_cast_loc);
       }
       break;
 
@@ -6271,6 +6347,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 
     case RID_CILK_SPAWN:
       {
+       location_t cilk_spawn_loc
+         = cp_lexer_peek_token (parser->lexer)->location;
        cp_lexer_consume_token (parser->lexer);
        token = cp_lexer_peek_token (parser->lexer);
        if (token->type == CPP_SEMICOLON)
@@ -6312,8 +6390,17 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
          }
        else
          {
+           location_t loc = postfix_expression.get_location ();
            postfix_expression = build_cilk_spawn (token->location, 
                                                   postfix_expression);
+           /* Build a location of the form:
+                _Cilk_spawn expr
+                ~~~~~~~~~~~~^~~~
+              with caret at the expr, ranging from the start of the
+              _Cilk_spawn token to the end of the expression.  */
+           location_t combined_loc =
+             make_location (loc, cilk_spawn_loc, get_finish (loc));
+           postfix_expression.set_location (combined_loc);
            if (postfix_expression != error_mark_node) 
              SET_EXPR_LOCATION (postfix_expression, input_location);
            parser->in_statement = parser->in_statement & ~IN_CILK_SPAWN;
@@ -6380,7 +6467,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
        if (cp_parser_allow_gnu_extensions_p (parser)
            && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
          {
-           tree initializer = NULL_TREE;
+           cp_expr initializer = NULL_TREE;
 
            cp_parser_parse_tentatively (parser);
 
@@ -6435,6 +6522,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
                postfix_expression
                  = finish_compound_literal (type, initializer,
                                             tf_warning_or_error);
+               postfix_expression.set_location (initializer.get_location ());
                break;
              }
          }
@@ -6482,6 +6570,9 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
                                                        postfix_expression,
                                                        false,
                                                        decltype_p);
+         postfix_expression.set_range (start_loc,
+                                       postfix_expression.get_location ());
+
          idk = CP_ID_KIND_NONE;
           is_member_access = false;
          break;
@@ -6495,6 +6586,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
            bool saved_non_integral_constant_expression_p = false;
            tsubst_flags_t complain = complain_flags (decltype_p);
            vec<tree, va_gc> *args;
+           location_t close_paren_loc;
 
             is_member_access = false;
 
@@ -6513,7 +6605,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
            args = (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=*/&close_paren_loc));
            if (is_builtin_constant_p)
              {
                parser->integral_constant_expression_p
@@ -6655,7 +6748,10 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
                                    koenig_p,
                                    complain);
 
-           protected_set_expr_location (postfix_expression, token->location);
+           location_t combined_loc = make_location (token->location,
+                                                    start_loc,
+                                                    close_paren_loc);
+           postfix_expression.set_location (combined_loc);
 
            /* The POSTFIX_EXPRESSION is certainly no longer an id.  */
            idk = CP_ID_KIND_NONE;
@@ -6716,7 +6812,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;
        }
@@ -6916,7 +7014,7 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
 static tree
 cp_parser_postfix_dot_deref_expression (cp_parser *parser,
                                        enum cpp_ttype token_type,
-                                       tree postfix_expression,
+                                       cp_expr postfix_expression,
                                        bool for_offsetof, cp_id_kind *idk,
                                        location_t location)
 {
@@ -6924,6 +7022,7 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
   bool dependent_p;
   bool pseudo_destructor_p;
   tree scope = NULL_TREE;
+  location_t start_loc = postfix_expression.get_start ();
 
   /* If this is a `->' operator, dereference the pointer.  */
   if (token_type == CPP_DEREF)
@@ -6953,7 +7052,7 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
       if (scope == unknown_type_node)
        {
          error_at (location, "%qE does not have class type",
-                   postfix_expression);
+                   postfix_expression.get_value ());
          scope = NULL_TREE;
        }
       /* Unlike the object expression in other contexts, *this is not
@@ -7070,6 +7169,16 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
            = finish_class_member_access_expr (postfix_expression, name,
                                               template_p, 
                                               tf_warning_or_error);
+         /* Build a location e.g.:
+              ptr->access_expr
+              ~~~^~~~~~~~~~~~~
+            where the caret is at the deref token, ranging from
+            the start of postfix_expression to the end of the access expr.  */
+         location_t end_loc
+           = get_finish (cp_lexer_previous_token (parser->lexer)->location);
+         location_t combined_loc
+           = make_location (input_location, start_loc, end_loc);
+         protected_set_expr_location (postfix_expression, combined_loc);
        }
     }
 
@@ -7118,7 +7227,8 @@ cp_parser_parenthesized_expression_list (cp_parser* parser,
                                         int is_attribute_list,
                                         bool cast_p,
                                          bool allow_expansion_p,
-                                        bool *non_constant_p)
+                                        bool *non_constant_p,
+                                        location_t *close_paren_loc)
 {
   vec<tree, va_gc> *expression_list;
   bool fold_expr_p = is_attribute_list != non_attr;
@@ -7222,6 +7332,9 @@ cp_parser_parenthesized_expression_list (cp_parser* parser,
        cp_lexer_consume_token (parser->lexer);
       }
 
+  if (close_paren_loc)
+    *close_paren_loc = cp_lexer_peek_token (parser->lexer)->location;
+
   if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
     {
       int ending;
@@ -7391,7 +7504,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)
 {
@@ -7589,14 +7702,22 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
        {
          tree identifier;
          tree expression;
-         location_t loc = token->location;
+         location_t start_loc = token->location;
 
          /* Consume the '&&' token.  */
          cp_lexer_consume_token (parser->lexer);
          /* Look for the identifier.  */
+         location_t finish_loc
+           = get_finish (cp_lexer_peek_token (parser->lexer)->location);
          identifier = cp_parser_identifier (parser);
+         /* Construct a location of the form:
+              &&label
+              ^~~~~~~
+            with caret==start at the "&&", finish at the end of the label.  */
+         location_t combined_loc
+           = make_location (start_loc, start_loc, finish_loc);
          /* Create an expression representing the address.  */
-         expression = finish_label_address_expr (identifier, loc);
+         expression = finish_label_address_expr (identifier, combined_loc);
          if (cp_parser_non_integral_constant_expression (parser,
                                                          NIC_ADDR_LABEL))
            expression = error_mark_node;
@@ -7605,8 +7726,8 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
     }
   if (unary_operator != ERROR_MARK)
     {
-      tree cast_expression;
-      tree expression = error_mark_node;
+      cp_expr cast_expression;
+      cp_expr expression = error_mark_node;
       non_integral_constant non_constant_p = NIC_NONE;
       location_t loc = token->location;
       tsubst_flags_t complain = complain_flags (decltype_p);
@@ -7622,6 +7743,14 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
                                     /*cast_p=*/false,
                                     /*decltype*/false,
                                     pidk);
+
+      /* Make a location:
+           OP_TOKEN  CAST_EXPRESSION
+           ^~~~~~~~~~~~~~~~~~~~~~~~~
+        with start==caret at the operator token, and
+        extending to the end of the cast_expression.  */
+      loc = make_location (loc, loc, cast_expression.get_finish ());
+
       /* Now, build an appropriate representation.  */
       switch (unary_operator)
        {
@@ -7630,6 +7759,9 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
          expression = build_x_indirect_ref (loc, cast_expression,
                                             RO_UNARY_STAR,
                                              complain);
+          /* TODO: build_x_indirect_ref does not always honor the
+             location, so ensure it is set.  */
+          expression.set_location (loc);
          break;
 
        case ADDR_EXPR:
@@ -7639,6 +7771,9 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
          expression = build_x_unary_op (loc, unary_operator,
                                         cast_expression,
                                          complain);
+          /* TODO: build_x_unary_op does not always honor the location,
+             so ensure it is set.  */
+          expression.set_location (loc);
          break;
 
        case PREINCREMENT_EXPR:
@@ -7659,7 +7794,7 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
                                         cast_expression);
              if (CONSTANT_CLASS_P (folded) && !TREE_OVERFLOW (folded))
                {
-                 expression = folded;
+                 expression = cp_expr (folded, loc);
                  break;
                }
            }
@@ -7737,6 +7872,8 @@ cp_parser_new_expression (cp_parser* parser)
   tree nelts = NULL_TREE;
   tree ret;
 
+  location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
+
   /* Look for the optional `::' operator.  */
   global_scope_p
     = (cp_parser_global_scope_opt (parser,
@@ -7821,9 +7958,19 @@ cp_parser_new_expression (cp_parser* parser)
     }
   else
     {
+      /* Construct a location e.g.:
+           ptr = new int[100]
+                 ^~~~~~~~~~~~
+         with caret == start at the start of the "new" token, and the end
+         at the end of the final token we consumed.  */
+      cp_token *end_tok = cp_lexer_previous_token (parser->lexer);
+      location_t end_loc = get_finish (end_tok->location);
+      location_t combined_loc = make_location (start_loc, start_loc, end_loc);
+
       /* Create a representation of the new-expression.  */
       ret = build_new (&placement, type, nelts, &initializer, global_scope_p,
                       tf_warning_or_error);
+      protected_set_expr_location (ret, combined_loc);
     }
 
   if (placement != NULL)
@@ -8203,7 +8350,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)
 {
@@ -8211,7 +8358,7 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p,
   if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
     {
       tree type = NULL_TREE;
-      tree expr = NULL_TREE;
+      cp_expr expr (NULL_TREE);
       int cast_expression = 0;
       const char *saved_message;
 
@@ -8224,7 +8371,9 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p,
       parser->type_definition_forbidden_message
        = G_("types may not be defined in casts");
       /* Consume the `('.  */
-      cp_lexer_consume_token (parser->lexer);
+      cp_token *open_paren = cp_lexer_consume_token (parser->lexer);
+      location_t open_paren_loc = open_paren->location;
+
       /* A very tricky bit is that `(struct S) { 3 }' is a
         compound-literal (which we permit in C++ as an extension).
         But, that construct is not a cast-expression -- it is a
@@ -8326,7 +8475,15 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p,
                return error_mark_node;
 
              /* Perform the cast.  */
-             expr = build_c_cast (input_location, type, expr);
+             /* Make a location:
+                  (TYPE) EXPR
+                  ^~~~~~~~~~~
+                with start==caret at the open paren, extending to the
+                end of "expr".  */
+             location_t cast_loc = make_location (open_paren_loc,
+                                                  open_paren_loc,
+                                                  expr.get_finish ());
+             expr = build_c_cast (cast_loc, type, expr);
              return expr;
            }
        }
@@ -8419,7 +8576,7 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p,
  ? PREC_NOT_OPERATOR                                        \
  : binops_by_token[token->type].prec)
 
-static tree
+static cp_expr
 cp_parser_binary_expression (cp_parser* parser, bool cast_p,
                             bool no_toplevel_fold_p,
                             bool decltype_p,
@@ -8429,7 +8586,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;
   cp_token *token;
   enum tree_code rhs_type;
   enum cp_parser_prec new_prec, lookahead_prec;
@@ -8569,6 +8726,11 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
                                      maybe_constant_value (rhs));
 
       overload = NULL;
+
+      location_t combined_loc = make_location (current.loc,
+                                              current.lhs.get_start (),
+                                              rhs.get_finish ());
+
       /* ??? 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
@@ -8579,18 +8741,22 @@ 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),
+                                 current.lhs, rhs);
       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, current.lhs_type,
+                                           rhs, rhs_type, &overload,
+                                           complain_flags (decltype_p));
+          /* TODO: build_x_binary_op doesn't always honor the location.  */
+          current.lhs.set_location (combined_loc);
+        }
       current.lhs_type = current.tree_type;
-      protected_set_expr_location (current.lhs, current.loc);
 
       /* If the binary operator required the use of an overloaded operator,
         then this expression cannot be an integral constant-expression.
@@ -8607,7 +8773,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
   return current.lhs;
 }
 
-static tree
+static cp_expr
 cp_parser_binary_expression (cp_parser* parser, bool cast_p,
                             bool no_toplevel_fold_p,
                             enum cp_parser_prec prec,
@@ -8631,10 +8797,10 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
      ? : assignment-expression */
 
 static tree
-cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
+cp_parser_question_colon_clause (cp_parser* parser, cp_expr logical_or_expr)
 {
   tree expr, folded_logical_or_expr = cp_fully_fold (logical_or_expr);
-  tree assignment_expr;
+  cp_expr assignment_expr;
   struct cp_token *token;
   location_t loc = cp_lexer_peek_token (parser->lexer)->location;
 
@@ -8673,6 +8839,15 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
   c_inhibit_evaluation_warnings -=
     folded_logical_or_expr == truthvalue_true_node;
 
+  /* Make a location:
+       LOGICAL_OR_EXPR ? EXPR : ASSIGNMENT_EXPR
+       ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
+     with the caret at the "?", ranging from the start of
+     the logical_or_expr to the end of the assignment_expr.  */
+  loc = make_location (loc,
+                      logical_or_expr.get_start (),
+                      assignment_expr.get_finish ());
+
   /* Build the conditional-expression.  */
   return build_x_conditional_expr (loc, logical_or_expr,
                                   expr,
@@ -8692,11 +8867,11 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
 
    Returns a representation for the expression.  */
 
-static tree
+static cp_expr
 cp_parser_assignment_expression (cp_parser* parser, cp_id_kind * pidk,
                                 bool cast_p, bool decltype_p)
 {
-  tree expr;
+  cp_expr expr;
 
   /* If the next token is the `throw' keyword, then we're looking at
      a throw-expression.  */
@@ -8725,10 +8900,10 @@ cp_parser_assignment_expression (cp_parser* parser, cp_id_kind * pidk,
          if (assignment_operator != ERROR_MARK)
            {
              bool non_constant_p;
-             location_t saved_input_location;
 
              /* Parse the right-hand side of the assignment.  */
-             tree rhs = cp_parser_initializer_clause (parser, &non_constant_p);
+             cp_expr rhs = cp_parser_initializer_clause (parser,
+                                                         &non_constant_p);
 
              if (BRACE_ENCLOSED_INITIALIZER_P (rhs))
                maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
@@ -8739,14 +8914,22 @@ cp_parser_assignment_expression (cp_parser* parser, cp_id_kind * pidk,
                                                              NIC_ASSIGNMENT))
                return error_mark_node;
              /* Build the assignment expression.  Its default
-                location is the location of the '=' token.  */
-             saved_input_location = input_location;
-             input_location = loc;
+                location:
+                  LHS = RHS
+                  ~~~~^~~~~
+                is the location of the '=' token as the
+                caret, ranging from the start of the lhs to the
+                end of the rhs.  */
+             loc = make_location (loc,
+                                  expr.get_start (),
+                                  rhs.get_finish ());
              expr = build_x_modify_expr (loc, expr,
                                          assignment_operator,
                                          rhs,
                                          complain_flags (decltype_p));
-             input_location = saved_input_location;
+              /* TODO: build_x_modify_expr doesn't honor the location,
+                 so we must set it here.  */
+              expr.set_location (loc);
            }
        }
     }
@@ -8855,16 +9038,16 @@ 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)
 {
-  tree expression = NULL_TREE;
+  cp_expr expression = NULL_TREE;
   location_t loc = UNKNOWN_LOCATION;
 
   while (true)
     {
-      tree assignment_expression;
+      cp_expr assignment_expression;
 
       /* Parse the next assignment-expression.  */
       assignment_expression
@@ -8886,9 +9069,17 @@ cp_parser_expression (cp_parser* parser, cp_id_kind * pidk,
       if (!expression)
        expression = assignment_expression;
       else
-       expression = build_x_compound_expr (loc, expression,
-                                           assignment_expression,
-                                           complain_flags (decltype_p));
+       {
+         /* Create a location with caret at the comma, ranging
+            from the start of the LHS to the end of the RHS.  */
+         loc = make_location (loc,
+                              expression.get_start (),
+                              assignment_expression.get_finish ());
+         expression = build_x_compound_expr (loc, expression,
+                                             assignment_expression,
+                                             complain_flags (decltype_p));
+         expression.set_location (loc);
+       }
       /* If the next token is not a comma, or we're in a fold-expression, then
         we are done with the expression.  */
       if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)
@@ -8915,7 +9106,7 @@ cp_parser_expression (cp_parser* parser, cp_id_kind * pidk,
   constant, *NON_CONSTANT_P is set to TRUE.  If ALLOW_NON_CONSTANT_P
   is false, NON_CONSTANT_P should be NULL.  */
 
-static tree
+static cp_expr
 cp_parser_constant_expression (cp_parser* parser,
                               bool allow_non_constant_p,
                               bool *non_constant_p)
@@ -8923,7 +9114,7 @@ cp_parser_constant_expression (cp_parser* parser,
   bool saved_integral_constant_expression_p;
   bool saved_allow_non_integral_constant_expression_p;
   bool saved_non_integral_constant_expression_p;
-  tree expression;
+  cp_expr expression;
 
   /* It might seem that we could simply parse the
      conditional-expression, and then check to see if it were
@@ -8996,13 +9187,15 @@ cp_parser_constant_expression (cp_parser* parser,
      | offsetof-member-designator "[" expression "]"
      | offsetof-member-designator "->" id-expression  */
 
-static tree
+static cp_expr
 cp_parser_builtin_offsetof (cp_parser *parser)
 {
   int save_ice_p, save_non_ice_p;
-  tree type, expr;
+  tree type;
+  cp_expr expr;
   cp_id_kind dummy;
   cp_token *token;
+  location_t finish_loc;
 
   /* We're about to accept non-integral-constant things, but will
      definitely yield an integral constant expression.  Save and
@@ -9010,6 +9203,8 @@ cp_parser_builtin_offsetof (cp_parser *parser)
   save_ice_p = parser->integral_constant_expression_p;
   save_non_ice_p = parser->non_integral_constant_expression_p;
 
+  location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
+
   /* Consume the "__builtin_offsetof" token.  */
   cp_lexer_consume_token (parser->lexer);
   /* Consume the opening `('.  */
@@ -9055,6 +9250,7 @@ cp_parser_builtin_offsetof (cp_parser *parser)
 
        case CPP_CLOSE_PAREN:
          /* Consume the ")" token.  */
+         finish_loc = cp_lexer_peek_token (parser->lexer)->location;
          cp_lexer_consume_token (parser->lexer);
          goto success;
 
@@ -9069,7 +9265,15 @@ cp_parser_builtin_offsetof (cp_parser *parser)
     }
 
  success:
-  expr = finish_offsetof (expr, loc);
+  /* Make a location of the form:
+       __builtin_offsetof (struct s, f)
+       ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~
+     with caret at the type-id, ranging from the start of the
+     "_builtin_offsetof" token to the close paren.  */
+  loc = make_location (loc, start_loc, finish_loc);
+  /* The result will be an INTEGER_CST, so we need to explicitly
+     preserve the location.  */
+  expr = cp_expr (finish_offsetof (expr, loc), loc);
 
  failure:
   parser->integral_constant_expression_p = save_ice_p;
@@ -9293,7 +9497,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 ();
@@ -13290,7 +13494,7 @@ cp_parser_mem_initializer_id (cp_parser* parser)
    Returns an IDENTIFIER_NODE for the operator which is a
    human-readable spelling of the identifier, e.g., `operator +'.  */
 
-static tree
+static cp_expr
 cp_parser_operator_function_id (cp_parser* parser)
 {
   /* Look for the `operator' keyword.  */
@@ -13330,7 +13534,7 @@ cp_literal_operator_id (const char* name)
    Returns an IDENTIFIER_NODE for the operator which is a
    human-readable spelling of the identifier, e.g., `operator +'.  */
 
-static tree
+static cp_expr
 cp_parser_operator (cp_parser* parser)
 {
   tree id = NULL_TREE;
@@ -13339,6 +13543,9 @@ cp_parser_operator (cp_parser* parser)
 
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
+
+  location_t start_loc = token->location;
+
   /* Figure out which operator we have.  */
   switch (token->type)
     {
@@ -13355,7 +13562,7 @@ cp_parser_operator (cp_parser* parser)
          break;
 
        /* Consume the `new' or `delete' token.  */
-       cp_lexer_consume_token (parser->lexer);
+       location_t end_loc = cp_lexer_consume_token (parser->lexer)->location;
 
        /* Peek at the next token.  */
        token = cp_lexer_peek_token (parser->lexer);
@@ -13366,7 +13573,8 @@ cp_parser_operator (cp_parser* parser)
            /* Consume the `[' token.  */
            cp_lexer_consume_token (parser->lexer);
            /* Look for the `]' token.  */
-           cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
+           end_loc = cp_parser_require (parser, CPP_CLOSE_SQUARE,
+                                         RT_CLOSE_SQUARE)->location;
            id = ansi_opname (op == NEW_EXPR
                              ? VEC_NEW_EXPR : VEC_DELETE_EXPR);
          }
@@ -13374,7 +13582,9 @@ cp_parser_operator (cp_parser* parser)
        else
          id = ansi_opname (op);
 
-       return id;
+       location_t loc = make_location (start_loc, start_loc, end_loc);
+
+       return cp_expr (id, loc);
       }
 
     case CPP_PLUS:
@@ -13620,7 +13830,7 @@ cp_parser_operator (cp_parser* parser)
       id = error_mark_node;
     }
 
-  return id;
+  return cp_expr (id, start_loc);
 }
 
 /* Parse a template-declaration.
@@ -14530,6 +14740,18 @@ cp_parser_template_id (cp_parser *parser,
 
       /* Reset the contents of the START_OF_ID token.  */
       token->type = CPP_TEMPLATE_ID;
+
+      /* Update the location to be of the form:
+          template-name < template-argument-list [opt] >
+          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+        with caret == start at the start of the template-name,
+        ranging until the closing '>'.  */
+      location_t finish_loc
+       = get_finish (cp_lexer_previous_token (parser->lexer)->location);
+      location_t combined_loc
+       = make_location (token->location, token->location, finish_loc);
+      token->location = combined_loc;
+
       /* Retrieve any deferred checks.  Do not pop this access checks yet
         so the memory will not be reclaimed during token replacing below.  */
       token->u.tree_check_value = ggc_cleared_alloc<struct tree_check> ();
@@ -20316,10 +20538,10 @@ cp_parser_initializer (cp_parser* parser, bool* is_direct_init,
 
    Otherwise, calls cp_parser_braced_list.  */
 
-static tree
+static cp_expr
 cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p)
 {
-  tree initializer;
+  cp_expr initializer;
 
   /* Assume the expression is constant.  */
   *non_constant_p = false;
@@ -20352,10 +20574,11 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p)
    trailing `,' was provided.  NON_CONSTANT_P is as for
    cp_parser_initializer.  */     
 
-static tree
+static cp_expr
 cp_parser_braced_list (cp_parser* parser, bool* non_constant_p)
 {
   tree initializer;
+  location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
 
   /* Consume the `{' token.  */
   cp_lexer_consume_token (parser->lexer);
@@ -20374,9 +20597,18 @@ cp_parser_braced_list (cp_parser* parser, bool* non_constant_p)
   else
     *non_constant_p = false;
   /* Now, there should be a trailing `}'.  */
+  location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
   cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
   TREE_TYPE (initializer) = init_list_type_node;
-  return initializer;
+
+  cp_expr result (initializer);
+  /* Build a location of the form:
+       { ... }
+       ^~~~~~~
+     with caret==start at the open brace, finish at the close brace.  */
+  location_t combined_loc = make_location (start_loc, start_loc, finish_loc);
+  result.set_location (combined_loc);
+  return result;
 }
 
 /* Consume tokens up to, and including, the next non-nested closing `]'.
@@ -24077,7 +24309,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,
@@ -24319,7 +24551,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
@@ -25323,7 +25555,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,
@@ -25333,14 +25565,16 @@ cp_parser_simple_cast_expression (cp_parser *parser)
 /* Parse a functional cast to TYPE.  Returns an expression
    representing the cast.  */
 
-static tree
+static cp_expr
 cp_parser_functional_cast (cp_parser* parser, tree type)
 {
   vec<tree, va_gc> *vec;
   tree expression_list;
-  tree cast;
+  cp_expr cast;
   bool nonconst_p;
 
+  location_t start_loc = input_location;
+
   if (!type)
     type = error_mark_node;
 
@@ -25352,9 +25586,21 @@ cp_parser_functional_cast (cp_parser* parser, tree type)
       CONSTRUCTOR_IS_DIRECT_INIT (expression_list) = 1;
       if (TREE_CODE (type) == TYPE_DECL)
        type = TREE_TYPE (type);
-      return finish_compound_literal (type, expression_list,
+
+      cast = finish_compound_literal (type, expression_list,
                                      tf_warning_or_error);
-    }
+      /* Create a location of the form:
+           type_name{i, f}
+           ^~~~~~~~~~~~~~~
+        with caret == start at the start of the type name,
+        finishing at the closing brace.  */
+      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);
+      cast.set_location (combined_loc);
+      return cast;
+   }
 
 
   vec = cp_parser_parenthesized_expression_list (parser, non_attr,
@@ -25380,6 +25626,16 @@ cp_parser_functional_cast (cp_parser* parser, tree type)
       && cp_parser_non_integral_constant_expression (parser,
                                                     NIC_CONSTRUCTOR))
     return error_mark_node;
+
+  /* Create a location of the form:
+       float(i)
+       ^~~~~~~~
+     with caret == start at the start of the type name,
+     finishing at the closing paren.  */
+  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);
+  cast.set_location (combined_loc);
   return cast;
 }
 
@@ -27133,7 +27389,7 @@ cp_parser_allow_gnu_extensions_p (cp_parser* parser)
 
   Returns a tree representation of the expression.  */
 
-static tree
+static cp_expr
 cp_parser_objc_expression (cp_parser* parser)
 {
   /* Try to figure out what kind of declaration is present.  */
@@ -27185,12 +27441,23 @@ cp_parser_objc_message_expression (cp_parser* parser)
 {
   tree receiver, messageargs;
 
+  location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
   cp_lexer_consume_token (parser->lexer);  /* Eat '['.  */
   receiver = cp_parser_objc_message_receiver (parser);
   messageargs = cp_parser_objc_message_args (parser);
+  location_t end_loc = cp_lexer_peek_token (parser->lexer)->location;
   cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
 
-  return objc_build_message_expr (receiver, messageargs);
+  tree result = objc_build_message_expr (receiver, messageargs);
+
+  /* Construct a location e.g.
+       [self func1:5]
+       ^~~~~~~~~~~~~~
+     ranging from the '[' to the ']', with the caret at the start.  */
+  location_t combined_loc = make_location (start_loc, start_loc, end_loc);
+  protected_set_expr_location (result, combined_loc);
+
+  return result;
 }
 
 /* Parse an objc-message-receiver.
@@ -27307,11 +27574,12 @@ cp_parser_objc_message_args (cp_parser* parser)
 
    Returns an encoded representation of the type argument.  */
 
-static tree
+static cp_expr
 cp_parser_objc_encode_expression (cp_parser* parser)
 {
   tree type;
   cp_token *token;
+  location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
 
   cp_lexer_consume_token (parser->lexer);  /* Eat '@encode'.  */
   cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
@@ -27339,7 +27607,16 @@ cp_parser_objc_encode_expression (cp_parser* parser)
       return value;
     }
 
-  return objc_build_encode_expr (type);
+
+  /* Build a location of the form:
+       @encode(int)
+       ^~~~~~~~~~~~
+     with caret==start at the @ token, finishing at the close paren.  */
+  location_t combined_loc
+    = make_location (start_loc, start_loc,
+                     cp_lexer_previous_token (parser->lexer)->location);
+
+  return cp_expr (objc_build_encode_expr (type), combined_loc);
 }
 
 /* Parse an Objective-C @defs expression.  */
@@ -27368,13 +27645,23 @@ static tree
 cp_parser_objc_protocol_expression (cp_parser* parser)
 {
   tree proto;
+  location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
 
   cp_lexer_consume_token (parser->lexer);  /* Eat '@protocol'.  */
   cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
   proto = cp_parser_identifier (parser);
   cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
 
-  return objc_build_protocol_expr (proto);
+  /* Build a location of the form:
+       @protocol(prot)
+       ^~~~~~~~~~~~~~~
+     with caret==start at the @ token, finishing at the close paren.  */
+  location_t combined_loc
+    = make_location (start_loc, start_loc,
+                     cp_lexer_previous_token (parser->lexer)->location);
+  tree result = objc_build_protocol_expr (proto);
+  protected_set_expr_location (result, combined_loc);
+  return result;
 }
 
 /* Parse an Objective-C selector expression.
@@ -27450,7 +27737,18 @@ cp_parser_objc_selector_expression (cp_parser* parser)
  finish_selector:
   cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
 
-  return objc_build_selector_expr (loc, sel_seq);
+
+  /* Build a location of the form:
+       @selector(func)
+       ^~~~~~~~~~~~~~~
+     with caret==start at the @ token, finishing at the close paren.  */
+  location_t combined_loc
+    = make_location (loc, loc,
+                     cp_lexer_previous_token (parser->lexer)->location);
+  tree result = objc_build_selector_expr (combined_loc, sel_seq);
+  /* TODO: objc_build_selector_expr doesn't always honor the location.  */
+  protected_set_expr_location (result, combined_loc);
+  return result;
 }
 
 /* Parse a list of identifiers.
@@ -32560,7 +32858,8 @@ cp_parser_omp_for_cond (cp_parser *parser, tree decl, enum tree_code code)
          || CLASS_TYPE_P (TREE_TYPE (decl))))
     return cond;
 
-  return build_x_binary_op (input_location, TREE_CODE (cond),
+  return build_x_binary_op (EXPR_LOC_OR_LOC (cond, input_location),
+                           TREE_CODE (cond),
                            TREE_OPERAND (cond, 0), ERROR_MARK,
                            TREE_OPERAND (cond, 1), ERROR_MARK,
                            /*overload=*/NULL, tf_warning_or_error);
@@ -36287,16 +36586,18 @@ cp_parser_transaction_expression (cp_parser *parser, enum rid keyword)
   cp_token *token;
   tree expr, noex;
   bool noex_expr;
+  location_t loc = cp_lexer_peek_token (parser->lexer)->location;
 
   gcc_assert (keyword == RID_TRANSACTION_ATOMIC
       || keyword == RID_TRANSACTION_RELAXED);
 
   if (!flag_tm)
-    error (keyword == RID_TRANSACTION_RELAXED
-          ? G_("%<__transaction_relaxed%> without transactional memory "
-               "support enabled")
-          : G_("%<__transaction_atomic%> without transactional memory "
-               "support enabled"));
+    error_at (loc,
+             keyword == RID_TRANSACTION_RELAXED
+             ? G_("%<__transaction_relaxed%> without transactional memory "
+                 "support enabled")
+             : G_("%<__transaction_atomic%> without transactional memory "
+                  "support enabled"));
 
   token = cp_parser_require_keyword (parser, keyword,
       (keyword == RID_TRANSACTION_ATOMIC ? RT_TRANSACTION_ATOMIC
index 3bb61847ca80e02dcd5e0a65ffeef902c0e859c3..82f7d3a2c5ed8ea5ca10319604ade1025d81b106 100644 (file)
@@ -1672,8 +1672,8 @@ force_paren_expr (tree expr)
 
 /* Finish a parenthesized expression EXPR.  */
 
-tree
-finish_parenthesized_expr (tree expr)
+cp_expr
+finish_parenthesized_expr (cp_expr expr)
 {
   if (EXPR_P (expr))
     /* This inhibits warnings in c_common_truthvalue_conversion.  */
@@ -1688,7 +1688,7 @@ finish_parenthesized_expr (tree expr)
   if (TREE_CODE (expr) == STRING_CST)
     PAREN_STRING_LITERAL_P (expr) = 1;
 
-  expr = force_paren_expr (expr);
+  expr = cp_expr (force_paren_expr (expr), expr.get_location ());
 
   return expr;
 }
@@ -2164,8 +2164,8 @@ empty_expr_stmt_p (tree expr_stmt)
    the function (or functions) to call; ARGS are the arguments to the
    call.  Returns the functions to be considered by overload resolution.  */
 
-tree
-perform_koenig_lookup (tree fn, vec<tree, va_gc> *args,
+cp_expr
+perform_koenig_lookup (cp_expr fn, vec<tree, va_gc> *args,
                       tsubst_flags_t complain)
 {
   tree identifier = NULL_TREE;
@@ -2460,10 +2460,23 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
    is indicated by CODE, which should be POSTINCREMENT_EXPR or
    POSTDECREMENT_EXPR.)  */
 
-tree
-finish_increment_expr (tree expr, enum tree_code code)
-{
-  return build_x_unary_op (input_location, code, expr, tf_warning_or_error);
+cp_expr
+finish_increment_expr (cp_expr expr, enum tree_code code)
+{
+  /* input_location holds the location of the trailing operator token.
+     Build a location of the form:
+       expr++
+       ~~~~^~
+     with the caret at the operator token, ranging from the start
+     of EXPR to the end of the operator token.  */
+  location_t combined_loc = make_location (input_location,
+                                          expr.get_start (),
+                                          get_finish (input_location));
+  cp_expr result = build_x_unary_op (combined_loc, code, expr,
+                                    tf_warning_or_error);
+  /* TODO: build_x_unary_op doesn't honor the location, so set it here.  */
+  result.set_location (combined_loc);
+  return result;
 }
 
 /* Finish a use of `this'.  Returns an expression for `this'.  */
@@ -2557,11 +2570,21 @@ finish_pseudo_destructor_expr (tree object, tree scope, tree destructor,
 
 /* Finish an expression of the form CODE EXPR.  */
 
-tree
-finish_unary_op_expr (location_t loc, enum tree_code code, tree expr,
+cp_expr
+finish_unary_op_expr (location_t op_loc, enum tree_code code, cp_expr expr,
                      tsubst_flags_t complain)
 {
-  tree result = build_x_unary_op (loc, code, expr, complain);
+  /* Build a location of the form:
+       ++expr
+       ^~~~~~
+     with the caret at the operator token, ranging from the start
+     of the operator token to the end of EXPR.  */
+  location_t combined_loc = make_location (op_loc,
+                                          op_loc, expr.get_finish ());
+  cp_expr result = build_x_unary_op (combined_loc, code, expr, complain);
+  /* TODO: build_x_unary_op doesn't always honor the location.  */
+  result.set_location (combined_loc);
+
   tree result_ovl, expr_ovl;
 
   if (!(complain & tf_warning))
@@ -2581,7 +2604,7 @@ finish_unary_op_expr (location_t loc, enum tree_code code, tree expr,
     result_ovl = cp_fully_fold (result_ovl);
 
   if (CONSTANT_CLASS_P (result_ovl) && TREE_OVERFLOW_P (result_ovl))
-    overflow_warning (input_location, result_ovl);
+    overflow_warning (combined_loc, result_ovl);
 
   return result;
 }
@@ -3324,7 +3347,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,
@@ -3669,7 +3692,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
index 1d2943f50fb1d1f286f0453dff020fa6328459a4..0a1e446c95cc001323194ef2be9709fe7f09ed36 100644 (file)
@@ -2261,7 +2261,7 @@ lookup_anon_field (tree t, tree type)
    functions indicated by MEMBER.  */
 
 tree
-build_class_member_access_expr (tree object, tree member,
+build_class_member_access_expr (cp_expr object, tree member,
                                tree access_path, bool preserve_reference,
                                tsubst_flags_t complain)
 {
@@ -2291,10 +2291,10 @@ build_class_member_access_expr (tree object, tree member,
              && CLASS_TYPE_P (TREE_TYPE (object_type)))
            error ("request for member %qD in %qE, which is of pointer "
                   "type %qT (maybe you meant to use %<->%> ?)",
-                  member, object, object_type);
+                  member, object.get_value (), object_type);
          else
            error ("request for member %qD in %qE, which is of non-class "
-                  "type %qT", member, object, object_type);
+                  "type %qT", member, object.get_value (), object_type);
        }
       return error_mark_node;
     }
@@ -2624,7 +2624,7 @@ check_template_keyword (tree decl)
    be a template via the use of the "A::template B" syntax.  */
 
 tree
-finish_class_member_access_expr (tree object, tree name, bool template_p,
+finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
                                 tsubst_flags_t complain)
 {
   tree expr;
@@ -2658,7 +2658,7 @@ finish_class_member_access_expr (tree object, tree name, bool template_p,
              && TYPE_P (TREE_OPERAND (name, 0))
              && dependent_type_p (TREE_OPERAND (name, 0))))
        return build_min_nt_loc (UNKNOWN_LOCATION, COMPONENT_REF,
-                                object, name, NULL_TREE);
+                                object.get_value (), name, NULL_TREE);
       object = build_non_dependent_expr (object);
     }
   else if (c_dialect_objc ()
@@ -2681,10 +2681,10 @@ finish_class_member_access_expr (tree object, tree name, bool template_p,
              && CLASS_TYPE_P (TREE_TYPE (object_type)))
            error ("request for member %qD in %qE, which is of pointer "
                   "type %qT (maybe you meant to use %<->%> ?)",
-                  name, object, object_type);
+                  name, object.get_value (), object_type);
          else
            error ("request for member %qD in %qE, which is of non-class "
-                  "type %qT", name, object, object_type);
+                  "type %qT", name, object.get_value (), object_type);
        }
       return error_mark_node;
     }
@@ -5111,7 +5111,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);
   if (final_type != 0)
     result = cp_convert (final_type, result, complain);
 
@@ -5269,7 +5269,7 @@ pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain)
    and XARG is the operand.  */
 
 tree
-build_x_unary_op (location_t loc, enum tree_code code, tree xarg,
+build_x_unary_op (location_t loc, enum tree_code code, cp_expr xarg,
                  tsubst_flags_t complain)
 {
   tree orig_expr = xarg;
@@ -5279,7 +5279,7 @@ build_x_unary_op (location_t loc, enum tree_code code, tree xarg,
   if (processing_template_decl)
     {
       if (type_dependent_expression_p (xarg))
-       return build_min_nt_loc (loc, code, xarg, NULL_TREE);
+       return build_min_nt_loc (loc, code, xarg.get_value (), NULL_TREE);
 
       xarg = build_non_dependent_expr (xarg);
     }
@@ -5314,7 +5314,7 @@ build_x_unary_op (location_t loc, enum tree_code code, tree xarg,
                error (DECL_CONSTRUCTOR_P (fn)
                       ? G_("taking address of constructor %qE")
                       : G_("taking address of destructor %qE"),
-                      xarg);
+                      xarg.get_value ());
              return error_mark_node;
            }
        }
@@ -5330,7 +5330,7 @@ build_x_unary_op (location_t loc, enum tree_code code, tree xarg,
              if (complain & tf_error)
                {
                  error ("invalid use of %qE to form a "
-                        "pointer-to-member-function", xarg);
+                        "pointer-to-member-function", xarg.get_value ());
                  if (TREE_CODE (xarg) != OFFSET_REF)
                    inform (input_location, "  a qualified-id is required");
                }
@@ -5341,7 +5341,7 @@ build_x_unary_op (location_t loc, enum tree_code code, tree xarg,
              if (complain & tf_error)
                error ("parentheses around %qE cannot be used to form a"
                       " pointer-to-member-function",
-                      xarg);
+                      xarg.get_value ());
              else
                return error_mark_node;
              PTRMEM_OK_P (xarg) = 1;
@@ -5438,7 +5438,7 @@ build_nop (tree type, tree expr)
 {
   if (type == error_mark_node || error_operand_p (expr))
     return expr;
-  return build1 (NOP_EXPR, type, expr);
+  return build1_loc (EXPR_LOCATION (expr), NOP_EXPR, type, expr);
 }
 
 /* Take the address of ARG, whatever that means under C++ semantics.
@@ -7270,6 +7270,18 @@ build_c_cast (location_t /*loc*/, tree type, tree expr)
   return cp_build_c_cast (type, expr, tf_warning_or_error);
 }
 
+/* Like the "build_c_cast" used for c-common, but using cp_expr to
+   preserve location information even for tree nodes that don't
+   support it.  */
+
+cp_expr
+build_c_cast (location_t loc, tree type, cp_expr expr)
+{
+  cp_expr result = cp_build_c_cast (type, expr, tf_warning_or_error);
+  result.set_location (loc);
+  return result;
+}
+
 /* Build an expression representing an explicit C-style cast to type
    TYPE of expression EXPR.  */
 
@@ -7775,7 +7787,7 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
   return result;
 }
 
-tree
+cp_expr
 build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
                     tree rhs, tsubst_flags_t complain)
 {
index b7effc3b04a21539124749d130349ab2dc3f9147..352c0fa372497d717630cbe262a42f2a2e92e24f 100644 (file)
@@ -1,3 +1,27 @@
+2015-12-04  David Malcolm  <dmalcolm@redhat.com>
+
+       * g++.dg/cpp0x/nsdmi-template14.C: Move dg-error directive.
+       * g++.dg/gomp/loop-1.C: Update dg-error locations.
+       * g++.dg/plugin/diagnostic-test-expressions-1.C: New file, adapted
+       from gcc.dg/plugin/diagnostic-test-expressions-1.c.
+       * g++.dg/plugin/plugin.exp (plugin_test_list): Add the above.
+       * g++.dg/template/crash55.C: Update dg-error directives.
+       * g++.dg/template/pseudodtor3.C: Update column numbers in dg-error
+       directives.
+       * g++.dg/template/pr64100.C: Update location of dg-error
+       directive.
+       * g++.dg/template/ref3.C: Add XFAIL (PR c++/68699).
+       * g++.dg/ubsan/pr63956.C: Update dg directives to reflect
+       improved location information.
+       * g++.dg/warn/pr35635.C (func3): Update location of a
+       dg-warning.
+       * g++.dg/warn/Wconversion-real-integer2.C: Update location of
+       dg-warning; add a dg-message.
+       * obj-c++.dg/plugin/diagnostic-test-expressions-1.mm: New file,
+       based on objc.dg/plugin/diagnostic-test-expressions-1.m.
+       * obj-c++.dg/plugin/plugin.exp: New file, based on
+       objc.dg/plugin/plugin.exp.
+
 2015-12-04  Jakub Jelinek  <jakub@redhat.com>
 
        PR c/68656
index 9cb01f1b7eee892db7a92b19c6ee8fcbcedea175..47f5b631bf9fd2bacb94066dbb19da66cdfbe3e1 100644 (file)
@@ -8,10 +8,10 @@ template<int> struct A // { dg-error "has been parsed" }
 
 template<int N> struct B
 {
-  B* p = new B<N>;
+  B* p = new B<N>; // { dg-error "recursive instantiation of non-static data" }
 };
 
-B<1> x; // { dg-error "recursive instantiation of non-static data" }
+B<1> x;
 
 struct C
 {
index 46e707fc4c95e41e44eba3d00cb4a746ba322780..de08eb3271d85cc1a848cf172f495ac6774c3db6 100644 (file)
@@ -86,16 +86,16 @@ f1 (int x)
     for (j = baz (&i); j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
-  for (i = 0; i < 16; i++) /* { dg-error "condition expression refers to iteration variable" } */
-    for (j = 16; j > (i & x); j--)
+  for (i = 0; i < 16; i++)
+    for (j = 16; j > (i & x); j--) /* { dg-error "condition expression refers to iteration variable" } */
       ;
   #pragma omp for collapse(2)
-  for (i = 0; i < 16; i++) /* { dg-error "condition expression refers to iteration variable" } */
-    for (j = 0; j < i; j++)
+  for (i = 0; i < 16; i++)
+    for (j = 0; j < i; j++) /* { dg-error "condition expression refers to iteration variable" } */
       ;
   #pragma omp for collapse(2)
-  for (i = 0; i < 16; i++) /* { dg-error "condition expression refers to iteration variable" } */
-    for (j = 0; j < i + 4; j++)
+  for (i = 0; i < 16; i++)
+    for (j = 0; j < i + 4; j++) /* { dg-error "condition expression refers to iteration variable" } */
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < j + 4; i++) /* { dg-error "condition expression refers to iteration variable" } */
@@ -110,8 +110,8 @@ f1 (int x)
     for (j = 0; j < 16; j++)
       ;
   #pragma omp for collapse(2)
-  for (i = 0; i < 16; i++) /* { dg-error "condition expression refers to iteration variable" } */
-    for (j = 0; j < baz (&i); j++)
+  for (i = 0; i < 16; i++)
+    for (j = 0; j < baz (&i); j++) /* { dg-error "condition expression refers to iteration variable" } */
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i += j) /* { dg-error "increment expression refers to iteration variable" } */
@@ -219,20 +219,20 @@ f2 (int x)
     for (int j = baz (&i); j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
-  for (int i = 0; i < 16; i++) /* { dg-error "condition expression refers to iteration variable" } */
-    for (int j = 16; j > (i & x); j--)
+  for (int i = 0; i < 16; i++)
+    for (int j = 16; j > (i & x); j--) /* { dg-error "condition expression refers to iteration variable" } */
       ;
   #pragma omp for collapse(2)
-  for (int i = 0; i < 16; i++) /* { dg-error "condition expression refers to iteration variable" } */
-    for (int j = 0; j < i; j++)
+  for (int i = 0; i < 16; i++)
+    for (int j = 0; j < i; j++) /* { dg-error "condition expression refers to iteration variable" } */
       ;
   #pragma omp for collapse(2)
-  for (int i = 0; i < 16; i++) /* { dg-error "condition expression refers to iteration variable" } */
-    for (int j = 0; j < i + 4; j++)
+  for (int i = 0; i < 16; i++)
+    for (int j = 0; j < i + 4; j++) /* { dg-error "condition expression refers to iteration variable" } */
       ;
   #pragma omp for collapse(2)
-  for (int i = 0; i < 16; i++) /* { dg-error "condition expression refers to iteration variable" } */
-    for (int j = 0; j < baz (&i); j++)
+  for (int i = 0; i < 16; i++)
+    for (int j = 0; j < baz (&i); j++) /* { dg-error "condition expression refers to iteration variable" } */
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++) /* { dg-error "increment expression refers to iteration variable" } */
diff --git a/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C b/gcc/testsuite/g++.dg/plugin/diagnostic-test-expressions-1.C
new file mode 100644 (file)
index 0000000..4d3b07c
--- /dev/null
@@ -0,0 +1,784 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdiagnostics-show-caret -fpermissive" } */
+
+/* This is a collection of unittests to verify that we're correctly
+   capturing the source code ranges of various kinds of expression.
+
+   It uses the various "diagnostic_test_*_expression_range_plugin"
+   plugins which handles "__emit_expression_range" by generating a warning
+   at the given source range of the input argument.  Each of the
+   different plugins do this at a different phase of the internal
+   representation (tree, gimple, etc), so we can verify that the
+   source code range information is valid at each phase.
+
+   We want to accept an expression of any type.  We use variadic arguments.
+   For compatibility with the C tests we have a dummy argument, since
+   C requires at least one argument before the ellipsis.  */
+
+extern void __emit_expression_range (int dummy, ...);
+
+int global;
+
+void test_parentheses (int a, int b)
+{
+  __emit_expression_range (0, (a + b) ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, (a + b) );
+                               ~~~^~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, (a + b) * (a - b) ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, (a + b) * (a - b) );
+                               ~~~~~~~~^~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, !(a && b) ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, !(a && b) );
+                               ^~~~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+/* Postfix expressions.  ************************************************/
+
+void test_array_reference (int *arr)
+{
+  __emit_expression_range (0, arr[100] ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, arr[100] );
+                               ~~~~~~~^
+   { dg-end-multiline-output "" } */
+}
+
+int test_function_call (int p, int q, int r)
+{
+  __emit_expression_range (0, test_function_call (p, q, r) ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, test_function_call (p, q, r) );
+                               ~~~~~~~~~~~~~~~~~~~^~~~~~~~~
+   { dg-end-multiline-output "" } */
+  return 0;
+}
+
+struct test_struct
+{
+  int field;
+};
+
+int test_structure_references (struct test_struct *ptr)
+{
+  struct test_struct local;
+  local.field = 42;
+
+  __emit_expression_range (0, local.field ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, local.field );
+                               ~~~~~~^~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, ptr->field ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, ptr->field );
+                               ~~~~~^~~~~
+   { dg-end-multiline-output "" } */
+}
+
+int test_postfix_incdec (int i)
+{
+  __emit_expression_range (0, i++ ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, i++ );
+                               ~^~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, i-- ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, i-- );
+                               ~^~
+   { dg-end-multiline-output "" } */
+}
+
+/* Unary operators.  ****************************************************/
+
+int test_prefix_incdec (int i)
+{
+  __emit_expression_range (0, ++i ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, ++i );
+                               ^~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, --i ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, --i );
+                               ^~~
+   { dg-end-multiline-output "" } */
+}
+
+void test_address_operator (void)
+{
+  __emit_expression_range (0, &global ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, &global );
+                               ^~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+void test_indirection (int *ptr)
+{
+  __emit_expression_range (0, *ptr ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, *ptr );
+                               ^~~~
+   { dg-end-multiline-output "" } */
+}
+
+void test_unary_minus (int i)
+{
+  __emit_expression_range (0, -i ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, -i );
+                               ^~
+   { dg-end-multiline-output "" } */
+}
+
+void test_ones_complement (int i)
+{
+  __emit_expression_range (0, ~i ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, ~i );
+                               ^~
+   { dg-end-multiline-output "" } */
+}
+
+void test_logical_negation (int flag)
+{
+  __emit_expression_range (0, !flag ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, !flag );
+                               ^~~~~
+   { dg-end-multiline-output "" } */
+}
+
+/* Casts.  ****************************************************/
+
+void test_cast (void *ptr)
+{
+  __emit_expression_range (0, (int *)ptr ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, (int *)ptr );
+                               ^~~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, *(int *)0xdeadbeef ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, *(int *)0xdeadbeef );
+                               ^~~~~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+}
+
+/* Binary operators.  *******************************************/
+
+void test_multiplicative_operators (int lhs, int rhs)
+{
+  __emit_expression_range (0, lhs * rhs ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, lhs * rhs );
+                               ~~~~^~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, lhs / rhs ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, lhs / rhs );
+                               ~~~~^~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, lhs % rhs ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, lhs % rhs );
+                               ~~~~^~~~~
+   { dg-end-multiline-output "" } */
+}
+
+void test_additive_operators (int lhs, int rhs)
+{
+  __emit_expression_range (0, lhs + rhs ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, lhs + rhs );
+                               ~~~~^~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, lhs - rhs ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, lhs - rhs );
+                               ~~~~^~~~~
+   { dg-end-multiline-output "" } */
+}
+
+void test_shift_operators (int lhs, int rhs)
+{
+  __emit_expression_range (0, lhs << rhs ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, lhs << rhs );
+                               ~~~~^~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, lhs >> rhs ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, lhs >> rhs );
+                               ~~~~^~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+void test_relational_operators (int lhs, int rhs)
+{
+  __emit_expression_range (0, lhs < rhs ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, lhs < rhs );
+                               ~~~~^~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, lhs > rhs ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, lhs > rhs );
+                               ~~~~^~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, lhs <= rhs ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, lhs <= rhs );
+                               ~~~~^~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, lhs >= rhs ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, lhs >= rhs );
+                               ~~~~^~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+void test_equality_operators (int lhs, int rhs)
+{
+  __emit_expression_range (0, lhs == rhs ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, lhs == rhs );
+                               ~~~~^~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, lhs != rhs ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, lhs != rhs );
+                               ~~~~^~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+void test_bitwise_binary_operators (int lhs, int rhs)
+{
+  __emit_expression_range (0, lhs & rhs ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, lhs & rhs );
+                               ~~~~^~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, lhs ^ rhs ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, lhs ^ rhs );
+                               ~~~~^~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, lhs | rhs ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, lhs | rhs );
+                               ~~~~^~~~~
+   { dg-end-multiline-output "" } */
+}
+
+void test_logical_operators (int lhs, int rhs)
+{
+  __emit_expression_range (0, lhs && rhs ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, lhs && rhs );
+                               ~~~~^~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, lhs || rhs ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, lhs || rhs );
+                               ~~~~^~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+/* Conditional operator.  *******************************************/
+
+void test_conditional_operators (int flag, int on_true, int on_false)
+{
+  __emit_expression_range (0, flag ? on_true : on_false ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, flag ? on_true : on_false );
+                               ~~~~~^~~~~~~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+/* Assignment expressions.  *******************************************/
+
+void test_assignment_expressions (int dest, int other)
+{
+  __emit_expression_range (0, dest = other ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, dest = other );
+                               ~~~~~^~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, dest *= other ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, dest *= other );
+                               ~~~~~^~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, dest /= other ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, dest /= other );
+                               ~~~~~^~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, dest %= other ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, dest %= other );
+                               ~~~~~^~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, dest += other ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, dest += other );
+                               ~~~~~^~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, dest -= other ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, dest -= other );
+                               ~~~~~^~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, dest <<= other ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, dest <<= other );
+                               ~~~~~^~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, dest >>= other ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, dest >>= other );
+                               ~~~~~^~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, dest &= other ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, dest &= other );
+                               ~~~~~^~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, dest ^= other ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, dest ^= other );
+                               ~~~~~^~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, dest |= other ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, dest |= other );
+                               ~~~~~^~~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+/* Comma operator.  *******************************************/
+
+void test_comma_operator (int a, int b)
+{
+  __emit_expression_range (0, (a++, a + b) ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, (a++, a + b) );
+                               ~~~~^~~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+/* Literals.  **************************************************/
+
+/* We can't test the ranges of literals directly, since the underlying
+   tree nodes don't retain a location.  However, we can test that they
+   have ranges during parsing by building compound expressions using
+   them, and verifying the ranges of the compound expressions.  */
+
+void test_string_literals (int i)
+{
+  __emit_expression_range (0, "foo"[i] ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, "foo"[i] );
+                               ~~~~~~~^
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, &"foo" "bar" ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, &"foo" "bar" );
+                               ^~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+void test_numeric_literals (int i)
+{
+  __emit_expression_range (0, 42 + i ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, 42 + i );
+                               ~~~^~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, i + 42 ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, i + 42 );
+                               ~~^~~~
+   { dg-end-multiline-output "" } */
+
+  /* Verify locations of negative literals (via folding of
+     unary negation).  */
+
+  __emit_expression_range (0, -42 + i ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, -42 + i );
+                               ~~~~^~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, i + -42 ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, i + -42 );
+                               ~~^~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, i ? 0 : -1 ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, i ? 0 : -1 );
+                               ~~^~~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+/* Braced initializers.  ***************************************/
+
+/* We can't test the ranges of these directly, since the underlying
+   tree nodes don't retain a location.  However, we can test that they
+   have ranges during parsing by building compound expressions using
+   them, and verifying the ranges of the compound expressions.  */
+
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+void test_braced_init (void)
+{
+  /* Verify start of range.  */
+  __emit_expression_range (0, (vector(4, float)){2., 2., 2., 2.} + 1); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, (vector(4, float)){2., 2., 2., 2.} + 1);
+                                                 ~~~~~~~~~~~~~~~~~^~~
+   { dg-end-multiline-output "" } */
+
+  /* Verify end of range.  */
+  __emit_expression_range (0, 1 + (vector(4, float)){2., 2., 2., 2.}); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, 1 + (vector(4, float)){2., 2., 2., 2.});
+                               ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+/* Statement expressions.  ***************************************/
+
+void test_statement_expression (void)
+{
+  __emit_expression_range (0, ({ static int a; a; }) + 1);  /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, ({ static int a; a; }) + 1);
+                               ~~~~~~~~~~~~~~~~~~~~~~~^~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, 1 + ({ static int a; a; }) );  /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, 1 + ({ static int a; a; }) );
+                               ~~^~~~~~~~~~~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+/* Other expressions.  */
+
+void test_address_of_label (void)
+{
+ label:
+  __emit_expression_range (0, &&label );  /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, &&label );
+                               ^~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+void test_transaction_expressions (void)
+{
+  int i;
+  i = __transaction_atomic (42); /* { dg-error "without transactional memory support enabled" } */
+/* { dg-begin-multiline-output "" }
+   i = __transaction_atomic (42);
+       ^~~~~~~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+  i = __transaction_relaxed (42); /* { dg-error "without transactional memory support enabled" } */
+/* { dg-begin-multiline-output "" }
+   i = __transaction_relaxed (42);
+       ^~~~~~~~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+void test_keywords (int i)
+{
+  __emit_expression_range (0, __FUNCTION__[i] );  /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, __FUNCTION__[i] );
+                               ~~~~~~~~~~~~~~^
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, __PRETTY_FUNCTION__[i] );  /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, __PRETTY_FUNCTION__[i] );
+                               ~~~~~~~~~~~~~~~~~~~~~^
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, __func__[i] );  /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, __func__[i] );
+                               ~~~~~~~~~~^
+   { dg-end-multiline-output "" } */
+}
+
+void test_builtin_va_arg (__builtin_va_list v)
+{
+  __emit_expression_range (0,  __builtin_va_arg (v, int) );  /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0,  __builtin_va_arg (v, int) );
+                                ~~~~~~~~~~~~~~~~~~~~~^~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0,  __builtin_va_arg (v, int) + 1 );  /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0,  __builtin_va_arg (v, int) + 1 );
+                                ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~
+   { dg-end-multiline-output "" } */
+}
+
+struct s { int i; float f; };
+
+void test_builtin_offsetof (int i)
+{
+  __emit_expression_range (0,  i + __builtin_offsetof (struct s, f) );  /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0,  i + __builtin_offsetof (struct s, f) );
+                                ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0,  __builtin_offsetof (struct s, f) + i );  /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0,  __builtin_offsetof (struct s, f) + i );
+                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~
+   { dg-end-multiline-output "" } */
+}
+
+/* Examples of non-trivial expressions.  ****************************/
+
+extern double sqrt (double x);
+
+void test_quadratic (double a, double b, double c)
+{
+  __emit_expression_range (0, b * b - 4 * a * c ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, b * b - 4 * a * c );
+                               ~~~~~~^~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0,
+     (-b + sqrt (b * b - 4 * a * c))
+     / (2 * a)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+      (-b + sqrt (b * b - 4 * a * c))
+      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+      / (2 * a));
+      ^~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+}
+
+int bar (int);
+void test_combinations (int a)
+{
+  __emit_expression_range (0, bar (a) > a ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, bar (a) > a );
+                               ~~~~~~~~^~~
+   { dg-end-multiline-output "" } */
+}
+
+/* C++-specific expresssions. ****************************************/
+
+void test_cp_literal_keywords (int a, int b)
+{
+  this; /* { dg-error "invalid use of 'this' in non-member function" } */
+/* { dg-begin-multiline-output "" }
+   this;
+   ^~~~
+   { dg-end-multiline-output "" } */
+
+}
+
+class base {
+ public:
+  base ();
+  base (int i);
+  virtual ~base ();
+  int pub ();
+private:
+  int priv ();
+};
+class derived : public base { ~derived (); };
+
+void test_cp_casts (base *ptr)
+{
+  __emit_expression_range (0, dynamic_cast <derived *> (ptr)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, dynamic_cast <derived *> (ptr));
+                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, static_cast <derived *> (ptr)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, static_cast <derived *> (ptr));
+                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, reinterpret_cast <int *> (ptr)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, reinterpret_cast <int *> (ptr));
+                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, const_cast <base *> (ptr)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, const_cast <base *> (ptr));
+                               ^~~~~~~~~~~~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+void test_functional_casts (int i, float f)
+{
+  __emit_expression_range (0, float(i)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, float(i));
+                               ^~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, int(f)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, int(f));
+                               ^~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, s{i, f}); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, s{i, f});
+                               ^~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+template <typename TYPENAME>
+class example_template
+{
+public:
+  example_template (TYPENAME v);
+};
+
+void test_template_id (void)
+{
+  example_template <int>; /* { dg-warning "declaration does not declare anything" } */
+/* { dg-begin-multiline-output "" }
+   example_template <int>;
+   ^~~~~~~~~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+void test_new (void)
+{
+  __emit_expression_range (0, ::new base); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, ::new base);
+                               ^~~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, new base); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, new base);
+                               ^~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, new (base)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, new (base));
+                               ^~~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, new base (42)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, new base (42));
+                               ^~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  __emit_expression_range (0, new (base) (42)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, new (base) (42));
+                               ^~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+
+  /* TODO: placement new.  */
+
+  __emit_expression_range (0, new example_template<int> (42)); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, new example_template<int> (42));
+                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+}
+
+void test_methods ()
+{
+  __emit_expression_range (0, ((base *)1)->pub () ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, ((base *)1)->pub () );
+                               ~~~~~~~~~~~~~~~~~^~
+   { dg-end-multiline-output "" } */
+
+  ((base *)1)->priv (); // { dg-error " is private " }
+/* { dg-begin-multiline-output "" }
+   ((base *)1)->priv ();
+                      ^
+   { dg-end-multiline-output "" }
+   { dg-begin-multiline-output "" }
+   int priv ();
+       ^~~~
+   { dg-end-multiline-output "" } */
+}
+
+class tests
+{
+public:
+  void test_method_calls ();
+  int some_method () const;
+};
+
+void
+tests::test_method_calls ()
+{
+  __emit_expression_range (0, this->some_method () ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range (0, this->some_method () );
+                               ~~~~~~~~~~~~~~~~~~^~
+   { dg-end-multiline-output "" } */
+}
index 3ed13974124af29f74e641170e0c33db978ec782..3be89a0f4e82a34c4d9501262b81030f7ef293ea 100644 (file)
@@ -62,7 +62,10 @@ set plugin_test_list [list \
     { dumb_plugin.c dumb-plugin-test-1.C } \
     { header_plugin.c header-plugin-test.C } \
     { decl_plugin.c decl-plugin-test.C } \
-    { def_plugin.c def-plugin-test.C } ]
+    { def_plugin.c def-plugin-test.C } \
+    { ../../gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.c \
+         diagnostic-test-expressions-1.C } \
+]
 
 foreach plugin_test $plugin_test_list {
     # Replace each source file with its full-path name
index 9b80fd125da17b4846ab56756f3bbc862ae79a0f..b9b29f7fc8d7dff597a2120b1c723bba553e8648 100644 (file)
@@ -1,6 +1,7 @@
 //PR c++/27668
 
 template<typename class T, T = T()> // { dg-error "nested-name-specifier|two or more|valid type" }
+// { dg-error "cast" "" { target c++98_only } 3 }
 struct A {};
 
-template<int> void foo(A<int>);        // { dg-error "cast|argument" "" { target c++98_only } }
+template<int> void foo(A<int>);        // { dg-error "template argument 2" "" { target c++98_only } }
index 493849f24cfeda3e45e203220492fe142cf73ed9..051800cbca0b2ad75edf3995cc3b4e91bc07190d 100644 (file)
@@ -1,8 +1,8 @@
 // { dg-do compile { target c++11 } }
 
 template<typename> struct foo // { dg-message "note" }
-{ // { dg-error "incomplete type" }
-    static_assert(noexcept(((foo *)1)->~foo()), "");
+{
+    static_assert(noexcept(((foo *)1)->~foo()), ""); // { dg-error "incomplete type" }
 }; 
 
 template class foo<int>;
index 202182f533707ab7577f652efe9d9ba66b859e71..8700bb95252cb500360a36d02e1aa785886200c7 100644 (file)
@@ -11,7 +11,7 @@ struct A
 template <typename T> struct B
 {
   T &foo ();
-  B () { foo.~T (); }  // { dg-error "10:invalid use of member" }
+  B () { foo.~T (); }  // { dg-error "15:invalid use of member" }
 };
 
 B<int> b;
@@ -19,7 +19,7 @@ B<int> b;
 template <typename T, typename S> struct C
 {
   T t;
-  C () { t.~S (); }    // { dg-error "10:is not of type" }
+  C () { t.~S (); }    // { dg-error "13:is not of type" }
 };
 
 C<int, long int> c;
index 976c093a15b7244540da35cf6847b2a716525cca..91e3c93a35d9e275ec68061f153b75d40719242b 100644 (file)
@@ -5,7 +5,8 @@ template<const int&> struct A {};
 template<typename T> struct B
 {
   A<(T)0> b; // { dg-error "constant|not a valid" }
-  A<T(0)> a; // { dg-error "constant|not a valid" }
+  A<T(0)> a; // { dg-error "constant|not a valid" "" { xfail c++98_only } }
+                                                       // PR c++/68699
 };
 
 B<const int&> b;
index 185a719c8c47cf8cf08a06eb9081843bbd66ea23..b2656313b33e3695e2c088a0fa1e0f409c3885c0 100644 (file)
@@ -10,15 +10,18 @@ fn1 (int a, int b)
 {
   if (b != 2)
     a <<= b;
+    // { dg-error "5 << -2.. is negative" "" { target *-*-* } 12 }
+    // { dg-error "is >= than the precision of the left operand" "" { target *-*-* } 12 }
+    // { dg-error "-2 << 4.. is negative" "" { target *-*-* } 12 }
   return a;
 }
 
 constexpr int i1 = fn1 (5, 3);
-constexpr int i2 = fn1 (5, -2); // { dg-error "is negative" }
-constexpr int i3 = fn1 (5, sizeof (int) * __CHAR_BIT__); // { dg-error "is >= than the precision of the left operand" }
-constexpr int i4 = fn1 (5, 256); // { dg-error "is >= than the precision of the left operand" }
+constexpr int i2 = fn1 (5, -2); // { dg-message "in constexpr expansion" }
+constexpr int i3 = fn1 (5, sizeof (int) * __CHAR_BIT__); // { dg-message "in constexpr expansion" }
+constexpr int i4 = fn1 (5, 256); // { dg-message "in constexpr expansion" }
 constexpr int i5 = fn1 (5, 2);
-constexpr int i6 = fn1 (-2, 4); // { dg-error "is negative" }
+constexpr int i6 = fn1 (-2, 4); // { dg-message "in constexpr expansion" }
 constexpr int i7 = fn1 (0, 2);
 
 SA (i1 == 40);
@@ -30,13 +33,16 @@ fn2 (int a, int b)
 {
   if (b != 2)
     a >>= b;
+    // { dg-error "4 >> -1.. is negative" "" { target *-*-* } 35 }
+    // { dg-error "is >= than the precision of the left operand" "" { target *-*-* } 35 }
+
   return a;
 }
 
 constexpr int j1 = fn2 (4, 1);
-constexpr int j2 = fn2 (4, -1); // { dg-error "is negative" }
-constexpr int j3 = fn2 (10, sizeof (int) * __CHAR_BIT__); // { dg-error "is >= than the precision of the left operand" }
-constexpr int j4 = fn2 (1, 256); // { dg-error "is >= than the precision of the left operand" }
+constexpr int j2 = fn2 (4, -1); // { dg-message "in constexpr expansion" }
+constexpr int j3 = fn2 (10, sizeof (int) * __CHAR_BIT__); // { dg-message "in constexpr expansion" }
+constexpr int j4 = fn2 (1, 256); // { dg-message "in constexpr expansion" }
 constexpr int j5 = fn2 (5, 2);
 constexpr int j6 = fn2 (-2, 4);
 constexpr int j7 = fn2 (0, 4);
@@ -49,12 +55,12 @@ constexpr int
 fn3 (int a, int b)
 {
   if (b != 2)
-    a = a / b;
+    a = a / b; // { dg-error "..7 / 0.. is not a constant expression" }
   return a;
 }
 
 constexpr int k1 = fn3 (8, 4);
-constexpr int k2 = fn3 (7, 0); // { dg-error "is not a constant expression" }
+constexpr int k2 = fn3 (7, 0); // { dg-message "in constexpr expansion" }
 constexpr int k3 = fn3 (INT_MIN, -1); // { dg-error "overflow in constant expression" }
 
 SA (k1 == 2);
@@ -63,12 +69,12 @@ constexpr float
 fn4 (float a, float b)
 {
   if (b != 2.0)
-    a = a / b;
+    a = a / b; // { dg-error "is not a constant expression" }
   return a;
 }
 
 constexpr float l1 = fn4 (5.0, 3.0);
-constexpr float l2 = fn4 (7.0, 0.0); // { dg-error "is not a constant expression" }
+constexpr float l2 = fn4 (7.0, 0.0); // { dg-message "in constexpr expansion" }
 
 constexpr int
 fn5 (const int *a, int b)
index 0494588c15b7bd158a2ac25e176faa5246941712..7e39d5fa747e262eb969b6309094b2d9b4eabb5a 100644 (file)
 //
 // That is more useful.
 
-#define INT_MAX __INT_MAX__ 
+#define INT_MAX __INT_MAX__ // { dg-warning "17: conversion to .float. alters .int. constant value" }
 
 float  vfloat;
 
 void h (void)
 {
-    vfloat = INT_MAX; // { dg-warning "conversion to .float. alters .int. constant value" }
+    vfloat = INT_MAX; // { dg-message "14: in expansion of macro .INT_MAX." }
 }
index de68ceb484c49bf104032d850ccca49618ec0b83..19345c51162ed5f43b6a127477b4d266ed9e4873 100644 (file)
@@ -62,9 +62,9 @@ void func3()
   /* At least one branch of ? does not fit in the destination, thus
      warn.  */
   uchar_x = bar != 0 ? 2.1 : 10; /* { dg-warning "conversion" } */
-  uchar_x = bar != 0  /* { dg-warning "negative integer implicitly converted to unsigned type" } */
-    ? (unsigned char) 1024 
-    : -1; 
+  uchar_x = bar != 0
+    ? (unsigned char) 1024 /* { dg-warning "negative integer implicitly converted to unsigned type" } */
+    : -1;
 }
 
 void func4()
diff --git a/gcc/testsuite/obj-c++.dg/plugin/diagnostic-test-expressions-1.mm b/gcc/testsuite/obj-c++.dg/plugin/diagnostic-test-expressions-1.mm
new file mode 100644 (file)
index 0000000..609fe3d
--- /dev/null
@@ -0,0 +1,94 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdiagnostics-show-caret" } */
+
+/* This file is similar to diagnostic-test-expressions-1.c
+   (see the notes in that file); this file adds test
+   coverage for various Objective C constructs. */
+
+extern void __emit_expression_range (int dummy, ...);
+
+@protocol prot
+@end
+
+@interface tests <prot>
+- (int) func0;
+- (int) func1:(int)i;
++ (int) func2;
+- (void) test_sending_messages;
++ (void) test_class_dot_name;
+- (void) test_at_selector;
+- (void) test_at_protocol;
+- (void) test_at_encode:(int)i;
+@end
+
+@implementation tests
+- (int) func0
+{
+  return 42;
+}
+- (int) func1:(int)i
+{
+  return i * i;
+}
++ (int) func2
+{
+  return 0;
+}
+- (void) test_sending_messages
+{
+  __emit_expression_range ( 0, [self func0] ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range ( 0, [self func0] );
+                                ^~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+  __emit_expression_range ( 0, [self func1:5] ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range ( 0, [self func1:5] );
+                                ^~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+}
++ (void) test_class_dot_name
+{
+  __emit_expression_range ( 0, tests.func2 ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range ( 0, tests.func2 );
+                                ~~~~~~^~~~~
+   { dg-end-multiline-output "" } */
+}
+- (void) test_at_selector
+{
+  __emit_expression_range ( 0, @selector(func0) ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range ( 0, @selector(func0) );
+                                ^~~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+}
+- (void) test_at_protocol
+{
+  __emit_expression_range ( 0, @protocol(prot) ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range ( 0, @protocol(prot) );
+                                ^~~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+}
+- (void) test_at_encode:(int)i
+{
+  /* @encode() generates a STRING_CST which doesn't retain a location
+     after parsing, so we need to access it via compound expressions
+     that can't be folded away.  */
+
+  /* Verify start.  */
+  __emit_expression_range ( 0, @encode(int) + i ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range ( 0, @encode(int) + i );
+                                ~~~~~~~~~~~~~^~~
+   { dg-end-multiline-output "" } */
+
+  /* Verify finish.  */
+  __emit_expression_range ( 0, i + @encode(int) ); /* { dg-warning "range" } */
+/* { dg-begin-multiline-output "" }
+   __emit_expression_range ( 0, i + @encode(int) );
+                                ~~^~~~~~~~~~~~~~
+   { dg-end-multiline-output "" } */
+}
+@end
diff --git a/gcc/testsuite/obj-c++.dg/plugin/plugin.exp b/gcc/testsuite/obj-c++.dg/plugin/plugin.exp
new file mode 100644 (file)
index 0000000..d0d400b
--- /dev/null
@@ -0,0 +1,90 @@
+#   Copyright (C) 2009-2015 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Test the functionality of the GCC plugin support
+
+load_lib target-supports.exp
+load_lib obj-c++-dg.exp
+
+global TESTING_IN_BUILD_TREE
+global ENABLE_PLUGIN
+
+# The plugin testcases currently only work when the build tree is available.
+# Also check whether the host supports plugins.
+if { ![info exists TESTING_IN_BUILD_TREE] || ![info exists ENABLE_PLUGIN] } {
+    return
+}
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# The procedures in plugin-support.exp need these parameters.
+set default_flags $DEFAULT_CFLAGS
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+# Load support procs.
+load_lib plugin-support.exp
+
+# These tests don't run runtest_file_p consistently if it
+# doesn't return the same values, so disable parallelization
+# of this *.exp file.  The first parallel runtest to reach
+# this will run all the tests serially.
+if ![gcc_parallel_test_run_p plugin] {
+    return
+}
+gcc_parallel_test_enable 0
+
+# Specify the plugin source file and the associated test files in a list.
+# plugin_test_list={ {plugin1 test1 test2 ...} {plugin2 test1 ...} ... }
+set plugin_test_list [list \
+    { ../../gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.c \
+         diagnostic-test-expressions-1.mm } \
+]
+
+foreach plugin_test $plugin_test_list {
+    # Replace each source file with its full-path name
+    for {set i 0} {$i < [llength $plugin_test]} {incr i} {
+       set basename [lindex $plugin_test $i]
+       set plugin_test [lreplace $plugin_test $i $i $srcdir/$subdir/$basename]
+    }
+    set plugin_src [lindex $plugin_test 0]
+    # If we're only testing specific files and this isn't one of them, skip it.
+    if ![runtest_file_p $runtests $plugin_src] then {
+        continue
+    }
+    set plugin_input_tests [lreplace $plugin_test 0 0]
+    plugin-test-execute $plugin_src $plugin_input_tests
+}
+
+# run the plugindir tests
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/plugindir*.mm]] \
+       "" $DEFAULT_CFLAGS
+
+# All done.
+dg-finish
+
+gcc_parallel_test_enable 1
index bd5cf73b65918d6925b17211a7b40d310bd5a30c..c8b3ab8531cc19788352623a5c2b6b08c7dcfe17 100644 (file)
@@ -13905,7 +13905,7 @@ nonnull_arg_p (const_tree arg)
 /* Given location LOC, strip away any packed range information
    or ad-hoc information.  */
 
-static location_t
+location_t
 get_pure_location (location_t loc)
 {
   if (IS_ADHOC_LOC (loc))
@@ -13935,20 +13935,20 @@ set_block (location_t loc, tree block)
   return COMBINE_LOCATION_DATA (line_table, pure_loc, src_range, block);
 }
 
-void
+location_t
 set_source_range (tree expr, location_t start, location_t finish)
 {
   source_range src_range;
   src_range.m_start = start;
   src_range.m_finish = finish;
-  set_source_range (expr, src_range);
+  return set_source_range (expr, src_range);
 }
 
-void
+location_t
 set_source_range (tree expr, source_range src_range)
 {
   if (!EXPR_P (expr))
-    return;
+    return UNKNOWN_LOCATION;
 
   location_t pure_loc = get_pure_location (EXPR_LOCATION (expr));
   location_t adhoc = COMBINE_LOCATION_DATA (line_table,
@@ -13956,6 +13956,21 @@ set_source_range (tree expr, source_range src_range)
                                            src_range,
                                            NULL);
   SET_EXPR_LOCATION (expr, adhoc);
+  return adhoc;
+}
+
+location_t
+make_location (location_t caret, location_t start, location_t finish)
+{
+  location_t pure_loc = get_pure_location (caret);
+  source_range src_range;
+  src_range.m_start = start;
+  src_range.m_finish = finish;
+  location_t combined_loc = COMBINE_LOCATION_DATA (line_table,
+                                                  pure_loc,
+                                                  src_range,
+                                                  NULL);
+  return combined_loc;
 }
 
 /* Return the name of combined function FN, for debugging purposes.  */
index a60e9dd31cbd796cdb1c9c8ae59a2b2ef332fe26..aef825d092f450100369dc40681b65faad9a7b11 100644 (file)
@@ -5369,6 +5369,16 @@ type_with_alias_set_p (const_tree t)
   return false;
 }
 
+extern location_t get_pure_location (location_t loc);
+
+/* Get the endpoint of any range encoded within location LOC.  */
+
+static inline location_t
+get_finish (location_t loc)
+{
+  return get_range_from_loc (line_table, loc).m_finish;
+}
+
 extern location_t set_block (location_t loc, tree block);
 
 extern void gt_ggc_mx (tree &);
@@ -5377,10 +5387,10 @@ extern void gt_pch_nx (tree &, gt_pointer_operator, void *);
 
 extern bool nonnull_arg_p (const_tree);
 
-extern void
+extern location_t
 set_source_range (tree expr, location_t start, location_t finish);
 
-extern void
+extern location_t
 set_source_range (tree expr, source_range src_range);
 
 static inline source_range
@@ -5390,6 +5400,9 @@ get_decl_source_range (tree decl)
   return get_range_from_loc (line_table, loc);
 }
 
+extern location_t
+make_location (location_t caret, location_t start, location_t finish);
+
 /* Return true if it makes sense to promote/demote from_type to to_type. */
 inline bool
 desired_pro_or_demotion_p (const_tree to_type, const_tree from_type)