summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2016-11-02 23:41:51 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2016-11-02 23:41:51 +0000
commit80b64f0861e1e7370bca2ccc9b95a848b7e1e815 (patch)
treec066b85be069bf33b947690cac275c4503483102
parent5fc6f9459190fa1c9cb5e117c74aee45c80703ed (diff)
downloadbcm5719-llvm-80b64f0861e1e7370bca2ccc9b95a848b7e1e815.tar.gz
bcm5719-llvm-80b64f0861e1e7370bca2ccc9b95a848b7e1e815.zip
[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 llvm-svn: 285867
-rw-r--r--libcxxabi/src/private_typeinfo.cpp47
-rw-r--r--libcxxabi/src/private_typeinfo.h27
-rw-r--r--libcxxabi/test/catch_function_03.pass.cpp65
-rw-r--r--libcxxabi/test/catch_member_function_pointer_02.pass.cpp68
-rw-r--r--libcxxabi/test/libcxxabi/test/config.py2
5 files changed, 208 insertions, 1 deletions
diff --git a/libcxxabi/src/private_typeinfo.cpp b/libcxxabi/src/private_typeinfo.cpp
index 73ef362aafc..6112a1f92a9 100644
--- a/libcxxabi/src/private_typeinfo.cpp
+++ b/libcxxabi/src/private_typeinfo.cpp
@@ -105,6 +105,45 @@ __function_type_info::~__function_type_info()
{
}
+// __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 __shim_type_info* thrown_type,
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_catch(
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;
diff --git a/libcxxabi/src/private_typeinfo.h b/libcxxabi/src/private_typeinfo.h
index ef98c3ae60b..fa6bd63eb09 100644
--- a/libcxxabi/src/private_typeinfo.h
+++ b/libcxxabi/src/private_typeinfo.h
@@ -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();
diff --git a/libcxxabi/test/catch_function_03.pass.cpp b/libcxxabi/test/catch_function_03.pass.cpp
new file mode 100644
index 00000000000..4118fde1d95
--- /dev/null
+++ b/libcxxabi/test/catch_function_03.pass.cpp
@@ -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();
+}
diff --git a/libcxxabi/test/catch_member_function_pointer_02.pass.cpp b/libcxxabi/test/catch_member_function_pointer_02.pass.cpp
new file mode 100644
index 00000000000..860d8ed28f8
--- /dev/null
+++ b/libcxxabi/test/catch_member_function_pointer_02.pass.cpp
@@ -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();
+}
diff --git a/libcxxabi/test/libcxxabi/test/config.py b/libcxxabi/test/libcxxabi/test/config.py
index 3d5a235df77..7cb1e9ba6c4 100644
--- a/libcxxabi/test/libcxxabi/test/config.py
+++ b/libcxxabi/test/libcxxabi/test/config.py
@@ -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']
OpenPOWER on IntegriCloud