This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[patch] initial location support for C parser
- From: Aldy Hernandez <aldyh at redhat dot com>
- To: joseph at codesourcery dot com, lopezibanez at gmail dot com, gcc-patches at gcc dot gnu dot org
- Cc: jason at redhat dot com, charlet at act-europe dot fr
- Date: Fri, 22 Aug 2008 17:52:02 -0400
- Subject: [patch] initial location support for C parser
Hi folks.
Here is a patch/RFC before I go any further.
My plan here is to make all the build* routines in the parser take a
location, and fix everything else accordingly, eventually getting rid of
input_location. Arnaud and Manuel are tackling similar tasks, I hope we
can work in tandem.
Joseph (and Jason), I would like your input on this before I go on. I
am committed to fixing the location information throughout the compiler.
And though I know you like to have everything fixed in one go, I work
better with an incremental approach. I sincerely hope you can
accomodate this.
I am going through tests in dg.exp and verifying that we have the
correct column information. I'd like to fix as I go.
With this initial patch I noticed that to come up with suitable tests
for all this, I would have to basically write an entire ISO C
comformance test, something which is perhaps beyond the scope of my
work. I would like to fix existing tests as I go, and perhaps add new
ones when it is obvious how to add new tests. Sometimes I noticed it
was incredibly hard to contrive a test for a particular location we were
setting. I hope we can come to a middle ground here-- I doubt I have
the time, desire, or inclination to write an entire comformance suite.
The following patch works, fixes at least one test case, and gives
everyone an idea of what I'm after. It has been tested for C, C++, and
ObjC on x86_64-linux.
OK?
* tree.c (protected_set_expr_location): New.
* tree.h (protected_set_expr_location): New prototype.
* c-tree.h (build_array_ref): Add argument.
(parser_build_unary_op): Same.
* c-typeck.c (build_indirect_ref): Handle new location argument.
(build_array_ref): Same.
(parser_build_unary_op): Same.
* gimplify.c (gimplify_asm_expr): Set input_location before calling
error.
* c-omp.c (c_finish_omp_atomic): Pass location when calling
build_indirect_ref.
* c-common.c (finish_label_address_expr): Handle new location
argument.
* c-common.h (build_indirect_ref): Add argument.
(finish_label_address_expr): Same.
* c-parser.c (c_parser_unary_expression): Pass location to build
functions.
(c_parser_postfix_expression): Same.
objc/
* objc-act.c (build_typed_selector_reference): Pass input_location to
build_unary_op calls.
(build_selector_reference): Same, but to build_array_ref.
(objc_substitute_decl): Same.
(build_ivar_reference): Same, but to build_indirect_ref.
(get_super_receiver): Same.
testsuite/
* gcc.dg/20010516-1.c: Test for columns.
cp/
* typeck.c (build_x_indirect_ref): Add location argument.
* class.c (build_base_path): Pass location to build_indirect_ref.
* pt.c (tsubst_copy_and_build): Pass location to
finish_label_address_expr.
* parser.c (cp_parser_unary_expression): Same.
Index: tree.c
===================================================================
--- tree.c (revision 139386)
+++ tree.c (working copy)
@@ -3543,6 +3543,16 @@ set_expr_locus (tree node, source_locati
else
EXPR_CHECK (node)->exp.locus = *loc;
}
+
+/* Like SET_EXPR_LOCATION, but make sure the tree can have a location.
+
+ LOC is the location to use in tree T. */
+
+void protected_set_expr_location (tree t, location_t loc)
+{
+ if (t && t != error_mark_node && CAN_HAVE_LOCATION_P (t))
+ SET_EXPR_LOCATION (t, loc);
+}
/* Return a declaration like DDECL except that its DECL_ATTRIBUTES
is ATTRIBUTE. */
Index: tree.h
===================================================================
--- tree.h (revision 139386)
+++ tree.h (working copy)
@@ -1578,6 +1578,8 @@ struct tree_constructor GTY(())
location. */
#define CAN_HAVE_LOCATION_P(NODE) (EXPR_P (NODE))
+extern void protected_set_expr_location (tree, location_t);
+
/* In a TARGET_EXPR node. */
#define TARGET_EXPR_SLOT(NODE) TREE_OPERAND_CHECK_CODE (NODE, TARGET_EXPR, 0)
#define TARGET_EXPR_INITIAL(NODE) TREE_OPERAND_CHECK_CODE (NODE, TARGET_EXPR, 1)
Index: objc/objc-act.c
===================================================================
--- objc/objc-act.c (revision 139386)
+++ objc/objc-act.c (working copy)
@@ -2630,7 +2630,8 @@ build_typed_selector_reference (tree ide
return_at_index:
expr = build_unary_op (ADDR_EXPR,
build_array_ref (UOBJC_SELECTOR_TABLE_decl,
- build_int_cst (NULL_TREE, index)),
+ build_int_cst (NULL_TREE, index),
+ input_location),
1);
return convert (objc_selector_type, expr);
}
@@ -2648,7 +2649,8 @@ build_selector_reference (tree ident)
return (flag_next_runtime
? TREE_PURPOSE (*chain)
: build_array_ref (UOBJC_SELECTOR_TABLE_decl,
- build_int_cst (NULL_TREE, index)));
+ build_int_cst (NULL_TREE, index),
+ input_location));
index++;
chain = &TREE_CHAIN (*chain);
@@ -2661,7 +2663,8 @@ build_selector_reference (tree ident)
return (flag_next_runtime
? expr
: build_array_ref (UOBJC_SELECTOR_TABLE_decl,
- build_int_cst (NULL_TREE, index)));
+ build_int_cst (NULL_TREE, index),
+ input_location));
}
static GTY(()) int class_reference_idx;
@@ -3046,11 +3049,13 @@ objc_substitute_decl (tree expr, tree ol
return build_array_ref (objc_substitute_decl (TREE_OPERAND (expr, 0),
oldexpr,
newexpr),
- TREE_OPERAND (expr, 1));
+ TREE_OPERAND (expr, 1),
+ input_location);
case INDIRECT_REF:
return build_indirect_ref (objc_substitute_decl (TREE_OPERAND (expr, 0),
oldexpr,
- newexpr), "->");
+ newexpr), "->",
+ input_location);
default:
return expr;
}
@@ -6713,7 +6718,8 @@ build_ivar_reference (tree id)
self_decl = convert (objc_instance_type, self_decl); /* cast */
}
- return objc_build_component_ref (build_indirect_ref (self_decl, "->"), id);
+ return objc_build_component_ref (build_indirect_ref (self_decl, "->",
+ input_location), id);
}
/* Compute a hash value for a given method SEL_NAME. */
@@ -8737,7 +8743,7 @@ get_super_receiver (void)
super_class
= build_indirect_ref
(build_c_cast (build_pointer_type (objc_class_type),
- super_class), "unary *");
+ super_class), "unary *", input_location);
}
else
{
Index: testsuite/gcc.dg/20010516-1.c
===================================================================
--- testsuite/gcc.dg/20010516-1.c (revision 139386)
+++ testsuite/gcc.dg/20010516-1.c (working copy)
@@ -1,5 +1,7 @@
+/* { dg-options "-fshow-column" } */
+
foo()
{
char d;
- __asm volatile ( "" :: "m"(&d)); /* { dg-error "" "non-lvalue" } */
+ __asm volatile ( "" :: "m"(&d)); /* { dg-error "34:" "non-lvalue" } */
}
Index: cp/typeck.c
===================================================================
--- cp/typeck.c (revision 139386)
+++ cp/typeck.c (working copy)
@@ -2405,7 +2405,8 @@ build_x_indirect_ref (tree expr, const c
/* Helper function called from c-common. */
tree
-build_indirect_ref (tree ptr, const char *errorstring)
+build_indirect_ref (tree ptr, const char *errorstring,
+ location_t loc __attribute__ ((__unused__)))
{
return cp_build_indirect_ref (ptr, errorstring, tf_warning_or_error);
}
Index: cp/class.c
===================================================================
--- cp/class.c (revision 139386)
+++ cp/class.c (working copy)
@@ -299,7 +299,7 @@ build_base_path (enum tree_code code,
{
expr = build_nop (build_pointer_type (target_type), expr);
if (!want_pointer)
- expr = build_indirect_ref (expr, NULL);
+ expr = build_indirect_ref (expr, NULL, EXPR_LOCATION (expr));
return expr;
}
Index: cp/pt.c
===================================================================
--- cp/pt.c (revision 139386)
+++ cp/pt.c (working copy)
@@ -11050,7 +11050,8 @@ tsubst_copy_and_build (tree t,
op1 = tsubst_non_call_postfix_expression (op1, args, complain,
in_decl);
if (TREE_CODE (op1) == LABEL_DECL)
- return finish_label_address_expr (DECL_NAME (op1));
+ return finish_label_address_expr (DECL_NAME (op1),
+ EXPR_LOCATION (op1));
return build_x_unary_op (ADDR_EXPR, op1, complain);
case PLUS_EXPR:
Index: cp/parser.c
===================================================================
--- cp/parser.c (revision 139386)
+++ cp/parser.c (working copy)
@@ -5423,13 +5423,14 @@ cp_parser_unary_expression (cp_parser *p
{
tree identifier;
tree expression;
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
/* Consume the '&&' token. */
cp_lexer_consume_token (parser->lexer);
/* Look for the identifier. */
identifier = cp_parser_identifier (parser);
/* Create an expression representing the address. */
- expression = finish_label_address_expr (identifier);
+ expression = finish_label_address_expr (identifier, loc);
if (cp_parser_non_integral_constant_expression (parser,
"the address of a label"))
expression = error_mark_node;
Index: c-tree.h
===================================================================
--- c-tree.h (revision 139403)
+++ c-tree.h (working copy)
@@ -549,12 +549,13 @@ extern tree c_type_promotes_to (tree);
extern struct c_expr default_function_array_conversion (struct c_expr);
extern tree composite_type (tree, tree);
extern tree build_component_ref (tree, tree);
-extern tree build_array_ref (tree, tree);
+extern tree build_array_ref (tree, tree, location_t);
extern tree build_external_ref (tree, int, location_t);
extern void pop_maybe_used (bool);
extern struct c_expr c_expr_sizeof_expr (struct c_expr);
extern struct c_expr c_expr_sizeof_type (struct c_type_name *);
-extern struct c_expr parser_build_unary_op (enum tree_code, struct c_expr);
+extern struct c_expr parser_build_unary_op (enum tree_code, struct c_expr,
+ location_t);
extern struct c_expr parser_build_binary_op (enum tree_code, struct c_expr,
struct c_expr);
extern tree build_conditional_expr (tree, tree, tree);
Index: c-typeck.c
===================================================================
--- c-typeck.c (revision 139386)
+++ c-typeck.c (working copy)
@@ -1967,13 +1967,16 @@ build_component_ref (tree datum, tree co
/* Given an expression PTR for a pointer, return an expression
for the value pointed to.
- ERRORSTRING is the name of the operator to appear in error messages. */
+ ERRORSTRING is the name of the operator to appear in error messages.
+
+ LOC is the location to use for the generated tree. */
tree
-build_indirect_ref (tree ptr, const char *errorstring)
+build_indirect_ref (tree ptr, const char *errorstring, location_t loc)
{
tree pointer = default_conversion (ptr);
tree type = TREE_TYPE (pointer);
+ tree ref;
if (TREE_CODE (type) == POINTER_TYPE)
{
@@ -1992,11 +1995,14 @@ build_indirect_ref (tree ptr, const char
if (TREE_CODE (pointer) == ADDR_EXPR
&& (TREE_TYPE (TREE_OPERAND (pointer, 0))
== TREE_TYPE (type)))
- return TREE_OPERAND (pointer, 0);
+ {
+ ref = TREE_OPERAND (pointer, 0);
+ protected_set_expr_location (ref, loc);
+ return ref;
+ }
else
{
tree t = TREE_TYPE (type);
- tree ref;
ref = build1 (INDIRECT_REF, t, pointer);
@@ -2019,6 +2025,7 @@ build_indirect_ref (tree ptr, const char
TREE_SIDE_EFFECTS (ref)
= TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer);
TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t);
+ protected_set_expr_location (ref, loc);
return ref;
}
}
@@ -2034,11 +2041,14 @@ build_indirect_ref (tree ptr, const char
If A is a variable or a member, we generate a primitive ARRAY_REF.
This avoids forcing the array out of registers, and can work on
arrays that are not lvalues (for example, members of structures returned
- by functions). */
+ by functions).
+
+ LOC is the location to use for the returned expression. */
tree
-build_array_ref (tree array, tree index)
+build_array_ref (tree array, tree index, location_t loc)
{
+ tree ret;
bool swapped = false;
if (TREE_TYPE (array) == error_mark_node
|| TREE_TYPE (index) == error_mark_node)
@@ -2139,7 +2149,9 @@ build_array_ref (tree array, tree index)
in an inline function.
Hope it doesn't break something else. */
| TREE_THIS_VOLATILE (array));
- return require_complete_type (fold (rval));
+ ret = require_complete_type (fold (rval));
+ protected_set_expr_location (ret, loc);
+ return ret;
}
else
{
@@ -2152,7 +2164,7 @@ build_array_ref (tree array, tree index)
gcc_assert (TREE_CODE (TREE_TYPE (TREE_TYPE (ar))) != FUNCTION_TYPE);
return build_indirect_ref (build_binary_op (PLUS_EXPR, ar, index, 0),
- "array indexing");
+ "array indexing", loc);
}
}
@@ -2724,16 +2736,20 @@ convert_arguments (int nargs, tree *arga
/* This is the entry point used by the parser to build unary operators
in the input. CODE, a tree_code, specifies the unary operator, and
ARG is the operand. For unary plus, the C parser currently uses
- CONVERT_EXPR for code. */
+ CONVERT_EXPR for code.
+
+ LOC is the location to use for the tree generated.
+*/
struct c_expr
-parser_build_unary_op (enum tree_code code, struct c_expr arg)
+parser_build_unary_op (enum tree_code code, struct c_expr arg, location_t loc)
{
struct c_expr result;
result.original_code = ERROR_MARK;
result.value = build_unary_op (code, arg.value, 0);
-
+ protected_set_expr_location (result.value, loc);
+
if (TREE_OVERFLOW_P (result.value) && !TREE_OVERFLOW_P (arg.value))
overflow_warning (result.value);
Index: gimplify.c
===================================================================
--- gimplify.c (revision 139386)
+++ gimplify.c (working copy)
@@ -4761,6 +4761,8 @@ gimplify_asm_expr (tree *expr_p, gimple_
mark_addressable (TREE_VALUE (link));
if (tret == GS_ERROR)
{
+ if (EXPR_HAS_LOCATION (TREE_VALUE (link)))
+ input_location = EXPR_LOCATION (TREE_VALUE (link));
error ("memory input %d is not directly addressable", i);
ret = tret;
}
Index: c-omp.c
===================================================================
--- c-omp.c (revision 139386)
+++ c-omp.c (working copy)
@@ -137,7 +137,7 @@ c_finish_omp_atomic (enum tree_code code
tree var = create_tmp_var_raw (TREE_TYPE (addr), NULL);
addr = build4 (TARGET_EXPR, TREE_TYPE (addr), var, addr, NULL, NULL);
}
- lhs = build_indirect_ref (addr, NULL);
+ lhs = build_indirect_ref (addr, NULL, EXPR_LOCATION (addr));
/* There are lots of warnings, errors, and conversions that need to happen
in the course of interpreting a statement. Use the normal mechanisms
Index: c-common.c
===================================================================
--- c-common.c (revision 139386)
+++ c-common.c (working copy)
@@ -4994,10 +4994,12 @@ c_do_switch_warnings (splay_tree cases,
}
/* Finish an expression taking the address of LABEL (an
- IDENTIFIER_NODE). Returns an expression for the address. */
+ IDENTIFIER_NODE). Returns an expression for the address.
+
+ LOC is the location for the expression returned. */
tree
-finish_label_address_expr (tree label)
+finish_label_address_expr (tree label, location_t loc)
{
tree result;
@@ -5016,6 +5018,7 @@ finish_label_address_expr (tree label)
/* The current function in not necessarily uninlinable.
Computed gotos are incompatible with inlining, but the value
here could be used only in a diagnostic, for example. */
+ protected_set_expr_location (result, loc);
}
return result;
Index: c-common.h
===================================================================
--- c-common.h (revision 139386)
+++ c-common.h (working copy)
@@ -357,7 +357,7 @@ extern void push_cleanup (tree, tree, bo
extern tree pushdecl_top_level (tree);
extern tree pushdecl (tree);
extern tree build_modify_expr (tree, enum tree_code, tree);
-extern tree build_indirect_ref (tree, const char *);
+extern tree build_indirect_ref (tree, const char *, location_t);
extern int c_expand_decl (tree);
@@ -851,7 +851,7 @@ extern tree build_function_call (tree, t
extern tree resolve_overloaded_builtin (tree, tree);
-extern tree finish_label_address_expr (tree);
+extern tree finish_label_address_expr (tree, location_t);
/* Same function prototype, but the C and C++ front ends have
different implementations. Used in c-common.c. */
Index: c-parser.c
===================================================================
--- c-parser.c (revision 139403)
+++ c-parser.c (working copy)
@@ -4798,27 +4798,29 @@ c_parser_unary_expression (c_parser *par
{
int ext;
struct c_expr ret, op;
+ location_t loc = c_parser_peek_token (parser)->location;
switch (c_parser_peek_token (parser)->type)
{
case CPP_PLUS_PLUS:
c_parser_consume_token (parser);
op = c_parser_cast_expression (parser, NULL);
op = default_function_array_conversion (op);
- return parser_build_unary_op (PREINCREMENT_EXPR, op);
+ return parser_build_unary_op (PREINCREMENT_EXPR, op, loc);
case CPP_MINUS_MINUS:
c_parser_consume_token (parser);
op = c_parser_cast_expression (parser, NULL);
op = default_function_array_conversion (op);
- return parser_build_unary_op (PREDECREMENT_EXPR, op);
+ return parser_build_unary_op (PREDECREMENT_EXPR, op, loc);
case CPP_AND:
c_parser_consume_token (parser);
return parser_build_unary_op (ADDR_EXPR,
- c_parser_cast_expression (parser, NULL));
+ c_parser_cast_expression (parser, NULL),
+ loc);
case CPP_MULT:
c_parser_consume_token (parser);
op = c_parser_cast_expression (parser, NULL);
op = default_function_array_conversion (op);
- ret.value = build_indirect_ref (op.value, "unary *");
+ ret.value = build_indirect_ref (op.value, "unary *", loc);
ret.original_code = ERROR_MARK;
return ret;
case CPP_PLUS:
@@ -4829,29 +4831,29 @@ c_parser_unary_expression (c_parser *par
c_parser_consume_token (parser);
op = c_parser_cast_expression (parser, NULL);
op = default_function_array_conversion (op);
- return parser_build_unary_op (CONVERT_EXPR, op);
+ return parser_build_unary_op (CONVERT_EXPR, op, loc);
case CPP_MINUS:
c_parser_consume_token (parser);
op = c_parser_cast_expression (parser, NULL);
op = default_function_array_conversion (op);
- return parser_build_unary_op (NEGATE_EXPR, op);
+ return parser_build_unary_op (NEGATE_EXPR, op, loc);
case CPP_COMPL:
c_parser_consume_token (parser);
op = c_parser_cast_expression (parser, NULL);
op = default_function_array_conversion (op);
- return parser_build_unary_op (BIT_NOT_EXPR, op);
+ return parser_build_unary_op (BIT_NOT_EXPR, op, loc);
case CPP_NOT:
c_parser_consume_token (parser);
op = c_parser_cast_expression (parser, NULL);
op = default_function_array_conversion (op);
- return parser_build_unary_op (TRUTH_NOT_EXPR, op);
+ return parser_build_unary_op (TRUTH_NOT_EXPR, op, loc);
case CPP_AND_AND:
/* Refer to the address of a label as a pointer. */
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_NAME))
{
ret.value = finish_label_address_expr
- (c_parser_peek_token (parser)->value);
+ (c_parser_peek_token (parser)->value, loc);
c_parser_consume_token (parser);
}
else
@@ -4878,12 +4880,12 @@ c_parser_unary_expression (c_parser *par
c_parser_consume_token (parser);
op = c_parser_cast_expression (parser, NULL);
op = default_function_array_conversion (op);
- return parser_build_unary_op (REALPART_EXPR, op);
+ return parser_build_unary_op (REALPART_EXPR, op, loc);
case RID_IMAGPART:
c_parser_consume_token (parser);
op = c_parser_cast_expression (parser, NULL);
op = default_function_array_conversion (op);
- return parser_build_unary_op (IMAGPART_EXPR, op);
+ return parser_build_unary_op (IMAGPART_EXPR, op, loc);
default:
return c_parser_postfix_expression (parser);
}
@@ -5273,11 +5275,12 @@ c_parser_postfix_expression (c_parser *p
else
{
tree idx;
+ loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
idx = c_parser_expression (parser).value;
c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
"expected %<]%>");
- offsetof_ref = build_array_ref (offsetof_ref, idx);
+ offsetof_ref = build_array_ref (offsetof_ref, idx, loc);
}
}
}
@@ -5513,17 +5516,19 @@ c_parser_postfix_expression_after_primar
struct c_expr expr)
{
tree ident, idx, exprlist;
+ location_t loc = c_parser_peek_token (parser)->location;
while (true)
{
switch (c_parser_peek_token (parser)->type)
{
case CPP_OPEN_SQUARE:
/* Array reference. */
+ loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
idx = c_parser_expression (parser).value;
c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
"expected %<]%>");
- expr.value = build_array_ref (expr.value, idx);
+ expr.value = build_array_ref (expr.value, idx, loc);
expr.original_code = ERROR_MARK;
break;
case CPP_OPEN_PAREN:
@@ -5572,7 +5577,8 @@ c_parser_postfix_expression_after_primar
}
c_parser_consume_token (parser);
expr.value = build_component_ref (build_indirect_ref (expr.value,
- "->"), ident);
+ "->", loc),
+ ident);
expr.original_code = ERROR_MARK;
break;
case CPP_PLUS_PLUS: