/ test / inherited_exception.pass.cpp
inherited_exception.pass.cpp
  1  //===--------------------- inherited_exception.cpp ------------------------===//
  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-exception
  6  //
  7  //===----------------------------------------------------------------------===//
  8  //
  9  // This test case checks specifically the cases under C++ ABI 15.3.1, and 15.3.2
 10  //
 11  //  C++ ABI 15.3:
 12  //  A handler is a match for an exception object of type E if
 13  //  >  *  The handler is of type cv T or cv T& and E and T are the same type   <
 14  //  >     (ignoring the top-level cv-qualifiers), or                           <
 15  //  >  *  the handler is of type cv T or cv T& and T is an unambiguous base    <
 16  //  >     class of E, or                                                       <
 17  //     *  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 is
 23  //        std::nullptr_t
 24  //
 25  //===----------------------------------------------------------------------===//
 26  
 27  // UNSUPPORTED: no-exceptions
 28  
 29  // FIXME: GCC doesn't allow turning off the warning for exceptions being caught
 30  //        by earlier handlers, which this test is exercising. We have to disable
 31  //        warnings altogether to remove the error.
 32  //        See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97675.
 33  // ADDITIONAL_COMPILE_FLAGS: -Wno-error
 34  
 35  // Clang emits  warnings about exceptions of type 'Child' being caught by
 36  // an earlier handler of type 'Base'. Congrats clang, you've just
 37  // diagnosed the behavior under test.
 38  #if defined(__clang__)
 39  #pragma clang diagnostic ignored "-Wexceptions"
 40  #endif
 41  
 42  #include <assert.h>
 43  
 44  struct Base {
 45    int b1;
 46  };
 47  
 48  struct Base2 {
 49    int b2;
 50  };
 51  
 52  struct Child : public Base, public Base2 {
 53    int c;
 54  };
 55  
 56  void f1() {
 57    Child child;
 58    child.b1 = 10;
 59    child.b2 = 11;
 60    child.c = 12;
 61    throw child;
 62  }
 63  
 64  void f2() {
 65    Child child;
 66    child.b1 = 10;
 67    child.b2 = 11;
 68    child.c = 12;
 69    throw static_cast<Base2&>(child);
 70  }
 71  
 72  void f3() {
 73    static Child child;
 74    child.b1 = 10;
 75    child.b2 = 11;
 76    child.c = 12;
 77    throw static_cast<Base2*>(&child);
 78  }
 79  
 80  int main(int, char**)
 81  {
 82      try
 83      {
 84          f1();
 85          assert(false);
 86      }
 87      catch (const Child& c)
 88      {
 89          assert(true);
 90      }
 91      catch (const Base& b)
 92      {
 93          assert(false);
 94      }
 95      catch (...)
 96      {
 97          assert(false);
 98      }
 99  
100      try
101      {
102          f1();
103          assert(false);
104      }
105      catch (const Base& c)
106      {
107          assert(true);
108      }
109      catch (const Child& b)
110      {
111          assert(false);
112      }
113      catch (...)
114      {
115          assert(false);
116      }
117  
118      try
119      {
120          f1();
121          assert(false);
122      }
123      catch (const Base2& c)
124      {
125          assert(true);
126      }
127      catch (const Child& b)
128      {
129          assert(false);
130      }
131      catch (...)
132      {
133          assert(false);
134      }
135  
136      try
137      {
138          f2();
139          assert(false);
140      }
141      catch (const Child& c)
142      {
143          assert(false);
144      }
145      catch (const Base& b)
146      {
147          assert(false);
148      }
149      catch (const Base2& b)
150      {
151          assert(true);
152      }
153      catch (...)
154      {
155          assert(false);
156      }
157  
158      try
159      {
160          f3();
161          assert(false);
162      }
163      catch (const Base* c)
164      {
165          assert(false);
166      }
167      catch (const Child* b)
168      {
169          assert(false);
170      }
171      catch (const Base2* c)
172      {
173          assert(true);
174      }
175      catch (...)
176      {
177          assert(false);
178      }
179  
180      return 0;
181  }