aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/semantics.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/semantics.cc')
-rw-r--r--gcc/cp/semantics.cc118
1 files changed, 77 insertions, 41 deletions
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 73b4917..a2ee3a3 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -601,6 +601,25 @@ add_decl_expr (tree decl)
add_stmt (r);
}
+/* Set EXPR_LOCATION on one cleanup T to LOC. */
+
+static void
+set_one_cleanup_loc (tree t, location_t loc)
+{
+ if (!t)
+ return;
+ if (TREE_CODE (t) != POSTCONDITION_STMT)
+ protected_set_expr_location (t, loc);
+ /* Avoid locus differences for C++ cdtor calls depending on whether
+ cdtor_returns_this: a conversion to void is added to discard the return
+ value, and this conversion ends up carrying the location, and when it
+ gets discarded, the location is lost. So hold it in the call as well. */
+ if (TREE_CODE (t) == NOP_EXPR
+ && TREE_TYPE (t) == void_type_node
+ && TREE_CODE (TREE_OPERAND (t, 0)) == CALL_EXPR)
+ protected_set_expr_location (TREE_OPERAND (t, 0), loc);
+}
+
/* Set EXPR_LOCATION of the cleanups of any CLEANUP_STMT in STMTS to LOC. */
static void
@@ -608,18 +627,7 @@ set_cleanup_locs (tree stmts, location_t loc)
{
if (TREE_CODE (stmts) == CLEANUP_STMT)
{
- tree t = CLEANUP_EXPR (stmts);
- if (t && TREE_CODE (t) != POSTCONDITION_STMT)
- protected_set_expr_location (t, loc);
- /* Avoid locus differences for C++ cdtor calls depending on whether
- cdtor_returns_this: a conversion to void is added to discard the return
- value, and this conversion ends up carrying the location, and when it
- gets discarded, the location is lost. So hold it in the call as
- well. */
- if (TREE_CODE (t) == NOP_EXPR
- && TREE_TYPE (t) == void_type_node
- && TREE_CODE (TREE_OPERAND (t, 0)) == CALL_EXPR)
- protected_set_expr_location (TREE_OPERAND (t, 0), loc);
+ set_one_cleanup_loc (CLEANUP_EXPR (stmts), loc);
set_cleanup_locs (CLEANUP_BODY (stmts), loc);
}
else if (TREE_CODE (stmts) == STATEMENT_LIST)
@@ -777,37 +785,48 @@ finish_cond (tree *cond_p, tree expr)
*cond_p = expr;
}
-/* If *COND_P specifies a conditional with a declaration, transform the
- loop such that
+/* If loop condition specifies a conditional with a declaration,
+ such as
while (A x = 42) { }
for (; A x = 42;) { }
- becomes
- while (true) { A x = 42; if (!x) break; }
- for (;;) { A x = 42; if (!x) break; }
- The statement list for BODY will be empty if the conditional did
+ move the *BODY_P statements as a BIND_EXPR into {FOR,WHILE}_COND_PREP
+ and if there is any CLEANUP_STMT at the end, remove that and
+ put the cleanup into {FOR,WHILE}_COND_CLEANUP.
+ genericize_c_loop will then handle it appropriately. In particular,
+ the {FOR,WHILE}_COND, {FOR,WHILE}_BODY, if used continue label and
+ FOR_EXPR will be appended into the {FOR,WHILE}_COND_PREP BIND_EXPR,
+ but it can't be done too early because only the actual body should
+ bind BREAK_STMT and CONTINUE_STMT to the inner loop.
+ The statement list for *BODY will be empty if the conditional did
not declare anything. */
static void
-simplify_loop_decl_cond (tree *cond_p, tree body)
+adjust_loop_decl_cond (tree *body_p, tree *prep_p, tree *cleanup_p)
{
- tree cond, if_stmt;
-
- if (!TREE_SIDE_EFFECTS (body))
+ if (!TREE_SIDE_EFFECTS (*body_p))
return;
- cond = *cond_p;
- *cond_p = boolean_true_node;
-
- if_stmt = begin_if_stmt ();
- cond_p = &cond;
- while (TREE_CODE (*cond_p) == ANNOTATE_EXPR)
- cond_p = &TREE_OPERAND (*cond_p, 0);
- *cond_p = cp_build_unary_op (TRUTH_NOT_EXPR, *cond_p, false,
- tf_warning_or_error);
- finish_if_stmt_cond (cond, if_stmt);
- finish_break_stmt ();
- finish_then_clause (if_stmt);
- finish_if_stmt (if_stmt);
+ gcc_assert (!processing_template_decl);
+ if (*body_p != cur_stmt_list)
+ {
+ /* There can be either no cleanup at all, if the condition
+ declaration doesn't have non-trivial destructor, or a single
+ one if it does. In that case extract it into *CLEANUP_P. */
+ gcc_assert (stmt_list_stack->length () > 1
+ && (*stmt_list_stack)[stmt_list_stack->length ()
+ - 2] == *body_p);
+ tree_stmt_iterator last = tsi_last (*body_p);
+ gcc_assert (tsi_one_before_end_p (last)
+ && TREE_CODE (tsi_stmt (last)) == CLEANUP_STMT
+ && CLEANUP_BODY (tsi_stmt (last)) == cur_stmt_list
+ && tsi_end_p (tsi_last (cur_stmt_list))
+ && !CLEANUP_EH_ONLY (tsi_stmt (last)));
+ *cleanup_p = CLEANUP_EXPR (tsi_stmt (last));
+ tsi_delink (&last);
+ }
+ current_binding_level->keep = true;
+ *prep_p = *body_p;
+ *body_p = push_stmt_list ();
}
/* Finish a goto-statement. */
@@ -1368,7 +1387,8 @@ tree
begin_while_stmt (void)
{
tree r;
- r = build_stmt (input_location, WHILE_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
+ r = build_stmt (input_location, WHILE_STMT, NULL_TREE, NULL_TREE, NULL_TREE,
+ NULL_TREE, NULL_TREE);
add_stmt (r);
WHILE_BODY (r) = do_pushlevel (sk_block);
begin_cond (&WHILE_COND (r));
@@ -1406,7 +1426,9 @@ finish_while_stmt_cond (tree cond, tree while_stmt, bool ivdep,
build_int_cst (integer_type_node,
annot_expr_no_vector_kind),
integer_zero_node);
- simplify_loop_decl_cond (&WHILE_COND (while_stmt), WHILE_BODY (while_stmt));
+ adjust_loop_decl_cond (&WHILE_BODY (while_stmt),
+ &WHILE_COND_PREP (while_stmt),
+ &WHILE_COND_CLEANUP (while_stmt));
}
/* Finish a while-statement, which may be given by WHILE_STMT. */
@@ -1415,8 +1437,14 @@ void
finish_while_stmt (tree while_stmt)
{
end_maybe_infinite_loop (boolean_true_node);
- WHILE_BODY (while_stmt) = do_poplevel (WHILE_BODY (while_stmt));
+ WHILE_BODY (while_stmt)
+ = (WHILE_COND_PREP (while_stmt)
+ ? pop_stmt_list (WHILE_BODY (while_stmt))
+ : do_poplevel (WHILE_BODY (while_stmt)));
finish_loop_cond (&WHILE_COND (while_stmt), WHILE_BODY (while_stmt));
+ if (WHILE_COND_PREP (while_stmt))
+ WHILE_COND_PREP (while_stmt) = do_poplevel (WHILE_COND_PREP (while_stmt));
+ set_one_cleanup_loc (WHILE_COND_CLEANUP (while_stmt), input_location);
}
/* Begin a do-statement. Returns a newly created DO_STMT if
@@ -1547,7 +1575,8 @@ begin_for_stmt (tree scope, tree init)
tree r;
r = build_stmt (input_location, FOR_STMT, NULL_TREE, NULL_TREE,
- NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE);
+ NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE,
+ NULL_TREE, NULL_TREE);
if (scope == NULL_TREE)
{
@@ -1605,7 +1634,8 @@ finish_for_cond (tree cond, tree for_stmt, bool ivdep, tree unroll,
build_int_cst (integer_type_node,
annot_expr_no_vector_kind),
integer_zero_node);
- simplify_loop_decl_cond (&FOR_COND (for_stmt), FOR_BODY (for_stmt));
+ adjust_loop_decl_cond (&FOR_BODY (for_stmt), &FOR_COND_PREP (for_stmt),
+ &FOR_COND_CLEANUP (for_stmt));
}
/* Finish the increment-EXPRESSION in a for-statement, which may be
@@ -1679,11 +1709,17 @@ finish_for_stmt (tree for_stmt)
RANGE_FOR_BODY (for_stmt) = do_poplevel (RANGE_FOR_BODY (for_stmt));
else
{
- FOR_BODY (for_stmt) = do_poplevel (FOR_BODY (for_stmt));
+ FOR_BODY (for_stmt)
+ = (FOR_COND_PREP (for_stmt)
+ ? pop_stmt_list (FOR_BODY (for_stmt))
+ : do_poplevel (FOR_BODY (for_stmt)));
if (FOR_COND (for_stmt))
finish_loop_cond (&FOR_COND (for_stmt),
FOR_EXPR (for_stmt) ? integer_one_node
: FOR_BODY (for_stmt));
+ if (FOR_COND_PREP (for_stmt))
+ FOR_COND_PREP (for_stmt) = do_poplevel (FOR_COND_PREP (for_stmt));
+ set_one_cleanup_loc (FOR_COND_CLEANUP (for_stmt), input_location);
}
/* Pop the scope for the body of the loop. */