/ test / incomplete_type.sh.cpp
incomplete_type.sh.cpp
  1  //===------------------------- incomplete_type.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  // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#rtti-layout
  9  
 10  // Two abi::__pbase_type_info objects can always be compared for equality
 11  // (i.e. of the types represented) or ordering by comparison of their name
 12  // NTBS addresses. In addition, unless either or both have either of the
 13  // incomplete flags set, equality can be tested by comparing the type_info
 14  // addresses.
 15  
 16  // UNSUPPORTED: no-exceptions
 17  // UNSUPPORTED: no-rtti
 18  
 19  // The fix for PR25898 landed in the system dylibs in macOS 10.13
 20  // XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}}
 21  
 22  // RUN: %{cxx} %{flags} %{compile_flags} -Wno-unreachable-code -c %s -o %t.one.o
 23  // RUN: %{cxx} %{flags} %{compile_flags} -Wno-unreachable-code -c %s -o %t.two.o -DTU_ONE
 24  // RUN: %{cxx} %{flags} %t.one.o %t.two.o %{link_flags} -o %t.exe
 25  // RUN: %{exec} %t.exe
 26  
 27  #include <stdio.h>
 28  #include <cstring>
 29  #include <cassert>
 30  #include <typeinfo>
 31  
 32  // Check that the addresses of the typeinfo differ but still compare equal
 33  // via their NTBS.
 34  inline void
 35  AssertIncompleteTypeInfoEquals(std::type_info const& LHS, std::type_info const& RHS)
 36  {
 37    assert(&LHS != &RHS);
 38    assert(strcmp(LHS.name(), RHS.name()) == 0);
 39  }
 40  
 41  struct NeverDefined;
 42  void ThrowNeverDefinedMP();
 43  std::type_info const& ReturnTypeInfoNeverDefinedMP();
 44  
 45  struct IncompleteAtThrow;
 46  void ThrowIncompleteMP();
 47  void ThrowIncompletePP();
 48  void ThrowIncompletePMP();
 49  std::type_info const& ReturnTypeInfoIncompleteMP();
 50  std::type_info const& ReturnTypeInfoIncompletePP();
 51  
 52  struct CompleteAtThrow;
 53  void ThrowCompleteMP();
 54  void ThrowCompletePP();
 55  void ThrowCompletePMP();
 56  std::type_info const& ReturnTypeInfoCompleteMP();
 57  std::type_info const& ReturnTypeInfoCompletePP();
 58  
 59  void ThrowNullptr();
 60  
 61  #ifndef TU_ONE
 62  
 63  void ThrowNeverDefinedMP() { throw (int NeverDefined::*)nullptr; }
 64  std::type_info const& ReturnTypeInfoNeverDefinedMP() { return typeid(int NeverDefined::*); }
 65  
 66  void ThrowIncompleteMP() { throw (int IncompleteAtThrow::*)nullptr; }
 67  void ThrowIncompletePP() { throw (IncompleteAtThrow**)nullptr; }
 68  void ThrowIncompletePMP() { throw (int IncompleteAtThrow::**)nullptr; }
 69  std::type_info const& ReturnTypeInfoIncompleteMP() { return typeid(int IncompleteAtThrow::*); }
 70  std::type_info const& ReturnTypeInfoIncompletePP() { return typeid(IncompleteAtThrow**); }
 71  
 72  struct CompleteAtThrow {};
 73  void ThrowCompleteMP() { throw (int CompleteAtThrow::*)nullptr; }
 74  void ThrowCompletePP() { throw (CompleteAtThrow**)nullptr; }
 75  void ThrowCompletePMP() { throw (int CompleteAtThrow::**)nullptr; }
 76  std::type_info const& ReturnTypeInfoCompleteMP() { return typeid(int CompleteAtThrow::*); }
 77  std::type_info const& ReturnTypeInfoCompletePP() { return typeid(CompleteAtThrow**); }
 78  
 79  void ThrowNullptr() { throw nullptr; }
 80  
 81  #else
 82  
 83  struct IncompleteAtThrow {};
 84  
 85  int main(int, char**) {
 86    AssertIncompleteTypeInfoEquals(ReturnTypeInfoNeverDefinedMP(), typeid(int NeverDefined::*));
 87    try {
 88      ThrowNeverDefinedMP();
 89      assert(false);
 90    } catch (int IncompleteAtThrow::*) {
 91      assert(false);
 92    } catch (int CompleteAtThrow::*) {
 93      assert(false);
 94    } catch (int NeverDefined::*p) {
 95      assert(!p);
 96    }
 97    catch(...) { assert(!"FAIL: Didn't catch NeverDefined::*" ); }
 98  
 99    AssertIncompleteTypeInfoEquals(ReturnTypeInfoIncompleteMP(), typeid(int IncompleteAtThrow::*));
100    try {
101      ThrowIncompleteMP();
102      assert(false);
103    } catch (CompleteAtThrow**) {
104      assert(false);
105    } catch (int CompleteAtThrow::*) {
106      assert(false);
107    } catch (IncompleteAtThrow**) {
108      assert(false);
109    } catch (int IncompleteAtThrow::*p) {
110      assert(!p);
111    }
112    catch(...) { assert(!"FAIL: Didn't catch IncompleteAtThrow::*" ); }
113  
114    AssertIncompleteTypeInfoEquals(ReturnTypeInfoIncompletePP(), typeid(IncompleteAtThrow**));
115    try {
116      ThrowIncompletePP();
117      assert(false);
118    } catch (int IncompleteAtThrow::*) {
119      assert(false);
120    } catch (IncompleteAtThrow** p) {
121      assert(!p);
122    }
123    catch(...) { assert(!"FAIL: Didn't catch IncompleteAtThrow**" ); }
124  
125    try {
126      ThrowIncompletePMP();
127      assert(false);
128    } catch (int IncompleteAtThrow::*) {
129      assert(false);
130    } catch (IncompleteAtThrow**) {
131      assert(false);
132    } catch (int IncompleteAtThrow::**p) {
133      assert(!p);
134    }
135    catch(...) { assert(!"FAIL: Didn't catch IncompleteAtThrow::**" ); }
136  
137    AssertIncompleteTypeInfoEquals(ReturnTypeInfoCompleteMP(), typeid(int CompleteAtThrow::*));
138    try {
139      ThrowCompleteMP();
140      assert(false);
141    } catch (IncompleteAtThrow**) {
142      assert(false);
143    } catch (int IncompleteAtThrow::*) {
144      assert(false);
145    } catch (CompleteAtThrow**) {
146      assert(false);
147    } catch (int CompleteAtThrow::*p) {
148      assert(!p);
149    }
150    catch(...) { assert(!"FAIL: Didn't catch CompleteAtThrow::" ); }
151  
152    AssertIncompleteTypeInfoEquals(ReturnTypeInfoCompletePP(), typeid(CompleteAtThrow**));
153    try {
154      ThrowCompletePP();
155      assert(false);
156    } catch (IncompleteAtThrow**) {
157      assert(false);
158    } catch (int IncompleteAtThrow::*) {
159      assert(false);
160    } catch (int CompleteAtThrow::*) {
161      assert(false);
162    } catch (CompleteAtThrow**p) {
163      assert(!p);
164    }
165    catch(...) { assert(!"FAIL: Didn't catch CompleteAtThrow**" ); }
166  
167    try {
168      ThrowCompletePMP();
169      assert(false);
170    } catch (IncompleteAtThrow**) {
171      assert(false);
172    } catch (int IncompleteAtThrow::*) {
173      assert(false);
174    } catch (int CompleteAtThrow::*) {
175      assert(false);
176    } catch (CompleteAtThrow**) {
177      assert(false);
178    } catch (int CompleteAtThrow::**p) {
179      assert(!p);
180    }
181    catch(...) { assert(!"FAIL: Didn't catch CompleteAtThrow::**" ); }
182  
183  #if __cplusplus >= 201103L
184    // Catch nullptr as complete type
185    try {
186      ThrowNullptr();
187    } catch (int IncompleteAtThrow::*p) {
188      assert(!p);
189    }
190    catch(...) { assert(!"FAIL: Didn't catch nullptr as IncompleteAtThrow::*" ); }
191  
192    // Catch nullptr as an incomplete type
193    try {
194      ThrowNullptr();
195    } catch (int CompleteAtThrow::*p) {
196      assert(!p);
197    }
198    catch(...) { assert(!"FAIL: Didn't catch nullptr as CompleteAtThrow::*" ); }
199  
200    // Catch nullptr as a type that is never complete.
201    try {
202      ThrowNullptr();
203    } catch (int NeverDefined::*p) {
204      assert(!p);
205    }
206    catch(...) { assert(!"FAIL: Didn't catch nullptr as NeverDefined::*" ); }
207  #endif
208  
209    return 0;
210  }
211  #endif