This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
[PATCH] c++/58796 Make nullptr match exception handlers of pointer type
- From: Jonathan Wakely <jwakely at redhat dot com>
- To: libstdc++ at gcc dot gnu dot org, gcc-patches at gcc dot gnu dot org
- Cc: Jason Merrill <jason at redhat dot com>
- Date: Fri, 15 Jul 2016 12:47:35 +0100
- Subject: [PATCH] c++/58796 Make nullptr match exception handlers of pointer type
- Authentication-results: sourceware.org; auth=none
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 <jwakely@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