summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog4
-rw-r--r--gcc/builtins.def2
-rw-r--r--gcc/c-family/ChangeLog15
-rw-r--r--gcc/c-family/c-common.c28
-rw-r--r--gcc/c-family/c-common.h6
-rw-r--r--gcc/c-family/c-cppbuiltin.c4
-rw-r--r--gcc/c-family/c-pretty-print.c4
-rw-r--r--gcc/c/ChangeLog6
-rw-r--r--gcc/c/c-decl.c14
-rw-r--r--gcc/c/c-parser.c1
-rw-r--r--gcc/cp/ChangeLog44
-rw-r--r--gcc/cp/call.c17
-rw-r--r--gcc/cp/class.c23
-rw-r--r--gcc/cp/cp-tree.h9
-rw-r--r--gcc/cp/cvt.c33
-rw-r--r--gcc/cp/decl.c52
-rw-r--r--gcc/cp/error.c8
-rw-r--r--gcc/cp/lambda.c5
-rw-r--r--gcc/cp/lex.c2
-rw-r--r--gcc/cp/mangle.c12
-rw-r--r--gcc/cp/name-lookup.c1
-rw-r--r--gcc/cp/name-lookup.h1
-rw-r--r--gcc/cp/parser.c123
-rw-r--r--gcc/cp/rtti.c5
-rw-r--r--gcc/cp/search.c22
-rw-r--r--gcc/cp/semantics.c9
-rw-r--r--gcc/cp/typeck.c16
-rw-r--r--gcc/testsuite/g++.dg/tm/composite1.C14
-rw-r--r--gcc/testsuite/g++.dg/tm/dynamic1.C13
-rw-r--r--gcc/testsuite/g++.dg/tm/dynamic2.C17
-rw-r--r--gcc/testsuite/g++.dg/tm/eh1.C10
-rw-r--r--gcc/testsuite/g++.dg/tm/eh2.C14
-rw-r--r--gcc/testsuite/g++.dg/tm/eh4.C21
-rw-r--r--gcc/testsuite/g++.dg/tm/inherit1.C11
-rw-r--r--gcc/testsuite/g++.dg/tm/inherit2.C33
-rw-r--r--gcc/testsuite/g++.dg/tm/jump1.C23
-rw-r--r--gcc/testsuite/g++.dg/tm/keyword1.C9
-rw-r--r--gcc/testsuite/g++.dg/tm/lambda1.C10
-rw-r--r--gcc/testsuite/g++.dg/tm/lambda2.C9
-rw-r--r--gcc/testsuite/g++.dg/tm/macro1.C5
-rw-r--r--gcc/testsuite/g++.dg/tm/mangle1.C18
-rw-r--r--gcc/testsuite/g++.dg/tm/noexcept-7.C7
-rw-r--r--gcc/testsuite/g++.dg/tm/overload1.C6
-rw-r--r--gcc/testsuite/g++.dg/tm/overload2.C9
-rw-r--r--gcc/testsuite/g++.dg/tm/pretty-print1.C6
-rw-r--r--gcc/testsuite/g++.dg/tm/static_cast1.C9
-rw-r--r--gcc/testsuite/g++.dg/tm/sync1.C15
-rw-r--r--gcc/testsuite/g++.dg/tm/sync2.C21
-rw-r--r--gcc/testsuite/g++.dg/tm/template-3.C15
-rw-r--r--gcc/testsuite/g++.dg/tm/template-4.C13
-rw-r--r--gcc/testsuite/g++.dg/tm/template-5.C12
-rw-r--r--gcc/testsuite/g++.dg/tm/unsafe1.C15
-rw-r--r--gcc/testsuite/g++.dg/tm/unsafe2.C13
-rw-r--r--gcc/testsuite/lib/g++.exp4
-rw-r--r--gcc/tree.c2
-rw-r--r--gcc/tree.h3
-rw-r--r--include/demangle.h2
-rw-r--r--libiberty/ChangeLog9
-rw-r--r--libiberty/cp-demangle.c36
-rw-r--r--libiberty/testsuite/demangle-expected3
-rw-r--r--libstdc++-v3/libsupc++/cxxabi.h3
-rw-r--r--libstdc++-v3/libsupc++/pbase_type_info.cc13
62 files changed, 833 insertions, 56 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 4ba93a24d65..0d740a24901 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/builtins.def b/gcc/builtins.def
index f7ac4a834cc..2cb82510bc5 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -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)
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 78cc2bdc8b8..c75d4895097 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -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.
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index f38378d69dd..4b64a448a88 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -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));
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index ff4530f630e..d5fb4998268 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -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
diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c
index b222a9f263b..e109e820eea 100644
--- a/gcc/c-family/c-cppbuiltin.c
+++ b/gcc/c-family/c-cppbuiltin.c
@@ -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");
}
diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-print.c
index e2809cff35b..c61c41f1810 100644
--- a/gcc/c-family/c-pretty-print.c
+++ b/gcc/c-family/c-pretty-print.c
@@ -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__");
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index c6eab4ed0fc..e0f169dc1d5 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -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
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index a110226d01f..ce8406a13e4 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -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
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 00fa2386c46..0df7d7bb01e 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -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;
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index e6e2e0caf0d..bc169b82bd0 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 367d42b217c..050d0457483 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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);
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 9611dec3435..ef537be5c30 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -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);
}
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 80d6c4e4a2f..5acb065aba0 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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);
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 6d4bd9aac25..b61588021a3 100644
--- a/gcc/cp/cvt.c
+++ b/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)));
+}
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 2be7d2f977f..eff52819aca 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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;
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index faf8744e225..17870b5f1c3 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -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;
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index ea9dba05227..ceab6469574 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -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. */
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index f81c17b4a51..6acf47e631e 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -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)
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 248d280a3fd..faeea141528 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -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
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index bd052a48753..b5030120d6d 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -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;
diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index 82b5e53c740..d430edb73b7 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -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. */
};
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 46aff88f61e..ffed595ac0e 100644
--- a/gcc/cp/parser.c
+++ b/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);
diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c
index e4b6e00e3b8..85be2b29d15 100644
--- a/gcc/cp/rtti.c
+++ b/gcc/cp/rtti.c
@@ -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,
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 42db122e98c..508e66c43bb 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -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))
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index f5bb0c1beb4..ea403987b23 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -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
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 482e42c819b..9e6f9494e6f 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -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);
}
diff --git a/gcc/testsuite/g++.dg/tm/composite1.C b/gcc/testsuite/g++.dg/tm/composite1.C
new file mode 100644
index 00000000000..6e823176128
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/composite1.C
@@ -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;
+}
diff --git a/gcc/testsuite/g++.dg/tm/dynamic1.C b/gcc/testsuite/g++.dg/tm/dynamic1.C
new file mode 100644
index 00000000000..a6f49567432
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/dynamic1.C
@@ -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;
+};
diff --git a/gcc/testsuite/g++.dg/tm/dynamic2.C b/gcc/testsuite/g++.dg/tm/dynamic2.C
new file mode 100644
index 00000000000..3003b62ca0a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/dynamic2.C
@@ -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" }
+}
diff --git a/gcc/testsuite/g++.dg/tm/eh1.C b/gcc/testsuite/g++.dg/tm/eh1.C
new file mode 100644
index 00000000000..156121142e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/eh1.C
@@ -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)()) { }
+}
diff --git a/gcc/testsuite/g++.dg/tm/eh2.C b/gcc/testsuite/g++.dg/tm/eh2.C
new file mode 100644
index 00000000000..307a63924c3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/eh2.C
@@ -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 (...) { }
+}
diff --git a/gcc/testsuite/g++.dg/tm/eh4.C b/gcc/testsuite/g++.dg/tm/eh4.C
new file mode 100644
index 00000000000..68275e99706
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/eh4.C
@@ -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();
+}
diff --git a/gcc/testsuite/g++.dg/tm/inherit1.C b/gcc/testsuite/g++.dg/tm/inherit1.C
new file mode 100644
index 00000000000..b8480a10892
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/inherit1.C
@@ -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" }
+};
diff --git a/gcc/testsuite/g++.dg/tm/inherit2.C b/gcc/testsuite/g++.dg/tm/inherit2.C
new file mode 100644
index 00000000000..3b696a9ffb6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/inherit2.C
@@ -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
+ }
+}
diff --git a/gcc/testsuite/g++.dg/tm/jump1.C b/gcc/testsuite/g++.dg/tm/jump1.C
new file mode 100644
index 00000000000..003eed034c9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/jump1.C
@@ -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;
+ }
+ }
+}
diff --git a/gcc/testsuite/g++.dg/tm/keyword1.C b/gcc/testsuite/g++.dg/tm/keyword1.C
new file mode 100644
index 00000000000..3537e0fe992
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/keyword1.C
@@ -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" }
+}
diff --git a/gcc/testsuite/g++.dg/tm/lambda1.C b/gcc/testsuite/g++.dg/tm/lambda1.C
new file mode 100644
index 00000000000..d0cffbff22f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/lambda1.C
@@ -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" }
+}
diff --git a/gcc/testsuite/g++.dg/tm/lambda2.C b/gcc/testsuite/g++.dg/tm/lambda2.C
new file mode 100644
index 00000000000..82e509e3658
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/lambda2.C
@@ -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" }
+}
diff --git a/gcc/testsuite/g++.dg/tm/macro1.C b/gcc/testsuite/g++.dg/tm/macro1.C
new file mode 100644
index 00000000000..dcf388839b1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/macro1.C
@@ -0,0 +1,5 @@
+// { dg-options -fgnu-tm }
+
+#ifndef __cpp_transactional_memory
+#error __cpp_transactional_memory not defined
+#endif
diff --git a/gcc/testsuite/g++.dg/tm/mangle1.C b/gcc/testsuite/g++.dg/tm/mangle1.C
new file mode 100644
index 00000000000..f081f8e0289
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/mangle1.C
@@ -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) { }
diff --git a/gcc/testsuite/g++.dg/tm/noexcept-7.C b/gcc/testsuite/g++.dg/tm/noexcept-7.C
new file mode 100644
index 00000000000..bfa675c987f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/noexcept-7.C
@@ -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" }
+}
diff --git a/gcc/testsuite/g++.dg/tm/overload1.C b/gcc/testsuite/g++.dg/tm/overload1.C
new file mode 100644
index 00000000000..71ecab9ff15
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/overload1.C
@@ -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 "" }
diff --git a/gcc/testsuite/g++.dg/tm/overload2.C b/gcc/testsuite/g++.dg/tm/overload2.C
new file mode 100644
index 00000000000..3510779644e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/overload2.C
@@ -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;
diff --git a/gcc/testsuite/g++.dg/tm/pretty-print1.C b/gcc/testsuite/g++.dg/tm/pretty-print1.C
new file mode 100644
index 00000000000..d7c1de0ae52
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/pretty-print1.C
@@ -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" }
+
diff --git a/gcc/testsuite/g++.dg/tm/static_cast1.C b/gcc/testsuite/g++.dg/tm/static_cast1.C
new file mode 100644
index 00000000000..31606c57a7e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/static_cast1.C
@@ -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" }
+}
diff --git a/gcc/testsuite/g++.dg/tm/sync1.C b/gcc/testsuite/g++.dg/tm/sync1.C
new file mode 100644
index 00000000000..a567b2cc3e2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/sync1.C
@@ -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;
+ }
+}
diff --git a/gcc/testsuite/g++.dg/tm/sync2.C b/gcc/testsuite/g++.dg/tm/sync2.C
new file mode 100644
index 00000000000..f13c9c55e90
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/sync2.C
@@ -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" } }
diff --git a/gcc/testsuite/g++.dg/tm/template-3.C b/gcc/testsuite/g++.dg/tm/template-3.C
new file mode 100644
index 00000000000..356d2a89b9b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/template-3.C
@@ -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);
+}
diff --git a/gcc/testsuite/g++.dg/tm/template-4.C b/gcc/testsuite/g++.dg/tm/template-4.C
new file mode 100644
index 00000000000..dd257111bda
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/template-4.C
@@ -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);
+}
diff --git a/gcc/testsuite/g++.dg/tm/template-5.C b/gcc/testsuite/g++.dg/tm/template-5.C
new file mode 100644
index 00000000000..6501ed1a073
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/template-5.C
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/tm/unsafe1.C b/gcc/testsuite/g++.dg/tm/unsafe1.C
new file mode 100644
index 00000000000..91dd7b110ec
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/unsafe1.C
@@ -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);
+}
diff --git a/gcc/testsuite/g++.dg/tm/unsafe2.C b/gcc/testsuite/g++.dg/tm/unsafe2.C
new file mode 100644
index 00000000000..1b81b310057
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/unsafe2.C
@@ -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" }
+}
diff --git a/gcc/testsuite/lib/g++.exp b/gcc/testsuite/lib/g++.exp
index b440dd7f6c8..229fbc3f633 100644
--- a/gcc/testsuite/lib/g++.exp
+++ b/gcc/testsuite/lib/g++.exp
@@ -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
diff --git a/gcc/tree.c b/gcc/tree.c
index 84fd34deb7a..af318495f0f 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -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);
diff --git a/gcc/tree.h b/gcc/tree.h
index 35c72b661b3..4c803f4b4e3 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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
diff --git a/include/demangle.h b/include/demangle.h
index e415de069fe..f4c41218e7f 100644
--- a/include/demangle.h
+++ b/include/demangle.h
@@ -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
};
diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog
index 8fdf6d2d83c..1cd2aea1f97 100644
--- a/libiberty/ChangeLog
+++ b/libiberty/ChangeLog
@@ -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
diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index c587895086d..ff608a36d67 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -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;
diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected
index 5200cb34d19..041b113d63f 100644
--- a/libiberty/testsuite/demangle-expected
+++ b/libiberty/testsuite/demangle-expected
@@ -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)
diff --git a/libstdc++-v3/libsupc++/cxxabi.h b/libstdc++-v3/libsupc++/cxxabi.h
index 571e42e9ad1..08eb7bcce5f 100644
--- a/libstdc++-v3/libsupc++/cxxabi.h
+++ b/libstdc++-v3/libsupc++/cxxabi.h
@@ -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:
diff --git a/libstdc++-v3/libsupc++/pbase_type_info.cc b/libstdc++-v3/libsupc++/pbase_type_info.cc
index cbfdc172f83..0e9652932c0 100644
--- a/libstdc++-v3/libsupc++/pbase_type_info.cc
+++ b/libstdc++-v3/libsupc++/pbase_type_info.cc
@@ -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;