From 51dc660315ef83dcb907f3bd3a0a56abb9efed7a Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 7 Nov 2016 18:09:29 -0500 Subject: [PATCH] Implement P0012R1, Make exception specifications part of the type system. gcc/cp/ * cp-tree.h (enum tsubst_flags): Add tf_fndecl_type. (flag_noexcept_type, ce_type): New. * call.c (build_conv): Add ck_fnptr. (enum conversion_kind): Change ck_tsafe to ck_fnptr. (convert_like_real): Likewise. (standard_conversion): Likewise. Allow function pointer conversions for pointers to member functions. (reference_compatible_p): Allow function pointer conversions. (direct_reference_binding): Likewise. (reference_binding): Reference-compatible is no longer a subset of reference-related. (is_subseq): Also strip ck_lvalue after next_conversion. * class.c (instantiate_type): Check fnptr_conv_p. (resolve_address_of_overloaded_function): Likewise. * cvt.c (can_convert_tx_safety): Now static. (noexcept_conv_p, fnptr_conv_p, strip_fnptr_conv): New. * decl.c (flag_noexcept_type): Define. (cxx_init_decl_processing): Set it. (bad_specifiers): Check it. (grokdeclarator) [cdk_function]: Add exception-spec to type here. * lambda.c (maybe_add_lambda_conv_op): Add exception-spec to returned pointer. * mangle.c (struct globals): Add need_cxx1z_warning. (mangle_decl): Check it. (write_exception_spec): New. (write_function_type): Call it. (canonicalize_for_substitution): Handle exception spec. (write_type): Likewise. (write_encoding): Set processing_template_decl across mangling of partially-instantiated type. * pt.c (determine_specialization): Pass tf_fndecl_type. (tsubst_decl, fn_type_unification): Likewise. (tsubst): Strip tf_fndecl_type, pass it to tsubst_exception_specification. (convert_nontype_argument_function): Handle function pointer conversion. (convert_nontype_argument): Likewise. (unify, for_each_template_parm_r): Walk into noexcept-specifier. * rtti.c (ptr_initializer): Encode noexcept. * tree.c (canonical_eh_spec): New. (build_exception_variant): Use it. * typeck.c (composite_pointer_type): Handle fnptr conversion. (comp_except_specs): Compare canonical EH specs. (structural_comptypes): Call it. gcc/c-family/ * c.opt (Wc++1z-compat): New. * c-cppbuiltin.c (c_cpp_builtins): Add __cpp_noexcept_function_type. libstdc++-v3/ * include/bits/c++config (_GLIBCXX_NOEXCEPT_PARM) (_GLIBCXX_NOEXCEPT_QUAL): New. * include/std/type_traits (is_function): Use them. * libsubc++/new (launder): Likewise. * libsupc++/cxxabi.h (__pbase_type_info::__masks): Add __noexcept_mask. * libsupc++/pbase_type_info.cc (__do_catch): Handle function pointer conversion. libiberty/ * cp-demangle.c (is_fnqual_component_type): New. (d_encoding, d_print_comp_inner, d_print_mod_list): Use it. (FNQUAL_COMPONENT_CASE): New. (d_make_comp, has_return_type, d_print_comp_inner) (d_print_function_type): Use it. (next_is_type_qual): New. (d_cv_qualifiers, d_print_mod): Handle noexcept and throw-spec. include/ * demangle.h (enum demangle_component_type): Add DEMANGLE_COMPONENT_NOEXCEPT, DEMANGLE_COMPONENT_THROW_SPEC. From-SVN: r241944 --- gcc/c-family/ChangeLog | 5 + gcc/c-family/c-cppbuiltin.c | 1 + gcc/c-family/c.opt | 7 + gcc/cp/ChangeLog | 47 +++++ gcc/cp/call.c | 77 ++++---- gcc/cp/class.c | 14 +- gcc/cp/cp-tree.h | 12 +- gcc/cp/cvt.c | 77 +++++++- gcc/cp/decl.c | 11 +- gcc/cp/lambda.c | 3 + gcc/cp/mangle.c | 71 ++++++- gcc/cp/pt.c | 53 ++++- gcc/cp/rtti.c | 8 + gcc/cp/tree.c | 40 ++++ gcc/cp/typeck.c | 47 +++-- gcc/doc/invoke.texi | 5 + gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C | 6 + gcc/testsuite/g++.dg/cpp1z/noexcept-type1.C | 8 + gcc/testsuite/g++.dg/cpp1z/noexcept-type11.C | 3 + gcc/testsuite/g++.dg/cpp1z/noexcept-type12.C | 23 +++ gcc/testsuite/g++.dg/cpp1z/noexcept-type2.C | 10 + gcc/testsuite/g++.dg/cpp1z/noexcept-type3.C | 13 ++ gcc/testsuite/g++.dg/cpp1z/noexcept-type4.C | 16 ++ gcc/testsuite/g++.dg/cpp1z/noexcept-type5.C | 25 +++ gcc/testsuite/g++.dg/cpp1z/noexcept-type6.C | 13 ++ gcc/testsuite/g++.dg/cpp1z/noexcept-type7.C | 14 ++ gcc/testsuite/g++.dg/cpp1z/noexcept-type8.C | 22 +++ gcc/testsuite/g++.dg/cpp1z/noexcept-type9.C | 18 ++ gcc/testsuite/g++.dg/eh/spec2.C | 6 +- gcc/testsuite/g++.old-deja/g++.eh/spec7.C | 2 +- include/ChangeLog | 5 + include/demangle.h | 4 +- libiberty/ChangeLog | 10 + libiberty/cp-demangle.c | 181 +++++++++++------- libiberty/testsuite/demangle-expected | 10 + libstdc++-v3/ChangeLog | 11 ++ libstdc++-v3/include/bits/c++config | 8 + libstdc++-v3/include/std/type_traits | 96 +++++----- libstdc++-v3/libsupc++/cxxabi.h | 3 +- libstdc++-v3/libsupc++/new | 8 +- libstdc++-v3/libsupc++/pbase_type_info.cc | 13 +- .../ext/profile/mutex_extensions_neg.cc | 2 +- 42 files changed, 801 insertions(+), 207 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1z/noexcept-type1.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/noexcept-type11.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/noexcept-type12.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/noexcept-type2.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/noexcept-type3.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/noexcept-type4.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/noexcept-type5.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/noexcept-type6.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/noexcept-type7.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/noexcept-type8.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/noexcept-type9.C diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 39e6de147df0..5207c34c912a 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2016-11-07 Jason Merrill + + * c.opt (Wc++1z-compat): New. + * c-cppbuiltin.c (c_cpp_builtins): Add __cpp_noexcept_function_type. + 2016-11-07 Martin Liska * c-warn.c (warn_for_unused_label): Save all labels used diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c index e40fa6ff9dc4..55dbf44d34f6 100644 --- a/gcc/c-family/c-cppbuiltin.c +++ b/gcc/c-family/c-cppbuiltin.c @@ -941,6 +941,7 @@ c_cpp_builtins (cpp_reader *pfile) cpp_define (pfile, "__cpp_inline_variables=201606"); cpp_define (pfile, "__cpp_aggregate_bases=201603"); cpp_define (pfile, "__cpp_deduction_guides=201606"); + cpp_define (pfile, "__cpp_noexcept_function_type=201510"); } if (flag_concepts) cpp_define (pfile, "__cpp_concepts=201507"); diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 7d8a7265752b..213353b9abdf 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -360,6 +360,13 @@ Wc++14-compat C++ ObjC++ Var(warn_cxx14_compat) Warning LangEnabledBy(C++ ObjC++,Wall) Warn about C++ constructs whose meaning differs between ISO C++ 2011 and ISO C++ 2014. +Wc++1z-compat +C++ ObjC++ Var(warn_cxx1z_compat) Warning LangEnabledBy(C++ ObjC++,Wall) +Warn about C++ constructs whose meaning differs between ISO C++ 2014 and (forthcoming) ISO C++ 201z(7?). + +Wc++17-compat +C++ ObjC++ Warning Alias(Wc++1z-compat) Undocumented + Wcast-qual C ObjC C++ ObjC++ Var(warn_cast_qual) Warning Warn about casts which discard qualifiers. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a65ddec3343b..f325ccc89322 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,52 @@ 2016-11-07 Jason Merrill + Implement P0012R1, Make exception specifications part of the type + system. + * cp-tree.h (enum tsubst_flags): Add tf_fndecl_type. + (flag_noexcept_type, ce_type): New. + * call.c (build_conv): Add ck_fnptr. + (enum conversion_kind): Change ck_tsafe to ck_fnptr. + (convert_like_real): Likewise. + (standard_conversion): Likewise. Allow function pointer + conversions for pointers to member functions. + (reference_compatible_p): Allow function pointer conversions. + (direct_reference_binding): Likewise. + (reference_binding): Reference-compatible is no longer a subset of + reference-related. + (is_subseq): Also strip ck_lvalue after next_conversion. + * class.c (instantiate_type): Check fnptr_conv_p. + (resolve_address_of_overloaded_function): Likewise. + * cvt.c (can_convert_tx_safety): Now static. + (noexcept_conv_p, fnptr_conv_p, strip_fnptr_conv): New. + * decl.c (flag_noexcept_type): Define. + (cxx_init_decl_processing): Set it. + (bad_specifiers): Check it. + (grokdeclarator) [cdk_function]: Add exception-spec to type here. + * lambda.c (maybe_add_lambda_conv_op): Add exception-spec to + returned pointer. + * mangle.c (struct globals): Add need_cxx1z_warning. + (mangle_decl): Check it. + (write_exception_spec): New. + (write_function_type): Call it. + (canonicalize_for_substitution): Handle exception spec. + (write_type): Likewise. + (write_encoding): Set processing_template_decl across mangling of + partially-instantiated type. + * pt.c (determine_specialization): Pass tf_fndecl_type. + (tsubst_decl, fn_type_unification): Likewise. + (tsubst): Strip tf_fndecl_type, pass it to + tsubst_exception_specification. + (convert_nontype_argument_function): Handle function pointer + conversion. + (convert_nontype_argument): Likewise. + (unify, for_each_template_parm_r): Walk into noexcept-specifier. + * rtti.c (ptr_initializer): Encode noexcept. + * tree.c (canonical_eh_spec): New. + (build_exception_variant): Use it. + * typeck.c (composite_pointer_type): Handle fnptr conversion. + (comp_except_specs): Compare canonical EH specs. + (structural_comptypes): Call it. + * call.c (standard_conversion): Reorganize pointer conversions. * pt.c (convert_nontype_argument_function): Convert to ref here. (convert_nontype_argument): Not here. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 0466cd13e382..0dcf322344c0 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -45,7 +45,7 @@ along with GCC; see the file COPYING3. If not see enum conversion_kind { ck_identity, ck_lvalue, - ck_tsafe, + ck_fnptr, ck_qual, ck_std, ck_ptr, @@ -771,6 +771,7 @@ build_conv (conversion_kind code, tree type, conversion *from) break; case ck_qual: + case ck_fnptr: if (rank < cr_exact) rank = cr_exact; break; @@ -1285,18 +1286,6 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, conv = build_conv (ck_ptr, from, conv); conv->base_p = true; } - else if (tx_safe_fn_type_p (from_pointee)) - { - /* A prvalue of type "pointer to transaction_safe function" can be - converted to a prvalue of type "pointer to function". */ - tree unsafe = tx_unsafe_fn_variant (from_pointee); - if (same_type_p (unsafe, to_pointee)) - { - from_pointee = unsafe; - from = build_pointer_type (unsafe); - conv = build_conv (ck_tsafe, from, conv); - } - } if (same_type_p (from, to)) /* OK */; @@ -1310,6 +1299,8 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, else if (expr && string_conv_p (to, expr, 0)) /* converting from string constant to char *. */ conv = build_conv (ck_qual, to, conv); + else if (fnptr_conv_p (to, from)) + conv = build_conv (ck_fnptr, to, conv); /* Allow conversions among compatible ObjC pointer types (base conversions have been already handled above). */ else if (c_dialect_objc () @@ -1332,18 +1323,29 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, tree fbase = class_of_this_parm (fromfn); tree tbase = class_of_this_parm (tofn); - if (!DERIVED_FROM_P (fbase, tbase) - || !same_type_p (static_fn_type (fromfn), - static_fn_type (tofn))) + if (!DERIVED_FROM_P (fbase, tbase)) + return NULL; + + tree fstat = static_fn_type (fromfn); + tree tstat = static_fn_type (tofn); + if (same_type_p (tstat, fstat) + || fnptr_conv_p (tstat, fstat)) + /* OK */; + else return NULL; - from = build_memfn_type (fromfn, - tbase, - cp_type_quals (tbase), - type_memfn_rqual (tofn)); - from = build_ptrmemfunc_type (build_pointer_type (from)); - conv = build_conv (ck_pmem, from, conv); - conv->base_p = true; + if (!same_type_p (fbase, tbase)) + { + from = build_memfn_type (fstat, + tbase, + cp_type_quals (tbase), + type_memfn_rqual (tofn)); + from = build_ptrmemfunc_type (build_pointer_type (from)); + conv = build_conv (ck_pmem, from, conv); + conv->base_p = true; + } + if (fnptr_conv_p (tstat, fstat)) + conv = build_conv (ck_fnptr, to, conv); } else if (tcode == BOOLEAN_TYPE) { @@ -1441,10 +1443,14 @@ reference_compatible_p (tree t1, tree t2) { /* [dcl.init.ref] - "cv1 T1" is reference compatible with "cv2 T2" if T1 is - reference-related to T2 and cv1 is the same cv-qualification as, - or greater cv-qualification than, cv2. */ - return (reference_related_p (t1, t2) + "cv1 T1" is reference compatible with "cv2 T2" if + * T1 is reference-related to T2 or + * T2 is "noexcept function" and T1 is "function", where the + function types are otherwise the same, + and cv1 is the same cv-qualification as, or greater cv-qualification + than, cv2. */ + return ((reference_related_p (t1, t2) + || fnptr_conv_p (t1, t2)) && at_least_as_qualified_p (t1, t2)); } @@ -1478,7 +1484,7 @@ direct_reference_binding (tree type, conversion *conv) either an identity conversion or, if the conversion function returns an entity of a type that is a derived class of the parameter type, a derived-to-base conversion. */ - if (!same_type_ignoring_top_level_qualifiers_p (t, conv->type)) + if (is_properly_derived_from (conv->type, t)) { /* Represent the derived-to-base conversion. */ conv = build_conv (ck_base, t, conv); @@ -1591,7 +1597,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags, [8.5.3/5 dcl.init.ref] is changed to also require direct bindings for const and rvalue references to rvalues of compatible class type. We should also do direct bindings for non-class xvalues. */ - if (related_p && gl_kind) + if ((related_p || compatible_p) && gl_kind) { /* [dcl.init.ref] @@ -6978,9 +6984,9 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, case ck_lvalue: return decay_conversion (expr, complain); - case ck_tsafe: + case ck_fnptr: /* ??? Should the address of a transaction-safe pointer point to the TM - clone, and this conversion look up the primary function? */ + clone, and this conversion look up the primary function? */ return build_nop (totype, expr); case ck_qual: @@ -8863,10 +8869,15 @@ is_subseq (conversion *ics1, conversion *ics2) ics2 = next_conversion (ics2); + while (ics2->kind == ck_rvalue + || ics2->kind == ck_lvalue) + ics2 = next_conversion (ics2); + if (ics2->kind == ics1->kind && same_type_p (ics2->type, ics1->type) - && same_type_p (next_conversion (ics2)->type, - next_conversion (ics1)->type)) + && (ics1->kind == ck_identity + || same_type_p (next_conversion (ics2)->type, + next_conversion (ics1)->type))) return true; } } diff --git a/gcc/cp/class.c b/gcc/cp/class.c index c6b4ed6af339..5460ae5d6265 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -8177,10 +8177,14 @@ resolve_address_of_overloaded_function (tree target_type, if (DECL_ANTICIPATED (fn)) continue; + /* In C++17 we need the noexcept-qualifier to compare types. */ + if (flag_noexcept_type) + maybe_instantiate_noexcept (fn); + /* See if there's a match. */ tree fntype = static_fn_type (fn); if (same_type_p (target_fn_type, fntype) - || can_convert_tx_safety (target_fn_type, fntype)) + || fnptr_conv_p (target_fn_type, fntype)) matches = tree_cons (fn, NULL_TREE, matches); } } @@ -8257,10 +8261,14 @@ resolve_address_of_overloaded_function (tree target_type, require_deduced_type (instantiation); } + /* In C++17 we need the noexcept-qualifier to compare types. */ + if (flag_noexcept_type) + maybe_instantiate_noexcept (instantiation); + /* See if there's a match. */ tree fntype = static_fn_type (instantiation); if (same_type_p (target_fn_type, fntype) - || can_convert_tx_safety (target_fn_type, fntype)) + || fnptr_conv_p (target_fn_type, fntype)) matches = tree_cons (instantiation, fn, matches); } @@ -8424,6 +8432,8 @@ instantiate_type (tree lhstype, tree rhs, tsubst_flags_t complain) tree fntype = non_reference (lhstype); if (same_type_p (fntype, TREE_TYPE (rhs))) return rhs; + if (fnptr_conv_p (fntype, TREE_TYPE (rhs))) + return rhs; if (flag_ms_extensions && TYPE_PTRMEMFUNC_P (fntype) && !TYPE_PTRMEMFUNC_P (TREE_TYPE (rhs))) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d3a5aeb785ba..20b52ad675d3 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4744,6 +4744,8 @@ enum tsubst_flags { for calls in decltype (5.2.2/11). */ tf_partial = 1 << 8, /* Doing initial explicit argument substitution in fn_type_unification. */ + tf_fndecl_type = 1 << 9, /* Substituting the type of a function + declaration. */ /* Convenient substitution flags combinations. */ tf_warning_or_error = tf_warning | tf_error }; @@ -4949,6 +4951,10 @@ extern int at_eof; extern bool defer_mangling_aliases; +/* True if noexcept is part of the type (i.e. in C++17). */ + +extern bool flag_noexcept_type; + /* A list of namespace-scope objects which have constructors or destructors which reside in the global scope. The decl is stored in the TREE_VALUE slot and the initializer is stored in the @@ -5737,7 +5743,8 @@ extern tree type_promotes_to (tree); extern tree perform_qualification_conversions (tree, tree); extern bool tx_safe_fn_type_p (tree); extern tree tx_unsafe_fn_variant (tree); -extern bool can_convert_tx_safety (tree, tree); +extern bool fnptr_conv_p (tree, tree); +extern tree strip_fnptr_conv (tree); /* in name-lookup.c */ extern tree pushdecl (tree); @@ -6577,6 +6584,7 @@ extern tree build_overload (tree, tree); extern tree ovl_scope (tree); extern const char *cxx_printable_name (tree, int); extern const char *cxx_printable_name_translate (tree, int); +extern tree canonical_eh_spec (tree); extern tree build_exception_variant (tree, tree); extern tree bind_template_template_parm (tree, tree); extern tree array_type_nelts_total (tree); @@ -6648,7 +6656,7 @@ extern tree complete_type (tree); extern tree complete_type_or_else (tree, tree); extern tree complete_type_or_maybe_complain (tree, tree, tsubst_flags_t); extern int type_unknown_p (const_tree); -enum { ce_derived, ce_normal, ce_exact }; +enum { ce_derived, ce_type, ce_normal, ce_exact }; extern bool comp_except_specs (const_tree, const_tree, int); extern bool comptypes (tree, tree, int); extern bool same_type_ignoring_top_level_qualifiers_p (tree, tree); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 2f5f15a2c826..400566f4e361 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -1932,9 +1932,84 @@ tx_unsafe_fn_variant (tree t) /* Return true iff FROM can convert to TO by a transaction-safety conversion. */ -bool +static bool can_convert_tx_safety (tree to, tree from) { return (flag_tm && tx_safe_fn_type_p (from) && same_type_p (to, tx_unsafe_fn_variant (from))); } + +/* Return true iff FROM can convert to TO by dropping noexcept. */ + +static bool +noexcept_conv_p (tree to, tree from) +{ + if (!flag_noexcept_type) + return false; + + tree t = non_reference (to); + tree f = from; + if (TYPE_PTRMEMFUNC_P (t) + && TYPE_PTRMEMFUNC_P (f)) + { + t = TYPE_PTRMEMFUNC_FN_TYPE (t); + f = TYPE_PTRMEMFUNC_FN_TYPE (f); + } + if (TREE_CODE (t) == POINTER_TYPE + && TREE_CODE (f) == POINTER_TYPE) + { + t = TREE_TYPE (t); + f = TREE_TYPE (f); + } + tree_code code = TREE_CODE (f); + if (TREE_CODE (t) != code) + return false; + if (code != FUNCTION_TYPE && code != METHOD_TYPE) + return false; + if (!type_throw_all_p (t) + || type_throw_all_p (f)) + return false; + tree v = build_exception_variant (f, NULL_TREE); + return same_type_p (t, v); +} + +/* Return true iff FROM can convert to TO by a function pointer conversion. */ + +bool +fnptr_conv_p (tree to, tree from) +{ + tree t = non_reference (to); + tree f = from; + if (TYPE_PTRMEMFUNC_P (t) + && TYPE_PTRMEMFUNC_P (f)) + { + t = TYPE_PTRMEMFUNC_FN_TYPE (t); + f = TYPE_PTRMEMFUNC_FN_TYPE (f); + } + if (TREE_CODE (t) == POINTER_TYPE + && TREE_CODE (f) == POINTER_TYPE) + { + t = TREE_TYPE (t); + f = TREE_TYPE (f); + } + + return (noexcept_conv_p (t, f) + || can_convert_tx_safety (t, f)); +} + +/* Return FN with any NOP_EXPRs that represent function pointer + conversions stripped. */ + +tree +strip_fnptr_conv (tree fn) +{ + while (TREE_CODE (fn) == NOP_EXPR) + { + tree op = TREE_OPERAND (fn, 0); + if (fnptr_conv_p (TREE_TYPE (fn), TREE_TYPE (op))) + fn = op; + else + break; + } + return fn; +} diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index ecf4d147d2a2..c0321f9f9594 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -73,8 +73,6 @@ static int check_static_variable_definition (tree, tree); static void record_unknown_type (tree, const char *); static tree builtin_function_1 (tree, tree, bool); static int member_function_or_else (tree, tree, enum overload_flags); -static void bad_specifiers (tree, enum bad_spec_place, int, int, int, int, - int); static void check_for_uninitialized_const_var (tree); static tree local_variable_p_walkfn (tree *, int *, void *); static const char *tag_name (enum tag_types); @@ -227,6 +225,9 @@ struct GTY((for_user)) named_label_entry { function, two inside the body of a function in a local class, etc.) */ int function_depth; +/* Whether the exception-specifier is part of a function type (i.e. C++17). */ +bool flag_noexcept_type; + /* States indicating how grokdeclarator() should handle declspecs marked with __attribute__((deprecated)). An object declared as __attribute__((deprecated)) suppresses warnings of uses of other @@ -4044,6 +4045,8 @@ cxx_init_decl_processing (void) std_node = current_namespace; pop_namespace (); + flag_noexcept_type = (cxx_dialect >= cxx1z); + c_common_nodes_and_builtins (); integer_two_node = build_int_cst (NULL_TREE, 2); @@ -7842,6 +7845,7 @@ bad_specifiers (tree object, if (friendp) error ("%q+D declared as a friend", object); if (raises + && !flag_noexcept_type && (TREE_CODE (object) == TYPE_DECL || (!TYPE_PTRFN_P (TREE_TYPE (object)) && !TYPE_REFFN_P (TREE_TYPE (object)) @@ -10477,6 +10481,9 @@ grokdeclarator (const cp_declarator *declarator, The optional attribute-specifier-seq appertains to the function type. */ decl_attributes (&type, attrs, 0); + + if (raises) + type = build_exception_variant (type, raises); } break; diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index d4284bfa48b4..c48cd5201e06 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -1029,6 +1029,9 @@ maybe_add_lambda_conv_op (tree type) tree stattype = build_function_type (fn_result, FUNCTION_ARG_CHAIN (callop)); stattype = (cp_build_type_attribute_variant (stattype, TYPE_ATTRIBUTES (optype))); + if (flag_noexcept_type + && TYPE_NOTHROW_P (TREE_TYPE (callop))) + stattype = build_exception_variant (stattype, noexcept_true_spec); /* First build up the conversion op. */ diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index f3b2fe3ee8de..a354ec5ead3d 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -114,6 +114,9 @@ struct GTY(()) globals { /* True if the mangling will be different in a future version of the ABI. */ bool need_abi_warning; + + /* True if the mangling will be different in C++17 mode. */ + bool need_cxx1z_warning; }; static GTY (()) globals G; @@ -344,6 +347,43 @@ dump_substitution_candidates (void) } } +/* ::= + Do -- non-throwing exception specification + DO E -- computed (instantiation-dependent) noexcept + Dw * E -- throw (types) */ + +static void +write_exception_spec (tree spec) +{ + + if (!spec || spec == noexcept_false_spec) + /* Nothing. */ + return; + + if (!flag_noexcept_type) + { + G.need_cxx1z_warning = true; + return; + } + + if (nothrow_spec_p (spec)) + write_string ("Do"); + else if (TREE_PURPOSE (spec)) + { + gcc_assert (uses_template_parms (TREE_PURPOSE (spec))); + write_string ("DO"); + write_expression (TREE_PURPOSE (spec)); + write_char ('E'); + } + else + { + write_string ("Dw"); + for (tree t = spec; t; t = TREE_CHAIN (t)) + write_type (TREE_VALUE (t)); + write_char ('E'); + } +} + /* Both decls and types can be substitution candidates, but sometimes they refer to the same thing. For instance, a TYPE_DECL and RECORD_TYPE for the same class refer to the same thing, and should @@ -375,7 +415,15 @@ canonicalize_for_substitution (tree node) cp_type_quals (node)); if (TREE_CODE (node) == FUNCTION_TYPE || TREE_CODE (node) == METHOD_TYPE) - node = build_ref_qualified_type (node, type_memfn_rqual (orig)); + { + node = build_ref_qualified_type (node, type_memfn_rqual (orig)); + tree r = canonical_eh_spec (TYPE_RAISES_EXCEPTIONS (orig)); + if (flag_noexcept_type) + node = build_exception_variant (node, r); + else + /* Set the warning flag if appropriate. */ + write_exception_spec (r); + } } return node; } @@ -777,9 +825,11 @@ write_encoding (const tree decl) { tree fn_type; tree d; + bool tmpl = decl_is_template_id (decl, NULL); - if (decl_is_template_id (decl, NULL)) + if (tmpl) { + ++processing_template_decl; fn_type = get_mostly_instantiated_function_type (decl); /* FN_TYPE will not have parameter types for in-charge or VTT parameters. Therefore, we pass NULL_TREE to @@ -796,6 +846,9 @@ write_encoding (const tree decl) write_bare_function_type (fn_type, mangle_return_type_p (decl), d); + + if (tmpl) + --processing_template_decl; } } @@ -2064,7 +2117,11 @@ write_type (tree type) type = TYPE_MAIN_VARIANT (type); if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE) - type = build_ref_qualified_type (type, type_memfn_rqual (type_orig)); + { + type = build_ref_qualified_type (type, type_memfn_rqual (type_orig)); + type = build_exception_variant (type, + TYPE_RAISES_EXCEPTIONS (type_orig)); + } /* According to the C++ ABI, some library classes are passed the same as the scalar type of their single member and use the same @@ -2589,6 +2646,8 @@ write_function_type (const tree type) write_CV_qualifiers_for_type (this_type); } + write_exception_spec (TYPE_RAISES_EXCEPTIONS (type)); + if (tx_safe_fn_type_p (type)) write_string ("Dx"); @@ -3776,6 +3835,12 @@ mangle_decl (const tree decl) } SET_DECL_ASSEMBLER_NAME (decl, id); + if (G.need_cxx1z_warning) + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc__1z_compat, + "mangled name for %qD will change in C++17 because the " + "exception specification is part of a function type", + decl); + if (id != DECL_NAME (decl) /* Don't do this for a fake symbol we aren't going to emit anyway. */ && TREE_CODE (decl) != TYPE_DECL diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 45965aa788da..3df71dd97dbd 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -2216,7 +2216,7 @@ determine_specialization (tree template_id, continue; // Then, try to form the new function type. - insttype = tsubst (TREE_TYPE (fn), targs, tf_none, NULL_TREE); + insttype = tsubst (TREE_TYPE (fn), targs, tf_fndecl_type, NULL_TREE); if (insttype == error_mark_node) continue; fn_arg_types @@ -5876,7 +5876,7 @@ get_underlying_template (tree tmpl) } /* Subroutine of convert_nontype_argument. Converts EXPR to TYPE, which - must be a function or a pointer-to-function type, as specified + must be a reference-to-function or a pointer-to-function type, as specified in [temp.arg.nontype]: disambiguate EXPR if it is an overload set, and check that the resulting function has external linkage. */ @@ -5892,7 +5892,7 @@ convert_nontype_argument_function (tree type, tree expr, if (fn == error_mark_node) return error_mark_node; - fn_no_ptr = fn; + fn_no_ptr = strip_fnptr_conv (fn); if (TREE_CODE (fn_no_ptr) == ADDR_EXPR) fn_no_ptr = TREE_OPERAND (fn_no_ptr, 0); if (BASELINK_P (fn_no_ptr)) @@ -6672,6 +6672,11 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) && !check_valid_ptrmem_cst_expr (type, expr, complain)) return error_mark_node; + /* Repeated conversion can't deal with a conversion that turns PTRMEM_CST + into a CONSTRUCTOR, so build up a new PTRMEM_CST instead. */ + if (fnptr_conv_p (type, TREE_TYPE (expr))) + expr = make_ptrmem_cst (type, PTRMEM_CST_MEMBER (expr)); + /* There is no way to disable standard conversions in resolve_address_of_overloaded_function (called by instantiate_type). It is possible that the call succeeded by @@ -8861,6 +8866,13 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d) want walk_tree walking into them itself. */ *walk_subtrees = 0; } + + if (flag_noexcept_type) + { + tree spec = TYPE_RAISES_EXCEPTIONS (t); + if (spec) + WALK_SUBTREE (TREE_PURPOSE (spec)); + } break; case TYPEOF_TYPE: @@ -11932,7 +11944,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) member = 0; ctx = DECL_CONTEXT (t); } - type = tsubst (TREE_TYPE (t), args, complain, in_decl); + type = tsubst (TREE_TYPE (t), args, complain|tf_fndecl_type, in_decl); if (type == error_mark_node) RETURN (error_mark_node); @@ -13015,6 +13027,9 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) } } + bool fndecl_type = (complain & tf_fndecl_type); + complain &= ~tf_fndecl_type; + if (type && code != TYPENAME_TYPE && code != TEMPLATE_TYPE_PARM @@ -13512,8 +13527,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) return error_mark_node; /* Substitute the exception specification. */ - specs = tsubst_exception_specification (t, args, complain, - in_decl, /*defer_ok*/true); + specs = tsubst_exception_specification (t, args, complain, in_decl, + /*defer_ok*/fndecl_type); if (specs == error_mark_node) return error_mark_node; if (specs) @@ -17991,7 +18006,7 @@ fn_type_unification (tree fn, access path at this point. */ push_deferring_access_checks (dk_deferred); fntype = tsubst (TREE_TYPE (fn), explicit_targs, - complain | tf_partial, NULL_TREE); + complain | tf_partial | tf_fndecl_type, NULL_TREE); pop_deferring_access_checks (); input_location = loc; processing_template_decl -= incomplete; @@ -20333,9 +20348,27 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, args[i] = TREE_VALUE (a); nargs = i; - return type_unification_real (tparms, targs, TYPE_ARG_TYPES (parm), - args, nargs, 1, DEDUCE_EXACT, - LOOKUP_NORMAL, NULL, explain_p); + if (type_unification_real (tparms, targs, TYPE_ARG_TYPES (parm), + args, nargs, 1, DEDUCE_EXACT, + LOOKUP_NORMAL, NULL, explain_p)) + return 1; + + if (flag_noexcept_type) + { + tree pspec = TYPE_RAISES_EXCEPTIONS (parm); + tree aspec = canonical_eh_spec (TYPE_RAISES_EXCEPTIONS (arg)); + if (pspec == NULL_TREE) pspec = noexcept_false_spec; + if (aspec == NULL_TREE) aspec = noexcept_false_spec; + if (TREE_PURPOSE (pspec) && TREE_PURPOSE (aspec) + && uses_template_parms (TREE_PURPOSE (pspec))) + RECUR_AND_CHECK_FAILURE (tparms, targs, TREE_PURPOSE (pspec), + TREE_PURPOSE (aspec), + UNIFY_ALLOW_NONE, explain_p); + else if (nothrow_spec_p (pspec) && !nothrow_spec_p (aspec)) + return unify_type_mismatch (explain_p, parm, arg); + } + + return 0; } case OFFSET_TYPE: diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index cfbc3d40680d..247a98fc5e94 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -985,6 +985,14 @@ ptr_initializer (tinfo_s *ti, tree target) flags |= 0x20; to = tx_unsafe_fn_variant (to); } + if (flag_noexcept_type + && (TREE_CODE (to) == FUNCTION_TYPE + || TREE_CODE (to) == METHOD_TYPE) + && TYPE_NOTHROW_P (to)) + { + flags |= 0x40; + to = build_exception_variant (to, NULL_TREE); + } CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init); CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, flags)); CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 4dc6e2268517..7872dd29cf82 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2209,6 +2209,27 @@ cxx_printable_name_translate (tree decl, int v) return cxx_printable_name_internal (decl, v, true); } +/* Return the canonical version of exception-specification RAISES for a C++17 + function type, for use in type comparison and building TYPE_CANONICAL. */ + +tree +canonical_eh_spec (tree raises) +{ + if (raises == NULL_TREE) + return raises; + else if (DEFERRED_NOEXCEPT_SPEC_P (raises) + || uses_template_parms (raises) + || uses_template_parms (TREE_PURPOSE (raises))) + /* Keep a dependent or deferred exception specification. */ + return raises; + else if (nothrow_spec_p (raises)) + /* throw() -> noexcept. */ + return noexcept_true_spec; + else + /* For C++17 type matching, anything else -> nothing. */ + return NULL_TREE; +} + /* Build the FUNCTION_TYPE or METHOD_TYPE which may throw exceptions listed in RAISES. */ @@ -2230,6 +2251,25 @@ build_exception_variant (tree type, tree raises) /* Need to build a new variant. */ v = build_variant_type_copy (type); TYPE_RAISES_EXCEPTIONS (v) = raises; + + if (!flag_noexcept_type) + /* The exception-specification is not part of the canonical type. */ + return v; + + /* Canonicalize the exception specification. */ + tree cr = canonical_eh_spec (raises); + + if (TYPE_STRUCTURAL_EQUALITY_P (type)) + /* Propagate structural equality. */ + SET_TYPE_STRUCTURAL_EQUALITY (v); + else if (TYPE_CANONICAL (type) != type || cr != raises) + /* Build the underlying canonical type, since it is different + from TYPE. */ + TYPE_CANONICAL (v) = build_exception_variant (TYPE_CANONICAL (type), cr); + else + /* T is its own canonical type. */ + TYPE_CANONICAL (v) = v; + return v; } diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 4ff2bc2d26ec..211696cf0295 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -647,6 +647,14 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2, return objc_common_type (t1, t2); } + /* if T1 or T2 is "pointer to noexcept function" and the other type is + "pointer to function", where the function types are otherwise the same, + "pointer to function" */ + if (fnptr_conv_p (t1, t2)) + return t1; + if (fnptr_conv_p (t2, t1)) + return t2; + /* [expr.eq] permits the application of a pointer conversion to bring the pointers to a common type. */ if (TYPE_PTR_P (t1) && TYPE_PTR_P (t2) @@ -710,22 +718,6 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2, return error_mark_node; } } - else if (TYPE_PTR_P (t1) && TYPE_PTR_P (t2) - && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (t1)) - && TREE_CODE (TREE_TYPE (t2)) == TREE_CODE (TREE_TYPE (t1))) - { - /* ...if T1 is "pointer to transaction_safe function" and T2 is "pointer - to function", where the function types are otherwise the same, T2, and - vice versa.... */ - tree f1 = TREE_TYPE (t1); - tree f2 = TREE_TYPE (t2); - bool safe1 = tx_safe_fn_type_p (f1); - bool safe2 = tx_safe_fn_type_p (f2); - if (safe1 && !safe2) - t1 = build_pointer_type (tx_unsafe_fn_variant (f1)); - else if (safe2 && !safe1) - t2 = build_pointer_type (tx_unsafe_fn_variant (f2)); - } return composite_pointer_type_r (t1, t2, operation, complain); } @@ -1020,6 +1012,7 @@ comp_except_types (tree a, tree b, bool exact) /* Return true if TYPE1 and TYPE2 are equivalent exception specifiers. If EXACT is ce_derived, T2 can be stricter than T1 (according to 15.4/5). + If EXACT is ce_type, the C++17 type compatibility rules apply. 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 @@ -1038,8 +1031,13 @@ comp_except_specs (const_tree t1, const_tree t2, int exact) /* First handle noexcept. */ if (exact < ce_exact) { + if (exact == ce_type + && (canonical_eh_spec (CONST_CAST_TREE (t1)) + == canonical_eh_spec (CONST_CAST_TREE (t2)))) + return true; + /* noexcept(false) is compatible with no exception-specification, - and stricter than any spec. */ + and less strict than any spec. */ if (t1 == noexcept_false_spec) return t2 == NULL_TREE || exact == ce_derived; /* Even a derived noexcept(false) is compatible with no @@ -1222,10 +1220,17 @@ structural_comptypes (tree t1, tree t2, int strict) return false; /* Need to check this before TYPE_MAIN_VARIANT. FIXME function qualifiers should really change the main variant. */ - if ((TREE_CODE (t1) == FUNCTION_TYPE - || TREE_CODE (t1) == METHOD_TYPE) - && type_memfn_rqual (t1) != type_memfn_rqual (t2)) - return false; + if (TREE_CODE (t1) == FUNCTION_TYPE + || TREE_CODE (t1) == METHOD_TYPE) + { + if (type_memfn_rqual (t1) != type_memfn_rqual (t2)) + return false; + if (flag_noexcept_type + && !comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1), + TYPE_RAISES_EXCEPTIONS (t2), + ce_type)) + return false; + } /* Allow for two different type nodes which have essentially the same definition. Note that we already checked for equality of the type diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index e0afc269471f..17c5c225d0c9 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -5574,6 +5574,11 @@ enabled by @option{-Wall}. Warn about C++ constructs whose meaning differs between ISO C++ 2011 and ISO C++ 2014. This warning is enabled by @option{-Wall}. +@item -Wc++1z-compat @r{(C++ and Objective-C++ only)} +@opindex Wc++1z-compat +Warn about C++ constructs whose meaning differs between ISO C++ 2014 +and the forthoming ISO C++ 2017(?). This warning is enabled by @option{-Wall}. + @item -Wcast-qual @opindex Wcast-qual @opindex Wno-cast-qual diff --git a/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C b/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C index 6ac66e07ce14..f4658a960677 100644 --- a/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C +++ b/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C @@ -380,6 +380,12 @@ # error "__cpp_capture_star_this != 201603" #endif +#ifndef __cpp_noexcept_function_type +# error "__cpp_noexcept_function_type" +#elif __cpp_noexcept_function_type != 201510 +# error "__cpp_noexcept_function_type != 201510" +#endif + #ifdef __has_cpp_attribute # if ! __has_cpp_attribute(maybe_unused) diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type1.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type1.C new file mode 100644 index 000000000000..62e1322e35ab --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type1.C @@ -0,0 +1,8 @@ +// Testcase from P0012r1 +// { dg-options -std=c++1z } + +void (*p)() throw(int); +void (**pp)() noexcept = &p; // { dg-error "" } cannot convert to pointer to noexcept function + +struct S { typedef void (*p)(); operator p(); }; +void (*q)() noexcept = S(); // { dg-error "" } cannot convert to pointer to noexcept function diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type11.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type11.C new file mode 100644 index 000000000000..bcd4d8d613d1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type11.C @@ -0,0 +1,3 @@ +// { dg-options "-Wall -std=c++14" } + +void f(int(*)() noexcept) { } // { dg-warning "mangled" } diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type12.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type12.C new file mode 100644 index 000000000000..39820af136ec --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type12.C @@ -0,0 +1,23 @@ +// { dg-options -std=c++1z } + +template +void f(R (*)(A...) noexcept(B)) { } + +template +void f2(R (*)(A...) noexcept(B)) { } + +void g(int); +void h(int) noexcept; + +int main() +{ + f(g); + f2(h); +} + +// { dg-final { scan-assembler "_Z1fIvJiELb0EEvPDOT1_EFT_DpT0_E" } } +// { dg-final { scan-assembler "_Z2f2IvJiELb1EEvPDOT1_EFT_DpT0_E" } } + +void f3(void (*)() noexcept) { } + +// { dg-final { scan-assembler "_Z2f3PDoFvvE" } } diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type2.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type2.C new file mode 100644 index 000000000000..747bb194c302 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type2.C @@ -0,0 +1,10 @@ +// Test for function pointer conversion on template arguments. +// { dg-options -std=c++1z } + +template struct A { }; + +void f() noexcept { }; +constexpr void (*p)() noexcept = f; + +A a; +A

b; diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type3.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type3.C new file mode 100644 index 000000000000..9303da87b8cf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type3.C @@ -0,0 +1,13 @@ +// Test for overload resolution. +// { dg-options -std=c++1z } + +void f(void (*)() noexcept) = delete; +void f(void (*)()) { } +void g() {} +void h() noexcept {} + +int main() +{ + f(g); + f(h); // { dg-error "deleted" } +} diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type4.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type4.C new file mode 100644 index 000000000000..621da9341ea3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type4.C @@ -0,0 +1,16 @@ +// Test for deduction. +// { dg-options -std=c++1z } + +template +void f(R (*)(A...)); +void g(int) noexcept; + +template +void h(R (*)(A...) noexcept); +void i(int); + +int main() +{ + f(g); + h(i); // { dg-error "" } +} diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type5.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type5.C new file mode 100644 index 000000000000..9e5d20224e2c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type5.C @@ -0,0 +1,25 @@ +// Test for composite pointer type. +// { dg-options -std=c++1z } + +typedef void (*P)(); +typedef void (*NP)() noexcept; + +void f(); +void g() noexcept; + +bool b; + +template struct Same; +template struct Same { }; + +Same s; + +int main() +{ + P p = 0; + NP np = 0; + + p == np; + p != np; + p < np; +} diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type6.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type6.C new file mode 100644 index 000000000000..50684571b621 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type6.C @@ -0,0 +1,13 @@ +// Test for lambda conversion. +// { dg-options -std=c++1z } + +void f() +{ + auto l = []() noexcept { return 0; }; + int (*p)() noexcept = l; + int (*q)() = l; + + auto l2 = []{ return 0; }; + p = l2; // { dg-error "" } + q = l2; +} diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type7.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type7.C new file mode 100644 index 000000000000..1f78114dc74b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type7.C @@ -0,0 +1,14 @@ +// Test for static_cast. +// { dg-options -std=c++1z } + +void f() +{ + typedef void (*P)(); + typedef void (*NP)() noexcept; + + P p; + NP np; + + static_cast

(np); + static_cast(p); // { dg-error "" } +} diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type8.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type8.C new file mode 100644 index 000000000000..0182e3a31117 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type8.C @@ -0,0 +1,22 @@ +// Test for exception handling. +// { dg-options -std=c++1z } +// { dg-do run } + +void f() {} +void g() noexcept {} + +int main() +{ + try { throw g; } + catch (void (*)()) { } + + try { throw g; } + catch (void (*)() noexcept) { } + + try { throw f; } + catch (void (*)()) { } + + try { throw f; } + catch (void (*)() noexcept) { __builtin_abort(); } + catch (...) { } +} diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type9.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type9.C new file mode 100644 index 000000000000..4547c4cc4d3c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type9.C @@ -0,0 +1,18 @@ +// Test for PMF template args. +// { dg-options -std=c++1z } +// { dg-do run } + +struct A +{ + void f() noexcept; + void g(); +}; + +template struct B { }; +template struct C { }; + +B<&A::f> b1; +B<&A::g> b2; + +C<&A::f> c1; +C<&A::g> c2; // { dg-error "" } diff --git a/gcc/testsuite/g++.dg/eh/spec2.C b/gcc/testsuite/g++.dg/eh/spec2.C index 64807dd26774..8107f019eb7e 100644 --- a/gcc/testsuite/g++.dg/eh/spec2.C +++ b/gcc/testsuite/g++.dg/eh/spec2.C @@ -2,9 +2,9 @@ struct S { void f (void); }; -typedef void f1 (void) throw (int); // { dg-error "exception" } -typedef void (*f2) (void) throw (int); // { dg-error "exception" } -typedef void (S::*f3) (void) throw (int); // { dg-error "exception" } +typedef void f1 (void) throw (int); // { dg-error "exception" "" { target c++14_down } } +typedef void (*f2) (void) throw (int); // { dg-error "exception" "" { target c++14_down } } +typedef void (S::*f3) (void) throw (int); // { dg-error "exception" "" { target c++14_down } } void (*f4) (void) throw (int); void (S::*f5) (void) throw (int); diff --git a/gcc/testsuite/g++.old-deja/g++.eh/spec7.C b/gcc/testsuite/g++.old-deja/g++.eh/spec7.C index 2ef88a249006..2a4a989913de 100644 --- a/gcc/testsuite/g++.old-deja/g++.eh/spec7.C +++ b/gcc/testsuite/g++.old-deja/g++.eh/spec7.C @@ -10,7 +10,7 @@ struct A static void (A::*pmf)() throw (); }; -void (A::* A::pmf)() = &A::g; +void (A::* A::pmf)() throw() = &A::g; int main() { diff --git a/include/ChangeLog b/include/ChangeLog index 5054b7e912aa..d029f722ae9e 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,8 @@ +2016-11-07 Jason Merrill + + * demangle.h (enum demangle_component_type): Add + DEMANGLE_COMPONENT_NOEXCEPT, DEMANGLE_COMPONENT_THROW_SPEC. + 2016-10-17 Jakub Jelinek * dwarf2.h (enum dwarf_calling_convention): Add new DWARF5 diff --git a/include/demangle.h b/include/demangle.h index 1d7cadf4b71f..7a03c204aac9 100644 --- a/include/demangle.h +++ b/include/demangle.h @@ -449,7 +449,9 @@ enum demangle_component_type /* A transaction-safe function type. */ DEMANGLE_COMPONENT_TRANSACTION_SAFE, /* A cloned function. */ - DEMANGLE_COMPONENT_CLONE + DEMANGLE_COMPONENT_CLONE, + DEMANGLE_COMPONENT_NOEXCEPT, + DEMANGLE_COMPONENT_THROW_SPEC }; /* Types which are only used internally. */ diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog index 40e5bc7cc9e7..727ffd39007b 100644 --- a/libiberty/ChangeLog +++ b/libiberty/ChangeLog @@ -1,3 +1,13 @@ +2016-11-07 Jason Merrill + + * cp-demangle.c (is_fnqual_component_type): New. + (d_encoding, d_print_comp_inner, d_print_mod_list): Use it. + (FNQUAL_COMPONENT_CASE): New. + (d_make_comp, has_return_type, d_print_comp_inner) + (d_print_function_type): Use it. + (next_is_type_qual): New. + (d_cv_qualifiers, d_print_mod): Handle noexcept and throw-spec. + 2016-11-02 Mark Wielaard * cplus-dem.c (demangle_signature): Move fall through comment. diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c index 46382ccee22e..e239155c442f 100644 --- a/libiberty/cp-demangle.c +++ b/libiberty/cp-demangle.c @@ -436,6 +436,8 @@ static struct demangle_component *d_operator_name (struct d_info *); static struct demangle_component *d_special_name (struct d_info *); +static struct demangle_component *d_parmlist (struct d_info *); + static int d_call_offset (struct d_info *, int); static struct demangle_component *d_ctor_dtor_name (struct d_info *); @@ -559,6 +561,32 @@ static int d_demangle_callback (const char *, int, demangle_callbackref, void *); static char *d_demangle (const char *, int, size_t *); +/* True iff TYPE is a demangling component representing a + function-type-qualifier. */ + +static int +is_fnqual_component_type (enum demangle_component_type type) +{ + return (type == DEMANGLE_COMPONENT_RESTRICT_THIS + || type == DEMANGLE_COMPONENT_VOLATILE_THIS + || type == DEMANGLE_COMPONENT_CONST_THIS + || type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS + || type == DEMANGLE_COMPONENT_TRANSACTION_SAFE + || type == DEMANGLE_COMPONENT_NOEXCEPT + || type == DEMANGLE_COMPONENT_THROW_SPEC + || type == DEMANGLE_COMPONENT_REFERENCE_THIS); +} + +#define FNQUAL_COMPONENT_CASE \ + case DEMANGLE_COMPONENT_RESTRICT_THIS: \ + case DEMANGLE_COMPONENT_VOLATILE_THIS: \ + case DEMANGLE_COMPONENT_CONST_THIS: \ + case DEMANGLE_COMPONENT_REFERENCE_THIS: \ + case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: \ + case DEMANGLE_COMPONENT_TRANSACTION_SAFE: \ + case DEMANGLE_COMPONENT_NOEXCEPT: \ + case DEMANGLE_COMPONENT_THROW_SPEC + #ifdef CP_DEMANGLE_DEBUG static void @@ -984,14 +1012,9 @@ d_make_comp (struct d_info *di, enum demangle_component_type type, case DEMANGLE_COMPONENT_RESTRICT: case DEMANGLE_COMPONENT_VOLATILE: case DEMANGLE_COMPONENT_CONST: - case DEMANGLE_COMPONENT_RESTRICT_THIS: - case DEMANGLE_COMPONENT_VOLATILE_THIS: - case DEMANGLE_COMPONENT_CONST_THIS: - case DEMANGLE_COMPONENT_TRANSACTION_SAFE: - case DEMANGLE_COMPONENT_REFERENCE_THIS: - case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: case DEMANGLE_COMPONENT_ARGLIST: case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: + FNQUAL_COMPONENT_CASE: break; /* Other types should not be seen here. */ @@ -1225,12 +1248,7 @@ has_return_type (struct demangle_component *dc) return 0; case DEMANGLE_COMPONENT_TEMPLATE: return ! is_ctor_dtor_or_conversion (d_left (dc)); - case DEMANGLE_COMPONENT_RESTRICT_THIS: - case DEMANGLE_COMPONENT_VOLATILE_THIS: - case DEMANGLE_COMPONENT_CONST_THIS: - case DEMANGLE_COMPONENT_REFERENCE_THIS: - case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: - case DEMANGLE_COMPONENT_TRANSACTION_SAFE: + FNQUAL_COMPONENT_CASE: return has_return_type (d_left (dc)); } } @@ -1287,13 +1305,12 @@ d_encoding (struct d_info *di, int top_level) while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS || dc->type == DEMANGLE_COMPONENT_CONST_THIS - || dc->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE || dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS || dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS) dc = d_left (dc); /* If the top level is a DEMANGLE_COMPONENT_LOCAL_NAME, then - there may be CV-qualifiers on its right argument which + there may be function-qualifiers on its right argument which really apply here; this happens when parsing a class which is local to a function. */ if (dc->type == DEMANGLE_COMPONENT_LOCAL_NAME) @@ -1301,12 +1318,7 @@ d_encoding (struct d_info *di, int top_level) struct demangle_component *dcr; dcr = d_right (dc); - while (dcr->type == DEMANGLE_COMPONENT_RESTRICT_THIS - || dcr->type == DEMANGLE_COMPONENT_VOLATILE_THIS - || dcr->type == DEMANGLE_COMPONENT_CONST_THIS - || dcr->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE - || dcr->type == DEMANGLE_COMPONENT_REFERENCE_THIS - || dcr->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS) + while (is_fnqual_component_type (dcr->type)) dcr = d_left (dcr); dc->u.s_binary.right = dcr; } @@ -2239,6 +2251,24 @@ d_ctor_dtor_name (struct d_info *di) } } +/* True iff we're looking at an order-insensitive type-qualifier, including + function-type-qualifiers. */ + +static int +next_is_type_qual (struct d_info *di) +{ + char peek = d_peek_char (di); + if (peek == 'r' || peek == 'V' || peek == 'K') + return 1; + if (peek == 'D') + { + peek = d_peek_next_char (di); + if (peek == 'x' || peek == 'o' || peek == 'O' || peek == 'w') + return 1; + } + return 0; +} + /* ::= ::= ::= @@ -2324,9 +2354,7 @@ cplus_demangle_type (struct d_info *di) __vector, and it treats it as order-sensitive when mangling names. */ - peek = d_peek_char (di); - if (peek == 'r' || peek == 'V' || peek == 'K' - || (peek == 'D' && d_peek_next_char (di) == 'x')) + if (next_is_type_qual (di)) { struct demangle_component **pret; @@ -2361,6 +2389,7 @@ cplus_demangle_type (struct d_info *di) can_subst = 1; + peek = d_peek_char (di); switch (peek) { case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': @@ -2648,10 +2677,10 @@ d_cv_qualifiers (struct d_info *di, pstart = pret; peek = d_peek_char (di); - while (peek == 'r' || peek == 'V' || peek == 'K' - || (peek == 'D' && d_peek_next_char (di) == 'x')) + while (next_is_type_qual (di)) { enum demangle_component_type t; + struct demangle_component *right = NULL; d_advance (di, 1); if (peek == 'r') @@ -2677,12 +2706,41 @@ d_cv_qualifiers (struct d_info *di, } else { - t = DEMANGLE_COMPONENT_TRANSACTION_SAFE; - di->expansion += sizeof "transaction_safe"; - d_advance (di, 1); + peek = d_next_char (di); + if (peek == 'x') + { + t = DEMANGLE_COMPONENT_TRANSACTION_SAFE; + di->expansion += sizeof "transaction_safe"; + } + else if (peek == 'o' + || peek == 'O') + { + t = DEMANGLE_COMPONENT_NOEXCEPT; + di->expansion += sizeof "noexcept"; + if (peek == 'O') + { + right = d_expression (di); + if (right == NULL) + return NULL; + if (! d_check_char (di, 'E')) + return NULL; + } + } + else if (peek == 'w') + { + t = DEMANGLE_COMPONENT_THROW_SPEC; + di->expansion += sizeof "throw"; + right = d_parmlist (di); + if (right == NULL) + return NULL; + if (! d_check_char (di, 'E')) + return NULL; + } + else + return NULL; } - *pret = d_make_comp (di, t, NULL, NULL); + *pret = d_make_comp (di, t, NULL, right); if (*pret == NULL) return NULL; pret = &d_left (*pret); @@ -3973,6 +4031,8 @@ d_count_templates_scopes (int *num_templates, int *num_scopes, case DEMANGLE_COMPONENT_REFERENCE_THIS: case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: case DEMANGLE_COMPONENT_TRANSACTION_SAFE: + case DEMANGLE_COMPONENT_NOEXCEPT: + case DEMANGLE_COMPONENT_THROW_SPEC: case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: case DEMANGLE_COMPONENT_POINTER: case DEMANGLE_COMPONENT_COMPLEX: @@ -4587,12 +4647,7 @@ d_print_comp_inner (struct d_print_info *dpi, int options, adpm[i].templates = dpi->templates; ++i; - if (typed_name->type != DEMANGLE_COMPONENT_RESTRICT_THIS - && typed_name->type != DEMANGLE_COMPONENT_VOLATILE_THIS - && typed_name->type != DEMANGLE_COMPONENT_CONST_THIS - && typed_name->type != DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS - && typed_name->type != DEMANGLE_COMPONENT_TRANSACTION_SAFE - && typed_name->type != DEMANGLE_COMPONENT_REFERENCE_THIS) + if (!is_fnqual_component_type (typed_name->type)) break; typed_name = d_left (typed_name); @@ -4629,13 +4684,7 @@ d_print_comp_inner (struct d_print_info *dpi, int options, d_print_error (dpi); return; } - while (local_name->type == DEMANGLE_COMPONENT_RESTRICT_THIS - || local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS - || local_name->type == DEMANGLE_COMPONENT_CONST_THIS - || local_name->type == DEMANGLE_COMPONENT_REFERENCE_THIS - || local_name->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE - || (local_name->type - == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)) + while (is_fnqual_component_type (local_name->type)) { if (i >= sizeof adpm / sizeof adpm[0]) { @@ -4960,16 +5009,11 @@ d_print_comp_inner (struct d_print_info *dpi, int options, } /* Fall through. */ - case DEMANGLE_COMPONENT_RESTRICT_THIS: - case DEMANGLE_COMPONENT_VOLATILE_THIS: - case DEMANGLE_COMPONENT_CONST_THIS: - case DEMANGLE_COMPONENT_REFERENCE_THIS: - case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: case DEMANGLE_COMPONENT_POINTER: case DEMANGLE_COMPONENT_COMPLEX: case DEMANGLE_COMPONENT_IMAGINARY: - case DEMANGLE_COMPONENT_TRANSACTION_SAFE: + FNQUAL_COMPONENT_CASE: modifier: { /* We keep a list of modifiers on the stack. */ @@ -5674,13 +5718,7 @@ d_print_mod_list (struct d_print_info *dpi, int options, if (mods->printed || (! suffix - && (mods->mod->type == DEMANGLE_COMPONENT_RESTRICT_THIS - || mods->mod->type == DEMANGLE_COMPONENT_VOLATILE_THIS - || mods->mod->type == DEMANGLE_COMPONENT_CONST_THIS - || mods->mod->type == DEMANGLE_COMPONENT_REFERENCE_THIS - || mods->mod->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE - || (mods->mod->type - == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)))) + && (is_fnqual_component_type (mods->mod->type)))) { d_print_mod_list (dpi, options, mods->next, suffix); return; @@ -5733,12 +5771,7 @@ d_print_mod_list (struct d_print_info *dpi, int options, dc = dc->u.s_unary_num.sub; } - while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS - || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS - || dc->type == DEMANGLE_COMPONENT_CONST_THIS - || dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS - || dc->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE - || dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS) + while (is_fnqual_component_type (dc->type)) dc = d_left (dc); d_print_comp (dpi, options, dc); @@ -5777,6 +5810,24 @@ d_print_mod (struct d_print_info *dpi, int options, case DEMANGLE_COMPONENT_TRANSACTION_SAFE: d_append_string (dpi, " transaction_safe"); return; + case DEMANGLE_COMPONENT_NOEXCEPT: + d_append_string (dpi, " noexcept"); + if (d_right (mod)) + { + d_append_char (dpi, '('); + d_print_comp (dpi, options, d_right (mod)); + d_append_char (dpi, ')'); + } + return; + case DEMANGLE_COMPONENT_THROW_SPEC: + d_append_string (dpi, " throw"); + if (d_right (mod)) + { + d_append_char (dpi, '('); + d_print_comp (dpi, options, d_right (mod)); + d_append_char (dpi, ')'); + } + return; case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: d_append_char (dpi, ' '); d_print_comp (dpi, options, d_right (mod)); @@ -5864,12 +5915,7 @@ d_print_function_type (struct d_print_info *dpi, int options, need_space = 1; need_paren = 1; break; - case DEMANGLE_COMPONENT_RESTRICT_THIS: - case DEMANGLE_COMPONENT_VOLATILE_THIS: - case DEMANGLE_COMPONENT_CONST_THIS: - case DEMANGLE_COMPONENT_REFERENCE_THIS: - case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: - case DEMANGLE_COMPONENT_TRANSACTION_SAFE: + FNQUAL_COMPONENT_CASE: break; default: break; @@ -6411,7 +6457,6 @@ is_ctor_or_dtor (const char *mangled, case DEMANGLE_COMPONENT_CONST_THIS: case DEMANGLE_COMPONENT_REFERENCE_THIS: case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: - case DEMANGLE_COMPONENT_TRANSACTION_SAFE: default: dc = NULL; break; diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected index a56776355bfe..5badc3e58493 100644 --- a/libiberty/testsuite/demangle-expected +++ b/libiberty/testsuite/demangle-expected @@ -4596,3 +4596,13 @@ __10%0__S4_0T0T0 # Inheriting constructor _ZN1DCI11BEi D::B(int) + +# exception-specification (C++17) +_Z1fIvJiELb0EEvPDOT1_EFT_DpT0_E +void f(void (*)(int) noexcept(false)) + +_Z1fIvJiELb0EEvPDoFT_DpT0_E +void f(void (*)(int) noexcept) + +_Z1fIvJiELb0EEvPDwiEFT_DpT0_E +void f(void (*)(int) throw(int)) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 8c7c50af634a..61dafba43e9b 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,14 @@ +2016-11-07 Jason Merrill + + * include/bits/c++config (_GLIBCXX_NOEXCEPT_PARM) + (_GLIBCXX_NOEXCEPT_QUAL): New. + * include/std/type_traits (is_function): Use them. + * libsubc++/new (launder): Likewise. + * libsupc++/cxxabi.h (__pbase_type_info::__masks): Add + __noexcept_mask. + * libsupc++/pbase_type_info.cc (__do_catch): Handle function + pointer conversion. + 2016-11-07 François Dumont * config/abi/pre/gnu-versioned-namespace.ver: Export C++17 new of diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config index 6d3226fcd573..8a27d14f9515 100644 --- a/libstdc++-v3/include/bits/c++config +++ b/libstdc++-v3/include/bits/c++config @@ -146,6 +146,14 @@ # endif #endif +#if __cpp_noexcept_function_type +#define _GLIBCXX_NOEXCEPT_PARM , bool _N +#define _GLIBCXX_NOEXCEPT_QUAL noexcept (_N) +#else +#define _GLIBCXX_NOEXCEPT_PARM +#define _GLIBCXX_NOEXCEPT_QUAL +#endif + // Macro for extern template, ie controlling template linkage via use // of extern keyword on template declaration. As documented in the g++ // manual, it inhibits all implicit instantiations and is used diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index 6824c9eb27e3..e5f2bbaf745f 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -458,100 +458,100 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct is_function : public false_type { }; - template - struct is_function<_Res(_ArgTypes...)> + template + struct is_function<_Res(_ArgTypes...) _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes...) &> + template + struct is_function<_Res(_ArgTypes...) & _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes...) &&> + template + struct is_function<_Res(_ArgTypes...) && _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes......)> + template + struct is_function<_Res(_ArgTypes......) _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes......) &> + template + struct is_function<_Res(_ArgTypes......) & _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes......) &&> + template + struct is_function<_Res(_ArgTypes......) && _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes...) const> + template + struct is_function<_Res(_ArgTypes...) const _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes...) const &> + template + struct is_function<_Res(_ArgTypes...) const & _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes...) const &&> + template + struct is_function<_Res(_ArgTypes...) const && _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes......) const> + template + struct is_function<_Res(_ArgTypes......) const _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes......) const &> + template + struct is_function<_Res(_ArgTypes......) const & _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes......) const &&> + template + struct is_function<_Res(_ArgTypes......) const && _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes...) volatile> + template + struct is_function<_Res(_ArgTypes...) volatile _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes...) volatile &> + template + struct is_function<_Res(_ArgTypes...) volatile & _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes...) volatile &&> + template + struct is_function<_Res(_ArgTypes...) volatile && _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes......) volatile> + template + struct is_function<_Res(_ArgTypes......) volatile _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes......) volatile &> + template + struct is_function<_Res(_ArgTypes......) volatile & _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes......) volatile &&> + template + struct is_function<_Res(_ArgTypes......) volatile && _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes...) const volatile> + template + struct is_function<_Res(_ArgTypes...) const volatile _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes...) const volatile &> + template + struct is_function<_Res(_ArgTypes...) const volatile & _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes...) const volatile &&> + template + struct is_function<_Res(_ArgTypes...) const volatile && _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes......) const volatile> + template + struct is_function<_Res(_ArgTypes......) const volatile _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes......) const volatile &> + template + struct is_function<_Res(_ArgTypes......) const volatile & _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; - template - struct is_function<_Res(_ArgTypes......) const volatile &&> + template + struct is_function<_Res(_ArgTypes......) const volatile && _GLIBCXX_NOEXCEPT_QUAL> : public true_type { }; #define __cpp_lib_is_null_pointer 201309 diff --git a/libstdc++-v3/libsupc++/cxxabi.h b/libstdc++-v3/libsupc++/cxxabi.h index f4b8f75fd180..7f1bd996a352 100644 --- a/libstdc++-v3/libsupc++/cxxabi.h +++ b/libstdc++-v3/libsupc++/cxxabi.h @@ -279,7 +279,8 @@ namespace __cxxabiv1 __restrict_mask = 0x4, __incomplete_mask = 0x8, __incomplete_class_mask = 0x10, - __transaction_safe_mask = 0x20 + __transaction_safe_mask = 0x20, + __noexcept_mask = 0x40 }; protected: diff --git a/libstdc++-v3/libsupc++/new b/libstdc++-v3/libsupc++/new index 6bc6c008c187..1e5964938151 100644 --- a/libstdc++-v3/libsupc++/new +++ b/libstdc++-v3/libsupc++/new @@ -197,10 +197,10 @@ namespace std // The program is ill-formed if T is a function type or // (possibly cv-qualified) void. - template - void launder(_Ret (*)(_Args...)) = delete; - template - void launder(_Ret (*)(_Args......)) = delete; + template + void launder(_Ret (*)(_Args...) _GLIBCXX_NOEXCEPT_QUAL) = delete; + template + void launder(_Ret (*)(_Args......) _GLIBCXX_NOEXCEPT_QUAL) = delete; void launder(void*) = delete; void launder(const void*) = delete; diff --git a/libstdc++-v3/libsupc++/pbase_type_info.cc b/libstdc++-v3/libsupc++/pbase_type_info.cc index ff6b756519b6..b2b9c0900978 100644 --- a/libstdc++-v3/libsupc++/pbase_type_info.cc +++ b/libstdc++-v3/libsupc++/pbase_type_info.cc @@ -80,12 +80,13 @@ __do_catch (const type_info *thr_type, unsigned tflags = thrown_type->__flags; - bool throw_tx = (tflags & __transaction_safe_mask); - bool catch_tx = (__flags & __transaction_safe_mask); - if (throw_tx && !catch_tx) - /* Catch can perform a transaction-safety conversion. */ - tflags &= ~__transaction_safe_mask; - if (catch_tx && !throw_tx) + const unsigned fqual_mask = __transaction_safe_mask|__noexcept_mask; + unsigned throw_fqual = (tflags & fqual_mask); + unsigned catch_fqual = (__flags & fqual_mask); + if (throw_fqual & ~catch_fqual) + /* Catch can perform a function pointer conversion. */ + tflags &= catch_fqual; + if (catch_fqual & ~throw_fqual) /* But not the reverse. */ return false; diff --git a/libstdc++-v3/testsuite/ext/profile/mutex_extensions_neg.cc b/libstdc++-v3/testsuite/ext/profile/mutex_extensions_neg.cc index 20bc198d5f1b..15cebed38f8a 100644 --- a/libstdc++-v3/testsuite/ext/profile/mutex_extensions_neg.cc +++ b/libstdc++-v3/testsuite/ext/profile/mutex_extensions_neg.cc @@ -25,7 +25,7 @@ #include -// { dg-error "multiple inlined namespaces" "" { target *-*-* } 342 } +// { dg-error "multiple inlined namespaces" "" { target *-*-* } 350 } // "template argument 1 is invalid" // { dg-prune-output "tuple:993" } -- 2.39.3