From patchwork Mon Nov 21 20:33:04 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Torvald Riegel X-Patchwork-Id: 126924 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 BAFB0B7204 for ; Tue, 22 Nov 2011 07:33:34 +1100 (EST) Received: (qmail 31518 invoked by alias); 21 Nov 2011 20:33:32 -0000 Received: (qmail 31494 invoked by uid 22791); 21 Nov 2011 20:33:28 -0000 X-SWARE-Spam-Status: No, hits=-7.1 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, SPF_HELO_PASS, TW_TM, TW_TX X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 21 Nov 2011 20:33:10 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id pALKXA0o032118 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 21 Nov 2011 15:33:10 -0500 Received: from [10.36.6.232] (vpn1-6-232.ams2.redhat.com [10.36.6.232]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id pALKX4G7023550; Mon, 21 Nov 2011 15:33:05 -0500 Subject: [patch] Support noexcept-specifications for transaction statements and expressions. From: Torvald Riegel To: GCC Patches Cc: Richard Henderson , Aldy Hernandez , Jason Merrill Date: Mon, 21 Nov 2011 21:33:04 +0100 Message-ID: <1321907584.12248.141.camel@triegel.csb> Mime-Version: 1.0 X-IsSubscribed: yes 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 This revision of the patch is now complete and passes all the tests I could come up with. Compared to previous iterations, I added parsing of noexcept without explicit true/false. This makes cp_parser_noexcept_specification_opt a bit more complex, but we can now reuse it. The other two patches I posted recently (fixing instantiations, handling MUST_NOT_THROW_EXPR in voidify_wrapper_expr) are required for noexcept support to work. OK for trunk? commit 0d82e90a50631296a67813605b7aeebd586064d6 Author: Torvald Riegel Date: Tue Nov 15 15:00:48 2011 +0100 Support noexcept-specifications for transaction statements and expressions. gcc/ * tree.h (TRANSACTION_EXPR_NOEX): New. * tree.def (TRANSACTION_EXPR): Add noexcept spec as 2nd operand. * c-parser.c (c_parser_transaction_expression): Adapt to this. * c-typeck.c (c_finish_transaction): Same. gcc/cp/ * semantics.c (finish_transaction_stmt, build_transaction_expr): Accept new noexcept parameter and handle it. (begin_transaction_stmt): Adapt to additional noexcept operand. * cp-tree.h (finish_transaction_stmt, build_transaction_expr): Adapt declarations. * parser.c (cp_parser_exception_specification_opt): Extract noexcept-specification parsing to ... (cp_parser_noexcept_specification_opt): ...here. Allow for parsing non-constexpr noexcept arguments. (cp_parser_transaction, cp_parser_transaction_expression): Parse and handle noexcept-specifications. (cp_parser_function_transaction): Adapt to finish_transaction_stmt change. * pt.c (tsubst_expr): Handle noexcept specs when instantiating transactions. gcc/testsuite/ * g++.dg/tm/noexcept-1.C: New test. * g++.dg/tm/noexcept-2.C: New test. * g++.dg/tm/noexcept-3.C: New test. * g++.dg/tm/noexcept-4.C: New test. * g++.dg/tm/noexcept-5.C: New test. diff --git a/gcc/c-parser.c b/gcc/c-parser.c index b88b11f..e1ce35f 100644 --- a/gcc/c-parser.c +++ b/gcc/c-parser.c @@ -10703,7 +10703,8 @@ c_parser_transaction_expression (c_parser *parser, enum rid keyword) { tree expr = c_parser_expression (parser).value; ret.original_type = TREE_TYPE (expr); - ret.value = build1 (TRANSACTION_EXPR, ret.original_type, expr); + ret.value = build2 (TRANSACTION_EXPR, ret.original_type, expr, + NULL_TREE); if (this_in & TM_STMT_ATTR_RELAXED) TRANSACTION_EXPR_RELAXED (ret.value) = 1; SET_EXPR_LOCATION (ret.value, loc); diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 4a134b0..f015ff6 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -10930,7 +10930,7 @@ c_finish_omp_clauses (tree clauses) tree c_finish_transaction (location_t loc, tree block, int flags) { - tree stmt = build_stmt (loc, TRANSACTION_EXPR, block); + tree stmt = build_stmt (loc, TRANSACTION_EXPR, block, NULL_TREE); if (flags & TM_STMT_ATTR_OUTER) TRANSACTION_EXPR_OUTER (stmt) = 1; if (flags & TM_STMT_ATTR_RELAXED) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3f4f408..ba124cf 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5571,8 +5571,8 @@ extern void finish_omp_barrier (void); extern void finish_omp_flush (void); extern void finish_omp_taskwait (void); extern tree begin_transaction_stmt (location_t, tree *, int); -extern void finish_transaction_stmt (tree, tree, int); -extern tree build_transaction_expr (location_t, tree, int); +extern void finish_transaction_stmt (tree, tree, int, tree); +extern tree build_transaction_expr (location_t, tree, int, tree); extern void finish_omp_taskyield (void); extern bool cxx_omp_create_clause_info (tree, tree, bool, bool, bool); extern tree baselink_for_fns (tree); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 4a2b2a9..dea59f1 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -19509,19 +19509,23 @@ cp_parser_base_specifier (cp_parser* parser) /* Exception handling [gram.exception] */ -/* Parse an (optional) exception-specification. +/* Parse an (optional) noexcept-specification. - exception-specification: - throw ( type-id-list [opt] ) + noexcept-specification: + noexcept ( constant-expression ) [opt] - Returns a TREE_LIST representing the exception-specification. The - TREE_VALUE of each node is a type. */ + If no noexcept-specification is present, returns NULL_TREE. + Otherwise, if REQUIRE_CONSTEXPR is false, then either parse and return any + expression if parentheses follow noexcept, or return BOOLEAN_TRUE_NODE if + there are no parentheses. CONSUMED_EXPR will be set accordingly. + Otherwise, returns a noexcept specification. */ static tree -cp_parser_exception_specification_opt (cp_parser* parser) +cp_parser_noexcept_specification_opt (cp_parser* parser, + bool require_constexpr, + bool* consumed_expr) { cp_token *token; - tree type_id_list; const char *saved_message; /* Peek at the next token. */ @@ -19537,23 +19541,66 @@ cp_parser_exception_specification_opt (cp_parser* parser) { cp_lexer_consume_token (parser->lexer); - /* Types may not be defined in an exception-specification. */ - saved_message = parser->type_definition_forbidden_message; - parser->type_definition_forbidden_message - = G_("types may not be defined in an exception-specification"); + if (require_constexpr) + { + /* Types may not be defined in an exception-specification. */ + saved_message = parser->type_definition_forbidden_message; + parser->type_definition_forbidden_message + = G_("types may not be defined in an exception-specification"); - expr = cp_parser_constant_expression (parser, false, NULL); + expr = cp_parser_constant_expression (parser, false, NULL); - /* Restore the saved message. */ - parser->type_definition_forbidden_message = saved_message; + /* Restore the saved message. */ + parser->type_definition_forbidden_message = saved_message; + } + else + { + expr = cp_parser_expression (parser, false, NULL); + *consumed_expr = true; + } cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); } else - expr = boolean_true_node; + { + expr = boolean_true_node; + if (!require_constexpr) + *consumed_expr = false; + } - return build_noexcept_spec (expr, tf_warning_or_error); + /* We cannot build a noexcept-spec right away because this will check + that expr is a constexpr. */ + if (require_constexpr) + return build_noexcept_spec (expr, tf_warning_or_error); + else + return expr; } + else + return NULL_TREE; +} + +/* Parse an (optional) exception-specification. + + exception-specification: + throw ( type-id-list [opt] ) + + Returns a TREE_LIST representing the exception-specification. The + TREE_VALUE of each node is a type. */ + +static tree +cp_parser_exception_specification_opt (cp_parser* parser) +{ + cp_token *token; + tree type_id_list; + const char *saved_message; + + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + + /* Is it a noexcept-specification? */ + type_id_list = cp_parser_noexcept_specification_opt(parser, true, NULL); + if (type_id_list != NULL_TREE) + return type_id_list; /* If it's not `throw', then there's no exception-specification. */ if (!cp_parser_is_keyword (token, RID_THROW)) @@ -26778,11 +26825,9 @@ cp_parser_txn_attribute_opt (cp_parser *parser) /* Parse a __transaction_atomic or __transaction_relaxed statement. transaction-statement: - __transaction_atomic txn-attribute[opt] txn-exception-spec[opt] + __transaction_atomic txn-attribute[opt] txn-noexcept-spec[opt] compound-statement - __transaction_relaxed txn-exception-spec[opt] compound-statement - - ??? The exception specification is not yet implemented. + __transaction_relaxed txn-noexcept-spec[opt] compound-statement */ static tree @@ -26791,7 +26836,7 @@ cp_parser_transaction (cp_parser *parser, enum rid keyword) unsigned char old_in = parser->in_transaction; unsigned char this_in = 1, new_in; cp_token *token; - tree stmt, attrs; + tree stmt, attrs, noex; gcc_assert (keyword == RID_TRANSACTION_ATOMIC || keyword == RID_TRANSACTION_RELAXED); @@ -26809,6 +26854,9 @@ cp_parser_transaction (cp_parser *parser, enum rid keyword) this_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER); } + /* Parse a noexcept specification. */ + noex = cp_parser_noexcept_specification_opt(parser, true, NULL); + /* Keep track if we're in the lexical scope of an outer transaction. */ new_in = this_in | (old_in & TM_STMT_ATTR_OUTER); @@ -26818,7 +26866,7 @@ cp_parser_transaction (cp_parser *parser, enum rid keyword) cp_parser_compound_statement (parser, NULL, false, false); parser->in_transaction = old_in; - finish_transaction_stmt (stmt, NULL, this_in); + finish_transaction_stmt (stmt, NULL, this_in, noex); return stmt; } @@ -26826,10 +26874,8 @@ cp_parser_transaction (cp_parser *parser, enum rid keyword) /* Parse a __transaction_atomic or __transaction_relaxed expression. transaction-expression: - __transaction_atomic txn-exception-spec[opt] ( expression ) - __transaction_relaxed txn-exception-spec[opt] ( expression ) - - ??? The exception specification is not yet implemented. + __transaction_atomic txn-noexcept-spec[opt] ( expression ) + __transaction_relaxed txn-noexcept-spec[opt] ( expression ) */ static tree @@ -26838,7 +26884,8 @@ cp_parser_transaction_expression (cp_parser *parser, enum rid keyword) unsigned char old_in = parser->in_transaction; unsigned char this_in = 1; cp_token *token; - tree expr; + tree expr, noex; + bool noex_expr; gcc_assert (keyword == RID_TRANSACTION_ATOMIC || keyword == RID_TRANSACTION_RELAXED); @@ -26858,14 +26905,39 @@ cp_parser_transaction_expression (cp_parser *parser, enum rid keyword) if (keyword == RID_TRANSACTION_RELAXED) this_in |= TM_STMT_ATTR_RELAXED; + /* Set this early. This might mean that we allow transaction_cancel in + an expression that we find out later actually has to be a constexpr. + However, we expect that cxx_constant_value will be able to deal with + this; also, if the noexcept has no constexpr, then what we parse next + really is a transaction's body. */ parser->in_transaction = this_in; - cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); - expr = cp_parser_expression (parser, /*cast_p=*/false, NULL); - finish_parenthesized_expr (expr); - expr = build_transaction_expr (token->location, expr, this_in); + /* Parse a noexcept specification. */ + noex = cp_parser_noexcept_specification_opt(parser, false, &noex_expr); - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + if (!noex || !noex_expr + || cp_lexer_peek_token (parser->lexer)->type == CPP_OPEN_PAREN) + { + cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); + + expr = cp_parser_expression (parser, /*cast_p=*/false, NULL); + finish_parenthesized_expr (expr); + + cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + } + else + { + /* The only expression that is available got parsed for the noexcept + already. noexcept is true then. */ + expr = noex; + noex = boolean_true_node; + } + + /* Now we know which expression is supposed to be a constexpr. */ + if (noex && noex != error_mark_node) + noex = build_noexcept_spec (noex, tf_warning_or_error); + + expr = build_transaction_expr (token->location, expr, this_in, noex); parser->in_transaction = old_in; if (cp_parser_non_integral_constant_expression (parser, NIC_TRANSACTION)) @@ -26921,7 +26993,7 @@ cp_parser_function_transaction (cp_parser *parser, enum rid keyword) parser->in_transaction = old_in; - finish_transaction_stmt (stmt, compound_stmt, new_in); + finish_transaction_stmt (stmt, compound_stmt, new_in, NULL_TREE); return ctor_initializer_p; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f817b6f..a5b5d48 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13204,22 +13204,41 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, case TRANSACTION_EXPR: { int flags = 0; + tree noex; flags |= (TRANSACTION_EXPR_OUTER (t) ? TM_STMT_ATTR_OUTER : 0); flags |= (TRANSACTION_EXPR_RELAXED (t) ? TM_STMT_ATTR_RELAXED : 0); + noex = TRANSACTION_EXPR_NOEX (t); + if (noex) + { + if (noex != noexcept_false_spec && noex != noexcept_true_spec + && noex != error_mark_node) + { + /* Finish processing the noexcept expression. */ + noex = tsubst_copy_and_build (noex, args, complain, in_decl, + /*function_p=*/false, + /*integral_const_expr_p=*/true); + noex = build_noexcept_spec (TREE_PURPOSE (noex), + tf_warning_or_error); + } + gcc_assert (noex == noexcept_false_spec + || noex == noexcept_true_spec + || noex == error_mark_node); + TRANSACTION_EXPR_NOEX (t) = NULL_TREE; + } - if (TRANSACTION_EXPR_IS_STMT (t)) - { - stmt = begin_transaction_stmt (input_location, NULL, flags); - RECUR (TRANSACTION_EXPR_BODY (t)); - finish_transaction_stmt (stmt, NULL, flags); - } - else - { - stmt = build_transaction_expr (EXPR_LOCATION (t), + if (TRANSACTION_EXPR_IS_STMT (t)) + { + stmt = begin_transaction_stmt (input_location, NULL, flags); + RECUR (TRANSACTION_EXPR_BODY (t)); + finish_transaction_stmt (stmt, NULL, flags, noex); + } + else + { + stmt = build_transaction_expr (EXPR_LOCATION (t), RECUR (TRANSACTION_EXPR_BODY (t)), - flags); - return stmt; - } + flags, noex); + return stmt; + } } break; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index fe685fa..a49437d 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5000,7 +5000,7 @@ begin_transaction_stmt (location_t loc, tree *pcompound, int flags) if (pcompound) *pcompound = begin_compound_stmt (0); - r = build_stmt (loc, TRANSACTION_EXPR, NULL_TREE); + r = build_stmt (loc, TRANSACTION_EXPR, NULL_TREE, NULL_TREE); /* Only add the statement to the function if support enabled. */ if (flag_tm) @@ -5018,28 +5018,57 @@ begin_transaction_stmt (location_t loc, tree *pcompound, int flags) /* End a __transaction_atomic or __transaction_relaxed statement. If COMPOUND_STMT is non-null, this is for a function-transaction-block, - and we should end the compound. */ + and we should end the compound. If NOEX is NOEXCEPT_TRUE_SPEC, we wrap + the body in a MUST_NOT_THROW_EXPR. */ void -finish_transaction_stmt (tree stmt, tree compound_stmt, int flags) +finish_transaction_stmt (tree stmt, tree compound_stmt, int flags, tree noex) { TRANSACTION_EXPR_BODY (stmt) = pop_stmt_list (TRANSACTION_EXPR_BODY (stmt)); TRANSACTION_EXPR_OUTER (stmt) = (flags & TM_STMT_ATTR_OUTER) != 0; TRANSACTION_EXPR_RELAXED (stmt) = (flags & TM_STMT_ATTR_RELAXED) != 0; TRANSACTION_EXPR_IS_STMT (stmt) = 1; + /* noexcept specifications are not allowed for function transactions. */ + gcc_assert (!(noex && compound_stmt)); + if (processing_template_decl) + TRANSACTION_EXPR_NOEX (stmt) = noex; + else if (noex == noexcept_true_spec) + { + tree body = TRANSACTION_EXPR_BODY (stmt); + body = build1 (MUST_NOT_THROW_EXPR, TREE_TYPE (body), body); + SET_EXPR_LOCATION (body, EXPR_LOCATION (TRANSACTION_EXPR_BODY (stmt))); + TREE_SIDE_EFFECTS (body) = 1; + TRANSACTION_EXPR_BODY (stmt) = body; + } + if (compound_stmt) finish_compound_stmt (compound_stmt); finish_stmt (); } -/* Build a __transaction_atomic or __transaction_relaxed expression. */ +/* Build a __transaction_atomic or __transaction_relaxed expression. If + NOEX is NOEXCEPT_TRUE_SPEC, we wrap the body in a MUST_NOT_THROW_EXPR. */ tree -build_transaction_expr (location_t loc, tree expr, int flags) +build_transaction_expr (location_t loc, tree expr, int flags, tree noex) { tree ret; - ret = build1 (TRANSACTION_EXPR, TREE_TYPE (expr), expr); + if (!processing_template_decl) + { + /* We can build the noexcept-specification now because we don't have + a template and can require NOEX to be a constexpr. + if (noex && noex != error_mark_node) + noex = build_noexcept_spec (noex, tf_warning_or_error); */ + if (noex == noexcept_true_spec) + { + expr = build1 (MUST_NOT_THROW_EXPR, TREE_TYPE (expr), expr); + SET_EXPR_LOCATION (expr, loc); + TREE_SIDE_EFFECTS (expr) = 1; + } + noex = NULL_TREE; + } + ret = build2 (TRANSACTION_EXPR, TREE_TYPE (expr), expr, noex); if (flags & TM_STMT_ATTR_RELAXED) TRANSACTION_EXPR_RELAXED (ret) = 1; SET_EXPR_LOCATION (ret, loc); diff --git a/gcc/testsuite/g++.dg/tm/noexcept-1.C b/gcc/testsuite/g++.dg/tm/noexcept-1.C new file mode 100644 index 0000000..86940d2 --- /dev/null +++ b/gcc/testsuite/g++.dg/tm/noexcept-1.C @@ -0,0 +1,38 @@ +// { dg-do compile } +// { dg-options "-fgnu-tm -O -std=c++0x -fdump-tree-tmmark -fdump-tree-tmlower" } + +struct TrueFalse +{ + static constexpr bool v() { return true; } +}; + +int global; + +template int foo() +{ + __transaction_atomic noexcept(T::v()) { global += 1; } + return __transaction_atomic noexcept(T::v()) (global + 2); +} + +int f1() +{ + return foo(); +} + +int f2() +{ + return __transaction_atomic noexcept(true) (global + 3) + + __transaction_atomic noexcept(TrueFalse::v()) (global + 4); +} + +int f3() +{ + __transaction_atomic noexcept(true) { global += 5; } + __transaction_atomic noexcept(TrueFalse::v()) { global += 6; } + return global; +} + +/* { dg-final { scan-tree-dump-times "eh_must_not_throw" 6 "tmlower" } } */ +/* { dg-final { scan-tree-dump-times "ITM_RU4\\s*\\(&global" 6 "tmmark" } } */ +/* { dg-final { cleanup-tree-dump "tmmark" } } */ +/* { dg-final { cleanup-tree-dump "tmlower" } } */ diff --git a/gcc/testsuite/g++.dg/tm/noexcept-2.C b/gcc/testsuite/g++.dg/tm/noexcept-2.C new file mode 100644 index 0000000..f9cbbb6 --- /dev/null +++ b/gcc/testsuite/g++.dg/tm/noexcept-2.C @@ -0,0 +1,20 @@ +// { dg-do compile } +// { dg-options "-fgnu-tm -std=c++0x" } + +// All of these must fail, because they are not constant expressions. +template int foo(int x, T t) +{ + __transaction_atomic noexcept(t) { x++; } /* { dg-error "not a constant" } */ + return __transaction_atomic noexcept(t) (x+1); /* { dg-error "not a constant" } */ +} + +int bar(int x) +{ + __transaction_atomic noexcept(x == 23) { x++; } /* { dg-error "not a constant" } */ + return __transaction_atomic noexcept(x == 42) (x+1); /* { dg-error "not a constant" } */ +} + +int f(int x) +{ + return foo(x, true); +} diff --git a/gcc/testsuite/g++.dg/tm/noexcept-3.C b/gcc/testsuite/g++.dg/tm/noexcept-3.C new file mode 100644 index 0000000..5a49ade --- /dev/null +++ b/gcc/testsuite/g++.dg/tm/noexcept-3.C @@ -0,0 +1,40 @@ +// { dg-do compile } +// { dg-options "-fgnu-tm -O -std=c++0x -fdump-tree-tmmark -fdump-tree-tmlower" } + +// Same as noexcept-1.C but all noexcepts are false. + +struct TrueFalse +{ + static constexpr bool v() { return false; } +}; + +int global; + +template int foo() +{ + __transaction_atomic noexcept(T::v()) { global += 1; } + return __transaction_atomic noexcept(T::v()) (global + 2); +} + +int f1() +{ + return foo(); +} + +int f2() +{ + return __transaction_atomic noexcept(false) (global + 3) + + __transaction_atomic noexcept(TrueFalse::v()) (global + 4); +} + +int f3() +{ + __transaction_atomic noexcept(false) { global += 5; } + __transaction_atomic noexcept(TrueFalse::v()) { global += 6; } + return global; +} + +/* { dg-final { scan-tree-dump-times "eh_must_not_throw" 0 "tmlower" } } */ +/* { dg-final { scan-tree-dump-times "ITM_RU4\\s*\\(&global" 6 "tmmark" } } */ +/* { dg-final { cleanup-tree-dump "tmmark" } } */ +/* { dg-final { cleanup-tree-dump "tmlower" } } */ diff --git a/gcc/testsuite/g++.dg/tm/noexcept-4.C b/gcc/testsuite/g++.dg/tm/noexcept-4.C new file mode 100644 index 0000000..b2674f5 --- /dev/null +++ b/gcc/testsuite/g++.dg/tm/noexcept-4.C @@ -0,0 +1,35 @@ +// { dg-do compile } +// { dg-options "-fgnu-tm -O -std=c++0x -fdump-tree-tmmark -fdump-tree-tmlower" } + +// Similar to noexcept-1.C but without an explicit (true) for noexcept. + +struct TrueFalse +{ + static constexpr bool v() { return true; } +}; + +int global; + +template int foo() +{ + __transaction_atomic noexcept { global += 1; } + return __transaction_atomic noexcept (global + 2) + + __transaction_atomic noexcept (global + 3); +} + +int f1() +{ + return foo(); +} + +int f3() +{ + __transaction_atomic noexcept { global += 4; } + return __transaction_atomic noexcept (global + 5) + + __transaction_atomic noexcept (global + 6); +} + +/* { dg-final { scan-tree-dump-times "eh_must_not_throw" 6 "tmlower" } } */ +/* { dg-final { scan-tree-dump-times "ITM_RU4\\s*\\(&global" 6 "tmmark" } } */ +/* { dg-final { cleanup-tree-dump "tmmark" } } */ +/* { dg-final { cleanup-tree-dump "tmlower" } } */ diff --git a/gcc/testsuite/g++.dg/tm/noexcept-5.C b/gcc/testsuite/g++.dg/tm/noexcept-5.C new file mode 100644 index 0000000..c56fc0d --- /dev/null +++ b/gcc/testsuite/g++.dg/tm/noexcept-5.C @@ -0,0 +1,21 @@ +// { dg-do compile } +// { dg-options "-fgnu-tm -O -std=c++0x -fdump-tree-tmmark -fdump-tree-tmlower" } + +int global; + +void f2(int x) +{ + __transaction_atomic + { + __transaction_atomic noexcept(true) + { + global += 1; + if (x) + throw 23; + } + } +} +/* { dg-final { scan-tree-dump-times "eh_must_not_throw" 1 "tmlower" } } */ +/* { dg-final { scan-tree-dump-times "ITM_RU4\\s*\\(&global" 1 "tmmark" } } */ +/* { dg-final { cleanup-tree-dump "tmmark" } } */ +/* { dg-final { cleanup-tree-dump "tmlower" } } */ diff --git a/gcc/tree.def b/gcc/tree.def index 2a2363e..e87fc61 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1077,8 +1077,9 @@ DEFTREECODE (OMP_ATOMIC_CAPTURE_NEW, "omp_atomic_capture_new", tcc_statement, 2) DEFTREECODE (OMP_CLAUSE, "omp_clause", tcc_exceptional, 0) /* TRANSACTION_EXPR tree code. - Operand 0: BODY: contains body of the transaction. */ -DEFTREECODE (TRANSACTION_EXPR, "transaction_expr", tcc_expression, 1) + Operand 0: BODY: contains body of the transaction. + Operand 1: contains noexcept argument, if noexcept has been specified. */ +DEFTREECODE (TRANSACTION_EXPR, "transaction_expr", tcc_expression, 2) /* Reduction operations. Operations that take a vector of elements and "reduce" it to a scalar diff --git a/gcc/tree.h b/gcc/tree.h index a76b0bc..6307aca 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1826,6 +1826,8 @@ extern void protected_set_expr_location (tree, location_t); /* TM directives and accessors. */ #define TRANSACTION_EXPR_BODY(NODE) \ TREE_OPERAND (TRANSACTION_EXPR_CHECK (NODE), 0) +#define TRANSACTION_EXPR_NOEX(NODE) \ + TREE_OPERAND (TRANSACTION_EXPR_CHECK (NODE), 1) #define TRANSACTION_EXPR_OUTER(NODE) \ (TRANSACTION_EXPR_CHECK (NODE)->base.static_flag) #define TRANSACTION_EXPR_RELAXED(NODE) \