]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
DR 1351 Represent the unevaluated exception specification of an implicitly declared...
authorJason Merrill <jason@redhat.com>
Tue, 29 Apr 2014 18:04:50 +0000 (14:04 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 29 Apr 2014 18:04:50 +0000 (14:04 -0400)
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.

From-SVN: r209907

17 files changed:
gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.def
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/except.c
gcc/cp/init.c
gcc/cp/method.c
gcc/cp/parser.c
gcc/cp/parser.h
gcc/cp/pt.c
gcc/cp/typeck.c
gcc/cp/typeck2.c
gcc/testsuite/g++.dg/cpp0x/nsdmi-defer6.C
gcc/testsuite/g++.dg/cpp0x/nsdmi-dr1397.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/nsdmi-eh1.C

index a5f3829d70516c3b740c9ee3916c7f6548540338..b2018255b1830816b13b891c4f46b36f296be5c4 100644 (file)
@@ -1,3 +1,33 @@
+2014-04-29  Jason Merrill  <jason@redhat.com>
+
+       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.
+
 2014-04-28  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/59120
index 334bfd5eee7b54d969a2c4db09883ed6e7e3918f..5cac488ee95c44ef7f5703d0993420a12346ed85 100644 (file)
@@ -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);
     }
 }
index 057e7ea5ef7ad32999d600086efe271b95a82fe8..b4a72d6e30af20745957a4168efd4f3ceec509fa 100644 (file)
@@ -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.
index f459e55bc84f991c0af45655be47063f353a93fb..55ecc4e5b5f970f56c4b23485b843ae2fadafd1c 100644 (file)
@@ -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);
index 7ce55c87d7791891c086146bdb32fca99fa31cde..202db35d3c85504e4fa72df5941047d4023448b4 100644 (file)
@@ -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;
index 8a7a8369f19a48b268347c30101907db2e87722d..918ea2fc6d08d5eac4455ef9e0ba22f36669c254 100644 (file)
@@ -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
index 221971ac95666efba8ca98b94e7c23387eb12eac..ead889c065824cb8cd3698d081c8b7d46290e8ce 100644 (file)
@@ -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 */
 
index fdc1011f1989e80c8aa6bc8a83a15759e6de1f51..8b9405c54edb97a536abd794e7b289b03160c9f9 100644 (file)
@@ -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;
index 11bff7f45878ece660410341cc9fdc71ce8b24f0..f8fc01ff531e129d0d886b5ed90e80661e8028f3 100644 (file)
@@ -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.  */
 
index 962cacedf80ae9d22f5e6df69e8bdf23b18412ba..5542dcd9ba38905aa4e719ad0b0e3420fcbcfa2d 100644 (file)
@@ -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 ();
index 758c6df3c27df7d024213c913e3dfc22df9f354e..96a84534045b6ff782502751f26acbe1f7692c9a 100644 (file)
@@ -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;
 
 
index c74e7ae7586088c1e56ca198e9d2b4ee3d718411..48cc2a9e9cf8ad2db4e37521a1c9a89c832e6518 100644 (file)
@@ -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
index 9a80727dd8e47dee4993fcaf0618654a9303e486..ae7fa776eb84023811b6ef4651bc9b9b5ba3ebf7 100644 (file)
@@ -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;
 
index 68e518a5c73e8e72fef76e0f3b0887a23fa9f0f3..5bbc2efd5e6689ac9bf734c66b33db27945f0f60 100644 (file)
@@ -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;
 
-  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))
+  /* 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;
-  else
-    gcc_checking_assert (!TREE_PURPOSE (add)
-                        || cp_tree_equal (noex, TREE_PURPOSE (add)));
+  noex = TREE_PURPOSE (list);
+  gcc_checking_assert (!TREE_PURPOSE (add)
+                      || cp_tree_equal (noex, TREE_PURPOSE (add)));
 
   /* Combine the dynamic-exception-specifiers, if any.  */
   orig_list = list;
index 033c14264dddef9e2124eb4c2006bf559a108b83..0f06343958b1275eec9292dcc972dceeea7b978e 100644 (file)
@@ -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 (file)
index 0000000..061af8b
--- /dev/null
@@ -0,0 +1,7 @@
+// DR 1397
+// { dg-require-effective-target c++11 }
+
+struct A
+{
+  int i = sizeof(A{});         // { dg-error "" }
+};
index edcf5887db14f1c67f405540e923d1b0c67152a3..9bc632c4bc7d89d00241a2f6b453c7c7189c6801 100644 (file)
@@ -1,5 +1,5 @@
 // Core issue 1351
-// { dg-do run { xfail *-*-* } }
+// { dg-do run }
 // { dg-require-effective-target c++11 }
 
 bool fail;