Eric Fiselier | 91fc04d | 2016-01-19 23:42:10 +0000 | [diff] [blame] | 1 | //===------------------------- incomplete_type.cpp --------------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is dual licensed under the MIT and the University of Illinois Open |
| 6 | // Source Licenses. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // http://mentorembedded.github.io/cxx-abi/abi.html#rtti-layout |
| 10 | |
| 11 | // Two abi::__pbase_type_info objects can always be compared for equality |
| 12 | // (i.e. of the types represented) or ordering by comparison of their name |
| 13 | // NTBS addresses. In addition, unless either or both have either of the |
| 14 | // incomplete flags set, equality can be tested by comparing the type_info |
| 15 | // addresses. |
| 16 | |
Asiri Rathnayake | 4174e8b | 2016-05-31 12:01:32 +0000 | [diff] [blame] | 17 | // UNSUPPORTED: libcxxabi-no-exceptions |
| 18 | |
Eric Fiselier | 065ab9e | 2017-07-06 00:29:09 +0000 | [diff] [blame] | 19 | // NOTE: Pass -lc++abi explicitly and before -lc++ so that -lc++ doesn't drag |
| 20 | // in the system libc++abi installation on OS X. (DYLD_LIBRARY_PATH is ignored |
| 21 | // for shell tests because of Apple security features). |
| 22 | |
Eric Fiselier | 91fc04d | 2016-01-19 23:42:10 +0000 | [diff] [blame] | 23 | // RUN: %cxx %flags %compile_flags -c %s -o %t.one.o |
| 24 | // RUN: %cxx %flags %compile_flags -c %s -o %t.two.o -DTU_ONE |
Eric Fiselier | 065ab9e | 2017-07-06 00:29:09 +0000 | [diff] [blame] | 25 | // RUN: %cxx %flags %t.one.o %t.two.o -lc++abi %link_flags -o %t.exe |
Eric Fiselier | 3a15043 | 2017-05-10 08:15:40 +0000 | [diff] [blame] | 26 | // RUN: %t.exe |
Eric Fiselier | 91fc04d | 2016-01-19 23:42:10 +0000 | [diff] [blame] | 27 | |
| 28 | #include <stdio.h> |
| 29 | #include <cstring> |
| 30 | #include <cassert> |
| 31 | #include <typeinfo> |
| 32 | |
| 33 | // Check that the addresses of the typeinfo differ but still compare equal |
| 34 | // via their NTBS. |
| 35 | inline void |
| 36 | AssertIncompleteTypeInfoEquals(std::type_info const& LHS, std::type_info const& RHS) |
| 37 | { |
| 38 | assert(&LHS != &RHS); |
| 39 | assert(strcmp(LHS.name(), RHS.name()) == 0); |
| 40 | } |
| 41 | |
| 42 | struct NeverDefined; |
| 43 | void ThrowNeverDefinedMP(); |
| 44 | std::type_info const& ReturnTypeInfoNeverDefinedMP(); |
| 45 | |
| 46 | struct IncompleteAtThrow; |
| 47 | void ThrowIncompleteMP(); |
| 48 | void ThrowIncompletePP(); |
| 49 | void ThrowIncompletePMP(); |
| 50 | std::type_info const& ReturnTypeInfoIncompleteMP(); |
| 51 | std::type_info const& ReturnTypeInfoIncompletePP(); |
| 52 | |
| 53 | struct CompleteAtThrow; |
| 54 | void ThrowCompleteMP(); |
| 55 | void ThrowCompletePP(); |
| 56 | void ThrowCompletePMP(); |
| 57 | std::type_info const& ReturnTypeInfoCompleteMP(); |
| 58 | std::type_info const& ReturnTypeInfoCompletePP(); |
| 59 | |
| 60 | void ThrowNullptr(); |
| 61 | |
| 62 | #ifndef TU_ONE |
| 63 | |
| 64 | void ThrowNeverDefinedMP() { throw (int NeverDefined::*)nullptr; } |
| 65 | std::type_info const& ReturnTypeInfoNeverDefinedMP() { return typeid(int NeverDefined::*); } |
| 66 | |
| 67 | void ThrowIncompleteMP() { throw (int IncompleteAtThrow::*)nullptr; } |
| 68 | void ThrowIncompletePP() { throw (IncompleteAtThrow**)nullptr; } |
| 69 | void ThrowIncompletePMP() { throw (int IncompleteAtThrow::**)nullptr; } |
| 70 | std::type_info const& ReturnTypeInfoIncompleteMP() { return typeid(int IncompleteAtThrow::*); } |
| 71 | std::type_info const& ReturnTypeInfoIncompletePP() { return typeid(IncompleteAtThrow**); } |
| 72 | |
| 73 | struct CompleteAtThrow {}; |
| 74 | void ThrowCompleteMP() { throw (int CompleteAtThrow::*)nullptr; } |
| 75 | void ThrowCompletePP() { throw (CompleteAtThrow**)nullptr; } |
| 76 | void ThrowCompletePMP() { throw (int CompleteAtThrow::**)nullptr; } |
| 77 | std::type_info const& ReturnTypeInfoCompleteMP() { return typeid(int CompleteAtThrow::*); } |
| 78 | std::type_info const& ReturnTypeInfoCompletePP() { return typeid(CompleteAtThrow**); } |
| 79 | |
| 80 | void ThrowNullptr() { throw nullptr; } |
| 81 | |
| 82 | #else |
| 83 | |
| 84 | struct IncompleteAtThrow {}; |
| 85 | |
| 86 | int main() { |
| 87 | AssertIncompleteTypeInfoEquals(ReturnTypeInfoNeverDefinedMP(), typeid(int NeverDefined::*)); |
| 88 | try { |
| 89 | ThrowNeverDefinedMP(); |
| 90 | assert(false); |
| 91 | } catch (int IncompleteAtThrow::*) { |
| 92 | assert(false); |
| 93 | } catch (int CompleteAtThrow::*) { |
| 94 | assert(false); |
Richard Smith | 081ea86 | 2016-07-19 20:19:37 +0000 | [diff] [blame] | 95 | } catch (int NeverDefined::*p) { |
| 96 | assert(!p); |
| 97 | } |
Marshall Clow | 3d356fd | 2017-06-22 00:49:03 +0000 | [diff] [blame] | 98 | catch(...) { assert(!"FAIL: Didn't catch NeverDefined::*" ); } |
| 99 | |
Eric Fiselier | 91fc04d | 2016-01-19 23:42:10 +0000 | [diff] [blame] | 100 | AssertIncompleteTypeInfoEquals(ReturnTypeInfoIncompleteMP(), typeid(int IncompleteAtThrow::*)); |
| 101 | try { |
| 102 | ThrowIncompleteMP(); |
| 103 | assert(false); |
| 104 | } catch (CompleteAtThrow**) { |
| 105 | assert(false); |
| 106 | } catch (int CompleteAtThrow::*) { |
| 107 | assert(false); |
| 108 | } catch (IncompleteAtThrow**) { |
| 109 | assert(false); |
Richard Smith | 081ea86 | 2016-07-19 20:19:37 +0000 | [diff] [blame] | 110 | } catch (int IncompleteAtThrow::*p) { |
| 111 | assert(!p); |
| 112 | } |
Marshall Clow | 3d356fd | 2017-06-22 00:49:03 +0000 | [diff] [blame] | 113 | catch(...) { assert(!"FAIL: Didn't catch IncompleteAtThrow::*" ); } |
Eric Fiselier | 91fc04d | 2016-01-19 23:42:10 +0000 | [diff] [blame] | 114 | |
| 115 | AssertIncompleteTypeInfoEquals(ReturnTypeInfoIncompletePP(), typeid(IncompleteAtThrow**)); |
| 116 | try { |
| 117 | ThrowIncompletePP(); |
| 118 | assert(false); |
| 119 | } catch (int IncompleteAtThrow::*) { |
| 120 | assert(false); |
Richard Smith | 081ea86 | 2016-07-19 20:19:37 +0000 | [diff] [blame] | 121 | } catch (IncompleteAtThrow** p) { |
| 122 | assert(!p); |
| 123 | } |
Marshall Clow | 3d356fd | 2017-06-22 00:49:03 +0000 | [diff] [blame] | 124 | catch(...) { assert(!"FAIL: Didn't catch IncompleteAtThrow**" ); } |
Eric Fiselier | 91fc04d | 2016-01-19 23:42:10 +0000 | [diff] [blame] | 125 | |
| 126 | try { |
| 127 | ThrowIncompletePMP(); |
| 128 | assert(false); |
| 129 | } catch (int IncompleteAtThrow::*) { |
| 130 | assert(false); |
| 131 | } catch (IncompleteAtThrow**) { |
| 132 | assert(false); |
Richard Smith | 081ea86 | 2016-07-19 20:19:37 +0000 | [diff] [blame] | 133 | } catch (int IncompleteAtThrow::**p) { |
| 134 | assert(!p); |
| 135 | } |
Marshall Clow | 3d356fd | 2017-06-22 00:49:03 +0000 | [diff] [blame] | 136 | catch(...) { assert(!"FAIL: Didn't catch IncompleteAtThrow::**" ); } |
Eric Fiselier | 91fc04d | 2016-01-19 23:42:10 +0000 | [diff] [blame] | 137 | |
| 138 | AssertIncompleteTypeInfoEquals(ReturnTypeInfoCompleteMP(), typeid(int CompleteAtThrow::*)); |
| 139 | try { |
| 140 | ThrowCompleteMP(); |
| 141 | assert(false); |
| 142 | } catch (IncompleteAtThrow**) { |
| 143 | assert(false); |
| 144 | } catch (int IncompleteAtThrow::*) { |
| 145 | assert(false); |
| 146 | } catch (CompleteAtThrow**) { |
| 147 | assert(false); |
Richard Smith | 081ea86 | 2016-07-19 20:19:37 +0000 | [diff] [blame] | 148 | } catch (int CompleteAtThrow::*p) { |
| 149 | assert(!p); |
| 150 | } |
Marshall Clow | 3d356fd | 2017-06-22 00:49:03 +0000 | [diff] [blame] | 151 | catch(...) { assert(!"FAIL: Didn't catch CompleteAtThrow::" ); } |
Eric Fiselier | 91fc04d | 2016-01-19 23:42:10 +0000 | [diff] [blame] | 152 | |
| 153 | AssertIncompleteTypeInfoEquals(ReturnTypeInfoCompletePP(), typeid(CompleteAtThrow**)); |
| 154 | try { |
| 155 | ThrowCompletePP(); |
| 156 | assert(false); |
| 157 | } catch (IncompleteAtThrow**) { |
| 158 | assert(false); |
| 159 | } catch (int IncompleteAtThrow::*) { |
| 160 | assert(false); |
| 161 | } catch (int CompleteAtThrow::*) { |
| 162 | assert(false); |
Richard Smith | 081ea86 | 2016-07-19 20:19:37 +0000 | [diff] [blame] | 163 | } catch (CompleteAtThrow**p) { |
| 164 | assert(!p); |
| 165 | } |
Marshall Clow | 3d356fd | 2017-06-22 00:49:03 +0000 | [diff] [blame] | 166 | catch(...) { assert(!"FAIL: Didn't catch CompleteAtThrow**" ); } |
Eric Fiselier | 91fc04d | 2016-01-19 23:42:10 +0000 | [diff] [blame] | 167 | |
| 168 | try { |
| 169 | ThrowCompletePMP(); |
| 170 | assert(false); |
| 171 | } catch (IncompleteAtThrow**) { |
| 172 | assert(false); |
| 173 | } catch (int IncompleteAtThrow::*) { |
| 174 | assert(false); |
| 175 | } catch (int CompleteAtThrow::*) { |
| 176 | assert(false); |
| 177 | } catch (CompleteAtThrow**) { |
| 178 | assert(false); |
Richard Smith | 081ea86 | 2016-07-19 20:19:37 +0000 | [diff] [blame] | 179 | } catch (int CompleteAtThrow::**p) { |
| 180 | assert(!p); |
| 181 | } |
Marshall Clow | 3d356fd | 2017-06-22 00:49:03 +0000 | [diff] [blame] | 182 | catch(...) { assert(!"FAIL: Didn't catch CompleteAtThrow::**" ); } |
Eric Fiselier | 91fc04d | 2016-01-19 23:42:10 +0000 | [diff] [blame] | 183 | |
| 184 | #if __cplusplus >= 201103L |
| 185 | // Catch nullptr as complete type |
| 186 | try { |
| 187 | ThrowNullptr(); |
Richard Smith | 081ea86 | 2016-07-19 20:19:37 +0000 | [diff] [blame] | 188 | } catch (int IncompleteAtThrow::*p) { |
| 189 | assert(!p); |
| 190 | } |
Marshall Clow | 3d356fd | 2017-06-22 00:49:03 +0000 | [diff] [blame] | 191 | catch(...) { assert(!"FAIL: Didn't catch nullptr as IncompleteAtThrow::*" ); } |
Eric Fiselier | 91fc04d | 2016-01-19 23:42:10 +0000 | [diff] [blame] | 192 | |
| 193 | // Catch nullptr as an incomplete type |
| 194 | try { |
| 195 | ThrowNullptr(); |
Richard Smith | 081ea86 | 2016-07-19 20:19:37 +0000 | [diff] [blame] | 196 | } catch (int CompleteAtThrow::*p) { |
| 197 | assert(!p); |
| 198 | } |
Marshall Clow | 3d356fd | 2017-06-22 00:49:03 +0000 | [diff] [blame] | 199 | catch(...) { assert(!"FAIL: Didn't catch nullptr as CompleteAtThrow::*" ); } |
| 200 | |
Eric Fiselier | 91fc04d | 2016-01-19 23:42:10 +0000 | [diff] [blame] | 201 | // Catch nullptr as a type that is never complete. |
| 202 | try { |
| 203 | ThrowNullptr(); |
Richard Smith | 081ea86 | 2016-07-19 20:19:37 +0000 | [diff] [blame] | 204 | } catch (int NeverDefined::*p) { |
| 205 | assert(!p); |
| 206 | } |
Marshall Clow | 3d356fd | 2017-06-22 00:49:03 +0000 | [diff] [blame] | 207 | catch(...) { assert(!"FAIL: Didn't catch nullptr as NeverDefined::*" ); } |
| 208 | |
Eric Fiselier | 91fc04d | 2016-01-19 23:42:10 +0000 | [diff] [blame] | 209 | #endif |
| 210 | } |
| 211 | #endif |