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:
Jason Merrill 2015-10-04 15:17:19 -04:00 committed by Jason Merrill
parent bd841941ec
commit b8fd7909c0
62 changed files with 833 additions and 56 deletions

View File

@ -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

View File

@ -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)

View File

@ -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.

View File

@ -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));

View File

@ -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

View File

@ -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");
}

View File

@ -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__");

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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)));
}

View File

@ -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;

View File

@ -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;

View File

@ -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. */

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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. */
};

View File

@ -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);

View File

@ -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,

View File

@ -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))

View File

@ -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

View File

@ -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);
}

View 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;
}

View 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;
};

View 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" }
}

View 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)()) { }
}

View 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 (...) { }
}

View 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();
}

View 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" }
};

View 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
}
}

View 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;
}
}
}

View 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" }
}

View 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" }
}

View 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" }
}

View File

@ -0,0 +1,5 @@
// { dg-options -fgnu-tm }
#ifndef __cpp_transactional_memory
#error __cpp_transactional_memory not defined
#endif

View 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) { }

View 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" }
}

View 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 "" }

View 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;

View 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" }

View 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" }
}

View 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;
}
}

View 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" } }

View 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);
}

View 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);
}

View 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" }

View 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);
}

View 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" }
}

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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
};

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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:

View File

@ -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;