Implement P0012R1, Make exception specifications part of the type system.
authorJason Merrill <jason@redhat.com>
Mon, 7 Nov 2016 23:09:29 +0000 (18:09 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 7 Nov 2016 23:09:29 +0000 (18:09 -0500)
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

42 files changed:
gcc/c-family/ChangeLog
gcc/c-family/c-cppbuiltin.c
gcc/c-family/c.opt
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/decl.c
gcc/cp/lambda.c
gcc/cp/mangle.c
gcc/cp/pt.c
gcc/cp/rtti.c
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/doc/invoke.texi
gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C
gcc/testsuite/g++.dg/cpp1z/noexcept-type1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/noexcept-type11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/noexcept-type12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/noexcept-type2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/noexcept-type3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/noexcept-type4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/noexcept-type5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/noexcept-type6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/noexcept-type7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/noexcept-type8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/noexcept-type9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/eh/spec2.C
gcc/testsuite/g++.old-deja/g++.eh/spec7.C
include/ChangeLog
include/demangle.h
libiberty/ChangeLog
libiberty/cp-demangle.c
libiberty/testsuite/demangle-expected
libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/c++config
libstdc++-v3/include/std/type_traits
libstdc++-v3/libsupc++/cxxabi.h
libstdc++-v3/libsupc++/new
libstdc++-v3/libsupc++/pbase_type_info.cc
libstdc++-v3/testsuite/ext/profile/mutex_extensions_neg.cc

index 39e6de147df05da037fab44e0d231a74dd2e175e..5207c34c912a79eec6c10fac3c9814efd637d39f 100644 (file)
@@ -1,3 +1,8 @@
+2016-11-07  Jason Merrill  <jason@redhat.com>
+
+       * c.opt (Wc++1z-compat): New.
+       * c-cppbuiltin.c (c_cpp_builtins): Add __cpp_noexcept_function_type.
+
 2016-11-07  Martin Liska  <mliska@suse.cz>
 
        * c-warn.c (warn_for_unused_label): Save all labels used
index e40fa6ff9dc442afcd6e7cd34fcde99fccface60..55dbf44d34f6141c37958920347d8784987b2caf 100644 (file)
@@ -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");
index 7d8a7265752b04be4ad4b40d3637f2d394212bc9..213353b9abdf766b59dce9ee6432e04d4f094499 100644 (file)
@@ -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.
index a65ddec3343b5d6c03347c13710d6f6e4d1f70a6..f325ccc89322f74389e60699c39398ffe1ae0794 100644 (file)
@@ -1,5 +1,52 @@
 2016-11-07  Jason Merrill  <jason@redhat.com>
 
+       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.
index 0466cd13e3824f3f31308c087bc08ddcf29270db..0dcf322344c07af5f44e947f2d57644e4aade41b 100644 (file)
@@ -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;
     }
 }
index c6b4ed6af3399602f105c13f4e44c57397c3e5a3..5460ae5d6265de1758a8610c137bf3716d3ad816 100644 (file)
@@ -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)))
index d3a5aeb785ba614eaf7fea3d2d00b41aebb71085..20b52ad675d3b470470e8b4df23f61de583ef532 100644 (file)
@@ -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);
index 2f5f15a2c8269c6f0ea003737b2828c4ee7ba203..400566f4e361725e13d7a2e8d50620f9162e5aa4 100644 (file)
@@ -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;
+}
index ecf4d147d2a24bbecdc6b49d29857ec031cbf682..c0321f9f9594c1255ba5a394cdd236dd46f5c303 100644 (file)
@@ -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;
 
index d4284bfa48b43f5a1681f916107c076dd515d22b..c48cd5201e06ac29c4cdb6656800205932c4d281 100644 (file)
@@ -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.  */
 
index f3b2fe3ee8de2107081a4783e50e0d53b49734b7..a354ec5ead3d485aee7b256c0710f4735af1ec8e 100644 (file)
@@ -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)
     }
 }
 
+/* <exception-spec> ::=
+      Do  -- non-throwing exception specification
+      DO <expression> E  -- computed (instantiation-dependent) noexcept
+      Dw <type>* 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
index 45965aa788da53d72cdc1b1980dec3b25b5b8e0d..3df71dd97dbd4ed07aa58aa91ae698d14564b58e 100644 (file)
@@ -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:
index cfbc3d40680dcc6661c647d1accb636c1f8b5b81..247a98fc5e94af5ef76a7b38ee8ff8bffcb863ad 100644 (file)
@@ -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,
index 4dc6e226851712a624fbabaabc5a7839b06a60fe..7872dd29cf82380ce37a50b9f925e69586157825 100644 (file)
@@ -2209,6 +2209,27 @@ cxx_printable_name_translate (tree decl, int v)
   return cxx_printable_name_internal (decl, v, true);
 }
 \f
+/* 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;
 }
 
index 4ff2bc2d26ecff8f5b8c6578d348bb1a5f5659a1..211696cf02957892b3af7d93036aa0e105872eab 100644 (file)
@@ -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
index e0afc269471f53e074d351a52615efbc8ec0307d..17c5c225d0c98b8e9ecffecda5985024ffaa12d0 100644 (file)
@@ -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
index 6ac66e07ce142e57fc54ff8c24541fa164e2166a..f4658a9606773b6afa2fdf0bc90a22ee408cfae0 100644 (file)
 #  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 (file)
index 0000000..62e1322
--- /dev/null
@@ -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 (file)
index 0000000..bcd4d8d
--- /dev/null
@@ -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 (file)
index 0000000..39820af
--- /dev/null
@@ -0,0 +1,23 @@
+// { dg-options -std=c++1z }
+
+template <class R, class... A, bool B>
+void f(R (*)(A...) noexcept(B)) { }
+
+template <class R, class... A, bool B>
+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 (file)
index 0000000..747bb19
--- /dev/null
@@ -0,0 +1,10 @@
+// Test for function pointer conversion on template arguments.
+// { dg-options -std=c++1z }
+
+template <void (*P)()> struct A { };
+
+void f() noexcept { };
+constexpr void (*p)() noexcept = f;
+
+A<f> a;
+A<p> 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 (file)
index 0000000..9303da8
--- /dev/null
@@ -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 (file)
index 0000000..621da93
--- /dev/null
@@ -0,0 +1,16 @@
+// Test for deduction.
+// { dg-options -std=c++1z }
+
+template <class R, class... A>
+void f(R (*)(A...));
+void g(int) noexcept;
+
+template <class R, class... A>
+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 (file)
index 0000000..9e5d202
--- /dev/null
@@ -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 <class T, class U> struct Same;
+template <class T> struct Same<T,T> { };
+
+Same<decltype(b ? &f : &g),P> 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 (file)
index 0000000..5068457
--- /dev/null
@@ -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 (file)
index 0000000..1f78114
--- /dev/null
@@ -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<P>(np);
+  static_cast<NP>(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 (file)
index 0000000..0182e3a
--- /dev/null
@@ -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 (file)
index 0000000..4547c4c
--- /dev/null
@@ -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 <void (A::*)()> struct B { };
+template <void (A::*)() noexcept> struct C { };
+
+B<&A::f> b1;
+B<&A::g> b2;
+
+C<&A::f> c1;
+C<&A::g> c2;                   // { dg-error "" }
index 64807dd267747a4808021fc3cfe4067ea6c023bb..8107f019eb7ec11b87b9a0ba95756e9a4eb9441e 100644 (file)
@@ -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);
index 2ef88a2490063f1cf187b954cdf038a9de57a629..2a4a989913dee2864c6bc44617b9b40264da2e76 100644 (file)
@@ -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()
 {
index 5054b7e912aab7007cdb7cf637179d73f1da2618..d029f722ae9e5227118815527a37dc131d3ab2f0 100644 (file)
@@ -1,3 +1,8 @@
+2016-11-07  Jason Merrill  <jason@redhat.com>
+
+       * demangle.h (enum demangle_component_type): Add
+       DEMANGLE_COMPONENT_NOEXCEPT, DEMANGLE_COMPONENT_THROW_SPEC.
+
 2016-10-17  Jakub Jelinek  <jakub@redhat.com>
 
        * dwarf2.h (enum dwarf_calling_convention): Add new DWARF5
index 1d7cadf4b71fcff175921e9577212d631cab980a..7a03c204aac90ddfbd70918391e39ca86e44576f 100644 (file)
@@ -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.  */
index 40e5bc7cc9e74243586dd7a9d4781544befc9715..727ffd39007b0d08de9461c2af2f0d7604192f84 100644 (file)
@@ -1,3 +1,13 @@
+2016-11-07  Jason Merrill  <jason@redhat.com>
+
+       * 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  <mjw@redhat.com>
 
        * cplus-dem.c (demangle_signature): Move fall through comment.
index 46382ccee22e2d4c96c92feee50af7c7fcb4b836..e239155c442f829ed20610e2c90d9a73c4306b07 100644 (file)
@@ -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;
+}
+
 /* <type> ::= <builtin-type>
           ::= <function-type>
           ::= <class-enum-type>
@@ -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;
index a56776355bfe0cbb53993b6b0e15e8bcfb7a644a..5badc3e58493bfd894b0250c84f8c4bc35dbabfd 100644 (file)
@@ -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, false>(void (*)(int) noexcept(false))
+
+_Z1fIvJiELb0EEvPDoFT_DpT0_E
+void f<void, int, false>(void (*)(int) noexcept)
+
+_Z1fIvJiELb0EEvPDwiEFT_DpT0_E
+void f<void, int, false>(void (*)(int) throw(int))
index 8c7c50af634a32868c1444e6fdf90ad64ebbf5f6..61dafba43e9b6aa36bdcd5bd9169039dcace350f 100644 (file)
@@ -1,3 +1,14 @@
+2016-11-07  Jason Merrill  <jason@redhat.com>
+
+       * 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  <fdumont@gcc.gnu.org>
 
        * config/abi/pre/gnu-versioned-namespace.ver: Export C++17 new of
index 6d3226fcd573bed0d49dbec9d3a4b869a6e3fd90..8a27d14f9515b219a97c1471618088d7c1ec2992 100644 (file)
 # 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
index 6824c9eb27e3d25b9c58a0630c9f20f5163a2925..e5f2bbaf745f4c87980075618c64e7e96f533e0f 100644 (file)
@@ -458,100 +458,100 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct is_function
     : public false_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes...)>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes...) _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes...) &>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes...) & _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes...) &&>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes...) && _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes......)>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes......) _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes......) &>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes......) & _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes......) &&>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes......) && _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes...) const>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes...) const _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes...) const &>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes...) const & _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes...) const &&>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes...) const && _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes......) const>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes......) const _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes......) const &>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes......) const & _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes......) const &&>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes......) const && _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes...) volatile>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes...) volatile _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes...) volatile &>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes...) volatile & _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes...) volatile &&>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes...) volatile && _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes......) volatile>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes......) volatile _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes......) volatile &>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes......) volatile & _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes......) volatile &&>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes......) volatile && _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes...) const volatile>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes...) const volatile _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes...) const volatile &>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes...) const volatile & _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes...) const volatile &&>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes...) const volatile && _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes......) const volatile>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes......) const volatile _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes......) const volatile &>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes......) const volatile & _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
-  template<typename _Res, typename... _ArgTypes>
-    struct is_function<_Res(_ArgTypes......) const volatile &&>
+  template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+    struct is_function<_Res(_ArgTypes......) const volatile && _GLIBCXX_NOEXCEPT_QUAL>
     : public true_type { };
 
 #define __cpp_lib_is_null_pointer 201309
index f4b8f75fd18015a668f73b8e00a41755e5d1007a..7f1bd996a352c890509a84c42b8358121b4e8304 100644 (file)
@@ -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:
index 6bc6c008c187dda2ba990440b5b7e06b27153034..1e59649381512e66d942629665759e90241f6693 100644 (file)
@@ -197,10 +197,10 @@ namespace std
   // The program is ill-formed if T is a function type or
   // (possibly cv-qualified) void.
 
-  template<typename _Ret, typename... _Args>
-    void launder(_Ret (*)(_Args...)) = delete;
-  template<typename _Ret, typename... _Args>
-    void launder(_Ret (*)(_Args......)) = delete;
+  template<typename _Ret, typename... _Args _GLIBCXX_NOEXCEPT_PARM>
+    void launder(_Ret (*)(_Args...) _GLIBCXX_NOEXCEPT_QUAL) = delete;
+  template<typename _Ret, typename... _Args _GLIBCXX_NOEXCEPT_PARM>
+    void launder(_Ret (*)(_Args......) _GLIBCXX_NOEXCEPT_QUAL) = delete;
 
   void launder(void*) = delete;
   void launder(const void*) = delete;
index ff6b756519b696c910bbbdad91733958dc506899..b2b9c09009788835aec5ae6a192d6f5964d0621e 100644 (file)
@@ -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;
   
index 20bc198d5f1b9ed76a280e4218f04900b8a930ba..15cebed38f8a464b2da71574f20d85916b10c363 100644 (file)
@@ -25,7 +25,7 @@
 
 #include <vector>
 
-// { dg-error "multiple inlined namespaces" "" { target *-*-* } 342 }
+// { dg-error "multiple inlined namespaces" "" { target *-*-* } 350 }
 
 // "template argument 1 is invalid"
 // { dg-prune-output "tuple:993" }