This allows exception handlers of pointer and pointer to data members to match exceptions of type std::nullptr_t.
Pointers to member functions don't work yet, because a nullptr_t exception object is only a single word, and we need two words for a pointer to member function, and we don't have anywhere to put those two words in the exception object. I'm going to raise this with the C++ ABI group to coordinate with other implementations. Tested x86_64-linux, I plan to commit this to trunk soon. libstdc++-v3: PR c++/58796 * libsupc++/pbase_type_info.cc (__pbase_type_info::__do_catch): Make nullptr match handlers of pointer type. gcc/testsuite: PR c++/58796 * g++.dg/cpp0x/nullptr21.C: Remove void* handlers. * g++.dg/cpp0x/nullptr35.C: New test.
commit 2e6bb9fbc1d47915bdfe487efd7e870600b4b442 Author: Jonathan Wakely <jwak...@redhat.com> Date: Thu Jul 14 14:33:24 2016 +0100 c++/58796 Make nullptr match exception handlers of pointer type libstdc++-v3: PR c++/58796 * libsupc++/pbase_type_info.cc (__pbase_type_info::__do_catch): Make nullptr match handlers of pointer type. gcc/testsuite: PR c++/58796 * g++.dg/cpp0x/nullptr21.C: Remove void* handlers. * g++.dg/cpp0x/nullptr35.C: New test. diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr21.C b/gcc/testsuite/g++.dg/cpp0x/nullptr21.C index 89884b9..c6f560e 100644 --- a/gcc/testsuite/g++.dg/cpp0x/nullptr21.C +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr21.C @@ -18,8 +18,6 @@ int main() { try { throw nullptr; - } catch (void*) { - foo (0, 1); } catch (bool) { foo (0, 2); } catch (int) { @@ -35,8 +33,6 @@ int main() nullptr_t mynull = 0; try { throw mynull; - } catch (void*) { - foo (1, 1); } catch (bool) { foo (1, 2); } catch (int) { diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr35.C b/gcc/testsuite/g++.dg/cpp0x/nullptr35.C new file mode 100644 index 0000000..2f93ce1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr35.C @@ -0,0 +1,52 @@ +// { dg-do run { target c++11 } } + +// Test catching as pointer and pointer to member types, [except.handle] p3. + +extern "C" void abort (void); + +typedef decltype(nullptr) nullptr_t; + +int result = 0; + +void __attribute__((noinline)) +caught(int bit) +{ + result &= bit; +} + +struct A { }; + +int main() +{ + try { + try { + try { + try { + try { + throw nullptr; + } catch (void* p) { + if (p == nullptr) + caught(1); + throw; + } + } catch (void(*pf)()) { + if (pf == nullptr) + caught(2); + throw; + } + } catch (int A::*pm) { + if (pm == nullptr) + caught(4); + throw; + } + } catch (int (A::*pmf)()) { // FIXME: currently unsupported + if (pmf == nullptr) + caught(8); + throw; + } + } catch (nullptr_t) { + } + + if (result != 7) // should be 15 + abort (); +} diff --git a/libstdc++-v3/libsupc++/pbase_type_info.cc b/libstdc++-v3/libsupc++/pbase_type_info.cc index d47fb23..a2993e4 100644 --- a/libstdc++-v3/libsupc++/pbase_type_info.cc +++ b/libstdc++-v3/libsupc++/pbase_type_info.cc @@ -38,6 +38,31 @@ __do_catch (const type_info *thr_type, return true; // same type #if __cpp_rtti + if (*thr_type == typeid (nullptr)) + { + // A catch handler for any pointer type matches nullptr_t. + if (typeid (*this) == typeid(__pointer_type_info)) + { + *thr_obj = nullptr; + return true; + } + else if (typeid (*this) == typeid(__pointer_to_member_type_info)) + { + if (__pointee->__is_function_p ()) + { + // A pointer-to-member-function is two words <ptr,adj> but the + // nullptr_t exception object at *(nullptr_t*)*thr_obj is only + // one word, so we can't safely return it as a PMF. FIXME. + return false; + } + else + { + *(ptrdiff_t*)*thr_obj = -1; // null pointer to data member + return true; + } + } + } + if (typeid (*this) != typeid (*thr_type)) return false; // not both same kind of pointers #endif