1 | //===- ValueHandleTest.cpp - ValueHandle tests ----------------------------===// |
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 | #include "llvm/IR/ValueHandle.h" |
10 | #include "llvm/IR/Constants.h" |
11 | #include "llvm/IR/Instructions.h" |
12 | #include "llvm/IR/LLVMContext.h" |
13 | #include "gtest/gtest.h" |
14 | #include <memory> |
15 | |
16 | using namespace llvm; |
17 | |
18 | namespace { |
19 | |
20 | class ValueHandle : public testing::Test { |
21 | protected: |
22 | LLVMContext Context; |
23 | Constant *ConstantV; |
24 | std::unique_ptr<BitCastInst> BitcastV; |
25 | |
26 | ValueHandle() |
27 | : ConstantV(ConstantInt::get(Ty: Type::getInt32Ty(C&: Context), V: 0)), |
28 | BitcastV(new BitCastInst(ConstantV, Type::getInt32Ty(C&: Context))) {} |
29 | }; |
30 | |
31 | class ConcreteCallbackVH final : public CallbackVH { |
32 | public: |
33 | ConcreteCallbackVH(Value *V) : CallbackVH(V) {} |
34 | }; |
35 | |
36 | TEST_F(ValueHandle, WeakVH_BasicOperation) { |
37 | WeakVH WVH(BitcastV.get()); |
38 | EXPECT_EQ(BitcastV.get(), WVH); |
39 | WVH = ConstantV; |
40 | EXPECT_EQ(ConstantV, WVH); |
41 | |
42 | // Make sure I can call a method on the underlying Value. It |
43 | // doesn't matter which method. |
44 | EXPECT_EQ(Type::getInt32Ty(Context), WVH->getType()); |
45 | EXPECT_EQ(Type::getInt32Ty(Context), (*WVH).getType()); |
46 | |
47 | WVH = BitcastV.get(); |
48 | BitcastV->replaceAllUsesWith(V: ConstantV); |
49 | EXPECT_EQ(WVH, BitcastV.get()); |
50 | BitcastV.reset(); |
51 | EXPECT_EQ(WVH, nullptr); |
52 | } |
53 | |
54 | TEST_F(ValueHandle, WeakTrackingVH_BasicOperation) { |
55 | WeakTrackingVH WVH(BitcastV.get()); |
56 | EXPECT_EQ(BitcastV.get(), WVH); |
57 | WVH = ConstantV; |
58 | EXPECT_EQ(ConstantV, WVH); |
59 | |
60 | // Make sure I can call a method on the underlying Value. It |
61 | // doesn't matter which method. |
62 | EXPECT_EQ(Type::getInt32Ty(Context), WVH->getType()); |
63 | EXPECT_EQ(Type::getInt32Ty(Context), (*WVH).getType()); |
64 | } |
65 | |
66 | TEST_F(ValueHandle, WeakTrackingVH_Comparisons) { |
67 | WeakTrackingVH BitcastWVH(BitcastV.get()); |
68 | WeakTrackingVH ConstantWVH(ConstantV); |
69 | |
70 | EXPECT_TRUE(BitcastWVH == BitcastWVH); |
71 | EXPECT_TRUE(BitcastV.get() == BitcastWVH); |
72 | EXPECT_TRUE(BitcastWVH == BitcastV.get()); |
73 | EXPECT_FALSE(BitcastWVH == ConstantWVH); |
74 | |
75 | EXPECT_TRUE(BitcastWVH != ConstantWVH); |
76 | EXPECT_TRUE(BitcastV.get() != ConstantWVH); |
77 | EXPECT_TRUE(BitcastWVH != ConstantV); |
78 | EXPECT_FALSE(BitcastWVH != BitcastWVH); |
79 | |
80 | // Cast to Value* so comparisons work. |
81 | Value *BV = BitcastV.get(); |
82 | Value *CV = ConstantV; |
83 | EXPECT_EQ(BV < CV, BitcastWVH < ConstantWVH); |
84 | EXPECT_EQ(BV <= CV, BitcastWVH <= ConstantWVH); |
85 | EXPECT_EQ(BV > CV, BitcastWVH > ConstantWVH); |
86 | EXPECT_EQ(BV >= CV, BitcastWVH >= ConstantWVH); |
87 | |
88 | EXPECT_EQ(BV < CV, BitcastV.get() < ConstantWVH); |
89 | EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantWVH); |
90 | EXPECT_EQ(BV > CV, BitcastV.get() > ConstantWVH); |
91 | EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantWVH); |
92 | |
93 | EXPECT_EQ(BV < CV, BitcastWVH < ConstantV); |
94 | EXPECT_EQ(BV <= CV, BitcastWVH <= ConstantV); |
95 | EXPECT_EQ(BV > CV, BitcastWVH > ConstantV); |
96 | EXPECT_EQ(BV >= CV, BitcastWVH >= ConstantV); |
97 | } |
98 | |
99 | TEST_F(ValueHandle, WeakTrackingVH_FollowsRAUW) { |
100 | WeakTrackingVH WVH(BitcastV.get()); |
101 | WeakTrackingVH WVH_Copy(WVH); |
102 | WeakTrackingVH WVH_Recreated(BitcastV.get()); |
103 | BitcastV->replaceAllUsesWith(V: ConstantV); |
104 | EXPECT_EQ(ConstantV, WVH); |
105 | EXPECT_EQ(ConstantV, WVH_Copy); |
106 | EXPECT_EQ(ConstantV, WVH_Recreated); |
107 | } |
108 | |
109 | TEST_F(ValueHandle, WeakTrackingVH_NullOnDeletion) { |
110 | WeakTrackingVH WVH(BitcastV.get()); |
111 | WeakTrackingVH WVH_Copy(WVH); |
112 | WeakTrackingVH WVH_Recreated(BitcastV.get()); |
113 | BitcastV.reset(); |
114 | Value *null_value = nullptr; |
115 | EXPECT_EQ(null_value, WVH); |
116 | EXPECT_EQ(null_value, WVH_Copy); |
117 | EXPECT_EQ(null_value, WVH_Recreated); |
118 | } |
119 | |
120 | |
121 | TEST_F(ValueHandle, AssertingVH_BasicOperation) { |
122 | AssertingVH<CastInst> AVH(BitcastV.get()); |
123 | CastInst *implicit_to_exact_type = AVH; |
124 | (void)implicit_to_exact_type; // Avoid warning. |
125 | |
126 | AssertingVH<Value> GenericAVH(BitcastV.get()); |
127 | EXPECT_EQ(BitcastV.get(), GenericAVH); |
128 | GenericAVH = ConstantV; |
129 | EXPECT_EQ(ConstantV, GenericAVH); |
130 | |
131 | // Make sure I can call a method on the underlying CastInst. It |
132 | // doesn't matter which method. |
133 | EXPECT_FALSE(AVH->mayWriteToMemory()); |
134 | EXPECT_FALSE((*AVH).mayWriteToMemory()); |
135 | } |
136 | |
137 | TEST_F(ValueHandle, AssertingVH_Const) { |
138 | const CastInst *ConstBitcast = BitcastV.get(); |
139 | AssertingVH<const CastInst> AVH(ConstBitcast); |
140 | const CastInst *implicit_to_exact_type = AVH; |
141 | (void)implicit_to_exact_type; // Avoid warning. |
142 | } |
143 | |
144 | TEST_F(ValueHandle, AssertingVH_Comparisons) { |
145 | AssertingVH<Value> BitcastAVH(BitcastV.get()); |
146 | AssertingVH<Value> ConstantAVH(ConstantV); |
147 | |
148 | EXPECT_TRUE(BitcastAVH == BitcastAVH); |
149 | EXPECT_TRUE(BitcastV.get() == BitcastAVH); |
150 | EXPECT_TRUE(BitcastAVH == BitcastV.get()); |
151 | EXPECT_FALSE(BitcastAVH == ConstantAVH); |
152 | |
153 | EXPECT_TRUE(BitcastAVH != ConstantAVH); |
154 | EXPECT_TRUE(BitcastV.get() != ConstantAVH); |
155 | EXPECT_TRUE(BitcastAVH != ConstantV); |
156 | EXPECT_FALSE(BitcastAVH != BitcastAVH); |
157 | |
158 | // Cast to Value* so comparisons work. |
159 | Value *BV = BitcastV.get(); |
160 | Value *CV = ConstantV; |
161 | EXPECT_EQ(BV < CV, BitcastAVH < ConstantAVH); |
162 | EXPECT_EQ(BV <= CV, BitcastAVH <= ConstantAVH); |
163 | EXPECT_EQ(BV > CV, BitcastAVH > ConstantAVH); |
164 | EXPECT_EQ(BV >= CV, BitcastAVH >= ConstantAVH); |
165 | |
166 | EXPECT_EQ(BV < CV, BitcastV.get() < ConstantAVH); |
167 | EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantAVH); |
168 | EXPECT_EQ(BV > CV, BitcastV.get() > ConstantAVH); |
169 | EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantAVH); |
170 | |
171 | EXPECT_EQ(BV < CV, BitcastAVH < ConstantV); |
172 | EXPECT_EQ(BV <= CV, BitcastAVH <= ConstantV); |
173 | EXPECT_EQ(BV > CV, BitcastAVH > ConstantV); |
174 | EXPECT_EQ(BV >= CV, BitcastAVH >= ConstantV); |
175 | } |
176 | |
177 | TEST_F(ValueHandle, AssertingVH_DoesNotFollowRAUW) { |
178 | AssertingVH<Value> AVH(BitcastV.get()); |
179 | BitcastV->replaceAllUsesWith(V: ConstantV); |
180 | EXPECT_EQ(BitcastV.get(), AVH); |
181 | } |
182 | |
183 | #ifdef NDEBUG |
184 | |
185 | TEST_F(ValueHandle, AssertingVH_ReducesToPointer) { |
186 | EXPECT_EQ(sizeof(CastInst *), sizeof(AssertingVH<CastInst>)); |
187 | } |
188 | |
189 | #elif LLVM_ENABLE_ABI_BREAKING_CHECKS // && !NDEBUG |
190 | |
191 | #ifdef GTEST_HAS_DEATH_TEST |
192 | |
193 | TEST_F(ValueHandle, AssertingVH_Asserts) { |
194 | AssertingVH<Value> AVH(BitcastV.get()); |
195 | EXPECT_DEATH({BitcastV.reset();}, |
196 | "An asserting value handle still pointed to this value!" ); |
197 | AssertingVH<Value> Copy(AVH); |
198 | AVH = nullptr; |
199 | EXPECT_DEATH({BitcastV.reset();}, |
200 | "An asserting value handle still pointed to this value!" ); |
201 | Copy = nullptr; |
202 | BitcastV.reset(); |
203 | } |
204 | |
205 | #endif // GTEST_HAS_DEATH_TEST |
206 | |
207 | #endif // NDEBUG |
208 | |
209 | TEST_F(ValueHandle, CallbackVH_BasicOperation) { |
210 | ConcreteCallbackVH CVH(BitcastV.get()); |
211 | EXPECT_EQ(BitcastV.get(), CVH); |
212 | CVH = ConstantV; |
213 | EXPECT_EQ(ConstantV, CVH); |
214 | |
215 | // Make sure I can call a method on the underlying Value. It |
216 | // doesn't matter which method. |
217 | EXPECT_EQ(Type::getInt32Ty(Context), CVH->getType()); |
218 | EXPECT_EQ(Type::getInt32Ty(Context), (*CVH).getType()); |
219 | } |
220 | |
221 | TEST_F(ValueHandle, CallbackVH_Comparisons) { |
222 | ConcreteCallbackVH BitcastCVH(BitcastV.get()); |
223 | ConcreteCallbackVH ConstantCVH(ConstantV); |
224 | |
225 | EXPECT_TRUE(BitcastCVH == BitcastCVH); |
226 | EXPECT_TRUE(BitcastV.get() == BitcastCVH); |
227 | EXPECT_TRUE(BitcastCVH == BitcastV.get()); |
228 | EXPECT_FALSE(BitcastCVH == ConstantCVH); |
229 | |
230 | EXPECT_TRUE(BitcastCVH != ConstantCVH); |
231 | EXPECT_TRUE(BitcastV.get() != ConstantCVH); |
232 | EXPECT_TRUE(BitcastCVH != ConstantV); |
233 | EXPECT_FALSE(BitcastCVH != BitcastCVH); |
234 | |
235 | // Cast to Value* so comparisons work. |
236 | Value *BV = BitcastV.get(); |
237 | Value *CV = ConstantV; |
238 | EXPECT_EQ(BV < CV, BitcastCVH < ConstantCVH); |
239 | EXPECT_EQ(BV <= CV, BitcastCVH <= ConstantCVH); |
240 | EXPECT_EQ(BV > CV, BitcastCVH > ConstantCVH); |
241 | EXPECT_EQ(BV >= CV, BitcastCVH >= ConstantCVH); |
242 | |
243 | EXPECT_EQ(BV < CV, BitcastV.get() < ConstantCVH); |
244 | EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantCVH); |
245 | EXPECT_EQ(BV > CV, BitcastV.get() > ConstantCVH); |
246 | EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantCVH); |
247 | |
248 | EXPECT_EQ(BV < CV, BitcastCVH < ConstantV); |
249 | EXPECT_EQ(BV <= CV, BitcastCVH <= ConstantV); |
250 | EXPECT_EQ(BV > CV, BitcastCVH > ConstantV); |
251 | EXPECT_EQ(BV >= CV, BitcastCVH >= ConstantV); |
252 | } |
253 | |
254 | TEST_F(ValueHandle, CallbackVH_CallbackOnDeletion) { |
255 | class RecordingVH final : public CallbackVH { |
256 | public: |
257 | int DeletedCalls; |
258 | int AURWCalls; |
259 | |
260 | RecordingVH() : DeletedCalls(0), AURWCalls(0) {} |
261 | RecordingVH(Value *V) : CallbackVH(V), DeletedCalls(0), AURWCalls(0) {} |
262 | |
263 | private: |
264 | void deleted() override { |
265 | DeletedCalls++; |
266 | CallbackVH::deleted(); |
267 | } |
268 | void allUsesReplacedWith(Value *) override { AURWCalls++; } |
269 | }; |
270 | |
271 | RecordingVH RVH; |
272 | RVH = BitcastV.get(); |
273 | EXPECT_EQ(0, RVH.DeletedCalls); |
274 | EXPECT_EQ(0, RVH.AURWCalls); |
275 | BitcastV.reset(); |
276 | EXPECT_EQ(1, RVH.DeletedCalls); |
277 | EXPECT_EQ(0, RVH.AURWCalls); |
278 | } |
279 | |
280 | TEST_F(ValueHandle, CallbackVH_CallbackOnRAUW) { |
281 | class RecordingVH final : public CallbackVH { |
282 | public: |
283 | int DeletedCalls; |
284 | Value *AURWArgument; |
285 | |
286 | RecordingVH() : DeletedCalls(0), AURWArgument(nullptr) {} |
287 | RecordingVH(Value *V) |
288 | : CallbackVH(V), DeletedCalls(0), AURWArgument(nullptr) {} |
289 | |
290 | private: |
291 | void deleted() override { |
292 | DeletedCalls++; |
293 | CallbackVH::deleted(); |
294 | } |
295 | void allUsesReplacedWith(Value *new_value) override { |
296 | EXPECT_EQ(nullptr, AURWArgument); |
297 | AURWArgument = new_value; |
298 | } |
299 | }; |
300 | |
301 | RecordingVH RVH; |
302 | RVH = BitcastV.get(); |
303 | EXPECT_EQ(0, RVH.DeletedCalls); |
304 | EXPECT_EQ(nullptr, RVH.AURWArgument); |
305 | BitcastV->replaceAllUsesWith(V: ConstantV); |
306 | EXPECT_EQ(0, RVH.DeletedCalls); |
307 | EXPECT_EQ(ConstantV, RVH.AURWArgument); |
308 | } |
309 | |
310 | TEST_F(ValueHandle, CallbackVH_DeletionCanRAUW) { |
311 | class RecoveringVH final : public CallbackVH { |
312 | public: |
313 | int DeletedCalls; |
314 | Value *AURWArgument; |
315 | LLVMContext *Context; |
316 | |
317 | RecoveringVH(LLVMContext &TheContext) |
318 | : DeletedCalls(0), AURWArgument(nullptr), Context(&TheContext) {} |
319 | |
320 | RecoveringVH(LLVMContext &TheContext, Value *V) |
321 | : CallbackVH(V), DeletedCalls(0), AURWArgument(nullptr), |
322 | Context(&TheContext) {} |
323 | |
324 | private: |
325 | void deleted() override { |
326 | getValPtr()->replaceAllUsesWith( |
327 | V: Constant::getNullValue(Ty: Type::getInt32Ty(C&: *Context))); |
328 | setValPtr(nullptr); |
329 | } |
330 | void allUsesReplacedWith(Value *new_value) override { |
331 | ASSERT_TRUE(nullptr != getValPtr()); |
332 | EXPECT_EQ(1U, getValPtr()->getNumUses()); |
333 | EXPECT_EQ(nullptr, AURWArgument); |
334 | AURWArgument = new_value; |
335 | } |
336 | }; |
337 | |
338 | // Normally, if a value has uses, deleting it will crash. However, we can use |
339 | // a CallbackVH to remove the uses before the check for no uses. |
340 | RecoveringVH RVH(Context); |
341 | RVH = RecoveringVH(Context, BitcastV.get()); |
342 | std::unique_ptr<BinaryOperator> BitcastUser(BinaryOperator::CreateAdd( |
343 | V1: RVH, V2: Constant::getNullValue(Ty: Type::getInt32Ty(C&: Context)))); |
344 | EXPECT_EQ(BitcastV.get(), BitcastUser->getOperand(0)); |
345 | BitcastV.reset(); // Would crash without the ValueHandler. |
346 | EXPECT_EQ(Constant::getNullValue(Type::getInt32Ty(Context)), |
347 | RVH.AURWArgument); |
348 | EXPECT_EQ(Constant::getNullValue(Type::getInt32Ty(Context)), |
349 | BitcastUser->getOperand(0)); |
350 | } |
351 | |
352 | TEST_F(ValueHandle, DestroyingOtherVHOnSameValueDoesntBreakIteration) { |
353 | // When a CallbackVH modifies other ValueHandles in its callbacks, |
354 | // that shouldn't interfere with non-modified ValueHandles receiving |
355 | // their appropriate callbacks. |
356 | // |
357 | // We create the active CallbackVH in the middle of a palindromic |
358 | // arrangement of other VHs so that the bad behavior would be |
359 | // triggered in whichever order callbacks run. |
360 | |
361 | class DestroyingVH final : public CallbackVH { |
362 | public: |
363 | std::unique_ptr<WeakTrackingVH> ToClear[2]; |
364 | DestroyingVH(Value *V) { |
365 | ToClear[0].reset(p: new WeakTrackingVH(V)); |
366 | setValPtr(V); |
367 | ToClear[1].reset(p: new WeakTrackingVH(V)); |
368 | } |
369 | void deleted() override { |
370 | ToClear[0].reset(); |
371 | ToClear[1].reset(); |
372 | CallbackVH::deleted(); |
373 | } |
374 | void allUsesReplacedWith(Value *) override { |
375 | ToClear[0].reset(); |
376 | ToClear[1].reset(); |
377 | } |
378 | }; |
379 | |
380 | { |
381 | WeakTrackingVH ShouldBeVisited1(BitcastV.get()); |
382 | DestroyingVH C(BitcastV.get()); |
383 | WeakTrackingVH ShouldBeVisited2(BitcastV.get()); |
384 | |
385 | BitcastV->replaceAllUsesWith(V: ConstantV); |
386 | EXPECT_EQ(ConstantV, static_cast<Value*>(ShouldBeVisited1)); |
387 | EXPECT_EQ(ConstantV, static_cast<Value*>(ShouldBeVisited2)); |
388 | } |
389 | |
390 | { |
391 | WeakTrackingVH ShouldBeVisited1(BitcastV.get()); |
392 | DestroyingVH C(BitcastV.get()); |
393 | WeakTrackingVH ShouldBeVisited2(BitcastV.get()); |
394 | |
395 | BitcastV.reset(); |
396 | EXPECT_EQ(nullptr, static_cast<Value*>(ShouldBeVisited1)); |
397 | EXPECT_EQ(nullptr, static_cast<Value*>(ShouldBeVisited2)); |
398 | } |
399 | } |
400 | |
401 | TEST_F(ValueHandle, AssertingVHCheckedLast) { |
402 | // If a CallbackVH exists to clear out a group of AssertingVHs on |
403 | // Value deletion, the CallbackVH should get a chance to do so |
404 | // before the AssertingVHs assert. |
405 | |
406 | class ClearingVH final : public CallbackVH { |
407 | public: |
408 | AssertingVH<Value> *ToClear[2]; |
409 | ClearingVH(Value *V, |
410 | AssertingVH<Value> &A0, AssertingVH<Value> &A1) |
411 | : CallbackVH(V) { |
412 | ToClear[0] = &A0; |
413 | ToClear[1] = &A1; |
414 | } |
415 | |
416 | void deleted() override { |
417 | *ToClear[0] = nullptr; |
418 | *ToClear[1] = nullptr; |
419 | CallbackVH::deleted(); |
420 | } |
421 | }; |
422 | |
423 | AssertingVH<Value> A1, A2; |
424 | A1 = BitcastV.get(); |
425 | ClearingVH C(BitcastV.get(), A1, A2); |
426 | A2 = BitcastV.get(); |
427 | // C.deleted() should run first, clearing the two AssertingVHs, |
428 | // which should prevent them from asserting. |
429 | BitcastV.reset(); |
430 | } |
431 | |
432 | TEST_F(ValueHandle, PoisoningVH_BasicOperation) { |
433 | PoisoningVH<CastInst> VH(BitcastV.get()); |
434 | CastInst *implicit_to_exact_type = VH; |
435 | (void)implicit_to_exact_type; // Avoid warning. |
436 | |
437 | PoisoningVH<Value> GenericVH(BitcastV.get()); |
438 | EXPECT_EQ(BitcastV.get(), GenericVH); |
439 | GenericVH = ConstantV; |
440 | EXPECT_EQ(ConstantV, GenericVH); |
441 | |
442 | // Make sure I can call a method on the underlying CastInst. It |
443 | // doesn't matter which method. |
444 | EXPECT_FALSE(VH->mayWriteToMemory()); |
445 | EXPECT_FALSE((*VH).mayWriteToMemory()); |
446 | } |
447 | |
448 | TEST_F(ValueHandle, PoisoningVH_Const) { |
449 | const CastInst *ConstBitcast = BitcastV.get(); |
450 | PoisoningVH<const CastInst> VH(ConstBitcast); |
451 | const CastInst *implicit_to_exact_type = VH; |
452 | (void)implicit_to_exact_type; // Avoid warning. |
453 | } |
454 | |
455 | TEST_F(ValueHandle, PoisoningVH_Comparisons) { |
456 | PoisoningVH<Value> BitcastVH(BitcastV.get()); |
457 | PoisoningVH<Value> ConstantVH(ConstantV); |
458 | |
459 | EXPECT_TRUE(BitcastVH == BitcastVH); |
460 | EXPECT_TRUE(BitcastV.get() == BitcastVH); |
461 | EXPECT_TRUE(BitcastVH == BitcastV.get()); |
462 | EXPECT_FALSE(BitcastVH == ConstantVH); |
463 | |
464 | EXPECT_TRUE(BitcastVH != ConstantVH); |
465 | EXPECT_TRUE(BitcastV.get() != ConstantVH); |
466 | EXPECT_TRUE(BitcastVH != ConstantV); |
467 | EXPECT_FALSE(BitcastVH != BitcastVH); |
468 | |
469 | // Cast to Value* so comparisons work. |
470 | Value *BV = BitcastV.get(); |
471 | Value *CV = ConstantV; |
472 | EXPECT_EQ(BV < CV, BitcastVH < ConstantVH); |
473 | EXPECT_EQ(BV <= CV, BitcastVH <= ConstantVH); |
474 | EXPECT_EQ(BV > CV, BitcastVH > ConstantVH); |
475 | EXPECT_EQ(BV >= CV, BitcastVH >= ConstantVH); |
476 | |
477 | EXPECT_EQ(BV < CV, BitcastV.get() < ConstantVH); |
478 | EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantVH); |
479 | EXPECT_EQ(BV > CV, BitcastV.get() > ConstantVH); |
480 | EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantVH); |
481 | |
482 | EXPECT_EQ(BV < CV, BitcastVH < ConstantV); |
483 | EXPECT_EQ(BV <= CV, BitcastVH <= ConstantV); |
484 | EXPECT_EQ(BV > CV, BitcastVH > ConstantV); |
485 | EXPECT_EQ(BV >= CV, BitcastVH >= ConstantV); |
486 | } |
487 | |
488 | TEST_F(ValueHandle, PoisoningVH_DoesNotFollowRAUW) { |
489 | PoisoningVH<Value> VH(BitcastV.get()); |
490 | BitcastV->replaceAllUsesWith(V: ConstantV); |
491 | EXPECT_TRUE(DenseMapInfo<PoisoningVH<Value>>::isEqual(VH, BitcastV.get())); |
492 | } |
493 | |
494 | TEST_F(ValueHandle, AssertingVH_DenseMap) { |
495 | DenseMap<AssertingVH<Value>, int> Map; |
496 | Map.insert(KV: {BitcastV.get(), 1}); |
497 | Map.insert(KV: {ConstantV, 2}); |
498 | // These will create a temporary AssertingVH during lookup. |
499 | EXPECT_TRUE(Map.contains(BitcastV.get())); |
500 | EXPECT_TRUE(Map.contains(ConstantV)); |
501 | // These will not create a temporary AssertingVH. |
502 | EXPECT_TRUE(Map.find_as(BitcastV.get()) != Map.end()); |
503 | EXPECT_TRUE(Map.find_as(ConstantV) != Map.end()); |
504 | } |
505 | |
506 | TEST_F(ValueHandle, PoisoningVH_DenseMap) { |
507 | DenseMap<PoisoningVH<Value>, int> Map; |
508 | Map.insert(KV: {BitcastV.get(), 1}); |
509 | Map.insert(KV: {ConstantV, 2}); |
510 | // These will create a temporary PoisoningVH during lookup. |
511 | EXPECT_TRUE(Map.contains(BitcastV.get())); |
512 | EXPECT_TRUE(Map.contains(ConstantV)); |
513 | // These will not create a temporary PoisoningVH. |
514 | EXPECT_TRUE(Map.find_as(BitcastV.get()) != Map.end()); |
515 | EXPECT_TRUE(Map.find_as(ConstantV) != Map.end()); |
516 | } |
517 | |
518 | #ifdef NDEBUG |
519 | |
520 | TEST_F(ValueHandle, PoisoningVH_ReducesToPointer) { |
521 | EXPECT_EQ(sizeof(CastInst *), sizeof(PoisoningVH<CastInst>)); |
522 | } |
523 | |
524 | #else // !NDEBUG |
525 | |
526 | TEST_F(ValueHandle, TrackingVH_Tracks) { |
527 | TrackingVH<Value> VH(BitcastV.get()); |
528 | BitcastV->replaceAllUsesWith(V: ConstantV); |
529 | EXPECT_EQ(VH, ConstantV); |
530 | } |
531 | |
532 | #ifdef GTEST_HAS_DEATH_TEST |
533 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS |
534 | |
535 | TEST_F(ValueHandle, PoisoningVH_Asserts) { |
536 | PoisoningVH<Value> VH(BitcastV.get()); |
537 | |
538 | // The poisoned handle shouldn't assert when the value is deleted. |
539 | BitcastV.reset(p: new BitCastInst(ConstantV, Type::getInt32Ty(C&: Context))); |
540 | // But should when we access the handle. |
541 | EXPECT_DEATH((void)*VH, "Accessed a poisoned value handle!" ); |
542 | |
543 | // Now check that poison catches RAUW. |
544 | VH = BitcastV.get(); |
545 | // The replace doesn't trigger anything immediately. |
546 | BitcastV->replaceAllUsesWith(V: ConstantV); |
547 | // But a use does. |
548 | EXPECT_DEATH((void)*VH, "Accessed a poisoned value handle!" ); |
549 | |
550 | // Don't clear anything out here as destroying the handles should be fine. |
551 | } |
552 | |
553 | #endif // LLVM_ENABLE_ABI_BREAKING_CHECKS |
554 | |
555 | TEST_F(ValueHandle, TrackingVH_Asserts) { |
556 | { |
557 | TrackingVH<Value> VH(BitcastV.get()); |
558 | |
559 | // The tracking handle shouldn't assert when the value is deleted. |
560 | BitcastV.reset(p: new BitCastInst(ConstantV, Type::getInt32Ty(C&: Context))); |
561 | // But should when we access the handle. |
562 | EXPECT_DEATH((void)*VH, |
563 | "TrackingVH must be non-null and valid on dereference!" ); |
564 | } |
565 | |
566 | { |
567 | TrackingVH<Instruction> VH(BitcastV.get()); |
568 | |
569 | BitcastV->replaceAllUsesWith(V: ConstantV); |
570 | EXPECT_DEATH((void)*VH, |
571 | "Tracked Value was replaced by one with an invalid type!" ); |
572 | } |
573 | } |
574 | |
575 | #endif // GTEST_HAS_DEATH_TEST |
576 | |
577 | #endif // NDEBUG |
578 | } |
579 | |