diff options
author | Aldy Hernandez <aldyh@gcc.gnu.org> | 2011-11-08 11:13:41 +0000 |
---|---|---|
committer | Aldy Hernandez <aldyh@gcc.gnu.org> | 2011-11-08 11:13:41 +0000 |
commit | 0a35513e4e73ec9c6f24e791d344308ad3ed030d (patch) | |
tree | e07de8d0b6265f8d72388d335bd471022e753d57 /gcc/cp | |
parent | 287188ea072dd887a17dd56360531c3a22307e7c (diff) | |
download | gcc-0a35513e4e73ec9c6f24e791d344308ad3ed030d.zip gcc-0a35513e4e73ec9c6f24e791d344308ad3ed030d.tar.gz gcc-0a35513e4e73ec9c6f24e791d344308ad3ed030d.tar.bz2 |
Merge from transactional-memory branch.
From-SVN: r181154
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 37 | ||||
-rw-r--r-- | gcc/cp/call.c | 3 | ||||
-rw-r--r-- | gcc/cp/class.c | 154 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 8 | ||||
-rw-r--r-- | gcc/cp/decl.c | 2 | ||||
-rw-r--r-- | gcc/cp/except.c | 49 | ||||
-rw-r--r-- | gcc/cp/parser.c | 339 | ||||
-rw-r--r-- | gcc/cp/parser.h | 4 | ||||
-rw-r--r-- | gcc/cp/pt.c | 22 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 59 |
10 files changed, 667 insertions, 10 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index bcdecdf..15b44b5 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,40 @@ +2011-11-07 Richard Henderson <rth@redhat.com> + Aldy Hernandez <aldyh@redhat.com> + Torvald Riegel <triegel@redhat.com> + + Merged from transactional-memory. + + * call.c (build_new_function_call): Call tm_malloc_replacement. + * class.c (check_bases): Compute transaction attributes for the + class based on its base classes. + (look_for_tm_attr_overrides, set_one_vmethod_tm_attributes, + set_method_tm_attributes): New. + (finish_struct_1): Call set_method_tm_attributes. + * cp-tree.h (begin_transaction_stmt, finish_transaction_stmt, + build_transaction_expr): Declare. + (TRANSACTION_EXPR_IS_STMT): New. + * decl.c (push_cp_library_fn): Set attribute to transaction_safe. + * except.c (do_get_exception_ptr): Apply transaction_pure. + (do_begin_catch): Mark _ITM_cxa_begin_catch transaction_pure and + record as transactional-memory wrapper. + (do_end_catch): Similarly for _ITM_cxa_end_catch. + (do_allocate_exception): Similarly for _ITM_cxa_allocate_exception. + (build_throw): Similarly for _ITM_cxa_throw. Make __cxa_rethrow pure. + * parser.h (struct cp_parser): Add in_transaction flag. + * parser.c (enum non_integral_constant): Add NIC_TRANSACTION. + (cp_parser_non_integral_constant_expression): Handle NIC_TRANSACTION. + (enum required_token): Add transaction tokens. + (cp_parser_transaction, cp_parser_transaction_expression, + cp_parser_function_transaction, cp_parser_transaction_cancel, + cp_parser_txn_attribute_opt): New. + (cp_parser_unary_expression): Handle RID_TRANSACTION*. + (cp_parser_statement, cp_parser_function_definition_after_declarator, + cp_parser_token_starts_function_definition_p): Same. + (cp_parser_required_error): Handle RT_TRANSACTION*. + * pt.c (tsubst_expr): Handle TRANSACTION_EXPR. + * semantics.c (begin_transaction_stmt, finish_transaction_stmt, + build_transaction_expr): New. + 2011-11-08 Dodji Seketeli <dodji@redhat.com> Fix context handling of alias-declaration diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 2bf22f9..578905e 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -3826,6 +3826,9 @@ build_new_function_call (tree fn, VEC(tree,gc) **args, bool koenig_p, return error_mark_node; } + if (flag_tm) + tm_malloc_replacement (fn); + /* If this function was found without using argument dependent lookup, then we want to ignore any undeclared friend functions. */ diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 1775868..be632be 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -1227,13 +1227,12 @@ check_bases (tree t, int* no_const_asn_ref_p) { int i; - int seen_non_virtual_nearly_empty_base_p; + bool seen_non_virtual_nearly_empty_base_p = 0; + int seen_tm_mask = 0; tree base_binfo; tree binfo; tree field = NULL_TREE; - seen_non_virtual_nearly_empty_base_p = 0; - if (!CLASSTYPE_NON_STD_LAYOUT (t)) for (field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field)) if (TREE_CODE (field) == FIELD_DECL) @@ -1338,6 +1337,23 @@ check_bases (tree t, break; } } + + /* Don't bother collecting tm attributes if transactional memory + support is not enabled. */ + if (flag_tm) + { + tree tm_attr = find_tm_attribute (TYPE_ATTRIBUTES (basetype)); + if (tm_attr) + seen_tm_mask |= tm_attr_to_mask (tm_attr); + } + } + + /* If one of the base classes had TM attributes, and the current class + doesn't define its own, then the current class inherits one. */ + if (seen_tm_mask && !find_tm_attribute (TYPE_ATTRIBUTES (t))) + { + tree tm_attr = tm_mask_to_attr (seen_tm_mask & -seen_tm_mask); + TYPE_ATTRIBUTES (t) = tree_cons (tm_attr, NULL, TYPE_ATTRIBUTES (t)); } } @@ -4258,6 +4274,137 @@ clone_constructors_and_destructors (tree t) clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/1); } +/* Subroutine of set_one_vmethod_tm_attributes. Search base classes + of TYPE for virtual functions which FNDECL overrides. Return a + mask of the tm attributes found therein. */ + +static int +look_for_tm_attr_overrides (tree type, tree fndecl) +{ + tree binfo = TYPE_BINFO (type); + tree base_binfo; + int ix, found = 0; + + for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ++ix) + { + tree o, basetype = BINFO_TYPE (base_binfo); + + if (!TYPE_POLYMORPHIC_P (basetype)) + continue; + + o = look_for_overrides_here (basetype, fndecl); + if (o) + found |= tm_attr_to_mask (find_tm_attribute + (TYPE_ATTRIBUTES (TREE_TYPE (o)))); + else + found |= look_for_tm_attr_overrides (basetype, fndecl); + } + + return found; +} + +/* Subroutine of set_method_tm_attributes. Handle the checks and + inheritance for one virtual method FNDECL. */ + +static void +set_one_vmethod_tm_attributes (tree type, tree fndecl) +{ + tree tm_attr; + int found, have; + + found = look_for_tm_attr_overrides (type, fndecl); + + /* If FNDECL doesn't actually override anything (i.e. T is the + class that first declares FNDECL virtual), then we're done. */ + if (found == 0) + return; + + tm_attr = find_tm_attribute (TYPE_ATTRIBUTES (TREE_TYPE (fndecl))); + have = tm_attr_to_mask (tm_attr); + + /* Intel STM Language Extension 3.0, Section 4.2 table 4: + tm_pure must match exactly, otherwise no weakening of + tm_safe > tm_callable > nothing. */ + /* ??? The tm_pure attribute didn't make the transition to the + multivendor language spec. */ + if (have == TM_ATTR_PURE) + { + if (found != TM_ATTR_PURE) + { + found &= -found; + goto err_override; + } + } + /* If the overridden function is tm_pure, then FNDECL must be. */ + else if (found == TM_ATTR_PURE && tm_attr) + goto err_override; + /* Look for base class combinations that cannot be satisfied. */ + else if (found != TM_ATTR_PURE && (found & TM_ATTR_PURE)) + { + found &= ~TM_ATTR_PURE; + found &= -found; + error_at (DECL_SOURCE_LOCATION (fndecl), + "method overrides both %<transaction_pure%> and %qE methods", + tm_mask_to_attr (found)); + } + /* If FNDECL did not declare an attribute, then inherit the most + restrictive one. */ + else if (tm_attr == NULL) + { + apply_tm_attr (fndecl, tm_mask_to_attr (found & -found)); + } + /* Otherwise validate that we're not weaker than a function + that is being overridden. */ + else + { + found &= -found; + if (found <= TM_ATTR_CALLABLE && have > found) + goto err_override; + } + return; + + err_override: + error_at (DECL_SOURCE_LOCATION (fndecl), + "method declared %qE overriding %qE method", + tm_attr, tm_mask_to_attr (found)); +} + +/* For each of the methods in T, propagate a class-level tm attribute. */ + +static void +set_method_tm_attributes (tree t) +{ + tree class_tm_attr, fndecl; + + /* Don't bother collecting tm attributes if transactional memory + support is not enabled. */ + if (!flag_tm) + return; + + /* Process virtual methods first, as they inherit directly from the + base virtual function and also require validation of new attributes. */ + if (TYPE_CONTAINS_VPTR_P (t)) + { + tree vchain; + for (vchain = BINFO_VIRTUALS (TYPE_BINFO (t)); vchain; + vchain = TREE_CHAIN (vchain)) + set_one_vmethod_tm_attributes (t, BV_FN (vchain)); + } + + /* If the class doesn't have an attribute, nothing more to do. */ + class_tm_attr = find_tm_attribute (TYPE_ATTRIBUTES (t)); + if (class_tm_attr == NULL) + return; + + /* Any method that does not yet have a tm attribute inherits + the one from the class. */ + for (fndecl = TYPE_METHODS (t); fndecl; fndecl = TREE_CHAIN (fndecl)) + { + if (!find_tm_attribute (TYPE_ATTRIBUTES (TREE_TYPE (fndecl)))) + apply_tm_attr (fndecl, class_tm_attr); + } +} + /* Returns true iff class T has a user-defined constructor other than the default constructor. */ @@ -5841,6 +5988,7 @@ finish_struct_1 (tree t) } finish_struct_bits (t); + set_method_tm_attributes (t); /* Complete the rtl for any static member objects of the type we're working on. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 177f100..32d08ca 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -73,6 +73,7 @@ c-common.h, not after. VEC_INIT_EXPR_IS_CONSTEXPR (in VEC_INIT_EXPR) DECL_OVERRIDE_P (in FUNCTION_DECL) IMPLICIT_CONV_EXPR_DIRECT_INIT (in IMPLICIT_CONV_EXPR) + TRANSACTION_EXPR_IS_STMT (in TRANSACTION_EXPR) 1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE) TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. @@ -3890,6 +3891,10 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) TREE_TYPE (OMP_CLAUSE_RANGE_CHECK (NODE, OMP_CLAUSE_PRIVATE, \ OMP_CLAUSE_COPYPRIVATE)) +/* Nonzero if this transaction expression's body contains statements. */ +#define TRANSACTION_EXPR_IS_STMT(NODE) \ + TREE_LANG_FLAG_0 (TRANSACTION_EXPR_CHECK (NODE)) + /* These macros provide convenient access to the various _STMT nodes created when parsing template declarations. */ #define TRY_STMTS(NODE) TREE_OPERAND (TRY_BLOCK_CHECK (NODE), 0) @@ -5556,6 +5561,9 @@ extern void finish_omp_atomic (enum tree_code, enum tree_code, 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_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/decl.c b/gcc/cp/decl.c index 1c33776..1c46adf 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4001,6 +4001,8 @@ push_cp_library_fn (enum tree_code operator_code, tree type) operator_code, type); pushdecl (fn); + if (flag_tm) + apply_tm_attr (fn, get_identifier ("transaction_safe")); return fn; } diff --git a/gcc/cp/except.c b/gcc/cp/except.c index e529685..670a66f 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -173,6 +173,9 @@ do_get_exception_ptr (void) { /* Declare void* __cxa_get_exception_ptr (void *) throw(). */ fn = declare_nothrow_library_fn (fn, ptr_type_node, ptr_type_node); + + if (flag_tm) + apply_tm_attr (fn, get_identifier ("transaction_pure")); } return cp_build_function_call_nary (fn, tf_warning_or_error, @@ -192,6 +195,17 @@ do_begin_catch (void) { /* Declare void* __cxa_begin_catch (void *) throw(). */ fn = declare_nothrow_library_fn (fn, ptr_type_node, ptr_type_node); + + /* Create its transactional-memory equivalent. */ + if (flag_tm) + { + tree fn2 = get_identifier ("_ITM_cxa_begin_catch"); + if (!get_global_value_if_present (fn2, &fn2)) + fn2 = declare_nothrow_library_fn (fn2, ptr_type_node, + ptr_type_node); + apply_tm_attr (fn2, get_identifier ("transaction_pure")); + record_tm_replacement (fn, fn2); + } } return cp_build_function_call_nary (fn, tf_warning_or_error, @@ -231,6 +245,19 @@ do_end_catch (tree type) fn = push_void_library_fn (fn, void_list_node); /* This can throw if the destructor for the exception throws. */ TREE_NOTHROW (fn) = 0; + + /* Create its transactional-memory equivalent. */ + if (flag_tm) + { + tree fn2 = get_identifier ("_ITM_cxa_end_catch"); + if (!get_global_value_if_present (fn2, &fn2)) + { + fn2 = push_void_library_fn (fn2, void_list_node); + TREE_NOTHROW (fn2) = 0; + } + apply_tm_attr (fn2, get_identifier ("transaction_pure")); + record_tm_replacement (fn, fn2); + } } cleanup = cp_build_function_call_vec (fn, NULL, tf_warning_or_error); @@ -581,6 +608,16 @@ do_allocate_exception (tree type) { /* Declare void *__cxa_allocate_exception(size_t) throw(). */ fn = declare_nothrow_library_fn (fn, ptr_type_node, size_type_node); + + if (flag_tm) + { + tree fn2 = get_identifier ("_ITM_cxa_allocate_exception"); + if (!get_global_value_if_present (fn2, &fn2)) + fn2 = declare_nothrow_library_fn (fn2, ptr_type_node, + size_type_node); + apply_tm_attr (fn2, get_identifier ("transaction_pure")); + record_tm_replacement (fn, fn2); + } } return cp_build_function_call_nary (fn, tf_warning_or_error, @@ -712,6 +749,15 @@ build_throw (tree exp) ptr_type_node, ptr_type_node, cleanup_type, NULL_TREE); fn = push_throw_library_fn (fn, tmp); + + if (flag_tm) + { + tree fn2 = get_identifier ("_ITM_cxa_throw"); + if (!get_global_value_if_present (fn2, &fn2)) + fn2 = push_throw_library_fn (fn2, tmp); + apply_tm_attr (fn2, get_identifier ("transaction_pure")); + record_tm_replacement (fn, fn2); + } } /* [except.throw] @@ -831,6 +877,9 @@ build_throw (tree exp) (fn, build_function_type_list (void_type_node, NULL_TREE)); } + if (flag_tm) + apply_tm_attr (fn, get_identifier ("transaction_pure")); + /* ??? Indicate that this function call allows exceptions of the type of the enclosing catch block (if known). */ exp = cp_build_function_call_vec (fn, NULL, tf_warning_or_error); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 3d35877..12f3c40 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -106,7 +106,9 @@ typedef enum non_integral_constant { /* a comma operator */ NIC_COMMA, /* a call to a constructor */ - NIC_CONSTRUCTOR + NIC_CONSTRUCTOR, + /* a transaction expression */ + NIC_TRANSACTION } non_integral_constant; /* The various kinds of errors about name-lookup failing. */ @@ -171,7 +173,10 @@ typedef enum required_token { RT_INTERATION, /* iteration-statement */ RT_JUMP, /* jump-statement */ RT_CLASS_KEY, /* class-key */ - RT_CLASS_TYPENAME_TEMPLATE /* class, typename, or template */ + RT_CLASS_TYPENAME_TEMPLATE, /* class, typename, or template */ + RT_TRANSACTION_ATOMIC, /* __transaction_atomic */ + RT_TRANSACTION_RELAXED, /* __transaction_relaxed */ + RT_TRANSACTION_CANCEL /* __transaction_cancel */ } required_token; /* Prototypes. */ @@ -2106,6 +2111,17 @@ static bool cp_parser_extension_opt static void cp_parser_label_declaration (cp_parser *); +/* Transactional Memory Extensions */ + +static tree cp_parser_transaction + (cp_parser *, enum rid); +static tree cp_parser_transaction_expression + (cp_parser *, enum rid); +static bool cp_parser_function_transaction + (cp_parser *, enum rid); +static tree cp_parser_transaction_cancel + (cp_parser *); + enum pragma_context { pragma_external, pragma_stmt, pragma_compound }; static bool cp_parser_pragma (cp_parser *, enum pragma_context); @@ -2671,6 +2687,10 @@ cp_parser_non_integral_constant_expression (cp_parser *parser, error ("a call to a constructor " "cannot appear in a constant-expression"); return true; + case NIC_TRANSACTION: + error ("a transaction expression " + "cannot appear in a constant-expression"); + return true; case NIC_THIS: msg = "this"; break; @@ -6372,6 +6392,10 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p, } break; + case RID_TRANSACTION_ATOMIC: + case RID_TRANSACTION_RELAXED: + return cp_parser_transaction_expression (parser, keyword); + case RID_NOEXCEPT: { tree expr; @@ -8506,6 +8530,11 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) declaration-statement try-block + TM Extension: + + statement: + atomic-statement + IN_COMPOUND is true when the statement is nested inside a cp_parser_compound_statement; this matters for certain pragmas. @@ -8582,6 +8611,14 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, cp_parser_declaration_statement (parser); return; + case RID_TRANSACTION_ATOMIC: + case RID_TRANSACTION_RELAXED: + statement = cp_parser_transaction (parser, keyword); + break; + case RID_TRANSACTION_CANCEL: + statement = cp_parser_transaction_cancel (parser); + break; + default: /* It might be a keyword like `int' that can start a declaration-statement. */ @@ -15194,6 +15231,11 @@ cp_parser_asm_definition (cp_parser* parser) function-definition: __extension__ function-definition + TM Extension: + + function-definition: + decl-specifier-seq [opt] declarator function-transaction-block + The DECL_SPECIFIERS apply to this declarator. Returns a representation of the entity declared. If MEMBER_P is TRUE, then this declarator appears in a class scope. The new DECL created by @@ -20911,12 +20953,19 @@ cp_parser_function_definition_after_declarator (cp_parser* parser, start_lambda_scope (current_function_decl); - /* If the next token is `try', then we are looking at a - function-try-block. */ - if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY)) + /* If the next token is `try', `__transaction_atomic', or + `__transaction_relaxed`, then we are looking at either function-try-block + or function-transaction-block. Note that all of these include the + function-body. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRANSACTION_ATOMIC)) + ctor_initializer_p = cp_parser_function_transaction (parser, + RID_TRANSACTION_ATOMIC); + else if (cp_lexer_next_token_is_keyword (parser->lexer, + RID_TRANSACTION_RELAXED)) + ctor_initializer_p = cp_parser_function_transaction (parser, + RID_TRANSACTION_RELAXED); + else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY)) ctor_initializer_p = cp_parser_function_try_block (parser); - /* A function-try-block includes the function-body, so we only do - this next part if we're not processing a function-try-block. */ else ctor_initializer_p = cp_parser_ctor_initializer_opt_and_function_body (parser); @@ -22073,6 +22122,12 @@ cp_parser_required_error (cp_parser *parser, case RT_AT_THROW: cp_parser_error (parser, "expected %<@throw%>"); return; + case RT_TRANSACTION_ATOMIC: + cp_parser_error (parser, "expected %<__transaction_atomic%>"); + return; + case RT_TRANSACTION_RELAXED: + cp_parser_error (parser, "expected %<__transaction_relaxed%>"); + return; default: break; } @@ -22303,6 +22358,10 @@ cp_parser_token_starts_function_definition_p (cp_token* token) || token->type == CPP_COLON /* A function-try-block begins with `try'. */ || token->keyword == RID_TRY + /* A function-transaction-block begins with `__transaction_atomic' + or `__transaction_relaxed'. */ + || token->keyword == RID_TRANSACTION_ATOMIC + || token->keyword == RID_TRANSACTION_RELAXED /* The named return value extension begins with `return'. */ || token->keyword == RID_RETURN); } @@ -26623,6 +26682,272 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) SET_EXPR_LOCATION (stmt, pragma_tok->location); } +/* Transactional Memory parsing routines. */ + +/* Parse a transaction attribute. + + txn-attribute: + attribute + [ [ identifier ] ] + + ??? Simplify this when C++0x bracket attributes are + implemented properly. */ + +static tree +cp_parser_txn_attribute_opt (cp_parser *parser) +{ + cp_token *token; + tree attr_name, attr = NULL; + + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE)) + return cp_parser_attributes_opt (parser); + + if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_SQUARE)) + return NULL_TREE; + cp_lexer_consume_token (parser->lexer); + if (!cp_parser_require (parser, CPP_OPEN_SQUARE, RT_OPEN_SQUARE)) + goto error1; + + token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_NAME || token->type == CPP_KEYWORD) + { + token = cp_lexer_consume_token (parser->lexer); + + attr_name = (token->type == CPP_KEYWORD + /* For keywords, use the canonical spelling, + not the parsed identifier. */ + ? ridpointers[(int) token->keyword] + : token->u.value); + attr = build_tree_list (attr_name, NULL_TREE); + } + else + cp_parser_error (parser, "expected identifier"); + + cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE); + error1: + cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE); + return attr; +} + +/* Parse a __transaction_atomic or __transaction_relaxed statement. + + transaction-statement: + __transaction_atomic txn-attribute[opt] txn-exception-spec[opt] + compound-statement + __transaction_relaxed txn-exception-spec[opt] compound-statement + + ??? The exception specification is not yet implemented. +*/ + +static tree +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; + + gcc_assert (keyword == RID_TRANSACTION_ATOMIC + || keyword == RID_TRANSACTION_RELAXED); + token = cp_parser_require_keyword (parser, keyword, + (keyword == RID_TRANSACTION_ATOMIC ? RT_TRANSACTION_ATOMIC + : RT_TRANSACTION_RELAXED)); + gcc_assert (token != NULL); + + if (keyword == RID_TRANSACTION_RELAXED) + this_in |= TM_STMT_ATTR_RELAXED; + else + { + attrs = cp_parser_txn_attribute_opt (parser); + if (attrs) + this_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER); + } + + /* Keep track if we're in the lexical scope of an outer transaction. */ + new_in = this_in | (old_in & TM_STMT_ATTR_OUTER); + + stmt = begin_transaction_stmt (token->location, NULL, this_in); + + parser->in_transaction = new_in; + cp_parser_compound_statement (parser, NULL, false, false); + parser->in_transaction = old_in; + + finish_transaction_stmt (stmt, NULL, this_in); + + return stmt; +} + +/* 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. +*/ + +static tree +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 ret; + + gcc_assert (keyword == RID_TRANSACTION_ATOMIC + || keyword == RID_TRANSACTION_RELAXED); + + if (!flag_tm) + error (keyword == RID_TRANSACTION_RELAXED + ? G_("%<__transaction_relaxed%> without transactional memory " + "support enabled") + : G_("%<__transaction_atomic%> without transactional memory " + "support enabled")); + + token = cp_parser_require_keyword (parser, keyword, + (keyword == RID_TRANSACTION_ATOMIC ? RT_TRANSACTION_ATOMIC + : RT_TRANSACTION_RELAXED)); + gcc_assert (token != NULL); + + if (keyword == RID_TRANSACTION_RELAXED) + this_in |= TM_STMT_ATTR_RELAXED; + + parser->in_transaction = this_in; + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + { + tree expr = cp_parser_expression (parser, /*cast_p=*/false, NULL); + ret = build_transaction_expr (token->location, expr, this_in); + } + else + { + cp_parser_error (parser, "expected %<(%>"); + ret = error_mark_node; + } + parser->in_transaction = old_in; + + if (cp_parser_non_integral_constant_expression (parser, NIC_TRANSACTION)) + return error_mark_node; + + return (flag_tm ? ret : error_mark_node); +} + +/* Parse a function-transaction-block. + + function-transaction-block: + __transaction_atomic txn-attribute[opt] ctor-initializer[opt] + function-body + __transaction_atomic txn-attribute[opt] function-try-block + __transaction_relaxed ctor-initializer[opt] function-body + __transaction_relaxed function-try-block +*/ + +static bool +cp_parser_function_transaction (cp_parser *parser, enum rid keyword) +{ + unsigned char old_in = parser->in_transaction; + unsigned char new_in = 1; + tree compound_stmt, stmt, attrs; + bool ctor_initializer_p; + cp_token *token; + + gcc_assert (keyword == RID_TRANSACTION_ATOMIC + || keyword == RID_TRANSACTION_RELAXED); + token = cp_parser_require_keyword (parser, keyword, + (keyword == RID_TRANSACTION_ATOMIC ? RT_TRANSACTION_ATOMIC + : RT_TRANSACTION_RELAXED)); + gcc_assert (token != NULL); + + if (keyword == RID_TRANSACTION_RELAXED) + new_in |= TM_STMT_ATTR_RELAXED; + else + { + attrs = cp_parser_txn_attribute_opt (parser); + if (attrs) + new_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER); + } + + stmt = begin_transaction_stmt (token->location, &compound_stmt, new_in); + + parser->in_transaction = new_in; + + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY)) + ctor_initializer_p = cp_parser_function_try_block (parser); + else + ctor_initializer_p + = cp_parser_ctor_initializer_opt_and_function_body (parser); + + parser->in_transaction = old_in; + + finish_transaction_stmt (stmt, compound_stmt, new_in); + + return ctor_initializer_p; +} + +/* Parse a __transaction_cancel statement. + + cancel-statement: + __transaction_cancel txn-attribute[opt] ; + __transaction_cancel txn-attribute[opt] throw-expression ; + + ??? Cancel and throw is not yet implemented. */ + +static tree +cp_parser_transaction_cancel (cp_parser *parser) +{ + cp_token *token; + bool is_outer = false; + tree stmt, attrs; + + token = cp_parser_require_keyword (parser, RID_TRANSACTION_CANCEL, + RT_TRANSACTION_CANCEL); + gcc_assert (token != NULL); + + attrs = cp_parser_txn_attribute_opt (parser); + if (attrs) + is_outer = (parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER) != 0); + + /* ??? Parse cancel-and-throw here. */ + + cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); + + if (!flag_tm) + { + error_at (token->location, "%<__transaction_cancel%> without " + "transactional memory support enabled"); + return error_mark_node; + } + else if (parser->in_transaction & TM_STMT_ATTR_RELAXED) + { + error_at (token->location, "%<__transaction_cancel%> within a " + "%<__transaction_relaxed%>"); + return error_mark_node; + } + else if (is_outer) + { + if ((parser->in_transaction & TM_STMT_ATTR_OUTER) == 0 + && !is_tm_may_cancel_outer (current_function_decl)) + { + error_at (token->location, "outer %<__transaction_cancel%> not " + "within outer %<__transaction_atomic%>"); + error_at (token->location, + " or a %<transaction_may_cancel_outer%> function"); + return error_mark_node; + } + } + else if (parser->in_transaction == 0) + { + error_at (token->location, "%<__transaction_cancel%> not within " + "%<__transaction_atomic%>"); + return error_mark_node; + } + + stmt = build_tm_abort_call (token->location, is_outer); + add_stmt (stmt); + finish_stmt (); + + return stmt; +} + /* The parser. */ static GTY (()) cp_parser *the_parser; diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index b44d23c..5b95f08 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -329,6 +329,10 @@ typedef struct GTY(()) cp_parser { a local class. */ bool in_function_body; + /* Nonzero if we're processing a __transaction_atomic or + __transaction_relaxed statement. */ + unsigned char in_transaction; + /* TRUE if we can auto-correct a colon to a scope operator. */ bool colon_corrects_to_scope_p; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index bf2a2c63..8c91a9e 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13108,6 +13108,28 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, } break; + case TRANSACTION_EXPR: + { + int flags = 0; + flags |= (TRANSACTION_EXPR_OUTER (t) ? TM_STMT_ATTR_OUTER : 0); + flags |= (TRANSACTION_EXPR_RELAXED (t) ? TM_STMT_ATTR_RELAXED : 0); + + 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), + RECUR (TRANSACTION_EXPR_BODY (t)), + flags); + return stmt; + } + } + break; + case EXPR_PACK_EXPANSION: error ("invalid use of pack expansion expression"); return error_mark_node; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 9d6bd31..508e252 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4968,6 +4968,64 @@ finish_omp_taskyield (void) finish_expr_stmt (stmt); } +/* Begin a __transaction_atomic or __transaction_relaxed statement. + If PCOMPOUND is non-null, this is for a function-transaction-block, and we + should create an extra compound stmt. */ + +tree +begin_transaction_stmt (location_t loc, tree *pcompound, int flags) +{ + tree r; + + if (pcompound) + *pcompound = begin_compound_stmt (0); + + r = build_stmt (loc, TRANSACTION_EXPR, NULL_TREE); + + /* Only add the statement to the function if support enabled. */ + if (flag_tm) + add_stmt (r); + else + error_at (loc, ((flags & TM_STMT_ATTR_RELAXED) != 0 + ? G_("%<__transaction_relaxed%> without " + "transactional memory support enabled") + : G_("%<__transaction_atomic%> without " + "transactional memory support enabled"))); + + TRANSACTION_EXPR_BODY (r) = push_stmt_list (); + return r; +} + +/* 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. */ + +void +finish_transaction_stmt (tree stmt, tree compound_stmt, int flags) +{ + 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; + + if (compound_stmt) + finish_compound_stmt (compound_stmt); + finish_stmt (); +} + +/* Build a __transaction_atomic or __transaction_relaxed expression. */ + +tree +build_transaction_expr (location_t loc, tree expr, int flags) +{ + tree ret; + ret = build1 (TRANSACTION_EXPR, TREE_TYPE (expr), expr); + if (flags & TM_STMT_ATTR_RELAXED) + TRANSACTION_EXPR_RELAXED (ret) = 1; + SET_EXPR_LOCATION (ret, loc); + return ret; +} + void init_cp_semantics (void) { @@ -8099,6 +8157,7 @@ potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags) case STMT_EXPR: case EXPR_STMT: case BIND_EXPR: + case TRANSACTION_EXPR: if (flags & tf_error) error ("expression %qE is not a constant-expression", t); return false; |