2525#include " llvm/ADT/SmallVector.h"
2626#include " llvm/ADT/iterator.h"
2727#include " llvm/Support/PointerLikeTypeTraits.h"
28+ #include < algorithm>
2829#include < cassert>
2930#include < cstddef>
3031#include < cstdint>
3132#include < iterator>
33+ #include < new>
3234#include < optional>
3335#include < utility>
3436
@@ -331,45 +333,65 @@ struct LazyOffsetPtr {
331333 // /
332334 // / If the low bit is clear, a pointer to the AST node. If the low
333335 // / 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; }
335355
336356public:
337357 LazyOffsetPtr () = default;
338- explicit LazyOffsetPtr (T *Ptr) : Ptr( reinterpret_cast < uint64_t > (Ptr)) { }
358+ explicit LazyOffsetPtr (T *Ptr) : Data() { SetPtr (Ptr); }
339359
340- explicit LazyOffsetPtr (uint64_t Offset) : Ptr((Offset << 1 ) | 0x01 ) {
360+ explicit LazyOffsetPtr (uint64_t Offset) : Data( ) {
341361 assert ((Offset << 1 >> 1 ) == Offset && " Offsets must require < 63 bits" );
342362 if (Offset == 0 )
343- Ptr = 0 ;
363+ SetPtr (nullptr );
364+ else
365+ SetU64 ((Offset << 1 ) | 0x01 );
344366 }
345367
346368 LazyOffsetPtr &operator =(T *Ptr) {
347- this -> Ptr = reinterpret_cast < uint64_t > (Ptr);
369+ SetPtr (Ptr);
348370 return *this ;
349371 }
350372
351373 LazyOffsetPtr &operator =(uint64_t Offset) {
352374 assert ((Offset << 1 >> 1 ) == Offset && " Offsets must require < 63 bits" );
353375 if (Offset == 0 )
354- Ptr = 0 ;
376+ SetPtr ( nullptr ) ;
355377 else
356- Ptr = ( Offset << 1 ) | 0x01 ;
378+ SetU64 (( Offset << 1 ) | 0x01 ) ;
357379
358380 return *this ;
359381 }
360382
361383 // / Whether this pointer is non-NULL.
362384 // /
363385 // / 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 ; }
365387
366388 // / Whether this pointer is non-NULL.
367389 // /
368390 // / 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 ; }
370392
371393 // / Whether this pointer is currently stored as an offset.
372- bool isOffset () const { return Ptr & 0x01 ; }
394+ bool isOffset () const { return GetLSB () & 0x01 ; }
373395
374396 // / Retrieve the pointer to the AST node that this lazy pointer points to.
375397 // /
@@ -380,17 +402,17 @@ struct LazyOffsetPtr {
380402 if (isOffset ()) {
381403 assert (Source &&
382404 " 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 )));
384406 }
385- return reinterpret_cast <T*>(Ptr );
407+ return GetPtr ( );
386408 }
387409
388410 // / Retrieve the address of the AST node pointer. Deserializes the pointee if
389411 // / necessary.
390412 T **getAddressOfPointer (ExternalASTSource *Source) const {
391413 // Ensure the integer is in pointer form.
392414 (void )get (Source);
393- return reinterpret_cast <T**>(&Ptr );
415+ return & GetPtr ( );
394416 }
395417};
396418
0 commit comments