+ XDELETE (cs);
+}
+\f
+/* Emit an if statement. IF_LOCUS is the location of the 'if'. COND,
+ THEN_BLOCK and ELSE_BLOCK are expressions to be used; ELSE_BLOCK
+ may be null. NESTED_IF is true if THEN_BLOCK contains another IF
+ statement, and was not surrounded with parenthesis. */
+
+void
+c_finish_if_stmt (location_t if_locus, tree cond, tree then_block,
+ tree else_block, bool nested_if)
+{
+ tree stmt;
+
+ /* Diagnose an ambiguous else if if-then-else is nested inside if-then. */
+ if (warn_parentheses && nested_if && else_block == NULL)
+ {
+ tree inner_if = then_block;
+
+ /* We know from the grammar productions that there is an IF nested
+ within THEN_BLOCK. Due to labels and c99 conditional declarations,
+ it might not be exactly THEN_BLOCK, but should be the last
+ non-container statement within. */
+ while (1)
+ switch (TREE_CODE (inner_if))
+ {
+ case COND_EXPR:
+ goto found;
+ case BIND_EXPR:
+ inner_if = BIND_EXPR_BODY (inner_if);
+ break;
+ case STATEMENT_LIST:
+ inner_if = expr_last (then_block);
+ break;
+ case TRY_FINALLY_EXPR:
+ case TRY_CATCH_EXPR:
+ inner_if = TREE_OPERAND (inner_if, 0);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ found:
+
+ if (COND_EXPR_ELSE (inner_if))
+ warning ("%Hsuggest explicit braces to avoid ambiguous `else'",
+ &if_locus);
+ }
+
+ /* Diagnose ";" via the special empty statement node that we create. */
+ if (extra_warnings)
+ {
+ if (TREE_CODE (then_block) == NOP_EXPR && !TREE_TYPE (then_block))
+ {
+ if (!else_block)
+ warning ("%Hempty body in an if-statement",
+ EXPR_LOCUS (then_block));
+ then_block = alloc_stmt_list ();
+ }
+ if (else_block
+ && TREE_CODE (else_block) == NOP_EXPR
+ && !TREE_TYPE (else_block))
+ {
+ warning ("%Hempty body in an else-statement",
+ EXPR_LOCUS (else_block));
+ else_block = alloc_stmt_list ();
+ }
+ }
+
+ stmt = build3 (COND_EXPR, NULL_TREE, cond, then_block, else_block);
+ SET_EXPR_LOCATION (stmt, if_locus);
+ add_stmt (stmt);
+}
+
+/* Emit a general-purpose loop construct. START_LOCUS is the location of
+ the beginning of the loop. COND is the loop condition. COND_IS_FIRST
+ is false for DO loops. INCR is the FOR increment expression. BODY is
+ the statement controlled by the loop. BLAB is the break label. CLAB is
+ the continue label. Everything is allowed to be NULL. */
+
+void
+c_finish_loop (location_t start_locus, tree cond, tree incr, tree body,
+ tree blab, tree clab, bool cond_is_first)
+{
+ tree entry = NULL, exit = NULL, t;
+
+ /* Detect do { ... } while (0) and don't generate loop construct. */
+ if (cond && !cond_is_first && integer_zerop (cond))
+ cond = NULL;
+ if (cond_is_first || cond)
+ {
+ tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
+
+ /* If we have an exit condition, then we build an IF with gotos either
+ out of the loop, or to the top of it. If there's no exit condition,
+ then we just build a jump back to the top. */
+ exit = build_and_jump (&LABEL_EXPR_LABEL (top));
+
+ if (cond)
+ {
+ /* Canonicalize the loop condition to the end. This means
+ generating a branch to the loop condition. Reuse the
+ continue label, if possible. */
+ if (cond_is_first)
+ {
+ if (incr || !clab)
+ {
+ entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
+ t = build_and_jump (&LABEL_EXPR_LABEL (entry));
+ }
+ else
+ t = build1 (GOTO_EXPR, void_type_node, clab);
+ SET_EXPR_LOCATION (t, start_locus);
+ add_stmt (t);
+ }
+
+ t = build_and_jump (&blab);
+ exit = build3 (COND_EXPR, void_type_node, cond, exit, t);
+ exit = fold (exit);
+ if (cond_is_first)
+ SET_EXPR_LOCATION (exit, start_locus);
+ else
+ SET_EXPR_LOCATION (exit, input_location);
+ }
+
+ add_stmt (top);
+ }
+
+ if (body)
+ add_stmt (body);
+ if (clab)
+ add_stmt (build1 (LABEL_EXPR, void_type_node, clab));
+ if (incr)
+ add_stmt (incr);
+ if (entry)
+ add_stmt (entry);
+ if (exit)
+ add_stmt (exit);
+ if (blab)
+ add_stmt (build1 (LABEL_EXPR, void_type_node, blab));
+}
+
+tree
+c_finish_bc_stmt (tree *label_p, bool is_break)
+{
+ tree label = *label_p;
+
+ if (!label)
+ *label_p = label = create_artificial_label ();
+ else if (TREE_CODE (label) != LABEL_DECL)
+ {
+ if (is_break)
+ error ("break statement not within loop or switch");
+ else
+ error ("continue statement not within a loop");
+ return NULL_TREE;
+ }
+
+ return add_stmt (build1 (GOTO_EXPR, void_type_node, label));
+}
+
+/* A helper routine for c_process_expr_stmt and c_finish_stmt_expr. */
+
+static void
+emit_side_effect_warnings (tree expr)
+{
+ if (expr == error_mark_node)
+ ;
+ else if (!TREE_SIDE_EFFECTS (expr))
+ {
+ if (!VOID_TYPE_P (TREE_TYPE (expr)) && !TREE_NO_WARNING (expr))
+ warning ("%Hstatement with no effect",
+ EXPR_HAS_LOCATION (expr) ? EXPR_LOCUS (expr) : &input_location);
+ }
+ else if (warn_unused_value)
+ warn_if_unused_value (expr, input_location);
+}
+
+/* Process an expression as if it were a complete statement. Emit
+ diagnostics, but do not call ADD_STMT. */
+
+tree
+c_process_expr_stmt (tree expr)
+{
+ if (!expr)
+ return NULL_TREE;
+
+ /* 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);
+
+ if (EXPR_P (expr))
+ SET_EXPR_LOCATION (expr, input_location);
+
+ return expr;
+}
+
+/* Emit an expression as a statement. */
+
+tree
+c_finish_expr_stmt (tree expr)
+{
+ if (expr)
+ return add_stmt (c_process_expr_stmt (expr));
+ else
+ return NULL;
+}
+
+/* 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 == error_mark_node
+ || (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 = build2 (MODIFY_EXPR, void_type_node, tmp, val);
+ SET_EXPR_LOCUS (*last_p, EXPR_LOCUS (last));
+
+ return build4 (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 ();
+ 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 = build3 (BIND_EXPR, void_type_node, NULL, stmt, NULL);
+ TREE_SIDE_EFFECTS (stmt) = 1;
+ }
+
+ return stmt;