forked from OSchip/llvm-project
[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
This commit is contained in:
parent
5fc6f94591
commit
80b64f0861
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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']
|
||||
|
|
Loading…
Reference in New Issue