* c-typeck.c (build_asm_stmt): New, broken out from ...
(c_expand_asm_operands): ... here. Just do rtl expansion.
(c_expand_return): Return the new stmt node.
(c_start_case, do_case): Likewise.
* c-common.c (c_expand_expr_stmt): Likewise.
* c-common.h: Update declarations.
* c-tree.h: Likewise.
* c-semantics.c (build_stmt): Use STMT_LINENO not TREE_COMPLEXITY.
* c-parse.in (fndef): Set DECL_SOURCE_LINE to the open brace.
(nested_function, notype_nested_function): Likewise.
(compstmt): Return the compound statement not the binding level.
(lineno_labeled_stmt): Simplify.
(lineno_stmt, lineno_label): Set STMT_LINENO.
(stmt, label): Return the new stmt node.
From-SVN: r38402
+2000-12-20 Richard Henderson <rth@redhat.com>
+
+ * c-typeck.c (build_asm_stmt): New, broken out from ...
+ (c_expand_asm_operands): ... here. Just do rtl expansion.
+ (c_expand_return): Return the new stmt node.
+ (c_start_case, do_case): Likewise.
+ * c-common.c (c_expand_expr_stmt): Likewise.
+ * c-common.h: Update declarations.
+ * c-tree.h: Likewise.
+ * c-semantics.c (build_stmt): Use STMT_LINENO not TREE_COMPLEXITY.
+ * c-parse.in (fndef): Set DECL_SOURCE_LINE to the open brace.
+ (nested_function, notype_nested_function): Likewise.
+ (compstmt): Return the compound statement not the binding level.
+ (lineno_labeled_stmt): Simplify.
+ (lineno_stmt, lineno_label): Set STMT_LINENO.
+ (stmt, label): Return the new stmt node.
+
2000-12-20 Bernd Schmidt <bernds@redhat.com>
* Makefile.in (OBJS): Add sched-ebb.o.
obstack_free (&tlist_obstack, tlist_firstobj);
}
-void
+tree
c_expand_expr_stmt (expr)
tree expr;
{
error ("expression statement has incomplete type");
last_expr_type = TREE_TYPE (expr);
- add_stmt (build_stmt (EXPR_STMT, expr));
+ return add_stmt (build_stmt (EXPR_STMT, expr));
}
\f
/* Validate the expression after `case' and apply default promotions. */
/* Print an error message for invalid operands to arith operation CODE.
NOP_EXPR is used as a special case (see truthvalue_conversion). */
extern void binary_op_error PARAMS ((enum tree_code));
-extern void c_expand_expr_stmt PARAMS ((tree));
+extern tree c_expand_expr_stmt PARAMS ((tree));
extern void c_expand_start_cond PARAMS ((tree, int));
extern void c_finish_then PARAMS ((void));
extern void c_expand_start_else PARAMS ((void));
extern void emit_local_var PARAMS ((tree));
extern void make_rtl_for_local_static PARAMS ((tree));
extern tree expand_cond PARAMS ((tree));
-extern void c_expand_return PARAMS ((tree));
-extern void do_case PARAMS ((tree, tree));
+extern tree c_expand_return PARAMS ((tree));
+extern tree do_case PARAMS ((tree, tree));
extern tree build_stmt PARAMS ((enum tree_code, ...));
extern tree build_case_label PARAMS ((tree, tree, tree));
extern tree build_continue_stmt PARAMS ((void));
%type <ttype> any_word extension
%type <ttype> compstmt compstmt_start compstmt_nostart compstmt_primary_start
-%type <ttype> do_stmt_start poplevel
+%type <ttype> do_stmt_start poplevel stmt label
%type <ttype> c99_block_start c99_block_end
%type <ttype> declarator
}
old_style_parm_decls
{ store_parm_decls (); }
- compstmt_or_error
- { finish_function (0);
+ save_filename save_lineno compstmt_or_error
+ { DECL_SOURCE_FILE (current_function_decl) = $7;
+ DECL_SOURCE_LINE (current_function_decl) = $8;
+ finish_function (0);
current_declspecs = TREE_VALUE (declspec_stack);
prefix_attributes = TREE_PURPOSE (declspec_stack);
declspec_stack = TREE_CHAIN (declspec_stack); }
}
old_style_parm_decls
{ store_parm_decls (); }
- compstmt_or_error
- { finish_function (0);
+ save_filename save_lineno compstmt_or_error
+ { DECL_SOURCE_FILE (current_function_decl) = $7;
+ DECL_SOURCE_LINE (current_function_decl) = $8;
+ finish_function (0);
current_declspecs = TREE_VALUE (declspec_stack);
prefix_attributes = TREE_PURPOSE (declspec_stack);
declspec_stack = TREE_CHAIN (declspec_stack); }
}
old_style_parm_decls
{ store_parm_decls (); }
- compstmt_or_error
- { finish_function (0);
+ save_filename save_lineno compstmt_or_error
+ { DECL_SOURCE_FILE (current_function_decl) = $6;
+ DECL_SOURCE_LINE (current_function_decl) = $7;
+ finish_function (0);
current_declspecs = TREE_VALUE (declspec_stack);
prefix_attributes = TREE_PURPOSE (declspec_stack);
declspec_stack = TREE_CHAIN (declspec_stack); }
which then was handled by compstmt_or_error.
There followed a repeated execution of that same rule,
which called YYERROR1 again, and so on. */
- compstmt
+ save_filename save_lineno compstmt
{ tree decl = current_function_decl;
+ DECL_SOURCE_FILE (decl) = $5;
+ DECL_SOURCE_LINE (decl) = $6;
finish_function (1);
pop_function_context ();
add_decl_stmt (decl); }
which then was handled by compstmt_or_error.
There followed a repeated execution of that same rule,
which called YYERROR1 again, and so on. */
- compstmt
+ save_filename save_lineno compstmt
{ tree decl = current_function_decl;
+ DECL_SOURCE_FILE (decl) = $5;
+ DECL_SOURCE_LINE (decl) = $6;
finish_function (1);
pop_function_context ();
add_decl_stmt (decl); }
compstmt: compstmt_start compstmt_nostart
{ RECHAIN_STMTS ($1, COMPOUND_BODY ($1));
- $$ = $2; }
+ $$ = $1; }
;
/* Value is number of statements counted as of the closeparen. */
;
lineno_labeled_stmt:
- save_filename save_lineno stmt
- { }
-/* | save_filename save_lineno error
- { }
-*/
- | save_filename save_lineno label lineno_labeled_stmt
- { }
+ lineno_stmt
+ | lineno_label lineno_labeled_stmt
;
/* Like lineno_labeled_stmt, but a block in C99. */
lineno_stmt:
save_filename save_lineno stmt
- { }
+ { if ($3)
+ {
+ STMT_LINENO ($3) = $2;
+ /* ??? We currently have no way of recording
+ the filename for a statement. This probably
+ matters little in practice at the moment,
+ but I suspect that problems will ocurr when
+ doing inlining at the tree level. */
+ }
+ }
;
lineno_label:
save_filename save_lineno label
- { }
+ { if ($3)
+ {
+ STMT_LINENO ($3) = $2;
+ }
+ }
;
select_or_iter_stmt:
/* Parse a single real statement, not including any labels. */
stmt:
compstmt
- { stmt_count++; }
+ { stmt_count++; $$ = $1; }
| expr ';'
{ stmt_count++;
- c_expand_expr_stmt ($1); }
+ $$ = c_expand_expr_stmt ($1); }
| c99_block_start select_or_iter_stmt c99_block_end
{ if (flag_isoc99)
- RECHAIN_STMTS ($1, COMPOUND_BODY ($1)); }
+ RECHAIN_STMTS ($1, COMPOUND_BODY ($1));
+ $$ = NULL_TREE; }
| BREAK ';'
{ stmt_count++;
- add_stmt (build_break_stmt ()); }
+ $$ = add_stmt (build_break_stmt ()); }
| CONTINUE ';'
{ stmt_count++;
- add_stmt (build_continue_stmt ()); }
+ $$ = add_stmt (build_continue_stmt ()); }
| RETURN ';'
{ stmt_count++;
- c_expand_return (NULL_TREE); }
+ $$ = c_expand_return (NULL_TREE); }
| RETURN expr ';'
{ stmt_count++;
- c_expand_return ($2); }
+ $$ = c_expand_return ($2); }
| ASM_KEYWORD maybe_type_qual '(' expr ')' ';'
{ stmt_count++;
STRIP_NOPS ($4);
$4 = TREE_OPERAND ($4, 0);
if (TREE_CHAIN ($4))
$4 = combine_strings ($4);
- add_stmt (build_stmt (ASM_STMT, NULL_TREE, $4,
- NULL_TREE, NULL_TREE, NULL_TREE));
+ $$ = add_stmt (build_stmt (ASM_STMT, NULL_TREE, $4,
+ NULL_TREE, NULL_TREE,
+ NULL_TREE));
}
else
- error ("argument of `asm' is not a constant string"); }
+ {
+ error ("argument of `asm' is not a constant string");
+ $$ = NULL_TREE;
+ }
+ }
/* This is the case with just output operands. */
| ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ')' ';'
{ stmt_count++;
- c_expand_asm_operands ($4, $6, NULL_TREE, NULL_TREE,
- $2 == ridpointers[(int)RID_VOLATILE],
- input_filename, lineno); }
+ $$ = build_asm_stmt ($2, $4, $6, NULL_TREE, NULL_TREE); }
/* This is the case with input operands as well. */
- | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ':' asm_operands ')' ';'
+ | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ':'
+ asm_operands ')' ';'
{ stmt_count++;
- c_expand_asm_operands ($4, $6, $8, NULL_TREE,
- $2 == ridpointers[(int)RID_VOLATILE],
- input_filename, lineno); }
+ $$ = build_asm_stmt ($2, $4, $6, $8, NULL_TREE); }
/* This is the case with clobbered registers as well. */
| ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ':'
asm_operands ':' asm_clobbers ')' ';'
{ stmt_count++;
- c_expand_asm_operands ($4, $6, $8, $10,
- $2 == ridpointers[(int)RID_VOLATILE],
- input_filename, lineno); }
+ $$ = build_asm_stmt ($2, $4, $6, $8, $10); }
| GOTO identifier ';'
{ tree decl;
stmt_count++;
if (decl != 0)
{
TREE_USED (decl) = 1;
- add_stmt (build_stmt (GOTO_STMT, decl));
+ $$ = add_stmt (build_stmt (GOTO_STMT, decl));
}
+ else
+ $$ = NULL_TREE;
}
| GOTO '*' expr ';'
{ if (pedantic)
pedwarn ("ISO C forbids `goto *expr;'");
stmt_count++;
$3 = convert (ptr_type_node, $3);
- add_stmt (build_stmt (GOTO_STMT, $3)); }
+ $$ = add_stmt (build_stmt (GOTO_STMT, $3)); }
| ';'
+ { $$ = NULL_TREE; }
;
/* Any kind of label, including jump labels and case labels.
label: CASE expr_no_commas ':'
{ stmt_count++;
- do_case ($2, NULL_TREE); }
+ $$ = do_case ($2, NULL_TREE); }
| CASE expr_no_commas ELLIPSIS expr_no_commas ':'
{ stmt_count++;
- do_case ($2, $4); }
+ $$ = do_case ($2, $4); }
| DEFAULT ':'
{ stmt_count++;
- do_case (NULL_TREE, NULL_TREE); }
+ $$ = do_case (NULL_TREE, NULL_TREE); }
| identifier save_filename save_lineno ':' maybe_attribute
{ tree label = define_label ($2, $3, $1);
stmt_count++;
if (label)
{
decl_attributes (label, $5, NULL_TREE);
- add_stmt (build_stmt (LABEL_STMT, label));
+ $$ = add_stmt (build_stmt (LABEL_STMT, label));
}
+ else
+ $$ = NULL_TREE;
}
;
/* Build a generic statement based on the given type of node and
arguments. Similar to `build_nt', except that we set
- TREE_COMPLEXITY to be the current line number. */
+ STMT_LINENO to be the current line number. */
+/* ??? This should be obsolete with the lineno_stmt productions
+ in the grammar. */
tree
build_stmt VPARAMS ((enum tree_code code, ...))
t = make_node (code);
length = TREE_CODE_LENGTH (code);
- TREE_COMPLEXITY (t) = lineno;
+ STMT_LINENO (t) = lineno;
for (i = 0; i < length; i++)
TREE_OPERAND (t, i) = va_arg (p, tree);
ATTRIBUTE_PRINTF_1;
extern tree c_start_case PARAMS ((tree));
extern void c_finish_case PARAMS ((void));
+extern tree build_asm_stmt PARAMS ((tree, tree, tree,
+ tree, tree));
/* Set to 0 at beginning of a function definition, set to 1 if
a return statement that specifies a return value is seen. */
}
}
\f
-/* Expand an ASM statement with operands, handling output operands
- that are not variables or INDIRECT_REFS by transforming such
- cases into cases that expand_asm_operands can handle.
-
- Arguments are same as for expand_asm_operands. */
+/* Build an asm-statement, whose components are a CV_QUALIFIER, a
+ STRING, some OUTPUTS, some INPUTS, and some CLOBBERS. */
-void
-c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
- tree string, outputs, inputs, clobbers;
- int vol;
- const char *filename;
- int line;
+tree
+build_asm_stmt (cv_qualifier, string, outputs, inputs, clobbers)
+ tree cv_qualifier;
+ tree string;
+ tree outputs;
+ tree inputs;
+ tree clobbers;
{
- int noutputs = list_length (outputs);
- register int i;
- /* o[I] is the place that output number I should be written. */
- register tree *o = (tree *) alloca (noutputs * sizeof (tree));
- register tree tail;
+ tree tail;
- if (TREE_CODE (string) == ADDR_EXPR)
- string = TREE_OPERAND (string, 0);
- if (last_tree && TREE_CODE (string) != STRING_CST)
+ if (TREE_CHAIN (string))
+ string = combine_strings (string);
+ if (TREE_CODE (string) != STRING_CST)
{
error ("asm template is not a string constant");
- return;
+ return NULL_TREE;
}
- /* Record the contents of OUTPUTS before it is modified. */
- for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
+ if (cv_qualifier != NULL_TREE
+ && cv_qualifier != ridpointers[(int) RID_VOLATILE])
+ {
+ warning ("%s qualifier ignored on asm",
+ IDENTIFIER_POINTER (cv_qualifier));
+ cv_qualifier = NULL_TREE;
+ }
+
+ /* We can remove output conversions that change the type,
+ but not the mode. */
+ for (tail = outputs; tail; tail = TREE_CHAIN (tail))
{
tree output = TREE_VALUE (tail);
- /* We can remove conversions that just change the type, not the mode. */
STRIP_NOPS (output);
- o[i] = output;
+ TREE_VALUE (tail) = output;
/* Allow conversions as LHS here. build_modify_expr as called below
will do the right thing with them. */
|| TREE_CODE (output) == FIX_CEIL_EXPR)
output = TREE_OPERAND (output, 0);
- if (last_tree)
- lvalue_or_else (o[i], "invalid lvalue in asm statement");
+ lvalue_or_else (TREE_VALUE (tail), "invalid lvalue in asm statement");
+ }
+
+ /* Remove output conversions that change the type but not the mode. */
+ for (tail = outputs; tail; tail = TREE_CHAIN (tail))
+ {
+ tree output = TREE_VALUE (tail);
+ STRIP_NOPS (output);
+ TREE_VALUE (tail) = output;
}
- /* Perform default conversions on array and function inputs. */
- /* Don't do this for other types--
- it would screw up operands expected to be in memory. */
- for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), i++)
+ /* Perform default conversions on array and function inputs.
+ Don't do this for other types as it would screw up operands
+ expected to be in memory. */
+ for (tail = inputs; tail; tail = TREE_CHAIN (tail))
if (TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == ARRAY_TYPE
|| TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == FUNCTION_TYPE)
TREE_VALUE (tail) = default_conversion (TREE_VALUE (tail));
- if (last_tree)
- {
- add_stmt (build_stmt (ASM_STMT,
- vol ? ridpointers[(int) RID_VOLATILE] : NULL_TREE,
- string, outputs, inputs, clobbers));
- return;
- }
+ return add_stmt (build_stmt (ASM_STMT, cv_qualifier, string,
+ outputs, inputs, clobbers));
+}
+
+/* Expand an ASM statement with operands, handling output operands
+ that are not variables or INDIRECT_REFS by transforming such
+ cases into cases that expand_asm_operands can handle.
+
+ Arguments are same as for expand_asm_operands. */
+
+void
+c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
+ tree string, outputs, inputs, clobbers;
+ int vol;
+ const char *filename;
+ int line;
+{
+ int noutputs = list_length (outputs);
+ register int i;
+ /* o[I] is the place that output number I should be written. */
+ register tree *o = (tree *) alloca (noutputs * sizeof (tree));
+ register tree tail;
+
+ /* Record the contents of OUTPUTS before it is modified. */
+ for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
+ o[i] = TREE_VALUE (tail);
- /* Generate the ASM_OPERANDS insn;
- store into the TREE_VALUEs of OUTPUTS some trees for
- where the values were actually stored. */
+ /* Generate the ASM_OPERANDS insn; store into the TREE_VALUEs of
+ OUTPUTS some trees for where the values were actually stored. */
expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line);
/* Copy all the intermediate outputs into the specified outputs. */
RETVAL is the expression for what to return,
or a null pointer for `return;' with no value. */
-void
+tree
c_expand_return (retval)
tree retval;
{
tree inner;
if (t == error_mark_node)
- return;
+ return NULL_TREE;
inner = t = convert (TREE_TYPE (res), t);
current_function_returns_value = 1;
}
- add_stmt (build_return_stmt (retval));
+ return add_stmt (build_return_stmt (retval));
}
\f
struct c_switch {
/* Process a case label. */
-void
+tree
do_case (low_value, high_value)
tree low_value;
tree high_value;
{
+ tree label = NULL_TREE;
+
if (switch_stack)
- c_add_case_label (switch_stack->cases,
- SWITCH_COND (switch_stack->switch_stmt),
- low_value,
- high_value);
+ {
+ label = c_add_case_label (switch_stack->cases,
+ SWITCH_COND (switch_stack->switch_stmt),
+ low_value, high_value);
+ if (label == error_mark_node)
+ label = NULL_TREE;
+ }
else if (low_value)
error ("case label not within a switch statement");
else
error ("`default' label not within a switch statement");
+
+ return label;
}
/* Finish the switch statement. */