[llvm-branch-commits] [clang] e541aa5 - [clang] Make LazyOffsetPtr more portable (#112927)
Tobias Hieta via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Oct 29 02:06:08 PDT 2024
Author: Jessica Clarke
Date: 2024-10-29T10:06:04+01:00
New Revision: e541aa5ff994a370bacb9b039f70efb0672c4a1b
URL: https://github.com/llvm/llvm-project/commit/e541aa5ff994a370bacb9b039f70efb0672c4a1b
DIFF: https://github.com/llvm/llvm-project/commit/e541aa5ff994a370bacb9b039f70efb0672c4a1b.diff
LOG: [clang] Make LazyOffsetPtr more portable (#112927)
LazyOffsetPtr currently relies on uint64_t being able to store a pointer
and, unless sizeof(uint64_t) == sizeof(void *), little endianness, since
getAddressOfPointer reinterprets the memory as a pointer. This also
doesn't properly respect the C++ object model.
As removing getAddressOfPointer would have wide-reaching implications,
improve the implementation to account for these problems by using
placement new and a suitably sized-and-aligned buffer, "right"-aligning
the objects on big-endian platforms so the LSBs are in the same place
for use as the discriminator.
Fixes: bc73ef0031b50f7443615fef614fb4ecaaa4bd11
Fixes: https://github.com/llvm/llvm-project/issues/111993
(cherry picked from commit 76196998e25b98d81abc437708622261810782ca)
Added:
Modified:
clang/include/clang/AST/ExternalASTSource.h
Removed:
################################################################################
diff --git a/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h
index 385c32edbae0fd..582ed7c65f58ca 100644
--- a/clang/include/clang/AST/ExternalASTSource.h
+++ b/clang/include/clang/AST/ExternalASTSource.h
@@ -25,10 +25,12 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/iterator.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
+#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <iterator>
+#include <new>
#include <optional>
#include <utility>
@@ -326,29 +328,49 @@ struct LazyOffsetPtr {
///
/// If the low bit is clear, a pointer to the AST node. If the low
/// bit is set, the upper 63 bits are the offset.
- mutable uint64_t Ptr = 0;
+ static constexpr size_t DataSize = std::max(sizeof(uint64_t), sizeof(T *));
+ alignas(uint64_t) alignas(T *) mutable unsigned char Data[DataSize] = {};
+
+ unsigned char GetLSB() const {
+ return Data[llvm::sys::IsBigEndianHost ? DataSize - 1 : 0];
+ }
+
+ template <typename U> U &As(bool New) const {
+ unsigned char *Obj =
+ Data + (llvm::sys::IsBigEndianHost ? DataSize - sizeof(U) : 0);
+ if (New)
+ return *new (Obj) U;
+ return *std::launder(reinterpret_cast<U *>(Obj));
+ }
+
+ T *&GetPtr() const { return As<T *>(false); }
+ uint64_t &GetU64() const { return As<uint64_t>(false); }
+ void SetPtr(T *Ptr) const { As<T *>(true) = Ptr; }
+ void SetU64(uint64_t U64) const { As<uint64_t>(true) = U64; }
public:
LazyOffsetPtr() = default;
- explicit LazyOffsetPtr(T *Ptr) : Ptr(reinterpret_cast<uint64_t>(Ptr)) {}
+ explicit LazyOffsetPtr(T *Ptr) : Data() { SetPtr(Ptr); }
- explicit LazyOffsetPtr(uint64_t Offset) : Ptr((Offset << 1) | 0x01) {
+ explicit LazyOffsetPtr(uint64_t Offset) : Data() {
assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits");
if (Offset == 0)
- Ptr = 0;
+ SetPtr(nullptr);
+ else
+ SetU64((Offset << 1) | 0x01);
}
LazyOffsetPtr &operator=(T *Ptr) {
- this->Ptr = reinterpret_cast<uint64_t>(Ptr);
+ SetPtr(Ptr);
return *this;
}
LazyOffsetPtr &operator=(uint64_t Offset) {
assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits");
if (Offset == 0)
- Ptr = 0;
+ SetPtr(nullptr);
else
- Ptr = (Offset << 1) | 0x01;
+ SetU64((Offset << 1) | 0x01);
return *this;
}
@@ -356,15 +378,15 @@ struct LazyOffsetPtr {
/// Whether this pointer is non-NULL.
///
/// This operation does not require the AST node to be deserialized.
- explicit operator bool() const { return Ptr != 0; }
+ explicit operator bool() const { return isOffset() || GetPtr() != nullptr; }
/// Whether this pointer is non-NULL.
///
/// This operation does not require the AST node to be deserialized.
- bool isValid() const { return Ptr != 0; }
+ bool isValid() const { return isOffset() || GetPtr() != nullptr; }
/// Whether this pointer is currently stored as an offset.
- bool isOffset() const { return Ptr & 0x01; }
+ bool isOffset() const { return GetLSB() & 0x01; }
/// Retrieve the pointer to the AST node that this lazy pointer points to.
///
@@ -375,9 +397,9 @@ struct LazyOffsetPtr {
if (isOffset()) {
assert(Source &&
"Cannot deserialize a lazy pointer without an AST source");
- Ptr = reinterpret_cast<uint64_t>((Source->*Get)(OffsT(Ptr >> 1)));
+ SetPtr((Source->*Get)(OffsT(GetU64() >> 1)));
}
- return reinterpret_cast<T*>(Ptr);
+ return GetPtr();
}
/// Retrieve the address of the AST node pointer. Deserializes the pointee if
@@ -385,7 +407,7 @@ struct LazyOffsetPtr {
T **getAddressOfPointer(ExternalASTSource *Source) const {
// Ensure the integer is in pointer form.
(void)get(Source);
- return reinterpret_cast<T**>(&Ptr);
+ return &GetPtr();
}
};
More information about the llvm-branch-commits
mailing list