/* This file is part of the C front end.
It contains routines to build C expressions given their operands,
including computing the types of the result, C-specific error checks,
- and some optimization.
-
- There are also routines to build RETURN_STMT nodes and CASE_STMT nodes,
- and to process initializations in declarations (since they work
- like a strange sort of assignment). */
+ and some optimization. */
#include "config.h"
#include "system.h"
#include "intl.h"
#include "ggc.h"
#include "target.h"
+#include "tree-iterator.h"
+#include "tree-gimple.h"
+
/* Nonzero if we've already printed a "missing braces around initializer"
message within this initializer. */
tagged_tu_seen_base = &tts;
if (DECL_NAME (s1) != NULL)
- for (s2 = TYPE_VALUES (t2); s2; s2 = TREE_CHAIN (s2))
+ for (s2 = TYPE_FIELDS (t2); s2; s2 = TREE_CHAIN (s2))
if (DECL_NAME (s1) == DECL_NAME (s2))
{
int result;
return result;
}
\f
-
-/* Return true if `t' is known to be non-negative. */
-
-int
-c_tree_expr_nonnegative_p (tree t)
-{
- if (TREE_CODE (t) == STMT_EXPR)
- {
- t = COMPOUND_BODY (STMT_EXPR_STMT (t));
-
- /* Find the last statement in the chain, ignoring the final
- * scope statement */
- while (TREE_CHAIN (t) != NULL_TREE
- && TREE_CODE (TREE_CHAIN (t)) != SCOPE_STMT)
- t = TREE_CHAIN (t);
- return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
- }
- return tree_expr_nonnegative_p (t);
-}
-
/* Return a tree for the difference of pointers OP0 and OP1.
The resulting tree has type int. */
/* Do not warn if the signed quantity is an unsuffixed
integer literal (or some static constant expression
involving such literals) and it is non-negative. */
- else if ((unsigned_op2 && c_tree_expr_nonnegative_p (op1))
- || (unsigned_op1 && c_tree_expr_nonnegative_p (op2)))
+ else if ((unsigned_op2 && tree_expr_nonnegative_p (op1))
+ || (unsigned_op1 && tree_expr_nonnegative_p (op2)))
/* OK */;
else
warning ("signed and unsigned type in conditional expression");
`foo() + bar(), baz()' the result of the `+' operator is not used,
so we should issue a warning. */
else if (warn_unused_value)
- warn_if_unused_value (TREE_VALUE (list));
+ warn_if_unused_value (TREE_VALUE (list), input_location);
return build (COMPOUND_EXPR, TREE_TYPE (rest), TREE_VALUE (list), rest);
}
\f
/* Build a complete asm-statement, whose components are a CV_QUALIFIER
(guaranteed to be 'volatile' or null) and ARGS (represented using
- an ASM_STMT node). */
+ an ASM_EXPR node). */
tree
build_asm_stmt (tree cv_qualifier, tree args)
{
some INPUTS, and some CLOBBERS. The latter three may be NULL.
SIMPLE indicates whether there was anything at all after the
string in the asm expression -- asm("blah") and asm("blah" : )
- are subtly different. We use a ASM_STMT node to represent this. */
+ are subtly different. We use a ASM_EXPR node to represent this. */
tree
build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers,
bool simple)
for (tail = inputs; tail; tail = TREE_CHAIN (tail))
TREE_VALUE (tail) = default_function_array_conversion (TREE_VALUE (tail));
- args = build_stmt (ASM_STMT, string, outputs, inputs, clobbers);
+ args = build_stmt (ASM_EXPR, string, outputs, inputs, clobbers);
/* Simple asm statements are treated as volatile. */
if (simple)
emit_queue ();
}
\f
-/* Expand a C `return' statement.
- RETVAL is the expression for what to return,
- or a null pointer for `return;' with no value. */
+/* Generate a C `return' statement. RETVAL is the expression for what
+ to return, or a null pointer for `return;' with no value. */
-tree
-c_expand_return (tree retval)
+void
+c_finish_return (tree retval)
{
tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl));
current_function_returns_value = 1;
if (t == error_mark_node)
- return NULL_TREE;
+ return;
inner = t = convert (TREE_TYPE (res), t);
retval = build (MODIFY_EXPR, TREE_TYPE (res), res, t);
}
- return add_stmt (build_return_stmt (retval));
+ add_stmt (build_stmt (RETURN_EXPR, retval));
}
\f
struct c_switch {
if (switch_stack)
{
- bool switch_was_empty_p = (SWITCH_BODY (switch_stack->switch_stmt) == NULL_TREE);
-
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 (switch_was_empty_p)
- {
- /* Attach the first case label to the SWITCH_BODY. */
- SWITCH_BODY (switch_stack->switch_stmt) = TREE_CHAIN (switch_stack->switch_stmt);
- TREE_CHAIN (switch_stack->switch_stmt) = NULL_TREE;
- }
}
else if (low_value)
error ("case label not within a switch statement");
/* Finish the switch statement. */
void
-c_finish_case (void)
+c_finish_case (tree body)
{
struct c_switch *cs = switch_stack;
+ SWITCH_BODY (cs->switch_stmt) = body;
+
/* Emit warnings as needed. */
c_do_switch_warnings (cs->cases, cs->switch_stmt);
- /* Rechain the next statements to the SWITCH_STMT. */
- last_tree = cs->switch_stmt;
-
/* Pop the stack. */
switch_stack = switch_stack->next;
splay_tree_delete (cs->cases);
free (cs);
}
+\f
+/* Keep a stack of if statements. We record the number of compound
+ statements seen up to the if keyword, as well as the line number
+ and file of the if. If a potentially ambiguous else is seen, that
+ fact is recorded; the warning is issued when we can be sure that
+ the enclosing if statement does not have an else branch. */
+typedef struct
+{
+ tree if_stmt;
+ location_t empty_locus;
+ int compstmt_count;
+ int stmt_count;
+ unsigned int needs_warning : 1;
+ unsigned int saw_else : 1;
+} if_elt;
+
+static if_elt *if_stack;
+
+/* Amount of space in the if statement stack. */
+static int if_stack_space = 0;
+
+/* Stack pointer. */
+static int if_stack_pointer = 0;
+
+/* Begin an if-statement. */
+
+void
+c_begin_if_stmt (void)
+{
+ tree r;
+ if_elt *elt;
+
+ /* Make sure there is enough space on the stack. */
+ if (if_stack_space == 0)
+ {
+ if_stack_space = 10;
+ if_stack = xmalloc (10 * sizeof (if_elt));
+ }
+ else if (if_stack_space == if_stack_pointer)
+ {
+ if_stack_space += 10;
+ if_stack = xrealloc (if_stack, if_stack_space * sizeof (if_elt));
+ }
+
+ r = add_stmt (build_stmt (COND_EXPR, NULL_TREE, NULL_TREE, NULL_TREE));
+
+ /* Record this if statement. */
+ elt = &if_stack[if_stack_pointer++];
+ memset (elt, 0, sizeof (*elt));
+ elt->if_stmt = r;
+}
+
+/* Record the start of an if-then, and record the start of it
+ for ambiguous else detection.
+
+ COND is the condition for the if-then statement.
+
+ IF_STMT is the statement node that has already been created for
+ this if-then statement. It is created before parsing the
+ condition to keep line number information accurate. */
+
+void
+c_finish_if_cond (tree cond, int compstmt_count, int stmt_count)
+{
+ if_elt *elt = &if_stack[if_stack_pointer - 1];
+ elt->compstmt_count = compstmt_count;
+ elt->stmt_count = stmt_count;
+ COND_EXPR_COND (elt->if_stmt) = lang_hooks.truthvalue_conversion (cond);
+}
+
+/* Called after the then-clause for an if-statement is processed. */
+
+void
+c_finish_then (tree then_stmt)
+{
+ if_elt *elt = &if_stack[if_stack_pointer - 1];
+ COND_EXPR_THEN (elt->if_stmt) = then_stmt;
+ elt->empty_locus = input_location;
+}
+
+/* Called between the then-clause and the else-clause
+ of an if-then-else. */
+
+void
+c_begin_else (int stmt_count)
+{
+ if_elt *elt = &if_stack[if_stack_pointer - 1];
+
+ /* An ambiguous else warning must be generated for the enclosing if
+ statement, unless we see an else branch for that one, too. */
+ if (warn_parentheses
+ && if_stack_pointer > 1
+ && (elt[0].compstmt_count == elt[-1].compstmt_count))
+ elt[-1].needs_warning = 1;
+
+ /* Even if a nested if statement had an else branch, it can't be
+ ambiguous if this one also has an else. So don't warn in that
+ case. Also don't warn for any if statements nested in this else. */
+ elt->needs_warning = 0;
+ elt->compstmt_count--;
+ elt->saw_else = 1;
+ elt->stmt_count = stmt_count;
+}
+
+/* Called after the else-clause for an if-statement is processed. */
+
+void
+c_finish_else (tree else_stmt)
+{
+ if_elt *elt = &if_stack[if_stack_pointer - 1];
+ COND_EXPR_ELSE (elt->if_stmt) = else_stmt;
+ elt->empty_locus = input_location;
+}
+
+/* Record the end of an if-then. Optionally warn if a nested
+ if statement had an ambiguous else clause. */
+
+void
+c_finish_if_stmt (int stmt_count)
+{
+ if_elt *elt = &if_stack[--if_stack_pointer];
+
+ if (COND_EXPR_ELSE (elt->if_stmt) == NULL)
+ COND_EXPR_ELSE (elt->if_stmt) = build_empty_stmt ();
+
+ if (elt->needs_warning)
+ warning ("%Hsuggest explicit braces to avoid ambiguous `else'",
+ EXPR_LOCUS (elt->if_stmt));
+
+ if (extra_warnings && stmt_count == elt->stmt_count)
+ {
+ if (elt->saw_else)
+ warning ("%Hempty body in an else-statement", &elt->empty_locus);
+ else
+ warning ("%Hempty body in an if-statement", &elt->empty_locus);
+ }
+}
+\f
+/* Begin a while statement. Returns a newly created WHILE_STMT if
+ appropriate. */
+
+tree
+c_begin_while_stmt (void)
+{
+ tree r;
+ r = add_stmt (build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE));
+ return r;
+}
+
+void
+c_finish_while_stmt_cond (tree cond, tree while_stmt)
+{
+ WHILE_COND (while_stmt) = (*lang_hooks.truthvalue_conversion) (cond);
+}
+
+void
+c_finish_while_stmt (tree body, tree while_stmt)
+{
+ WHILE_BODY (while_stmt) = body;
+}
+\f
+/* Create a for statement. */
+
+tree
+c_begin_for_stmt (void)
+{
+ tree r;
+ r = add_stmt (build_stmt (FOR_STMT, NULL_TREE, NULL_TREE,
+ NULL_TREE, NULL_TREE));
+ FOR_INIT_STMT (r) = push_stmt_list ();
+ return r;
+}
+
+void
+c_finish_for_stmt_init (tree for_stmt)
+{
+ FOR_INIT_STMT (for_stmt) = pop_stmt_list (FOR_INIT_STMT (for_stmt));
+}
+
+void
+c_finish_for_stmt_cond (tree cond, tree for_stmt)
+{
+ if (cond)
+ FOR_COND (for_stmt) = lang_hooks.truthvalue_conversion (cond);
+}
+
+void
+c_finish_for_stmt_incr (tree expr, tree for_stmt)
+{
+ FOR_EXPR (for_stmt) = expr;
+}
+
+void
+c_finish_for_stmt (tree body, tree for_stmt)
+{
+ FOR_BODY (for_stmt) = body;
+}
+\f
+/* A helper routine for c_finish_expr_stmt and c_finish_stmt_expr. */
+
+static void
+emit_side_effect_warnings (tree expr)
+{
+ if (!TREE_SIDE_EFFECTS (expr))
+ {
+ if (!VOID_TYPE_P (TREE_TYPE (expr)) && !TREE_NO_WARNING (expr))
+ warning ("%Hstatement with no effect",
+ EXPR_LOCUS (expr) ? EXPR_LOCUS (expr) : &input_location);
+ }
+ else if (warn_unused_value)
+ warn_if_unused_value (expr, input_location);
+}
+/* Emit an expression as a statement. */
+
+void
+c_finish_expr_stmt (tree expr)
+{
+ if (!expr)
+ return;
+
+ /* Do default conversion if safe and possibly important,
+ in case within ({...}). */
+ if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
+ && (flag_isoc99 || lvalue_p (expr)))
+ || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
+ expr = default_conversion (expr);
+
+ if (warn_sequence_point)
+ verify_sequence_points (expr);
+
+ if (TREE_TYPE (expr) != error_mark_node
+ && !COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (expr))
+ && TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE)
+ error ("expression statement has incomplete type");
+
+ /* If we're not processing a statement expression, warn about unused values.
+ Warnings for statement expressions will be emitted later, once we figure
+ out which is the result. */
+ if (!STATEMENT_LIST_STMT_EXPR (cur_stmt_list)
+ && (extra_warnings || warn_unused_value))
+ emit_side_effect_warnings (expr);
+
+ /* If the expression is not of a type to which we cannot assign a line
+ number, wrap the thing in a no-op NOP_EXPR. */
+ if (DECL_P (expr) || TREE_CODE_CLASS (TREE_CODE (expr)) == 'c')
+ expr = build1 (NOP_EXPR, TREE_TYPE (expr), expr);
+
+ add_stmt (expr);
+}
+
+/* Do the opposite and emit a statement as an expression. To begin,
+ create a new binding level and return it. */
+
+tree
+c_begin_stmt_expr (void)
+{
+ tree ret;
+
+ /* We must force a BLOCK for this level so that, if it is not expanded
+ later, there is a way to turn off the entire subtree of blocks that
+ are contained in it. */
+ keep_next_level ();
+ ret = c_begin_compound_stmt (true);
+
+ /* Mark the current statement list as belonging to a statement list. */
+ STATEMENT_LIST_STMT_EXPR (ret) = 1;
+
+ return ret;
+}
+
+tree
+c_finish_stmt_expr (tree body)
+{
+ tree last, type, tmp, val;
+ tree *last_p;
+
+ body = c_end_compound_stmt (body, true);
+
+ /* Locate the last statement in BODY. See c_end_compound_stmt
+ about always returning a BIND_EXPR. */
+ last_p = &BIND_EXPR_BODY (body);
+ last = BIND_EXPR_BODY (body);
+
+ continue_searching:
+ if (TREE_CODE (last) == STATEMENT_LIST)
+ {
+ tree_stmt_iterator i;
+
+ /* This can happen with degenerate cases like ({ }). No value. */
+ if (!TREE_SIDE_EFFECTS (last))
+ return body;
+
+ /* If we're supposed to generate side effects warnings, process
+ all of the statements except the last. */
+ if (extra_warnings || warn_unused_value)
+ {
+ for (i = tsi_start (last); !tsi_one_before_end_p (i); tsi_next (&i))
+ emit_side_effect_warnings (tsi_stmt (i));
+ }
+ else
+ i = tsi_last (last);
+ last_p = tsi_stmt_ptr (i);
+ last = *last_p;
+ }
+
+ /* If the end of the list is exception related, then the list was split
+ by a call to push_cleanup. Continue searching. */
+ if (TREE_CODE (last) == TRY_FINALLY_EXPR
+ || TREE_CODE (last) == TRY_CATCH_EXPR)
+ {
+ last_p = &TREE_OPERAND (last, 0);
+ last = *last_p;
+ goto continue_searching;
+ }
+
+ /* In the case that the BIND_EXPR is not necessary, return the
+ expression out from inside it. */
+ if (last == BIND_EXPR_BODY (body) && BIND_EXPR_VARS (body) == NULL)
+ return last;
+
+ /* Extract the type of said expression. */
+ type = TREE_TYPE (last);
+
+ /* If we're not returning a value at all, then the BIND_EXPR that
+ we already have is a fine expression to return. */
+ if (!type || VOID_TYPE_P (type))
+ return body;
+
+ /* Now that we've located the expression containing the value, it seems
+ silly to make voidify_wrapper_expr repeat the process. Create a
+ temporary of the appropriate type and stick it in a TARGET_EXPR. */
+ tmp = create_tmp_var_raw (type, NULL);
+
+ /* Unwrap a no-op NOP_EXPR as added by c_finish_expr_stmt. This avoids
+ tree_expr_nonnegative_p giving up immediately. */
+ val = last;
+ if (TREE_CODE (val) == NOP_EXPR
+ && TREE_TYPE (val) == TREE_TYPE (TREE_OPERAND (val, 0)))
+ val = TREE_OPERAND (val, 0);
+
+ *last_p = build (MODIFY_EXPR, void_type_node, tmp, val);
+ SET_EXPR_LOCUS (*last_p, EXPR_LOCUS (last));
+
+ return build (TARGET_EXPR, type, tmp, body, NULL_TREE, NULL_TREE);
+}
+\f
+/* Begin and end compound statements. This is as simple as pushing
+ and popping new statement lists from the tree. */
+
+tree
+c_begin_compound_stmt (bool do_scope)
+{
+ tree stmt = push_stmt_list ();
+ if (do_scope)
+ {
+ push_scope ();
+ clear_last_expr ();
+ }
+ return stmt;
+}
+
+tree
+c_end_compound_stmt (tree stmt, bool do_scope)
+{
+ tree block = NULL;
+
+ if (do_scope)
+ {
+ if (c_dialect_objc ())
+ objc_clear_super_receiver ();
+ block = pop_scope ();
+ }
+
+ stmt = pop_stmt_list (stmt);
+ stmt = c_build_bind_expr (block, stmt);
+
+ /* If this compound statement is nested immediately inside a statement
+ expression, then force a BIND_EXPR to be created. Otherwise we'll
+ do the wrong thing for ({ { 1; } }) or ({ 1; { } }). In particular,
+ STATEMENT_LISTs merge, and thus we can lose track of what statement
+ was really last. */
+ if (cur_stmt_list
+ && STATEMENT_LIST_STMT_EXPR (cur_stmt_list)
+ && TREE_CODE (stmt) != BIND_EXPR)
+ {
+ stmt = build (BIND_EXPR, void_type_node, NULL, stmt, NULL);
+ TREE_SIDE_EFFECTS (stmt) = 1;
+ }
+
+ return stmt;
+}
+
+/* Queue a cleanup. CLEANUP is an expression/statement to be executed
+ when the current scope is exited. EH_ONLY is true when this is not
+ meant to apply to normal control flow transfer. */
+
+void
+push_cleanup (tree decl ATTRIBUTE_UNUSED, tree cleanup, bool eh_only)
+{
+ enum tree_code code;
+ tree stmt, list;
+ bool stmt_expr;
+
+ code = eh_only ? TRY_CATCH_EXPR : TRY_FINALLY_EXPR;
+ stmt = build_stmt (code, NULL, cleanup);
+ add_stmt (stmt);
+ stmt_expr = STATEMENT_LIST_STMT_EXPR (cur_stmt_list);
+ list = push_stmt_list ();
+ TREE_OPERAND (stmt, 0) = list;
+ STATEMENT_LIST_STMT_EXPR (list) = stmt_expr;
+}
+\f
/* Build a binary-operation expression without default conversions.
CODE is the kind of expression to build.
This function differs from `build' in several ways:
constant expression involving such literals or a
conditional expression involving such literals)
and it is non-negative. */
- if (c_tree_expr_nonnegative_p (sop))
+ if (tree_expr_nonnegative_p (sop))
/* OK */;
/* Do not warn if the comparison is an equality operation,
the unsigned quantity is an integral constant, and it