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 for DR 1351/1397 (implicit EH spec and NSDMI)


DR 1351 says that when calculating the implicit exception-specification for a defaulted default constructor, we need to consider whether an NSDMI could throw. Previously we have represented an uncalculated implicit eh-spec with a list of the subobject constructors that will be called, but that doesn't really extend to handling NSDMIs, so this patch replaces that representation with a simple token that just means "figure it out later".

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 73c6946ee42b364de9587ebd2e4137e064a815f3
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Feb 11 23:07:29 2014 -0800

    	DR 1351
    	Represent the unevaluated exception specification of an implicitly
    	declared or deleted function with a simple placeholder, not a list
    	of functions.
    	* cp-tree.h (UNEVALUATED_NOEXCEPT_SPEC_P): New.
    	* except.c (unevaluated_noexcept_spec): New.
    	* class.c (deduce_noexcept_on_destructor): Use it.
    	* decl.c (check_redeclaration_exception_specification): Call
    	maybe_instantiate_noexcept.
    	(duplicate_decls): Call it before merge_types.
    	(start_preparsed_function): Call maybe_instantiate_noexcept.
    	* decl2.c (mark_used): Call maybe_instantiate_noexcept earlier.
    	* init.c (get_nsdmi): Factor out of perform_member_init.
    	* method.c (process_subob_fn): Call maybe_instantiate_noexcept.
    	(walk_field_subobs): Consider NSDMI for EH spec.
    	(get_defaulted_eh_spec): New.
    	(implicitly_declare_fn): Use unevaluated_noexcept_spec.
    	(defaulted_late_check): Defer EH checking in non-template classes.
    	(after_nsdmi_defaulted_late_checks): New.
    	* parser.c (cp_parser_class_specifier_1): Use it.
    	(unparsed_classes): New macro.
    	* parser.h (cp_unparsed_functions_entry_d): Add classes field.
    	* pt.c (maybe_instantiate_noexcept): Use get_defaulted_eh_spec.
    	Remove list-of-functions handling.
    	* typeck2.c (merge_exception_specifiers): Remove list-of-functions
    	handling and FN parameter.
    	* typeck.c (merge_types): Adjust.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 334bfd5..5cac488 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4725,11 +4725,7 @@ deduce_noexcept_on_destructor (tree dtor)
 {
   if (!TYPE_RAISES_EXCEPTIONS (TREE_TYPE (dtor)))
     {
-      tree ctx = DECL_CONTEXT (dtor);
-      tree implicit_fn = implicitly_declare_fn (sfk_destructor, ctx,
-						/*const_p=*/false,
-						NULL, NULL);
-      tree eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn));
+      tree eh_spec = unevaluated_noexcept_spec ();
       TREE_TYPE (dtor) = build_exception_variant (TREE_TYPE (dtor), eh_spec);
     }
 }
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 057e7ea..b4a72d6 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -212,9 +212,12 @@ DEFTREECODE (USING_STMT, "using_stmt", 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.  */
+/* An uninstantiated/unevaluated noexcept-specification.  For the
+   uninstantiated case, DEFERRED_NOEXCEPT_PATTERN is the pattern from the
+   template, and DEFERRED_NOEXCEPT_ARGS are the template arguments to
+   substitute into the pattern when needed.  For the unevaluated case,
+   those slots are NULL_TREE and we use get_defaulted_eh_spec to find
+   the exception-specification.  */
 DEFTREECODE (DEFERRED_NOEXCEPT, "deferred_noexcept", tcc_exceptional, 0)
 
 /* A template-id, like foo<int>.  The first operand is the template.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f459e55..55ecc4e 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -579,8 +579,10 @@ struct GTY (()) tree_default_arg {
   (((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	\
-      || is_overloaded_fn (TREE_PURPOSE (NODE))))
+   && (TREE_CODE (TREE_PURPOSE (NODE)) == DEFERRED_NOEXCEPT))
+#define UNEVALUATED_NOEXCEPT_SPEC_P(NODE)				\
+  (DEFERRED_NOEXCEPT_SPEC_P (NODE)					\
+   && DEFERRED_NOEXCEPT_PATTERN (TREE_PURPOSE (NODE)) == NULL_TREE)
 
 struct GTY (()) tree_deferred_noexcept {
   struct tree_base base;
@@ -4359,8 +4361,6 @@ extern int comparing_specializations;
    sizeof can be nested.  */
 
 extern int cp_unevaluated_operand;
-extern tree cp_convert_range_for (tree, tree, tree, bool);
-extern bool parsing_nsdmi (void);
 
 /* in pt.c  */
 
@@ -5420,6 +5420,7 @@ extern tree get_type_value			(tree);
 extern tree build_zero_init			(tree, tree, bool);
 extern tree build_value_init			(tree, tsubst_flags_t);
 extern tree build_value_init_noctor		(tree, tsubst_flags_t);
+extern tree get_nsdmi				(tree, bool);
 extern tree build_offset_ref			(tree, tree, bool,
 						 tsubst_flags_t);
 extern tree throw_bad_array_new_length		(void);
@@ -5468,6 +5469,9 @@ extern tree make_thunk				(tree, bool, tree, tree);
 extern void finish_thunk			(tree);
 extern void use_thunk				(tree, bool);
 extern bool trivial_fn_p			(tree);
+extern tree get_defaulted_eh_spec		(tree);
+extern tree unevaluated_noexcept_spec		(void);
+extern void after_nsdmi_defaulted_late_checks   (tree);
 extern bool maybe_explain_implicit_delete	(tree);
 extern void explain_implicit_non_constexpr	(tree);
 extern void deduce_inheriting_ctor		(tree);
@@ -5489,6 +5493,11 @@ extern tree implicitly_declare_fn               (special_function_kind, tree,
 /* In optimize.c */
 extern bool maybe_clone_body			(tree);
 
+/* In parser.c */
+extern tree cp_convert_range_for (tree, tree, tree, bool);
+extern bool parsing_nsdmi (void);
+extern void inject_this_parameter (tree, cp_cv_quals);
+
 /* in pt.c */
 extern bool check_template_shadow		(tree);
 extern tree get_innermost_template_args		(tree, int);
@@ -6162,7 +6171,7 @@ extern tree build_x_arrow			(location_t, tree,
 extern tree build_m_component_ref		(tree, tree, tsubst_flags_t);
 extern tree build_functional_cast		(tree, tree, tsubst_flags_t);
 extern tree add_exception_specifier		(tree, tree, int);
-extern tree merge_exception_specifiers		(tree, tree, tree);
+extern tree merge_exception_specifiers		(tree, tree);
 
 /* in mangle.c */
 extern void init_mangle				(void);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 7ce55c8..202db35 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1167,15 +1167,18 @@ static void
 check_redeclaration_exception_specification (tree new_decl,
 					     tree old_decl)
 {
-  tree new_type;
-  tree old_type;
-  tree new_exceptions;
-  tree old_exceptions;
+  tree new_exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (new_decl));
+  tree old_exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (old_decl));
 
-  new_type = TREE_TYPE (new_decl);
-  new_exceptions = TYPE_RAISES_EXCEPTIONS (new_type);
-  old_type = TREE_TYPE (old_decl);
-  old_exceptions = TYPE_RAISES_EXCEPTIONS (old_type);
+  /* Two default specs are equivalent, don't force evaluation.  */
+  if (UNEVALUATED_NOEXCEPT_SPEC_P (new_exceptions)
+      && UNEVALUATED_NOEXCEPT_SPEC_P (old_exceptions))
+    return;
+
+  maybe_instantiate_noexcept (new_decl);
+  maybe_instantiate_noexcept (old_decl);
+  new_exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (new_decl));
+  old_exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (old_decl));
 
   /* [except.spec]
 
@@ -1915,13 +1918,13 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
 
   if (types_match)
     {
+      if (TREE_CODE (newdecl) == FUNCTION_DECL)
+	check_redeclaration_exception_specification (newdecl, olddecl);
+
       /* Automatically handles default parameters.  */
       tree oldtype = TREE_TYPE (olddecl);
       tree newtype;
 
-      if (TREE_CODE (newdecl) == FUNCTION_DECL)
-	maybe_instantiate_noexcept (olddecl);
-
       /* For typedefs use the old type, as the new type's DECL_NAME points
 	 at newdecl, which will be ggc_freed.  */
       if (TREE_CODE (newdecl) == TYPE_DECL)
@@ -1952,10 +1955,6 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
 	    }
 	}
 
-      /* Do this after calling `merge_types' so that default
-	 parameters don't confuse us.  */
-      else if (TREE_CODE (newdecl) == FUNCTION_DECL)
-	check_redeclaration_exception_specification (newdecl, olddecl);
       TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype;
 
       if (TREE_CODE (newdecl) == FUNCTION_DECL)
@@ -13435,6 +13434,9 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
   if (!DECL_CLONED_FUNCTION_P (decl1))
     determine_visibility (decl1);
 
+  if (!processing_template_decl)
+    maybe_instantiate_noexcept (decl1);
+
   begin_scope (sk_function_parms, decl1);
 
   ++function_depth;
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 8a7a836..918ea2f 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -4806,6 +4806,9 @@ mark_used (tree decl, tsubst_flags_t complain)
   if (TREE_CODE (decl) == CONST_DECL)
     used_types_insert (DECL_CONTEXT (decl));
 
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    maybe_instantiate_noexcept (decl);
+
   if (TREE_CODE (decl) == FUNCTION_DECL
       && DECL_DELETED_FN (decl))
     {
@@ -4860,9 +4863,6 @@ mark_used (tree decl, tsubst_flags_t complain)
       return true;
     }
 
-  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/except.c b/gcc/cp/except.c
index 221971a..ead889c 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -1342,6 +1342,18 @@ build_noexcept_spec (tree expr, int complain)
     }
 }
 
+/* Returns a noexcept-specifier to be evaluated later, for an
+   implicitly-declared or explicitly defaulted special member function.  */
+
+tree
+unevaluated_noexcept_spec (void)
+{
+  static tree spec;
+  if (spec == NULL_TREE)
+    spec = build_noexcept_spec (make_node (DEFERRED_NOEXCEPT), tf_none);
+  return spec;
+}
+
 /* Returns a TRY_CATCH_EXPR that will put TRY_LIST and CATCH_LIST in the
    TRY and CATCH locations.  CATCH_LIST must be a STATEMENT_LIST */
 
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index fdc1011..8b9405c 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -521,6 +521,45 @@ perform_target_ctor (tree init)
     }
 }
 
+/* Return the non-static data initializer for FIELD_DECL MEMBER.  */
+
+tree
+get_nsdmi (tree member, bool in_ctor)
+{
+  tree init;
+  tree save_ccp = current_class_ptr;
+  tree save_ccr = current_class_ref;
+  if (!in_ctor)
+    inject_this_parameter (DECL_CONTEXT (member), TYPE_UNQUALIFIED);
+  if (DECL_LANG_SPECIFIC (member) && DECL_TEMPLATE_INFO (member))
+    /* Do deferred instantiation of the NSDMI.  */
+    init = (tsubst_copy_and_build
+	    (DECL_INITIAL (DECL_TI_TEMPLATE (member)),
+	     DECL_TI_ARGS (member),
+	     tf_warning_or_error, member, /*function_p=*/false,
+	     /*integral_constant_expression_p=*/false));
+  else
+    {
+      init = DECL_INITIAL (member);
+      if (init && TREE_CODE (init) == DEFAULT_ARG)
+	{
+	  error ("constructor required before non-static data member "
+		 "for %qD has been parsed", member);
+	  DECL_INITIAL (member) = error_mark_node;
+	  init = NULL_TREE;
+	}
+      /* Strip redundant TARGET_EXPR so we don't need to remap it, and
+	 so the aggregate init code below will see a CONSTRUCTOR.  */
+      if (init && TREE_CODE (init) == TARGET_EXPR
+	  && !VOID_TYPE_P (TREE_TYPE (TARGET_EXPR_INITIAL (init))))
+	init = TARGET_EXPR_INITIAL (init);
+      init = break_out_target_exprs (init);
+    }
+  current_class_ptr = save_ccp;
+  current_class_ref = save_ccr;
+  return init;
+}
+
 /* Initialize MEMBER, a FIELD_DECL, with INIT, a TREE_LIST of
    arguments.  If TREE_LIST is void_type_node, an empty initializer
    list was given; if NULL_TREE no initializer was given.  */
@@ -534,31 +573,7 @@ perform_member_init (tree member, tree init)
   /* Use the non-static data member initializer if there was no
      mem-initializer for this field.  */
   if (init == NULL_TREE)
-    {
-      if (DECL_LANG_SPECIFIC (member) && DECL_TEMPLATE_INFO (member))
-	/* Do deferred instantiation of the NSDMI.  */
-	init = (tsubst_copy_and_build
-		(DECL_INITIAL (DECL_TI_TEMPLATE (member)),
-		 DECL_TI_ARGS (member),
-		 tf_warning_or_error, member, /*function_p=*/false,
-		 /*integral_constant_expression_p=*/false));
-      else
-	{
-	  init = DECL_INITIAL (member);
-	  if (init && TREE_CODE (init) == DEFAULT_ARG)
-	    {
-	      error ("constructor required before non-static data member "
-		     "for %qD has been parsed", member);
-	      init = NULL_TREE;
-	    }
-	  /* Strip redundant TARGET_EXPR so we don't need to remap it, and
-	     so the aggregate init code below will see a CONSTRUCTOR.  */
-	  if (init && TREE_CODE (init) == TARGET_EXPR
-	      && !VOID_TYPE_P (TREE_TYPE (TARGET_EXPR_INITIAL (init))))
-	    init = TARGET_EXPR_INITIAL (init);
-	  init = break_out_target_exprs (init);
-	}
-    }
+    init = get_nsdmi (member, /*ctor*/true);
 
   if (init == error_mark_node)
     return;
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 11bff7f..f8fc01f 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1003,8 +1003,9 @@ process_subob_fn (tree fn, tree *spec_p, bool *trivial_p,
 
   if (spec_p)
     {
+      maybe_instantiate_noexcept (fn);
       tree raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
-      *spec_p = merge_exception_specifiers (*spec_p, raises, fn);
+      *spec_p = merge_exception_specifiers (*spec_p, raises);
     }
 
   if (!trivial_fn_p (fn))
@@ -1090,17 +1091,14 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
 		inform (0, "initializer for %q+#D is invalid", field);
 	      if (trivial_p)
 		*trivial_p = false;
-#if 0
 	      /* Core 1351: If the field has an NSDMI that could throw, the
-		 default constructor is noexcept(false).  FIXME this is
-		 broken by deferred parsing and 1360 saying we can't lazily
-		 declare a non-trivial default constructor.  Also this
-		 needs to do deferred instantiation.  Disable until the
-		 conflict between 1351 and 1360 is resolved.  */
-	      if (spec_p && !expr_noexcept_p (DECL_INITIAL (field), complain))
-		*spec_p = noexcept_false_spec;
-#endif
-
+		 default constructor is noexcept(false).  */
+	      if (spec_p)
+		{
+		  tree nsdmi = get_nsdmi (field, /*ctor*/false);
+		  if (!expr_noexcept_p (nsdmi, complain))
+		    *spec_p = noexcept_false_spec;
+		}
 	      /* Don't do the normal processing.  */
 	      continue;
 	    }
@@ -1438,6 +1436,26 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
   --c_inhibit_evaluation_warnings;
 }
 
+/* DECL is a defaulted function whose exception specification is now
+   needed.  Return what it should be.  */
+
+tree
+get_defaulted_eh_spec (tree decl)
+{
+  if (DECL_CLONED_FUNCTION_P (decl))
+    decl = DECL_CLONED_FUNCTION (decl);
+  special_function_kind sfk = special_function_p (decl);
+  tree ctype = DECL_CONTEXT (decl);
+  tree parms = FUNCTION_FIRST_USER_PARMTYPE (decl);
+  tree parm_type = TREE_VALUE (parms);
+  bool const_p = CP_TYPE_CONST_P (non_reference (parm_type));
+  tree spec = empty_except_spec;
+  synthesized_method_walk (ctype, sfk, const_p, &spec, NULL, NULL,
+			   NULL, false, DECL_INHERITED_CTOR_BASE (decl),
+			   parms);
+  return spec;
+}
+
 /* DECL is a deleted function.  If it's implicitly deleted, explain why and
    return true; else return false.  */
 
@@ -1675,6 +1693,13 @@ implicitly_declare_fn (special_function_kind kind, tree type,
       deleted_p = DECL_DELETED_FN (inherited_ctor);
       constexpr_p = DECL_DECLARED_CONSTEXPR_P (inherited_ctor);
     }
+  else if (cxx_dialect >= cxx11)
+    {
+      raises = unevaluated_noexcept_spec ();
+      synthesized_method_walk (type, kind, const_p, NULL, &trivial_p,
+			       &deleted_p, &constexpr_p, false,
+			       inherited_base, inherited_parms);
+    }
   else
     synthesized_method_walk (type, kind, const_p, &raises, &trivial_p,
 			     &deleted_p, &constexpr_p, false,
@@ -1826,25 +1851,33 @@ defaulted_late_check (tree fn)
      is explicitly defaulted on its first declaration, (...) it is
      implicitly considered to have the same exception-specification as if
      it had been implicitly declared.  */
-  if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)))
+  tree fn_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
+  if (!fn_spec)
     {
-      maybe_instantiate_noexcept (fn);
-      if (!comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)),
-			      eh_spec, ce_normal))
+      if (DECL_DEFAULTED_IN_CLASS_P (fn))
+	TREE_TYPE (fn) = build_exception_variant (TREE_TYPE (fn), eh_spec);
+    }
+  else if (UNEVALUATED_NOEXCEPT_SPEC_P (fn_spec))
+    /* Equivalent to the implicit spec.  */;
+  else if (DECL_DEFAULTED_IN_CLASS_P (fn)
+	   && !CLASSTYPE_TEMPLATE_INSTANTIATION (ctx))
+    /* We can't compare an explicit exception-specification on a
+       constructor defaulted in the class body to the implicit
+       exception-specification until after we've parsed any NSDMI; see
+       after_nsdmi_defaulted_late_checks.  */;
+  else
+    {
+      tree eh_spec = get_defaulted_eh_spec (fn);
+      if (!comp_except_specs (fn_spec, eh_spec, ce_normal))
 	{
 	  if (DECL_DEFAULTED_IN_CLASS_P (fn))
-	    {
-	      DECL_DELETED_FN (fn) = true;
-	      eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
-	    }
+	    DECL_DELETED_FN (fn) = true;
 	  else
 	    error ("function %q+D defaulted on its redeclaration "
 		   "with an exception-specification that differs from "
-		   "the implicit declaration %q#D", fn, implicit_fn);
+		   "the implicit exception-specification %qX", fn, eh_spec);
 	}
     }
-  if (DECL_DEFAULTED_IN_CLASS_P (fn))
-    TREE_TYPE (fn) = build_exception_variant (TREE_TYPE (fn), eh_spec);
 
   if (DECL_DEFAULTED_IN_CLASS_P (fn)
       && DECL_DECLARED_CONSTEXPR_P (implicit_fn))
@@ -1874,6 +1907,30 @@ defaulted_late_check (tree fn)
     DECL_DELETED_FN (fn) = 1;
 }
 
+/* OK, we've parsed the NSDMI for class T, now we can check any explicit
+   exception-specifications on functions defaulted in the class body.  */
+
+void
+after_nsdmi_defaulted_late_checks (tree t)
+{
+  if (uses_template_parms (t))
+    return;
+  if (t == error_mark_node)
+    return;
+  for (tree fn = TYPE_METHODS (t); fn; fn = DECL_CHAIN (fn))
+    if (!DECL_ARTIFICIAL (fn) && DECL_DEFAULTED_IN_CLASS_P (fn))
+      {
+	tree fn_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
+	if (UNEVALUATED_NOEXCEPT_SPEC_P (fn_spec))
+	  continue;
+
+	tree eh_spec = get_defaulted_eh_spec (fn);
+	if (!comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)),
+				eh_spec, ce_normal))
+	  DECL_DELETED_FN (fn) = true;
+      }
+}
+
 /* Returns true iff FN can be explicitly defaulted, and gives any
    errors if defaulting FN is ill-formed.  */
 
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 962cace..5542dcd 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1848,11 +1848,13 @@ cp_parser_context_new (cp_parser_context* next)
   parser->unparsed_queues->last ().funs_with_definitions
 #define unparsed_nsdmis \
   parser->unparsed_queues->last ().nsdmis
+#define unparsed_classes \
+  parser->unparsed_queues->last ().classes
 
 static void
 push_unparsed_function_queues (cp_parser *parser)
 {
-  cp_unparsed_functions_entry e = {NULL, make_tree_vector (), NULL};
+  cp_unparsed_functions_entry e = {NULL, make_tree_vector (), NULL, NULL};
   vec_safe_push (parser->unparsed_queues, e);
 }
 
@@ -17834,7 +17836,7 @@ cp_parser_virt_specifier_seq_opt (cp_parser* parser)
 /* Used by handling of trailing-return-types and NSDMI, in which 'this'
    is in scope even though it isn't real.  */
 
-static void
+void
 inject_this_parameter (tree ctype, cp_cv_quals quals)
 {
   tree this_parm;
@@ -19505,6 +19507,13 @@ cp_parser_class_specifier_1 (cp_parser* parser)
       current_class_ref = save_ccr;
       if (pushed_scope)
 	pop_scope (pushed_scope);
+
+      /* Now do some post-NSDMI bookkeeping.  */
+      FOR_EACH_VEC_SAFE_ELT (unparsed_classes, ix, class_type)
+	after_nsdmi_defaulted_late_checks (class_type);
+      vec_safe_truncate (unparsed_classes, 0);
+      after_nsdmi_defaulted_late_checks (type);
+
       /* Now parse the body of the functions.  */
       if (flag_openmp)
 	{
@@ -19521,6 +19530,8 @@ cp_parser_class_specifier_1 (cp_parser* parser)
 	  cp_parser_late_parsing_for_member (parser, decl);
       vec_safe_truncate (unparsed_funs_with_definitions, 0);
     }
+  else
+    vec_safe_push (unparsed_classes, type);
 
   /* Put back any saved access checks.  */
   pop_deferring_access_checks ();
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 758c6df..96a8453 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -149,7 +149,7 @@ typedef struct GTY(()) cp_default_arg_entry_d {
 } cp_default_arg_entry;
 
 
-/* An entry in a stack for member functions of local classes.  */
+/* An entry in a stack for member functions defined within their classes.  */
 
 typedef struct GTY(()) cp_unparsed_functions_entry_d {
   /* Functions with default arguments that require post-processing.
@@ -163,6 +163,10 @@ typedef struct GTY(()) cp_unparsed_functions_entry_d {
   /* Non-static data members with initializers that require post-processing.
      FIELD_DECLs appear in this list in declaration order.  */
   vec<tree, va_gc> *nsdmis;
+
+  /* Nested classes go in this vector, so that we can do some final
+     processing after parsing any NSDMIs.  */
+  vec<tree, va_gc> *classes;
 } cp_unparsed_functions_entry;
 
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index c74e7ae..48cc2a9 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -19470,14 +19470,16 @@ maybe_instantiate_noexcept (tree fn)
   fntype = TREE_TYPE (fn);
   spec = TYPE_RAISES_EXCEPTIONS (fntype);
 
-  if (!DEFERRED_NOEXCEPT_SPEC_P (spec))
+  if (!spec || !TREE_PURPOSE (spec))
     return;
 
   noex = TREE_PURPOSE (spec);
 
   if (TREE_CODE (noex) == DEFERRED_NOEXCEPT)
     {
-      if (push_tinst_level (fn))
+      if (DEFERRED_NOEXCEPT_PATTERN (noex) == NULL_TREE)
+	spec = get_defaulted_eh_spec (fn);
+      else if (push_tinst_level (fn))
 	{
 	  push_access_scope (fn);
 	  push_deferring_access_checks (dk_no_deferred);
@@ -19496,24 +19498,9 @@ maybe_instantiate_noexcept (tree fn)
 	}
       else
 	spec = noexcept_false_spec;
-    }
-  else
-    {
-      /* This is an implicitly declared function, so NOEX is a list of
-	 other functions to evaluate and merge.  */
-      tree elt;
-      spec = noexcept_true_spec;
-      for (elt = noex; elt; elt = OVL_NEXT (elt))
-	{
-	  tree fn = OVL_CURRENT (elt);
-	  tree subspec;
-	  maybe_instantiate_noexcept (fn);
-	  subspec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
-	  spec = merge_exception_specifiers (spec, subspec, NULL_TREE);
-	}
-    }
 
-  TREE_TYPE (fn) = build_exception_variant (fntype, spec);
+      TREE_TYPE (fn) = build_exception_variant (fntype, spec);
+    }
 
   FOR_EACH_CLONE (clone, fn)
     {
@@ -19664,9 +19651,6 @@ instantiate_decl (tree d, int defer_ok,
       SET_DECL_IMPLICIT_INSTANTIATION (d);
     }
 
-  if (TREE_CODE (d) == FUNCTION_DECL)
-    maybe_instantiate_noexcept (d);
-
   /* Defer all other templates, unless we have been explicitly
      forbidden from doing so.  */
   if (/* If there is no definition, we cannot instantiate the
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 9a80727..ae7fa77 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -840,8 +840,7 @@ merge_types (tree t1, tree t2)
 				  type_memfn_quals (t1),
 				  type_memfn_rqual (t1));
 	raises = merge_exception_specifiers (TYPE_RAISES_EXCEPTIONS (t1),
-					     TYPE_RAISES_EXCEPTIONS (t2),
-					     NULL_TREE);
+					     TYPE_RAISES_EXCEPTIONS (t2));
 	t1 = build_exception_variant (rval, raises);
 	break;
       }
@@ -852,8 +851,7 @@ merge_types (tree t1, tree t2)
 	   is just the main variant of this.  */
 	tree basetype = class_of_this_parm (t2);
 	tree raises = merge_exception_specifiers (TYPE_RAISES_EXCEPTIONS (t1),
-						  TYPE_RAISES_EXCEPTIONS (t2),
-						  NULL_TREE);
+						  TYPE_RAISES_EXCEPTIONS (t2));
 	cp_ref_qualifier rqual = type_memfn_rqual (t1);
 	tree t3;
 
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 68e518a..5bbc2efd 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1989,10 +1989,10 @@ nothrow_spec_p_uninst (const_tree spec)
 }
 
 /* Combine the two exceptions specifier lists LIST and ADD, and return
-   their union.  If FN is non-null, it's the source of ADD.  */
+   their union.  */
 
 tree
-merge_exception_specifiers (tree list, tree add, tree fn)
+merge_exception_specifiers (tree list, tree add)
 {
   tree noex, orig_list;
 
@@ -2008,22 +2008,18 @@ merge_exception_specifiers (tree list, tree add, tree fn)
   if (nothrow_spec_p_uninst (add))
     return list;
 
+  /* Two implicit noexcept specs (e.g. on a destructor) are equivalent.  */
+  if (UNEVALUATED_NOEXCEPT_SPEC_P (add)
+      && UNEVALUATED_NOEXCEPT_SPEC_P (list))
+    return list;
+  /* We should have instantiated other deferred noexcept specs by now.  */
+  gcc_assert (!DEFERRED_NOEXCEPT_SPEC_P (add));
+
+  if (nothrow_spec_p_uninst (list))
+    return add;
   noex = TREE_PURPOSE (list);
-  if (DEFERRED_NOEXCEPT_SPEC_P (add))
-    {
-      /* If ADD is a deferred noexcept, we must have been called from
-	 process_subob_fn.  For implicitly declared functions, we build up
-	 a list of functions to consider at instantiation time.  */
-      if (noex && operand_equal_p (noex, boolean_true_node, 0))
-	noex = NULL_TREE;
-      gcc_assert (fn && (!noex || is_overloaded_fn (noex)));
-      noex = build_overload (fn, noex);
-    }
-  else if (nothrow_spec_p_uninst (list))
-    return add;
-  else
-    gcc_checking_assert (!TREE_PURPOSE (add)
-			 || cp_tree_equal (noex, TREE_PURPOSE (add)));
+  gcc_checking_assert (!TREE_PURPOSE (add)
+		       || cp_tree_equal (noex, TREE_PURPOSE (add)));
 
   /* Combine the dynamic-exception-specifiers, if any.  */
   orig_list = list;
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer6.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer6.C
index 033c142..0f06343 100644
--- a/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer6.C
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-defer6.C
@@ -1,8 +1,8 @@
 // { dg-do compile { target c++11 } }
 
-struct A			// { dg-error "non-static data member" }
+struct A
 {
-  int i = (A(), 42);		// { dg-message "required here" }
+  int i = (A(), 42);		// { dg-error "constructor required" }
 };
 
 A a;
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-dr1397.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-dr1397.C
new file mode 100644
index 0000000..061af8b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-dr1397.C
@@ -0,0 +1,7 @@
+// DR 1397
+// { dg-require-effective-target c++11 }
+
+struct A
+{
+  int i = sizeof(A{});		// { dg-error "" }
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-eh1.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-eh1.C
index edcf588..9bc632c 100644
--- a/gcc/testsuite/g++.dg/cpp0x/nsdmi-eh1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-eh1.C
@@ -1,5 +1,5 @@
 // Core issue 1351
-// { dg-do run { xfail *-*-* } }
+// { dg-do run }
 // { dg-require-effective-target c++11 }
 
 bool fail;

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