25
25
#include " llvm/ADT/SmallVector.h"
26
26
#include " llvm/ADT/iterator.h"
27
27
#include " llvm/Support/PointerLikeTypeTraits.h"
28
+ #include < algorithm>
28
29
#include < cassert>
29
30
#include < cstddef>
30
31
#include < cstdint>
31
32
#include < iterator>
33
+ #include < new>
32
34
#include < optional>
33
35
#include < utility>
34
36
@@ -331,45 +333,65 @@ struct LazyOffsetPtr {
331
333
// /
332
334
// / If the low bit is clear, a pointer to the AST node. If the low
333
335
// / bit is set, the upper 63 bits are the offset.
334
- mutable uint64_t Ptr = 0 ;
336
+ static constexpr size_t DataSize = std::max(sizeof (uint64_t ), sizeof (T *));
337
+ alignas (uint64_t ) alignas(T *) mutable unsigned char Data[DataSize] = {};
338
+
339
+ unsigned char GetLSB () const {
340
+ return Data[llvm::sys::IsBigEndianHost ? DataSize - 1 : 0 ];
341
+ }
342
+
343
+ template <typename U> U &As (bool New) const {
344
+ unsigned char *Obj =
345
+ Data + (llvm::sys::IsBigEndianHost ? DataSize - sizeof (U) : 0 );
346
+ if (New)
347
+ return *new (Obj) U;
348
+ return *std::launder (reinterpret_cast <U *>(Obj));
349
+ }
350
+
351
+ T *&GetPtr () const { return As<T *>(false ); }
352
+ uint64_t &GetU64 () const { return As<uint64_t >(false ); }
353
+ void SetPtr (T *Ptr) const { As<T *>(true ) = Ptr; }
354
+ void SetU64 (uint64_t U64) const { As<uint64_t >(true ) = U64; }
335
355
336
356
public:
337
357
LazyOffsetPtr () = default;
338
- explicit LazyOffsetPtr (T *Ptr) : Ptr( reinterpret_cast < uint64_t > (Ptr)) { }
358
+ explicit LazyOffsetPtr (T *Ptr) : Data() { SetPtr (Ptr); }
339
359
340
- explicit LazyOffsetPtr (uint64_t Offset) : Ptr((Offset << 1 ) | 0x01 ) {
360
+ explicit LazyOffsetPtr (uint64_t Offset) : Data( ) {
341
361
assert ((Offset << 1 >> 1 ) == Offset && " Offsets must require < 63 bits" );
342
362
if (Offset == 0 )
343
- Ptr = 0 ;
363
+ SetPtr (nullptr );
364
+ else
365
+ SetU64 ((Offset << 1 ) | 0x01 );
344
366
}
345
367
346
368
LazyOffsetPtr &operator =(T *Ptr) {
347
- this -> Ptr = reinterpret_cast < uint64_t > (Ptr);
369
+ SetPtr (Ptr);
348
370
return *this ;
349
371
}
350
372
351
373
LazyOffsetPtr &operator =(uint64_t Offset) {
352
374
assert ((Offset << 1 >> 1 ) == Offset && " Offsets must require < 63 bits" );
353
375
if (Offset == 0 )
354
- Ptr = 0 ;
376
+ SetPtr ( nullptr ) ;
355
377
else
356
- Ptr = ( Offset << 1 ) | 0x01 ;
378
+ SetU64 (( Offset << 1 ) | 0x01 ) ;
357
379
358
380
return *this ;
359
381
}
360
382
361
383
// / Whether this pointer is non-NULL.
362
384
// /
363
385
// / This operation does not require the AST node to be deserialized.
364
- explicit operator bool () const { return Ptr != 0 ; }
386
+ explicit operator bool () const { return isOffset () || GetPtr () != nullptr ; }
365
387
366
388
// / Whether this pointer is non-NULL.
367
389
// /
368
390
// / This operation does not require the AST node to be deserialized.
369
- bool isValid () const { return Ptr != 0 ; }
391
+ bool isValid () const { return isOffset () || GetPtr () != nullptr ; }
370
392
371
393
// / Whether this pointer is currently stored as an offset.
372
- bool isOffset () const { return Ptr & 0x01 ; }
394
+ bool isOffset () const { return GetLSB () & 0x01 ; }
373
395
374
396
// / Retrieve the pointer to the AST node that this lazy pointer points to.
375
397
// /
@@ -380,17 +402,17 @@ struct LazyOffsetPtr {
380
402
if (isOffset ()) {
381
403
assert (Source &&
382
404
" Cannot deserialize a lazy pointer without an AST source" );
383
- Ptr = reinterpret_cast < uint64_t > ((Source->*Get)(OffsT (Ptr >> 1 )));
405
+ SetPtr ((Source->*Get)(OffsT (GetU64 () >> 1 )));
384
406
}
385
- return reinterpret_cast <T*>(Ptr );
407
+ return GetPtr ( );
386
408
}
387
409
388
410
// / Retrieve the address of the AST node pointer. Deserializes the pointee if
389
411
// / necessary.
390
412
T **getAddressOfPointer (ExternalASTSource *Source) const {
391
413
// Ensure the integer is in pointer form.
392
414
(void )get (Source);
393
- return reinterpret_cast <T**>(&Ptr );
415
+ return & GetPtr ( );
394
416
}
395
417
};
396
418
0 commit comments