[clang] [clang][bytecode] Support different integral types (e.g. addresses) (PR #185028)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 6 07:43:31 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
This is an alternative approach to https://github.com/llvm/llvm-project/pull/169769.
We leave the old `Integral<Bits, Signed>` intact and don't increase its size at all, but then introduce a new `IntegralOrPtr<Bits, Signed>`, which either holds its value _or_ a pointer and an offset. To support address-label-diffs, the offset is always pointer sized as well, making everything `>= 32` bits `sizeof(void*) + sizeof(void*) + sizeof(uint8_t)` in size.
The old approach did not work out in the end because we need to be able to do arithmetic (but essentially just `+` and `-`) on the offsets of such integers-that-are-actually-pointers.
c-t-t-:
https://llvm-compile-time-tracker.com/compare.php?from=e7448c3f4088cae61cb1bf8ade1a4a79d7cc4dbb&to=4aa23d5b4d8e6c43b0cf846f18f34ea967895fe5&stat=instructions:u
---
Patch is 60.44 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/185028.diff
33 Files Affected:
- (modified) clang/lib/AST/ByteCode/Boolean.h (+1-2)
- (modified) clang/lib/AST/ByteCode/Context.cpp (+1-1)
- (modified) clang/lib/AST/ByteCode/Descriptor.cpp (+7)
- (modified) clang/lib/AST/ByteCode/Descriptor.h (+5)
- (modified) clang/lib/AST/ByteCode/Integral.h (+372-10)
- (modified) clang/lib/AST/ByteCode/IntegralAP.h (+1)
- (modified) clang/lib/AST/ByteCode/Interp.cpp (+27-13)
- (modified) clang/lib/AST/ByteCode/Interp.h (+206-9)
- (modified) clang/lib/AST/ByteCode/InterpBuiltin.cpp (+26-34)
- (modified) clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp (+10-4)
- (modified) clang/lib/AST/ByteCode/InterpStack.h (+5-8)
- (modified) clang/lib/AST/ByteCode/Pointer.cpp (+9)
- (modified) clang/lib/AST/ByteCode/Pointer.h (+3-1)
- (modified) clang/lib/AST/ByteCode/PrimType.h (+28-4)
- (modified) clang/lib/AST/ByteCode/Primitives.h (+8)
- (added) clang/test/AST/ByteCode/addr-label-diff.c (+19)
- (added) clang/test/AST/ByteCode/addr-label-diff.cpp (+16)
- (modified) clang/test/AST/ByteCode/builtin-bit-cast.cpp (+8)
- (modified) clang/test/AST/ByteCode/const-eval.c (+6-3)
- (modified) clang/test/AST/ByteCode/cxx11.cpp (+12)
- (added) clang/test/AST/ByteCode/int-as-ptr-arith.c (+17)
- (modified) clang/test/CodeGen/const-init.c (+1)
- (modified) clang/test/CodeGen/const-label-addr.c (+1)
- (modified) clang/test/CodeGen/statements.c (+1)
- (modified) clang/test/CodeGen/staticinit.c (+1)
- (modified) clang/test/CodeGenCXX/2008-05-07-CrazyOffsetOf.cpp (+1)
- (modified) clang/test/CodeGenCXX/const-init-cxx11.cpp (+3)
- (modified) clang/test/CodeGenCXX/const-init.cpp (+6)
- (modified) clang/test/Sema/array-init.c (+2)
- (modified) clang/test/Sema/compound-literal.c (+1)
- (modified) clang/test/Sema/const-ptr-int-ptr-cast.c (+1)
- (modified) clang/test/Sema/init.c (+1)
- (modified) clang/test/SemaCXX/constexpr-string.cpp (+1)
``````````diff
diff --git a/clang/lib/AST/ByteCode/Boolean.h b/clang/lib/AST/ByteCode/Boolean.h
index fd8d546656881..09eefee14a854 100644
--- a/clang/lib/AST/ByteCode/Boolean.h
+++ b/clang/lib/AST/ByteCode/Boolean.h
@@ -61,11 +61,10 @@ class Boolean final {
bool isMin() const { return isZero(); }
constexpr static bool isMinusOne() { return false; }
-
constexpr static bool isSigned() { return false; }
-
constexpr static bool isNegative() { return false; }
constexpr static bool isPositive() { return !isNegative(); }
+ constexpr static bool isNumber() { return true; }
ComparisonCategoryResult compare(const Boolean &RHS) const {
return Compare(V, RHS.V);
diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp
index 879d51e6a2c3e..cc391ba3327f8 100644
--- a/clang/lib/AST/ByteCode/Context.cpp
+++ b/clang/lib/AST/ByteCode/Context.cpp
@@ -186,7 +186,7 @@ bool Context::evaluateStringRepr(State &Parent, const Expr *SizeExpr,
return false;
// Must be char.
- if (Ptr.getFieldDesc()->getElemSize() != 1 /*bytes*/)
+ if (Ptr.getFieldDesc()->getElemDataSize() != 1 /*bytes*/)
return false;
if (Size > Ptr.getNumElems()) {
diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp b/clang/lib/AST/ByteCode/Descriptor.cpp
index 5ebc726328fb7..6a192cad9bca2 100644
--- a/clang/lib/AST/ByteCode/Descriptor.cpp
+++ b/clang/lib/AST/ByteCode/Descriptor.cpp
@@ -483,3 +483,10 @@ bool Descriptor::hasTrivialDtor() const {
}
bool Descriptor::isUnion() const { return isRecord() && ElemRecord->isUnion(); }
+
+unsigned Descriptor::getElemDataSize() const {
+ if ((isPrimitive() || isPrimitiveArray()) && isIntegralType(getPrimType())) {
+ FIXED_SIZE_INT_TYPE_SWITCH(getPrimType(), { return T::bitWidth() / 8; });
+ }
+ return ElemSize;
+}
diff --git a/clang/lib/AST/ByteCode/Descriptor.h b/clang/lib/AST/ByteCode/Descriptor.h
index b052971733567..9046801f4ebef 100644
--- a/clang/lib/AST/ByteCode/Descriptor.h
+++ b/clang/lib/AST/ByteCode/Descriptor.h
@@ -246,6 +246,11 @@ struct Descriptor final {
unsigned getAllocSize() const { return AllocSize; }
/// returns the size of an element when the structure is viewed as an array.
unsigned getElemSize() const { return ElemSize; }
+ /// Returns the element data size, i.e. not what the size of
+ /// our primitive data type is, but what the data size of that is.
+ /// E.g., for PT_SInt32, that's 4 bytes.
+ unsigned getElemDataSize() const;
+
/// Returns the size of the metadata.
unsigned getMetadataSize() const { return MDSize; }
diff --git a/clang/lib/AST/ByteCode/Integral.h b/clang/lib/AST/ByteCode/Integral.h
index e90f1a9a74e1c..82b62f7969d12 100644
--- a/clang/lib/AST/ByteCode/Integral.h
+++ b/clang/lib/AST/ByteCode/Integral.h
@@ -14,6 +14,7 @@
#define LLVM_CLANG_AST_INTERP_INTEGRAL_H
#include "clang/AST/APValue.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/ComparisonCategories.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/Support/MathExtras.h"
@@ -22,6 +23,7 @@
#include <cstdint>
#include "Primitives.h"
+#include "Program.h"
namespace clang {
namespace interp {
@@ -69,7 +71,7 @@ template <unsigned Bits, bool Signed> class Integral final {
// The primitive representing the integral.
using ReprT = typename Repr<Bits, Signed>::Type;
- ReprT V;
+ ReprT V = 0;
static_assert(std::is_trivially_copyable_v<ReprT>);
/// Primitive representing limits.
@@ -83,7 +85,7 @@ template <unsigned Bits, bool Signed> class Integral final {
using AsUnsigned = Integral<Bits, false>;
/// Zero-initializes an integral.
- Integral() : V(0) {}
+ Integral() = default;
/// Constructs an integral from another integral.
template <unsigned SrcBits, bool SrcSign>
@@ -144,15 +146,12 @@ template <unsigned Bits, bool Signed> class Integral final {
}
constexpr static unsigned bitWidth() { return Bits; }
+ constexpr static bool isSigned() { return Signed; }
+ constexpr static bool isNumber() { return true; }
bool isZero() const { return !V; }
-
bool isMin() const { return *this == min(bitWidth()); }
-
bool isMinusOne() const { return Signed && V == ReprT(-1); }
-
- constexpr static bool isSigned() { return Signed; }
-
bool isNegative() const { return V < ReprT(0); }
bool isPositive() const { return !isNegative(); }
@@ -205,7 +204,8 @@ template <unsigned Bits, bool Signed> class Integral final {
static Integral zero(unsigned BitWidth = 0) { return from(0); }
template <typename ValT>
- static Integral from(ValT Value, unsigned NumBits = 0) {
+ static std::enable_if_t<!std::is_same_v<ValT, IntegralKind>, Integral>
+ from(ValT Value, unsigned NumBits = 0) {
if constexpr (std::is_integral_v<ValT>)
return Integral(Value);
else
@@ -213,7 +213,8 @@ template <unsigned Bits, bool Signed> class Integral final {
}
template <unsigned SrcBits, bool SrcSign>
- static Integral from(Integral<SrcBits, SrcSign> Value) {
+ static std::enable_if_t<SrcBits != 0, Integral>
+ from(Integral<SrcBits, SrcSign> Value) {
return Integral(Value.V);
}
@@ -287,7 +288,7 @@ template <unsigned Bits, bool Signed> class Integral final {
*R = Integral::from(A.V >> B.V, OpBits);
}
-private:
+public:
template <typename T> static bool CheckAddUB(T A, T B, T &R) {
if constexpr (std::is_signed_v<T>) {
return llvm::AddOverflow<T>(A, B, R);
@@ -327,6 +328,367 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Integral<Bits, Signed> I) {
return OS;
}
+template <unsigned Bits, bool Signed> class IntegralOrPtr final {
+ static_assert(Bits >= 32);
+
+public:
+ // The primitive representing the integral.
+ using ReprT = typename Repr<Bits, Signed>::Type;
+
+private:
+ using OffsetT = intptr_t;
+ static_assert(std::is_trivially_copyable_v<ReprT>);
+ template <unsigned OtherBits, bool OtherSigned> friend class IntegralOrPtr;
+
+ IntegralKind Kind = IntegralKind::Number;
+ union {
+ ReprT V;
+ struct {
+ const void *P;
+ OffsetT Offset;
+ } Ptr;
+ };
+
+ static_assert(sizeof(uintptr_t) >= sizeof(ReprT));
+
+ /// Primitive representing limits.
+ static const auto Min = std::numeric_limits<ReprT>::min();
+ static const auto Max = std::numeric_limits<ReprT>::max();
+
+ /// Construct an integral from anything that is convertible to storage.
+ template <typename T> explicit IntegralOrPtr(T V) : V(V) {}
+ template <typename T>
+ explicit IntegralOrPtr(IntegralKind Kind, T V) : Kind(Kind), V(V) {}
+
+public:
+ using AsUnsigned = IntegralOrPtr<Bits, false>;
+
+ /// Zero-initializes an integral.
+ IntegralOrPtr() = default;
+
+ /// Constructs an integral from another integral.
+ template <unsigned SrcBits, bool SrcSign>
+ explicit IntegralOrPtr(Integral<SrcBits, SrcSign> V) : Kind(V.Kind), V(V) {}
+
+ explicit IntegralOrPtr(IntegralKind Kind, const void *P, OffsetT Offset = 0)
+ : Kind(Kind) {
+ Ptr.P = P;
+ Ptr.Offset = Offset;
+ }
+
+ explicit IntegralOrPtr(const void *P1, const void *P2)
+ : Kind(IntegralKind::AddrLabelDiff) {
+ Ptr.P = P1;
+ Ptr.Offset = reinterpret_cast<uintptr_t>(P2);
+ }
+
+ IntegralKind getKind() const { return Kind; }
+ bool isNumber() const { return Kind == IntegralKind::Number; }
+ const void *getPtr() const {
+ assert(!isNumber());
+ return Ptr.P;
+ }
+ ReprT getOffset() const {
+ assert(!isNumber());
+ return Ptr.Offset;
+ }
+
+ /// Construct an integral from a value based on signedness.
+ explicit IntegralOrPtr(const APSInt &V)
+ : V(V.isSigned() ? V.getSExtValue() : V.getZExtValue()) {}
+
+ bool operator<(IntegralOrPtr RHS) const { return V < RHS.V; }
+ bool operator>(IntegralOrPtr RHS) const { return V > RHS.V; }
+ bool operator<=(IntegralOrPtr RHS) const { return V <= RHS.V; }
+ bool operator>=(IntegralOrPtr RHS) const { return V >= RHS.V; }
+ bool operator==(IntegralOrPtr RHS) const { return V == RHS.V; }
+ bool operator!=(IntegralOrPtr RHS) const { return V != RHS.V; }
+ bool operator>=(unsigned RHS) const {
+ return static_cast<unsigned>(V) >= RHS;
+ }
+
+ bool operator>(unsigned RHS) const {
+ return V >= 0 && static_cast<unsigned>(V) > RHS;
+ }
+
+ IntegralOrPtr operator-() const { return IntegralOrPtr(-V); }
+ IntegralOrPtr operator-(const IntegralOrPtr &Other) const {
+ return IntegralOrPtr(V - Other.V);
+ }
+ IntegralOrPtr operator~() const { return IntegralOrPtr(~V); }
+
+ template <unsigned DstBits, bool DstSign>
+ explicit operator IntegralOrPtr<DstBits, DstSign>() const {
+ return IntegralOrPtr<DstBits, DstSign>(Kind, V);
+ }
+
+ template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>
+ explicit operator Ty() const {
+ return V;
+ }
+
+ APSInt toAPSInt() const {
+ assert(isNumber());
+ return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
+ }
+
+ APSInt toAPSInt(unsigned BitWidth) const {
+ return APSInt(toAPInt(BitWidth), !Signed);
+ }
+
+ APInt toAPInt(unsigned BitWidth) const {
+ assert(isNumber());
+ if constexpr (Signed)
+ return APInt(Bits, static_cast<uint64_t>(V), Signed)
+ .sextOrTrunc(BitWidth);
+ else
+ return APInt(Bits, static_cast<uint64_t>(V), Signed)
+ .zextOrTrunc(BitWidth);
+ }
+
+ APValue toAPValue(const ASTContext &) const {
+ switch (Kind) {
+ case IntegralKind::Address: {
+ return APValue((const ValueDecl *)Ptr.P,
+ CharUnits::fromQuantity(Ptr.Offset),
+ APValue::NoLValuePath{});
+ }
+ case IntegralKind::LabelAddress: {
+ return APValue((const Expr *)Ptr.P, CharUnits::Zero(),
+ APValue::NoLValuePath{});
+ }
+ case IntegralKind::BlockAddress: {
+ const Block *B = reinterpret_cast<const Block *>(Ptr.P);
+ const Descriptor *D = B->getDescriptor();
+ if (const Expr *E = D->asExpr())
+ return APValue(E, CharUnits::Zero(), APValue::NoLValuePath{});
+
+ return APValue(D->asValueDecl(), CharUnits::Zero(),
+ APValue::NoLValuePath{});
+ }
+ case IntegralKind::AddrLabelDiff: {
+ return APValue(
+ (const AddrLabelExpr *)Ptr.P,
+ (const AddrLabelExpr *)reinterpret_cast<const void *>(Ptr.Offset));
+ }
+ case IntegralKind::Number:
+ return APValue(toAPSInt());
+ }
+ llvm_unreachable("Unhandled IntegralKind");
+ }
+
+ IntegralOrPtr<Bits, false> toUnsigned() const {
+ return IntegralOrPtr<Bits, false>(*this);
+ }
+
+ constexpr static unsigned bitWidth() { return Bits; }
+ constexpr static bool isSigned() { return Signed; }
+
+ bool isZero() const { return !V; }
+ bool isMin() const { return *this == min(bitWidth()); }
+ bool isMinusOne() const { return Signed && V == ReprT(-1); }
+ bool isNegative() const { return V < ReprT(0); }
+ bool isPositive() const { return !isNegative(); }
+
+ ComparisonCategoryResult compare(const IntegralOrPtr &RHS) const {
+ return Compare(V, RHS.V);
+ }
+
+ void bitcastToMemory(std::byte *Dest) const {
+ assert(isNumber());
+ std::memcpy(Dest, &V, sizeof(V));
+ }
+
+ static IntegralOrPtr bitcastFromMemory(const std::byte *Src,
+ unsigned BitWidth) {
+ assert(BitWidth == sizeof(ReprT) * 8);
+ ReprT V;
+
+ std::memcpy(&V, Src, sizeof(ReprT));
+ return IntegralOrPtr(V);
+ }
+
+ std::string toDiagnosticString(const ASTContext &Ctx) const {
+ std::string NameStr;
+ llvm::raw_string_ostream OS(NameStr);
+ OS << V;
+ return NameStr;
+ }
+
+ unsigned countLeadingZeros() const {
+ assert(isNumber());
+ if constexpr (!Signed)
+ return llvm::countl_zero<ReprT>(V);
+ if (isPositive())
+ return llvm::countl_zero<typename AsUnsigned::ReprT>(
+ static_cast<typename AsUnsigned::ReprT>(V));
+ llvm_unreachable("Don't call countLeadingZeros() on negative values.");
+ }
+
+ IntegralOrPtr truncate(unsigned TruncBits) const {
+ assert(TruncBits >= 1);
+ if (TruncBits >= Bits)
+ return *this;
+ const ReprT BitMask = (ReprT(1) << ReprT(TruncBits)) - 1;
+ const ReprT SignBit = ReprT(1) << (TruncBits - 1);
+ const ReprT ExtMask = ~BitMask;
+ return IntegralOrPtr((V & BitMask) |
+ (Signed && (V & SignBit) ? ExtMask : 0));
+ }
+
+ void print(llvm::raw_ostream &OS) const {
+ switch (Kind) {
+ case IntegralKind::Number:
+ OS << V;
+ break;
+ case IntegralKind::AddrLabelDiff:
+ OS << Ptr.P << " - " << (const void *)Ptr.Offset << " (AddrLabelDiff)";
+ break;
+ case IntegralKind::Address:
+ OS << Ptr.P << " + " << Ptr.Offset << " (Address)";
+ break;
+ case IntegralKind::BlockAddress:
+ OS << Ptr.P << " + " << Ptr.Offset << " (BlockAddress)";
+ break;
+ case IntegralKind::LabelAddress:
+ OS << Ptr.P << " + " << Ptr.Offset << " (LabelAddress)";
+ }
+ }
+
+ static IntegralOrPtr min(unsigned NumBits) { return IntegralOrPtr(Min); }
+ static IntegralOrPtr max(unsigned NumBits) { return IntegralOrPtr(Max); }
+ static IntegralOrPtr zero(unsigned BitWidth = 0) { return from(0); }
+
+ template <typename ValT>
+ static std::enable_if_t<!std::is_same_v<ValT, IntegralKind>, IntegralOrPtr>
+ from(ValT V, unsigned NumBits = 0) {
+ if constexpr (std::is_integral_v<ValT>)
+ return IntegralOrPtr(V);
+ else
+ return IntegralOrPtr(static_cast<IntegralOrPtr::ReprT>(V));
+ }
+
+ template <unsigned SrcBits, bool SrcSign>
+ static std::enable_if_t<SrcBits != 0, IntegralOrPtr>
+ from(IntegralOrPtr<SrcBits, SrcSign> V) {
+ auto A = IntegralOrPtr(V.Kind, V.V);
+ switch (V.Kind) {
+ case IntegralKind::Number:
+ A.V = V.V;
+ break;
+ case IntegralKind::AddrLabelDiff:
+ case IntegralKind::Address:
+ case IntegralKind::BlockAddress:
+ case IntegralKind::LabelAddress:
+ A.Ptr.P = V.Ptr.P;
+ A.Ptr.Offset = V.Ptr.Offset;
+ break;
+ }
+ return A;
+ }
+
+ template <typename T> static IntegralOrPtr from(IntegralKind Kind, T V) {
+ return IntegralOrPtr(Kind, V);
+ }
+
+ static bool increment(IntegralOrPtr A, IntegralOrPtr *R) {
+ assert(A.isNumber());
+ return add(A, IntegralOrPtr(ReprT(1)), A.bitWidth(), R);
+ }
+
+ static bool decrement(IntegralOrPtr A, IntegralOrPtr *R) {
+ assert(A.isNumber());
+ return sub(A, IntegralOrPtr(ReprT(1)), A.bitWidth(), R);
+ }
+
+ static bool add(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits,
+ IntegralOrPtr *R) {
+ assert(A.isNumber() && B.isNumber());
+ return Integral<Bits, Signed>::CheckAddUB(A.V, B.V, R->V);
+ }
+
+ static bool sub(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits,
+ IntegralOrPtr *R) {
+ assert(A.isNumber() && B.isNumber());
+ return Integral<Bits, Signed>::CheckSubUB(A.V, B.V, R->V);
+ }
+
+ static bool mul(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits,
+ IntegralOrPtr *R) {
+ assert(A.isNumber() && B.isNumber());
+ return Integral<Bits, Signed>::CheckMulUB(A.V, B.V, R->V);
+ }
+
+ static bool rem(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits,
+ IntegralOrPtr *R) {
+ assert(A.isNumber() && B.isNumber());
+ *R = IntegralOrPtr(A.V % B.V);
+ return false;
+ }
+
+ static bool div(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits,
+ IntegralOrPtr *R) {
+ assert(A.isNumber() && B.isNumber());
+ *R = IntegralOrPtr(A.V / B.V);
+ return false;
+ }
+
+ static bool bitAnd(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits,
+ IntegralOrPtr *R) {
+ assert(A.isNumber() && B.isNumber());
+ *R = IntegralOrPtr(A.V & B.V);
+ return false;
+ }
+
+ static bool bitOr(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits,
+ IntegralOrPtr *R) {
+ assert(A.isNumber() && B.isNumber());
+ *R = IntegralOrPtr(A.V | B.V);
+ return false;
+ }
+
+ static bool bitXor(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits,
+ IntegralOrPtr *R) {
+ assert(A.isNumber() && B.isNumber());
+ *R = IntegralOrPtr(A.V ^ B.V);
+ return false;
+ }
+
+ static bool neg(IntegralOrPtr A, IntegralOrPtr *R) {
+ if (Signed && A.isMin())
+ return true;
+
+ *R = -A;
+ return false;
+ }
+
+ static bool comp(IntegralOrPtr A, IntegralOrPtr *R) {
+ *R = IntegralOrPtr(~A.V);
+ return false;
+ }
+
+ template <unsigned RHSBits, bool RHSSign>
+ static void shiftLeft(const IntegralOrPtr A,
+ const IntegralOrPtr<RHSBits, RHSSign> B,
+ unsigned OpBits, IntegralOrPtr *R) {
+ *R = IntegralOrPtr::from(A.V << B.V, OpBits);
+ }
+
+ template <unsigned RHSBits, bool RHSSign>
+ static void shiftRight(const IntegralOrPtr A,
+ const IntegralOrPtr<RHSBits, RHSSign> B,
+ unsigned OpBits, IntegralOrPtr *R) {
+ *R = IntegralOrPtr::from(A.V >> B.V, OpBits);
+ }
+};
+
+template <unsigned Bits, bool Signed>
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+ IntegralOrPtr<Bits, Signed> I) {
+ I.print(OS);
+ return OS;
+}
+
} // namespace interp
} // namespace clang
diff --git a/clang/lib/AST/ByteCode/IntegralAP.h b/clang/lib/AST/ByteCode/IntegralAP.h
index b11e6eea28e3f..9f53ac7716bba 100644
--- a/clang/lib/AST/ByteCode/IntegralAP.h
+++ b/clang/lib/AST/ByteCode/IntegralAP.h
@@ -139,6 +139,7 @@ template <bool Signed> class IntegralAP final {
constexpr uint32_t bitWidth() const { return BitWidth; }
constexpr unsigned numWords() const { return APInt::getNumWords(BitWidth); }
constexpr bool singleWord() const { return numWords() == 1; }
+ constexpr static bool isNumber() { return true; }
APSInt toAPSInt(unsigned Bits = 0) const {
if (Bits == 0)
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index ebc7220aa5671..0f571f6789d10 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -88,20 +88,20 @@ static bool BCP(InterpState &S, CodePtr &RealPC, int32_t Offset, PrimType PT) {
if (PT == PT_Ptr) {
const auto &Ptr = S.Stk.pop<Pointer>();
assert(S.Stk.size() == StackSizeBefore);
- S.Stk.push<Integral<32, true>>(
- Integral<32, true>::from(CheckBCPResult(S, Ptr)));
+ S.Stk.push<IntegralOrPtr<32, true>>(
+ IntegralOrPtr<32, true>::from(CheckBCPResult(S, Ptr)));
} else {
// Pop the result from the stack and return success.
TYPE_SWITCH(PT, S.Stk.pop<T>(););
assert(S.Stk.size() == StackSizeBefore);
- S.Stk.push<Integral<32, true>>(Integral<32, true>::from(1));
+ S.Stk.push<IntegralOrPtr<32, true>>(IntegralOrPtr<32, true>::from(1));
}
} else {
if (!S.inConstantContext())
return Invalid(S, RealPC);
S.Stk.clearTo(StackSizeBefore);
- S.Stk.push<Integral<32, true>>(Integral<32, true>::from(0));
+ S.Stk.push<IntegralOrPtr<32, true>>(IntegralOrPtr<32, true>::from(0));
}
// RealPC should not have been modified.
@@ -2187,12 +2187,15 @@ bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,
S.CCEDiag(E, diag::note_constexpr_invalid_cast)
<< 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
- if (Ptr.isDummy())
+ if (S.getLangOpts().CPlusPlus && Ptr.isDummy() && !Ptr.pointsToLabel())
return false;
- if (Ptr.isFunctionPointer())
+ if (Ptr.isIntegralPointer())
+ return true;
+
+ if (Ptr.isDummy())
return true;
- if (Ptr.isBlockPointer() && !Ptr.isZero()) {
+ if (!Ptr.isZero()) {
// Only allow based lvalue casts if they are lossless.
if (S.getASTContext().getTargetInfo().getPointerWidth(LangAS::Default) !=
BitWidth)
@@ -2201,6 +2204,11 @@ bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,
return true;
}
+bool CheckIntegralAddressCast(InterpState &S, CodePtr OpPC, unsigned BitWidth) {
+ return (S.getASTContext().getTargetInfo().getPointerWidth(LangAS::Default) ==
+ BitWidth);
+}
+
bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
@@ -2286,13 +2294,19 @@ bool DiagTypeid(InterpState &S, CodePtr OpPC) {
bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS,
const Pointer &RHS) {
+ if (!LHS.pointsToStr...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/185028
More information about the cfe-commits
mailing list