Patchwork 15/n: trans-mem: compiler C++ changes

login
register
mail settings
Submitter Aldy Hernandez
Date Nov. 3, 2011, 6:53 p.m.
Message ID <4EB2E310.7010009@redhat.com>
Download mbox | patch
Permalink /patch/123494/
State New
Headers show

Comments

Aldy Hernandez - Nov. 3, 2011, 6:53 p.m.
Jason, all the compiler changes (including C++) are in a separate post:

http://gcc.gnu.org/ml/gcc-patches/2011-11/msg00380.html

If you would prefer, I can reply to this message and provide the C++ 
changelog entries separately.
Michael Matz - Nov. 4, 2011, 2:37 p.m.
Hi,

On Thu, 3 Nov 2011, Aldy Hernandez wrote:

> +++ gcc/cp/parser.c	(.../branches/transactional-memory)	(revision
> 180773)
> @@ -172,6 +172,10 @@ typedef enum required_token {
>    RT_JUMP, /* jump-statement */
>    RT_CLASS_KEY, /* class-key */
>    RT_CLASS_TYPENAME_TEMPLATE /* class, typename, or template */
> +
> +  , RT_TRANSACTION_ATOMIC, /* __transaction_atomic */
> +  RT_TRANSACTION_RELAXED, /* __transaction_relaxed */
> +  RT_TRANSACTION_CANCEL /* __transaction_cancel */

comma placement.


Ciao,
Michael.
Jason Merrill - Nov. 4, 2011, 3:51 p.m.
On 11/03/2011 02:53 PM, Aldy Hernandez wrote:
> +  if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_SQUARE))
> +    return NULL_TREE;
> +  cp_lexer_consume_token (parser->lexer);
> +  if (!cp_parser_require (parser, CPP_OPEN_SQUARE, RT_OPEN_SQUARE))
> +    goto error1;

Are you sure that [[attribute]] is the only way a [ can appear there? 
What about lambdas?  Just return NULL_TREE here if you see one [ 
followed by something else.  cp_lexer_peek_nth_token should be useful.

Jason
Aldy Hernandez - Nov. 4, 2011, 6:16 p.m.
On 11/04/11 10:51, Jason Merrill wrote:
> On 11/03/2011 02:53 PM, Aldy Hernandez wrote:
>> + if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_SQUARE))
>> + return NULL_TREE;
>> + cp_lexer_consume_token (parser->lexer);
>> + if (!cp_parser_require (parser, CPP_OPEN_SQUARE, RT_OPEN_SQUARE))
>> + goto error1;
>
> Are you sure that [[attribute]] is the only way a [ can appear there?
> What about lambdas? Just return NULL_TREE here if you see one [ followed
> by something else. cp_lexer_peek_nth_token should be useful.
>
> Jason

Richard?
Richard Henderson - Nov. 4, 2011, 6:19 p.m.
On 11/04/2011 11:16 AM, Aldy Hernandez wrote:
> On 11/04/11 10:51, Jason Merrill wrote:
>> On 11/03/2011 02:53 PM, Aldy Hernandez wrote:
>>> + if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_SQUARE))
>>> + return NULL_TREE;
>>> + cp_lexer_consume_token (parser->lexer);
>>> + if (!cp_parser_require (parser, CPP_OPEN_SQUARE, RT_OPEN_SQUARE))
>>> + goto error1;
>>
>> Are you sure that [[attribute]] is the only way a [ can appear there?
>> What about lambdas? Just return NULL_TREE here if you see one [ followed
>> by something else. cp_lexer_peek_nth_token should be useful.

Yes.  We're immediately following a keyword.  The only two valid tokens that can
follow that keyword are [ and {.


r~
Jason Merrill - Nov. 4, 2011, 6:31 p.m.
On 11/04/2011 02:19 PM, Richard Henderson wrote:
>> On 11/04/11 10:51, Jason Merrill wrote:
>>> Are you sure that [[attribute]] is the only way a [ can appear there?
>
> Yes.  We're immediately following a keyword.  The only two valid tokens that can
> follow that keyword are [ and {.

Ah, I saw the cp_parser_expression call in 
cp_parser_transaction_expression and didn't notice that we only get 
there with a '('.  Speaking of which, that function's comment doesn't 
match the code:

> +   transaction-expression:
> +     __transaction_atomic txn-exception-spec[opt] compound-statement
> +     __transaction_relaxed txn-exception-spec[opt] compound-statement

Also, in

> +   function-definition:
> +     decl-specifier-seq [opt] declarator function-atomic-block

function-atomic-block should be function-transaction-block, right?

Jason

Patch

Index: gcc/cp/class.c
===================================================================
--- gcc/cp/class.c	(.../trunk)	(revision 180744)
+++ gcc/cp/class.c	(.../branches/transactional-memory)	(revision 180773)
@@ -1227,13 +1227,12 @@  check_bases (tree t,
  	     int* no_const_asn_ref_p)
  {
    int i;
-  int seen_non_virtual_nearly_empty_base_p;
+  bool seen_non_virtual_nearly_empty_base_p = 0;
+  int seen_tm_mask = 0;
    tree base_binfo;
    tree binfo;
    tree field = NULL_TREE;

-  seen_non_virtual_nearly_empty_base_p = 0;
-
    if (!CLASSTYPE_NON_STD_LAYOUT (t))
      for (field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
        if (TREE_CODE (field) == FIELD_DECL)
@@ -1338,6 +1337,23 @@  check_bases (tree t,
  		  break;
  		}
  	}
+
+      /* Don't bother collecting tm attributes if transactional memory
+	 support is not enabled.  */
+      if (flag_tm)
+	{
+	  tree tm_attr = find_tm_attribute (TYPE_ATTRIBUTES (basetype));
+	  if (tm_attr)
+	    seen_tm_mask |= tm_attr_to_mask (tm_attr);
+	}
+    }
+
+  /* If one of the base classes had TM attributes, and the current class
+     doesn't define its own, then the current class inherits one.  */
+  if (seen_tm_mask && !find_tm_attribute (TYPE_ATTRIBUTES (t)))
+    {
+      tree tm_attr = tm_mask_to_attr (seen_tm_mask & -seen_tm_mask);
+      TYPE_ATTRIBUTES (t) = tree_cons (tm_attr, NULL, TYPE_ATTRIBUTES (t));
      }
  }

@@ -4252,6 +4268,137 @@  clone_constructors_and_destructors (tree
      clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/1);
  }

+/* Subroutine of set_one_vmethod_tm_attributes.  Search base classes
+   of TYPE for virtual functions which FNDECL overrides.  Return a
+   mask of the tm attributes found therein.  */
+
+static int
+look_for_tm_attr_overrides (tree type, tree fndecl)
+{
+  tree binfo = TYPE_BINFO (type);
+  tree base_binfo;
+  int ix, found = 0;
+
+  for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ++ix)
+    {
+      tree o, basetype = BINFO_TYPE (base_binfo);
+
+      if (!TYPE_POLYMORPHIC_P (basetype))
+	continue;
+
+      o = look_for_overrides_here (basetype, fndecl);
+      if (o)
+	found |= tm_attr_to_mask (find_tm_attribute
+				  (TYPE_ATTRIBUTES (TREE_TYPE (o))));
+      else
+	found |= look_for_tm_attr_overrides (basetype, fndecl);
+    }
+
+  return found;
+}
+
+/* Subroutine of set_method_tm_attributes.  Handle the checks and
+   inheritance for one virtual method FNDECL.  */
+
+static void
+set_one_vmethod_tm_attributes (tree type, tree fndecl)
+{
+  tree tm_attr;
+  int found, have;
+
+  found = look_for_tm_attr_overrides (type, fndecl);
+
+  /* If FNDECL doesn't actually override anything (i.e. T is the
+     class that first declares FNDECL virtual), then we're done.  */
+  if (found == 0)
+    return;
+
+  tm_attr = find_tm_attribute (TYPE_ATTRIBUTES (TREE_TYPE (fndecl)));
+  have = tm_attr_to_mask (tm_attr);
+
+  /* Intel STM Language Extension 3.0, Section 4.2 table 4:
+     tm_pure must match exactly, otherwise no weakening of
+     tm_safe > tm_callable > nothing.  */
+  /* ??? The tm_pure attribute didn't make the transition to the
+     multivendor language spec.  */
+  if (have == TM_ATTR_PURE)
+    {
+      if (found != TM_ATTR_PURE)
+	{
+	  found &= -found;
+	  goto err_override;
+	}
+    }
+  /* If the overridden function is tm_pure, then FNDECL must be.  */
+  else if (found == TM_ATTR_PURE && tm_attr)
+    goto err_override;
+  /* Look for base class combinations that cannot be satisfied.  */
+  else if (found != TM_ATTR_PURE && (found & TM_ATTR_PURE))
+    {
+      found &= ~TM_ATTR_PURE;
+      found &= -found;
+      error_at (DECL_SOURCE_LOCATION (fndecl),
+		"method overrides both %<transaction_pure%> and %qE methods",
+		tm_mask_to_attr (found));
+    }
+  /* If FNDECL did not declare an attribute, then inherit the most
+     restrictive one.  */
+  else if (tm_attr == NULL)
+    {
+      apply_tm_attr (fndecl, tm_mask_to_attr (found & -found));
+    }
+  /* Otherwise validate that we're not weaker than a function
+     that is being overridden.  */
+  else
+    {
+      found &= -found;
+      if (found <= TM_ATTR_CALLABLE && have > found)
+	goto err_override;
+    }
+  return;
+
+ err_override:
+  error_at (DECL_SOURCE_LOCATION (fndecl),
+	    "method declared %qE overriding %qE method",
+	    tm_attr, tm_mask_to_attr (found));
+}
+
+/* For each of the methods in T, propagate a class-level tm attribute.  */
+
+static void
+set_method_tm_attributes (tree t)
+{
+  tree class_tm_attr, fndecl;
+
+  /* Don't bother collecting tm attributes if transactional memory
+     support is not enabled.  */
+  if (!flag_tm)
+    return;
+
+  /* Process virtual methods first, as they inherit directly from the
+     base virtual function and also require validation of new 
attributes.  */
+  if (TYPE_CONTAINS_VPTR_P (t))
+    {
+      tree vchain;
+      for (vchain = BINFO_VIRTUALS (TYPE_BINFO (t)); vchain;
+	   vchain = TREE_CHAIN (vchain))
+	set_one_vmethod_tm_attributes (t, BV_FN (vchain));
+    }
+
+  /* If the class doesn't have an attribute, nothing more to do.  */
+  class_tm_attr = find_tm_attribute (TYPE_ATTRIBUTES (t));
+  if (class_tm_attr == NULL)
+    return;
+
+  /* Any method that does not yet have a tm attribute inherits
+     the one from the class.  */
+  for (fndecl = TYPE_METHODS (t); fndecl; fndecl = TREE_CHAIN (fndecl))
+    {
+      if (!find_tm_attribute (TYPE_ATTRIBUTES (TREE_TYPE (fndecl))))
+	apply_tm_attr (fndecl, class_tm_attr);
+    }
+}
+
  /* Returns true iff class T has a user-defined constructor other than
     the default constructor.  */

@@ -5835,6 +5982,7 @@  finish_struct_1 (tree t)
      }

    finish_struct_bits (t);
+  set_method_tm_attributes (t);

    /* Complete the rtl for any static member objects of the type we're
       working on.  */
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c	(.../trunk)	(revision 180744)
+++ gcc/cp/decl.c	(.../branches/transactional-memory)	(revision 180773)
@@ -4001,6 +4001,8 @@  push_cp_library_fn (enum tree_code opera
  				 operator_code,
  				 type);
    pushdecl (fn);
+  if (flag_tm)
+    apply_tm_attr (fn, get_identifier ("transaction_safe"));
    return fn;
  }

Index: gcc/cp/except.c
===================================================================
--- gcc/cp/except.c	(.../trunk)	(revision 180744)
+++ gcc/cp/except.c	(.../branches/transactional-memory)	(revision 180773)
@@ -173,6 +173,9 @@  do_get_exception_ptr (void)
      {
        /* Declare void* __cxa_get_exception_ptr (void *) throw().  */
        fn = declare_nothrow_library_fn (fn, ptr_type_node, ptr_type_node);
+
+      if (flag_tm)
+	apply_tm_attr (fn, get_identifier ("transaction_pure"));
      }

    return cp_build_function_call_nary (fn, tf_warning_or_error,
@@ -192,6 +195,17 @@  do_begin_catch (void)
      {
        /* Declare void* __cxa_begin_catch (void *) throw().  */
        fn = declare_nothrow_library_fn (fn, ptr_type_node, ptr_type_node);
+
+      /* Create its transactional-memory equivalent.  */
+      if (flag_tm)
+	{
+	  tree fn2 = get_identifier ("_ITM_cxa_begin_catch");
+	  if (!get_global_value_if_present (fn2, &fn2))
+	    fn2 = declare_nothrow_library_fn (fn2, ptr_type_node,
+					      ptr_type_node);
+	  apply_tm_attr (fn2, get_identifier ("transaction_pure"));
+	  record_tm_replacement (fn, fn2);
+	}
      }

    return cp_build_function_call_nary (fn, tf_warning_or_error,
@@ -231,6 +245,19 @@  do_end_catch (tree type)
        fn = push_void_library_fn (fn, void_list_node);
        /* This can throw if the destructor for the exception throws.  */
        TREE_NOTHROW (fn) = 0;
+
+      /* Create its transactional-memory equivalent.  */
+      if (flag_tm)
+	{
+	  tree fn2 = get_identifier ("_ITM_cxa_end_catch");
+	  if (!get_global_value_if_present (fn2, &fn2))
+	    {
+	      fn2 = push_void_library_fn (fn2, void_list_node);
+	      TREE_NOTHROW (fn2) = 0;
+	    }
+	  apply_tm_attr (fn2, get_identifier ("transaction_pure"));
+	  record_tm_replacement (fn, fn2);
+	}
      }

    cleanup = cp_build_function_call_vec (fn, NULL, tf_warning_or_error);
@@ -581,6 +608,16 @@  do_allocate_exception (tree type)
      {
        /* Declare void *__cxa_allocate_exception(size_t) throw().  */
        fn = declare_nothrow_library_fn (fn, ptr_type_node, size_type_node);
+
+      if (flag_tm)
+	{
+	  tree fn2 = get_identifier ("_ITM_cxa_allocate_exception");
+	  if (!get_global_value_if_present (fn2, &fn2))
+	    fn2 = declare_nothrow_library_fn (fn2, ptr_type_node,
+					      size_type_node);
+	  apply_tm_attr (fn2, get_identifier ("transaction_pure"));
+	  record_tm_replacement (fn, fn2);
+	}
      }

    return cp_build_function_call_nary (fn, tf_warning_or_error,
@@ -712,6 +749,15 @@  build_throw (tree exp)
  					  ptr_type_node, ptr_type_node,
  					  cleanup_type, NULL_TREE);
  	  fn = push_throw_library_fn (fn, tmp);
+
+	  if (flag_tm)
+	    {
+	      tree fn2 = get_identifier ("_ITM_cxa_throw");
+	      if (!get_global_value_if_present (fn2, &fn2))
+		fn2 = push_throw_library_fn (fn2, tmp);
+	      apply_tm_attr (fn2, get_identifier ("transaction_pure"));
+	      record_tm_replacement (fn, fn2);
+	    }
  	}

        /* [except.throw]
@@ -831,6 +877,9 @@  build_throw (tree exp)
  	    (fn, build_function_type_list (void_type_node, NULL_TREE));
  	}

+      if (flag_tm)
+	apply_tm_attr (fn, get_identifier ("transaction_pure"));
+
        /* ??? Indicate that this function call allows exceptions of the 
type
  	 of the enclosing catch block (if known).  */
        exp = cp_build_function_call_vec (fn, NULL, tf_warning_or_error);
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c	(.../trunk)	(revision 180744)
+++ gcc/cp/pt.c	(.../branches/transactional-memory)	(revision 180773)
@@ -12952,6 +12952,18 @@  tsubst_expr (tree t, tree args, tsubst_f
  	}
        break;

+    case TRANSACTION_EXPR:
+      {
+        int flags = 0;
+        flags |= (TRANSACTION_EXPR_OUTER (t) ? TM_STMT_ATTR_OUTER : 0);
+        flags |= (TRANSACTION_EXPR_RELAXED (t) ? TM_STMT_ATTR_RELAXED : 0);
+
+        stmt = begin_transaction_stmt (input_location, NULL, flags);
+        tmp = RECUR (TRANSACTION_EXPR_BODY (t));
+        finish_transaction_stmt (stmt, NULL, flags);
+      }
+      break;
+
      case EXPR_PACK_EXPANSION:
        error ("invalid use of pack expansion expression");
        return error_mark_node;
Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c	(.../trunk)	(revision 180744)
+++ gcc/cp/semantics.c	(.../branches/transactional-memory)	(revision 180773)
@@ -4965,6 +4965,50 @@  finish_omp_taskyield (void)
    finish_expr_stmt (stmt);
  }
  
+/* Begin a __transaction_atomic or __transaction_relaxed statement.
+   If PCOMPOUND is non-null, this is for a function-transaction-block, 
and we
+   should create an extra compound stmt.  */
+
+tree
+begin_transaction_stmt (location_t loc, tree *pcompound, int flags)
+{
+  tree r;
+
+  if (pcompound)
+    *pcompound = begin_compound_stmt (0);
+
+  r = build_stmt (loc, TRANSACTION_EXPR, NULL_TREE);
+
+  /* Only add the statement to the function if support enabled.  */
+  if (flag_tm)
+    add_stmt (r);
+  else
+    error_at (loc, ((flags & TM_STMT_ATTR_RELAXED) != 0 ?
+        "%<__transaction_relaxed%> without transactional memory "
+	      "support enabled"
+        : "%<__transaction_atomic%> without transactional memory "
+	      "support enabled"));
+
+  TRANSACTION_EXPR_BODY (r) = push_stmt_list ();
+  return r;
+}
+
+/* End a __transaction_atomic or __transaction_relaxed statement.
+   If COMPOUND_STMT is non-null, this is for a function-transaction-block,
+   and we should end the compound.  */
+
+void
+finish_transaction_stmt (tree stmt, tree compound_stmt, int flags)
+{
+  TRANSACTION_EXPR_BODY (stmt) = pop_stmt_list (TRANSACTION_EXPR_BODY 
(stmt));
+  TRANSACTION_EXPR_OUTER (stmt) = (flags & TM_STMT_ATTR_OUTER) != 0;
+  TRANSACTION_EXPR_RELAXED (stmt) = (flags & TM_STMT_ATTR_RELAXED) != 0;
+
+  if (compound_stmt)
+    finish_compound_stmt (compound_stmt);
+  finish_stmt ();
+}
+
  void
  init_cp_semantics (void)
  {
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(.../trunk)	(revision 180744)
+++ gcc/cp/parser.c	(.../branches/transactional-memory)	(revision 180773)
@@ -172,6 +172,10 @@  typedef enum required_token {
    RT_JUMP, /* jump-statement */
    RT_CLASS_KEY, /* class-key */
    RT_CLASS_TYPENAME_TEMPLATE /* class, typename, or template */
+
+  , RT_TRANSACTION_ATOMIC, /* __transaction_atomic */
+  RT_TRANSACTION_RELAXED, /* __transaction_relaxed */
+  RT_TRANSACTION_CANCEL /* __transaction_cancel */
  } required_token;

  /* Prototypes.  */
@@ -2104,6 +2108,17 @@  static bool cp_parser_extension_opt
  static void cp_parser_label_declaration
    (cp_parser *);

+/* Transactional Memory Extensions */
+
+static tree cp_parser_transaction
+  (cp_parser *, enum rid);
+static tree cp_parser_transaction_expression
+  (cp_parser *, enum rid);
+static bool cp_parser_function_transaction
+  (cp_parser *, enum rid);
+static tree cp_parser_transaction_cancel
+  (cp_parser *);
+
  enum pragma_context { pragma_external, pragma_stmt, pragma_compound };
  static bool cp_parser_pragma
    (cp_parser *, enum pragma_context);
@@ -6362,6 +6377,10 @@  cp_parser_unary_expression (cp_parser *p
  	  }
  	  break;

+	case RID_TRANSACTION_ATOMIC:
+	case RID_TRANSACTION_RELAXED:
+	  return cp_parser_transaction_expression (parser, keyword);
+
  	case RID_NOEXCEPT:
  	  {
  	    tree expr;
@@ -8496,6 +8515,11 @@  cp_parser_lambda_body (cp_parser* parser
       declaration-statement
       try-block

+  TM Extension:
+
+   statement:
+     atomic-statement
+
    IN_COMPOUND is true when the statement is nested inside a
    cp_parser_compound_statement; this matters for certain pragmas.

@@ -8572,6 +8596,14 @@  cp_parser_statement (cp_parser* parser,
  	  cp_parser_declaration_statement (parser);
  	  return;
  	
+	case RID_TRANSACTION_ATOMIC:
+	case RID_TRANSACTION_RELAXED:
+	  statement = cp_parser_transaction (parser, keyword);
+	  break;
+	case RID_TRANSACTION_CANCEL:
+	  statement = cp_parser_transaction_cancel (parser);
+	  break;
+
  	default:
  	  /* It might be a keyword like `int' that can start a
  	     declaration-statement.  */
@@ -15082,6 +15114,11 @@  cp_parser_asm_definition (cp_parser* par
     function-definition:
       __extension__ function-definition

+   TM Extension:
+
+   function-definition:
+     decl-specifier-seq [opt] declarator function-atomic-block
+
     The DECL_SPECIFIERS apply to this declarator.  Returns a
     representation of the entity declared.  If MEMBER_P is TRUE, then
     this declarator appears in a class scope.  The new DECL created by
@@ -20780,12 +20817,19 @@  cp_parser_function_definition_after_decl

    start_lambda_scope (current_function_decl);

-  /* If the next token is `try', then we are looking at a
-     function-try-block.  */
-  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY))
+  /* If the next token is `try', `__transaction_atomic', or
+     `__transaction_relaxed`, then we are looking at either 
function-try-block
+     or function-transaction-block.  Note that all of these include the
+     function-body.  */
+  if (cp_lexer_next_token_is_keyword (parser->lexer, 
RID_TRANSACTION_ATOMIC))
+    ctor_initializer_p = cp_parser_function_transaction (parser,
+        RID_TRANSACTION_ATOMIC);
+  else if (cp_lexer_next_token_is_keyword (parser->lexer,
+      RID_TRANSACTION_RELAXED))
+    ctor_initializer_p = cp_parser_function_transaction (parser,
+        RID_TRANSACTION_RELAXED);
+  else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY))
      ctor_initializer_p = cp_parser_function_try_block (parser);
-  /* A function-try-block includes the function-body, so we only do
-     this next part if we're not processing a function-try-block.  */
    else
      ctor_initializer_p
        = cp_parser_ctor_initializer_opt_and_function_body (parser);
@@ -21939,6 +21983,12 @@  cp_parser_required_error (cp_parser *par
        case RT_AT_THROW:
  	cp_parser_error (parser, "expected %<@throw%>");
  	return;
+      case RT_TRANSACTION_ATOMIC:
+	cp_parser_error (parser, "expected %<__transaction_atomic%>");
+	return;
+      case RT_TRANSACTION_RELAXED:
+	cp_parser_error (parser, "expected %<__transaction_relaxed%>");
+	return;
        default:
  	break;
      }
@@ -22169,6 +22219,10 @@  cp_parser_token_starts_function_definiti
  	  || token->type == CPP_COLON
  	  /* A function-try-block begins with `try'.  */
  	  || token->keyword == RID_TRY
+	  /* A function-transaction-block begins with `__transaction_atomic'
+	     or `__transaction_relaxed'.  */
+	  || token->keyword == RID_TRANSACTION_ATOMIC
+	  || token->keyword == RID_TRANSACTION_RELAXED
  	  /* The named return value extension begins with `return'.  */
  	  || token->keyword == RID_RETURN);
  }
@@ -26489,6 +26543,270 @@  cp_parser_omp_construct (cp_parser *pars
      SET_EXPR_LOCATION (stmt, pragma_tok->location);
  }
  
+/* Transactional Memory parsing routines.  */
+
+/* Parse a transaction attribute.
+
+   txn-attribute:
+	attribute
+	[ [ identifier ] ]
+
+   ??? Simplify this when C++0x bracket attributes are
+   implemented properly.  */
+
+static tree
+cp_parser_txn_attribute_opt (cp_parser *parser)
+{
+  cp_token *token;
+  tree attr_name, attr = NULL;
+
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE))
+    return cp_parser_attributes_opt (parser);
+
+  if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_SQUARE))
+    return NULL_TREE;
+  cp_lexer_consume_token (parser->lexer);
+  if (!cp_parser_require (parser, CPP_OPEN_SQUARE, RT_OPEN_SQUARE))
+    goto error1;
+
+  token = cp_lexer_peek_token (parser->lexer);
+  if (token->type == CPP_NAME || token->type == CPP_KEYWORD)
+    {
+      token = cp_lexer_consume_token (parser->lexer);
+
+      attr_name = (token->type == CPP_KEYWORD
+		   /* For keywords, use the canonical spelling,
+		      not the parsed identifier.  */
+		   ? ridpointers[(int) token->keyword]
+		   : token->u.value);
+      attr = build_tree_list (attr_name, NULL_TREE);
+    }
+  else
+    cp_parser_error (parser, "expected identifier");
+
+  cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
+ error1:
+  cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
+  return attr;
+}
+
+/* Parse a __transaction_atomic or __transaction_relaxed statement.
+
+   transaction-statement:
+     __transaction_atomic txn-attribute[opt] txn-exception-spec[opt]
+       compound-statement
+     __transaction_relaxed txn-exception-spec[opt] compound-statement
+
+   ??? The exception specification is not yet implemented.
+*/
+
+static tree
+cp_parser_transaction (cp_parser *parser, enum rid keyword)
+{
+  unsigned char old_in = parser->in_transaction;
+  unsigned char this_in = 1, new_in;
+  cp_token *token;
+  tree stmt, attrs;
+
+  gcc_assert (keyword == RID_TRANSACTION_ATOMIC
+      || keyword == RID_TRANSACTION_RELAXED);
+  token = cp_parser_require_keyword (parser, keyword,
+      (keyword == RID_TRANSACTION_ATOMIC ? RT_TRANSACTION_ATOMIC
+          : RT_TRANSACTION_RELAXED));
+  gcc_assert (token != NULL);
+
+  if (keyword == RID_TRANSACTION_RELAXED)
+    this_in |= TM_STMT_ATTR_RELAXED;
+  else
+    {
+      attrs = cp_parser_txn_attribute_opt (parser);
+      if (attrs)
+        this_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER);
+    }
+
+  /* Keep track if we're in the lexical scope of an outer transaction.  */
+  new_in = this_in | (old_in & TM_STMT_ATTR_OUTER);
+
+  stmt = begin_transaction_stmt (token->location, NULL, this_in);
+
+  parser->in_transaction = new_in;
+  cp_parser_compound_statement (parser, NULL, false, false);
+  parser->in_transaction = old_in;
+
+  finish_transaction_stmt (stmt, NULL, this_in);
+
+  return stmt;
+}
+
+/* Parse a __transaction_atomic or __transaction_relaxed expression.
+
+   transaction-expression:
+     __transaction_atomic txn-exception-spec[opt] compound-statement
+     __transaction_relaxed txn-exception-spec[opt] compound-statement
+
+   ??? The exception specification is not yet implemented.
+*/
+
+static tree
+cp_parser_transaction_expression (cp_parser *parser, enum rid keyword)
+{
+  unsigned char old_in = parser->in_transaction;
+  unsigned char this_in = 1;
+  cp_token *token;
+  tree ret, attrs;
+
+  gcc_assert (keyword == RID_TRANSACTION_ATOMIC
+      || keyword == RID_TRANSACTION_RELAXED);
+  token = cp_parser_require_keyword (parser, keyword,
+      (keyword == RID_TRANSACTION_ATOMIC ? RT_TRANSACTION_ATOMIC
+          : RT_TRANSACTION_RELAXED));
+  gcc_assert (token != NULL);
+
+  if (keyword == RID_TRANSACTION_RELAXED)
+    this_in |= TM_STMT_ATTR_RELAXED;
+  else
+    {
+      attrs = cp_parser_txn_attribute_opt (parser);
+      if (attrs)
+        this_in |= parse_tm_stmt_attr (attrs, 0);
+    }
+
+  parser->in_transaction = this_in;
+  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+    {
+      tree expr = cp_parser_expression (parser, /*cast_p=*/false, NULL);
+      ret = build1 (TRANSACTION_EXPR, TREE_TYPE (expr), expr);
+      if (this_in & TM_STMT_ATTR_RELAXED)
+	TRANSACTION_EXPR_RELAXED (ret) = 1;
+      SET_EXPR_LOCATION (ret, token->location);
+    }
+  else
+    {
+      cp_parser_error (parser, "expected %<(%>");
+      ret = error_mark_node;
+    }
+  parser->in_transaction = old_in;
+
+  return ret;
+}
+
+/* Parse a function-transaction-block.
+
+   function-transaction-block:
+     __transaction_atomic txn-attribute[opt] ctor-initializer[opt]
+         function-body
+     __transaction_atomic txn-attribute[opt] function-try-block
+     __transaction_relaxed ctor-initializer[opt] function-body
+     __transaction_relaxed function-try-block
+*/
+
+static bool
+cp_parser_function_transaction (cp_parser *parser, enum rid keyword)
+{
+  unsigned char old_in = parser->in_transaction;
+  unsigned char new_in = 1;
+  tree compound_stmt, stmt, attrs;
+  bool ctor_initializer_p;
+  cp_token *token;
+
+  gcc_assert (keyword == RID_TRANSACTION_ATOMIC
+      || keyword == RID_TRANSACTION_RELAXED);
+  token = cp_parser_require_keyword (parser, keyword,
+      (keyword == RID_TRANSACTION_ATOMIC ? RT_TRANSACTION_ATOMIC
+          : RT_TRANSACTION_RELAXED));
+  gcc_assert (token != NULL);
+
+  if (keyword == RID_TRANSACTION_RELAXED)
+    new_in |= TM_STMT_ATTR_RELAXED;
+  else
+    {
+      attrs = cp_parser_txn_attribute_opt (parser);
+      if (attrs)
+        new_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER);
+    }
+
+  stmt = begin_transaction_stmt (token->location, &compound_stmt, new_in);
+
+  parser->in_transaction = new_in;
+
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY))
+    ctor_initializer_p = cp_parser_function_try_block (parser);
+  else
+    ctor_initializer_p
+      = cp_parser_ctor_initializer_opt_and_function_body (parser);
+
+  parser->in_transaction = old_in;
+
+  finish_transaction_stmt (stmt, compound_stmt, new_in);
+
+  return ctor_initializer_p;
+}
+
+/* Parse a __transaction_cancel statement.
+
+   cancel-statement:
+     __transaction_cancel txn-attribute[opt] ;
+     __transaction_cancel txn-attribute[opt] throw-expression ;
+
+   ??? Cancel and throw is not yet implemented.  */
+
+static tree
+cp_parser_transaction_cancel (cp_parser *parser)
+{
+  cp_token *token;
+  bool is_outer = false;
+  tree stmt, attrs;
+
+  token = cp_parser_require_keyword (parser, RID_TRANSACTION_CANCEL,
+				     RT_TRANSACTION_CANCEL);
+  gcc_assert (token != NULL);
+
+  attrs = cp_parser_txn_attribute_opt (parser);
+  if (attrs)
+    is_outer = (parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER) != 0);
+
+  /* ??? Parse cancel-and-throw here.  */
+
+  cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
+
+  if (!flag_tm)
+    {
+      error_at (token->location, "%<__transaction_cancel%> without "
+		"transactional memory support enabled");
+      return error_mark_node;
+    }
+  else if (parser->in_transaction & TM_STMT_ATTR_RELAXED)
+    {
+      error_at (token->location, "%<__transaction_cancel%> within a "
+		"%<__transaction_relaxed%>");
+      return error_mark_node;
+    }
+  else if (is_outer)
+    {
+      if ((parser->in_transaction & TM_STMT_ATTR_OUTER) == 0
+	  && !is_tm_may_cancel_outer (current_function_decl))
+	{
+	  error_at (token->location, "outer %<__transaction_cancel%> not "
+		    "within outer %<__transaction_atomic%>");
+	  error_at (token->location,
+		    "  or a %<transaction_may_cancel_outer%> function");
+	  return error_mark_node;
+	}
+    }
+  else if (parser->in_transaction == 0)
+    {
+      error_at (token->location, "%<__transaction_cancel%> not within "
+		"%<__transaction_atomic%>");
+      return error_mark_node;
+    }
+
+  stmt = build_tm_abort_call (token->location, is_outer);
+  add_stmt (stmt);
+  finish_stmt ();
+
+  return stmt;
+}
+
  /* The parser.  */

  static GTY (()) cp_parser *the_parser;
Index: gcc/cp/parser.h
===================================================================
--- gcc/cp/parser.h	(.../trunk)	(revision 180744)
+++ gcc/cp/parser.h	(.../branches/transactional-memory)	(revision 180773)
@@ -329,6 +329,10 @@  typedef struct GTY(()) cp_parser {
       a local class.  */
    bool in_function_body;

+  /* Nonzero if we're processing a __transaction_atomic or
+     __transaction_relaxed statement.  */
+  unsigned char in_transaction;
+
    /* TRUE if we can auto-correct a colon to a scope operator.  */
    bool colon_corrects_to_scope_p;

Index: gcc/cp/call.c
===================================================================
--- gcc/cp/call.c	(.../trunk)	(revision 180744)
+++ gcc/cp/call.c	(.../branches/transactional-memory)	(revision 180773)
@@ -3826,6 +3826,9 @@  build_new_function_call (tree fn, VEC(tr
  	return error_mark_node;
      }

+  if (flag_tm)
+    tm_malloc_replacement (fn);
+
    /* If this function was found without using argument dependent
       lookup, then we want to ignore any undeclared friend
       functions.  */
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(.../trunk)	(revision 180744)
+++ gcc/cp/cp-tree.h	(.../branches/transactional-memory)	(revision 180773)
@@ -5525,6 +5525,8 @@  extern void finish_omp_atomic			(enum tr
  extern void finish_omp_barrier			(void);
  extern void finish_omp_flush			(void);
  extern void finish_omp_taskwait			(void);
+extern tree begin_transaction_stmt		(location_t, tree *, int);
+extern void finish_transaction_stmt		(tree, tree, int);
  extern void finish_omp_taskyield		(void);
  extern bool cxx_omp_create_clause_info		(tree, tree, bool, bool, bool);
  extern tree baselink_for_fns                    (tree);