diff options
author | Jason Merrill <jason@redhat.com> | 2010-06-04 17:21:23 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2010-06-04 17:21:23 -0400 |
commit | 3a55fb4c89d4489cd21a8efde78a6f0de2e72099 (patch) | |
tree | 45574d319c9bf599a6b62ec4994fe09f77d4a51b /gcc | |
parent | 0a766368bd6e51459bfd334086cc04af48f91f08 (diff) | |
download | gcc-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/ChangeLog | 24 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 24 | ||||
-rw-r--r-- | gcc/cp/cxx-pretty-print.c | 11 | ||||
-rw-r--r-- | gcc/cp/decl.c | 48 | ||||
-rw-r--r-- | gcc/cp/error.c | 18 | ||||
-rw-r--r-- | gcc/cp/except.c | 61 | ||||
-rw-r--r-- | gcc/cp/name-lookup.c | 2 | ||||
-rw-r--r-- | gcc/cp/parser.c | 39 | ||||
-rw-r--r-- | gcc/cp/pt.c | 10 | ||||
-rw-r--r-- | gcc/cp/search.c | 2 | ||||
-rw-r--r-- | gcc/cp/tree.c | 20 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 45 | ||||
-rw-r--r-- | gcc/cp/typeck2.c | 7 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/noexcept02.C | 52 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/noexcept03.C | 68 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/noexcept04.C | 31 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/noexcept05.C | 19 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/eh/spec8.C | 4 |
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" } }; |