From patchwork Sat Apr 14 21:43:44 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom de Vries X-Patchwork-Id: 152558 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 7A78EB7003 for ; Sun, 15 Apr 2012 07:44:25 +1000 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1335044666; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:Message-ID:Date:From:User-Agent:MIME-Version:To:CC: Subject:References:In-Reply-To:Content-Type:Mailing-List: Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:Sender:Delivered-To; bh=2QXhSveM8dTC+xN17gbBehrTZFA=; b=n9Id3KmiBeTY7bVBUOw2CRlR2xf6f3hJcNwVgDG4nQZtYTqcdZPs5NgI9A9HQC dLz1d/hoo0CZnpKZyNYBdJq6JFfFXaxFEvn56TqsPSUL0hrQpjc6bKV/TMofx72h DnXLXsrPyXPlUzHHLrkVkQNQurLKx0kbs03Bo4CTIMals= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:Received:Message-ID:Date:From:User-Agent:MIME-Version:To:CC:Subject:References:In-Reply-To:Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=TQjgfSgnz/GbYqDruvuT5G+3UvVyKiJiNq0VVfi+j/om56IeqC6fC9BYYIH+ok H0R2TiNXwucGI7+5BsM0ihwWCe8cToUVpai5iabE4MOsdLZGsaMWGcA/W5U2Avfy 0wqvfQnRcLPUf1op4TDuOfbduYIRDR6fo2riVgjX6j+BM=; Received: (qmail 8110 invoked by alias); 14 Apr 2012 21:44:21 -0000 Received: (qmail 8101 invoked by uid 22791); 14 Apr 2012 21:44:18 -0000 X-SWARE-Spam-Status: No, hits=-4.2 required=5.0 tests=AWL, BAYES_00, KHOP_RCVD_UNTRUST, KHOP_THREADED, RCVD_IN_HOSTKARMA_W, RCVD_IN_HOSTKARMA_WL, TW_TM X-Spam-Check-By: sourceware.org Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sat, 14 Apr 2012 21:44:01 +0000 Received: from svr-orw-fem-01.mgc.mentorg.com ([147.34.98.93]) by relay1.mentorg.com with esmtp id 1SJAlC-0002Hn-N6 from Tom_deVries@mentor.com ; Sat, 14 Apr 2012 14:43:58 -0700 Received: from SVR-IES-FEM-01.mgc.mentorg.com ([137.202.0.104]) by svr-orw-fem-01.mgc.mentorg.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.4675); Sat, 14 Apr 2012 14:43:58 -0700 Received: from [127.0.0.1] (137.202.0.76) by SVR-IES-FEM-01.mgc.mentorg.com (137.202.0.104) with Microsoft SMTP Server id 14.1.289.1; Sat, 14 Apr 2012 22:43:55 +0100 Message-ID: <4F89EF90.8060703@mentor.com> Date: Sat, 14 Apr 2012 23:43:44 +0200 From: Tom de Vries User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.28) Gecko/20120313 Lightning/1.0b2 Thunderbird/3.1.20 MIME-Version: 1.0 To: Jason Merrill CC: Richard Guenther , Jakub Jelinek , "gcc-patches@gcc.gnu.org" , Subject: Re: [PATCH] Prevent 'control reaches end of non-void function' warning for DO_WHILE References: <4EE1C91F.2020906@mentor.com> <4F1BF53A.9070703@mentor.com> <4F3F626D.4060408@redhat.com> In-Reply-To: <4F3F626D.4060408@redhat.com> Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Jason, On 18/02/12 09:33, Jason Merrill wrote: > On 01/22/2012 03:38 AM, Tom de Vries wrote: > > Sorry I didn't notice this patch until now; please CC me on C++ patches, > or at least mention C++ in the subject line. > OK, will do. >> + tree expr = NULL; >> + append_to_statement_list (*block, &expr); >> + *block = expr; > > Rather than doing this dance here, I think it would be better to enhance > append_to_statement_list to handle the case of the list argument being a > non-list. > Added return value to append_to_statement_list, so now it's: *block = append_to_statement_list (*block, NULL); >> + cp_walk_tree (&incr, cp_genericize_r, data, NULL); >> >> + if (incr && EXPR_P (incr)) >> + SET_EXPR_LOCATION (incr, start_locus); > > It might be better to set the location on incr before genericizing, so > that the location can trickle down. > I see. I reordered the code. >> + t = build1 (GOTO_EXPR, void_type_node, get_bc_label (bc_break)); >> + SET_EXPR_LOCATION (t, start_locus); > > Here you can use build1_loc instead of two separate statements. > Done. >> - /* If we use a LOOP_EXPR here, we have to feed the whole thing >> - back through the main gimplifier to lower it. Given that we >> - have to gimplify the loop body NOW so that we can resolve >> - break/continue stmts, seems easier to just expand to gotos. */ > > Since we're now lowering the loop at genericize time rather than > gimplify, what's the rationale for not using LOOP_EXPR/EXIT_EXPR? We > should still say something here. I suppose the rationale is that the C > front end currently goes straight to gotos. > I think we could indeed use LOOP_EXPR/EXIT_EXPR. I'm not sure what the gain would be, since at least for C it would be a construct alive only between genericize and gimplify. But I guess it makes sense from orthogonality point of view. Added a comment with todo. >> if (cond != error_mark_node) >> { >> - gimplify_expr (&cond, &exit_seq, NULL, is_gimple_val, fb_rvalue); >> - stmt = gimple_build_cond (NE_EXPR, cond, >> - build_int_cst (TREE_TYPE (cond), 0), >> - gimple_label_label (top), >> - get_bc_label (bc_break)); >> - gimple_seq_add_stmt (&exit_seq, stmt); >> + cond = build2 (NE_EXPR, boolean_type_node, cond, >> + build_int_cst (TREE_TYPE (cond), 0)); > > I don't think we still need this extra comparison to 0, that seems like > a gimple-specific thing. > OK, removed. >> if (FOR_INIT_STMT (stmt)) >> + append_to_statement_list (FOR_INIT_STMT (stmt), &expr); >> >> + genericize_cp_loop (&loop, EXPR_LOCATION (stmt), FOR_COND (stmt), >> + FOR_BODY (stmt), FOR_EXPR (stmt), 1, walk_subtrees, data); > > The call to genericize_cp_loop will clear *walk_subtrees, which means we > don't genericize the FOR_INIT_STMT. > I see. Added call to cp_generize_r. >> + tree jump = build_and_jump (&label); > > Again, let's use build1_loc. > Done. >> + *stmt_p = build_and_jump (&label); >> + SET_EXPR_LOCATION (*stmt_p, location); > > And here. > Done. >> + stmt = make_node (OMP_FOR); > > Why make a new OMP_FOR rather than repurpose the one we already have? > We've already modified its operands. > Done. Bootstrapped and reg-tested on x86_64. OK for trunk? Thanks, - Tom > Jason 2012-04-14 Tom de Vries * tree-iterator.c (append_to_statement_list_1, append_to_statement_list) (append_to_statement_list_force): Return resulting list. Handle list_p == NULL. * tree-iterator.h (append_to_statement_list) (append_to_statement_list_force): Add tree return type. * cp-gimplify.c (begin_bc_block): Add location parameter and use as location argument to create_artificial_label. (finish_bc_block): Change return type to void. Remove body_seq parameter, and add block parameter. Append label to STMT_LIST and return in block. (gimplify_cp_loop, gimplify_for_stmt, gimplify_while_stmt) (gimplify_do_stmt, gimplify_switch_stmt): Remove function. (genericize_cp_loop, genericize_for_stmt, genericize_while_stmt) (genericize_do_stmt, genericize_switch_stmt, genericize_continue_stmt) (genericize_break_stmt, genericize_omp_for_stmt): New function. (cp_gimplify_omp_for): Remove bc_continue processing. (cp_gimplify_expr): Genericize VEC_INIT_EXPR. (cp_gimplify_expr): Mark FOR_STMT, WHILE_STMT, DO_STMT, SWITCH_STMT, CONTINUE_STMT, and BREAK_STMT as unreachable. (cp_genericize_r): Genericize FOR_STMT, WHILE_STMT, DO_STMT, SWITCH_STMT, CONTINUE_STMT, BREAK_STMT and OMP_FOR. (cp_genericize_tree): New function, factored out of ... (cp_genericize): ... this function. * g++.dg/pr51264-4.C: New test. Index: gcc/tree-iterator.c =================================================================== --- gcc/tree-iterator.c (revision 185028) +++ gcc/tree-iterator.c (working copy) @@ -57,45 +57,56 @@ free_stmt_list (tree t) VEC_safe_push (tree, gc, stmt_list_cache, t); } -/* A subroutine of append_to_statement_list{,_force}. T is not NULL. */ +/* A subroutine of append_to_statement_list{,_force}. */ -static void +static tree append_to_statement_list_1 (tree t, tree *list_p) { - tree list = *list_p; + tree list; tree_stmt_iterator i; + list = list_p == NULL ? NULL_TREE : *list_p; + if (!list) { if (t && TREE_CODE (t) == STATEMENT_LIST) { - *list_p = t; - return; + list = t; + if (list_p) + *list_p = list; + return list; } - *list_p = list = alloc_stmt_list (); + list = alloc_stmt_list (); } i = tsi_last (list); tsi_link_after (&i, t, TSI_CONTINUE_LINKING); + + if (list_p) + *list_p = list; + return list; } /* Add T to the end of the list container pointed to by LIST_P. - If T is an expression with no effects, it is ignored. */ + If T is an expression with no effects, it is ignored. Return resulting + list. */ -void +tree append_to_statement_list (tree t, tree *list_p) { if (t && TREE_SIDE_EFFECTS (t)) - append_to_statement_list_1 (t, list_p); + return append_to_statement_list_1 (t, list_p); + return list_p == NULL ? NULL_TREE : *list_p; } /* Similar, but the statement is always added, regardless of side effects. */ -void +tree append_to_statement_list_force (tree t, tree *list_p) { if (t != NULL_TREE) - append_to_statement_list_1 (t, list_p); + return append_to_statement_list_1 (t, list_p); + return list_p == NULL ? NULL_TREE : *list_p; } /* Links a statement, or a chain of statements, before the current stmt. */ Index: gcc/tree-iterator.h =================================================================== --- gcc/tree-iterator.h (revision 185028) +++ gcc/tree-iterator.h (working copy) @@ -115,7 +115,7 @@ extern void tsi_delink (tree_stmt_iterat extern tree alloc_stmt_list (void); extern void free_stmt_list (tree); -extern void append_to_statement_list (tree, tree *); -extern void append_to_statement_list_force (tree, tree *); +extern tree append_to_statement_list (tree, tree *); +extern tree append_to_statement_list_force (tree, tree *); #endif /* GCC_TREE_ITERATOR_H */ Index: gcc/cp/cp-gimplify.c =================================================================== --- gcc/cp/cp-gimplify.c (revision 185028) +++ gcc/cp/cp-gimplify.c (working copy) @@ -34,6 +34,11 @@ along with GCC; see the file COPYING3. #include "flags.h" #include "splay-tree.h" +/* Forward declarations. */ + +static tree cp_genericize_r (tree *, int *, void *); +static void cp_genericize_tree (tree*); + /* Local declarations. */ enum bc_t { bc_break = 0, bc_continue = 1 }; @@ -45,37 +50,40 @@ static tree bc_label[2]; /* Begin a scope which can be exited by a break or continue statement. BC indicates which. - Just creates a label and pushes it into the current context. */ + Just creates a label with location LOCATION and pushes it into the current + context. */ static tree -begin_bc_block (enum bc_t bc) +begin_bc_block (enum bc_t bc, location_t location) { - tree label = create_artificial_label (input_location); + tree label = create_artificial_label (location); DECL_CHAIN (label) = bc_label[bc]; bc_label[bc] = label; return label; } /* Finish a scope which can be exited by a break or continue statement. - LABEL was returned from the most recent call to begin_bc_block. BODY is + LABEL was returned from the most recent call to begin_bc_block. BLOCK is an expression for the contents of the scope. If we saw a break (or continue) in the scope, append a LABEL_EXPR to - body. Otherwise, just forget the label. */ + BLOCK. Otherwise, just forget the label. */ -static gimple_seq -finish_bc_block (enum bc_t bc, tree label, gimple_seq body) +static void +finish_bc_block (tree *block, enum bc_t bc, tree label) { gcc_assert (label == bc_label[bc]); if (TREE_USED (label)) { - gimple_seq_add_stmt (&body, gimple_build_label (label)); + *block = append_to_statement_list (*block, NULL); + + append_to_statement_list (build1 (LABEL_EXPR, void_type_node, label), + block); } bc_label[bc] = DECL_CHAIN (label); DECL_CHAIN (label) = NULL_TREE; - return body; } /* Get the LABEL_EXPR to represent a break or continue statement @@ -183,173 +191,207 @@ genericize_if_stmt (tree *stmt_p) evaluated before the loop body as in while and for loops, or after the loop body as in do-while loops. */ -static gimple_seq -gimplify_cp_loop (tree cond, tree body, tree incr, bool cond_is_first) -{ - gimple top, entry, stmt; - gimple_seq stmt_list, body_seq, incr_seq, exit_seq; - tree cont_block, break_block; - location_t stmt_locus; - - stmt_locus = input_location; - stmt_list = NULL; - body_seq = NULL; - incr_seq = NULL; - exit_seq = NULL; - entry = NULL; - - break_block = begin_bc_block (bc_break); - cont_block = begin_bc_block (bc_continue); +static void +genericize_cp_loop (tree *stmt_p, location_t start_locus, tree cond, tree body, + tree incr, bool cond_is_first, int *walk_subtrees, + void *data) +{ + tree blab, clab; + tree entry = NULL, exit = NULL, t; + tree stmt_list = NULL; + + blab = begin_bc_block (bc_break, start_locus); + clab = begin_bc_block (bc_continue, start_locus); + + if (incr && EXPR_P (incr)) + SET_EXPR_LOCATION (incr, start_locus); + + cp_walk_tree (&cond, cp_genericize_r, data, NULL); + cp_walk_tree (&body, cp_genericize_r, data, NULL); + cp_walk_tree (&incr, cp_genericize_r, data, NULL); + *walk_subtrees = 0; /* If condition is zero don't generate a loop construct. */ if (cond && integer_zerop (cond)) { - top = NULL; if (cond_is_first) { - stmt = gimple_build_goto (get_bc_label (bc_break)); - gimple_set_location (stmt, stmt_locus); - gimple_seq_add_stmt (&stmt_list, stmt); + t = build1_loc (start_locus, GOTO_EXPR, void_type_node, + get_bc_label (bc_break)); + append_to_statement_list (t, &stmt_list); } } else { - /* If we use a LOOP_EXPR here, we have to feed the whole thing - back through the main gimplifier to lower it. Given that we - have to gimplify the loop body NOW so that we can resolve - break/continue stmts, seems easier to just expand to gotos. */ - top = gimple_build_label (create_artificial_label (stmt_locus)); + /* Expand to gotos, just like c_finish_loop. TODO: Use LOOP_EXPR. */ + tree top = build1 (LABEL_EXPR, void_type_node, + create_artificial_label (start_locus)); /* 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 = build1 (GOTO_EXPR, void_type_node, LABEL_EXPR_LABEL (top)); + if (cond && !integer_nonzerop (cond)) { - if (cond != error_mark_node) - { - gimplify_expr (&cond, &exit_seq, NULL, is_gimple_val, fb_rvalue); - stmt = gimple_build_cond (NE_EXPR, cond, - build_int_cst (TREE_TYPE (cond), 0), - gimple_label_label (top), - get_bc_label (bc_break)); - gimple_seq_add_stmt (&exit_seq, stmt); - } - + /* 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) { - entry = gimple_build_label - (create_artificial_label (stmt_locus)); - stmt = gimple_build_goto (gimple_label_label (entry)); + entry = build1 (LABEL_EXPR, void_type_node, + create_artificial_label (start_locus)); + t = build1_loc (start_locus, GOTO_EXPR, void_type_node, + LABEL_EXPR_LABEL (entry)); } else - stmt = gimple_build_goto (get_bc_label (bc_continue)); - gimple_set_location (stmt, stmt_locus); - gimple_seq_add_stmt (&stmt_list, stmt); + t = build1_loc (start_locus, GOTO_EXPR, void_type_node, + get_bc_label (bc_continue)); + append_to_statement_list (t, &stmt_list); } - } - else - { - stmt = gimple_build_goto (gimple_label_label (top)); - gimple_seq_add_stmt (&exit_seq, stmt); - } - } - gimplify_stmt (&body, &body_seq); - gimplify_stmt (&incr, &incr_seq); + t = build1 (GOTO_EXPR, void_type_node, get_bc_label (bc_break)); + exit = fold_build3_loc (start_locus, + COND_EXPR, void_type_node, cond, exit, t); + } - body_seq = finish_bc_block (bc_continue, cont_block, body_seq); + append_to_statement_list (top, &stmt_list); + } - gimple_seq_add_stmt (&stmt_list, top); - gimple_seq_add_seq (&stmt_list, body_seq); - gimple_seq_add_seq (&stmt_list, incr_seq); - gimple_seq_add_stmt (&stmt_list, entry); - gimple_seq_add_seq (&stmt_list, exit_seq); + append_to_statement_list (body, &stmt_list); + finish_bc_block (&stmt_list, bc_continue, clab); + append_to_statement_list (incr, &stmt_list); + append_to_statement_list (entry, &stmt_list); + append_to_statement_list (exit, &stmt_list); + finish_bc_block (&stmt_list, bc_break, blab); - annotate_all_with_location (stmt_list, stmt_locus); + if (stmt_list == NULL_TREE) + stmt_list = build1 (NOP_EXPR, void_type_node, integer_zero_node); - return finish_bc_block (bc_break, break_block, stmt_list); + *stmt_p = stmt_list; } -/* Gimplify a FOR_STMT node. Move the stuff in the for-init-stmt into the - prequeue and hand off to gimplify_cp_loop. */ +/* Genericize a FOR_STMT node *STMT_P. */ static void -gimplify_for_stmt (tree *stmt_p, gimple_seq *pre_p) +genericize_for_stmt (tree *stmt_p, int *walk_subtrees, void *data) { tree stmt = *stmt_p; + tree expr = NULL; + tree loop; + tree init = FOR_INIT_STMT (stmt); - if (FOR_INIT_STMT (stmt)) - gimplify_and_add (FOR_INIT_STMT (stmt), pre_p); + if (init) + { + cp_walk_tree (&init, cp_genericize_r, data, NULL); + append_to_statement_list (init, &expr); + } - gimple_seq_add_seq (pre_p, - gimplify_cp_loop (FOR_COND (stmt), FOR_BODY (stmt), - FOR_EXPR (stmt), 1)); - *stmt_p = NULL_TREE; + genericize_cp_loop (&loop, EXPR_LOCATION (stmt), FOR_COND (stmt), + FOR_BODY (stmt), FOR_EXPR (stmt), 1, walk_subtrees, data); + append_to_statement_list (loop, &expr); + *stmt_p = expr; } -/* Gimplify a WHILE_STMT node. */ +/* Genericize a WHILE_STMT node *STMT_P. */ static void -gimplify_while_stmt (tree *stmt_p, gimple_seq *pre_p) +genericize_while_stmt (tree *stmt_p, int *walk_subtrees, void *data) { tree stmt = *stmt_p; - gimple_seq_add_seq (pre_p, - gimplify_cp_loop (WHILE_COND (stmt), WHILE_BODY (stmt), - NULL_TREE, 1)); - *stmt_p = NULL_TREE; + genericize_cp_loop (stmt_p, EXPR_LOCATION (stmt), WHILE_COND (stmt), + WHILE_BODY (stmt), NULL_TREE, 1, walk_subtrees, data); } -/* Gimplify a DO_STMT node. */ +/* Genericize a DO_STMT node *STMT_P. */ static void -gimplify_do_stmt (tree *stmt_p, gimple_seq *pre_p) +genericize_do_stmt (tree *stmt_p, int *walk_subtrees, void *data) { tree stmt = *stmt_p; - gimple_seq_add_seq (pre_p, - gimplify_cp_loop (DO_COND (stmt), DO_BODY (stmt), - NULL_TREE, 0)); - *stmt_p = NULL_TREE; + genericize_cp_loop (stmt_p, EXPR_LOCATION (stmt), DO_COND (stmt), + DO_BODY (stmt), NULL_TREE, 0, walk_subtrees, data); } -/* Genericize a SWITCH_STMT by turning it into a SWITCH_EXPR. */ +/* Genericize a SWITCH_STMT node *STMT_P by turning it into a SWITCH_EXPR. */ static void -gimplify_switch_stmt (tree *stmt_p, gimple_seq *pre_p) +genericize_switch_stmt (tree *stmt_p, int *walk_subtrees, void *data) { tree stmt = *stmt_p; - tree break_block, body, t; - location_t stmt_locus = input_location; - gimple_seq seq = NULL; + tree break_block, body, cond, type; + location_t stmt_locus = EXPR_LOCATION (stmt); - break_block = begin_bc_block (bc_break); + break_block = begin_bc_block (bc_break, stmt_locus); body = SWITCH_STMT_BODY (stmt); if (!body) body = build_empty_stmt (stmt_locus); + cond = SWITCH_STMT_COND (stmt); + type = SWITCH_STMT_TYPE (stmt); - t = build3 (SWITCH_EXPR, SWITCH_STMT_TYPE (stmt), - SWITCH_STMT_COND (stmt), body, NULL_TREE); - SET_EXPR_LOCATION (t, stmt_locus); - gimplify_and_add (t, &seq); + cp_walk_tree (&body, cp_genericize_r, data, NULL); + cp_walk_tree (&cond, cp_genericize_r, data, NULL); + cp_walk_tree (&type, cp_genericize_r, data, NULL); + *walk_subtrees = 0; - seq = finish_bc_block (bc_break, break_block, seq); - gimple_seq_add_seq (pre_p, seq); - *stmt_p = NULL_TREE; + *stmt_p = build3_loc (stmt_locus, SWITCH_EXPR, type, cond, body, NULL_TREE); + finish_bc_block (stmt_p, bc_break, break_block); +} + +/* Genericize a CONTINUE_STMT node *STMT_P. */ + +static void +genericize_continue_stmt (tree *stmt_p) +{ + tree stmt_list = NULL; + tree pred = build_predict_expr (PRED_CONTINUE, NOT_TAKEN); + tree label = get_bc_label (bc_continue); + location_t location = EXPR_LOCATION (*stmt_p); + tree jump = build1_loc (location, GOTO_EXPR, void_type_node, label); + append_to_statement_list (pred, &stmt_list); + append_to_statement_list (jump, &stmt_list); + *stmt_p = stmt_list; +} + +/* Genericize a BREAK_STMT node *STMT_P. */ + +static void +genericize_break_stmt (tree *stmt_p) +{ + tree label = get_bc_label (bc_break); + location_t location = EXPR_LOCATION (*stmt_p); + *stmt_p = build1_loc (location, GOTO_EXPR, void_type_node, label); +} + +/* Genericize a OMP_FOR node *STMT_P. */ + +static void +genericize_omp_for_stmt (tree *stmt_p, int *walk_subtrees, void *data) +{ + tree stmt = *stmt_p; + location_t locus = EXPR_LOCATION (stmt); + tree clab = begin_bc_block (bc_continue, locus); + + cp_walk_tree (&OMP_FOR_BODY (stmt), cp_genericize_r, data, NULL); + cp_walk_tree (&OMP_FOR_CLAUSES (stmt), cp_genericize_r, data, NULL); + cp_walk_tree (&OMP_FOR_INIT (stmt), cp_genericize_r, data, NULL); + cp_walk_tree (&OMP_FOR_COND (stmt), cp_genericize_r, data, NULL); + cp_walk_tree (&OMP_FOR_INCR (stmt), cp_genericize_r, data, NULL); + cp_walk_tree (&OMP_FOR_PRE_BODY (stmt), cp_genericize_r, data, NULL); + *walk_subtrees = 0; + + finish_bc_block (&OMP_FOR_BODY (stmt), bc_continue, clab); } -/* Hook into the middle of gimplifying an OMP_FOR node. This is required - in order to properly gimplify CONTINUE statements. Here we merely - manage the continue stack; the rest of the job is performed by the - regular gimplifier. */ +/* Hook into the middle of gimplifying an OMP_FOR node. */ static enum gimplify_status cp_gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) { tree for_stmt = *expr_p; - tree cont_block; - gimple stmt; gimple_seq seq = NULL; /* Protect ourselves from recursion. */ @@ -357,18 +399,7 @@ cp_gimplify_omp_for (tree *expr_p, gimpl return GS_UNHANDLED; OMP_FOR_GIMPLIFYING_P (for_stmt) = 1; - /* Note that while technically the continue label is enabled too soon - here, we should have already diagnosed invalid continues nested within - statement expressions within the INIT, COND, or INCR expressions. */ - cont_block = begin_bc_block (bc_continue); - gimplify_and_add (for_stmt, &seq); - stmt = gimple_seq_last_stmt (seq); - if (gimple_code (stmt) == GIMPLE_OMP_FOR) - gimple_omp_set_body (stmt, finish_bc_block (bc_continue, cont_block, - gimple_omp_body (stmt))); - else - seq = finish_bc_block (bc_continue, cont_block, seq); gimple_seq_add_seq (pre_p, seq); OMP_FOR_GIMPLIFYING_P (for_stmt) = 0; @@ -528,6 +559,7 @@ cp_gimplify_expr (tree *expr_p, gimple_s init, VEC_INIT_EXPR_VALUE_INIT (*expr_p), from_array, tf_warning_or_error); + cp_genericize_tree (expr_p); ret = GS_OK; input_location = loc; } @@ -634,42 +666,17 @@ cp_gimplify_expr (tree *expr_p, gimple_s gcc_unreachable (); case FOR_STMT: - gimplify_for_stmt (expr_p, pre_p); - ret = GS_OK; - break; - case WHILE_STMT: - gimplify_while_stmt (expr_p, pre_p); - ret = GS_OK; - break; - case DO_STMT: - gimplify_do_stmt (expr_p, pre_p); - ret = GS_OK; - break; - case SWITCH_STMT: - gimplify_switch_stmt (expr_p, pre_p); - ret = GS_OK; - break; + case CONTINUE_STMT: + case BREAK_STMT: + gcc_unreachable (); case OMP_FOR: ret = cp_gimplify_omp_for (expr_p, pre_p); break; - case CONTINUE_STMT: - gimple_seq_add_stmt (pre_p, gimple_build_predict (PRED_CONTINUE, NOT_TAKEN)); - gimple_seq_add_stmt (pre_p, gimple_build_goto (get_bc_label (bc_continue))); - *expr_p = NULL_TREE; - ret = GS_ALL_DONE; - break; - - case BREAK_STMT: - gimple_seq_add_stmt (pre_p, gimple_build_goto (get_bc_label (bc_break))); - *expr_p = NULL_TREE; - ret = GS_ALL_DONE; - break; - case EXPR_STMT: gimplify_expr_stmt (expr_p); ret = GS_OK; @@ -1102,17 +1109,45 @@ cp_genericize_r (tree *stmt_p, int *walk } else if (TREE_CODE (stmt) == CONVERT_EXPR) gcc_assert (!CONVERT_EXPR_VBASE_PATH (stmt)); + else if (TREE_CODE (stmt) == FOR_STMT) + genericize_for_stmt (stmt_p, walk_subtrees, data); + else if (TREE_CODE (stmt) == WHILE_STMT) + genericize_while_stmt (stmt_p, walk_subtrees, data); + else if (TREE_CODE (stmt) == DO_STMT) + genericize_do_stmt (stmt_p, walk_subtrees, data); + else if (TREE_CODE (stmt) == SWITCH_STMT) + genericize_switch_stmt (stmt_p, walk_subtrees, data); + else if (TREE_CODE (stmt) == CONTINUE_STMT) + genericize_continue_stmt (stmt_p); + else if (TREE_CODE (stmt) == BREAK_STMT) + genericize_break_stmt (stmt_p); + else if (TREE_CODE (stmt) == OMP_FOR) + genericize_omp_for_stmt (stmt_p, walk_subtrees, data); pointer_set_insert (p_set, *stmt_p); return NULL; } +/* Lower C++ front end trees to GENERIC in T_P. */ + +static void +cp_genericize_tree (tree* t_p) +{ + struct cp_genericize_data wtd; + + wtd.p_set = pointer_set_create (); + wtd.bind_expr_stack = NULL; + wtd.omp_ctx = NULL; + cp_walk_tree (t_p, cp_genericize_r, &wtd, NULL); + pointer_set_destroy (wtd.p_set); + VEC_free (tree, heap, wtd.bind_expr_stack); +} + void cp_genericize (tree fndecl) { tree t; - struct cp_genericize_data wtd; /* Fix up the types of parms passed by invisible reference. */ for (t = DECL_ARGUMENTS (fndecl); t; t = DECL_CHAIN (t)) @@ -1163,12 +1198,7 @@ cp_genericize (tree fndecl) /* We do want to see every occurrence of the parms, so we can't just use walk_tree's hash functionality. */ - wtd.p_set = pointer_set_create (); - wtd.bind_expr_stack = NULL; - wtd.omp_ctx = NULL; - cp_walk_tree (&DECL_SAVED_TREE (fndecl), cp_genericize_r, &wtd, NULL); - pointer_set_destroy (wtd.p_set); - VEC_free (tree, heap, wtd.bind_expr_stack); + cp_genericize_tree (&DECL_SAVED_TREE (fndecl)); /* Do everything else. */ c_genericize (fndecl); Index: gcc/testsuite/g++.dg/pr51264-4.C =================================================================== --- /dev/null (new file) +++ gcc/testsuite/g++.dg/pr51264-4.C (revision 0) @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -Werror -Wreturn-type" } */ + +/* Test-case from http://gcc.gnu.org/bugzilla/show_bug.cgi?id=25973#c4. */ + +struct Block +{ + public: + Block (); + ~Block (); +}; + +bool func (bool bar) +{ + Block block; + bool foo = false; + + if (!foo || bar) + do + { + return true; + } + while (0); + else + do + { + return false; + } + while (0); +}