Here is the most recent version, which is now based on both Richard Henderson's fix for voidify_wrapper_expr (patch2) and Jason Merrill's conditional MUST_NOT_THROW_EXPR (patch3).
patch2: voidify_wrapper_expr wasn't handling MUST_NOT_THROW_EXPR. The patch adds a reasonable default handling that applies to this case (and this way, we don't need to teach language-independent code about MUST_NOT_THROW_EXPR). patch3: As Jason pointed out, storing the noexcept specification in the TRANSACTION_EXPR is less clean than just extending MUST_NOT_THROW_EXPR with support for a boolean condition. This patch does that, including instantiation etc. patch4: This is the noexcept patch again. Nothing changed since last time except it's now based on conditional MUST_NOT_THROW_EXPR, which simiplifies things. OK for trunk? On Mon, 2011-11-21 at 16:39 -0500, Jason Merrill wrote: > On 11/21/2011 04:27 PM, Torvald Riegel wrote: > > On Mon, 2011-11-21 at 16:06 -0500, Jason Merrill wrote: > >> At this point I think it'd be simpler to handle noexcept in a > >> transaction-expression directly in cp_parser_transaction_expression. > > > > And keep transaction statements as is, or change them as well? > > I don't have a strong opinion either way on statements, since they don't > have to deal with the ambiguity issue. Whichever seems more convenient > to you. > > >> Since TRANSACTION_EXPR_NOEX is only for the template representation, I'd > >> rather not add it to the language-independent tree code. Maybe > >> introduce a C++ template-specific NOEXCEPT_REGION tree code? > > > Hmm, I'm a bit confused because looking at the previous iterations of > > this patch we said that it's best to keep the noexcept information > > attached to the transactions. What made you change your mind? I don't > > see any changes to language-independent code that didn't exist in the > > previous iterations. > > Right, this issue just didn't occur to me before, sorry. > > Jason
commit 80fc3e71ee98e98fd0e75cd720fe9db25616f281 Author: Torvald Riegel <trie...@redhat.com> Date: Mon Nov 21 00:25:08 2011 +0100 Add default handling for outermost wrappers in voidify_wrapper_expr. gcc/ * gimplify.c (voidify_wrapper_expr): Add default handling for outermost wrapper. diff --git a/gcc/gimplify.c b/gcc/gimplify.c index f548e70..fe8d2f8 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -1081,6 +1081,15 @@ voidify_wrapper_expr (tree wrapper, tree temp) break; default: + /* Assume that any tree upon which voidify_wrapper_expr is + directly called is a wrapper, and that its body is op0. */ + if (p == &wrapper) + { + TREE_SIDE_EFFECTS (*p) = 1; + TREE_TYPE (*p) = void_type_node; + p = &TREE_OPERAND (*p, 0); + break; + } goto out; } }
commit c97d12da67d3b2936cdb75c31cc10c02e4fa388d Author: Torvald Riegel <trie...@redhat.com> Date: Thu Dec 8 12:23:57 2011 +0100 Add condition to MUST_NOT_THROW_EXPR. gcc/cp/ * cp-tree.def (MUST_NOT_THROW_EXPR): Add condition parameter. * cp-tree.h (MUST_NOT_THROW_COND): New. (build_must_not_throw_expr): Declare. * dump.c (cp_dump_tree): Dump MUST_NOT_THROW_EXPR condition. * except.c (build_must_not_throw_expr): New. (initialize_handler_parm): Use it. (begin_eh_spec_block, wrap_cleanups_r): Adapt to condition. * pt.c (tsubst_expr): Handle MUST_NOT_THROW_EXPR. diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 5fc5496..83e0b5b 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -281,8 +281,9 @@ DEFTREECODE (EH_SPEC_BLOCK, "eh_spec_block", tcc_statement, 2) DEFTREECODE (HANDLER, "handler", tcc_statement, 2) /* A MUST_NOT_THROW_EXPR wraps an expression that may not - throw, and must call terminate if it does. */ -DEFTREECODE (MUST_NOT_THROW_EXPR, "must_not_throw_expr", tcc_expression, 1) + throw, and must call terminate if it does. The second argument + is a condition, used in templates to express noexcept (condition). */ +DEFTREECODE (MUST_NOT_THROW_EXPR, "must_not_throw_expr", tcc_expression, 2) /* A CLEANUP_STMT marks the point at which a declaration is fully constructed. The CLEANUP_EXPR is run on behalf of CLEANUP_DECL diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 955d0eb..c28b229 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3016,6 +3016,11 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define VEC_INIT_EXPR_VALUE_INIT(NODE) \ TREE_LANG_FLAG_1 (VEC_INIT_EXPR_CHECK (NODE)) +/* The condition under which this MUST_NOT_THROW_EXPR actually blocks + exceptions. NULL_TREE means 'true'. */ +#define MUST_NOT_THROW_COND(NODE) \ + TREE_OPERAND (MUST_NOT_THROW_EXPR_CHECK (NODE), 1) + /* The TYPE_MAIN_DECL for a class template type is a TYPE_DECL, not a TEMPLATE_DECL. This macro determines whether or not a given class type is really a template type, as opposed to an instantiation or @@ -5148,6 +5153,7 @@ extern bool type_noexcept_p (const_tree); extern bool type_throw_all_p (const_tree); extern tree build_noexcept_spec (tree, int); extern void choose_personality_routine (enum languages); +extern tree build_must_not_throw_expr (tree,tree); extern tree eh_type_info (tree); extern tree begin_eh_spec_block (void); extern void finish_eh_spec_block (tree, tree); diff --git a/gcc/cp/dump.c b/gcc/cp/dump.c index d1631fc..a461094 100644 --- a/gcc/cp/dump.c +++ b/gcc/cp/dump.c @@ -413,6 +413,7 @@ cp_dump_tree (void* dump_info, tree t) case MUST_NOT_THROW_EXPR: dump_stmt (di, t); dump_child ("body", TREE_OPERAND (t, 0)); + dump_child ("cond", MUST_NOT_THROW_COND (t)); break; case USING_STMT: diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 670a66f..c56dc2c 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -374,6 +374,28 @@ choose_personality_routine (enum languages lang) state = gave_error; } +/* Wrap EXPR in a MUST_NOT_THROW_EXPR expressing that EXPR must + not throw any exceptions if COND is true. A condition of + NULL_TREE is treated as 'true'. */ + +tree +build_must_not_throw_expr (tree body, tree cond) +{ + tree type = body ? TREE_TYPE (body) : void_type_node; + + if (cond && !value_dependent_expression_p (cond)) + { + cond = cxx_constant_value (cond); + if (integer_zerop (cond)) + return body; + else if (integer_onep (cond)) + cond = NULL_TREE; + } + + return build2 (MUST_NOT_THROW_EXPR, type, body, cond); +} + + /* Initialize the catch parameter DECL. */ static void @@ -418,7 +440,7 @@ initialize_handler_parm (tree decl, tree exp) /* Force cleanups now to avoid nesting problems with the MUST_NOT_THROW_EXPR. */ init = fold_build_cleanup_point_expr (TREE_TYPE (init), init); - init = build1 (MUST_NOT_THROW_EXPR, TREE_TYPE (init), init); + init = build_must_not_throw_expr (init, NULL_TREE); } decl = pushdecl (decl); @@ -560,7 +582,8 @@ begin_eh_spec_block (void) MUST_NOT_THROW_EXPR. */ if (TYPE_NOEXCEPT_P (TREE_TYPE (current_function_decl))) { - r = build_stmt (spec_location, MUST_NOT_THROW_EXPR, NULL_TREE); + r = build_stmt (spec_location, MUST_NOT_THROW_EXPR, + NULL_TREE, NULL_TREE); TREE_SIDE_EFFECTS (r) = 1; } else @@ -664,7 +687,8 @@ wrap_cleanups_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, cleanup = TARGET_EXPR_CLEANUP (exp); if (cleanup) { - cleanup = build1 (MUST_NOT_THROW_EXPR, void_type_node, cleanup); + cleanup = build2 (MUST_NOT_THROW_EXPR, void_type_node, cleanup, + NULL_TREE); TARGET_EXPR_CLEANUP (exp) = cleanup; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index bb5aa0c..f5a3175 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13260,6 +13260,10 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, } break; + case MUST_NOT_THROW_EXPR: + return build_must_not_throw_expr (RECUR (TREE_OPERAND (t, 0)), + RECUR (MUST_NOT_THROW_COND (t))); + case EXPR_PACK_EXPANSION: error ("invalid use of pack expansion expression"); return error_mark_node;
commit 09c6c04763b505525bdde3151a59219346a84de2 Author: Torvald Riegel <trie...@redhat.com> Date: Thu Dec 8 17:30:21 2011 +0100 Support noexcept-specifications for transaction statements and expressions. gcc/cp/ * semantics.c (finish_transaction_stmt, build_transaction_expr): Accept new noexcept parameter and handle it. * 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): Adapt to new noexcept parameters when building 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/cp/cp-tree.h b/gcc/cp/cp-tree.h index c28b229..f443816 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5587,8 +5587,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 5952a0f..bb685a6 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -19564,19 +19564,25 @@ 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 unless RETURN_COND is true, + in which case a boolean condition is returned instead. */ static tree -cp_parser_exception_specification_opt (cp_parser* parser) +cp_parser_noexcept_specification_opt (cp_parser* parser, + bool require_constexpr, + bool* consumed_expr, + bool return_cond) { cp_token *token; - tree type_id_list; const char *saved_message; /* Peek at the next token. */ @@ -19592,23 +19598,67 @@ 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 (!return_cond) + 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, + false); + 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)) @@ -26837,11 +26887,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 @@ -26850,7 +26898,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); @@ -26868,6 +26916,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, true); + /* Keep track if we're in the lexical scope of an outer transaction. */ new_in = this_in | (old_in & TM_STMT_ATTR_OUTER); @@ -26877,7 +26928,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; } @@ -26885,10 +26936,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 @@ -26897,7 +26946,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); @@ -26917,14 +26967,36 @@ 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, + true); - 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; + } + + 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)) @@ -26980,7 +27052,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 f5a3175..3b0cb23 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13246,15 +13246,24 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, if (TRANSACTION_EXPR_IS_STMT (t)) { + tree body = TRANSACTION_EXPR_BODY (t); + tree noex = NULL_TREE; + if (TREE_CODE (body) == MUST_NOT_THROW_EXPR) + { + noex = MUST_NOT_THROW_COND (body); + if (noex == NULL_TREE) + noex = boolean_true_node; + body = TREE_OPERAND (body, 0); + } stmt = begin_transaction_stmt (input_location, NULL, flags); - RECUR (TRANSACTION_EXPR_BODY (t)); - finish_transaction_stmt (stmt, NULL, flags); + RECUR (body); + finish_transaction_stmt (stmt, NULL, flags, RECUR (noex)); } else { stmt = build_transaction_expr (EXPR_LOCATION (t), RECUR (TRANSACTION_EXPR_BODY (t)), - flags); + flags, NULL_TREE); return stmt; } } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 2dab6a7..4b1ec46 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5020,27 +5020,47 @@ 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 non-NULL, we wrap the body in + a MUST_NOT_THROW_EXPR with NOEX as condition. */ 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 (noex) + { + tree body = build_must_not_throw_expr (TRANSACTION_EXPR_BODY (stmt), + noex); + 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 non-NULL, we wrap the body in a MUST_NOT_THROW_EXPR with NOEX as + condition. */ 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; + if (noex) + { + expr = build_must_not_throw_expr (expr, noex); + SET_EXPR_LOCATION (expr, loc); + TREE_SIDE_EFFECTS (expr) = 1; + } ret = build1 (TRANSACTION_EXPR, TREE_TYPE (expr), expr); if (flags & TM_STMT_ATTR_RELAXED) TRANSACTION_EXPR_RELAXED (ret) = 1; 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..9b1a8c6 --- /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<typename T> int foo() +{ + __transaction_atomic noexcept(T::v()) { global += 1; } + return __transaction_atomic noexcept(T::v()) (global + 2); +} + +int f1() +{ + return foo<TrueFalse>(); +} + +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_RU" 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<typename T> 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<bool>(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..958290e --- /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<typename T> int foo() +{ + __transaction_atomic noexcept(T::v()) { global += 1; } + return __transaction_atomic noexcept(T::v()) (global + 2); +} + +int f1() +{ + return foo<TrueFalse>(); +} + +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_RU" 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..1166a15 --- /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<typename T> int foo() +{ + __transaction_atomic noexcept { global += 1; } + return __transaction_atomic noexcept (global + 2) + + __transaction_atomic noexcept (global + 3); +} + +int f1() +{ + return foo<TrueFalse>(); +} + +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_RU" 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..44ef617 --- /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_RU" 1 "tmmark" } } */ +/* { dg-final { cleanup-tree-dump "tmmark" } } */ +/* { dg-final { cleanup-tree-dump "tmlower" } } */