Implement N4514, C++ Extensions for Transactional Memory.
authorJason Merrill <jason@redhat.com>
Sun, 4 Oct 2015 19:17:19 +0000 (15:17 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Sun, 4 Oct 2015 19:17:19 +0000 (15:17 -0400)
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

62 files changed:
gcc/ChangeLog
gcc/builtins.def
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c-family/c-cppbuiltin.c
gcc/c-family/c-pretty-print.c
gcc/c/ChangeLog
gcc/c/c-decl.c
gcc/c/c-parser.c
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/decl.c
gcc/cp/error.c
gcc/cp/lambda.c
gcc/cp/lex.c
gcc/cp/mangle.c
gcc/cp/name-lookup.c
gcc/cp/name-lookup.h
gcc/cp/parser.c
gcc/cp/rtti.c
gcc/cp/search.c
gcc/cp/semantics.c
gcc/cp/typeck.c
gcc/testsuite/g++.dg/tm/composite1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/dynamic1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/dynamic2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/eh1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/eh2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/eh4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/inherit1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/inherit2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/jump1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/keyword1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/lambda1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/lambda2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/macro1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/mangle1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/noexcept-7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/overload1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/overload2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/pretty-print1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/static_cast1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/sync1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/sync2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/template-3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/template-4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/template-5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/unsafe1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tm/unsafe2.C [new file with mode: 0644]
gcc/testsuite/lib/g++.exp
gcc/tree.c
gcc/tree.h
include/demangle.h
libiberty/ChangeLog
libiberty/cp-demangle.c
libiberty/testsuite/demangle-expected
libstdc++-v3/libsupc++/cxxabi.h
libstdc++-v3/libsupc++/pbase_type_info.cc

index 4ba93a24d652019fde3d086329329c2b90f9d6e5..0d740a24901d1a3ef9b182735bb0052e6d693073 100644 (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
index f7ac4a834cc40906cba3c6d9edf23ebef743b9e5..2cb82510bc5da016e14eeabf72f203612d1ecd37 100644 (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)
index 78cc2bdc8b83172de16c75c363ea02664f30e6e1..c75d489509731773eff49f58d0a949d8889d8d73 100644 (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.
index f38378d69dd1be998e32674891371caebe16a5d1..4b64a448a88cf32af5950081b6233de57d243fe4 100644 (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));
index ff4530f630e8003675b3ba37e8478c0425eb8835..d5fb4998268a3ad79d0d406fe9624f042eed69d7 100644 (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
 
index b222a9f263b1da7106701b5be39a0188c320d3cc..e109e820eeaf4870a3f9dfd059ead8aa13676b2a 100644 (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");
     }
index e2809cff35bc125a81c05be6ae372d0eaa390a22..c61c41f1810dc0d1e283fa65d56ff9b6ce02ed2a 100644 (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__");
index c6eab4ed0fc84030506aced1d05c352e7b0fc8c9..e0f169dc1d5da8e9cb6bdd7384ac004d5dfec4b1 100644 (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
index a110226d01fa679aef9044dc42164ca64270ac6d..ce8406a13e47070579a5cc6ac3925ccad689cb96 100644 (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
index 00fa2386c46d58034954574c1e1fe12d181b6588..0df7d7bb01e21d81e6e537498be1509ee9906251 100644 (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;
index e6e2e0caf0d565afa294c877ab05c4b4394499de..bc169b82bd0626b09cd22ee476b797f5fa210dbc 100644 (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
index 367d42b217c83f5c37c605b55ae64c399c596a5d..050d04574834e69c2193442e943ef2cddb7a1100 100644 (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);
index 9611dec3435bbf2f998223a8f45bd5bf11160f0a..ef537be5c30e8654326e38b84888fc6c94168a06 100644 (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);
        }
 
index 80d6c4e4a2f69e73ae2e51d4f1bf594d58ac9a37..5acb065aba0169d62e2ceb08c3d7af993519b99b 100644 (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);
 
index 6d4bd9aac256bd1b3a61b0948f64b05a2b9760f7..b61588021a346eef0aac3c8ceaa11df7da043cbd 100644 (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)));
+}
index 2be7d2f977f169c471d27abb909d20ff7517b56e..eff52819acaef34cfe1c775df972b630362be0ae 100644 (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;
 
index faf8744e225c19823283e2815e198021a45bc448..17870b5f1c382aafa078c6982e2a27dda868f9a9 100644 (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;
index ea9dba05227556fd958adcbdd187d05e13920303..ceab646957436ff1786da53e70500e4c907f5d99 100644 (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.  */
 
index f81c17b4a51f577f220b1451bf0fae2004baa24b..6acf47e631e3799f20cfeefad2ac4a3f4ded3f4f 100644 (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)
index 248d280a3fd76c1949a3621784e236cef8e716d2..faeea1415281129f49d7f635c4c468495da5e117 100644 (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
index bd052a487537cf20cf64357171f7c90621c15a4e..b5030120d6d66a2cb45665d8f7285230c79ed933 100644 (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;
index 82b5e53c7403ce82b6bccf492b4fc6b8a24e9eff..d430edb73b74d4fa98266c0058feca1b5dcc05ac 100644 (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.  */
 };
 
index 46aff88f61e5f455b7c4c4e7591b77d2e2256259..ffed595ac0e01f46b4a39450867e2e6f972fe10d 100644 (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);
index e4b6e00e3b8b8a3e69b2cfe7c792cd5cf1daa990..85be2b29d1567a7cf5e6f342f9b251a182564abb 100644 (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,
index 42db122e98c73932bcf5d1591a4296ee2d9e5d50..508e66c43bb37d0f40e0c7f5903dce94e37d6077 100644 (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))
index f5bb0c1beb4b31f94d6053c593dc7617108c6ed0..ea403987b235f8d0666d53c24b5a016622507ae6 100644 (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
index 482e42c819b3311770479e8f288e4d8a4051a236..9e6f9494e6fb8d2e3d2b41c36934502cbfa4e69c 100644 (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);
 }
diff --git a/gcc/testsuite/g++.dg/tm/composite1.C b/gcc/testsuite/g++.dg/tm/composite1.C
new file mode 100644 (file)
index 0000000..6e82317
--- /dev/null
@@ -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 (file)
index 0000000..a6f4956
--- /dev/null
@@ -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 (file)
index 0000000..3003b62
--- /dev/null
@@ -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 (file)
index 0000000..1561211
--- /dev/null
@@ -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 (file)
index 0000000..307a639
--- /dev/null
@@ -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 (file)
index 0000000..68275e9
--- /dev/null
@@ -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 (file)
index 0000000..b8480a1
--- /dev/null
@@ -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 (file)
index 0000000..3b696a9
--- /dev/null
@@ -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 (file)
index 0000000..003eed0
--- /dev/null
@@ -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 (file)
index 0000000..3537e0f
--- /dev/null
@@ -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 (file)
index 0000000..d0cffbf
--- /dev/null
@@ -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 (file)
index 0000000..82e509e
--- /dev/null
@@ -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 (file)
index 0000000..dcf3888
--- /dev/null
@@ -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 (file)
index 0000000..f081f8e
--- /dev/null
@@ -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 (file)
index 0000000..bfa675c
--- /dev/null
@@ -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 (file)
index 0000000..71ecab9
--- /dev/null
@@ -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 (file)
index 0000000..3510779
--- /dev/null
@@ -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 (file)
index 0000000..d7c1de0
--- /dev/null
@@ -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 (file)
index 0000000..31606c5
--- /dev/null
@@ -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 (file)
index 0000000..a567b2c
--- /dev/null
@@ -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 (file)
index 0000000..f13c9c5
--- /dev/null
@@ -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 (file)
index 0000000..356d2a8
--- /dev/null
@@ -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 (file)
index 0000000..dd25711
--- /dev/null
@@ -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 (file)
index 0000000..6501ed1
--- /dev/null
@@ -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 (file)
index 0000000..91dd7b1
--- /dev/null
@@ -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 (file)
index 0000000..1b81b31
--- /dev/null
@@ -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" }
+}
index b440dd7f6c8cc269c8e68c24628d4198342b4582..229fbc3f633eb6b4fd45b2ddb8b0fdc700367ec9 100644 (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
index 84fd34deb7ac19cf86086daebd1bcedbb9fc360e..af318495f0f1f091d45c06dfef218dfbd98343f8 100644 (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);
index 35c72b661b379afd0ee86c87811daeaca548a566..4c803f4b4e3f04045083d6d4659fb01939992df5 100644 (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
index e415de069fe277e08ebd411352f986fb6192bd8d..f4c41218e7fea0bdaf05c9b5747a3f6172698e23 100644 (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
 };
index 8fdf6d2d83cc3e31aa6332725e32d61a56f80ceb..1cd2aea1f97762f0b047c09c6d9c9dc37a518f81 100644 (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
index c587895086d3cbc2fef7d03fb9ba3c005eda2cb9..ff608a36d670d73a9f1bf681dd20d1b1f2767006 100644 (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;
index 5200cb34d19f421682ec57bf4af5be2903c56fdf..041b113d63fe98ae35ec7c41ea7b76be140e04ba 100644 (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)
index 571e42e9ad132fefdf32f14ae527519cfb0294b9..08eb7bcce5f33a32ef9f9572e650822140545465 100644 (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:
index cbfdc172f83a8d73e21dab73215e3494bb4d82d7..0e9652932c01aa0b59490852d13e01840eed1a64 100644 (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;