mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-28 16:01:00 +08:00
Implement N4514, C++ Extensions for Transactional Memory.
gcc/ * builtins.def (BUILT_IN_ABORT): Add transaction_pure attribute. gcc/c-family/ * c-common.c (c_common_reswords): Add C++ TM TS keywords. (c_common_attribute_table): Add transaction_safe_dynamic. transaction_safe now affects type identity. (handle_tm_attribute): Handle transaction_safe_dynamic. * c-common.h (enum rid): Add RID_ATOMIC_NOEXCEPT, RID_ATOMIC_CANCEL, RID_SYNCHRONIZED. (OBJC_IS_CXX_KEYWORD): Add RID_SYNCHRONIZED. (D_TRANSMEM): New. * c-cppbuiltin.c (c_cpp_builtins): Define __cpp_transactional_memory. * c-pretty-print.c (pp_c_attributes_display): Don't print transaction_safe in C++. gcc/c/ * c-parser.c (c_lex_one_token): Handle @synchronized. * c-decl.c (match_builtin_function_types): A declaration of a built-in can change whether the function is transaction_safe. gcc/cp/ * cp-tree.h (struct cp_declarator): Add tx_qualifier field. (BCS_NORMAL, BCS_TRANSACTION): New enumerators. * lex.c (init_reswords): Limit TM kewords to -fgnu-tm. * parser.c (cp_lexer_get_preprocessor_token): Fix @synchronized. (make_call_declarator): Take tx_qualifier. (cp_parser_tx_qualifier_opt): New. (cp_parser_lambda_declarator_opt): Use it. (cp_parser_direct_declarator): Likewise. (cp_parser_statement): Handle atomic_noexcept, atomic_cancel. (cp_parser_compound_statement): Change in_try parameter to bcs_flags. (cp_parser_std_attribute): Map optimize_for_synchronized to transaction_callable. (cp_parser_transaction): Take the token. Handle atomic_noexcept. * lambda.c (maybe_add_lambda_conv_op): Handle transaction-safety. * call.c (enum conversion_kind): Add ck_tsafe. (standard_conversion): Handle transaction-safety conversion. (convert_like_real, resolve_address_of_overloaded_function): Likewise. (check_methods): Diagnose transaction_safe_dynamic on non-virtual function. (look_for_tm_attr_overrides): Don't inherit transaction_safe_dynamic. * cvt.c (tx_safe_fn_type_p, tx_unsafe_fn_variant) (can_convert_tx_safety): New. * typeck.c (composite_pointer_type): Handle transaction-safety. * name-lookup.h (enum scope_kind): Add sk_transaction. * name-lookup.c (begin_scope): Handle it. * semantics.c (begin_compound_stmt): Pass it. * decl.c (check_previous_goto_1): Check it. (struct named_label_entry): Add in_transaction_scope. (poplevel_named_label_1): Set it. (check_goto): Check it. (duplicate_decls): A specialization can be transaction_safe independently of its template. (grokdeclarator): Handle tx-qualifier. * rtti.c (ptr_initializer): Handle transaction-safe. * search.c (check_final_overrider): Check transaction_safe_dynamic. Don't check transaction_safe. * mangle.c (write_function_type): Mangle transaction_safe here. (write_CV_qualifiers_for_type): Not here. (write_type): Preserve transaction_safe when stripping attributes. * error.c (dump_type_suffix): Print transaction_safe. libiberty/ * cp-demangle.c (d_cv_qualifiers): Dx means transaction_safe. (cplus_demangle_type): Let d_cv_qualifiers handle it. (d_dump, d_make_comp, has_return_type, d_encoding) (d_count_templates_scopes, d_print_comp_inner) (d_print_mod_list, d_print_mod, d_print_function_type) (is_ctor_or_dtor): Handle DEMANGLE_COMPONENT_TRANSACTION_SAFE. From-SVN: r228462
This commit is contained in:
parent
bd841941ec
commit
b8fd7909c0
@ -1,3 +1,7 @@
|
||||
2015-10-04 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* builtins.def (BUILT_IN_ABORT): Add transaction_pure attribute.
|
||||
|
||||
2015-10-04 Uros Bizjak <ubizjak@gmail.com>
|
||||
|
||||
* config/i386/i386.c (ix86_nsaved_regs): Use GENERAL_REGNO_P to
|
||||
|
@ -729,7 +729,7 @@ DEF_GCC_BUILTIN (BUILT_IN_UMULL_OVERFLOW, "umull_overflow", BT_FN_BOOL_UL
|
||||
DEF_GCC_BUILTIN (BUILT_IN_UMULLL_OVERFLOW, "umulll_overflow", BT_FN_BOOL_ULONGLONG_ULONGLONG_ULONGLONGPTR, ATTR_NOTHROW_LEAF_LIST)
|
||||
|
||||
/* Category: miscellaneous builtins. */
|
||||
DEF_LIB_BUILTIN (BUILT_IN_ABORT, "abort", BT_FN_VOID, ATTR_NORETURN_NOTHROW_LEAF_LIST)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_ABORT, "abort", BT_FN_VOID, ATTR_TMPURE_NORETURN_NOTHROW_LEAF_LIST)
|
||||
DEF_LIB_BUILTIN (BUILT_IN_ABS, "abs", BT_FN_INT_INT, ATTR_CONST_NOTHROW_LEAF_LIST)
|
||||
DEF_GCC_BUILTIN (BUILT_IN_AGGREGATE_INCOMING_ADDRESS, "aggregate_incoming_address", BT_FN_PTR_VAR, ATTR_LEAF_LIST)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_ALLOCA, "alloca", BT_FN_PTR_SIZE, ATTR_MALLOC_NOTHROW_LEAF_LIST)
|
||||
|
@ -1,3 +1,18 @@
|
||||
2015-10-04 Jason Merrill <jason@redhat.com>
|
||||
|
||||
Implement N4514, C++ Extensions for Transactional Memory.
|
||||
* c-common.c (c_common_reswords): Add C++ TM TS keywords.
|
||||
(c_common_attribute_table): Add transaction_safe_dynamic.
|
||||
transaction_safe now affects type identity.
|
||||
(handle_tm_attribute): Handle transaction_safe_dynamic.
|
||||
* c-common.h (enum rid): Add RID_ATOMIC_NOEXCEPT,
|
||||
RID_ATOMIC_CANCEL, RID_SYNCHRONIZED.
|
||||
(OBJC_IS_CXX_KEYWORD): Add RID_SYNCHRONIZED.
|
||||
(D_TRANSMEM): New.
|
||||
* c-cppbuiltin.c (c_cpp_builtins): Define __cpp_transactional_memory.
|
||||
* c-pretty-print.c (pp_c_attributes_display): Don't print
|
||||
transaction_safe in C++.
|
||||
|
||||
2015-10-02 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
* c.opt (Wduplicated-cond): Don't enable by -Wall anymore.
|
||||
|
@ -594,6 +594,12 @@ const struct c_common_resword c_common_reswords[] =
|
||||
{ "wchar_t", RID_WCHAR, D_CXXONLY },
|
||||
{ "while", RID_WHILE, 0 },
|
||||
|
||||
/* C++ transactional memory. */
|
||||
{ "synchronized", RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
|
||||
{ "atomic_noexcept", RID_ATOMIC_NOEXCEPT, D_CXXONLY | D_TRANSMEM },
|
||||
{ "atomic_cancel", RID_ATOMIC_CANCEL, D_CXXONLY | D_TRANSMEM },
|
||||
{ "atomic_commit", RID_TRANSACTION_ATOMIC, D_CXXONLY | D_TRANSMEM },
|
||||
|
||||
/* Concepts-related keywords */
|
||||
{ "concept", RID_CONCEPT, D_CXX_CONCEPTS_FLAGS | D_CXXWARN },
|
||||
{ "requires", RID_REQUIRES, D_CXX_CONCEPTS_FLAGS | D_CXXWARN },
|
||||
@ -609,7 +615,6 @@ const struct c_common_resword c_common_reswords[] =
|
||||
{ "protocol", RID_AT_PROTOCOL, D_OBJC },
|
||||
{ "selector", RID_AT_SELECTOR, D_OBJC },
|
||||
{ "finally", RID_AT_FINALLY, D_OBJC },
|
||||
{ "synchronized", RID_AT_SYNCHRONIZED, D_OBJC },
|
||||
{ "optional", RID_AT_OPTIONAL, D_OBJC },
|
||||
{ "required", RID_AT_REQUIRED, D_OBJC },
|
||||
{ "property", RID_AT_PROPERTY, D_OBJC },
|
||||
@ -728,8 +733,10 @@ const struct attribute_spec c_common_attribute_table[] =
|
||||
{ "transaction_callable", 0, 0, false, true, false,
|
||||
handle_tm_attribute, false },
|
||||
{ "transaction_unsafe", 0, 0, false, true, false,
|
||||
handle_tm_attribute, false },
|
||||
handle_tm_attribute, true },
|
||||
{ "transaction_safe", 0, 0, false, true, false,
|
||||
handle_tm_attribute, true },
|
||||
{ "transaction_safe_dynamic", 0, 0, true, false, false,
|
||||
handle_tm_attribute, false },
|
||||
{ "transaction_may_cancel_outer", 0, 0, false, true, false,
|
||||
handle_tm_attribute, false },
|
||||
@ -9136,6 +9143,23 @@ handle_tm_attribute (tree *node, tree name, tree args,
|
||||
}
|
||||
break;
|
||||
|
||||
case FUNCTION_DECL:
|
||||
{
|
||||
/* transaction_safe_dynamic goes on the FUNCTION_DECL, but we also
|
||||
want to set transaction_safe on the type. */
|
||||
gcc_assert (is_attribute_p ("transaction_safe_dynamic", name));
|
||||
if (!TYPE_P (DECL_CONTEXT (*node)))
|
||||
error_at (DECL_SOURCE_LOCATION (*node),
|
||||
"%<transaction_safe_dynamic%> may only be specified for "
|
||||
"a virtual function");
|
||||
*no_add_attrs = false;
|
||||
decl_attributes (&TREE_TYPE (*node),
|
||||
build_tree_list (get_identifier ("transaction_safe"),
|
||||
NULL_TREE),
|
||||
0);
|
||||
break;
|
||||
}
|
||||
|
||||
case POINTER_TYPE:
|
||||
{
|
||||
enum tree_code subcode = TREE_CODE (TREE_TYPE (*node));
|
||||
|
@ -154,6 +154,9 @@ enum rid
|
||||
/* C++ concepts */
|
||||
RID_CONCEPT, RID_REQUIRES,
|
||||
|
||||
/* C++ transactional memory. */
|
||||
RID_ATOMIC_NOEXCEPT, RID_ATOMIC_CANCEL, RID_SYNCHRONIZED,
|
||||
|
||||
/* Cilk Plus keywords. */
|
||||
RID_CILK_SPAWN, RID_CILK_SYNC, RID_CILK_FOR,
|
||||
|
||||
@ -246,7 +249,7 @@ enum rid
|
||||
is found elsewhere, it follows the rules of the C/C++ language.
|
||||
*/
|
||||
#define OBJC_IS_CXX_KEYWORD(rid) \
|
||||
(rid == RID_CLASS \
|
||||
(rid == RID_CLASS || rid == RID_SYNCHRONIZED \
|
||||
|| rid == RID_PUBLIC || rid == RID_PROTECTED || rid == RID_PRIVATE \
|
||||
|| rid == RID_TRY || rid == RID_THROW || rid == RID_CATCH)
|
||||
|
||||
@ -391,6 +394,7 @@ extern machine_mode c_default_pointer_mode;
|
||||
#define D_CXX_OBJC 0x100 /* In Objective C, and C++, but not C. */
|
||||
#define D_CXXWARN 0x200 /* In C warn with -Wcxx-compat. */
|
||||
#define D_CXX_CONCEPTS 0x400 /* In C++, only with concepts. */
|
||||
#define D_TRANSMEM 0X800 /* C++ transactional memory TS. */
|
||||
|
||||
#define D_CXX_CONCEPTS_FLAGS D_CXXONLY | D_CXX_CONCEPTS
|
||||
|
||||
|
@ -877,6 +877,10 @@ c_cpp_builtins (cpp_reader *pfile)
|
||||
/* Use a value smaller than the 201507 specified in
|
||||
the TS, since we don't yet support extended auto. */
|
||||
cpp_define (pfile, "__cpp_concepts=201500");
|
||||
if (flag_tm)
|
||||
/* Use a value smaller than the 201505 specified in
|
||||
the TS, since we don't yet support atomic_cancel. */
|
||||
cpp_define (pfile, "__cpp_transactional_memory=210500");
|
||||
if (flag_sized_deallocation)
|
||||
cpp_define (pfile, "__cpp_sized_deallocation=201309");
|
||||
}
|
||||
|
@ -802,6 +802,10 @@ pp_c_attributes_display (c_pretty_printer *pp, tree a)
|
||||
as = lookup_attribute_spec (TREE_PURPOSE (a));
|
||||
if (!as || as->affects_type_identity == false)
|
||||
continue;
|
||||
if (c_dialect_cxx ()
|
||||
&& !strcmp ("transaction_safe", as->name))
|
||||
/* In C++ transaction_safe is printed at the end of the declarator. */
|
||||
continue;
|
||||
if (is_first)
|
||||
{
|
||||
pp_c_ws_string (pp, "__attribute__");
|
||||
|
@ -1,3 +1,9 @@
|
||||
2015-10-04 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* c-parser.c (c_lex_one_token): Handle @synchronized.
|
||||
* c-decl.c (match_builtin_function_types): A declaration of a built-in
|
||||
can change whether the function is transaction_safe.
|
||||
|
||||
2015-10-02 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c/67730
|
||||
|
@ -1659,7 +1659,19 @@ match_builtin_function_types (tree newtype, tree oldtype)
|
||||
}
|
||||
|
||||
trytype = build_function_type (newrettype, tryargs);
|
||||
return build_type_attribute_variant (trytype, TYPE_ATTRIBUTES (oldtype));
|
||||
|
||||
/* Allow declaration to change transaction_safe attribute. */
|
||||
tree oldattrs = TYPE_ATTRIBUTES (oldtype);
|
||||
tree oldtsafe = lookup_attribute ("transaction_safe", oldattrs);
|
||||
tree newattrs = TYPE_ATTRIBUTES (newtype);
|
||||
tree newtsafe = lookup_attribute ("transaction_safe", newattrs);
|
||||
if (oldtsafe && !newtsafe)
|
||||
oldattrs = remove_attribute ("transaction_safe", oldattrs);
|
||||
else if (newtsafe && !oldtsafe)
|
||||
oldattrs = tree_cons (get_identifier ("transaction_safe"),
|
||||
NULL_TREE, oldattrs);
|
||||
|
||||
return build_type_attribute_variant (trytype, oldattrs);
|
||||
}
|
||||
|
||||
/* Subroutine of diagnose_mismatched_decls. Check for function type
|
||||
|
@ -390,6 +390,7 @@ c_lex_one_token (c_parser *parser, c_token *token)
|
||||
case RID_THROW: token->keyword = RID_AT_THROW; break;
|
||||
case RID_TRY: token->keyword = RID_AT_TRY; break;
|
||||
case RID_CATCH: token->keyword = RID_AT_CATCH; break;
|
||||
case RID_SYNCHRONIZED: token->keyword = RID_AT_SYNCHRONIZED; break;
|
||||
default: token->keyword = C_RID_CODE (token->value);
|
||||
}
|
||||
break;
|
||||
|
@ -1,3 +1,47 @@
|
||||
2015-10-04 Jason Merrill <jason@redhat.com>
|
||||
|
||||
Implement N4514, C++ Extensions for Transactional Memory.
|
||||
* cp-tree.h (struct cp_declarator): Add tx_qualifier field.
|
||||
(BCS_NORMAL, BCS_TRANSACTION): New enumerators.
|
||||
* lex.c (init_reswords): Limit TM kewords to -fgnu-tm.
|
||||
* parser.c (cp_lexer_get_preprocessor_token): Fix @synchronized.
|
||||
(make_call_declarator): Take tx_qualifier.
|
||||
(cp_parser_tx_qualifier_opt): New.
|
||||
(cp_parser_lambda_declarator_opt): Use it.
|
||||
(cp_parser_direct_declarator): Likewise.
|
||||
(cp_parser_statement): Handle atomic_noexcept, atomic_cancel.
|
||||
(cp_parser_compound_statement): Change in_try parameter to bcs_flags.
|
||||
(cp_parser_std_attribute): Map optimize_for_synchronized to
|
||||
transaction_callable.
|
||||
(cp_parser_transaction): Take the token. Handle atomic_noexcept.
|
||||
* lambda.c (maybe_add_lambda_conv_op): Handle transaction-safety.
|
||||
* call.c (enum conversion_kind): Add ck_tsafe.
|
||||
(standard_conversion): Handle transaction-safety conversion.
|
||||
(convert_like_real, resolve_address_of_overloaded_function): Likewise.
|
||||
(check_methods): Diagnose transaction_safe_dynamic on non-virtual
|
||||
function.
|
||||
(look_for_tm_attr_overrides): Don't inherit transaction_safe_dynamic.
|
||||
* cvt.c (tx_safe_fn_type_p, tx_unsafe_fn_variant)
|
||||
(can_convert_tx_safety): New.
|
||||
* typeck.c (composite_pointer_type): Handle transaction-safety.
|
||||
* name-lookup.h (enum scope_kind): Add sk_transaction.
|
||||
* name-lookup.c (begin_scope): Handle it.
|
||||
* semantics.c (begin_compound_stmt): Pass it.
|
||||
* decl.c (check_previous_goto_1): Check it.
|
||||
(struct named_label_entry): Add in_transaction_scope.
|
||||
(poplevel_named_label_1): Set it.
|
||||
(check_goto): Check it.
|
||||
(duplicate_decls): A specialization can be transaction_safe
|
||||
independently of its template.
|
||||
(grokdeclarator): Handle tx-qualifier.
|
||||
* rtti.c (ptr_initializer): Handle transaction-safe.
|
||||
* search.c (check_final_overrider): Check transaction_safe_dynamic.
|
||||
Don't check transaction_safe.
|
||||
* mangle.c (write_function_type): Mangle transaction_safe here.
|
||||
(write_CV_qualifiers_for_type): Not here.
|
||||
(write_type): Preserve transaction_safe when stripping attributes.
|
||||
* error.c (dump_type_suffix): Print transaction_safe.
|
||||
|
||||
2015-10-02 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c/64249
|
||||
|
@ -51,6 +51,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
enum conversion_kind {
|
||||
ck_identity,
|
||||
ck_lvalue,
|
||||
ck_tsafe,
|
||||
ck_qual,
|
||||
ck_std,
|
||||
ck_ptr,
|
||||
@ -1265,6 +1266,17 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
|
||||
conv = build_conv (ck_ptr, from, conv);
|
||||
conv->base_p = true;
|
||||
}
|
||||
else if (tx_safe_fn_type_p (TREE_TYPE (from)))
|
||||
{
|
||||
/* A prvalue of type "pointer to transaction_safe function" can be
|
||||
converted to a prvalue of type "pointer to function". */
|
||||
tree unsafe = tx_unsafe_fn_variant (TREE_TYPE (from));
|
||||
if (same_type_p (unsafe, TREE_TYPE (to)))
|
||||
{
|
||||
from = build_pointer_type (unsafe);
|
||||
conv = build_conv (ck_tsafe, from, conv);
|
||||
}
|
||||
}
|
||||
|
||||
if (tcode == POINTER_TYPE)
|
||||
{
|
||||
@ -6638,6 +6650,11 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
|
||||
case ck_lvalue:
|
||||
return decay_conversion (expr, complain);
|
||||
|
||||
case ck_tsafe:
|
||||
/* ??? Should the address of a transaction-safe pointer point to the TM
|
||||
clone, and this conversion look up the primary function? */
|
||||
return build_nop (totype, expr);
|
||||
|
||||
case ck_qual:
|
||||
/* Warn about deprecated conversion if appropriate. */
|
||||
string_conv_p (totype, expr, 1);
|
||||
|
@ -4570,6 +4570,11 @@ check_methods (tree t)
|
||||
grok_special_member_properties. */
|
||||
if (DECL_DESTRUCTOR_P (x) && user_provided_p (x))
|
||||
TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 1;
|
||||
if (!DECL_VIRTUAL_P (x)
|
||||
&& lookup_attribute ("transaction_safe_dynamic", DECL_ATTRIBUTES (x)))
|
||||
error_at (DECL_SOURCE_LOCATION (x),
|
||||
"%<transaction_safe_dynamic%> may only be specified for "
|
||||
"a virtual function");
|
||||
}
|
||||
}
|
||||
|
||||
@ -4932,8 +4937,14 @@ look_for_tm_attr_overrides (tree type, tree fndecl)
|
||||
|
||||
o = look_for_overrides_here (basetype, fndecl);
|
||||
if (o)
|
||||
found |= tm_attr_to_mask (find_tm_attribute
|
||||
(TYPE_ATTRIBUTES (TREE_TYPE (o))));
|
||||
{
|
||||
if (lookup_attribute ("transaction_safe_dynamic",
|
||||
DECL_ATTRIBUTES (o)))
|
||||
/* transaction_safe_dynamic is not inherited. */;
|
||||
else
|
||||
found |= tm_attr_to_mask (find_tm_attribute
|
||||
(TYPE_ATTRIBUTES (TREE_TYPE (o))));
|
||||
}
|
||||
else
|
||||
found |= look_for_tm_attr_overrides (basetype, fndecl);
|
||||
}
|
||||
@ -7608,7 +7619,9 @@ resolve_address_of_overloaded_function (tree target_type,
|
||||
continue;
|
||||
|
||||
/* See if there's a match. */
|
||||
if (same_type_p (target_fn_type, static_fn_type (fn)))
|
||||
tree fntype = static_fn_type (fn);
|
||||
if (same_type_p (target_fn_type, fntype)
|
||||
|| can_convert_tx_safety (target_fn_type, fntype))
|
||||
matches = tree_cons (fn, NULL_TREE, matches);
|
||||
}
|
||||
}
|
||||
@ -7686,7 +7699,9 @@ resolve_address_of_overloaded_function (tree target_type,
|
||||
}
|
||||
|
||||
/* See if there's a match. */
|
||||
if (same_type_p (target_fn_type, static_fn_type (instantiation)))
|
||||
tree fntype = static_fn_type (instantiation);
|
||||
if (same_type_p (target_fn_type, fntype)
|
||||
|| can_convert_tx_safety (target_fn_type, fntype))
|
||||
matches = tree_cons (instantiation, fn, matches);
|
||||
}
|
||||
|
||||
|
@ -5317,6 +5317,8 @@ struct cp_declarator {
|
||||
cp_virt_specifiers virt_specifiers;
|
||||
/* The ref-qualifier for the function. */
|
||||
cp_ref_qualifier ref_qualifier;
|
||||
/* The transaction-safety qualifier for the function. */
|
||||
tree tx_qualifier;
|
||||
/* The exception-specification for the function. */
|
||||
tree exception_specification;
|
||||
/* The late-specified return type, if any. */
|
||||
@ -5604,6 +5606,9 @@ extern tree convert_force (tree, tree, int,
|
||||
extern tree build_expr_type_conversion (int, tree, bool);
|
||||
extern tree type_promotes_to (tree);
|
||||
extern tree perform_qualification_conversions (tree, tree);
|
||||
extern bool tx_safe_fn_type_p (tree);
|
||||
extern tree tx_unsafe_fn_variant (tree);
|
||||
extern bool can_convert_tx_safety (tree, tree);
|
||||
|
||||
/* in name-lookup.c */
|
||||
extern tree pushdecl (tree);
|
||||
@ -6218,9 +6223,11 @@ extern void finish_cleanup (tree, tree);
|
||||
extern bool is_this_parameter (tree);
|
||||
|
||||
enum {
|
||||
BCS_NORMAL = 0,
|
||||
BCS_NO_SCOPE = 1,
|
||||
BCS_TRY_BLOCK = 2,
|
||||
BCS_FN_BODY = 4
|
||||
BCS_FN_BODY = 4,
|
||||
BCS_TRANSACTION = 8
|
||||
};
|
||||
extern tree begin_compound_stmt (unsigned int);
|
||||
|
||||
|
33
gcc/cp/cvt.c
33
gcc/cp/cvt.c
@ -1790,3 +1790,36 @@ perform_qualification_conversions (tree type, tree expr)
|
||||
else
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
/* True iff T is a transaction-safe function type. */
|
||||
|
||||
bool
|
||||
tx_safe_fn_type_p (tree t)
|
||||
{
|
||||
if (TREE_CODE (t) != FUNCTION_TYPE
|
||||
&& TREE_CODE (t) != METHOD_TYPE)
|
||||
return false;
|
||||
return !!lookup_attribute ("transaction_safe", TYPE_ATTRIBUTES (t));
|
||||
}
|
||||
|
||||
/* Return the transaction-unsafe variant of transaction-safe function type
|
||||
T. */
|
||||
|
||||
tree
|
||||
tx_unsafe_fn_variant (tree t)
|
||||
{
|
||||
gcc_assert (tx_safe_fn_type_p (t));
|
||||
tree attrs = remove_attribute ("transaction_safe",
|
||||
TYPE_ATTRIBUTES (t));
|
||||
return cp_build_type_attribute_variant (t, attrs);
|
||||
}
|
||||
|
||||
/* Return true iff FROM can convert to TO by a transaction-safety
|
||||
conversion. */
|
||||
|
||||
bool
|
||||
can_convert_tx_safety (tree to, tree from)
|
||||
{
|
||||
return (flag_tm && tx_safe_fn_type_p (from)
|
||||
&& same_type_p (to, tx_unsafe_fn_variant (from)));
|
||||
}
|
||||
|
@ -230,6 +230,7 @@ struct GTY((for_user)) named_label_entry {
|
||||
bool in_try_scope;
|
||||
bool in_catch_scope;
|
||||
bool in_omp_scope;
|
||||
bool in_transaction_scope;
|
||||
};
|
||||
|
||||
#define named_labels cp_function_chain->x_named_labels
|
||||
@ -498,6 +499,9 @@ poplevel_named_label_1 (named_label_entry **slot, cp_binding_level *bl)
|
||||
case sk_omp:
|
||||
ent->in_omp_scope = true;
|
||||
break;
|
||||
case sk_transaction:
|
||||
ent->in_transaction_scope = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -2049,6 +2053,17 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
|
||||
}
|
||||
}
|
||||
|
||||
/* An explicit specialization of a function template or of a member
|
||||
function of a class template can be declared transaction_safe
|
||||
independently of whether the corresponding template entity is declared
|
||||
transaction_safe. */
|
||||
if (flag_tm && TREE_CODE (newdecl) == FUNCTION_DECL
|
||||
&& DECL_TEMPLATE_INSTANTIATION (olddecl)
|
||||
&& DECL_TEMPLATE_SPECIALIZATION (newdecl)
|
||||
&& tx_safe_fn_type_p (newtype)
|
||||
&& !tx_safe_fn_type_p (TREE_TYPE (newdecl)))
|
||||
newtype = tx_unsafe_fn_variant (newtype);
|
||||
|
||||
TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype;
|
||||
|
||||
if (TREE_CODE (newdecl) == FUNCTION_DECL)
|
||||
@ -2975,7 +2990,7 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names,
|
||||
{
|
||||
cp_binding_level *b;
|
||||
bool identified = false, complained = false;
|
||||
bool saw_eh = false, saw_omp = false;
|
||||
bool saw_eh = false, saw_omp = false, saw_tm = false;
|
||||
|
||||
if (exited_omp)
|
||||
{
|
||||
@ -3043,6 +3058,18 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names,
|
||||
inform (input_location, " enters OpenMP structured block");
|
||||
saw_omp = true;
|
||||
}
|
||||
if (b->kind == sk_transaction && !saw_tm)
|
||||
{
|
||||
if (!identified)
|
||||
{
|
||||
complained = identify_goto (decl, locus);
|
||||
identified = true;
|
||||
}
|
||||
if (complained)
|
||||
inform (input_location,
|
||||
" enters synchronized or atomic statement");
|
||||
saw_tm = true;
|
||||
}
|
||||
}
|
||||
|
||||
return !identified;
|
||||
@ -3109,7 +3136,7 @@ check_goto (tree decl)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ent->in_try_scope || ent->in_catch_scope
|
||||
if (ent->in_try_scope || ent->in_catch_scope || ent->in_transaction_scope
|
||||
|| ent->in_omp_scope || !vec_safe_is_empty (ent->bad_decls))
|
||||
{
|
||||
complained = permerror (DECL_SOURCE_LOCATION (decl),
|
||||
@ -3148,6 +3175,8 @@ check_goto (tree decl)
|
||||
inform (input_location, " enters try block");
|
||||
else if (ent->in_catch_scope && !saw_catch)
|
||||
inform (input_location, " enters catch block");
|
||||
else if (ent->in_transaction_scope)
|
||||
inform (input_location, " enters synchronized or atomic statement");
|
||||
}
|
||||
|
||||
if (ent->in_omp_scope)
|
||||
@ -9976,6 +10005,8 @@ grokdeclarator (const cp_declarator *declarator,
|
||||
virt_specifiers = declarator->u.function.virt_specifiers;
|
||||
/* And ref-qualifier, too */
|
||||
rqual = declarator->u.function.ref_qualifier;
|
||||
/* And tx-qualifier. */
|
||||
tree tx_qual = declarator->u.function.tx_qualifier;
|
||||
/* Pick up the exception specifications. */
|
||||
raises = declarator->u.function.exception_specification;
|
||||
/* If the exception-specification is ill-formed, let's pretend
|
||||
@ -10153,13 +10184,24 @@ grokdeclarator (const cp_declarator *declarator,
|
||||
}
|
||||
|
||||
type = build_function_type (type, arg_types);
|
||||
if (declarator->std_attributes)
|
||||
|
||||
tree attrs = declarator->std_attributes;
|
||||
if (tx_qual)
|
||||
{
|
||||
tree att = build_tree_list (tx_qual, NULL_TREE);
|
||||
/* transaction_safe applies to the type, but
|
||||
transaction_safe_dynamic applies to the function. */
|
||||
if (is_attribute_p ("transaction_safe", tx_qual))
|
||||
attrs = chainon (attrs, att);
|
||||
else
|
||||
returned_attrs = chainon (returned_attrs, att);
|
||||
}
|
||||
if (attrs)
|
||||
/* [dcl.fct]/2:
|
||||
|
||||
The optional attribute-specifier-seq appertains to
|
||||
the function type. */
|
||||
decl_attributes (&type, declarator->std_attributes,
|
||||
0);
|
||||
decl_attributes (&type, attrs, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -868,6 +868,8 @@ dump_type_suffix (cxx_pretty_printer *pp, tree t, int flags)
|
||||
TREE_CODE (t) == FUNCTION_TYPE
|
||||
&& (flags & TFF_POINTER));
|
||||
dump_ref_qualifier (pp, t, flags);
|
||||
if (tx_safe_fn_type_p (t))
|
||||
pp_cxx_ws_string (pp, "transaction_safe");
|
||||
dump_exception_spec (pp, TYPE_RAISES_EXCEPTIONS (t), flags);
|
||||
dump_type_suffix (pp, TREE_TYPE (t), flags);
|
||||
break;
|
||||
@ -1570,6 +1572,12 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
|
||||
dump_ref_qualifier (pp, fntype, flags);
|
||||
}
|
||||
|
||||
if (tx_safe_fn_type_p (fntype))
|
||||
{
|
||||
pp->padding = pp_before;
|
||||
pp_cxx_ws_string (pp, "transaction_safe");
|
||||
}
|
||||
|
||||
if (flags & TFF_EXCEPTION_SPECIFICATION)
|
||||
{
|
||||
pp->padding = pp_before;
|
||||
|
@ -895,7 +895,8 @@ maybe_add_lambda_conv_op (tree type)
|
||||
|
||||
vec<tree, va_gc> *direct_argvec = 0;
|
||||
tree decltype_call = 0, call = 0;
|
||||
tree fn_result = TREE_TYPE (TREE_TYPE (callop));
|
||||
tree optype = TREE_TYPE (callop);
|
||||
tree fn_result = TREE_TYPE (optype);
|
||||
|
||||
if (generic_lambda_p)
|
||||
{
|
||||
@ -993,6 +994,8 @@ maybe_add_lambda_conv_op (tree type)
|
||||
CALL_FROM_THUNK_P (call) = 1;
|
||||
|
||||
tree stattype = build_function_type (fn_result, FUNCTION_ARG_CHAIN (callop));
|
||||
stattype = (cp_build_type_attribute_variant
|
||||
(stattype, TYPE_ATTRIBUTES (optype)));
|
||||
|
||||
/* First build up the conversion op. */
|
||||
|
||||
|
@ -176,6 +176,8 @@ init_reswords (void)
|
||||
mask |= D_CXX11;
|
||||
if (!flag_concepts)
|
||||
mask |= D_CXX_CONCEPTS;
|
||||
if (!flag_tm)
|
||||
mask |= D_TRANSMEM;
|
||||
if (flag_no_asm)
|
||||
mask |= D_ASM | D_EXT;
|
||||
if (flag_no_gnu_keywords)
|
||||
|
@ -1911,7 +1911,13 @@ write_type (tree type)
|
||||
{
|
||||
tree t = TYPE_MAIN_VARIANT (type);
|
||||
if (TYPE_ATTRIBUTES (t) && !OVERLOAD_TYPE_P (t))
|
||||
t = cp_build_type_attribute_variant (t, NULL_TREE);
|
||||
{
|
||||
tree attrs = NULL_TREE;
|
||||
if (tx_safe_fn_type_p (type))
|
||||
attrs = tree_cons (get_identifier ("transaction_safe"),
|
||||
NULL_TREE, attrs);
|
||||
t = cp_build_type_attribute_variant (t, attrs);
|
||||
}
|
||||
gcc_assert (t != type);
|
||||
if (TREE_CODE (t) == FUNCTION_TYPE
|
||||
|| TREE_CODE (t) == METHOD_TYPE)
|
||||
@ -2209,6 +2215,7 @@ write_CV_qualifiers_for_type (const tree type)
|
||||
tree name = get_attribute_name (a);
|
||||
const attribute_spec *as = lookup_attribute_spec (name);
|
||||
if (as && as->affects_type_identity
|
||||
&& !is_attribute_p ("transaction_safe", name)
|
||||
&& !is_attribute_p ("abi_tag", name))
|
||||
vec.safe_push (a);
|
||||
}
|
||||
@ -2470,6 +2477,9 @@ write_function_type (const tree type)
|
||||
write_CV_qualifiers_for_type (this_type);
|
||||
}
|
||||
|
||||
if (tx_safe_fn_type_p (type))
|
||||
write_string ("Dx");
|
||||
|
||||
write_char ('F');
|
||||
/* We don't track whether or not a type is `extern "C"'. Note that
|
||||
you can have an `extern "C"' function that does not have
|
||||
|
@ -1591,6 +1591,7 @@ begin_scope (scope_kind kind, tree entity)
|
||||
case sk_class:
|
||||
case sk_scoped_enum:
|
||||
case sk_function_parms:
|
||||
case sk_transaction:
|
||||
case sk_omp:
|
||||
scope->keep = keep_next_level_flag;
|
||||
break;
|
||||
|
@ -121,6 +121,7 @@ enum scope_kind {
|
||||
specialization. Since, by definition, an
|
||||
explicit specialization is introduced by
|
||||
"template <>", this scope is always empty. */
|
||||
sk_transaction, /* A synchronized or atomic statement. */
|
||||
sk_omp /* An OpenMP structured block. */
|
||||
};
|
||||
|
||||
|
123
gcc/cp/parser.c
123
gcc/cp/parser.c
@ -829,6 +829,7 @@ cp_lexer_get_preprocessor_token (cp_lexer *lexer, cp_token *token)
|
||||
case RID_THROW: token->keyword = RID_AT_THROW; break;
|
||||
case RID_TRY: token->keyword = RID_AT_TRY; break;
|
||||
case RID_CATCH: token->keyword = RID_AT_CATCH; break;
|
||||
case RID_SYNCHRONIZED: token->keyword = RID_AT_SYNCHRONIZED; break;
|
||||
default: token->keyword = C_RID_CODE (token->u.value);
|
||||
}
|
||||
}
|
||||
@ -1343,7 +1344,7 @@ clear_decl_specs (cp_decl_specifier_seq *decl_specs)
|
||||
VAR_DECLs or FUNCTION_DECLs) should do that directly. */
|
||||
|
||||
static cp_declarator *make_call_declarator
|
||||
(cp_declarator *, tree, cp_cv_quals, cp_virt_specifiers, cp_ref_qualifier, tree, tree, tree);
|
||||
(cp_declarator *, tree, cp_cv_quals, cp_virt_specifiers, cp_ref_qualifier, tree, tree, tree, tree);
|
||||
static cp_declarator *make_array_declarator
|
||||
(cp_declarator *, tree);
|
||||
static cp_declarator *make_pointer_declarator
|
||||
@ -1521,6 +1522,7 @@ make_call_declarator (cp_declarator *target,
|
||||
cp_cv_quals cv_qualifiers,
|
||||
cp_virt_specifiers virt_specifiers,
|
||||
cp_ref_qualifier ref_qualifier,
|
||||
tree tx_qualifier,
|
||||
tree exception_specification,
|
||||
tree late_return_type,
|
||||
tree requires_clause)
|
||||
@ -1533,6 +1535,7 @@ make_call_declarator (cp_declarator *target,
|
||||
declarator->u.function.qualifiers = cv_qualifiers;
|
||||
declarator->u.function.virt_specifiers = virt_specifiers;
|
||||
declarator->u.function.ref_qualifier = ref_qualifier;
|
||||
declarator->u.function.tx_qualifier = tx_qualifier;
|
||||
declarator->u.function.exception_specification = exception_specification;
|
||||
declarator->u.function.late_return_type = late_return_type;
|
||||
declarator->u.function.requires_clause = requires_clause;
|
||||
@ -2029,7 +2032,7 @@ static void cp_parser_label_for_labeled_statement
|
||||
static tree cp_parser_expression_statement
|
||||
(cp_parser *, tree);
|
||||
static tree cp_parser_compound_statement
|
||||
(cp_parser *, tree, bool, bool);
|
||||
(cp_parser *, tree, int, bool);
|
||||
static void cp_parser_statement_seq_opt
|
||||
(cp_parser *, tree);
|
||||
static tree cp_parser_selection_statement
|
||||
@ -2139,6 +2142,8 @@ static cp_virt_specifiers cp_parser_virt_specifier_seq_opt
|
||||
(cp_parser *);
|
||||
static cp_ref_qualifier cp_parser_ref_qualifier_opt
|
||||
(cp_parser *);
|
||||
static tree cp_parser_tx_qualifier_opt
|
||||
(cp_parser *);
|
||||
static tree cp_parser_late_return_type_opt
|
||||
(cp_parser *, cp_declarator *, tree &, cp_cv_quals);
|
||||
static tree cp_parser_declarator_id
|
||||
@ -2346,7 +2351,7 @@ static tree cp_parser_nested_requirement
|
||||
/* Transactional Memory Extensions */
|
||||
|
||||
static tree cp_parser_transaction
|
||||
(cp_parser *, enum rid);
|
||||
(cp_parser *, cp_token *);
|
||||
static tree cp_parser_transaction_expression
|
||||
(cp_parser *, enum rid);
|
||||
static bool cp_parser_function_transaction
|
||||
@ -4262,7 +4267,7 @@ cp_parser_statement_expr (cp_parser *parser)
|
||||
/* Start the statement-expression. */
|
||||
tree expr = begin_stmt_expr ();
|
||||
/* Parse the compound-statement. */
|
||||
cp_parser_compound_statement (parser, expr, false, false);
|
||||
cp_parser_compound_statement (parser, expr, BCS_NORMAL, false);
|
||||
/* Finish up. */
|
||||
expr = finish_stmt_expr (expr, false);
|
||||
/* Consume the ')'. */
|
||||
@ -9630,6 +9635,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
|
||||
tree attributes = NULL_TREE;
|
||||
tree exception_spec = NULL_TREE;
|
||||
tree template_param_list = NULL_TREE;
|
||||
tree tx_qual = NULL_TREE;
|
||||
|
||||
/* The template-parameter-list is optional, but must begin with
|
||||
an opening angle if present. */
|
||||
@ -9680,6 +9686,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
|
||||
LAMBDA_EXPR_MUTABLE_P (lambda_expr) = 1;
|
||||
}
|
||||
|
||||
tx_qual = cp_parser_tx_qualifier_opt (parser);
|
||||
|
||||
/* Parse optional exception specification. */
|
||||
exception_spec = cp_parser_exception_specification_opt (parser);
|
||||
|
||||
@ -9727,6 +9735,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
|
||||
declarator = make_call_declarator (declarator, param_list, quals,
|
||||
VIRT_SPEC_UNSPECIFIED,
|
||||
REF_QUAL_NONE,
|
||||
tx_qual,
|
||||
exception_spec,
|
||||
/*late_return_type=*/NULL_TREE,
|
||||
/*requires_clause*/NULL_TREE);
|
||||
@ -10043,7 +10052,10 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
|
||||
|
||||
case RID_TRANSACTION_ATOMIC:
|
||||
case RID_TRANSACTION_RELAXED:
|
||||
statement = cp_parser_transaction (parser, keyword);
|
||||
case RID_SYNCHRONIZED:
|
||||
case RID_ATOMIC_NOEXCEPT:
|
||||
case RID_ATOMIC_CANCEL:
|
||||
statement = cp_parser_transaction (parser, token);
|
||||
break;
|
||||
case RID_TRANSACTION_CANCEL:
|
||||
statement = cp_parser_transaction_cancel (parser);
|
||||
@ -10072,7 +10084,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
|
||||
}
|
||||
/* Anything that starts with a `{' must be a compound-statement. */
|
||||
else if (token->type == CPP_OPEN_BRACE)
|
||||
statement = cp_parser_compound_statement (parser, NULL, false, false);
|
||||
statement = cp_parser_compound_statement (parser, NULL, BCS_NORMAL, false);
|
||||
/* CPP_PRAGMA is a #pragma inside a function body, which constitutes
|
||||
a statement all its own. */
|
||||
else if (token->type == CPP_PRAGMA)
|
||||
@ -10327,7 +10339,7 @@ cp_parser_expression_statement (cp_parser* parser, tree in_statement_expr)
|
||||
|
||||
static tree
|
||||
cp_parser_compound_statement (cp_parser *parser, tree in_statement_expr,
|
||||
bool in_try, bool function_body)
|
||||
int bcs_flags, bool function_body)
|
||||
{
|
||||
tree compound_stmt;
|
||||
|
||||
@ -10339,7 +10351,7 @@ cp_parser_compound_statement (cp_parser *parser, tree in_statement_expr,
|
||||
pedwarn (input_location, OPT_Wpedantic,
|
||||
"compound-statement in constexpr function");
|
||||
/* Begin the compound-statement. */
|
||||
compound_stmt = begin_compound_stmt (in_try ? BCS_TRY_BLOCK : 0);
|
||||
compound_stmt = begin_compound_stmt (bcs_flags);
|
||||
/* If the next keyword is `__label__' we have a label declaration. */
|
||||
while (cp_lexer_next_token_is_keyword (parser->lexer, RID_LABEL))
|
||||
cp_parser_label_declaration (parser);
|
||||
@ -11500,7 +11512,7 @@ cp_parser_implicitly_scoped_statement (cp_parser* parser, bool *if_p,
|
||||
}
|
||||
/* if a compound is opened, we simply parse the statement directly. */
|
||||
else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
|
||||
statement = cp_parser_compound_statement (parser, NULL, false, false);
|
||||
statement = cp_parser_compound_statement (parser, NULL, BCS_NORMAL, false);
|
||||
/* If the token is not a `{', then we must take special action. */
|
||||
else
|
||||
{
|
||||
@ -18451,6 +18463,8 @@ cp_parser_direct_declarator (cp_parser* parser,
|
||||
cv_quals = cp_parser_cv_qualifier_seq_opt (parser);
|
||||
/* Parse the ref-qualifier. */
|
||||
ref_qual = cp_parser_ref_qualifier_opt (parser);
|
||||
/* Parse the tx-qualifier. */
|
||||
tree tx_qual = cp_parser_tx_qualifier_opt (parser);
|
||||
/* And the exception-specification. */
|
||||
exception_specification
|
||||
= cp_parser_exception_specification_opt (parser);
|
||||
@ -18489,6 +18503,7 @@ cp_parser_direct_declarator (cp_parser* parser,
|
||||
cv_quals,
|
||||
virt_specifiers,
|
||||
ref_qual,
|
||||
tx_qual,
|
||||
exception_specification,
|
||||
late_return,
|
||||
requires_clause);
|
||||
@ -19101,6 +19116,41 @@ cp_parser_ref_qualifier_opt (cp_parser* parser)
|
||||
return ref_qual;
|
||||
}
|
||||
|
||||
/* Parse an optional tx-qualifier.
|
||||
|
||||
tx-qualifier:
|
||||
transaction_safe
|
||||
transaction_safe_dynamic */
|
||||
|
||||
static tree
|
||||
cp_parser_tx_qualifier_opt (cp_parser *parser)
|
||||
{
|
||||
cp_token *token = cp_lexer_peek_token (parser->lexer);
|
||||
if (token->type == CPP_NAME)
|
||||
{
|
||||
tree name = token->u.value;
|
||||
const char *p = IDENTIFIER_POINTER (name);
|
||||
const int len = strlen ("transaction_safe");
|
||||
if (!strncmp (p, "transaction_safe", len))
|
||||
{
|
||||
p += len;
|
||||
if (*p == '\0'
|
||||
|| !strcmp (p, "_dynamic"))
|
||||
{
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
if (!flag_tm)
|
||||
{
|
||||
error ("%E requires %<-fgnu-tm%>", name);
|
||||
return NULL_TREE;
|
||||
}
|
||||
else
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Parse an (optional) virt-specifier-seq.
|
||||
|
||||
virt-specifier-seq:
|
||||
@ -20109,7 +20159,9 @@ cp_parser_default_argument (cp_parser *parser, bool template_parm_p)
|
||||
static void
|
||||
cp_parser_function_body (cp_parser *parser, bool in_function_try_block)
|
||||
{
|
||||
cp_parser_compound_statement (parser, NULL, in_function_try_block, true);
|
||||
cp_parser_compound_statement (parser, NULL, (in_function_try_block
|
||||
? BCS_TRY_BLOCK : BCS_NORMAL),
|
||||
true);
|
||||
}
|
||||
|
||||
/* Parse a ctor-initializer-opt followed by a function-body. Return
|
||||
@ -22598,7 +22650,7 @@ cp_parser_try_block (cp_parser* parser)
|
||||
error ("%<try%> in %<constexpr%> function");
|
||||
|
||||
try_block = begin_try_block ();
|
||||
cp_parser_compound_statement (parser, NULL, true, false);
|
||||
cp_parser_compound_statement (parser, NULL, BCS_TRY_BLOCK, false);
|
||||
finish_try_block (try_block);
|
||||
cp_parser_handler_seq (parser);
|
||||
finish_handler_sequence (try_block);
|
||||
@ -22675,7 +22727,7 @@ cp_parser_handler (cp_parser* parser)
|
||||
declaration = cp_parser_exception_declaration (parser);
|
||||
finish_handler_parms (declaration, handler);
|
||||
cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
|
||||
cp_parser_compound_statement (parser, NULL, false, false);
|
||||
cp_parser_compound_statement (parser, NULL, BCS_NORMAL, false);
|
||||
finish_handler (handler);
|
||||
}
|
||||
|
||||
@ -23354,6 +23406,14 @@ cp_parser_std_attribute (cp_parser *parser)
|
||||
" use %<gnu::deprecated%>");
|
||||
TREE_PURPOSE (TREE_PURPOSE (attribute)) = get_identifier ("gnu");
|
||||
}
|
||||
/* Transactional Memory TS optimize_for_synchronized attribute is
|
||||
equivalent to GNU transaction_callable. */
|
||||
else if (is_attribute_p ("optimize_for_synchronized", attr_id))
|
||||
TREE_PURPOSE (attribute)
|
||||
= get_identifier ("transaction_callable");
|
||||
/* Transactional Memory attributes are GNU attributes. */
|
||||
else if (tm_attr_to_mask (attr_id))
|
||||
TREE_PURPOSE (attribute) = attr_id;
|
||||
}
|
||||
|
||||
/* Now parse the optional argument clause of the attribute. */
|
||||
@ -28391,7 +28451,7 @@ cp_parser_objc_try_catch_finally_statement (cp_parser *parser)
|
||||
/* NB: The @try block needs to be wrapped in its own STATEMENT_LIST
|
||||
node, lest it get absorbed into the surrounding block. */
|
||||
stmt = push_stmt_list ();
|
||||
cp_parser_compound_statement (parser, NULL, false, false);
|
||||
cp_parser_compound_statement (parser, NULL, BCS_NORMAL, false);
|
||||
objc_begin_try_stmt (location, pop_stmt_list (stmt));
|
||||
|
||||
while (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_CATCH))
|
||||
@ -28447,7 +28507,7 @@ cp_parser_objc_try_catch_finally_statement (cp_parser *parser)
|
||||
forget about the closing parenthesis and keep going. */
|
||||
}
|
||||
objc_begin_catch_clause (parameter_declaration);
|
||||
cp_parser_compound_statement (parser, NULL, false, false);
|
||||
cp_parser_compound_statement (parser, NULL, BCS_NORMAL, false);
|
||||
objc_finish_catch_clause ();
|
||||
}
|
||||
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_FINALLY))
|
||||
@ -28457,7 +28517,7 @@ cp_parser_objc_try_catch_finally_statement (cp_parser *parser)
|
||||
/* NB: The @finally block needs to be wrapped in its own STATEMENT_LIST
|
||||
node, lest it get absorbed into the surrounding block. */
|
||||
stmt = push_stmt_list ();
|
||||
cp_parser_compound_statement (parser, NULL, false, false);
|
||||
cp_parser_compound_statement (parser, NULL, BCS_NORMAL, false);
|
||||
objc_build_finally_clause (location, pop_stmt_list (stmt));
|
||||
}
|
||||
|
||||
@ -28488,7 +28548,7 @@ cp_parser_objc_synchronized_statement (cp_parser *parser)
|
||||
/* NB: The @synchronized block needs to be wrapped in its own STATEMENT_LIST
|
||||
node, lest it get absorbed into the surrounding block. */
|
||||
stmt = push_stmt_list ();
|
||||
cp_parser_compound_statement (parser, NULL, false, false);
|
||||
cp_parser_compound_statement (parser, NULL, BCS_NORMAL, false);
|
||||
|
||||
return objc_build_synchronized (location, lock, pop_stmt_list (stmt));
|
||||
}
|
||||
@ -33964,8 +34024,8 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok)
|
||||
attribute
|
||||
[ [ identifier ] ]
|
||||
|
||||
??? Simplify this when C++0x bracket attributes are
|
||||
implemented properly. */
|
||||
We use this instead of cp_parser_attributes_opt for transactions to avoid
|
||||
the pedwarn in C++98 mode. */
|
||||
|
||||
static tree
|
||||
cp_parser_txn_attribute_opt (cp_parser *parser)
|
||||
@ -34012,21 +34072,17 @@ cp_parser_txn_attribute_opt (cp_parser *parser)
|
||||
*/
|
||||
|
||||
static tree
|
||||
cp_parser_transaction (cp_parser *parser, enum rid keyword)
|
||||
cp_parser_transaction (cp_parser *parser, cp_token *token)
|
||||
{
|
||||
unsigned char old_in = parser->in_transaction;
|
||||
unsigned char this_in = 1, new_in;
|
||||
cp_token *token;
|
||||
enum rid keyword = token->keyword;
|
||||
tree stmt, attrs, noex;
|
||||
|
||||
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);
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
|
||||
if (keyword == RID_TRANSACTION_RELAXED)
|
||||
if (keyword == RID_TRANSACTION_RELAXED
|
||||
|| keyword == RID_SYNCHRONIZED)
|
||||
this_in |= TM_STMT_ATTR_RELAXED;
|
||||
else
|
||||
{
|
||||
@ -34036,7 +34092,16 @@ cp_parser_transaction (cp_parser *parser, enum rid keyword)
|
||||
}
|
||||
|
||||
/* Parse a noexcept specification. */
|
||||
noex = cp_parser_noexcept_specification_opt (parser, true, NULL, true);
|
||||
if (keyword == RID_ATOMIC_NOEXCEPT)
|
||||
noex = boolean_true_node;
|
||||
else if (keyword == RID_ATOMIC_CANCEL)
|
||||
{
|
||||
/* cancel-and-throw is unimplemented. */
|
||||
sorry ("atomic_cancel");
|
||||
noex = NULL_TREE;
|
||||
}
|
||||
else
|
||||
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);
|
||||
@ -34044,7 +34109,7 @@ cp_parser_transaction (cp_parser *parser, enum rid keyword)
|
||||
stmt = begin_transaction_stmt (token->location, NULL, this_in);
|
||||
|
||||
parser->in_transaction = new_in;
|
||||
cp_parser_compound_statement (parser, NULL, false, false);
|
||||
cp_parser_compound_statement (parser, NULL, BCS_TRANSACTION, false);
|
||||
parser->in_transaction = old_in;
|
||||
|
||||
finish_transaction_stmt (stmt, NULL, this_in, noex);
|
||||
|
@ -983,6 +983,11 @@ ptr_initializer (tinfo_s *ti, tree target)
|
||||
|
||||
if (incomplete)
|
||||
flags |= 8;
|
||||
if (tx_safe_fn_type_p (to))
|
||||
{
|
||||
flags |= 0x20;
|
||||
to = tx_unsafe_fn_variant (to);
|
||||
}
|
||||
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init);
|
||||
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, flags));
|
||||
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
|
||||
|
@ -2014,8 +2014,11 @@ check_final_overrider (tree overrider, tree basefn)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for conflicting type attributes. */
|
||||
if (!comp_type_attributes (over_type, base_type))
|
||||
/* Check for conflicting type attributes. But leave transaction_safe for
|
||||
set_one_vmethod_tm_attributes. */
|
||||
if (!comp_type_attributes (over_type, base_type)
|
||||
&& !tx_safe_fn_type_p (base_type)
|
||||
&& !tx_safe_fn_type_p (over_type))
|
||||
{
|
||||
error ("conflicting type attributes specified for %q+#D", overrider);
|
||||
error (" overriding %q+#D", basefn);
|
||||
@ -2023,6 +2026,21 @@ check_final_overrider (tree overrider, tree basefn)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* A function declared transaction_safe_dynamic that overrides a function
|
||||
declared transaction_safe (but not transaction_safe_dynamic) is
|
||||
ill-formed. */
|
||||
if (tx_safe_fn_type_p (base_type)
|
||||
&& lookup_attribute ("transaction_safe_dynamic",
|
||||
DECL_ATTRIBUTES (overrider))
|
||||
&& !lookup_attribute ("transaction_safe_dynamic",
|
||||
DECL_ATTRIBUTES (basefn)))
|
||||
{
|
||||
error_at (DECL_SOURCE_LOCATION (overrider),
|
||||
"%qD declared %<transaction_safe_dynamic%>", overrider);
|
||||
inform (DECL_SOURCE_LOCATION (basefn),
|
||||
"overriding %qD declared %<transaction_safe%>", basefn);
|
||||
}
|
||||
|
||||
if (DECL_DELETED_FN (basefn) != DECL_DELETED_FN (overrider))
|
||||
{
|
||||
if (DECL_DELETED_FN (overrider))
|
||||
|
@ -1355,7 +1355,14 @@ begin_compound_stmt (unsigned int flags)
|
||||
keep_next_level (false);
|
||||
}
|
||||
else
|
||||
r = do_pushlevel (flags & BCS_TRY_BLOCK ? sk_try : sk_block);
|
||||
{
|
||||
scope_kind sk = sk_block;
|
||||
if (flags & BCS_TRY_BLOCK)
|
||||
sk = sk_try;
|
||||
else if (flags & BCS_TRANSACTION)
|
||||
sk = sk_transaction;
|
||||
r = do_pushlevel (sk);
|
||||
}
|
||||
|
||||
/* When processing a template, we need to remember where the braces were,
|
||||
so that we can set up identical scopes when instantiating the template
|
||||
|
@ -715,6 +715,22 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
|
||||
return error_mark_node;
|
||||
}
|
||||
}
|
||||
else if (TYPE_PTR_P (t1) && TYPE_PTR_P (t2)
|
||||
&& FUNC_OR_METHOD_TYPE_P (TREE_TYPE (t1))
|
||||
&& TREE_CODE (TREE_TYPE (t2)) == TREE_CODE (TREE_TYPE (t1)))
|
||||
{
|
||||
/* ...if T1 is "pointer to transaction_safe function" and T2 is "pointer
|
||||
to function", where the function types are otherwise the same, T2, and
|
||||
vice versa.... */
|
||||
tree f1 = TREE_TYPE (t1);
|
||||
tree f2 = TREE_TYPE (t2);
|
||||
bool safe1 = tx_safe_fn_type_p (f1);
|
||||
bool safe2 = tx_safe_fn_type_p (f2);
|
||||
if (safe1 && !safe2)
|
||||
t1 = build_pointer_type (tx_unsafe_fn_variant (f1));
|
||||
else if (safe2 && !safe1)
|
||||
t2 = build_pointer_type (tx_unsafe_fn_variant (f2));
|
||||
}
|
||||
|
||||
return composite_pointer_type_r (t1, t2, operation, complain);
|
||||
}
|
||||
|
14
gcc/testsuite/g++.dg/tm/composite1.C
Normal file
14
gcc/testsuite/g++.dg/tm/composite1.C
Normal file
@ -0,0 +1,14 @@
|
||||
// Test for composite pointer type.
|
||||
// { dg-options -fgnu-tm }
|
||||
|
||||
void f(bool b)
|
||||
{
|
||||
void (*p)() transaction_safe = 0;
|
||||
void (*g)() = 0;
|
||||
|
||||
g = b ? p : g; // OK
|
||||
p = b ? p : g; // { dg-error "" }
|
||||
|
||||
p == g;
|
||||
p != g;
|
||||
}
|
13
gcc/testsuite/g++.dg/tm/dynamic1.C
Normal file
13
gcc/testsuite/g++.dg/tm/dynamic1.C
Normal file
@ -0,0 +1,13 @@
|
||||
// Test that transaction_safe_dynamic can only be used on virtual functions.
|
||||
// { dg-options "-fgnu-tm -std=c++14" }
|
||||
|
||||
void f() transaction_safe_dynamic; // { dg-error "virtual" }
|
||||
auto a = []() transaction_safe_dynamic {}; // { dg-error "virtual" }
|
||||
struct A {
|
||||
void f() transaction_safe_dynamic; // { dg-error "virtual" }
|
||||
virtual void g();
|
||||
};
|
||||
|
||||
struct B: A {
|
||||
void g() transaction_safe_dynamic;
|
||||
};
|
17
gcc/testsuite/g++.dg/tm/dynamic2.C
Normal file
17
gcc/testsuite/g++.dg/tm/dynamic2.C
Normal file
@ -0,0 +1,17 @@
|
||||
// { dg-options "-fgnu-tm -std=c++14 -O2" }
|
||||
|
||||
void unsafe();
|
||||
struct A {
|
||||
virtual void f() transaction_safe_dynamic;
|
||||
};
|
||||
struct B:A {
|
||||
void f() { unsafe(); }
|
||||
};
|
||||
|
||||
void f() transaction_safe {
|
||||
B b;
|
||||
A& ar = b;
|
||||
// This is undefined behavior, we want to give an error with
|
||||
// devirtualization.
|
||||
ar.f(); // { dg-error "unsafe" }
|
||||
}
|
10
gcc/testsuite/g++.dg/tm/eh1.C
Normal file
10
gcc/testsuite/g++.dg/tm/eh1.C
Normal file
@ -0,0 +1,10 @@
|
||||
// A handler can involve a transaction-safety conversion.
|
||||
// { dg-do run }
|
||||
// { dg-options "-fgnu-tm" }
|
||||
|
||||
void g() transaction_safe {}
|
||||
int main()
|
||||
{
|
||||
try { throw g; }
|
||||
catch (void (*p)()) { }
|
||||
}
|
14
gcc/testsuite/g++.dg/tm/eh2.C
Normal file
14
gcc/testsuite/g++.dg/tm/eh2.C
Normal file
@ -0,0 +1,14 @@
|
||||
// A handler cannot do the reverse of a transaction-safety conversion.
|
||||
// { dg-do run }
|
||||
// { dg-options "-fgnu-tm" }
|
||||
|
||||
extern "C" void abort();
|
||||
|
||||
void g() {}
|
||||
|
||||
int main()
|
||||
{
|
||||
try { throw g; }
|
||||
catch (void (*p)() transaction_safe) { abort(); }
|
||||
catch (...) { }
|
||||
}
|
21
gcc/testsuite/g++.dg/tm/eh4.C
Normal file
21
gcc/testsuite/g++.dg/tm/eh4.C
Normal file
@ -0,0 +1,21 @@
|
||||
// Test that throwing out of an atomic_commit block commits the transaction.
|
||||
|
||||
// { dg-do run }
|
||||
// { dg-options "-fgnu-tm" }
|
||||
|
||||
int main()
|
||||
{
|
||||
static int i;
|
||||
bool caught = false;
|
||||
try {
|
||||
atomic_commit {
|
||||
i = 12;
|
||||
throw 42;
|
||||
i = 24;
|
||||
}
|
||||
} catch (int x) {
|
||||
caught = (x == 42);
|
||||
}
|
||||
if (!caught || i != 12)
|
||||
__builtin_abort();
|
||||
}
|
11
gcc/testsuite/g++.dg/tm/inherit1.C
Normal file
11
gcc/testsuite/g++.dg/tm/inherit1.C
Normal file
@ -0,0 +1,11 @@
|
||||
// Testcase from TM TS
|
||||
// { dg-options "-std=c++14 -fgnu-tm" }
|
||||
|
||||
struct B {
|
||||
virtual void f() transaction_safe;
|
||||
};
|
||||
|
||||
struct D3 : B
|
||||
{
|
||||
void f() transaction_safe_dynamic override; // { dg-error "" "B::f() is transaction_safe" }
|
||||
};
|
33
gcc/testsuite/g++.dg/tm/inherit2.C
Normal file
33
gcc/testsuite/g++.dg/tm/inherit2.C
Normal file
@ -0,0 +1,33 @@
|
||||
// Testcase from TM TS
|
||||
// { dg-options "-std=c++14 -fgnu-tm" }
|
||||
|
||||
#include <iostream>
|
||||
|
||||
struct B {
|
||||
virtual void f() transaction_safe;
|
||||
virtual ~B() transaction_safe_dynamic;
|
||||
};
|
||||
// pre-existing code
|
||||
struct D1 : B
|
||||
{
|
||||
void f() override { } // ok
|
||||
~D1() override { } // ok
|
||||
};
|
||||
struct D2 : B
|
||||
{
|
||||
void f() override { std::cout << "D2::f" << std::endl; } // { dg-error "" "transaction-safe f has transaction-unsafe definition" }
|
||||
~D2() override { std::cout << "~D2" << std::endl; } // ok
|
||||
};
|
||||
int main()
|
||||
{
|
||||
D2 * d2 = new D2;
|
||||
B * b2 = d2;
|
||||
atomic_commit {
|
||||
B b; // ok
|
||||
D1 d1; // ok
|
||||
B& b1 = d1;
|
||||
D2 x; // { dg-error "" "destructor of D2 is not transaction-safe" }
|
||||
b1.f(); // ok, calls D1::f()
|
||||
delete b2; // undefined behavior: calls unsafe destructor of D2
|
||||
}
|
||||
}
|
23
gcc/testsuite/g++.dg/tm/jump1.C
Normal file
23
gcc/testsuite/g++.dg/tm/jump1.C
Normal file
@ -0,0 +1,23 @@
|
||||
// A goto or switch statement shall not be used to transfer control into a
|
||||
// synchronized or atomic block.
|
||||
// { dg-options "-fgnu-tm" }
|
||||
|
||||
void f()
|
||||
{
|
||||
static int i;
|
||||
synchronized {
|
||||
++i;
|
||||
inside: // { dg-message "" }
|
||||
++i;
|
||||
}
|
||||
goto inside; // { dg-message "" }
|
||||
|
||||
switch (i)
|
||||
{
|
||||
synchronized {
|
||||
++i;
|
||||
case 42: // { dg-error "" }
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
9
gcc/testsuite/g++.dg/tm/keyword1.C
Normal file
9
gcc/testsuite/g++.dg/tm/keyword1.C
Normal file
@ -0,0 +1,9 @@
|
||||
// Test that these aren't keywords without -fgnu-tm.
|
||||
|
||||
int main()
|
||||
{
|
||||
synchronized { } // { dg-error "not declared" }
|
||||
atomic_noexcept { } // { dg-error "not declared" }
|
||||
atomic_cancel { } // { dg-error "not declared" }
|
||||
atomic_commit { } // { dg-error "not declared" }
|
||||
}
|
10
gcc/testsuite/g++.dg/tm/lambda1.C
Normal file
10
gcc/testsuite/g++.dg/tm/lambda1.C
Normal file
@ -0,0 +1,10 @@
|
||||
// Test for lambda conversion.
|
||||
// { dg-options "-fgnu-tm -std=c++14" }
|
||||
|
||||
void f(bool b)
|
||||
{
|
||||
void (*p)() transaction_safe;
|
||||
|
||||
p = []() transaction_safe {};
|
||||
p = []{}; // { dg-error "transaction_safe" }
|
||||
}
|
9
gcc/testsuite/g++.dg/tm/lambda2.C
Normal file
9
gcc/testsuite/g++.dg/tm/lambda2.C
Normal file
@ -0,0 +1,9 @@
|
||||
// Test for lambda call.
|
||||
// { dg-options "-fgnu-tm -std=c++14" }
|
||||
|
||||
void unsafe ();
|
||||
void f() transaction_safe
|
||||
{
|
||||
[]{}(); // OK, implicitly transaction-safe.
|
||||
[]{unsafe();}(); // { dg-error "unsafe" }
|
||||
}
|
5
gcc/testsuite/g++.dg/tm/macro1.C
Normal file
5
gcc/testsuite/g++.dg/tm/macro1.C
Normal file
@ -0,0 +1,5 @@
|
||||
// { dg-options -fgnu-tm }
|
||||
|
||||
#ifndef __cpp_transactional_memory
|
||||
#error __cpp_transactional_memory not defined
|
||||
#endif
|
18
gcc/testsuite/g++.dg/tm/mangle1.C
Normal file
18
gcc/testsuite/g++.dg/tm/mangle1.C
Normal file
@ -0,0 +1,18 @@
|
||||
// Test for transaction_safe mangling.
|
||||
// { dg-options -fgnu-tm }
|
||||
|
||||
// { dg-final { scan-assembler "_Z1fPDxFvvE" } }
|
||||
void f(void (*)() transaction_safe) {}
|
||||
|
||||
// { dg-final { scan-assembler "_Z1fPDxFvvEPFvvE" } }
|
||||
void f(void (*)() transaction_safe, void (*)()) {}
|
||||
|
||||
// { dg-final { scan-assembler "_Z1fPDxFvvES0_" } }
|
||||
void f(void (*)() transaction_safe, void (*)() transaction_safe) {}
|
||||
|
||||
// { dg-final { scan-assembler "_Z1f1AIKDxFvvEE" } }
|
||||
template <class T> struct A { };
|
||||
void f(A<void () const transaction_safe>) { }
|
||||
|
||||
// { dg-final { scan-assembler "_Z1fM1AIiEKDxFvvE" } }
|
||||
void f(void (A<int>::*)() const transaction_safe) { }
|
7
gcc/testsuite/g++.dg/tm/noexcept-7.C
Normal file
7
gcc/testsuite/g++.dg/tm/noexcept-7.C
Normal file
@ -0,0 +1,7 @@
|
||||
// FIXME the TS says atomic_noexcept calls abort, not terminate.
|
||||
// { dg-options "-fgnu-tm" }
|
||||
|
||||
void f()
|
||||
{
|
||||
atomic_noexcept { throw; } // { dg-warning "terminate" }
|
||||
}
|
6
gcc/testsuite/g++.dg/tm/overload1.C
Normal file
6
gcc/testsuite/g++.dg/tm/overload1.C
Normal file
@ -0,0 +1,6 @@
|
||||
// Function declarations that differ only in the presence or absence of a
|
||||
// tx-qualifier cannot be overloaded.
|
||||
// { dg-options "-fgnu-tm" }
|
||||
|
||||
void f(); // { dg-message "" }
|
||||
void f() transaction_safe; // { dg-error "" }
|
9
gcc/testsuite/g++.dg/tm/overload2.C
Normal file
9
gcc/testsuite/g++.dg/tm/overload2.C
Normal file
@ -0,0 +1,9 @@
|
||||
// 13.4p1: A function with type F is selected for the function type FT of the
|
||||
// target type required in the context if F (after possibly applying the
|
||||
// transaction-safety conversion (4.14 [conv.tx])) is identical to FT.
|
||||
// { dg-options "-fgnu-tm" }
|
||||
|
||||
void f() transaction_safe;
|
||||
void f(int);
|
||||
|
||||
void (*p)() = f;
|
6
gcc/testsuite/g++.dg/tm/pretty-print1.C
Normal file
6
gcc/testsuite/g++.dg/tm/pretty-print1.C
Normal file
@ -0,0 +1,6 @@
|
||||
// Test for pretty-printing in diagnostics.
|
||||
// { dg-options "-fgnu-tm" }
|
||||
|
||||
void f();
|
||||
void (*p)() transaction_safe = f; // { dg-error "void \\(\\*\\)\\(\\) transaction_safe" }
|
||||
|
9
gcc/testsuite/g++.dg/tm/static_cast1.C
Normal file
9
gcc/testsuite/g++.dg/tm/static_cast1.C
Normal file
@ -0,0 +1,9 @@
|
||||
// The inverse of a transaction-safety conversion cannot be performed with
|
||||
// static_cast.
|
||||
// { dg-options "-fgnu-tm" }
|
||||
|
||||
typedef void (*TS)() transaction_safe;
|
||||
void f()
|
||||
{
|
||||
static_cast<TS>(f); // { dg-error "static_cast" }
|
||||
}
|
15
gcc/testsuite/g++.dg/tm/sync1.C
Normal file
15
gcc/testsuite/g++.dg/tm/sync1.C
Normal file
@ -0,0 +1,15 @@
|
||||
// Testcase from TM TS.
|
||||
// { dg-options -fgnu-tm }
|
||||
|
||||
extern "C" int printf (const char *, ...);
|
||||
|
||||
int f()
|
||||
{
|
||||
static int i = 0;
|
||||
synchronized {
|
||||
printf("before %d\n", i);
|
||||
++i;
|
||||
printf("after %d\n", i);
|
||||
return i;
|
||||
}
|
||||
}
|
21
gcc/testsuite/g++.dg/tm/sync2.C
Normal file
21
gcc/testsuite/g++.dg/tm/sync2.C
Normal file
@ -0,0 +1,21 @@
|
||||
// { dg-do compile { target c++11 } }
|
||||
// { dg-options "-fgnu-tm -fdump-tree-optimized-asmname" }
|
||||
|
||||
struct Tsafe
|
||||
{
|
||||
void f() transaction_safe;
|
||||
};
|
||||
|
||||
void Tsafe::f() { }
|
||||
|
||||
struct Tcall
|
||||
{
|
||||
[[optimize_for_synchronized]] void f();
|
||||
};
|
||||
|
||||
void Tcall::f() { }
|
||||
|
||||
// { dg-final { scan-tree-dump-times "_ZN5Tsafe1fEv" 1 "optimized" } }
|
||||
// { dg-final { scan-tree-dump-times "_ZN5Tcall1fEv" 1 "optimized" } }
|
||||
// { dg-final { scan-tree-dump-times "_ZGTtN5Tsafe1fEv" 1 "optimized" } }
|
||||
// { dg-final { scan-tree-dump-times "_ZGTtN5Tcall1fEv" 1 "optimized" } }
|
15
gcc/testsuite/g++.dg/tm/template-3.C
Normal file
15
gcc/testsuite/g++.dg/tm/template-3.C
Normal file
@ -0,0 +1,15 @@
|
||||
// { dg-options "-fgnu-tm" }
|
||||
|
||||
void fn(int) transaction_safe;
|
||||
void fn(double);
|
||||
|
||||
template <class T> void f(T t) transaction_safe
|
||||
{
|
||||
fn(t); // { dg-error "double" }
|
||||
}
|
||||
|
||||
void g()
|
||||
{
|
||||
f(42); // OK
|
||||
f(3.14);
|
||||
}
|
13
gcc/testsuite/g++.dg/tm/template-4.C
Normal file
13
gcc/testsuite/g++.dg/tm/template-4.C
Normal file
@ -0,0 +1,13 @@
|
||||
// Test for transaction-safety conversion in deduction.
|
||||
// { dg-options "-fgnu-tm" }
|
||||
|
||||
void fn(int) transaction_safe;
|
||||
void fn();
|
||||
|
||||
template <class T> void f(void(*)(T));
|
||||
template <class T> void f2(void(*)(T) transaction_safe);
|
||||
|
||||
void g()
|
||||
{
|
||||
f(fn);
|
||||
}
|
12
gcc/testsuite/g++.dg/tm/template-5.C
Normal file
12
gcc/testsuite/g++.dg/tm/template-5.C
Normal file
@ -0,0 +1,12 @@
|
||||
// Test for deduction based on transaction_safe.
|
||||
// { dg-options "-fgnu-tm -std=c++11" }
|
||||
|
||||
void f() transaction_safe;
|
||||
void g();
|
||||
|
||||
template <class T> struct A;
|
||||
template <class R, class...Ps>
|
||||
struct A<R (Ps...) transaction_safe> { };
|
||||
|
||||
A<decltype(f)> a;
|
||||
A<decltype(g)> b; // { dg-error "incomplete" }
|
15
gcc/testsuite/g++.dg/tm/unsafe1.C
Normal file
15
gcc/testsuite/g++.dg/tm/unsafe1.C
Normal file
@ -0,0 +1,15 @@
|
||||
// Transaction-unsafe testcase from TM TS.
|
||||
// { dg-options -fgnu-tm }
|
||||
|
||||
struct S {
|
||||
virtual ~S();
|
||||
};
|
||||
int f() transaction_safe {
|
||||
S s; // { dg-error "unsafe" "invocation of unsafe destructor" }
|
||||
}
|
||||
|
||||
int g(int x) { // is transaction-safe
|
||||
if (x <= 0)
|
||||
return 0;
|
||||
return x + g(x-1);
|
||||
}
|
13
gcc/testsuite/g++.dg/tm/unsafe2.C
Normal file
13
gcc/testsuite/g++.dg/tm/unsafe2.C
Normal file
@ -0,0 +1,13 @@
|
||||
// Transaction-unsafe testcase from TM TS.
|
||||
// { dg-options -fgnu-tm }
|
||||
|
||||
template<class T>
|
||||
void f(T) transaction_safe;
|
||||
template<>
|
||||
void f(bool); // not transaction-safe
|
||||
|
||||
int g() transaction_safe
|
||||
{
|
||||
f(42); // OK
|
||||
f(true); // { dg-error "unsafe" }
|
||||
}
|
@ -141,6 +141,10 @@ proc g++_link_flags { paths } {
|
||||
if [file exists "${gccpath}/librx/librx.a"] {
|
||||
append flags "-L${gccpath}/librx "
|
||||
}
|
||||
if [file exists "${gccpath}/libitm/libitm.spec"] {
|
||||
append flags "-B${gccpath}/libitm/ -L${gccpath}/libitm/.libs"
|
||||
append ld_library_path ":${gccpath}/libitm/.libs"
|
||||
}
|
||||
append ld_library_path [gcc-set-multilib-library-path $GXX_UNDER_TEST]
|
||||
} else {
|
||||
global tool_root_dir
|
||||
|
@ -5017,6 +5017,8 @@ comp_type_attributes (const_tree type1, const_tree type2)
|
||||
if (!a)
|
||||
return 1;
|
||||
}
|
||||
if (lookup_attribute ("transaction_safe", CONST_CAST_TREE (a)))
|
||||
return 0;
|
||||
/* As some type combinations - like default calling-convention - might
|
||||
be compatible, we have to call the target hook to get the final result. */
|
||||
return targetm.comp_type_attributes (type1, type2);
|
||||
|
@ -592,6 +592,9 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
|
||||
#define COMPLETE_OR_UNBOUND_ARRAY_TYPE_P(NODE) \
|
||||
(COMPLETE_TYPE_P (TREE_CODE (NODE) == ARRAY_TYPE ? TREE_TYPE (NODE) : (NODE)))
|
||||
|
||||
#define FUNC_OR_METHOD_TYPE_P(NODE) \
|
||||
(TREE_CODE (NODE) == FUNCTION_TYPE || TREE_CODE (NODE) == METHOD_TYPE)
|
||||
|
||||
/* Define many boolean fields that all tree nodes have. */
|
||||
|
||||
/* In VAR_DECL, PARM_DECL and RESULT_DECL nodes, nonzero means address
|
||||
|
@ -442,6 +442,8 @@ enum demangle_component_type
|
||||
DEMANGLE_COMPONENT_PACK_EXPANSION,
|
||||
/* A name with an ABI tag. */
|
||||
DEMANGLE_COMPONENT_TAGGED_NAME,
|
||||
/* A transaction-safe function type. */
|
||||
DEMANGLE_COMPONENT_TRANSACTION_SAFE,
|
||||
/* A cloned function. */
|
||||
DEMANGLE_COMPONENT_CLONE
|
||||
};
|
||||
|
@ -1,3 +1,12 @@
|
||||
2015-09-30 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* cp-demangle.c (d_cv_qualifiers): Dx means transaction_safe.
|
||||
(cplus_demangle_type): Let d_cv_qualifiers handle it.
|
||||
(d_dump, d_make_comp, has_return_type, d_encoding)
|
||||
(d_count_templates_scopes, d_print_comp_inner)
|
||||
(d_print_mod_list, d_print_mod, d_print_function_type)
|
||||
(is_ctor_or_dtor): Handle DEMANGLE_COMPONENT_TRANSACTION_SAFE.
|
||||
|
||||
2015-08-15 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* cp-demangle.c (d_abi_tags): Preserve di->last_name across any
|
||||
|
@ -686,6 +686,9 @@ d_dump (struct demangle_component *dc, int indent)
|
||||
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
|
||||
printf ("rvalue reference this\n");
|
||||
break;
|
||||
case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
|
||||
printf ("transaction_safe this\n");
|
||||
break;
|
||||
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
|
||||
printf ("vendor type qualifier\n");
|
||||
break;
|
||||
@ -970,6 +973,7 @@ d_make_comp (struct d_info *di, enum demangle_component_type type,
|
||||
case DEMANGLE_COMPONENT_RESTRICT_THIS:
|
||||
case DEMANGLE_COMPONENT_VOLATILE_THIS:
|
||||
case DEMANGLE_COMPONENT_CONST_THIS:
|
||||
case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
|
||||
case DEMANGLE_COMPONENT_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_ARGLIST:
|
||||
@ -1212,6 +1216,7 @@ has_return_type (struct demangle_component *dc)
|
||||
case DEMANGLE_COMPONENT_CONST_THIS:
|
||||
case DEMANGLE_COMPONENT_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
|
||||
return has_return_type (d_left (dc));
|
||||
}
|
||||
}
|
||||
@ -1268,6 +1273,7 @@ d_encoding (struct d_info *di, int top_level)
|
||||
while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|
||||
|| dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|
||||
|| dc->type == DEMANGLE_COMPONENT_CONST_THIS
|
||||
|| dc->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
|
||||
|| dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS
|
||||
|| dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
|
||||
dc = d_left (dc);
|
||||
@ -1284,6 +1290,7 @@ d_encoding (struct d_info *di, int top_level)
|
||||
while (dcr->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|
||||
|| dcr->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|
||||
|| dcr->type == DEMANGLE_COMPONENT_CONST_THIS
|
||||
|| dcr->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
|
||||
|| dcr->type == DEMANGLE_COMPONENT_REFERENCE_THIS
|
||||
|| dcr->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
|
||||
dcr = d_left (dcr);
|
||||
@ -2281,7 +2288,8 @@ cplus_demangle_type (struct d_info *di)
|
||||
names. */
|
||||
|
||||
peek = d_peek_char (di);
|
||||
if (peek == 'r' || peek == 'V' || peek == 'K')
|
||||
if (peek == 'r' || peek == 'V' || peek == 'K'
|
||||
|| (peek == 'D' && d_peek_next_char (di) == 'x'))
|
||||
{
|
||||
struct demangle_component **pret;
|
||||
|
||||
@ -2592,7 +2600,7 @@ cplus_demangle_type (struct d_info *di)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* <CV-qualifiers> ::= [r] [V] [K] */
|
||||
/* <CV-qualifiers> ::= [r] [V] [K] [Dx] */
|
||||
|
||||
static struct demangle_component **
|
||||
d_cv_qualifiers (struct d_info *di,
|
||||
@ -2603,7 +2611,8 @@ d_cv_qualifiers (struct d_info *di,
|
||||
|
||||
pstart = pret;
|
||||
peek = d_peek_char (di);
|
||||
while (peek == 'r' || peek == 'V' || peek == 'K')
|
||||
while (peek == 'r' || peek == 'V' || peek == 'K'
|
||||
|| (peek == 'D' && d_peek_next_char (di) == 'x'))
|
||||
{
|
||||
enum demangle_component_type t;
|
||||
|
||||
@ -2622,13 +2631,19 @@ d_cv_qualifiers (struct d_info *di,
|
||||
: DEMANGLE_COMPONENT_VOLATILE);
|
||||
di->expansion += sizeof "volatile";
|
||||
}
|
||||
else
|
||||
else if (peek == 'K')
|
||||
{
|
||||
t = (member_fn
|
||||
? DEMANGLE_COMPONENT_CONST_THIS
|
||||
: DEMANGLE_COMPONENT_CONST);
|
||||
di->expansion += sizeof "const";
|
||||
}
|
||||
else
|
||||
{
|
||||
t = DEMANGLE_COMPONENT_TRANSACTION_SAFE;
|
||||
di->expansion += sizeof "transaction_safe";
|
||||
d_advance (di, 1);
|
||||
}
|
||||
|
||||
*pret = d_make_comp (di, t, NULL, NULL);
|
||||
if (*pret == NULL)
|
||||
@ -2694,7 +2709,7 @@ d_ref_qualifier (struct d_info *di, struct demangle_component *sub)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E */
|
||||
/* <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] [T] E */
|
||||
|
||||
static struct demangle_component *
|
||||
d_function_type (struct d_info *di)
|
||||
@ -3899,6 +3914,7 @@ d_count_templates_scopes (int *num_templates, int *num_scopes,
|
||||
case DEMANGLE_COMPONENT_CONST_THIS:
|
||||
case DEMANGLE_COMPONENT_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
|
||||
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
|
||||
case DEMANGLE_COMPONENT_POINTER:
|
||||
case DEMANGLE_COMPONENT_COMPLEX:
|
||||
@ -4420,6 +4436,7 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
|
||||
&& typed_name->type != DEMANGLE_COMPONENT_VOLATILE_THIS
|
||||
&& typed_name->type != DEMANGLE_COMPONENT_CONST_THIS
|
||||
&& typed_name->type != DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS
|
||||
&& typed_name->type != DEMANGLE_COMPONENT_TRANSACTION_SAFE
|
||||
&& typed_name->type != DEMANGLE_COMPONENT_REFERENCE_THIS)
|
||||
break;
|
||||
|
||||
@ -4461,6 +4478,7 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
|
||||
|| local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|
||||
|| local_name->type == DEMANGLE_COMPONENT_CONST_THIS
|
||||
|| local_name->type == DEMANGLE_COMPONENT_REFERENCE_THIS
|
||||
|| local_name->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
|
||||
|| (local_name->type
|
||||
== DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS))
|
||||
{
|
||||
@ -4796,6 +4814,7 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
|
||||
case DEMANGLE_COMPONENT_POINTER:
|
||||
case DEMANGLE_COMPONENT_COMPLEX:
|
||||
case DEMANGLE_COMPONENT_IMAGINARY:
|
||||
case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
|
||||
modifier:
|
||||
{
|
||||
/* We keep a list of modifiers on the stack. */
|
||||
@ -5484,6 +5503,7 @@ d_print_mod_list (struct d_print_info *dpi, int options,
|
||||
|| mods->mod->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|
||||
|| mods->mod->type == DEMANGLE_COMPONENT_CONST_THIS
|
||||
|| mods->mod->type == DEMANGLE_COMPONENT_REFERENCE_THIS
|
||||
|| mods->mod->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
|
||||
|| (mods->mod->type
|
||||
== DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS))))
|
||||
{
|
||||
@ -5542,6 +5562,7 @@ d_print_mod_list (struct d_print_info *dpi, int options,
|
||||
|| dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|
||||
|| dc->type == DEMANGLE_COMPONENT_CONST_THIS
|
||||
|| dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS
|
||||
|| dc->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
|
||||
|| dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
|
||||
dc = d_left (dc);
|
||||
|
||||
@ -5578,6 +5599,9 @@ d_print_mod (struct d_print_info *dpi, int options,
|
||||
case DEMANGLE_COMPONENT_CONST_THIS:
|
||||
d_append_string (dpi, " const");
|
||||
return;
|
||||
case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
|
||||
d_append_string (dpi, " transaction_safe");
|
||||
return;
|
||||
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
|
||||
d_append_char (dpi, ' ');
|
||||
d_print_comp (dpi, options, d_right (mod));
|
||||
@ -5668,6 +5692,7 @@ d_print_function_type (struct d_print_info *dpi, int options,
|
||||
case DEMANGLE_COMPONENT_CONST_THIS:
|
||||
case DEMANGLE_COMPONENT_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -6200,6 +6225,7 @@ is_ctor_or_dtor (const char *mangled,
|
||||
case DEMANGLE_COMPONENT_CONST_THIS:
|
||||
case DEMANGLE_COMPONENT_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
|
||||
case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
|
||||
default:
|
||||
dc = NULL;
|
||||
break;
|
||||
|
@ -4395,3 +4395,6 @@ void IndirectExternCall<void ( regparm<3> stdcall*)(int, int), int>(void ( regpa
|
||||
_ZNSt8ios_base7failureB5cxx11C1EPKcRKSt10error_code
|
||||
std::ios_base::failure[abi:cxx11]::failure(char const*, std::error_code const&)
|
||||
std::ios_base::failure[abi:cxx11]::failure
|
||||
--format=gnu-v3
|
||||
_Z1fPDxFvvES0_
|
||||
f(void (*)() transaction_safe, void (*)() transaction_safe)
|
||||
|
@ -281,7 +281,8 @@ namespace __cxxabiv1
|
||||
__volatile_mask = 0x2,
|
||||
__restrict_mask = 0x4,
|
||||
__incomplete_mask = 0x8,
|
||||
__incomplete_class_mask = 0x10
|
||||
__incomplete_class_mask = 0x10,
|
||||
__transaction_safe_mask = 0x20
|
||||
};
|
||||
|
||||
protected:
|
||||
|
@ -50,8 +50,19 @@ __do_catch (const type_info *thr_type,
|
||||
|
||||
const __pbase_type_info *thrown_type =
|
||||
static_cast <const __pbase_type_info *> (thr_type);
|
||||
|
||||
unsigned tflags = thrown_type->__flags;
|
||||
|
||||
bool throw_tx = (tflags & __transaction_safe_mask);
|
||||
bool catch_tx = (__flags & __transaction_safe_mask);
|
||||
if (throw_tx && !catch_tx)
|
||||
/* Catch can perform a transaction-safety conversion. */
|
||||
tflags &= ~__transaction_safe_mask;
|
||||
if (catch_tx && !throw_tx)
|
||||
/* But not the reverse. */
|
||||
return false;
|
||||
|
||||
if (thrown_type->__flags & ~__flags)
|
||||
if (tflags & ~__flags)
|
||||
// We're less qualified.
|
||||
return false;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user