]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Implement noexcept-specification (15.4)
authorJason Merrill <jason@redhat.com>
Fri, 4 Jun 2010 21:21:23 +0000 (17:21 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 4 Jun 2010 21:21:23 +0000 (17:21 -0400)
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.

From-SVN: r160298

19 files changed:
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/cxx-pretty-print.c
gcc/cp/decl.c
gcc/cp/error.c
gcc/cp/except.c
gcc/cp/name-lookup.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/search.c
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/cp/typeck2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/noexcept02.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/noexcept03.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/noexcept04.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/noexcept05.C [new file with mode: 0644]
gcc/testsuite/g++.dg/eh/spec8.C

index 0c11af7d32cf030a143254fc56b3b856cb66ec05..958481083864bc19e9d8a4d709b896f952b6cbb0 100644 (file)
@@ -1,5 +1,29 @@
 2010-06-04  Jason Merrill  <jason@redhat.com>
 
+       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.
+
        Implement noexcept operator (5.3.7)
        * cp-tree.def (NOEXCEPT_EXPR): New.
        * except.c (check_noexcept_r, finish_noexcept_expr): New.
index e48e4690c028f68ef4218fcd4e3f1cf30343935c..6b292b66f7316dc039ad47e1a6734604da83386d 100644 (file)
@@ -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);
index 04a83140ad9bbe65090e4ab93a144bd686a42a9d..e6c68ba5ddb55b9933990ead51f817d83c389591 100644 (file)
@@ -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))
index 82182623e95b84e8c7d499dd4f733547eec5d5a2..ef00a11b21b3e6093556c909defc686a876c684e 100644 (file)
@@ -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.  */
index 381163b2daf6148141a15417a9789d46ebd49bd5..d535f05a54d89b185a1646268d654b15073bac87 100644 (file)
@@ -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);
index 76731f44702a79e11f84d12385f4b407e7e72523..7be760e18c0b6db79609d932f1a437fcfa6c7451 100644 (file)
@@ -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);
+    }
+}
index 936c25638e0bba3141d5adcb3d2cfe77611d8f18..3236b64e73c687da1a436fe07bb4062527ef9abc 100644 (file)
@@ -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);
index 32e86e911661cf2047b0f8a3e1426ee1c4a1db4c..a33330ce566595eab18ff9daa4035b41309782d3 100644 (file)
@@ -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
index 0d58035e271faa2d29f378024a5e3bb8f48e56a2..4c98bf276ede55b62944cfcca29aa5ee75c60350 100644 (file)
@@ -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;
index 4843855bf70e4ec1ad6ac919badc34c425ca8953..e30882116bb2f00d8ef6a5870f7d48edc9225ed4 100644 (file)
@@ -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);
index c4b9dd5b5fb7bb3b422b3c24b839812a1790e34c..7d0e4765cd158ede1a83b4730f4b804178ad3073 100644 (file)
@@ -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
index a00908e5c3813957490e7c6381583f168993df53..26ffe1cc416e732d960e531b8ade1df2471b7bca 100644 (file)
@@ -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
index 7603ead5463fee99d4b51f5f9448d10ec9d29e95..93ea70d3808fd99d4cbcdd57d7a1c782fc30ce1f 100644 (file)
@@ -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))
index 3eb8e2d84cce39c52b29a53998c66298987b9d05..7fe8c5010cd057ab71c3058a0fde1b4b4b36271d 100644 (file)
@@ -1,6 +1,10 @@
 2010-06-04  Jason Merrill  <jason@redhat.com>
 
        * g++.dg/cpp0x/noexcept01.C: New.
+       * g++.dg/cpp0x/noexcept02.C: New.
+       * g++.dg/cpp0x/noexcept03.C: New.
+       * g++.dg/cpp0x/noexcept04.C: New.
+       * g++.dg/cpp0x/noexcept05.C: New.
 
 2010-06-04  Jakub Jelinek  <jakub@redhat.com>
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept02.C b/gcc/testsuite/g++.dg/cpp0x/noexcept02.C
new file mode 100644 (file)
index 0000000..be6fa00
--- /dev/null
@@ -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 (file)
index 0000000..d992245
--- /dev/null
@@ -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 (file)
index 0000000..8df8186
--- /dev/null
@@ -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 (file)
index 0000000..6acea43
--- /dev/null
@@ -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();
+}
index 7a35e6e807217d969a08e855b78d83f89b18542d..72dadff2257d29998b15a90910a46f2132c18b25 100644 (file)
@@ -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" }
 };