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