This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH to implement C++0x noexcept


I've just checked in support for C++0x noexcept, as defined in

http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2010/n3050.html

A noexcept-specification is represented by putting the expression in the TREE_PURPOSE of TREE_RAISES_EXCEPTIONS.

Since most non-template noexcept-specifications, including instantiations of templates, will be either noexcept(true) or noexcept(false), we always use the same node for such specifications. This also simplifies some tests.

The first patch is some cleanup that is necessary for the noexcept patches, but is also correct by itself. The second patch implements the noexcept-expression. The third patch implements the noexcept-specification.

Tested x86_64-pc-linux-gnu, applied to trunk.
commit c0f832033ab6a61743a521bb196ae9b060fa7e56
Author: jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Fri Jun 4 21:21:02 2010 +0000

    	* call.c (build_conditional_expr): Never fold in unevaluated context.
    	* tree.c (build_aggr_init_expr): Propagate TREE_NOTHROW.
    	* semantics.c (simplify_aggr_init_expr): Likewise.
    	* typeck.c (merge_types): Call merge_exception_specifiers.
    	* decl.c (duplicate_decls): Check DECL_SOURCE_LOCATION rather than
    	DECL_ANTICIPATED for preferring new type.
    
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 60cc4f2..03d188b 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -3631,7 +3631,6 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3,
   tree arg2_type;
   tree arg3_type;
   tree result = NULL_TREE;
-  tree result_save;
   tree result_type = NULL_TREE;
   bool lvalue_p = true;
   struct z_candidate *candidates = 0;
@@ -4020,12 +4019,10 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3,
     }
 
  valid_operands:
-  result_save = build3 (COND_EXPR, result_type, arg1, arg2, arg3);
-  result = fold_if_not_in_template (result_save);
-
-  if (cp_unevaluated_operand && TREE_CODE (result) == CALL_EXPR)
-    /* Avoid folding to a CALL_EXPR within decltype (c++/42013).  */
-    result = result_save;
+  result = build3 (COND_EXPR, result_type, arg1, arg2, arg3);
+  if (!cp_unevaluated_operand)
+    /* Avoid folding within decltype (c++/42013) and noexcept.  */
+    result = fold_if_not_in_template (result);
 
   /* We can't use result_type below, as fold might have returned a
      throw_expr.  */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 3905196..8218262 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1286,7 +1286,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
       /* Even if the types match, prefer the new declarations type for
 	 built-ins which have not been explicitly declared, for
 	 exception lists, etc...  */
-      else if (DECL_ANTICIPATED (olddecl))
+      else if (DECL_SOURCE_LOCATION (olddecl) == BUILTINS_LOCATION)
 	{
 	  tree type = TREE_TYPE (newdecl);
 	  tree attribs = (*targetm.merge_type_attributes)
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 05d1cad..2d02690 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -3255,6 +3255,7 @@ simplify_aggr_init_expr (tree *tp)
 				    fn,
 				    aggr_init_expr_nargs (aggr_init_expr),
 				    AGGR_INIT_EXPR_ARGP (aggr_init_expr));
+  TREE_NOTHROW (call_expr) = TREE_NOTHROW (aggr_init_expr);
 
   if (style == ctor)
     {
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 9a5ee0f..c4b9dd5 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -418,6 +418,7 @@ build_aggr_init_expr (tree type, tree init)
 				      AGGR_INIT_EXPR_ARGP (init));
       TREE_SIDE_EFFECTS (rval) = 1;
       AGGR_INIT_VIA_CTOR_P (rval) = is_ctor;
+      TREE_NOTHROW (rval) = TREE_NOTHROW (init);
     }
   else
     rval = init;
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 3a7610a..a00908e 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -829,26 +829,17 @@ merge_types (tree t1, tree t2)
 
 	/* Simple way if one arg fails to specify argument types.  */
 	if (p1 == NULL_TREE || TREE_VALUE (p1) == void_type_node)
-	  {
-	    parms = p2;
-	    raises = TYPE_RAISES_EXCEPTIONS (t2);
-	  }
+	  parms = p2;
 	else if (p2 == NULL_TREE || TREE_VALUE (p2) == void_type_node)
-	  {
-	    parms = p1;
-	    raises = TYPE_RAISES_EXCEPTIONS (t1);
-	  }
+	  parms = p1;
 	else
-	  {
-	    parms = commonparms (p1, p2);
-	    /* In cases where we're merging a real declaration with a
-	       built-in declaration, t1 is the real one.  */
-	    raises = TYPE_RAISES_EXCEPTIONS (t1);
-	  }
+	  parms = commonparms (p1, p2);
 
 	rval = build_function_type (valtype, parms);
 	gcc_assert (type_memfn_quals (t1) == type_memfn_quals (t2));
 	rval = apply_memfn_quals (rval, type_memfn_quals (t1));
+	raises = merge_exception_specifiers (TYPE_RAISES_EXCEPTIONS (t1),
+					     TYPE_RAISES_EXCEPTIONS (t2));
 	t1 = build_exception_variant (rval, raises);
 	break;
       }
@@ -858,7 +849,8 @@ merge_types (tree t1, tree t2)
 	/* Get this value the long way, since TYPE_METHOD_BASETYPE
 	   is just the main variant of this.  */
 	tree basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t2)));
-	tree raises = TYPE_RAISES_EXCEPTIONS (t1);
+	tree raises = merge_exception_specifiers (TYPE_RAISES_EXCEPTIONS (t1),
+						  TYPE_RAISES_EXCEPTIONS (t2));
 	tree t3;
 
 	/* If this was a member function type, get back to the

commit 98fe9664d14d2fc65e98120de16e84bf64830074
Author: jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Fri Jun 4 21:21:13 2010 +0000

    	Implement noexcept operator (5.3.7)
    	* c-common.c (c_common_reswords): Add noexcept.
    	* c-common.h (enum rid): Add RID_NOEXCEPT.
    cp/
    	* cp-tree.def (NOEXCEPT_EXPR): New.
    	* except.c (check_noexcept_r, finish_noexcept_expr): New.
    	* cp-tree.h: Declare finish_noexcept_expr.
    	* parser.c (cp_parser_unary_expression): Parse noexcept-expression.
    	* pt.c (tsubst_copy_and_build): And tsubst it.
    	(type_dependent_expression_p): Handle it.
    	(value_dependent_expression_p): Handle it.
    
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 97d6034..1c51118 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -661,6 +661,7 @@ const struct c_common_resword c_common_reswords[] =
   { "mutable",		RID_MUTABLE,	D_CXXONLY | D_CXXWARN },
   { "namespace",	RID_NAMESPACE,	D_CXXONLY | D_CXXWARN },
   { "new",		RID_NEW,	D_CXXONLY | D_CXXWARN },
+  { "noexcept",		RID_NOEXCEPT,	D_CXXONLY | D_CXX0X | D_CXXWARN },
   { "nullptr",		RID_NULLPTR,	D_CXXONLY | D_CXX0X | D_CXXWARN },
   { "operator",		RID_OPERATOR,	D_CXXONLY | D_CXXWARN },
   { "private",		RID_PRIVATE,	D_CXX_OBJC | D_CXXWARN },
diff --git a/gcc/c-common.h b/gcc/c-common.h
index f0541e9..289d70c 100644
--- a/gcc/c-common.h
+++ b/gcc/c-common.h
@@ -125,7 +125,7 @@ enum rid
   RID_IS_UNION,
 
   /* C++0x */
-  RID_CONSTEXPR, RID_DECLTYPE, RID_NULLPTR, RID_STATIC_ASSERT,
+  RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
 
   /* Objective-C */
   RID_AT_ENCODE,   RID_AT_END,
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index c71f94c..b77350f 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -247,6 +247,7 @@ DEFTREECODE (STATIC_CAST_EXPR, "static_cast_expr", tcc_unary, 1)
 DEFTREECODE (DYNAMIC_CAST_EXPR, "dynamic_cast_expr", tcc_unary, 1)
 DEFTREECODE (DOTSTAR_EXPR, "dotstar_expr", tcc_expression, 2)
 DEFTREECODE (TYPEID_EXPR, "typeid_expr", tcc_expression, 1)
+DEFTREECODE (NOEXCEPT_EXPR, "noexcept_expr", tcc_unary, 1)
 
 /* A placeholder for an expression that is not type-dependent, but
    does occur in a template.  When an expression that is not
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 89a3b7c..e48e469 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4820,6 +4820,7 @@ extern tree build_exc_ptr			(void);
 extern tree build_throw				(tree);
 extern int nothrow_libfn_p			(const_tree);
 extern void check_handlers			(tree);
+extern tree finish_noexcept_expr		(tree);
 extern void choose_personality_routine		(enum languages);
 extern tree eh_type_info			(tree);
 extern tree begin_eh_spec_block			(void);
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index 6f7f70a..76731f4 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -998,3 +998,67 @@ check_handlers (tree handlers)
 	  check_handlers_1 (handler, i);
       }
 }
+
+/* walk_tree helper for finish_noexcept_expr.  Returns non-null if the
+   expression *TP causes the noexcept operator to evaluate to false.
+
+   5.3.7 [expr.noexcept]: The result of the noexcept operator is false if
+   in a potentially-evaluated context the expression would contain
+   * a potentially evaluated call to a function, member function,
+     function pointer, or member function pointer that does not have a
+     non-throwing exception-specification (15.4),
+   * a potentially evaluated throw-expression (15.1),
+   * a potentially evaluated dynamic_cast expression dynamic_cast<T>(v),
+     where T is a reference type, that requires a run-time check (5.2.7), or
+   * a potentially evaluated typeid expression (5.2.8) applied to a glvalue
+     expression whose type is a polymorphic class type (10.3).  */
+
+static tree
+check_noexcept_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
+		  void *data ATTRIBUTE_UNUSED)
+{
+  tree t = *tp;
+  enum tree_code code = TREE_CODE (t);
+  if (code == CALL_EXPR
+      || code == AGGR_INIT_EXPR)
+    {
+      /* We can only use the exception specification of the called function
+	 for determining the value of a noexcept expression; we can't use
+	 TREE_NOTHROW, as it might have a different value in another
+	 translation unit, creating ODR problems.
+
+         We could use TREE_NOTHROW (t) for !TREE_PUBLIC fns, though... */
+      tree fn = (code == AGGR_INIT_EXPR
+		 ? AGGR_INIT_EXPR_FN (t) : CALL_EXPR_FN (t));
+      if (TREE_CODE (fn) == ADDR_EXPR)
+	{
+	  /* We do use TREE_NOTHROW for ABI internals like __dynamic_cast,
+	     and for C library functions known not to throw.  */
+	  tree fn2 = TREE_OPERAND (fn, 0);
+	  if (TREE_CODE (fn2) == FUNCTION_DECL
+	      && DECL_EXTERN_C_P (fn2)
+	      && (DECL_ARTIFICIAL (fn2)
+		  || nothrow_libfn_p (fn2)))
+	    return TREE_NOTHROW (fn2) ? NULL_TREE : t;
+	}
+      fn = TREE_TYPE (TREE_TYPE (fn));
+      if (!TYPE_NOTHROW_P (fn))
+	return t;
+    }
+
+  return NULL_TREE;
+}
+
+/* Evaluate noexcept ( EXPR ).  */
+
+tree
+finish_noexcept_expr (tree expr)
+{
+  if (processing_template_decl)
+    return build_min (NOEXCEPT_EXPR, boolean_type_node, expr);
+
+  if (cp_walk_tree_without_duplicates (&expr, check_noexcept_r, 0))
+    return boolean_false_node;
+  else
+    return boolean_true_node;
+}
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 05d713c..32e86e9 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -5841,6 +5841,51 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p,
 	  }
 	  break;
 
+	case RID_NOEXCEPT:
+	  {
+	    tree expr;
+	    const char *saved_message;
+	    bool saved_integral_constant_expression_p;
+	    bool saved_non_integral_constant_expression_p;
+	    bool saved_greater_than_is_operator_p;
+
+	    cp_lexer_consume_token (parser->lexer);
+	    cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
+
+	    saved_message = parser->type_definition_forbidden_message;
+	    parser->type_definition_forbidden_message
+	      = G_("types may not be defined in %<noexcept%> expressions");
+
+	    saved_integral_constant_expression_p
+	      = parser->integral_constant_expression_p;
+	    saved_non_integral_constant_expression_p
+	      = parser->non_integral_constant_expression_p;
+	    parser->integral_constant_expression_p = false;
+
+	    saved_greater_than_is_operator_p
+	      = parser->greater_than_is_operator_p;
+	    parser->greater_than_is_operator_p = true;
+
+	    ++cp_unevaluated_operand;
+	    ++c_inhibit_evaluation_warnings;
+	    expr = cp_parser_expression (parser, false, NULL);
+	    --c_inhibit_evaluation_warnings;
+	    --cp_unevaluated_operand;
+
+	    parser->greater_than_is_operator_p
+	      = saved_greater_than_is_operator_p;
+
+	    parser->integral_constant_expression_p
+	      = saved_integral_constant_expression_p;
+	    parser->non_integral_constant_expression_p
+	      = saved_non_integral_constant_expression_p;
+
+	    parser->type_definition_forbidden_message = saved_message;
+
+	    cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
+	    return finish_noexcept_expr (expr);
+	  }
+
 	default:
 	  break;
 	}
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index dcb455b..0d58035 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -12245,6 +12245,17 @@ tsubst_copy_and_build (tree t,
 	return cxx_sizeof_or_alignof_expr (op1, TREE_CODE (t), 
                                            complain & tf_error);
 
+    case NOEXCEPT_EXPR:
+      op1 = TREE_OPERAND (t, 0);
+      ++cp_unevaluated_operand;
+      ++c_inhibit_evaluation_warnings;
+      op1 = tsubst_copy_and_build (op1, args, complain, in_decl,
+				   /*function_p=*/false,
+				   /*integral_constant_expression_p=*/false);
+      --cp_unevaluated_operand;
+      --c_inhibit_evaluation_warnings;
+      return finish_noexcept_expr (op1);
+
     case MODOP_EXPR:
       {
 	tree r = build_x_modify_expr
@@ -17577,6 +17588,7 @@ value_dependent_expression_p (tree expression)
         return true;
       else if (TYPE_P (expression))
 	return dependent_type_p (expression);
+    case NOEXCEPT_EXPR:
       return type_dependent_expression_p (expression);
 
     case SCOPE_REF:
@@ -17680,6 +17692,7 @@ type_dependent_expression_p (tree expression)
   if (TREE_CODE (expression) == PSEUDO_DTOR_EXPR
       || TREE_CODE (expression) == SIZEOF_EXPR
       || TREE_CODE (expression) == ALIGNOF_EXPR
+      || TREE_CODE (expression) == NOEXCEPT_EXPR
       || TREE_CODE (expression) == TRAIT_EXPR
       || TREE_CODE (expression) == TYPEID_EXPR
       || TREE_CODE (expression) == DELETE_EXPR
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept01.C b/gcc/testsuite/g++.dg/cpp0x/noexcept01.C
new file mode 100644
index 0000000..e3341d8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept01.C
@@ -0,0 +1,75 @@
+// Test for noexcept-expression
+// { dg-options "-std=c++0x -O2" }
+
+#include <typeinfo>
+
+#define SA(X) static_assert(X, #X)
+
+void f();
+void g() throw();
+SA(noexcept(g()));
+SA(!noexcept(f()));
+SA(!noexcept(throw 1));
+SA(noexcept(42));
+
+struct A
+{
+  virtual ~A();
+};
+
+struct B: public A
+{
+  virtual ~B();
+};
+
+A* ap;
+
+struct C { };
+C* cp;
+
+SA (noexcept (dynamic_cast<B*>(ap)));
+SA (!noexcept (dynamic_cast<B&>(*ap)));
+SA (!noexcept (typeid (*ap)));
+SA (noexcept (typeid (*cp)));
+
+SA (!noexcept (true ? 1 : throw 1));
+SA (!noexcept (true || true ? 1 : throw 1));
+
+SA (noexcept (C()));
+
+struct D
+{
+  D() throw();
+};
+
+SA (noexcept (D()));
+
+struct E
+{
+  E() throw();
+  ~E();
+};
+
+SA (!noexcept (E()));
+
+struct F
+{
+  virtual void f();
+};
+
+SA (noexcept (F()));
+
+template <class T, bool b>
+void tf()
+{
+  SA (noexcept (T()) == b);
+}
+
+template void tf<int,true>();
+template void tf<E, false>();
+
+// Make sure that noexcept uses the declared exception-specification, not
+// any knowledge we might have about whether or not the function really
+// throws.
+void h() { }
+SA(!noexcept(h()));

commit 3644efa555cc85fc27dada414f6de71133046242
Author: jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Fri Jun 4 21:21:23 2010 +0000

    	Implement noexcept-specification (15.4)
    	* parser.c (cp_parser_exception_specification_opt): Parse it.
    	Give -Wdeprecated warning about throw() specs.
    	* pt.c (tsubst_exception_specification): Handle it.
    	* error.c (dump_exception_spec): Handle it.
    	* cxx-pretty-print.c (pp_cxx_exception_specification): Likewise.
    	* typeck.c (comp_except_specs): Handle compatibility rules.
    	Change exact parm to take an enum.
    	* typeck2.c (merge_exception_specifiers): Handle noexcept.
    	* except.c (nothrow_spec_p, type_noexcept_p): New fns.
    	(type_throw_all_p, build_noexcept_spec): New fns.
    	* cp-tree.h (TYPE_NOTHROW_P, TYPE_NOEXCEPT_P): Use them.
    	(comp_except_specs): Define ce_derived, ce_normal, ce_exact enums.
    	(cp_tree_index): Add CPTI_NOEXCEPT_TRUE_SPEC, CPTI_NOEXCEPT_FALSE_SPEC.
    	(noexcept_true_spec, noexcept_false_spec): New macros.
    	* name-lookup.c (pushdecl_maybe_friend): Adjust.
    	* search.c (check_final_overrider): Adjust.
    	* decl.c (check_redeclaration_exception_specification): Adjust.
    	(use_eh_spec_block): Use type_throw_all_p.
    	(cxx_init_decl_processing): Set noexcept_false_spec,noexcept_true_spec.
    	Give operator new a noexcept-specification in C++0x mode.
    	* tree.c (build_exception_variant, cxx_type_hash_eq): Adjust.
    	(cp_build_type_attribute_variant): Don't test TYPE_RAISES_EXCEPTIONS.
    
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index e48e469..6b292b6 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -758,6 +758,8 @@ enum cp_tree_index
     CPTI_LANG_NAME_JAVA,
 
     CPTI_EMPTY_EXCEPT_SPEC,
+    CPTI_NOEXCEPT_TRUE_SPEC,
+    CPTI_NOEXCEPT_FALSE_SPEC,
     CPTI_JCLASS,
     CPTI_TERMINATE,
     CPTI_CALL_UNEXPECTED,
@@ -847,6 +849,8 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 
 /* Exception specifier used for throw().  */
 #define empty_except_spec		cp_global_trees[CPTI_EMPTY_EXCEPT_SPEC]
+#define noexcept_true_spec		cp_global_trees[CPTI_NOEXCEPT_TRUE_SPEC]
+#define noexcept_false_spec		cp_global_trees[CPTI_NOEXCEPT_FALSE_SPEC]
 
 /* If non-NULL, a POINTER_TYPE equivalent to (java::lang::Class*).  */
 #define jclass_node			cp_global_trees[CPTI_JCLASS]
@@ -1726,19 +1730,18 @@ struct GTY(()) lang_type {
 /* For FUNCTION_TYPE or METHOD_TYPE, a list of the exceptions that
    this type can raise.  Each TREE_VALUE is a _TYPE.  The TREE_VALUE
    will be NULL_TREE to indicate a throw specification of `()', or
-   no exceptions allowed.  */
+   no exceptions allowed.  For a noexcept specification, TREE_VALUE
+   is NULL_TREE and TREE_PURPOSE is the constant-expression. */
 #define TYPE_RAISES_EXCEPTIONS(NODE) TYPE_LANG_SLOT_1 (NODE)
 
-/* For FUNCTION_TYPE or METHOD_TYPE, return 1 iff it is declared `throw()'.  */
-#define TYPE_NOTHROW_P(NODE) \
-  (TYPE_RAISES_EXCEPTIONS (NODE) \
-   && TREE_VALUE (TYPE_RAISES_EXCEPTIONS (NODE)) == NULL_TREE)
+/* For FUNCTION_TYPE or METHOD_TYPE, return 1 iff it is declared `throw()'
+   or noexcept(true).  */
+#define TYPE_NOTHROW_P(NODE) nothrow_spec_p (TYPE_RAISES_EXCEPTIONS (NODE))
 
 /* For FUNCTION_TYPE or METHOD_TYPE, true if NODE is noexcept.  This is the
    case for things declared noexcept(true) and, with -fnothrow-opt, for
    throw() functions.  */
-#define TYPE_NOEXCEPT_P(NODE) \
-  (flag_nothrow_opt && TYPE_NOTHROW_P(NODE))
+#define TYPE_NOEXCEPT_P(NODE) type_noexcept_p (NODE)
 
 /* The binding level associated with the namespace.  */
 #define NAMESPACE_LEVEL(NODE) \
@@ -4821,6 +4824,10 @@ extern tree build_throw				(tree);
 extern int nothrow_libfn_p			(const_tree);
 extern void check_handlers			(tree);
 extern tree finish_noexcept_expr		(tree);
+extern bool nothrow_spec_p			(const_tree);
+extern bool type_noexcept_p			(const_tree);
+extern bool type_throw_all_p			(const_tree);
+extern tree build_noexcept_spec			(tree, int);
 extern void choose_personality_routine		(enum languages);
 extern tree eh_type_info			(tree);
 extern tree begin_eh_spec_block			(void);
@@ -5348,7 +5355,8 @@ extern tree require_complete_type		(tree);
 extern tree complete_type			(tree);
 extern tree complete_type_or_else		(tree, tree);
 extern int type_unknown_p			(const_tree);
-extern bool comp_except_specs			(const_tree, const_tree, bool);
+enum { ce_derived, ce_normal, ce_exact };
+extern bool comp_except_specs			(const_tree, const_tree, int);
 extern bool comptypes				(tree, tree, int);
 extern bool compparms				(const_tree, const_tree);
 extern int comp_cv_qualification		(const_tree, const_tree);
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index 04a8314..e6c68ba 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -1418,8 +1418,17 @@ pp_cxx_exception_specification (cxx_pretty_printer *pp, tree t)
   tree ex_spec = TYPE_RAISES_EXCEPTIONS (t);
   bool need_comma = false;
 
-  if (!TYPE_NOTHROW_P (t) && ex_spec == NULL)
+  if (ex_spec == NULL)
     return;
+  if (TREE_PURPOSE (ex_spec))
+    {
+      pp_cxx_ws_string (pp, "noexcept");
+      pp_cxx_whitespace (pp);
+      pp_cxx_left_paren (pp);
+      pp_cxx_expression (pp, TREE_PURPOSE (ex_spec));
+      pp_cxx_right_paren (pp);
+      return;
+    }
   pp_cxx_ws_string (pp, "throw");
   pp_cxx_left_paren (pp);
   for (; ex_spec && TREE_VALUE (ex_spec); ex_spec = TREE_CHAIN (ex_spec))
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 8218262..ef00a11 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1104,10 +1104,10 @@ check_redeclaration_exception_specification (tree new_decl,
   if ((pedantic || ! DECL_IN_SYSTEM_HEADER (old_decl))
       && ! DECL_IS_BUILTIN (old_decl)
       && flag_exceptions
-      && !comp_except_specs (new_exceptions, old_exceptions,
-			     /*exact=*/true))
+      && !comp_except_specs (new_exceptions, old_exceptions, ce_normal))
     {
-      error ("declaration of %qF throws different exceptions", new_decl);
+      error ("declaration of %qF has a different exception specifier",
+	     new_decl);
       error ("from previous declaration %q+F", old_decl);
     }
 }
@@ -3433,6 +3433,8 @@ cxx_init_decl_processing (void)
   truthvalue_true_node = boolean_true_node;
 
   empty_except_spec = build_tree_list (NULL_TREE, NULL_TREE);
+  noexcept_true_spec = build_tree_list (boolean_true_node, NULL_TREE);
+  noexcept_false_spec = build_tree_list (boolean_false_node, NULL_TREE);
 
 #if 0
   record_builtin_type (RID_MAX, NULL, string_type_node);
@@ -3498,29 +3500,37 @@ cxx_init_decl_processing (void)
   current_lang_name = lang_name_cplusplus;
 
   {
-    tree bad_alloc_id;
-    tree bad_alloc_type_node;
-    tree bad_alloc_decl;
     tree newtype, deltype;
     tree ptr_ftype_sizetype;
-
-    push_namespace (std_identifier);
-    bad_alloc_id = get_identifier ("bad_alloc");
-    bad_alloc_type_node = make_class_type (RECORD_TYPE);
-    TYPE_CONTEXT (bad_alloc_type_node) = current_namespace;
-    bad_alloc_decl
-      = create_implicit_typedef (bad_alloc_id, bad_alloc_type_node);
-    DECL_CONTEXT (bad_alloc_decl) = current_namespace;
-    pop_namespace ();
+    tree new_eh_spec;
 
     ptr_ftype_sizetype
       = build_function_type (ptr_type_node,
 			     tree_cons (NULL_TREE,
 					size_type_node,
 					void_list_node));
-    newtype = build_exception_variant
-      (ptr_ftype_sizetype, add_exception_specifier
-       (NULL_TREE, bad_alloc_type_node, -1));
+    if (cxx_dialect == cxx98)
+      {
+	tree bad_alloc_id;
+	tree bad_alloc_type_node;
+	tree bad_alloc_decl;
+
+	push_namespace (std_identifier);
+	bad_alloc_id = get_identifier ("bad_alloc");
+	bad_alloc_type_node = make_class_type (RECORD_TYPE);
+	TYPE_CONTEXT (bad_alloc_type_node) = current_namespace;
+	bad_alloc_decl
+	  = create_implicit_typedef (bad_alloc_id, bad_alloc_type_node);
+	DECL_CONTEXT (bad_alloc_decl) = current_namespace;
+	pop_namespace ();
+
+	new_eh_spec
+	  = add_exception_specifier (NULL_TREE, bad_alloc_type_node, -1);
+      }
+    else
+      new_eh_spec = noexcept_false_spec;
+
+    newtype = build_exception_variant (ptr_ftype_sizetype, new_eh_spec);
     deltype = build_exception_variant (void_ftype_ptr, empty_except_spec);
     push_cp_library_fn (NEW_EXPR, newtype);
     push_cp_library_fn (VEC_NEW_EXPR, newtype);
@@ -12198,7 +12208,7 @@ use_eh_spec_block (tree fn)
 {
   return (flag_exceptions && flag_enforce_eh_specs
 	  && !processing_template_decl
-	  && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn))
+	  && !type_throw_all_p (TREE_TYPE (fn))
 	  /* We insert the EH_SPEC_BLOCK only in the original
 	     function; then, it is copied automatically to the
 	     clones.  */
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 381163b..d535f05 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -1388,7 +1388,15 @@ dump_parameters (tree parmtypes, int flags)
 static void
 dump_exception_spec (tree t, int flags)
 {
-  if (t)
+  if (t && TREE_PURPOSE (t))
+    {
+      pp_cxx_ws_string (cxx_pp, "noexcept");
+      pp_cxx_whitespace (cxx_pp);
+      pp_cxx_left_paren (cxx_pp);
+      dump_expr (TREE_PURPOSE (t), flags);
+      pp_cxx_right_paren (cxx_pp);
+    }
+  else if (t)
     {
       pp_cxx_ws_string (cxx_pp, "throw");
       pp_cxx_whitespace (cxx_pp);
@@ -2116,6 +2124,14 @@ dump_expr (tree t, int flags)
       pp_cxx_right_paren (cxx_pp);
       break;
 
+    case NOEXCEPT_EXPR:
+      pp_cxx_ws_string (cxx_pp, "noexcept");
+      pp_cxx_whitespace (cxx_pp);
+      pp_cxx_left_paren (cxx_pp);
+      dump_expr (TREE_OPERAND (t, 0), flags);
+      pp_cxx_right_paren (cxx_pp);
+      break;
+
     case REALPART_EXPR:
     case IMAGPART_EXPR:
       pp_cxx_ws_string (cxx_pp, operator_name_info[TREE_CODE (t)].name);
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index 76731f4..7be760e 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -1062,3 +1062,64 @@ finish_noexcept_expr (tree expr)
   else
     return boolean_true_node;
 }
+
+/* Return true iff SPEC is throw() or noexcept(true).  */
+
+bool
+nothrow_spec_p (const_tree spec)
+{
+  if (spec == NULL_TREE
+      || TREE_VALUE (spec) != NULL_TREE
+      || spec == noexcept_false_spec)
+    return false;
+  if (TREE_PURPOSE (spec) == NULL_TREE
+      || spec == noexcept_true_spec)
+    return true;
+  gcc_assert (processing_template_decl
+	      || TREE_PURPOSE (spec) == error_mark_node);
+  return false;
+}
+
+/* For FUNCTION_TYPE or METHOD_TYPE, true if NODE is noexcept.  This is the
+   case for things declared noexcept(true) and, with -fnothrow-opt, for
+   throw() functions.  */
+
+bool
+type_noexcept_p (const_tree type)
+{
+  tree spec = TYPE_RAISES_EXCEPTIONS (type);
+  if (flag_nothrow_opt)
+    return nothrow_spec_p (spec);
+  else
+    return spec == noexcept_true_spec;
+}
+
+/* For FUNCTION_TYPE or METHOD_TYPE, true if NODE can throw any type,
+   i.e. no exception-specification or noexcept(false).  */
+
+bool
+type_throw_all_p (const_tree type)
+{
+  tree spec = TYPE_RAISES_EXCEPTIONS (type);
+  return spec == NULL_TREE || spec == noexcept_false_spec;
+}
+
+/* Create a representation of the noexcept-specification with
+   constant-expression of EXPR.  COMPLAIN is as for tsubst.  */
+
+tree
+build_noexcept_spec (tree expr, int complain)
+{
+  expr = perform_implicit_conversion_flags (boolean_type_node, expr,
+					    complain,
+					    LOOKUP_NORMAL);
+  if (expr == boolean_true_node)
+    return noexcept_true_spec;
+  else if (expr == boolean_false_node)
+    return noexcept_false_spec;
+  else
+    {
+      gcc_assert (processing_template_decl || expr == error_mark_node);
+      return build_tree_list (expr, NULL_TREE);
+    }
+}
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 936c256..3236b64 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -805,7 +805,7 @@ pushdecl_maybe_friend (tree x, bool is_friend)
 				TYPE_RAISES_EXCEPTIONS (TREE_TYPE (previous));
 		  if (!comp_except_specs (previous_exception_spec,
 					  x_exception_spec,
-					  true))
+					  ce_normal))
 		    {
 		      pedwarn (input_location, 0, "declaration of %q#D with C language linkage",
 			       x);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 32e86e9..a33330c 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -17534,13 +17534,50 @@ 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?  */
+  if (cp_parser_is_keyword (token, RID_NOEXCEPT))
+    {
+      tree expr;
+      cp_lexer_consume_token (parser->lexer);
+
+      if (cp_lexer_peek_token (parser->lexer)->type == CPP_OPEN_PAREN)
+	{
+	  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");
+
+	  expr = cp_parser_constant_expression (parser, false, NULL);
+
+	  /* Restore the saved message.  */
+	  parser->type_definition_forbidden_message = saved_message;
+
+	  cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
+	}
+      else
+	expr = boolean_true_node;
+
+      return build_noexcept_spec (expr, tf_warning_or_error);
+    }
+
   /* If it's not `throw', then there's no exception-specification.  */
   if (!cp_parser_is_keyword (token, RID_THROW))
     return NULL_TREE;
 
+#if 0
+  /* Enable this once a lot of code has transitioned to noexcept?  */
+  if (cxx_dialect == cxx0x && !in_system_header)
+    warning (OPT_Wdeprecated, "dynamic exception specifications are "
+	     "deprecated in C++0x; use %<noexcept%> instead.");
+#endif
+
   /* Consume the `throw'.  */
   cp_lexer_consume_token (parser->lexer);
 
@@ -17552,8 +17589,6 @@ cp_parser_exception_specification_opt (cp_parser* parser)
   /* If it's not a `)', then there is a type-id-list.  */
   if (token->type != CPP_CLOSE_PAREN)
     {
-      const char *saved_message;
-
       /* Types may not be defined in an exception-specification.  */
       saved_message = parser->type_definition_forbidden_message;
       parser->type_definition_forbidden_message
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 0d58035..4c98bf2 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -9838,7 +9838,15 @@ tsubst_exception_specification (tree fntype,
 
   specs = TYPE_RAISES_EXCEPTIONS (fntype);
   new_specs = NULL_TREE;
-  if (specs)
+  if (specs && TREE_PURPOSE (specs))
+    {
+      /* A noexcept-specifier.  */
+      new_specs = tsubst_copy_and_build
+	(TREE_PURPOSE (specs), args, complain, in_decl, /*function_p=*/false,
+	 /*integral_constant_expression_p=*/true);
+      new_specs = build_noexcept_spec (new_specs, complain);
+    }
+  else if (specs)
     {
       if (! TREE_VALUE (specs))
 	new_specs = specs;
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 4843855..e308821 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -1867,7 +1867,7 @@ check_final_overrider (tree overrider, tree basefn)
     }
 
   /* Check throw specifier is at least as strict.  */
-  if (!comp_except_specs (base_throw, over_throw, 0))
+  if (!comp_except_specs (base_throw, over_throw, ce_derived))
     {
       error ("looser throw specifier for %q+#F", overrider);
       error ("  overriding %q+#F", basefn);
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index c4b9dd5..7d0e476 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1467,12 +1467,16 @@ cxx_printable_name_translate (tree decl, int v)
 tree
 build_exception_variant (tree type, tree raises)
 {
-  tree v = TYPE_MAIN_VARIANT (type);
-  int type_quals = TYPE_QUALS (type);
+  tree v;
+  int type_quals;
 
-  for (; v; v = TYPE_NEXT_VARIANT (v))
+  if (comp_except_specs (raises, TYPE_RAISES_EXCEPTIONS (type), ce_exact))
+    return type;
+
+  type_quals = TYPE_QUALS (type);
+  for (v = TYPE_MAIN_VARIANT (type); v; v = TYPE_NEXT_VARIANT (v))
     if (check_qualified_type (v, type, type_quals)
-	&& comp_except_specs (raises, TYPE_RAISES_EXCEPTIONS (v), 1))
+	&& comp_except_specs (raises, TYPE_RAISES_EXCEPTIONS (v), ce_exact))
       return v;
 
   /* Need to build a new variant.  */
@@ -2645,10 +2649,8 @@ cp_build_type_attribute_variant (tree type, tree attributes)
   tree new_type;
 
   new_type = build_type_attribute_variant (type, attributes);
-  if ((TREE_CODE (new_type) == FUNCTION_TYPE
-       || TREE_CODE (new_type) == METHOD_TYPE)
-      && (TYPE_RAISES_EXCEPTIONS (new_type)
-	  != TYPE_RAISES_EXCEPTIONS (type)))
+  if (TREE_CODE (new_type) == FUNCTION_TYPE
+      || TREE_CODE (new_type) == METHOD_TYPE)
     new_type = build_exception_variant (new_type,
 					TYPE_RAISES_EXCEPTIONS (type));
 
@@ -2669,7 +2671,7 @@ cxx_type_hash_eq (const_tree typea, const_tree typeb)
   gcc_assert (TREE_CODE (typea) == FUNCTION_TYPE);
 
   return comp_except_specs (TYPE_RAISES_EXCEPTIONS (typea),
-			    TYPE_RAISES_EXCEPTIONS (typeb), 1);
+			    TYPE_RAISES_EXCEPTIONS (typeb), ce_exact);
 }
 
 /* Apply FUNC to all language-specific sub-trees of TP in a pre-order
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index a00908e..26ffe1c 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -981,29 +981,56 @@ comp_except_types (tree a, tree b, bool exact)
 }
 
 /* Return true if TYPE1 and TYPE2 are equivalent exception specifiers.
-   If EXACT is false, T2 can be stricter than T1 (according to 15.4/7),
-   otherwise it must be exact. Exception lists are unordered, but
-   we've already filtered out duplicates. Most lists will be in order,
-   we should try to make use of that.  */
+   If EXACT is ce_derived, T2 can be stricter than T1 (according to 15.4/5).
+   If EXACT is ce_normal, the compatibility rules in 15.4/3 apply.
+   If EXACT is ce_exact, the specs must be exactly the same. Exception lists
+   are unordered, but we've already filtered out duplicates. Most lists will
+   be in order, we should try to make use of that.  */
 
 bool
-comp_except_specs (const_tree t1, const_tree t2, bool exact)
+comp_except_specs (const_tree t1, const_tree t2, int exact)
 {
   const_tree probe;
   const_tree base;
   int  length = 0;
+  const_tree noexcept_spec = NULL_TREE;
+  const_tree other_spec;
 
   if (t1 == t2)
     return true;
 
+  /* First test noexcept compatibility.  */
+  if (t1 && TREE_PURPOSE (t1))
+    noexcept_spec = t1, other_spec = t2;
+  else if (t2 && TREE_PURPOSE (t2))
+    noexcept_spec = t2, other_spec = t1;
+  if (noexcept_spec)
+    {
+      tree p = TREE_PURPOSE (noexcept_spec);
+      /* Two noexcept-specs are equivalent iff their exprs are.  */
+      if (other_spec && TREE_PURPOSE (other_spec))
+	return cp_tree_equal (p, TREE_PURPOSE (other_spec));
+      /* noexcept(true) is compatible with throw().  */
+      else if (exact < ce_exact && p == boolean_true_node)
+	return nothrow_spec_p (other_spec);
+      /* noexcept(false) is compatible with any throwing
+	 dynamic-exception-spec.  */
+      else if (exact < ce_exact && p == boolean_false_node)
+	return !nothrow_spec_p (other_spec);
+      /* A dependent noexcept-spec is not compatible with any
+	 dynamic-exception-spec.  */
+      else
+	return false;
+    }
+
   if (t1 == NULL_TREE)			   /* T1 is ...  */
-    return t2 == NULL_TREE || !exact;
+    return t2 == NULL_TREE || exact == ce_derived;
   if (!TREE_VALUE (t1))			   /* t1 is EMPTY */
     return t2 != NULL_TREE && !TREE_VALUE (t2);
   if (t2 == NULL_TREE)			   /* T2 is ...  */
     return false;
   if (TREE_VALUE (t1) && !TREE_VALUE (t2)) /* T2 is EMPTY, T1 is not */
-    return !exact;
+    return exact == ce_derived;
 
   /* Neither set is ... or EMPTY, make sure each part of T2 is in T1.
      Count how many we find, to determine exactness. For exact matching and
@@ -1018,7 +1045,7 @@ comp_except_specs (const_tree t1, const_tree t2, bool exact)
 
 	  if (comp_except_types (a, b, exact))
 	    {
-	      if (probe == base && exact)
+	      if (probe == base && exact > ce_derived)
 		base = TREE_CHAIN (probe);
 	      length++;
 	      break;
@@ -1027,7 +1054,7 @@ comp_except_specs (const_tree t1, const_tree t2, bool exact)
       if (probe == NULL_TREE)
 	return false;
     }
-  return !exact || base == NULL_TREE || length == list_length (t1);
+  return exact == ce_derived || base == NULL_TREE || length == list_length (t1);
 }
 
 /* Compare the array types T1 and T2.  ALLOW_REDECLARATION is true if
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 7603ead..93ea70d 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1721,6 +1721,13 @@ merge_exception_specifiers (tree list, tree add)
 {
   if (!list || !add)
     return NULL_TREE;
+  /* A noexcept(true) spec takes precedence over a throw() spec.
+     A throw(type-list) spec takes precedence over a noexcept(false) spec.
+     Any other noexcept-spec should only be merged with an equivalent one.
+     So the !TREE_VALUE code is correct for the latter two cases.  */
+  else if (list == noexcept_true_spec
+	   || add == noexcept_true_spec)
+    return noexcept_true_spec;
   else if (!TREE_VALUE (list))
     return add;
   else if (!TREE_VALUE (add))
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept02.C b/gcc/testsuite/g++.dg/cpp0x/noexcept02.C
new file mode 100644
index 0000000..be6fa00
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept02.C
@@ -0,0 +1,52 @@
+// Test for noexcept-specification
+// { dg-options "-std=c++0x" }
+
+#define SA(X) static_assert(X, #X)
+
+void f();
+void f() noexcept(false);
+void f() noexcept(1 == 0);
+void f();
+
+SA(!noexcept(f()));
+
+void g() throw (int);
+void g() noexcept(false);	// { dg-error "previous declaration" }
+void g();			// { dg-error "different exception" }
+
+void h() throw();
+void h() noexcept;
+void h() throw();
+void h() noexcept;
+
+template <class T>
+void g (T) noexcept(noexcept(T())); // { dg-error "previous declaration" }
+template <class T>
+void g (T) noexcept(noexcept(T(0))); // { dg-error "different exception" }
+
+template <class T>
+void f (T) noexcept(noexcept(T()) && noexcept(T()));
+template <class T>
+void f (T) noexcept(noexcept(T()) && noexcept(T()));
+template <class T>
+void f2(T a) noexcept (noexcept (f (a)));
+
+struct A { A(); };
+SA(noexcept(f(1)));
+SA(!noexcept(f(A())));
+SA(noexcept(f2(1)));
+SA(!noexcept(f2(A())));
+
+template <class... Ts>
+void f3(Ts... ts) noexcept (noexcept (f(ts...)));
+
+SA(noexcept(f3(1)));
+SA(!noexcept(f3(A())));
+
+template <class T1, class T2>
+void f (T1, T2) noexcept(noexcept(T1(), T2()));
+
+SA(noexcept(f3(1,1)));
+SA(!noexcept(f3(1,A())));
+SA(!noexcept(f3(A(),1)));
+SA(!noexcept(f3(A(),A())));
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept03.C b/gcc/testsuite/g++.dg/cpp0x/noexcept03.C
new file mode 100644
index 0000000..d992245
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept03.C
@@ -0,0 +1,68 @@
+// Runtime test for noexcept-specification.
+// { dg-options "-std=c++0x" }
+// { dg-do run }
+
+#include <exception>
+#include <cstdlib>
+
+void my_terminate ()
+{
+  std::exit (0);
+}
+
+void my_unexpected ()
+{
+  throw;
+}
+
+void g() { throw 1; }
+void (*p)() = g;
+void f () noexcept (false)
+{
+  p();
+}
+
+template <class T>
+void f(T) noexcept (noexcept (T()))
+{
+  p();
+}
+
+template <class T>
+void f2(T a) noexcept (noexcept (f (a)))
+{
+  f(a);
+}
+
+struct A { A() { } };
+
+// throw(int) overrides noexcept(false) in either order.
+void h() throw (int, std::bad_exception);
+void h() noexcept (false)
+{
+  throw 1.0;
+}
+
+void i() noexcept (false);
+void i() throw (int, std::bad_exception)
+{
+  throw 1.0;
+}
+
+int main()
+{
+  // noexcept(false) allows throw.
+  try { f(); } catch (int) { }
+  // noexcept(noexcept(A())) == noexcept(false).
+  try { f(A()); } catch (int) { }
+  try { f2(A()); } catch (int) { }
+
+  std::set_unexpected (my_unexpected);
+  try { h(); } catch (std::bad_exception) { }
+  try { i(); } catch (std::bad_exception) { }
+
+  std::set_terminate (my_terminate);
+  // noexcept(noexcept(int())) == noexcept(true).
+  try { f2(1); } catch (...) { }
+  return 1;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept04.C b/gcc/testsuite/g++.dg/cpp0x/noexcept04.C
new file mode 100644
index 0000000..8df8186
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept04.C
@@ -0,0 +1,31 @@
+// Make sure that we call terminate when a noexcept spec is violated.
+// The function pointers are there to make sure that
+// the compiler doesn't get clever about optimizing the calls based on
+// knowledge about the called functions.
+
+// { dg-options "-std=c++0x" }
+// { dg-do run }
+
+#include <exception>
+#include <cstdlib>
+
+void my_terminate ()
+{
+  std::exit (0);
+}
+
+void g() { throw 1; }
+void (*p1)() = g;
+void f() noexcept { p1(); }
+void (*p2)() = f;
+void h() { p2(); }
+
+int main()
+{
+  std::set_terminate (my_terminate);
+
+  try { h(); }
+  catch (int) { }
+
+  return 1;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept05.C b/gcc/testsuite/g++.dg/cpp0x/noexcept05.C
new file mode 100644
index 0000000..6acea43
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept05.C
@@ -0,0 +1,19 @@
+// Make sure that we force an LSDA for a noexcept spec so
+// that the personality routine will call terminate.  Also check that we
+// optimize away the EH cleanup for var because the personality routine
+// will call terminate before unwinding: there should not be an EH region
+// (i.e. LEHB/LEHE labels) around the call to g().
+
+// { dg-final { scan-assembler-not "_ZSt9terminatev" } }
+// { dg-final { scan-assembler-not "EHB" } }
+// { dg-final { scan-assembler "LSDA" } }
+
+// { dg-options "-std=c++0x" }
+
+struct A { ~A(); };
+void g();
+void f() noexcept
+{
+  A var;
+  g();
+}
diff --git a/gcc/testsuite/g++.dg/eh/spec8.C b/gcc/testsuite/g++.dg/eh/spec8.C
index 7a35e6e..72dadff 100644
--- a/gcc/testsuite/g++.dg/eh/spec8.C
+++ b/gcc/testsuite/g++.dg/eh/spec8.C
@@ -3,9 +3,9 @@
 struct exception {};
 
 template <typename T> void foo() throw(exception); // { dg-error "declaration" }
-template <typename T> void foo(); // { dg-error "exceptions" }
+template <typename T> void foo(); // { dg-error "exception" }
 
 struct bar
 {
-  template <typename T> friend void foo(); // { dg-error "exceptions" }
+  template <typename T> friend void foo(); // { dg-error "exception" }
 };

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]