+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
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:
+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.
#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_?:
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);
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);
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,
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);
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,
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,
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;
/* 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;
/* 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);
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);
{
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);
}
{
/* 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;
/* 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] */
/* 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);
(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 *);
(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);
(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 *);
/* 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] */
(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 *);
(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);
/* 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);
(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);
(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);
/* Parse an identifier. Returns an IDENTIFIER_NODE representing the
identifier. */
-static tree
+static cp_expr
cp_parser_identifier (cp_parser* parser)
{
cp_token *token;
/* 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
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)
{
return error_mark_node;
}
+ location_t loc = tok->location;
+
if (cpp_userdef_string_p (tok->type))
{
string_tree = USERDEF_LITERAL_VALUE (tok->u.value);
}
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);
}
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);
}
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. */
/* 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);
/* 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);
/* 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 ();
/* 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] */
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;
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,
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:
}
/* 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
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);
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;
/* 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:
/* 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. */
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);
/* 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:
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,
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. */
{
error_at (id_expr_token->location,
"local variable %qD may not appear in this context",
- decl);
+ decl.get_value ());
return error_mark_node;
}
}
id_expr_token->location));
if (error_msg)
cp_parser_error (parser, error_msg);
+ decl.set_location (id_expr_token->location);
return decl;
}
}
}
-static inline tree
+static inline cp_expr
cp_parser_primary_expression (cp_parser *parser,
bool address_p,
bool cast_p,
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,
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,
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);
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)
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)
case RID_CONSTCAST:
{
tree type;
- tree expression;
+ cp_expr expression;
const char *saved_message;
bool saved_in_type_id_in_expr_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;
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;
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)
}
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;
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);
postfix_expression
= finish_compound_literal (type, initializer,
tf_warning_or_error);
+ postfix_expression.set_location (initializer.get_location ());
break;
}
}
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;
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;
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
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;
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;
}
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)
{
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)
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
= 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);
}
}
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;
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;
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)
{
{
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;
}
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);
/*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)
{
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:
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:
cast_expression);
if (CONSTANT_CLASS_P (folded) && !TREE_OVERFLOW (folded))
{
- expression = folded;
+ expression = cp_expr (folded, loc);
break;
}
}
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,
}
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)
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)
{
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;
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
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;
}
}
? 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,
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;
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
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.
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,
? : 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;
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,
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. */
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);
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);
}
}
}
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
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)
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)
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
| 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
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 `('. */
case CPP_CLOSE_PAREN:
/* Consume the ")" token. */
+ finish_loc = cp_lexer_peek_token (parser->lexer)->location;
cp_lexer_consume_token (parser->lexer);
goto success;
}
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;
Returns a representation of the expression. */
-static tree
+static cp_expr
cp_parser_lambda_expression (cp_parser* parser)
{
tree lambda_expr = build_lambda_expr ();
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. */
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;
/* 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)
{
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);
/* 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);
}
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:
id = error_mark_node;
}
- return id;
+ return cp_expr (id, start_loc);
}
/* Parse a template-declaration.
/* 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> ();
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;
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);
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 `]'.
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,
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
/* 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,
/* 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;
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,
&& 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;
}
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. */
{
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.
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);
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. */
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.
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.
|| 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);
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
/* 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. */
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;
}
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;
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'. */
/* 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))
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;
}
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,
}
}
- return decl;
+ return cp_expr (decl, location);
}
/* Implement the __typeof keyword: Return the type of EXPR, suitable for
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)
{
&& 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;
}
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;
&& 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 ()
&& 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;
}
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);
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;
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);
}
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;
}
}
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");
}
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;
{
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.
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. */
return result;
}
-tree
+cp_expr
build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
tree rhs, tsubst_flags_t complain)
{
+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
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
{
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" } */
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" } */
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" } */
--- /dev/null
+/* { 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 "" } */
+}
{ 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
//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 } }
// { 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>;
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;
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;
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;
{
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);
{
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);
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);
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)
//
// 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." }
}
/* 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()
--- /dev/null
+/* { 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
--- /dev/null
+# 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
/* 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))
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,
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. */
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 &);
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
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)