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