[libcxxabi] r285867 - [p0012] Implement ABI support for throwing a noexcept function pointer and

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 2 16:41:52 PDT 2016


Author: rsmith
Date: Wed Nov  2 18:41:51 2016
New Revision: 285867

URL: http://llvm.org/viewvc/llvm-project?rev=285867&view=rev
Log:
[p0012] Implement ABI support for throwing a noexcept function pointer and
catching as non-noexcept

This implements the following proposal from cxx-abi-dev:

http://sourcerytools.com/pipermail/cxx-abi-dev/2016-October/002988.html

... which is necessary for complete support of http://wg21.link/p0012,
specifically throwing noexcept function and member function pointers and
catching them as non-noexcept pointers.

Differential Review: https://reviews.llvm.org/D26178

Added:
    libcxxabi/trunk/test/catch_function_03.pass.cpp
    libcxxabi/trunk/test/catch_member_function_pointer_02.pass.cpp
Modified:
    libcxxabi/trunk/src/private_typeinfo.cpp
    libcxxabi/trunk/src/private_typeinfo.h
    libcxxabi/trunk/test/libcxxabi/test/config.py

Modified: libcxxabi/trunk/src/private_typeinfo.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/private_typeinfo.cpp?rev=285867&r1=285866&r2=285867&view=diff
==============================================================================
--- libcxxabi/trunk/src/private_typeinfo.cpp (original)
+++ libcxxabi/trunk/src/private_typeinfo.cpp Wed Nov  2 18:41:51 2016
@@ -105,6 +105,45 @@ __function_type_info::~__function_type_i
 {
 }
 
+// __qualified_function_type_info
+
+__qualified_function_type_info::~__qualified_function_type_info()
+{
+}
+
+// Determine if a function pointer conversion can convert a pointer (or pointer
+// to member) to type x into a pointer (or pointer to member) to type y.
+static bool is_function_pointer_conversion(const std::type_info* x,
+                                           const std::type_info* y)
+{
+    const unsigned int discardable_quals =
+        __qualified_function_type_info::__noexcept_mask |
+        __qualified_function_type_info::__transaction_safe_mask |
+        __qualified_function_type_info::__noreturn_mask;
+
+    // If x has only discardable qualifiers and y is unqualified, then
+    // conversion is permitted.
+    const __qualified_function_type_info* qual_x =
+        dynamic_cast<const __qualified_function_type_info *>(x);
+    if (!qual_x)
+        return false;
+    if ((qual_x->__qualifiers & ~discardable_quals) == 0 &&
+        is_equal(qual_x->__base_type, y, false))
+        return true;
+
+    // Otherwise, x's qualifiers must be the same as y's, plus some discardable
+    // ones.
+    const __qualified_function_type_info* qual_y =
+        dynamic_cast<const __qualified_function_type_info *>(y);
+    if (!qual_y)
+        return false;
+    if (qual_y->__qualifiers & ~qual_x->__qualifiers)
+        return false;
+    if (qual_x->__qualifiers & ~qual_y->__qualifiers & ~discardable_quals)
+        return false;
+    return is_equal(qual_x->__base_type, qual_y->__base_type, false);
+}
+
 // __enum_type_info
 
 __enum_type_info::~__enum_type_info()
@@ -395,6 +434,10 @@ __pointer_type_info::can_catch(const __s
         return false;
     if (is_equal(__pointee, thrown_pointer_type->__pointee, false))
         return true;
+    // bullet 3C
+    if (is_function_pointer_conversion(thrown_pointer_type->__pointee,
+                                       __pointee))
+      return true;
     // bullet 3A
     if (is_equal(__pointee, &typeid(void), false)) {
         // pointers to functions cannot be converted to void*.
@@ -502,7 +545,9 @@ bool __pointer_to_member_type_info::can_
         return false;
     if (thrown_pointer_type->__flags & ~__flags)
         return false;
-    if (!is_equal(__pointee, thrown_pointer_type->__pointee, false))
+    if (!is_equal(__pointee, thrown_pointer_type->__pointee, false) &&
+        !is_function_pointer_conversion(thrown_pointer_type->__pointee,
+                                        __pointee))
         return false;
     if (is_equal(__context, thrown_pointer_type->__context, false))
         return true;

Modified: libcxxabi/trunk/src/private_typeinfo.h
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/private_typeinfo.h?rev=285867&r1=285866&r2=285867&view=diff
==============================================================================
--- libcxxabi/trunk/src/private_typeinfo.h (original)
+++ libcxxabi/trunk/src/private_typeinfo.h Wed Nov  2 18:41:51 2016
@@ -49,6 +49,33 @@ public:
                                            void *&) const;
 };
 
+// This implements the following proposal from cxx-abi-dev (not yet part of the
+// ABI document):
+//
+//   http://sourcerytools.com/pipermail/cxx-abi-dev/2016-October/002988.html
+//
+// This is necessary for support of http://wg21.link/p0012, which permits throwing
+// noexcept function and member function pointers and catching them as non-noexcept
+// pointers.
+class _LIBCXXABI_TYPE_VIS __qualified_function_type_info : public __shim_type_info {
+public:
+  const __function_type_info* __base_type;
+  unsigned int __qualifiers;
+
+  enum __qualifiers_mask {
+    __const_mask = 0x01,
+    __volatile_mask = 0x02,
+    __restrict_mask = 0x04,
+    __lval_ref_mask = 0x08,
+    __rval_ref_mask = 0x10,
+    __noexcept_mask = 0x20,
+    __transaction_safe_mask = 0x40,
+    __noreturn_mask = 0x80
+  };
+
+  _LIBCXXABI_HIDDEN virtual ~__qualified_function_type_info();
+};
+
 class _LIBCXXABI_TYPE_VIS __enum_type_info : public __shim_type_info {
 public:
   _LIBCXXABI_HIDDEN virtual ~__enum_type_info();

Added: libcxxabi/trunk/test/catch_function_03.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/catch_function_03.pass.cpp?rev=285867&view=auto
==============================================================================
--- libcxxabi/trunk/test/catch_function_03.pass.cpp (added)
+++ libcxxabi/trunk/test/catch_function_03.pass.cpp Wed Nov  2 18:41:51 2016
@@ -0,0 +1,65 @@
+//===---------------------- catch_function_03.cpp -------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Can a noexcept function pointer be caught by a non-noexcept catch clause?
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+// UNSUPPORTED: libcxxabi-no-exceptions, libcxxabi-no-qualified-function-types
+
+#include <cassert>
+
+template<bool Noexcept> void f() noexcept(Noexcept) {}
+template<bool Noexcept> using FnType = void() noexcept(Noexcept);
+
+template<bool ThrowNoexcept, bool CatchNoexcept>
+void check()
+{
+    try
+    {
+        auto *p = f<ThrowNoexcept>;
+        throw p;
+        assert(false);
+    }
+    catch (FnType<CatchNoexcept> *p)
+    {
+        assert(ThrowNoexcept || !CatchNoexcept);
+        assert(p == &f<ThrowNoexcept>);
+    }
+    catch (...)
+    {
+        assert(!ThrowNoexcept && CatchNoexcept);
+    }
+}
+
+void check_deep() {
+    auto *p = f<true>;
+    try
+    {
+        throw &p;
+    }
+    catch (FnType<false> **q)
+    {
+        assert(false);
+    }
+    catch (FnType<true> **q)
+    {
+    }
+    catch (...)
+    {
+        assert(false);
+    }
+}
+
+int main()
+{
+    check<false, false>();
+    check<false, true>();
+    check<true, false>();
+    check<true, true>();
+    check_deep();
+}

Added: libcxxabi/trunk/test/catch_member_function_pointer_02.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/catch_member_function_pointer_02.pass.cpp?rev=285867&view=auto
==============================================================================
--- libcxxabi/trunk/test/catch_member_function_pointer_02.pass.cpp (added)
+++ libcxxabi/trunk/test/catch_member_function_pointer_02.pass.cpp Wed Nov  2 18:41:51 2016
@@ -0,0 +1,68 @@
+//===--------------- catch_member_function_pointer_02.cpp -----------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Can a noexcept member function pointer be caught by a non-noexcept catch
+// clause?
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+// UNSUPPORTED: libcxxabi-no-exceptions, libcxxabi-no-qualified-function-types
+
+#include <cassert>
+
+struct X {
+  template<bool Noexcept> void f() noexcept(Noexcept) {}
+};
+template<bool Noexcept> using FnType = void (X::*)() noexcept(Noexcept);
+
+template<bool ThrowNoexcept, bool CatchNoexcept>
+void check()
+{
+    try
+    {
+        auto p = &X::f<ThrowNoexcept>;
+        throw p;
+        assert(false);
+    }
+    catch (FnType<CatchNoexcept> p)
+    {
+        assert(ThrowNoexcept || !CatchNoexcept);
+        assert(p == &X::f<ThrowNoexcept>);
+    }
+    catch (...)
+    {
+        assert(!ThrowNoexcept && CatchNoexcept);
+    }
+}
+
+void check_deep() {
+    FnType<true> p = &X::f<true>;
+    try
+    {
+        throw &p;
+    }
+    catch (FnType<false> *q)
+    {
+        assert(false);
+    }
+    catch (FnType<true> *q)
+    {
+    }
+    catch (...)
+    {
+        assert(false);
+    }
+}
+
+int main()
+{
+    check<false, false>();
+    check<false, true>();
+    check<true, false>();
+    check<true, true>();
+    check_deep();
+}

Modified: libcxxabi/trunk/test/libcxxabi/test/config.py
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/libcxxabi/test/config.py?rev=285867&r1=285866&r2=285867&view=diff
==============================================================================
--- libcxxabi/trunk/test/libcxxabi/test/config.py (original)
+++ libcxxabi/trunk/test/libcxxabi/test/config.py Wed Nov  2 18:41:51 2016
@@ -37,6 +37,8 @@ class Configuration(LibcxxConfiguration)
         super(Configuration, self).configure_features()
         if not self.get_lit_bool('enable_exceptions', True):
             self.config.available_features.add('libcxxabi-no-exceptions')
+        if not self.cxx.addCompileFlagIfSupported(['-Xclang', '-mqualified-function-type-info']):
+            self.config.available_features.add("libcxxabi-no-qualified-function-types")
 
     def configure_compile_flags(self):
         self.cxx.compile_flags += ['-DLIBCXXABI_NO_TIMER']




More information about the cfe-commits mailing list