diff --git a/gcc/c-parser.c b/gcc/c-parser.c
index e6a7fdf..e707ba3 100644
--- a/gcc/c-parser.c
+++ b/gcc/c-parser.c
@@ -10637,7 +10637,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 c4e8930..8db0906 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -10929,7 +10929,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 1bb6d98..d63644f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5531,8 +5531,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 7242fbf..5d5e276 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -19333,19 +19333,17 @@ 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.  */
+   ??? What does it return precisely?  */
 
 static tree
-cp_parser_exception_specification_opt (cp_parser* parser)
+cp_parser_noexcept_specification_opt (cp_parser* parser)
 {
   cp_token *token;
-  tree type_id_list;
   const char *saved_message;
 
   /* Peek at the next token.  */
@@ -19378,6 +19376,32 @@ cp_parser_exception_specification_opt (cp_parser* parser)
 
       return build_noexcept_spec (expr, tf_warning_or_error);
     }
+  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);
+  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))
@@ -26598,11 +26622,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
@@ -26611,7 +26633,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);
@@ -26629,6 +26651,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);
+
   /* Keep track if we're in the lexical scope of an outer transaction.  */
   new_in = this_in | (old_in & TM_STMT_ATTR_OUTER);
 
@@ -26638,7 +26663,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;
 }
@@ -26646,10 +26671,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
@@ -26658,7 +26681,7 @@ 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;
 
   gcc_assert (keyword == RID_TRANSACTION_ATOMIC
       || keyword == RID_TRANSACTION_RELAXED);
@@ -26678,12 +26701,15 @@ cp_parser_transaction_expression (cp_parser *parser, enum rid keyword)
   if (keyword == RID_TRANSACTION_RELAXED)
     this_in |= TM_STMT_ATTR_RELAXED;
 
+  /* Parse a noexcept specification.  */
+  noex = cp_parser_noexcept_specification_opt(parser);
+
   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);
+  expr = build_transaction_expr (token->location, expr, this_in, noex);
 
   cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
   parser->in_transaction = old_in;
@@ -26741,7 +26767,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 3196d12..bd99f44 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -12955,22 +12955,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)
+	      {
+		/* Check the expression again.  */
+		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);
+		if (noex == error_mark_node)
+		  noex = noexcept_false_spec;
+	      }
+	    gcc_assert (noex == noexcept_false_spec
+			|| noex == noexcept_true_spec);
+	    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 068754a..a5be1b1 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -4977,7 +4977,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)
@@ -4995,28 +4995,52 @@ 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 (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;
+    }
+  else if (noex != noexcept_false_spec && noex != error_mark_node)
+    TRANSACTION_EXPR_NOEX (stmt) = noex;
+
   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 (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;
+    }
+  else if (noex == noexcept_false_spec || noex == error_mark_node)
+    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..c2cb7bb
--- /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 no noexcept at all.
+
+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..a54f482
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/noexcept-4.C
@@ -0,0 +1,14 @@
+// { dg-do compile }
+// { dg-options "-fgnu-tm -O -std=c++0x -fdump-tree-tmmark -fdump-tree-tmlower" }
+
+int global;
+
+int f2()
+{
+  return __transaction_atomic noexcept(true) (global + 3);
+}
+
+/* { 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/testsuite/g++.dg/tm/noexcept-5.C b/gcc/testsuite/g++.dg/tm/noexcept-5.C
new file mode 100644
index 0000000..f86bbb8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tm/noexcept-5.C
@@ -0,0 +1,23 @@
+// { 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;
+        }
+    }
+}
+// FIXME: check that there actually is a call to terminate!
+
+/* { 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 2310801..9c5aada 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1817,6 +1817,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) \
