Patchwork C++ PATCH for c++/49107 (excessive instantiation due to noexcept)

login
register
mail settings
Submitter Jason Merrill
Date June 8, 2011, 9:32 p.m.
Message ID <4DEFEA53.9030000@redhat.com>
Download mbox | patch
Permalink /patch/99561/
State New
Headers show

Comments

Jason Merrill - June 8, 2011, 9:32 p.m.
49107 is an issue with the addition of noexcept to the standard library 
causing extra instantiations, to the point that code that worked before 
doesn't work now due to circular dependency.  Someone suggested that to 
avoid this problem we could defer instantiation of noexcept-specifiers 
until they are actually needed.  This patch implements that suggestion, 
and does in fact seem to fix the problem.

Tested x86_64-pc-linux-gnu, applying to trunk.
Paolo Carlini - June 9, 2011, 7:50 a.m.
On 06/08/2011 11:32 PM, Jason Merrill wrote:
> 49107 is an issue with the addition of noexcept to the standard 
> library causing extra instantiations, to the point that code that 
> worked before doesn't work now due to circular dependency.  Someone 
> suggested that to avoid this problem we could defer instantiation of 
> noexcept-specifiers until they are actually needed.  This patch 
> implements that suggestion, and does in fact seem to fix the problem.
Thanks a lot Jason.

I'm trying to figure out which are the implications for the library of 
the comment you added to c++/48468, I think it would be now more 
difficult to implement consolidated is_nothrow_* traits, thus not 
computing first via sfinae the corresponding is_* trait. But doesn't 
seem a serious limitation...

Thanks again,
Paolo.

Patch

commit 03a304001f8fdb776a96648786fe667ad416ebeb
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Jun 8 09:06:07 2011 -0400

    	PR c++/49107
    	* cp-tree.def (DEFERRED_NOEXCEPT): New.
    	* cp-tree.h (struct tree_deferred_noexcept): New.
    	(DEFERRED_NOEXCEPT_PATTERN, DEFERRED_NOEXCEPT_ARGS): New.
    	(DEFERRED_NOEXCEPT_SPEC_P): New.
    	(enum cp_tree_node_structure_enum): Add TS_CP_DEFERRED_NOEXCEPT.
    	(union lang_tree_node): Add tree_deferred_noexcept.
    	(maybe_instantiate_noexcept): Declare.
    	* cp-objcp-common.c (cp_tree_size): Handle DEFERRED_NOEXCEPT.
    	* error.c (dump_exception_spec): Likewise.
    	* cxx-pretty-print.c (pp_cxx_exception_specification): Likewise.
    	* ptree.c (cxx_print_xnode): Likewise.
    	* tree.c (cp_tree_equal): Likewise.
    	* decl.c (cp_tree_node_structure): Likewise.
    	(duplicate_decls): Call maybe_instantiate_noexcept.
    	* except.c (build_noexcept_spec): Handle DEFERRED_NOEXCEPT.
    	(nothrow_spec_p, type_noexcept_p, type_throw_all_p): Check
    	DEFERRED_NOEXCEPT_SPEC_P.
    	* typeck2.c (merge_exception_specifiers): Likewise.
    	* decl2.c (mark_used): Call maybe_instantiate_noexcept.
    	* method.c (process_subob_fn, defaulted_late_check): Likewise.
    	* pt.c (tsubst_exception_specification): Add defer_ok parm.
    	Build DEFERRED_NOEXCEPT.
    	(maybe_instantiate_noexcept): New.
    	(tsubst, regenerate_decl_from_template, instantiate_decl): Adjust.
    	* search.c (check_final_overrider): Call maybe_instantiate_noexcept.

diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c
index df6b1dd..1866b81 100644
--- a/gcc/cp/cp-objcp-common.c
+++ b/gcc/cp/cp-objcp-common.c
@@ -79,6 +79,7 @@  cp_tree_size (enum tree_code code)
     case BASELINK:		return sizeof (struct tree_baselink);
     case TEMPLATE_PARM_INDEX:	return sizeof (template_parm_index);
     case DEFAULT_ARG:		return sizeof (struct tree_default_arg);
+    case DEFERRED_NOEXCEPT:	return sizeof (struct tree_deferred_noexcept);
     case OVERLOAD:		return sizeof (struct tree_overload);
     case STATIC_ASSERT:         return sizeof (struct tree_static_assert);
     case TYPE_ARGUMENT_PACK:
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 001ef10..ce11417 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -214,6 +214,11 @@  DEFTREECODE (USING_STMT, "using_directive", tcc_statement, 1)
    parsing had occurred.  */
 DEFTREECODE (DEFAULT_ARG, "default_arg", tcc_exceptional, 0)
 
+/* An uninstantiated noexcept-specification.  DEFERRED_NOEXCEPT_PATTERN is
+   the pattern from the template, and DEFERRED_NOEXCEPT_ARGS are the
+   template arguments to substitute into the pattern when needed.  */
+DEFTREECODE (DEFERRED_NOEXCEPT, "deferred_noexcept", tcc_exceptional, 0)
+
 /* A template-id, like foo<int>.  The first operand is the template.
    The second is NULL if there are no explicit arguments, or a
    TREE_VEC of arguments.  The template will be a FUNCTION_DECL,
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 0395db7..71f7dd4 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -507,6 +507,22 @@  struct GTY (()) tree_default_arg {
   VEC(tree,gc) *instantiations;
 };
 
+
+#define DEFERRED_NOEXCEPT_PATTERN(NODE) \
+  (((struct tree_deferred_noexcept *)DEFERRED_NOEXCEPT_CHECK (NODE))->pattern)
+#define DEFERRED_NOEXCEPT_ARGS(NODE) \
+  (((struct tree_deferred_noexcept *)DEFERRED_NOEXCEPT_CHECK (NODE))->args)
+#define DEFERRED_NOEXCEPT_SPEC_P(NODE)				\
+  ((NODE) && (TREE_PURPOSE (NODE))				\
+   && TREE_CODE (TREE_PURPOSE (NODE)) == DEFERRED_NOEXCEPT)
+
+struct GTY (()) tree_deferred_noexcept {
+  struct tree_base base;
+  tree pattern;
+  tree args;
+};
+
+
 /* The condition associated with the static assertion.  This must be
    an integral constant expression.  */
 #define STATIC_ASSERT_CONDITION(NODE) \
@@ -693,6 +709,7 @@  enum cp_tree_node_structure_enum {
   TS_CP_BASELINK,
   TS_CP_WRAPPER,
   TS_CP_DEFAULT_ARG,
+  TS_CP_DEFERRED_NOEXCEPT,
   TS_CP_STATIC_ASSERT,
   TS_CP_ARGUMENT_PACK_SELECT,
   TS_CP_TRAIT_EXPR,
@@ -711,6 +728,7 @@  union GTY((desc ("cp_tree_node_structure (&%h)"),
   struct tree_overload GTY ((tag ("TS_CP_OVERLOAD"))) overload;
   struct tree_baselink GTY ((tag ("TS_CP_BASELINK"))) baselink;
   struct tree_default_arg GTY ((tag ("TS_CP_DEFAULT_ARG"))) default_arg;
+  struct tree_deferred_noexcept GTY ((tag ("TS_CP_DEFERRED_NOEXCEPT"))) deferred_noexcept;
   struct lang_identifier GTY ((tag ("TS_CP_IDENTIFIER"))) identifier;
   struct tree_static_assert GTY ((tag ("TS_CP_STATIC_ASSERT"))) 
     static_assertion;
@@ -5130,6 +5148,7 @@  extern int more_specialized_fn			(tree, tree, int);
 extern void do_decl_instantiation		(tree, tree);
 extern void do_type_instantiation		(tree, tree, tsubst_flags_t);
 extern bool always_instantiate_p		(tree);
+extern void maybe_instantiate_noexcept		(tree);
 extern tree instantiate_decl			(tree, int, bool);
 extern int comp_template_parms			(const_tree, const_tree);
 extern bool uses_parameter_packs                (tree);
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index 2f392de..c5f1ac0 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -1446,7 +1446,10 @@  pp_cxx_exception_specification (cxx_pretty_printer *pp, tree t)
       pp_cxx_ws_string (pp, "noexcept");
       pp_cxx_whitespace (pp);
       pp_cxx_left_paren (pp);
-      pp_cxx_expression (pp, TREE_PURPOSE (ex_spec));
+      if (DEFERRED_NOEXCEPT_SPEC_P (ex_spec))
+	pp_cxx_ws_string (pp, "<uninstantiated>");
+      else
+	pp_cxx_expression (pp, TREE_PURPOSE (ex_spec));
       pp_cxx_right_paren (pp);
       return;
     }
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 30f70d9..d7da390 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1784,6 +1784,9 @@  duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
       tree oldtype = TREE_TYPE (olddecl);
       tree newtype;
 
+      if (TREE_CODE (newdecl) == FUNCTION_DECL)
+	maybe_instantiate_noexcept (olddecl);
+
       /* Merge the data types specified in the two decls.  */
       newtype = merge_types (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
 
@@ -13665,6 +13668,7 @@  cp_tree_node_structure (union lang_tree_node * t)
   switch (TREE_CODE (&t->generic))
     {
     case DEFAULT_ARG:		return TS_CP_DEFAULT_ARG;
+    case DEFERRED_NOEXCEPT:	return TS_CP_DEFERRED_NOEXCEPT;
     case IDENTIFIER_NODE:	return TS_CP_IDENTIFIER;
     case OVERLOAD:		return TS_CP_OVERLOAD;
     case TEMPLATE_PARM_INDEX:	return TS_CP_TPI;
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 9005f7e..a0512cd 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -4228,6 +4228,9 @@  mark_used (tree decl)
       return;
     }
 
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    maybe_instantiate_noexcept (decl);
+
   /* Normally, we can wait until instantiation-time to synthesize DECL.
      However, if DECL is a static data member initialized with a constant
      or a constexpr function, we need it right now because a reference to
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index d9652dc..96796c2 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -1438,7 +1438,10 @@  dump_exception_spec (tree t, int flags)
       pp_cxx_ws_string (cxx_pp, "noexcept");
       pp_cxx_whitespace (cxx_pp);
       pp_cxx_left_paren (cxx_pp);
-      dump_expr (TREE_PURPOSE (t), flags);
+      if (DEFERRED_NOEXCEPT_SPEC_P (t))
+	pp_cxx_ws_string (cxx_pp, "<uninstantiated>");
+      else
+	dump_expr (TREE_PURPOSE (t), flags);
       pp_cxx_right_paren (cxx_pp);
     }
   else if (t)
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index 874f111..3399652 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -1160,6 +1160,7 @@  finish_noexcept_expr (tree expr, tsubst_flags_t complain)
 bool
 nothrow_spec_p (const_tree spec)
 {
+  gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (spec));
   if (spec == NULL_TREE
       || TREE_VALUE (spec) != NULL_TREE
       || spec == noexcept_false_spec)
@@ -1180,6 +1181,7 @@  bool
 type_noexcept_p (const_tree type)
 {
   tree spec = TYPE_RAISES_EXCEPTIONS (type);
+  gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (spec));
   if (flag_nothrow_opt)
     return nothrow_spec_p (spec);
   else
@@ -1193,6 +1195,7 @@  bool
 type_throw_all_p (const_tree type)
 {
   tree spec = TYPE_RAISES_EXCEPTIONS (type);
+  gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (spec));
   return spec == NULL_TREE || spec == noexcept_false_spec;
 }
 
@@ -1204,7 +1207,7 @@  build_noexcept_spec (tree expr, int complain)
 {
   /* This isn't part of the signature, so don't bother trying to evaluate
      it until instantiation.  */
-  if (!processing_template_decl)
+  if (!processing_template_decl && TREE_CODE (expr) != DEFERRED_NOEXCEPT)
     {
       expr = perform_implicit_conversion_flags (boolean_type_node, expr,
 						complain,
@@ -1219,7 +1222,8 @@  build_noexcept_spec (tree expr, int complain)
     return error_mark_node;
   else
     {
-      gcc_assert (processing_template_decl || expr == error_mark_node);
+      gcc_assert (processing_template_decl || expr == error_mark_node
+		  || TREE_CODE (expr) == DEFERRED_NOEXCEPT);
       return build_tree_list (expr, NULL_TREE);
     }
 }
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index cf35b4a..9188700 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -923,7 +923,9 @@  process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
 
   if (spec_p)
     {
-      tree raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
+      tree raises;
+      maybe_instantiate_noexcept (fn);
+      raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
       *spec_p = merge_exception_specifiers (*spec_p, raises);
     }
 
@@ -1558,7 +1560,9 @@  defaulted_late_check (tree fn)
      it had been implicitly declared.  */
   if (DECL_DEFAULTED_IN_CLASS_P (fn))
     {
-      tree eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn));
+      tree eh_spec;
+      maybe_instantiate_noexcept (fn);
+      eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn));
       if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn))
 	  && !comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)),
 				 eh_spec, ce_normal))
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 61ca31c..51d590e 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -10342,7 +10342,8 @@  static tree
 tsubst_exception_specification (tree fntype,
 				tree args,
 				tsubst_flags_t complain,
-				tree in_decl)
+				tree in_decl,
+				bool defer_ok)
 {
   tree specs;
   tree new_specs;
@@ -10352,9 +10353,33 @@  tsubst_exception_specification (tree fntype,
   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);
+      tree expr = TREE_PURPOSE (specs);
+      if (expr == boolean_true_node || expr == boolean_false_node)
+	new_specs = expr;
+      else if (defer_ok)
+	{
+	  /* Defer instantiation of noexcept-specifiers to avoid
+	     excessive instantiations (c++/49107).  */
+	  new_specs = make_node (DEFERRED_NOEXCEPT);
+	  if (DEFERRED_NOEXCEPT_SPEC_P (specs))
+	    {
+	      /* We already partially instantiated this member template,
+		 so combine the new args with the old.  */
+	      DEFERRED_NOEXCEPT_PATTERN (new_specs)
+		= DEFERRED_NOEXCEPT_PATTERN (expr);
+	      DEFERRED_NOEXCEPT_ARGS (new_specs)
+		= add_to_template_args (DEFERRED_NOEXCEPT_ARGS (expr), args);
+	    }
+	  else
+	    {
+	      DEFERRED_NOEXCEPT_PATTERN (new_specs) = expr;
+	      DEFERRED_NOEXCEPT_ARGS (new_specs) = args;
+	    }
+	}
+      else
+	new_specs = tsubst_copy_and_build
+	  (expr, args, complain, in_decl, /*function_p=*/false,
+	   /*integral_constant_expression_p=*/true);
       new_specs = build_noexcept_spec (new_specs, complain);
     }
   else if (specs)
@@ -10879,7 +10904,7 @@  tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 
 	/* Substitute the exception specification.  */
 	specs = tsubst_exception_specification (t, args, complain,
-						in_decl);
+						in_decl, /*defer_ok*/true);
 	if (specs == error_mark_node)
 	  return error_mark_node;
 	if (specs)
@@ -17159,7 +17184,8 @@  regenerate_decl_from_template (tree decl, tree tmpl)
 	args = get_innermost_template_args (args, parms_depth);
 
       specs = tsubst_exception_specification (TREE_TYPE (code_pattern),
-					      args, tf_error, NULL_TREE);
+					      args, tf_error, NULL_TREE,
+					      /*defer_ok*/false);
       if (specs)
 	TREE_TYPE (decl) = build_exception_variant (TREE_TYPE (decl),
 						    specs);
@@ -17324,6 +17350,46 @@  always_instantiate_p (tree decl)
 	      && decl_maybe_constant_var_p (decl)));
 }
 
+/* If FN has a noexcept-specifier that hasn't been instantiated yet,
+   instantiate it now, modifying TREE_TYPE (fn).  */
+
+void
+maybe_instantiate_noexcept (tree fn)
+{
+  tree fntype = TREE_TYPE (fn);
+  tree spec = TYPE_RAISES_EXCEPTIONS (fntype);
+  tree noex = NULL_TREE;
+  location_t saved_loc = input_location;
+  tree clone;
+
+  if (!DEFERRED_NOEXCEPT_SPEC_P (spec))
+    return;
+  noex = TREE_PURPOSE (spec);
+
+  push_tinst_level (fn);
+  push_access_scope (fn);
+  input_location = DECL_SOURCE_LOCATION (fn);
+  noex = tsubst_copy_and_build (DEFERRED_NOEXCEPT_PATTERN (noex),
+				DEFERRED_NOEXCEPT_ARGS (noex),
+				tf_warning_or_error, fn, /*function_p=*/false,
+				/*integral_constant_expression_p=*/true);
+  input_location = saved_loc;
+  pop_access_scope (fn);
+  pop_tinst_level ();
+  spec = build_noexcept_spec (noex, tf_warning_or_error);
+  if (spec == error_mark_node)
+    spec = noexcept_false_spec;
+  TREE_TYPE (fn) = build_exception_variant (fntype, spec);
+
+  FOR_EACH_CLONE (clone, fn)
+    {
+      if (TREE_TYPE (clone) == fntype)
+	TREE_TYPE (clone) = TREE_TYPE (fn);
+      else
+	TREE_TYPE (clone) = build_exception_variant (TREE_TYPE (clone), spec);
+    }
+}
+
 /* Produce the definition of D, a _DECL generated from a template.  If
    DEFER_OK is nonzero, then we don't have to actually do the
    instantiation now; we just have to do it sometime.  Normally it is
@@ -17460,6 +17526,9 @@  instantiate_decl (tree d, int defer_ok,
       SET_DECL_IMPLICIT_INSTANTIATION (d);
     }
 
+  if (TREE_CODE (d) == FUNCTION_DECL)
+    maybe_instantiate_noexcept (d);
+
   /* Recheck the substitutions to obtain any warning messages
      about ignoring cv qualifiers.  Don't do this for artificial decls,
      as it breaks the context-sensitive substitution for lambda op(). */
@@ -17477,7 +17546,7 @@  instantiate_decl (tree d, int defer_ok,
 	{
 	  tsubst (DECL_ARGUMENTS (gen), gen_args, tf_warning_or_error, d);
           tsubst_exception_specification (type, gen_args, tf_warning_or_error,
-                                          d);
+                                          d, /*defer_ok*/true);
 	  /* Don't simply tsubst the function type, as that will give
 	     duplicate warnings about poor parameter qualifications.
 	     The function arguments are the same as the decl_arguments
diff --git a/gcc/cp/ptree.c b/gcc/cp/ptree.c
index 5c9626e..fb05e13 100644
--- a/gcc/cp/ptree.c
+++ b/gcc/cp/ptree.c
@@ -227,6 +227,10 @@  cxx_print_xnode (FILE *file, tree node, int indent)
       indent_to (file, indent + 3);
       fprintf (file, "index %d", ARGUMENT_PACK_SELECT_INDEX (node));
       break;
+    case DEFERRED_NOEXCEPT:
+      print_node (file, "pattern", DEFERRED_NOEXCEPT_PATTERN (node), indent+4);
+      print_node (file, "args", DEFERRED_NOEXCEPT_ARGS (node), indent+4);
+      break;
     default:
       break;
     }
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index cf0b1a0..97f593c 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -1803,8 +1803,8 @@  check_final_overrider (tree overrider, tree basefn)
   tree base_type = TREE_TYPE (basefn);
   tree over_return = TREE_TYPE (over_type);
   tree base_return = TREE_TYPE (base_type);
-  tree over_throw = TYPE_RAISES_EXCEPTIONS (over_type);
-  tree base_throw = TYPE_RAISES_EXCEPTIONS (base_type);
+  tree over_throw, base_throw;
+
   int fail = 0;
 
   if (DECL_INVALID_OVERRIDER_P (overrider))
@@ -1888,6 +1888,11 @@  check_final_overrider (tree overrider, tree basefn)
     }
 
   /* Check throw specifier is at least as strict.  */
+  maybe_instantiate_noexcept (basefn);
+  maybe_instantiate_noexcept (overrider);
+  base_throw = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (basefn));
+  over_throw = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (overrider));
+
   if (!comp_except_specs (base_throw, over_throw, ce_derived))
     {
       error ("looser throw specifier for %q+#F", overrider);
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 025fe2d..5b988e9 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2340,6 +2340,13 @@  cp_tree_equal (tree t1, tree t2)
       /* Now compare operands as usual.  */
       break;
 
+    case DEFERRED_NOEXCEPT:
+      return (cp_tree_equal (DEFERRED_NOEXCEPT_PATTERN (t1),
+			     DEFERRED_NOEXCEPT_PATTERN (t2))
+	      && comp_template_args (DEFERRED_NOEXCEPT_ARGS (t1),
+				     DEFERRED_NOEXCEPT_ARGS (t2)));
+      break;
+
     default:
       break;
     }
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 4d5c21a..f291393 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1769,10 +1769,15 @@  merge_exception_specifiers (tree list, tree add)
     return list;
   else if (!add || add == noexcept_false_spec)
     return add;
+
+  /* We need to instantiate deferred noexcept before we get here.  */
+  gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (list)
+	      && !DEFERRED_NOEXCEPT_SPEC_P (add));
+
   /* For merging noexcept(true) and throw(), take the more recent one (LIST).
      Any other noexcept-spec should only be merged with an equivalent one.
      So the !TREE_VALUE code below is correct for all cases.  */
-  else if (!TREE_VALUE (add))
+  if (!TREE_VALUE (add))
     return list;
   else if (!TREE_VALUE (list))
     return add;
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept11.C b/gcc/testsuite/g++.dg/cpp0x/noexcept11.C
new file mode 100644
index 0000000..b7c64a6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept11.C
@@ -0,0 +1,53 @@ 
+// PR c++/49107
+// { dg-options -std=c++0x }
+
+template<typename _Tp>
+_Tp declval() noexcept;
+
+template<typename _Tp , typename = decltype(_Tp(declval<_Tp&&>()))>
+struct trait
+{
+  static const bool value=true;
+};
+
+template<class _T2>
+struct pair
+{
+  _T2 second;
+  void swap(pair& __p)
+    noexcept(trait<_T2>::value);
+};
+
+template < class R_ >
+struct Main
+{
+  Main() {}
+  Main(const typename R_::Sub1T& r) ;
+  Main(const typename R_::Sub2T& l) ;
+};
+
+template < class R_ >
+class Sub1
+{
+  typedef pair<typename R_::MainT> Rep;
+  Rep base;
+};
+
+template < class R_ >
+struct Sub2
+{
+  typedef pair<typename R_::MainT> Rep;
+  Rep base;
+};
+
+struct Kernel
+{
+  typedef Main<Kernel> MainT;
+  typedef Sub1<Kernel> Sub1T;
+  typedef Sub2<Kernel> Sub2T;
+};
+
+Main<Kernel> f()
+{
+  return Main<Kernel> ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept12.C b/gcc/testsuite/g++.dg/cpp0x/noexcept12.C
new file mode 100644
index 0000000..1fd1b03
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept12.C
@@ -0,0 +1,11 @@ 
+// Test that we handle merging with deferred noexcept.
+// { dg-options -std=c++0x }
+
+template <class U>
+struct O
+{
+  template <class T>
+  void f() noexcept(noexcept(T()));
+};
+
+template<> template<> void O<int>::f<int>() noexcept { }
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae11.C b/gcc/testsuite/g++.dg/cpp0x/sfinae11.C
index a3ffc34..117b08b 100644
--- a/gcc/testsuite/g++.dg/cpp0x/sfinae11.C
+++ b/gcc/testsuite/g++.dg/cpp0x/sfinae11.C
@@ -6,7 +6,7 @@  template<class T>
 T&& declval() noexcept;
 
 template< class T >
-inline void f1( T& x ) noexcept( noexcept( declval<T&>().foo() ) )
+inline void f1( T& x ) noexcept( noexcept( declval<T&>().foo() ) ) // { dg-error "Z" }
 {
   x.foo();
 }
@@ -21,7 +21,7 @@  inline void f2( T& x ) noexcept( Noexcept )
 
 // a common and trivial mistake
 template< class T >
-inline void f3( T& x ) noexcept( declval<T&>().foo() )
+inline void f3( T& x ) noexcept( declval<T&>().foo() ) // { dg-error "Z" }
 {
   x.foo();
 }
@@ -50,7 +50,7 @@  int main()
   static_assert(  noexcept( f2(y) ), "OK." );
   // static_assert(  noexcept( f3(y) ), "shall be ill-formed(OK)." );
 
-  static_assert(  noexcept( f1(z) ), "shall be ill-formed." ); // { dg-error "no match" }
+  noexcept( f1(z) );		// { dg-message "required" }
   static_assert(  noexcept( f2(z) ), "shall be ill-formed." ); // { dg-error "no match" }
-  static_assert( !noexcept( f3(z) ), "shall be ill-formed." ); // { dg-error "no match" }
+  noexcept( f3(z) );		// { dg-message "required" }
 }