188 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This test case checks specifically the cases under bullet 3.3:10//11// C++ ABI 15.3:12// A handler is a match for an exception object of type E if13// * The handler is of type cv T or cv T& and E and T are the same type14// (ignoring the top-level cv-qualifiers), or15// * the handler is of type cv T or cv T& and T is an unambiguous base16// class of E, or17// > * the handler is of type cv1 T* cv2 and E is a pointer type that can <18// > be converted to the type of the handler by either or both of <19// > o a standard pointer conversion (4.10 [conv.ptr]) not involving <20// > conversions to private or protected or ambiguous classes <21// > o a qualification conversion <22// * the handler is a pointer or pointer to member type and E is23// std::nullptr_t24//25//===----------------------------------------------------------------------===//26 27// UNSUPPORTED: no-exceptions28 29// This test requires the fix to https://github.com/llvm/llvm-project/issues/64953,30// which landed in d5f84e6 and is in the libc++abi built library.31// XFAIL: using-built-library-before-llvm-1832 33#include <exception>34#include <stdlib.h>35#include <assert.h>36#include <stdio.h>37 38struct Base {39 int b;40};41struct Base2 {42 int b;43};44struct Derived1 : Base {45 int b;46};47struct Derived2 : Base {48 int b;49};50struct Derived3 : Base2 {51 int b;52};53struct Private : private Base {54 int b;55};56struct Protected : protected Base {57 int b;58};59struct Virtual1 : virtual Base {60 int b;61};62struct Virtual2 : virtual Base {63 int b;64};65 66struct Ambiguous1 : Derived1, Derived2 {67 int b;68};69struct Ambiguous2 : Derived1, Private {70 int b;71};72struct Ambiguous3 : Derived1, Protected {73 int b;74};75 76struct NoPublic1 : Private, Base2 {77 int b;78};79struct NoPublic2 : Protected, Base2 {80 int b;81};82 83struct Catchable1 : Derived3, Derived1 {84 int b;85};86struct Catchable2 : Virtual1, Virtual2 {87 int b;88};89struct Catchable3 : virtual Base, Virtual2 {90 int b;91};92 93// Check that, when we have a null pointer-to-object that we catch a nullptr.94template <typename T // Handler type95 ,96 typename E // Thrown exception type97 >98void assert_catches() {99 try {100 throw static_cast<E>(0);101 printf("%s\n", __PRETTY_FUNCTION__);102 assert(false && "Statements after throw must be unreachable");103 } catch (T t) {104 assert(t == nullptr);105 return;106 } catch (...) {107 printf("%s\n", __PRETTY_FUNCTION__);108 assert(false && "Should not have entered catch-all");109 }110 111 printf("%s\n", __PRETTY_FUNCTION__);112 assert(false && "The catch should have returned");113}114 115template <typename T // Handler type116 ,117 typename E // Thrown exception type118 >119void assert_cannot_catch() {120 try {121 throw static_cast<E>(0);122 printf("%s\n", __PRETTY_FUNCTION__);123 assert(false && "Statements after throw must be unreachable");124 } catch (T t) {125 printf("%s\n", __PRETTY_FUNCTION__);126 assert(false && "Should not have entered the catch");127 } catch (...) {128 assert(true);129 return;130 }131 132 printf("%s\n", __PRETTY_FUNCTION__);133 assert(false && "The catch-all should have returned");134}135 136// Check that when we have a pointer-to-actual-object we, in fact, get the137// adjusted pointer to the base class.138template <typename T // Handler type139 ,140 typename O // Object type141 >142void assert_catches_bp() {143 O* o = new (O);144 try {145 throw o;146 printf("%s\n", __PRETTY_FUNCTION__);147 assert(false && "Statements after throw must be unreachable");148 } catch (T t) {149 assert(t == static_cast<T>(o));150 //__builtin_printf("o = %p t = %p\n", o, t);151 delete o;152 return;153 } catch (...) {154 printf("%s\n", __PRETTY_FUNCTION__);155 assert(false && "Should not have entered catch-all");156 }157 158 printf("%s\n", __PRETTY_FUNCTION__);159 assert(false && "The catch should have returned");160}161 162void f1() {163 assert_catches<Base*, Catchable1*>();164 assert_catches<Base*, Catchable2*>();165 assert_catches<Base*, Catchable3*>();166}167 168void f2() {169 assert_cannot_catch<Base*, Ambiguous1*>();170 assert_cannot_catch<Base*, Ambiguous2*>();171 assert_cannot_catch<Base*, Ambiguous3*>();172 assert_cannot_catch<Base*, NoPublic1*>();173 assert_cannot_catch<Base*, NoPublic2*>();174}175 176void f3() {177 assert_catches_bp<Base*, Catchable1>();178 assert_catches_bp<Base*, Catchable2>();179 assert_catches_bp<Base*, Catchable3>();180}181 182int main(int, char**) {183 f1();184 f2();185 f3();186 return 0;187}188