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
@@ -326,45 +328,65 @@ struct LazyOffsetPtr {
326328 // /
327329 // / If the low bit is clear, a pointer to the AST node. If the low
328330 // / bit is set, the upper 63 bits are the offset.
329- mutable uint64_t Ptr = 0 ;
331+ static constexpr size_t DataSize = std::max(sizeof (uint64_t ), sizeof (T *));
332+ alignas (uint64_t ) alignas(T *) mutable unsigned char Data[DataSize] = {};
333+
334+ unsigned char GetLSB () const {
335+ return Data[llvm::sys::IsBigEndianHost ? DataSize - 1 : 0 ];
336+ }
337+
338+ template <typename U> U &As (bool New) const {
339+ unsigned char *Obj =
340+ Data + (llvm::sys::IsBigEndianHost ? DataSize - sizeof (U) : 0 );
341+ if (New)
342+ return *new (Obj) U;
343+ return *std::launder (reinterpret_cast <U *>(Obj));
344+ }
345+
346+ T *&GetPtr () const { return As<T *>(false ); }
347+ uint64_t &GetU64 () const { return As<uint64_t >(false ); }
348+ void SetPtr (T *Ptr) const { As<T *>(true ) = Ptr; }
349+ void SetU64 (uint64_t U64) const { As<uint64_t >(true ) = U64; }
330350
331351public:
332352 LazyOffsetPtr () = default;
333- explicit LazyOffsetPtr (T *Ptr) : Ptr( reinterpret_cast < uint64_t > (Ptr)) { }
353+ explicit LazyOffsetPtr (T *Ptr) : Data() { SetPtr (Ptr); }
334354
335- explicit LazyOffsetPtr (uint64_t Offset) : Ptr((Offset << 1 ) | 0x01 ) {
355+ explicit LazyOffsetPtr (uint64_t Offset) : Data( ) {
336356 assert ((Offset << 1 >> 1 ) == Offset && " Offsets must require < 63 bits" );
337357 if (Offset == 0 )
338- Ptr = 0 ;
358+ SetPtr (nullptr );
359+ else
360+ SetU64 ((Offset << 1 ) | 0x01 );
339361 }
340362
341363 LazyOffsetPtr &operator =(T *Ptr) {
342- this -> Ptr = reinterpret_cast < uint64_t > (Ptr);
364+ SetPtr (Ptr);
343365 return *this ;
344366 }
345367
346368 LazyOffsetPtr &operator =(uint64_t Offset) {
347369 assert ((Offset << 1 >> 1 ) == Offset && " Offsets must require < 63 bits" );
348370 if (Offset == 0 )
349- Ptr = 0 ;
371+ SetPtr ( nullptr ) ;
350372 else
351- Ptr = ( Offset << 1 ) | 0x01 ;
373+ SetU64 (( Offset << 1 ) | 0x01 ) ;
352374
353375 return *this ;
354376 }
355377
356378 // / Whether this pointer is non-NULL.
357379 // /
358380 // / This operation does not require the AST node to be deserialized.
359- explicit operator bool () const { return Ptr != 0 ; }
381+ explicit operator bool () const { return isOffset () || GetPtr () != nullptr ; }
360382
361383 // / Whether this pointer is non-NULL.
362384 // /
363385 // / This operation does not require the AST node to be deserialized.
364- bool isValid () const { return Ptr != 0 ; }
386+ bool isValid () const { return isOffset () || GetPtr () != nullptr ; }
365387
366388 // / Whether this pointer is currently stored as an offset.
367- bool isOffset () const { return Ptr & 0x01 ; }
389+ bool isOffset () const { return GetLSB () & 0x01 ; }
368390
369391 // / Retrieve the pointer to the AST node that this lazy pointer points to.
370392 // /
@@ -375,17 +397,17 @@ struct LazyOffsetPtr {
375397 if (isOffset ()) {
376398 assert (Source &&
377399 " Cannot deserialize a lazy pointer without an AST source" );
378- Ptr = reinterpret_cast < uint64_t > ((Source->*Get)(OffsT (Ptr >> 1 )));
400+ SetPtr ((Source->*Get)(OffsT (GetU64 () >> 1 )));
379401 }
380- return reinterpret_cast <T*>(Ptr );
402+ return GetPtr ( );
381403 }
382404
383405 // / Retrieve the address of the AST node pointer. Deserializes the pointee if
384406 // / necessary.
385407 T **getAddressOfPointer (ExternalASTSource *Source) const {
386408 // Ensure the integer is in pointer form.
387409 (void )get (Source);
388- return reinterpret_cast <T**>(&Ptr );
410+ return & GetPtr ( );
389411 }
390412};
391413
0 commit comments