diff mbox

Support noexcept-specifications for transaction statements and expressions.

Message ID 1321907584.12248.141.camel@triegel.csb
State New
Headers show

Commit Message

Torvald Riegel Nov. 21, 2011, 8:33 p.m. UTC
This revision of the patch is now complete and passes all the tests I
could come up with.  Compared to previous iterations, I added parsing of
noexcept without explicit true/false.  This makes
cp_parser_noexcept_specification_opt a bit more complex, but we can now
reuse it.
The other two patches I posted recently (fixing instantiations, handling
MUST_NOT_THROW_EXPR in voidify_wrapper_expr) are required for noexcept
support to work.

OK for trunk?
commit 0d82e90a50631296a67813605b7aeebd586064d6
Author: Torvald Riegel <triegel@redhat.com>
Date:   Tue Nov 15 15:00:48 2011 +0100

    Support noexcept-specifications for transaction statements and expressions.
    
    	gcc/
    	* tree.h (TRANSACTION_EXPR_NOEX): New.
    	* tree.def (TRANSACTION_EXPR): Add noexcept spec as 2nd operand.
    	* c-parser.c (c_parser_transaction_expression): Adapt to this.
    	* c-typeck.c (c_finish_transaction): Same.
    
    	gcc/cp/
    	* semantics.c (finish_transaction_stmt, build_transaction_expr):
    	Accept new noexcept parameter and handle it.
    	(begin_transaction_stmt): Adapt to additional noexcept operand.
    	* cp-tree.h (finish_transaction_stmt, build_transaction_expr): Adapt
    	declarations.
    	* parser.c (cp_parser_exception_specification_opt): Extract
    	noexcept-specification parsing to ...
    	(cp_parser_noexcept_specification_opt): ...here.  Allow for parsing
    	non-constexpr noexcept arguments.
    	(cp_parser_transaction, cp_parser_transaction_expression): Parse
    	and handle noexcept-specifications.
    	(cp_parser_function_transaction): Adapt to finish_transaction_stmt
    	change.
    	* pt.c (tsubst_expr): Handle noexcept specs when instantiating
    	transactions.
    
    	gcc/testsuite/
    	* g++.dg/tm/noexcept-1.C: New test.
    	* g++.dg/tm/noexcept-2.C: New test.
    	* g++.dg/tm/noexcept-3.C: New test.
    	* g++.dg/tm/noexcept-4.C: New test.
    	* g++.dg/tm/noexcept-5.C: New test.

Comments

Jason Merrill Nov. 21, 2011, 9:06 p.m. UTC | #1
At this point I think it'd be simpler to handle noexcept in a 
transaction-expression directly in cp_parser_transaction_expression.

Since TRANSACTION_EXPR_NOEX is only for the template representation, I'd 
rather not add it to the language-independent tree code.  Maybe 
introduce a C++ template-specific NOEXCEPT_REGION tree code?

Jason
Torvald Riegel Nov. 21, 2011, 9:27 p.m. UTC | #2
On Mon, 2011-11-21 at 16:06 -0500, Jason Merrill wrote:
> At this point I think it'd be simpler to handle noexcept in a 
> transaction-expression directly in cp_parser_transaction_expression.

And keep transaction statements as is, or change them as well?

> Since TRANSACTION_EXPR_NOEX is only for the template representation, I'd 
> rather not add it to the language-independent tree code.  Maybe 
> introduce a C++ template-specific NOEXCEPT_REGION tree code?

Hmm, I'm a bit confused because looking at the previous iterations of
this patch we said that it's best to keep the noexcept information
attached to the transactions.  What made you change your mind?  I don't
see any changes to language-independent code that didn't exist in the
previous iterations.

Torvald
Jason Merrill Nov. 21, 2011, 9:39 p.m. UTC | #3
On 11/21/2011 04:27 PM, Torvald Riegel wrote:
> On Mon, 2011-11-21 at 16:06 -0500, Jason Merrill wrote:
>> At this point I think it'd be simpler to handle noexcept in a
>> transaction-expression directly in cp_parser_transaction_expression.
>
> And keep transaction statements as is, or change them as well?

I don't have a strong opinion either way on statements, since they don't 
have to deal with the ambiguity issue.  Whichever seems more convenient 
to you.

>> Since TRANSACTION_EXPR_NOEX is only for the template representation, I'd
>> rather not add it to the language-independent tree code.  Maybe
>> introduce a C++ template-specific NOEXCEPT_REGION tree code?

> Hmm, I'm a bit confused because looking at the previous iterations of
> this patch we said that it's best to keep the noexcept information
> attached to the transactions.  What made you change your mind?  I don't
> see any changes to language-independent code that didn't exist in the
> previous iterations.

Right, this issue just didn't occur to me before, sorry.

Jason
diff mbox

Patch

diff --git a/gcc/c-parser.c b/gcc/c-parser.c
index b88b11f..e1ce35f 100644
--- a/gcc/c-parser.c
+++ b/gcc/c-parser.c
@@ -10703,7 +10703,8 @@  c_parser_transaction_expression (c_parser *parser, enum rid keyword)
     {
       tree expr = c_parser_expression (parser).value;
       ret.original_type = TREE_TYPE (expr);
-      ret.value = build1 (TRANSACTION_EXPR, ret.original_type, expr);
+      ret.value = build2 (TRANSACTION_EXPR, ret.original_type, expr,
+			  NULL_TREE);
       if (this_in & TM_STMT_ATTR_RELAXED)
 	TRANSACTION_EXPR_RELAXED (ret.value) = 1;
       SET_EXPR_LOCATION (ret.value, loc);
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index 4a134b0..f015ff6 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -10930,7 +10930,7 @@  c_finish_omp_clauses (tree clauses)
 tree
 c_finish_transaction (location_t loc, tree block, int flags)
 {
-  tree stmt = build_stmt (loc, TRANSACTION_EXPR, block);
+  tree stmt = build_stmt (loc, TRANSACTION_EXPR, block, NULL_TREE);
   if (flags & TM_STMT_ATTR_OUTER)
     TRANSACTION_EXPR_OUTER (stmt) = 1;
   if (flags & TM_STMT_ATTR_RELAXED)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 3f4f408..ba124cf 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5571,8 +5571,8 @@  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 tree build_transaction_expr		(location_t, tree, int);
+extern void finish_transaction_stmt		(tree, tree, int, tree);
+extern tree build_transaction_expr		(location_t, tree, int, tree);
 extern void finish_omp_taskyield		(void);
 extern bool cxx_omp_create_clause_info		(tree, tree, bool, bool, bool);
 extern tree baselink_for_fns                    (tree);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 4a2b2a9..dea59f1 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -19509,19 +19509,23 @@  cp_parser_base_specifier (cp_parser* parser)
 
 /* Exception handling [gram.exception] */
 
-/* Parse an (optional) exception-specification.
+/* Parse an (optional) noexcept-specification.
 
-   exception-specification:
-     throw ( type-id-list [opt] )
+   noexcept-specification:
+     noexcept ( constant-expression ) [opt]
 
-   Returns a TREE_LIST representing the exception-specification.  The
-   TREE_VALUE of each node is a type.  */
+   If no noexcept-specification is present, returns NULL_TREE.
+   Otherwise, if REQUIRE_CONSTEXPR is false, then either parse and return any
+   expression if parentheses follow noexcept, or return BOOLEAN_TRUE_NODE if
+   there are no parentheses.  CONSUMED_EXPR will be set accordingly.
+   Otherwise, returns a noexcept specification.  */
 
 static tree
-cp_parser_exception_specification_opt (cp_parser* parser)
+cp_parser_noexcept_specification_opt (cp_parser* parser,
+				      bool require_constexpr,
+				      bool* consumed_expr)
 {
   cp_token *token;
-  tree type_id_list;
   const char *saved_message;
 
   /* Peek at the next token.  */
@@ -19537,23 +19541,66 @@  cp_parser_exception_specification_opt (cp_parser* parser)
 	{
 	  cp_lexer_consume_token (parser->lexer);
 
-	  /* Types may not be defined in an exception-specification.  */
-	  saved_message = parser->type_definition_forbidden_message;
-	  parser->type_definition_forbidden_message
-	    = G_("types may not be defined in an exception-specification");
+	  if (require_constexpr)
+	    {
+	      /* Types may not be defined in an exception-specification.  */
+	      saved_message = parser->type_definition_forbidden_message;
+	      parser->type_definition_forbidden_message
+	      = G_("types may not be defined in an exception-specification");
 
-	  expr = cp_parser_constant_expression (parser, false, NULL);
+	      expr = cp_parser_constant_expression (parser, false, NULL);
 
-	  /* Restore the saved message.  */
-	  parser->type_definition_forbidden_message = saved_message;
+	      /* Restore the saved message.  */
+	      parser->type_definition_forbidden_message = saved_message;
+	    }
+	  else
+	    {
+	      expr = cp_parser_expression (parser, false, NULL);
+	      *consumed_expr = true;
+	    }
 
 	  cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
 	}
       else
-	expr = boolean_true_node;
+	{
+	  expr = boolean_true_node;
+	  if (!require_constexpr)
+	    *consumed_expr = false;
+	}
 
-      return build_noexcept_spec (expr, tf_warning_or_error);
+      /* We cannot build a noexcept-spec right away because this will check
+	 that expr is a constexpr.  */
+      if (require_constexpr)
+	return build_noexcept_spec (expr, tf_warning_or_error);
+      else
+	return expr;
     }
+  else
+    return NULL_TREE;
+}
+
+/* Parse an (optional) exception-specification.
+
+   exception-specification:
+     throw ( type-id-list [opt] )
+
+   Returns a TREE_LIST representing the exception-specification.  The
+   TREE_VALUE of each node is a type.  */
+
+static tree
+cp_parser_exception_specification_opt (cp_parser* parser)
+{
+  cp_token *token;
+  tree type_id_list;
+  const char *saved_message;
+
+  /* Peek at the next token.  */
+  token = cp_lexer_peek_token (parser->lexer);
+
+  /* Is it a noexcept-specification?  */
+  type_id_list = cp_parser_noexcept_specification_opt(parser, true, NULL);
+  if (type_id_list != NULL_TREE)
+    return type_id_list;
 
   /* If it's not `throw', then there's no exception-specification.  */
   if (!cp_parser_is_keyword (token, RID_THROW))
@@ -26778,11 +26825,9 @@  cp_parser_txn_attribute_opt (cp_parser *parser)
 /* Parse a __transaction_atomic or __transaction_relaxed statement.
 
    transaction-statement:
-     __transaction_atomic txn-attribute[opt] txn-exception-spec[opt]
+     __transaction_atomic txn-attribute[opt] txn-noexcept-spec[opt]
        compound-statement
-     __transaction_relaxed txn-exception-spec[opt] compound-statement
-
-   ??? The exception specification is not yet implemented.
+     __transaction_relaxed txn-noexcept-spec[opt] compound-statement
 */
 
 static tree
@@ -26791,7 +26836,7 @@  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;
+  tree stmt, attrs, noex;
 
   gcc_assert (keyword == RID_TRANSACTION_ATOMIC
       || keyword == RID_TRANSACTION_RELAXED);
@@ -26809,6 +26854,9 @@  cp_parser_transaction (cp_parser *parser, enum rid keyword)
 	this_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER);
     }
 
+  /* Parse a noexcept specification.  */
+  noex = cp_parser_noexcept_specification_opt(parser, true, NULL);
+
   /* Keep track if we're in the lexical scope of an outer transaction.  */
   new_in = this_in | (old_in & TM_STMT_ATTR_OUTER);
 
@@ -26818,7 +26866,7 @@  cp_parser_transaction (cp_parser *parser, enum rid keyword)
   cp_parser_compound_statement (parser, NULL, false, false);
   parser->in_transaction = old_in;
 
-  finish_transaction_stmt (stmt, NULL, this_in);
+  finish_transaction_stmt (stmt, NULL, this_in, noex);
 
   return stmt;
 }
@@ -26826,10 +26874,8 @@  cp_parser_transaction (cp_parser *parser, enum rid keyword)
 /* Parse a __transaction_atomic or __transaction_relaxed expression.
 
    transaction-expression:
-     __transaction_atomic txn-exception-spec[opt] ( expression )
-     __transaction_relaxed txn-exception-spec[opt] ( expression )
-
-   ??? The exception specification is not yet implemented.
+     __transaction_atomic txn-noexcept-spec[opt] ( expression )
+     __transaction_relaxed txn-noexcept-spec[opt] ( expression )
 */
 
 static tree
@@ -26838,7 +26884,8 @@  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 expr;
+  tree expr, noex;
+  bool noex_expr;
 
   gcc_assert (keyword == RID_TRANSACTION_ATOMIC
       || keyword == RID_TRANSACTION_RELAXED);
@@ -26858,14 +26905,39 @@  cp_parser_transaction_expression (cp_parser *parser, enum rid keyword)
   if (keyword == RID_TRANSACTION_RELAXED)
     this_in |= TM_STMT_ATTR_RELAXED;
 
+  /* Set this early.  This might mean that we allow transaction_cancel in
+     an expression that we find out later actually has to be a constexpr.
+     However, we expect that cxx_constant_value will be able to deal with
+     this; also, if the noexcept has no constexpr, then what we parse next
+     really is a transaction's body.  */
   parser->in_transaction = this_in;
-  cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
 
-  expr = cp_parser_expression (parser, /*cast_p=*/false, NULL);
-  finish_parenthesized_expr (expr);
-  expr = build_transaction_expr (token->location, expr, this_in);
+  /* Parse a noexcept specification.  */
+  noex = cp_parser_noexcept_specification_opt(parser, false, &noex_expr);
 
-  cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
+  if (!noex || !noex_expr
+      || cp_lexer_peek_token (parser->lexer)->type == CPP_OPEN_PAREN)
+    {
+      cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
+
+      expr = cp_parser_expression (parser, /*cast_p=*/false, NULL);
+      finish_parenthesized_expr (expr);
+
+      cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
+    }
+  else
+    {
+      /* The only expression that is available got parsed for the noexcept
+         already.  noexcept is true then.  */
+      expr = noex;
+      noex = boolean_true_node;
+    }
+
+  /* Now we know which expression is supposed to be a constexpr.  */
+  if (noex && noex != error_mark_node)
+    noex = build_noexcept_spec (noex, tf_warning_or_error);
+
+  expr = build_transaction_expr (token->location, expr, this_in, noex);
   parser->in_transaction = old_in;
 
   if (cp_parser_non_integral_constant_expression (parser, NIC_TRANSACTION))
@@ -26921,7 +26993,7 @@  cp_parser_function_transaction (cp_parser *parser, enum rid keyword)
 
   parser->in_transaction = old_in;
 
-  finish_transaction_stmt (stmt, compound_stmt, new_in);
+  finish_transaction_stmt (stmt, compound_stmt, new_in, NULL_TREE);
 
   return ctor_initializer_p;
 }
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index f817b6f..a5b5d48 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13204,22 +13204,41 @@  tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
     case TRANSACTION_EXPR:
       {
 	int flags = 0;
+	tree noex;
 	flags |= (TRANSACTION_EXPR_OUTER (t) ? TM_STMT_ATTR_OUTER : 0);
 	flags |= (TRANSACTION_EXPR_RELAXED (t) ? TM_STMT_ATTR_RELAXED : 0);
+	noex = TRANSACTION_EXPR_NOEX (t);
+	if (noex)
+	  {
+	    if (noex != noexcept_false_spec && noex != noexcept_true_spec
+		&& noex != error_mark_node)
+	      {
+		/* Finish processing the noexcept expression.  */
+		noex = tsubst_copy_and_build (noex, args, complain, in_decl,
+					      /*function_p=*/false,
+					      /*integral_const_expr_p=*/true);
+		noex = build_noexcept_spec (TREE_PURPOSE (noex),
+					    tf_warning_or_error);
+	      }
+	    gcc_assert (noex == noexcept_false_spec
+			|| noex == noexcept_true_spec
+			|| noex == error_mark_node);
+	    TRANSACTION_EXPR_NOEX (t) = NULL_TREE;
+	  }
 
-        if (TRANSACTION_EXPR_IS_STMT (t))
-          {
-            stmt = begin_transaction_stmt (input_location, NULL, flags);
-            RECUR (TRANSACTION_EXPR_BODY (t));
-            finish_transaction_stmt (stmt, NULL, flags);
-          }
-        else
-          {
-            stmt = build_transaction_expr (EXPR_LOCATION (t),
+	if (TRANSACTION_EXPR_IS_STMT (t))
+	  {
+	    stmt = begin_transaction_stmt (input_location, NULL, flags);
+	    RECUR (TRANSACTION_EXPR_BODY (t));
+	    finish_transaction_stmt (stmt, NULL, flags, noex);
+	  }
+	else
+	  {
+	    stmt = build_transaction_expr (EXPR_LOCATION (t),
 					   RECUR (TRANSACTION_EXPR_BODY (t)),
-					   flags);
-            return stmt;
-          }
+					   flags, noex);
+	    return stmt;
+	  }
       }
       break;
 
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index fe685fa..a49437d 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5000,7 +5000,7 @@  begin_transaction_stmt (location_t loc, tree *pcompound, int flags)
   if (pcompound)
     *pcompound = begin_compound_stmt (0);
 
-  r = build_stmt (loc, TRANSACTION_EXPR, NULL_TREE);
+  r = build_stmt (loc, TRANSACTION_EXPR, NULL_TREE, NULL_TREE);
 
   /* Only add the statement to the function if support enabled.  */
   if (flag_tm)
@@ -5018,28 +5018,57 @@  begin_transaction_stmt (location_t loc, tree *pcompound, int flags)
 
 /* 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.  */
+   and we should end the compound.  If NOEX is NOEXCEPT_TRUE_SPEC, we wrap
+   the body in a MUST_NOT_THROW_EXPR.  */
 
 void
-finish_transaction_stmt (tree stmt, tree compound_stmt, int flags)
+finish_transaction_stmt (tree stmt, tree compound_stmt, int flags, tree noex)
 {
   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;
   TRANSACTION_EXPR_IS_STMT (stmt) = 1;
 
+  /* noexcept specifications are not allowed for function transactions.  */
+  gcc_assert (!(noex && compound_stmt));
+  if (processing_template_decl)
+    TRANSACTION_EXPR_NOEX (stmt) = noex;
+  else if (noex == noexcept_true_spec)
+    {
+      tree body = TRANSACTION_EXPR_BODY (stmt);
+      body = build1 (MUST_NOT_THROW_EXPR, TREE_TYPE (body), body);
+      SET_EXPR_LOCATION (body, EXPR_LOCATION (TRANSACTION_EXPR_BODY (stmt)));
+      TREE_SIDE_EFFECTS (body) = 1;
+      TRANSACTION_EXPR_BODY (stmt) = body;
+    }
+
   if (compound_stmt)
     finish_compound_stmt (compound_stmt);
   finish_stmt ();
 }
 
-/* Build a __transaction_atomic or __transaction_relaxed expression.  */
+/* Build a __transaction_atomic or __transaction_relaxed expression.  If
+   NOEX is NOEXCEPT_TRUE_SPEC, we wrap the body in a MUST_NOT_THROW_EXPR.  */
 
 tree
-build_transaction_expr (location_t loc, tree expr, int flags)
+build_transaction_expr (location_t loc, tree expr, int flags, tree noex)
 {
   tree ret;
-  ret = build1 (TRANSACTION_EXPR, TREE_TYPE (expr), expr);
+  if (!processing_template_decl)
+    {
+      /* We can build the noexcept-specification now because we don't have
+         a template and can require NOEX to be a constexpr.
+      if (noex && noex != error_mark_node)
+	noex = build_noexcept_spec (noex, tf_warning_or_error); */
+      if (noex == noexcept_true_spec)
+	{
+	  expr = build1 (MUST_NOT_THROW_EXPR, TREE_TYPE (expr), expr);
+	  SET_EXPR_LOCATION (expr, loc);
+	  TREE_SIDE_EFFECTS (expr) = 1;
+	}
+      noex = NULL_TREE;
+    }
+  ret = build2 (TRANSACTION_EXPR, TREE_TYPE (expr), expr, noex);
   if (flags & TM_STMT_ATTR_RELAXED)
 	TRANSACTION_EXPR_RELAXED (ret) = 1;
   SET_EXPR_LOCATION (ret, loc);
diff --git a/gcc/testsuite/g++.dg/tm/noexcept-1.C b/gcc/testsuite/g++.dg/tm/noexcept-1.C
new file mode 100644
index 0000000..86940d2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/noexcept-1.C
@@ -0,0 +1,38 @@ 
+// { dg-do compile }
+// { dg-options "-fgnu-tm -O -std=c++0x -fdump-tree-tmmark -fdump-tree-tmlower" }
+
+struct TrueFalse
+{
+  static constexpr bool v() { return true; }
+};
+
+int global;
+
+template<typename T> int foo()
+{
+  __transaction_atomic noexcept(T::v()) { global += 1; }
+  return __transaction_atomic noexcept(T::v()) (global + 2);
+}
+
+int f1()
+{
+  return foo<TrueFalse>();
+}
+
+int f2()
+{
+  return __transaction_atomic noexcept(true) (global + 3)
+         + __transaction_atomic noexcept(TrueFalse::v()) (global + 4);
+}
+
+int f3()
+{
+  __transaction_atomic noexcept(true) { global += 5; }
+  __transaction_atomic noexcept(TrueFalse::v()) { global += 6; }
+  return global;
+}
+
+/* { dg-final { scan-tree-dump-times "eh_must_not_throw" 6 "tmlower" } } */
+/* { dg-final { scan-tree-dump-times "ITM_RU4\\s*\\(&global" 6 "tmmark" } } */
+/* { dg-final { cleanup-tree-dump "tmmark" } } */
+/* { dg-final { cleanup-tree-dump "tmlower" } } */
diff --git a/gcc/testsuite/g++.dg/tm/noexcept-2.C b/gcc/testsuite/g++.dg/tm/noexcept-2.C
new file mode 100644
index 0000000..f9cbbb6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/noexcept-2.C
@@ -0,0 +1,20 @@ 
+// { dg-do compile }
+// { dg-options "-fgnu-tm -std=c++0x" }
+
+// All of these must fail, because they are not constant expressions.
+template<typename T> int foo(int x, T t)
+{
+  __transaction_atomic noexcept(t) { x++; }      /* { dg-error "not a constant" } */
+  return __transaction_atomic noexcept(t) (x+1); /* { dg-error "not a constant" } */
+}
+
+int bar(int x)
+{
+  __transaction_atomic noexcept(x == 23) { x++; }      /* { dg-error "not a constant" } */
+  return __transaction_atomic noexcept(x == 42) (x+1); /* { dg-error "not a constant" } */
+}
+
+int f(int x)
+{
+  return foo<bool>(x, true);
+}
diff --git a/gcc/testsuite/g++.dg/tm/noexcept-3.C b/gcc/testsuite/g++.dg/tm/noexcept-3.C
new file mode 100644
index 0000000..5a49ade
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/noexcept-3.C
@@ -0,0 +1,40 @@ 
+// { dg-do compile }
+// { dg-options "-fgnu-tm -O -std=c++0x -fdump-tree-tmmark -fdump-tree-tmlower" }
+
+// Same as noexcept-1.C but all noexcepts are false.
+
+struct TrueFalse
+{
+  static constexpr bool v() { return false; }
+};
+
+int global;
+
+template<typename T> int foo()
+{
+  __transaction_atomic noexcept(T::v()) { global += 1; }
+  return __transaction_atomic noexcept(T::v()) (global + 2);
+}
+
+int f1()
+{
+  return foo<TrueFalse>();
+}
+
+int f2()
+{
+  return __transaction_atomic noexcept(false) (global + 3)
+         + __transaction_atomic noexcept(TrueFalse::v()) (global + 4);
+}
+
+int f3()
+{
+  __transaction_atomic noexcept(false) { global += 5; }
+  __transaction_atomic noexcept(TrueFalse::v()) { global += 6; }
+  return global;
+}
+
+/* { dg-final { scan-tree-dump-times "eh_must_not_throw" 0 "tmlower" } } */
+/* { dg-final { scan-tree-dump-times "ITM_RU4\\s*\\(&global" 6 "tmmark" } } */
+/* { dg-final { cleanup-tree-dump "tmmark" } } */
+/* { dg-final { cleanup-tree-dump "tmlower" } } */
diff --git a/gcc/testsuite/g++.dg/tm/noexcept-4.C b/gcc/testsuite/g++.dg/tm/noexcept-4.C
new file mode 100644
index 0000000..b2674f5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/noexcept-4.C
@@ -0,0 +1,35 @@ 
+// { dg-do compile }
+// { dg-options "-fgnu-tm -O -std=c++0x -fdump-tree-tmmark -fdump-tree-tmlower" }
+
+// Similar to noexcept-1.C but without an explicit (true) for noexcept.
+
+struct TrueFalse
+{
+  static constexpr bool v() { return true; }
+};
+
+int global;
+
+template<typename T> int foo()
+{
+  __transaction_atomic noexcept { global += 1; }
+  return __transaction_atomic noexcept (global + 2)
+         + __transaction_atomic noexcept (global + 3);
+}
+
+int f1()
+{
+  return foo<TrueFalse>();
+}
+
+int f3()
+{
+  __transaction_atomic noexcept { global += 4; }
+  return __transaction_atomic noexcept (global + 5)
+         + __transaction_atomic noexcept (global + 6);
+}
+
+/* { dg-final { scan-tree-dump-times "eh_must_not_throw" 6 "tmlower" } } */
+/* { dg-final { scan-tree-dump-times "ITM_RU4\\s*\\(&global" 6 "tmmark" } } */
+/* { dg-final { cleanup-tree-dump "tmmark" } } */
+/* { dg-final { cleanup-tree-dump "tmlower" } } */
diff --git a/gcc/testsuite/g++.dg/tm/noexcept-5.C b/gcc/testsuite/g++.dg/tm/noexcept-5.C
new file mode 100644
index 0000000..c56fc0d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/noexcept-5.C
@@ -0,0 +1,21 @@ 
+// { dg-do compile }
+// { dg-options "-fgnu-tm -O -std=c++0x -fdump-tree-tmmark -fdump-tree-tmlower" }
+
+int global;
+
+void f2(int x)
+{
+  __transaction_atomic
+    {
+      __transaction_atomic noexcept(true)
+        {
+	  global += 1;
+	  if (x)
+	      throw 23;
+        }
+    }
+}
+/* { dg-final { scan-tree-dump-times "eh_must_not_throw" 1 "tmlower" } } */
+/* { dg-final { scan-tree-dump-times "ITM_RU4\\s*\\(&global" 1 "tmmark" } } */
+/* { dg-final { cleanup-tree-dump "tmmark" } } */
+/* { dg-final { cleanup-tree-dump "tmlower" } } */
diff --git a/gcc/tree.def b/gcc/tree.def
index 2a2363e..e87fc61 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -1077,8 +1077,9 @@  DEFTREECODE (OMP_ATOMIC_CAPTURE_NEW, "omp_atomic_capture_new", tcc_statement, 2)
 DEFTREECODE (OMP_CLAUSE, "omp_clause", tcc_exceptional, 0)
 
 /* TRANSACTION_EXPR tree code.
-   Operand 0: BODY: contains body of the transaction.  */
-DEFTREECODE (TRANSACTION_EXPR, "transaction_expr", tcc_expression, 1)
+   Operand 0: BODY: contains body of the transaction.
+   Operand 1: contains noexcept argument, if noexcept has been specified.  */
+DEFTREECODE (TRANSACTION_EXPR, "transaction_expr", tcc_expression, 2)
 
 /* Reduction operations.
    Operations that take a vector of elements and "reduce" it to a scalar
diff --git a/gcc/tree.h b/gcc/tree.h
index a76b0bc..6307aca 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1826,6 +1826,8 @@  extern void protected_set_expr_location (tree, location_t);
 /* TM directives and accessors.  */
 #define TRANSACTION_EXPR_BODY(NODE) \
   TREE_OPERAND (TRANSACTION_EXPR_CHECK (NODE), 0)
+#define TRANSACTION_EXPR_NOEX(NODE) \
+  TREE_OPERAND (TRANSACTION_EXPR_CHECK (NODE), 1)
 #define TRANSACTION_EXPR_OUTER(NODE) \
   (TRANSACTION_EXPR_CHECK (NODE)->base.static_flag)
 #define TRANSACTION_EXPR_RELAXED(NODE) \