From 75fd1b5f51299a28407dfb547bdab8d44c61d6f0 Mon Sep 17 00:00:00 2001 From: Jonathan Roelofs Date: Sat, 31 May 2014 00:24:58 +0000 Subject: [PATCH] Add EH test cases corresponding to C++ ABI # 15.3.3 llvm-svn: 209943 --- libcxxabi/test/catch_pointer_reference.cpp | 444 +++++++++++++++++++++++++++++ 1 file changed, 444 insertions(+) create mode 100644 libcxxabi/test/catch_pointer_reference.cpp diff --git a/libcxxabi/test/catch_pointer_reference.cpp b/libcxxabi/test/catch_pointer_reference.cpp new file mode 100644 index 0000000..88d2140 --- /dev/null +++ b/libcxxabi/test/catch_pointer_reference.cpp @@ -0,0 +1,444 @@ +//===---------------------- catch_pointer_referece.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. +// +//===----------------------------------------------------------------------===// +// +// This test case checks specifically the cases under bullet 3.1 & 3.2: +// +// C++ ABI 15.3: +// A handler is a match for an exception object of type E if +// * The handler is of type cv T or cv T& and E and T are the same type +// (ignoring the top-level cv-qualifiers), or +// * the handler is of type cv T or cv T& and T is an unambiguous base +// class of E, or +// / * the handler is of type cv1 T* cv2 and E is a pointer type that can \ +// | be converted to the type of the handler by either or both of | +// | o a standard pointer conversion (4.10 [conv.ptr]) not involving | +// | conversions to private or protected or ambiguous classes | +// \ o a qualification conversion / +// * the handler is a pointer or pointer to member type and E is +// std::nullptr_t +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include + +struct Base {}; +struct Derived : Base {}; +struct Derived2 : Base {}; +struct Ambiguous : Derived, Derived2 {}; +struct Private : private Base {}; +struct Protected : protected Base {}; + +template +void assert_catches() +{ + try + { + O o; + throw static_cast(&o); + printf("%s\n", __PRETTY_FUNCTION__); + assert(false && "Statements after throw must be unreachable"); + } + catch (T t) + { + assert(true); + return; + } + catch (...) + { + printf("%s\n", __PRETTY_FUNCTION__); + assert(false && "Should not have entered catch-all"); + } + + printf("%s\n", __PRETTY_FUNCTION__); + assert(false && "The catch should have returned"); +} + +template +void assert_cannot_catch() +{ + try + { + O o; + throw static_cast(&o); + printf("%s\n", __PRETTY_FUNCTION__); + assert(false && "Statements after throw must be unreachable"); + } + catch (T t) + { + printf("%s\n", __PRETTY_FUNCTION__); + assert(false && "Should not have entered the catch"); + } + catch (...) + { + assert(true); + return; + } + + printf("%s\n", __PRETTY_FUNCTION__); + assert(false && "The catch-all should have returned"); +} + +void f1() +{ + // Test that every combination of handler of type: + // cv1 Base * cv2 + // catches an exception of type: + // Derived * + assert_catches< Base * , Derived *, Derived>(); + assert_catches(); + assert_catches< volatile Base * , Derived *, Derived>(); + assert_catches(); + assert_catches< Base * const , Derived *, Derived>(); + assert_catches(); + assert_catches< volatile Base * const , Derived *, Derived>(); + assert_catches(); + assert_catches< Base * volatile, Derived *, Derived>(); + assert_catches(); + assert_catches< volatile Base * volatile, Derived *, Derived>(); + assert_catches(); + assert_catches< Base * const volatile, Derived *, Derived>(); + assert_catches(); + assert_catches< volatile Base * const volatile, Derived *, Derived>(); + assert_catches(); +} + +void f2() +{ + // Test that every combination of handler of type: + // cv1 Base * cv2 + // catches an exception of type: + // Base * + assert_catches< Base * , Base *, Derived>(); + assert_catches(); + assert_catches< volatile Base * , Base *, Derived>(); + assert_catches(); + assert_catches< Base * const , Base *, Derived>(); + assert_catches(); + assert_catches< volatile Base * const , Base *, Derived>(); + assert_catches(); + assert_catches< Base * volatile, Base *, Derived>(); + assert_catches(); + assert_catches< volatile Base * volatile, Base *, Derived>(); + assert_catches(); + assert_catches< Base * const volatile, Base *, Derived>(); + assert_catches(); + assert_catches< volatile Base * const volatile, Base *, Derived>(); + assert_catches(); +} + +void f3() +{ + // Test that every combination of handler of type: + // cv1 Derived * cv2 + // catches an exception of type: + // Derived * + assert_catches< Derived * , Derived *, Derived>(); + assert_catches(); + assert_catches< volatile Derived * , Derived *, Derived>(); + assert_catches(); + assert_catches< Derived * const , Derived *, Derived>(); + assert_catches(); + assert_catches< volatile Derived * const , Derived *, Derived>(); + assert_catches(); + assert_catches< Derived * volatile, Derived *, Derived>(); + assert_catches(); + assert_catches< volatile Derived * volatile, Derived *, Derived>(); + assert_catches(); + assert_catches< Derived * const volatile, Derived *, Derived>(); + assert_catches(); + assert_catches< volatile Derived * const volatile, Derived *, Derived>(); + assert_catches(); +} + +void f4() +{ + // Test that every combination of handler of type: + // cv1 Derived * cv2 + // cannot catch an exception of type: + // Base * + assert_cannot_catch< Derived * , Base *, Derived>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Derived * , Base *, Derived>(); + assert_cannot_catch(); + assert_cannot_catch< Derived * const , Base *, Derived>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Derived * const , Base *, Derived>(); + assert_cannot_catch(); + assert_cannot_catch< Derived * volatile, Base *, Derived>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Derived * volatile, Base *, Derived>(); + assert_cannot_catch(); + assert_cannot_catch< Derived * const volatile, Base *, Derived>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Derived * const volatile, Base *, Derived>(); + assert_cannot_catch(); +} + +void f5() +{ + // Test that every combination of handler of type: + // cv1 Derived * cv2 & + // catches an exception of type: + // Derived * + assert_catches< Derived * &, Derived *, Derived>(); + assert_catches(); + assert_catches< volatile Derived * &, Derived *, Derived>(); + assert_catches(); + assert_catches< Derived * const &, Derived *, Derived>(); + assert_catches(); + assert_catches< volatile Derived * const &, Derived *, Derived>(); + assert_catches(); + assert_catches< Derived * volatile &, Derived *, Derived>(); + assert_catches(); + assert_catches< volatile Derived * volatile &, Derived *, Derived>(); + assert_catches(); + assert_catches< Derived * const volatile &, Derived *, Derived>(); + assert_catches(); + assert_catches< volatile Derived * const volatile &, Derived *, Derived>(); + assert_catches(); +} + +void f6() +{ + // Test that every combination of handler of type: + // cv1 Base * cv2 & + // catches an exception of type: + // Base * + assert_catches< Base * &, Base *, Derived>(); + assert_catches(); + assert_catches< volatile Base * &, Base *, Derived>(); + assert_catches(); + assert_catches< Base * const &, Base *, Derived>(); + assert_catches(); + assert_catches< volatile Base * const &, Base *, Derived>(); + assert_catches(); + assert_catches< Base * volatile &, Base *, Derived>(); + assert_catches(); + assert_catches< volatile Base * volatile &, Base *, Derived>(); + assert_catches(); + assert_catches< Base * const volatile &, Base *, Derived>(); + assert_catches(); + assert_catches< volatile Base * const volatile &, Base *, Derived>(); + assert_catches(); + +} + +void f7() +{ + // Test that every combination of handler of type: + // cv1 Derived * cv2 & + // cannot catch an exception of type: + // Base * + assert_cannot_catch< Derived * &, Base *, Derived>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Derived * &, Base *, Derived>(); + assert_cannot_catch(); + assert_cannot_catch< Derived * const &, Base *, Derived>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Derived * const &, Base *, Derived>(); + assert_cannot_catch(); + assert_cannot_catch< Derived * volatile &, Base *, Derived>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Derived * volatile &, Base *, Derived>(); + assert_cannot_catch(); + assert_cannot_catch< Derived * const volatile &, Base *, Derived>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Derived * const volatile &, Base *, Derived>(); + assert_cannot_catch(); +} + +void f8() +{ + // This test case has a caveat noted in the discussion here: + // https://gcc.gnu.org/ml/gcc-patches/2009-08/msg00264.html + // Specifically: + // This [test exposes a] corner case of the ARM C++ ABI. The generic C++ + // ABI also gets this wrong, because I failed to notice the subtlety here. + // The issue is that 15.3/3 3rd bullet says: + // The handler is of type cv1 T* cv2 and E is a pointer type that + // can be converted to the type of the handler by either or both of: + // * a standard pointer conversion (4.10) not involving conversions + // to pointers to private or protected or ambiguous classes + // Notice that the handlers of type "cv1 T*cv2&" are not allowed such + // freedom to find a base class. The ABI error is that we treat handlers + // of reference type exactly the same as the corresponding hander of + // non-reference type. Elsewhere in the exception handling this makes no + // difference (for instance bullet 1 explicitly says 'cv T or cv T&'). + // + // See also: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#388 + // + // TL;DR: it is an unresolved C++ ABI defect that these do catch + + // Test that every combination of handler of type: + // cv1 Base * cv2 & + // catches an exception of type: + // Derived * + assert_catches< Base * &, Derived *, Derived>(); + assert_catches(); + assert_catches< volatile Base * &, Derived *, Derived>(); + assert_catches(); + assert_catches< Base * const &, Derived *, Derived>(); + assert_catches(); + assert_catches< volatile Base * const &, Derived *, Derived>(); + assert_catches(); + assert_catches< Base * volatile &, Derived *, Derived>(); + assert_catches(); + assert_catches< volatile Base * volatile &, Derived *, Derived>(); + assert_catches(); + assert_catches< Base * const volatile &, Derived *, Derived>(); + assert_catches(); + assert_catches< volatile Base * const volatile &, Derived *, Derived>(); + assert_catches(); +} + +void f9() +{ + // Test that every combination of handler of type: + // cv1 Base * cv2 + // cannot catch an exception of type: + // Ambiguous * + assert_cannot_catch< Base * , Ambiguous *, Ambiguous>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Base * , Ambiguous *, Ambiguous>(); + assert_cannot_catch(); + assert_cannot_catch< Base * const , Ambiguous *, Ambiguous>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Base * const , Ambiguous *, Ambiguous>(); + assert_cannot_catch(); + assert_cannot_catch< Base * volatile, Ambiguous *, Ambiguous>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Base * volatile, Ambiguous *, Ambiguous>(); + assert_cannot_catch(); + assert_cannot_catch< Base * const volatile, Ambiguous *, Ambiguous>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Base * const volatile, Ambiguous *, Ambiguous>(); + assert_cannot_catch(); +} + +void f10() +{ + // Test that every combination of handler of type: + // cv1 Base * cv2 + // cannot catch an exception of type: + // Private * + assert_cannot_catch< Base * , Private *, Private>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Base * , Private *, Private>(); + assert_cannot_catch(); + assert_cannot_catch< Base * const , Private *, Private>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Base * const , Private *, Private>(); + assert_cannot_catch(); + assert_cannot_catch< Base * volatile, Private *, Private>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Base * volatile, Private *, Private>(); + assert_cannot_catch(); + assert_cannot_catch< Base * const volatile, Private *, Private>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Base * const volatile, Private *, Private>(); + assert_cannot_catch(); +} + +void f11() +{ + // Test that every combination of handler of type: + // cv1 Base * cv2 + // cannot catch an exception of type: + // Protected * + assert_cannot_catch< Base * , Protected *, Protected>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Base * , Protected *, Protected>(); + assert_cannot_catch(); + assert_cannot_catch< Base * const , Protected *, Protected>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Base * const , Protected *, Protected>(); + assert_cannot_catch(); + assert_cannot_catch< Base * volatile, Protected *, Protected>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Base * volatile, Protected *, Protected>(); + assert_cannot_catch(); + assert_cannot_catch< Base * const volatile, Protected *, Protected>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Base * const volatile, Protected *, Protected>(); + assert_cannot_catch(); +} + +void f12() +{ + // Test that every combination of handler of type: + // cv1 Base * cv2 & + // cannot catch an exception of type: + // Private * + assert_cannot_catch< Base * &, Private *, Private>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Base * &, Private *, Private>(); + assert_cannot_catch(); + assert_cannot_catch< Base * const &, Private *, Private>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Base * const &, Private *, Private>(); + assert_cannot_catch(); + assert_cannot_catch< Base * volatile &, Private *, Private>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Base * volatile &, Private *, Private>(); + assert_cannot_catch(); + assert_cannot_catch< Base * const volatile &, Private *, Private>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Base * const volatile &, Private *, Private>(); + assert_cannot_catch(); +} + +void f13() +{ + // Test that every combination of handler of type: + // cv1 Base * cv2 & + // cannot catch an exception of type: + // Protected * + assert_cannot_catch< Base * &, Protected *, Protected>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Base * &, Protected *, Protected>(); + assert_cannot_catch(); + assert_cannot_catch< Base * const &, Protected *, Protected>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Base * const &, Protected *, Protected>(); + assert_cannot_catch(); + assert_cannot_catch< Base * volatile &, Protected *, Protected>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Base * volatile &, Protected *, Protected>(); + assert_cannot_catch(); + assert_cannot_catch< Base * const volatile &, Protected *, Protected>(); + assert_cannot_catch(); + assert_cannot_catch< volatile Base * const volatile &, Protected *, Protected>(); + assert_cannot_catch(); +} + +int main() +{ + f1(); + f2(); + f3(); + f4(); + f5(); + f6(); + f7(); + f8(); + f9(); + f10(); + f11(); + f12(); + f13(); +} -- 2.7.4