1818#include " clang/AST/DeclBase.h"
1919#include " clang/Basic/LLVM.h"
2020#include " llvm/ADT/ArrayRef.h"
21+ #include " llvm/ADT/bit.h"
2122#include " llvm/ADT/DenseMap.h"
2223#include " llvm/ADT/IntrusiveRefCntPtr.h"
2324#include " llvm/ADT/PointerUnion.h"
@@ -321,50 +322,87 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
321322// / external AST source itself.
322323template <typename T, typename OffsT, T* (ExternalASTSource::*Get)(OffsT Offset)>
323324struct LazyOffsetPtr {
324- // / Either a pointer to an AST node or the offset within the
325- // / external AST source where the AST node can be found.
326- // /
327- // / If the low bit is clear, a pointer to the AST node. If the low
328- // / bit is set, the upper 63 bits are the offset.
329- mutable uint64_t Ptr = 0 ;
325+ // / Storage for a pointer or an offset, for the case where pointers are 64
326+ // / bits wide. The least-significant bit is used as the discriminator. If the
327+ // / bit is clear, a pointer to the AST node. If the bit is set, the upper 63
328+ // / bits are the offset.
329+ union StorageType64 {
330+ StorageType64 (uint64_t Offset) : ShiftedOffset ((Offset << 1 ) | 1 ) {
331+ assert (isOffset ());
332+ }
333+ StorageType64 (T *Ptr) : Pointer (Ptr) { assert (!isOffset ()); }
334+
335+ bool isOffset () { return llvm::bit_cast<uint64_t >(*this ) & 1 ; }
336+ uint64_t offset () { return ShiftedOffset >> 1 ; }
337+ T *&pointer () { return Pointer; }
338+
339+ uint64_t ShiftedOffset;
340+ T *Pointer;
341+ };
342+
343+ // / Storage for a pointer or an offset, for the case where pointers are not 64
344+ // / bits wide.
345+ union StorageType32 {
346+ StorageType32 (uint64_t Off) : Offset{true , Off} {}
347+ StorageType32 (T *Ptr) : Pointer{false , Ptr} {}
348+
349+ bool isOffset () { return Offset.IsOffset ; }
350+ uint64_t offset () { return Offset.Offset ; }
351+ T *&pointer () { return Pointer.Pointer ; }
352+
353+ struct OffsetType {
354+ uint64_t IsOffset : 1 ;
355+ uint64_t Offset : 63 ;
356+ } Offset;
357+ struct PointerType {
358+ uint64_t IsOffset : 1 ;
359+ T *Pointer;
360+ } Pointer;
361+ };
362+
363+ mutable std::conditional_t <sizeof (uint64_t ) == sizeof (T *), StorageType64,
364+ StorageType32>
365+ Storage;
330366
331367public:
332- LazyOffsetPtr () = default ;
333- explicit LazyOffsetPtr (T *Ptr) : Ptr( reinterpret_cast < uint64_t >( Ptr) ) {}
368+ LazyOffsetPtr () : LazyOffsetPtr( nullptr ) {}
369+ explicit LazyOffsetPtr (T *Ptr) : Storage( Ptr) {}
334370
335- explicit LazyOffsetPtr (uint64_t Offset) : Ptr(( Offset << 1 ) | 0x01 ) {
336- assert (( Offset << 1 >> 1 ) == Offset && " Offsets must require < 63 bits" );
371+ explicit LazyOffsetPtr (uint64_t Offset) : Storage( Offset) {
372+ assert (Offset == Storage. offset () && " Offsets must require < 63 bits" );
337373 if (Offset == 0 )
338- Ptr = 0 ;
374+ Storage = nullptr ;
339375 }
340376
341377 LazyOffsetPtr &operator =(T *Ptr) {
342- this -> Ptr = reinterpret_cast < uint64_t >( Ptr) ;
378+ Storage = Ptr;
343379 return *this ;
344380 }
345381
346382 LazyOffsetPtr &operator =(uint64_t Offset) {
347- assert ((Offset << 1 >> 1 ) == Offset && " Offsets must require < 63 bits" );
348383 if (Offset == 0 )
349- Ptr = 0 ;
350- else
351- Ptr = (Offset << 1 ) | 0x01 ;
352-
384+ Storage = nullptr ;
385+ else {
386+ Storage = Offset;
387+ assert (Offset == Storage.offset () && " Offsets must require < 63 bits" );
388+ }
353389 return *this ;
354390 }
355391
356392 // / Whether this pointer is non-NULL.
357393 // /
358394 // / This operation does not require the AST node to be deserialized.
359- explicit operator bool () const { return Ptr != 0 ; }
395+ explicit operator bool () const {
396+ return Storage.isOffset () || Storage.pointer ();
397+ }
360398
361399 // / Whether this pointer is non-NULL.
362400 // /
363401 // / This operation does not require the AST node to be deserialized.
364- bool isValid () const { return Ptr != 0 ; }
402+ bool isValid () const { return operator bool () ; }
365403
366404 // / Whether this pointer is currently stored as an offset.
367- bool isOffset () const { return Ptr & 0x01 ; }
405+ bool isOffset () const { return Storage. isOffset () ; }
368406
369407 // / Retrieve the pointer to the AST node that this lazy pointer points to.
370408 // /
@@ -375,17 +413,18 @@ struct LazyOffsetPtr {
375413 if (isOffset ()) {
376414 assert (Source &&
377415 " Cannot deserialize a lazy pointer without an AST source" );
378- Ptr = reinterpret_cast < uint64_t >(( Source->*Get)(OffsT (Ptr >> 1 )));
416+ Storage = ( Source->*Get)(static_cast < OffsT>(Storage. offset ( )));
379417 }
380- return reinterpret_cast <T*>(Ptr );
418+ return Storage. pointer ( );
381419 }
382420
383421 // / Retrieve the address of the AST node pointer. Deserializes the pointee if
384- // / necessary.
422+ // / necessary. This function should not exist, and we would like to remove it.
423+ // / Do not add new calls to it.
385424 T **getAddressOfPointer (ExternalASTSource *Source) const {
386425 // Ensure the integer is in pointer form.
387426 (void )get (Source);
388- return reinterpret_cast <T**>(&Ptr );
427+ return &Storage. pointer ( );
389428 }
390429};
391430
0 commit comments