https://github.com/tbaederr created
https://github.com/llvm/llvm-project/pull/169769
This adds an `IntegralKind` to `clang::interp::Integral` (not `IntegralAP` yet).
As a result, the size of such an integral is now different (larger) than that
of its underlying representation type.
If the type is now `IntegralKind::Number`, the value of the underlying type is
used as an internal value for a pointer or an address label difference (similar
to the existing "native pointer" mechanism in `Program`).
One existing problem is that the IDs we create for address label differences
can overflow the underlying integral type, e.g. in
```c
int c(void) {
static char ar1 = &&l2 - &&l1;
l1:
return 10;
l2:
return 11;
}
```
we can only save roughly 128 (depending on other saved pointers, etc.)
variables like `ar1` here, since otherwise the ID we create will overflow the
8bit size of the underling integral type.
Another unfortunate side-effect is that we need to pass around the `Program`
instance more often.
>From d08f49c2fce9033d3479e2013bbfd3e1bd8f0e9d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]>
Date: Mon, 17 Nov 2025 13:58:23 +0100
Subject: [PATCH] [clang][bytecode] Support different integral types (e.g.
addresses)
---
clang/lib/AST/ByteCode/Boolean.h | 8 +-
clang/lib/AST/ByteCode/Context.cpp | 11 +-
clang/lib/AST/ByteCode/Descriptor.cpp | 7 +
clang/lib/AST/ByteCode/Descriptor.h | 5 +
clang/lib/AST/ByteCode/EvalEmitter.cpp | 19 +--
clang/lib/AST/ByteCode/FixedPoint.h | 9 +-
clang/lib/AST/ByteCode/Floating.h | 7 +-
clang/lib/AST/ByteCode/Integral.h | 69 ++++++--
clang/lib/AST/ByteCode/IntegralAP.h | 8 +-
clang/lib/AST/ByteCode/Interp.cpp | 42 +++--
clang/lib/AST/ByteCode/Interp.h | 150 +++++++++++++++---
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 68 ++++----
clang/lib/AST/ByteCode/InterpFrame.cpp | 14 +-
clang/lib/AST/ByteCode/InterpHelpers.h | 4 +-
clang/lib/AST/ByteCode/InterpStack.h | 24 +--
clang/lib/AST/ByteCode/MemberPointer.cpp | 5 +-
clang/lib/AST/ByteCode/MemberPointer.h | 7 +-
clang/lib/AST/ByteCode/Pointer.cpp | 37 +++--
clang/lib/AST/ByteCode/Pointer.h | 11 +-
clang/lib/AST/ByteCode/PrimType.h | 16 ++
clang/lib/AST/ByteCode/Primitives.h | 8 +
clang/lib/AST/ByteCode/Program.cpp | 28 ++--
clang/lib/AST/ByteCode/Program.h | 39 +++++
clang/test/AST/ByteCode/addr-label-diff.c | 22 +++
clang/test/AST/ByteCode/const-eval.c | 3 +
clang/test/CodeGen/const-label-addr.c | 1 +
clang/test/CodeGen/statements.c | 1 +
clang/test/CodeGen/staticinit.c | 1 +
.../CodeGenCXX/2008-05-07-CrazyOffsetOf.cpp | 1 +
clang/test/CodeGenCXX/const-init-cxx11.cpp | 3 +
clang/test/Sema/compound-literal.c | 1 +
clang/test/SemaCXX/constexpr-string.cpp | 1 +
clang/unittests/AST/ByteCode/toAPValue.cpp | 16 +-
33 files changed, 475 insertions(+), 171 deletions(-)
create mode 100644 clang/test/AST/ByteCode/addr-label-diff.c
diff --git a/clang/lib/AST/ByteCode/Boolean.h b/clang/lib/AST/ByteCode/Boolean.h
index fd8d546656881..f04bcd3ba337c 100644
--- a/clang/lib/AST/ByteCode/Boolean.h
+++ b/clang/lib/AST/ByteCode/Boolean.h
@@ -52,10 +52,14 @@ class Boolean final {
APSInt toAPSInt(unsigned NumBits) const {
return APSInt(toAPSInt().zextOrTrunc(NumBits), true);
}
- APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }
+ APValue toAPValue(const ASTContext &, const Program &) const {
+ return APValue(toAPSInt());
+ }
Boolean toUnsigned() const { return *this; }
+ static IntegralKind getKind() { return IntegralKind::Number; }
+
constexpr static unsigned bitWidth() { return 1; }
bool isZero() const { return !V; }
bool isMin() const { return isZero(); }
@@ -84,7 +88,7 @@ class Boolean final {
void bitcastToMemory(std::byte *Buff) { std::memcpy(Buff, &V, sizeof(V)); }
void print(llvm::raw_ostream &OS) const { OS << (V ? "true" : "false"); }
- std::string toDiagnosticString(const ASTContext &Ctx) const {
+ std::string toDiagnosticString(const ASTContext &Ctx, const Program &) const
{
std::string NameStr;
llvm::raw_string_ostream OS(NameStr);
print(OS);
diff --git a/clang/lib/AST/ByteCode/Context.cpp
b/clang/lib/AST/ByteCode/Context.cpp
index 74ec986e49ca7..6f716b0aee70e 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()) {
@@ -199,7 +199,7 @@ bool Context::evaluateStringRepr(State &Parent, const Expr
*SizeExpr,
Result = APValue(APValue::UninitArray{}, Size, Size);
for (uint64_t I = 0; I != Size; ++I) {
if (std::optional<APValue> ElemVal =
- Ptr.atIndex(I).toRValue(*this, CharTy))
+ Ptr.atIndex(I).toRValue(*this, CharTy, *P))
Result.getArrayInitializedElt(I) = *ElemVal;
else
return false;
@@ -208,7 +208,12 @@ bool Context::evaluateStringRepr(State &Parent, const Expr
*SizeExpr,
assert((std::is_same_v<ResultT, std::string>));
if (Size < Result.max_size())
Result.resize(Size);
- Result.assign(reinterpret_cast<const char *>(Ptr.getRawAddress()), Size);
+ unsigned StartIndex = Ptr.getIndex();
+ for (uint64_t I = 0; I != Size; ++I) {
+ FIXED_SIZE_INT_TYPE_SWITCH(Ptr.getFieldDesc()->getPrimType(), {
+ Result[I] = static_cast<char>(Ptr.elem<T>(StartIndex + I));
+ });
+ }
}
return true;
diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp
b/clang/lib/AST/ByteCode/Descriptor.cpp
index 0a819599287ee..59ad3015b9b47 100644
--- a/clang/lib/AST/ByteCode/Descriptor.cpp
+++ b/clang/lib/AST/ByteCode/Descriptor.cpp
@@ -468,6 +468,13 @@ 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;
+}
+
InitMap::InitMap(unsigned N)
: UninitFields(N), Data(std::make_unique<T[]>(numFields(N))) {}
diff --git a/clang/lib/AST/ByteCode/Descriptor.h
b/clang/lib/AST/ByteCode/Descriptor.h
index 90dc2b4aa3111..e4f262d52b858 100644
--- a/clang/lib/AST/ByteCode/Descriptor.h
+++ b/clang/lib/AST/ByteCode/Descriptor.h
@@ -242,6 +242,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/EvalEmitter.cpp
b/clang/lib/AST/ByteCode/EvalEmitter.cpp
index a2e01efc8ffd9..9040e4ac5b67c 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.cpp
+++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp
@@ -182,7 +182,7 @@ template <PrimType OpType> bool
EvalEmitter::emitRet(SourceInfo Info) {
return true;
using T = typename PrimConv<OpType>::T;
- EvalResult.takeValue(S.Stk.pop<T>().toAPValue(Ctx.getASTContext()));
+ EvalResult.takeValue(S.Stk.pop<T>().toAPValue(Ctx.getASTContext(), S.P));
return true;
}
@@ -193,7 +193,7 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(SourceInfo
Info) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (Ptr.isFunctionPointer()) {
- EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext()));
+ EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext(), S.P));
return true;
}
@@ -224,7 +224,7 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(SourceInfo
Info) {
return false;
if (std::optional<APValue> V =
- Ptr.toRValue(Ctx, EvalResult.getSourceType())) {
+ Ptr.toRValue(Ctx, EvalResult.getSourceType(), P)) {
EvalResult.takeValue(std::move(*V));
} else {
return false;
@@ -234,14 +234,14 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(SourceInfo
Info) {
// the result, even if the pointer is dead.
// This will later be diagnosed by CheckLValueConstantExpression.
if (Ptr.isBlockPointer() && !Ptr.block()->isStatic()) {
- EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext()));
+ EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext(), S.P));
return true;
}
if (!Ptr.isLive() && !Ptr.isTemporary())
return false;
- EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext()));
+ EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext(), S.P));
}
return true;
@@ -261,7 +261,7 @@ bool EvalEmitter::emitRetValue(SourceInfo Info) {
return false;
if (std::optional<APValue> APV =
- Ptr.toRValue(S.getASTContext(), EvalResult.getSourceType())) {
+ Ptr.toRValue(S.getASTContext(), EvalResult.getSourceType(), P)) {
EvalResult.takeValue(std::move(*APV));
return true;
}
@@ -361,11 +361,12 @@ void EvalEmitter::updateGlobalTemporaries() {
const Pointer &Ptr = P.getPtrGlobal(*GlobalIndex);
APValue *Cached = Temp->getOrCreateValue(true);
if (OptPrimType T = Ctx.classify(E->getType())) {
- TYPE_SWITCH(*T,
- { *Cached = Ptr.deref<T>().toAPValue(Ctx.getASTContext());
});
+ TYPE_SWITCH(*T, {
+ *Cached = Ptr.deref<T>().toAPValue(Ctx.getASTContext(), S.P);
+ });
} else {
if (std::optional<APValue> APV =
- Ptr.toRValue(Ctx, Temp->getTemporaryExpr()->getType()))
+ Ptr.toRValue(Ctx, Temp->getTemporaryExpr()->getType(), P))
*Cached = *APV;
}
}
diff --git a/clang/lib/AST/ByteCode/FixedPoint.h
b/clang/lib/AST/ByteCode/FixedPoint.h
index fcb3c79cc1097..694b541c14cb5 100644
--- a/clang/lib/AST/ByteCode/FixedPoint.h
+++ b/clang/lib/AST/ByteCode/FixedPoint.h
@@ -13,6 +13,8 @@
#include "clang/AST/ComparisonCategories.h"
#include "llvm/ADT/APFixedPoint.h"
+#include "Program.h"
+
namespace clang {
namespace interp {
@@ -49,7 +51,9 @@ class FixedPoint final {
operator bool() const { return V.getBoolValue(); }
void print(llvm::raw_ostream &OS) const { OS << V; }
- APValue toAPValue(const ASTContext &) const { return APValue(V); }
+ APValue toAPValue(const ASTContext &, const Program &) const {
+ return APValue(V);
+ }
APSInt toAPSInt(unsigned BitWidth = 0) const { return V.getValue(); }
unsigned bitWidth() const { return V.getWidth(); }
@@ -78,9 +82,10 @@ class FixedPoint final {
return V.convertToInt(BitWidth, Signed, Overflow);
}
- std::string toDiagnosticString(const ASTContext &Ctx) const {
+ std::string toDiagnosticString(const ASTContext &Ctx, const Program &) const
{
return V.toString();
}
+ static IntegralKind getKind() { return IntegralKind::Number; }
ComparisonCategoryResult compare(const FixedPoint &Other) const {
int c = V.compare(Other.V);
diff --git a/clang/lib/AST/ByteCode/Floating.h
b/clang/lib/AST/ByteCode/Floating.h
index cc918dc12deb6..149133a535953 100644
--- a/clang/lib/AST/ByteCode/Floating.h
+++ b/clang/lib/AST/ByteCode/Floating.h
@@ -14,6 +14,7 @@
#define LLVM_CLANG_AST_INTERP_FLOATING_H
#include "Primitives.h"
+#include "Program.h"
#include "clang/AST/APValue.h"
#include "llvm/ADT/APFloat.h"
@@ -86,14 +87,16 @@ class Floating final {
APSInt toAPSInt(unsigned NumBits = 0) const {
return APSInt(getValue().bitcastToAPInt());
}
- APValue toAPValue(const ASTContext &) const { return APValue(getValue()); }
+ APValue toAPValue(const ASTContext &, const Program &) const {
+ return APValue(getValue());
+ }
void print(llvm::raw_ostream &OS) const {
// Can't use APFloat::print() since it appends a newline.
SmallVector<char, 16> Buffer;
getValue().toString(Buffer);
OS << Buffer;
}
- std::string toDiagnosticString(const ASTContext &Ctx) const {
+ std::string toDiagnosticString(const ASTContext &Ctx, const Program &) const
{
std::string NameStr;
llvm::raw_string_ostream OS(NameStr);
print(OS);
diff --git a/clang/lib/AST/ByteCode/Integral.h
b/clang/lib/AST/ByteCode/Integral.h
index e90f1a9a74e1c..d86f04c3afa8e 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,8 +71,9 @@ template <unsigned Bits, bool Signed> class Integral final {
// The primitive representing the integral.
using ReprT = typename Repr<Bits, Signed>::Type;
- ReprT V;
static_assert(std::is_trivially_copyable_v<ReprT>);
+ ReprT V;
+ IntegralKind Kind = IntegralKind::Number;
/// Primitive representing limits.
static const auto Min = std::numeric_limits<ReprT>::min();
@@ -78,6 +81,8 @@ template <unsigned Bits, bool Signed> class Integral final {
/// Construct an integral from anything that is convertible to storage.
template <typename T> explicit Integral(T V) : V(V) {}
+ template <typename T>
+ explicit Integral(IntegralKind Kind, T V) : V(V), Kind(Kind) {}
public:
using AsUnsigned = Integral<Bits, false>;
@@ -87,7 +92,9 @@ template <unsigned Bits, bool Signed> class Integral final {
/// Constructs an integral from another integral.
template <unsigned SrcBits, bool SrcSign>
- explicit Integral(Integral<SrcBits, SrcSign> V) : V(V.V) {}
+ explicit Integral(Integral<SrcBits, SrcSign> V) : V(V.V), Kind(V.Kind) {}
+
+ IntegralKind getKind() const { return Kind; }
/// Construct an integral from a value based on signedness.
explicit Integral(const APSInt &V)
@@ -115,7 +122,7 @@ template <unsigned Bits, bool Signed> class Integral final {
template <unsigned DstBits, bool DstSign>
explicit operator Integral<DstBits, DstSign>() const {
- return Integral<DstBits, DstSign>(V);
+ return Integral<DstBits, DstSign>(Kind, V);
}
template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>
@@ -137,7 +144,35 @@ template <unsigned Bits, bool Signed> class Integral final
{
return APInt(Bits, static_cast<uint64_t>(V), Signed)
.zextOrTrunc(BitWidth);
}
- APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }
+ APValue toAPValue(const ASTContext &, const Program &P) const {
+ switch (Kind) {
+ case IntegralKind::Address: {
+ const ValueDecl *VD =
+ reinterpret_cast<const ValueDecl *>(P.getNativePointer(V));
+ return APValue(VD, CharUnits::Zero(), APValue::NoLValuePath{});
+ }
+ case IntegralKind::LabelAddress: {
+ const Expr *VD = reinterpret_cast<const Expr *>(P.getNativePointer(V));
+ return APValue(VD, CharUnits::Zero(), APValue::NoLValuePath{});
+ }
+ case IntegralKind::BlockAddress: {
+ const Block *B = reinterpret_cast<const Block *>(P.getNativePointer(V));
+ 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: {
+ AddrLabelDiff ALD = P.getLabelDiff(V);
+ return APValue(ALD.LHS, ALD.RHS);
+ }
+ case IntegralKind::Number:
+ return APValue(toAPSInt());
+ }
+ llvm_unreachable("Unhandled IntegralKind");
+ }
Integral<Bits, false> toUnsigned() const {
return Integral<Bits, false>(*this);
@@ -172,7 +207,7 @@ template <unsigned Bits, bool Signed> class Integral final {
return Integral(V);
}
- std::string toDiagnosticString(const ASTContext &Ctx) const {
+ std::string toDiagnosticString(const ASTContext &Ctx, const Program &) const
{
std::string NameStr;
llvm::raw_string_ostream OS(NameStr);
OS << V;
@@ -198,14 +233,25 @@ template <unsigned Bits, bool Signed> class Integral
final {
return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0));
}
- void print(llvm::raw_ostream &OS) const { OS << V; }
+ void print(llvm::raw_ostream &OS) const {
+ OS << V;
+ if (Kind == IntegralKind::Address)
+ OS << " (Address)";
+ else if (Kind == IntegralKind::BlockAddress)
+ OS << " (BlockAddress)";
+ else if (Kind == IntegralKind::LabelAddress)
+ OS << " (LabelAddress)";
+ else if (Kind == IntegralKind::AddrLabelDiff)
+ OS << " (LabelAddrDiff)";
+ }
static Integral min(unsigned NumBits) { return Integral(Min); }
static Integral max(unsigned NumBits) { return Integral(Max); }
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,8 +259,13 @@ template <unsigned Bits, bool Signed> class Integral final
{
}
template <unsigned SrcBits, bool SrcSign>
- static Integral from(Integral<SrcBits, SrcSign> Value) {
- return Integral(Value.V);
+ static std::enable_if_t<SrcBits != 0, Integral>
+ from(Integral<SrcBits, SrcSign> Value) {
+ return Integral(Value.Kind, Value.V);
+ }
+
+ template <typename T> static Integral from(IntegralKind Kind, T Value) {
+ return Integral(Kind, Value);
}
static bool increment(Integral A, Integral *R) {
diff --git a/clang/lib/AST/ByteCode/IntegralAP.h
b/clang/lib/AST/ByteCode/IntegralAP.h
index b11e6eea28e3f..b14951559fd2a 100644
--- a/clang/lib/AST/ByteCode/IntegralAP.h
+++ b/clang/lib/AST/ByteCode/IntegralAP.h
@@ -22,6 +22,7 @@
#include <cstdint>
#include "Primitives.h"
+#include "Program.h"
namespace clang {
namespace interp {
@@ -150,7 +151,9 @@ template <bool Signed> class IntegralAP final {
else
return APSInt(getValue().zext(Bits), !Signed);
}
- APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }
+ APValue toAPValue(const ASTContext &, const Program &) const {
+ return APValue(toAPSInt());
+ }
bool isZero() const { return getValue().isZero(); }
bool isPositive() const {
@@ -179,12 +182,13 @@ template <bool Signed> class IntegralAP final {
unsigned countLeadingZeros() const { return getValue().countl_zero(); }
void print(llvm::raw_ostream &OS) const { getValue().print(OS, Signed); }
- std::string toDiagnosticString(const ASTContext &Ctx) const {
+ std::string toDiagnosticString(const ASTContext &Ctx, const Program &) const
{
std::string NameStr;
llvm::raw_string_ostream OS(NameStr);
print(OS);
return NameStr;
}
+ static IntegralKind getKind() { return IntegralKind::Number; }
IntegralAP truncate(unsigned BitWidth) const {
if constexpr (Signed)
diff --git a/clang/lib/AST/ByteCode/Interp.cpp
b/clang/lib/AST/ByteCode/Interp.cpp
index c3210d7119b40..92b70eb6895fa 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1149,7 +1149,7 @@ bool CheckDeleteSource(InterpState &S, CodePtr OpPC,
const Expr *Source,
// Whatever this is, we didn't heap allocate it.
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_delete_not_heap_alloc)
- << Ptr.toDiagnosticString(S.getASTContext());
+ << Ptr.toDiagnosticString(S.getASTContext(), S.P);
if (Ptr.isTemporary())
S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
@@ -1321,7 +1321,8 @@ bool Free(InterpState &S, CodePtr OpPC, bool
DeleteIsArrayForm,
(Ptr.isArrayElement() && Ptr.getIndex() != 0)) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_delete_subobject)
- << Ptr.toDiagnosticString(S.getASTContext()) << Ptr.isOnePastEnd();
+ << Ptr.toDiagnosticString(S.getASTContext(), S.P)
+ << Ptr.isOnePastEnd();
return false;
}
@@ -1445,7 +1446,7 @@ static bool getField(InterpState &S, CodePtr OpPC, const
Pointer &Ptr,
// `typeid(int).name`, but we currently diagnose `&typeid(int)`.
S.FFDiag(S.Current->getSource(OpPC),
diag::note_constexpr_access_unreadable_object)
- << AK_Read << Ptr.toDiagnosticString(S.getASTContext());
+ << AK_Read << Ptr.toDiagnosticString(S.getASTContext(), S.P);
return false;
}
@@ -1677,7 +1678,7 @@ static bool GetDynamicDecl(InterpState &S, CodePtr OpPC,
Pointer TypePtr,
if (const VarDecl *VD = TypePtr.getDeclDesc()->asVarDecl();
VD && !VD->isConstexpr()) {
const Expr *E = S.Current->getExpr(OpPC);
- APValue V = TypePtr.toAPValue(S.getASTContext());
+ APValue V = TypePtr.toAPValue(S.getASTContext(), S.P);
QualType TT = S.getASTContext().getLValueReferenceType(DynamicType);
S.FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type)
<< AccessKinds::AK_MemberCall << V.getAsString(S.getASTContext(),
TT);
@@ -2064,10 +2065,10 @@ bool handleFixedPointOverflow(InterpState &S, CodePtr
OpPC,
if (S.checkingForUndefinedBehavior()) {
S.getASTContext().getDiagnostics().Report(
E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
- << FP.toDiagnosticString(S.getASTContext()) << E->getType();
+ << FP.toDiagnosticString(S.getASTContext(), S.P) << E->getType();
}
S.CCEDiag(E, diag::note_constexpr_overflow)
- << FP.toDiagnosticString(S.getASTContext()) << E->getType();
+ << FP.toDiagnosticString(S.getASTContext(), S.P) << E->getType();
return S.noteUndefinedBehavior();
}
@@ -2085,12 +2086,12 @@ 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 (Ptr.isDummy() && !Ptr.pointsToLabel())
return false;
- if (Ptr.isFunctionPointer())
+ if (Ptr.isIntegralPointer())
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)
@@ -2099,6 +2100,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>();
@@ -2184,13 +2190,19 @@ bool DiagTypeid(InterpState &S, CodePtr OpPC) {
bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS,
const Pointer &RHS) {
+ if (!LHS.pointsToStringLiteral() || !RHS.pointsToStringLiteral())
+ return false;
+
unsigned LHSOffset = LHS.isOnePastEnd() ? LHS.getNumElems() : LHS.getIndex();
unsigned RHSOffset = RHS.isOnePastEnd() ? RHS.getNumElems() : RHS.getIndex();
- unsigned LHSLength = (LHS.getNumElems() - 1) * LHS.elemSize();
- unsigned RHSLength = (RHS.getNumElems() - 1) * RHS.elemSize();
+ const auto *LHSLit = cast<StringLiteral>(LHS.getDeclDesc()->asExpr());
+ const auto *RHSLit = cast<StringLiteral>(RHS.getDeclDesc()->asExpr());
+
+ StringRef LHSStr(LHSLit->getBytes());
+ unsigned LHSLength = LHSStr.size();
+ StringRef RHSStr(RHSLit->getBytes());
+ unsigned RHSLength = RHSStr.size();
- StringRef LHSStr((const char *)LHS.atIndex(0).getRawAddress(), LHSLength);
- StringRef RHSStr((const char *)RHS.atIndex(0).getRawAddress(), RHSLength);
int32_t IndexDiff = RHSOffset - LHSOffset;
if (IndexDiff < 0) {
if (static_cast<int32_t>(LHSLength) < -IndexDiff)
@@ -2206,11 +2218,11 @@ bool arePotentiallyOverlappingStringLiterals(const
Pointer &LHS,
StringRef Shorter;
StringRef Longer;
if (LHSLength < RHSLength) {
- ShorterCharWidth = LHS.elemSize();
+ ShorterCharWidth = LHS.getFieldDesc()->getElemDataSize();
Shorter = LHSStr;
Longer = RHSStr;
} else {
- ShorterCharWidth = RHS.elemSize();
+ ShorterCharWidth = RHS.getFieldDesc()->getElemDataSize();
Shorter = RHSStr;
Longer = LHSStr;
}
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index d8b8b209fa927..95caf0131a5c8 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -332,6 +332,33 @@ bool Sub(InterpState &S, CodePtr OpPC) {
const T &LHS = S.Stk.pop<T>();
const unsigned Bits = RHS.bitWidth() + 1;
+ // Handle (int)&&a - (int)&&b.
+ // Both operands should be integrals that point to labels and the result is a
+ // AddrLabelDiff integral.
+ if (LHS.getKind() == IntegralKind::LabelAddress ||
+ RHS.getKind() == IntegralKind::LabelAddress) {
+ const auto *A = reinterpret_cast<const Expr *>(
+ S.P.getNativePointer(static_cast<uint32_t>(LHS)));
+ const auto *B = reinterpret_cast<const Expr *>(
+ S.P.getNativePointer(static_cast<uint32_t>(RHS)));
+ if (isa<AddrLabelExpr>(A) && isa<AddrLabelExpr>(B)) {
+ const auto *LHSAddrExpr = cast<AddrLabelExpr>(A);
+ const auto *RHSAddrExpr = cast<AddrLabelExpr>(B);
+
+ if (LHSAddrExpr->getLabel()->getDeclContext() !=
+ RHSAddrExpr->getLabel()->getDeclContext())
+ return Invalid(S, OpPC);
+
+ unsigned Index = S.P.getOrCreateAddrLabelDiff(LHSAddrExpr, RHSAddrExpr);
+ if constexpr (std::is_same_v<T, Boolean>) {
+ } else if constexpr (std::is_same_v<T, FixedPoint>) {
+ } else {
+ S.Stk.push<T>(T::from(IntegralKind::AddrLabelDiff, Index));
+ }
+ return true;
+ }
+ }
+
return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
}
@@ -1005,16 +1032,16 @@ inline bool CmpHelper<Pointer>(InterpState &S, CodePtr
OpPC, CompareFn Fn) {
LHS.isTypeidPointer() || RHS.isTypeidPointer()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
- << LHS.toDiagnosticString(S.getASTContext())
- << RHS.toDiagnosticString(S.getASTContext());
+ << LHS.toDiagnosticString(S.getASTContext(), S.P)
+ << RHS.toDiagnosticString(S.getASTContext(), S.P);
return false;
}
if (!Pointer::hasSameBase(LHS, RHS)) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
- << LHS.toDiagnosticString(S.getASTContext())
- << RHS.toDiagnosticString(S.getASTContext());
+ << LHS.toDiagnosticString(S.getASTContext(), S.P)
+ << RHS.toDiagnosticString(S.getASTContext(), S.P);
return false;
}
@@ -1066,7 +1093,7 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr
OpPC, CompareFn Fn) {
if (P.isWeak()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
- << P.toDiagnosticString(S.getASTContext());
+ << P.toDiagnosticString(S.getASTContext(), S.P);
return false;
}
}
@@ -1088,8 +1115,8 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr
OpPC, CompareFn Fn) {
if (arePotentiallyOverlappingStringLiterals(LHS, RHS)) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_literal_comparison)
- << LHS.toDiagnosticString(S.getASTContext())
- << RHS.toDiagnosticString(S.getASTContext());
+ << LHS.toDiagnosticString(S.getASTContext(), S.P)
+ << RHS.toDiagnosticString(S.getASTContext(), S.P);
return false;
}
}
@@ -1106,14 +1133,14 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S,
CodePtr OpPC, CompareFn Fn) {
RHS.getOffset() == 0) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
- << LHS.toDiagnosticString(S.getASTContext());
+ << LHS.toDiagnosticString(S.getASTContext(), S.P);
return false;
}
if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
LHS.getOffset() == 0) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
- << RHS.toDiagnosticString(S.getASTContext());
+ << RHS.toDiagnosticString(S.getASTContext(), S.P);
return false;
}
@@ -1133,14 +1160,14 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S,
CodePtr OpPC, CompareFn Fn) {
CE && IsOpaqueConstantCall(CE)) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_opaque_call_comparison)
- << P.toDiagnosticString(S.getASTContext());
+ << P.toDiagnosticString(S.getASTContext(), S.P);
return false;
}
} else if (BothNonNull && P.isIntegralPointer()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_constant_comparison)
- << LHS.toDiagnosticString(S.getASTContext())
- << RHS.toDiagnosticString(S.getASTContext());
+ << LHS.toDiagnosticString(S.getASTContext(), S.P)
+ << RHS.toDiagnosticString(S.getASTContext(), S.P);
return false;
}
}
@@ -1148,8 +1175,8 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr
OpPC, CompareFn Fn) {
if (LHS.isUnknownSizeArray() && RHS.isUnknownSizeArray()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_zero_sized)
- << LHS.toDiagnosticString(S.getASTContext())
- << RHS.toDiagnosticString(S.getASTContext());
+ << LHS.toDiagnosticString(S.getASTContext(), S.P)
+ << RHS.toDiagnosticString(S.getASTContext(), S.P);
return false;
}
@@ -1217,8 +1244,8 @@ bool CMP3(InterpState &S, CodePtr OpPC, const
ComparisonCategoryInfo *CmpInfo) {
if (CmpResult == ComparisonCategoryResult::Unordered) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
- << LHS.toDiagnosticString(S.getASTContext())
- << RHS.toDiagnosticString(S.getASTContext());
+ << LHS.toDiagnosticString(S.getASTContext(), S.P)
+ << RHS.toDiagnosticString(S.getASTContext(), S.P);
return false;
}
}
@@ -1311,7 +1338,28 @@ bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
S.Stk.push<T>(Result);
return true;
}
- S.Stk.push<T>(Arg);
+
+ if constexpr (std::is_same_v<T, uint8_t>) {
+ S.Stk.push<Integral<8, false>>(Integral<8, false>::from(Arg));
+ } else if constexpr (std::is_same_v<T, int8_t>) {
+ S.Stk.push<Integral<8, true>>(Integral<8, true>::from(Arg));
+ } else if constexpr (std::is_same_v<T, uint16_t>) {
+ S.Stk.push<Integral<16, false>>(Integral<16, false>::from(Arg));
+ } else if constexpr (std::is_same_v<T, int16_t>) {
+ S.Stk.push<Integral<16, true>>(Integral<16, true>::from(Arg));
+ } else if constexpr (std::is_same_v<T, uint32_t>) {
+ S.Stk.push<Integral<32, false>>(Integral<32, false>::from(Arg));
+ } else if constexpr (std::is_same_v<T, int32_t>) {
+ S.Stk.push<Integral<32, true>>(Integral<32, true>::from(Arg));
+ } else if constexpr (std::is_same_v<T, uint64_t>) {
+ S.Stk.push<Integral<64, false>>(Integral<64, false>::from(Arg));
+ } else if constexpr (std::is_same_v<T, int64_t>) {
+ S.Stk.push<Integral<64, true>>(Integral<64, true>::from(Arg));
+ } else {
+ // Bool.
+ S.Stk.push<T>(Arg);
+ }
+
return true;
}
@@ -2392,11 +2440,28 @@ inline bool SubPtr(InterpState &S, CodePtr OpPC, bool
ElemSizeIsZero) {
const Pointer &LHS = S.Stk.pop<Pointer>().expand();
const Pointer &RHS = S.Stk.pop<Pointer>().expand();
+ if (LHS.pointsToLabel() || RHS.pointsToLabel()) {
+ const auto *LHSAddrExpr =
+ dyn_cast_if_present<AddrLabelExpr>(LHS.getDeclDesc()->asExpr());
+ const auto *RHSAddrExpr =
+ dyn_cast_if_present<AddrLabelExpr>(RHS.getDeclDesc()->asExpr());
+ if (!LHSAddrExpr || !RHSAddrExpr)
+ return false;
+
+ if (LHSAddrExpr->getLabel()->getDeclContext() !=
+ RHSAddrExpr->getLabel()->getDeclContext())
+ return Invalid(S, OpPC);
+
+ unsigned Index = S.P.getOrCreateAddrLabelDiff(LHSAddrExpr, RHSAddrExpr);
+ S.Stk.push<T>(T::from(IntegralKind::AddrLabelDiff, Index));
+ return true;
+ }
+
if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
S.FFDiag(S.Current->getSource(OpPC),
diag::note_constexpr_pointer_arith_unspecified)
- << LHS.toDiagnosticString(S.getASTContext())
- << RHS.toDiagnosticString(S.getASTContext());
+ << LHS.toDiagnosticString(S.getASTContext(), S.P)
+ << RHS.toDiagnosticString(S.getASTContext(), S.P);
return false;
}
@@ -2459,7 +2524,7 @@ inline bool Destroy(InterpState &S, CodePtr OpPC,
uint32_t I) {
} else {
S.FFDiag(Ptr.getDeclDesc()->getLocation(),
diag::note_constexpr_destroy_out_of_lifetime)
- << Ptr.toDiagnosticString(S.getASTContext());
+ << Ptr.toDiagnosticString(S.getASTContext(), S.P);
}
return false;
}
@@ -2493,7 +2558,16 @@ inline bool GetLocalEnabled(InterpState &S, CodePtr
OpPC, uint32_t I) {
template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC)
{
using T = typename PrimConv<TIn>::T;
using U = typename PrimConv<TOut>::T;
- S.Stk.push<U>(U::from(S.Stk.pop<T>()));
+
+ auto In = S.Stk.pop<T>();
+
+ if (In.getKind() != IntegralKind::Number &&
+ In.getKind() != IntegralKind::AddrLabelDiff) {
+ if (!CheckIntegralAddressCast(S, OpPC, In.bitWidth()))
+ return Invalid(S, OpPC);
+ }
+
+ S.Stk.push<U>(U::from(In));
return true;
}
@@ -2639,6 +2713,7 @@ static inline bool CastFloatingIntegralAPS(InterpState
&S, CodePtr OpPC,
bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,
const Pointer &Ptr, unsigned BitWidth);
+bool CheckIntegralAddressCast(InterpState &S, CodePtr OpPC, unsigned BitWidth);
bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth);
bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth);
@@ -2649,7 +2724,33 @@ bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
if (!CheckPointerToIntegralCast(S, OpPC, Ptr, T::bitWidth()))
return Invalid(S, OpPC);
- S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
+ if constexpr (std::is_same_v<T, Boolean>) {
+
+ S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
+ } else {
+ if (Ptr.isBlockPointer()) {
+ uintptr_t IntVal;
+ IntegralKind Kind = IntegralKind::Address;
+ if (Ptr.isDummy()) {
+ if (const Expr *E = Ptr.getDeclDesc()->asExpr()) {
+ IntVal = S.P.getOrCreateNativePointer(E);
+ if (isa<AddrLabelExpr>(E))
+ Kind = IntegralKind::LabelAddress;
+ } else
+ IntVal = S.P.getOrCreateNativePointer(Ptr.getDeclDesc()->asDecl());
+ } else {
+ Kind = IntegralKind::BlockAddress;
+ IntVal = S.P.getOrCreateNativePointer(Ptr.block());
+ }
+ S.Stk.push<T>(T::from(Kind, IntVal));
+ } else if (Ptr.isFunctionPointer()) {
+ uintptr_t IntVal = S.P.getOrCreateNativePointer(
+ Ptr.asFunctionPointer().getFunction()->getDecl());
+ S.Stk.push<T>(T::from(IntegralKind::Address, IntVal));
+ } else {
+ S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
+ }
+ }
return true;
}
@@ -3436,7 +3537,8 @@ template <PrimType Name, class T = typename
PrimConv<Name>::T>
inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
llvm::SmallVector<int64_t> ArrayIndices;
for (size_t I = 0; I != E->getNumExpressions(); ++I)
- ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
+ ArrayIndices.emplace_back(
+ static_cast<int64_t>(S.Stk.pop<Integral<64, true>>()));
int64_t Result;
if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
@@ -3551,7 +3653,7 @@ inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType
T, const Expr *Source,
if (NumElements.isNegative()) {
if (!IsNoThrow) {
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_negative)
- << NumElements.toDiagnosticString(S.getASTContext());
+ << NumElements.toDiagnosticString(S.getASTContext(), S.P);
return false;
}
S.Stk.push<Pointer>(0, nullptr);
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 659b6985d3157..37aff11e9208d 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -314,11 +314,12 @@ static bool interp__builtin_strlen(InterpState &S,
CodePtr OpPC,
return false;
assert(StrPtr.getFieldDesc()->isPrimitiveArray());
- unsigned ElemSize = StrPtr.getFieldDesc()->getElemSize();
+ PrimType ElemT = StrPtr.getFieldDesc()->getPrimType();
if (ID == Builtin::BI__builtin_wcslen || ID == Builtin::BIwcslen) {
- [[maybe_unused]] const ASTContext &AC = S.getASTContext();
- assert(ElemSize == AC.getTypeSizeInChars(AC.getWCharType()).getQuantity());
+ [[maybe_unused]] const ASTContext &ASTCtx = S.getASTContext();
+ assert(StrPtr.getFieldDesc()->getElemDataSize() ==
+ ASTCtx.getTypeSizeInChars(ASTCtx.getWCharType()).getQuantity());
}
size_t Len = 0;
@@ -329,19 +330,8 @@ static bool interp__builtin_strlen(InterpState &S, CodePtr
OpPC,
return false;
uint32_t Val;
- switch (ElemSize) {
- case 1:
- Val = ElemPtr.deref<uint8_t>();
- break;
- case 2:
- Val = ElemPtr.deref<uint16_t>();
- break;
- case 4:
- Val = ElemPtr.deref<uint32_t>();
- break;
- default:
- llvm_unreachable("Unsupported char size");
- }
+ FIXED_SIZE_INT_TYPE_SWITCH(
+ ElemT, { Val = static_cast<uint32_t>(ElemPtr.deref<T>()); });
if (Val == 0)
break;
}
@@ -1225,7 +1215,7 @@ static bool interp__builtin_assume_aligned(InterpState
&S, CodePtr OpPC,
}
}
- APValue AV = Ptr.toAPValue(S.getASTContext());
+ APValue AV = Ptr.toAPValue(S.getASTContext(), S.P);
CharUnits AVOffset = AV.getLValueOffset();
if (ExtraOffset)
AVOffset -= CharUnits::fromQuantity(ExtraOffset->getZExtValue());
@@ -1301,11 +1291,11 @@
interp__builtin_ptrauth_string_discriminator(InterpState &S, CodePtr OpPC,
const auto &Ptr = S.Stk.pop<Pointer>();
assert(Ptr.getFieldDesc()->isPrimitiveArray());
- // This should be created for a StringLiteral, so should alway shold at least
+ // This should be created for a StringLiteral, so always holds at least
// one array element.
assert(Ptr.getFieldDesc()->getNumElems() >= 1);
- StringRef R(&Ptr.deref<char>(), Ptr.getFieldDesc()->getNumElems() - 1);
- uint64_t Result = getPointerAuthStableSipHash(R);
+ uint64_t Result = getPointerAuthStableSipHash(
+ cast<StringLiteral>(Ptr.getFieldDesc()->asExpr())->getString());
pushInteger(S, Result, Call->getType());
return true;
}
@@ -1489,7 +1479,7 @@ static bool interp__builtin_operator_delete(InterpState
&S, CodePtr OpPC,
if (!BlockToDelete->isDynamic()) {
S.FFDiag(Call, diag::note_constexpr_delete_not_heap_alloc)
- << Ptr.toDiagnosticString(S.getASTContext());
+ << Ptr.toDiagnosticString(S.getASTContext(), S.P);
if (const auto *D = Ptr.getFieldDesc()->asDecl())
S.Note(D->getLocation(), diag::note_declared_at);
}
@@ -1790,7 +1780,7 @@ static bool interp__builtin_memcpy(InterpState &S,
CodePtr OpPC,
Pointer DiagPtr = (SrcPtr.isZero() ? SrcPtr : DestPtr);
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_null)
<< /*IsMove=*/Move << /*IsWchar=*/WChar << !SrcPtr.isZero()
- << DiagPtr.toDiagnosticString(ASTCtx);
+ << DiagPtr.toDiagnosticString(ASTCtx, S.P);
return false;
}
@@ -1900,8 +1890,8 @@ static bool interp__builtin_memcpy(InterpState &S,
CodePtr OpPC,
while (DestP.isBaseClass())
DestP = DestP.getBase();
- unsigned SrcIndex = SrcP.expand().getIndex() * SrcP.elemSize();
- unsigned DstIndex = DestP.expand().getIndex() * DestP.elemSize();
+ unsigned SrcIndex = SrcP.expand().getIndex() * SrcElemSize;
+ unsigned DstIndex = DestP.expand().getIndex() * DestElemSize;
unsigned N = Size.getZExtValue();
if ((SrcIndex <= DstIndex && (SrcIndex + N) > DstIndex) ||
@@ -1970,6 +1960,7 @@ static bool interp__builtin_memcmp(InterpState &S,
CodePtr OpPC,
BitcastBuffer BufferA(
Bits(ASTCtx.getTypeSize(ElemTypeA) * PtrA.getNumElems()));
readPointerToBuffer(S.getContext(), PtrA, BufferA, false);
+
// FIXME: The swapping here is UNDOING something we do when reading the
// data into the buffer.
if (ASTCtx.getTargetInfo().isBigEndian())
@@ -1996,21 +1987,22 @@ static bool interp__builtin_memcmp(InterpState &S,
CodePtr OpPC,
for (size_t I = 0; I != CmpSize; I += ElemSize) {
if (IsWide) {
- INT_TYPE_SWITCH(*S.getContext().classify(ASTCtx.getWCharType()), {
- T A = *reinterpret_cast<T *>(BufferA.atByte(I));
- T B = *reinterpret_cast<T *>(BufferB.atByte(I));
- if (A < B) {
- pushInteger(S, -1, Call->getType());
- return true;
- }
- if (A > B) {
- pushInteger(S, 1, Call->getType());
- return true;
- }
- });
+ FIXED_SIZE_INT_TYPE_SWITCH(
+ *S.getContext().classify(ASTCtx.getWCharType()), {
+ T A = T::bitcastFromMemory(BufferA.atByte(I), T::bitWidth());
+ T B = T::bitcastFromMemory(BufferB.atByte(I), T::bitWidth());
+ if (A < B) {
+ pushInteger(S, -1, Call->getType());
+ return true;
+ }
+ if (A > B) {
+ pushInteger(S, 1, Call->getType());
+ return true;
+ }
+ });
} else {
- std::byte A = BufferA.deref<std::byte>(Bytes(I));
- std::byte B = BufferB.deref<std::byte>(Bytes(I));
+ auto A = BufferA.deref<std::byte>(Bytes(I));
+ auto B = BufferB.deref<std::byte>(Bytes(I));
if (A < B) {
pushInteger(S, -1, Call->getType());
diff --git a/clang/lib/AST/ByteCode/InterpFrame.cpp
b/clang/lib/AST/ByteCode/InterpFrame.cpp
index 3b883761ad001..02ef50b379bdc 100644
--- a/clang/lib/AST/ByteCode/InterpFrame.cpp
+++ b/clang/lib/AST/ByteCode/InterpFrame.cpp
@@ -114,18 +114,18 @@ void InterpFrame::destroy(unsigned Idx) {
template <typename T>
static void print(llvm::raw_ostream &OS, const T &V, ASTContext &ASTCtx,
- QualType Ty) {
+ QualType Ty, const Program &P) {
if constexpr (std::is_same_v<Pointer, T>) {
if (Ty->isPointerOrReferenceType())
- V.toAPValue(ASTCtx).printPretty(OS, ASTCtx, Ty);
+ V.toAPValue(ASTCtx, P).printPretty(OS, ASTCtx, Ty);
else {
- if (std::optional<APValue> RValue = V.toRValue(ASTCtx, Ty))
+ if (std::optional<APValue> RValue = V.toRValue(ASTCtx, Ty, P))
RValue->printPretty(OS, ASTCtx, Ty);
else
OS << "...";
}
} else {
- V.toAPValue(ASTCtx).printPretty(OS, ASTCtx, Ty);
+ V.toAPValue(ASTCtx, P).printPretty(OS, ASTCtx, Ty);
}
}
@@ -178,7 +178,8 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const {
} else if (const auto *M = dyn_cast<CXXMethodDecl>(F)) {
print(OS, getThis(), S.getASTContext(),
S.getASTContext().getLValueReferenceType(
- S.getASTContext().getCanonicalTagType(M->getParent())));
+ S.getASTContext().getCanonicalTagType(M->getParent())),
+ S.P);
OS << ".";
}
}
@@ -196,7 +197,8 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const {
PrimType PrimTy = S.Ctx.classify(Ty).value_or(PT_Ptr);
- TYPE_SWITCH(PrimTy, print(OS, stackRef<T>(Off), S.getASTContext(), Ty));
+ TYPE_SWITCH(PrimTy,
+ print(OS, stackRef<T>(Off), S.getASTContext(), Ty, S.P));
Off += align(primSize(PrimTy));
if (I + 1 != N)
OS << ", ";
diff --git a/clang/lib/AST/ByteCode/InterpHelpers.h
b/clang/lib/AST/ByteCode/InterpHelpers.h
index 6bf89d318378c..edc6f83dd59be 100644
--- a/clang/lib/AST/ByteCode/InterpHelpers.h
+++ b/clang/lib/AST/ByteCode/InterpHelpers.h
@@ -124,10 +124,10 @@ bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT
*NumElements,
if (NumElements->isSigned() && NumElements->isNegative()) {
S.FFDiag(Loc, diag::note_constexpr_new_negative)
- << NumElements->toDiagnosticString(S.getASTContext());
+ << NumElements->toDiagnosticString(S.getASTContext(), S.P);
} else {
S.FFDiag(Loc, diag::note_constexpr_new_too_large)
- << NumElements->toDiagnosticString(S.getASTContext());
+ << NumElements->toDiagnosticString(S.getASTContext(), S.P);
}
}
return false;
diff --git a/clang/lib/AST/ByteCode/InterpStack.h
b/clang/lib/AST/ByteCode/InterpStack.h
index c647dfa6d85ea..b50e6b78d7bf6 100644
--- a/clang/lib/AST/ByteCode/InterpStack.h
+++ b/clang/lib/AST/ByteCode/InterpStack.h
@@ -173,29 +173,21 @@ class InterpStack final {
return PT_Ptr;
else if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, Boolean>)
return PT_Bool;
- else if constexpr (std::is_same_v<T, int8_t> ||
- std::is_same_v<T, Integral<8, true>>)
+ else if constexpr (std::is_same_v<T, Integral<8, true>>)
return PT_Sint8;
- else if constexpr (std::is_same_v<T, uint8_t> ||
- std::is_same_v<T, Integral<8, false>>)
+ else if constexpr (std::is_same_v<T, Integral<8, false>>)
return PT_Uint8;
- else if constexpr (std::is_same_v<T, int16_t> ||
- std::is_same_v<T, Integral<16, true>>)
+ else if constexpr (std::is_same_v<T, Integral<16, true>>)
return PT_Sint16;
- else if constexpr (std::is_same_v<T, uint16_t> ||
- std::is_same_v<T, Integral<16, false>>)
+ else if constexpr (std::is_same_v<T, Integral<16, false>>)
return PT_Uint16;
- else if constexpr (std::is_same_v<T, int32_t> ||
- std::is_same_v<T, Integral<32, true>>)
+ else if constexpr (std::is_same_v<T, Integral<32, true>>)
return PT_Sint32;
- else if constexpr (std::is_same_v<T, uint32_t> ||
- std::is_same_v<T, Integral<32, false>>)
+ else if constexpr (std::is_same_v<T, Integral<32, false>>)
return PT_Uint32;
- else if constexpr (std::is_same_v<T, int64_t> ||
- std::is_same_v<T, Integral<64, true>>)
+ else if constexpr (std::is_same_v<T, Integral<64, true>>)
return PT_Sint64;
- else if constexpr (std::is_same_v<T, uint64_t> ||
- std::is_same_v<T, Integral<64, false>>)
+ else if constexpr (std::is_same_v<T, Integral<64, false>>)
return PT_Uint64;
else if constexpr (std::is_same_v<T, Floating>)
return PT_Float;
diff --git a/clang/lib/AST/ByteCode/MemberPointer.cpp
b/clang/lib/AST/ByteCode/MemberPointer.cpp
index 8b1b0187818e9..812bb92d2fb3d 100644
--- a/clang/lib/AST/ByteCode/MemberPointer.cpp
+++ b/clang/lib/AST/ByteCode/MemberPointer.cpp
@@ -80,13 +80,14 @@ FunctionPointer MemberPointer::toFunctionPointer(const
Context &Ctx) const {
return
FunctionPointer(Ctx.getProgram().getFunction(cast<FunctionDecl>(Dcl)));
}
-APValue MemberPointer::toAPValue(const ASTContext &ASTCtx) const {
+APValue MemberPointer::toAPValue(const ASTContext &ASTCtx,
+ const Program &P) const {
if (isZero())
return APValue(static_cast<ValueDecl *>(nullptr),
/*IsDerivedMember=*/false,
/*Path=*/{});
if (hasBase())
- return Base.toAPValue(ASTCtx);
+ return Base.toAPValue(ASTCtx, P);
return APValue(getDecl(), /*IsDerivedMember=*/false,
/*Path=*/{});
diff --git a/clang/lib/AST/ByteCode/MemberPointer.h
b/clang/lib/AST/ByteCode/MemberPointer.h
index 8dd75cad092c0..a51e00e3c064c 100644
--- a/clang/lib/AST/ByteCode/MemberPointer.h
+++ b/clang/lib/AST/ByteCode/MemberPointer.h
@@ -86,7 +86,7 @@ class MemberPointer final {
return MemberPointer(Instance, this->Dcl, this->PtrOffset);
}
- APValue toAPValue(const ASTContext &) const;
+ APValue toAPValue(const ASTContext &, const Program &) const;
bool isZero() const { return Base.isZero() && !Dcl; }
bool hasBase() const { return !Base.isZero(); }
@@ -101,8 +101,9 @@ class MemberPointer final {
<< ")";
}
- std::string toDiagnosticString(const ASTContext &Ctx) const {
- return toAPValue(Ctx).getAsString(Ctx, Dcl->getType());
+ std::string toDiagnosticString(const ASTContext &Ctx,
+ const Program &P) const {
+ return toAPValue(Ctx, P).getAsString(Ctx, Dcl->getType());
}
ComparisonCategoryResult compare(const MemberPointer &RHS) const {
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp
b/clang/lib/AST/ByteCode/Pointer.cpp
index 25719bd6f0f91..f4292202b9265 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -169,7 +169,7 @@ Pointer &Pointer::operator=(Pointer &&P) {
return *this;
}
-APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
+APValue Pointer::toAPValue(const ASTContext &ASTCtx, const Program &) const {
llvm::SmallVector<APValue::LValuePathEntry, 5> Path;
if (isZero())
@@ -425,7 +425,8 @@ size_t Pointer::computeOffsetForComparison() const {
return Result;
}
-std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
+std::string Pointer::toDiagnosticString(const ASTContext &Ctx,
+ const Program &P) const {
if (isZero())
return "nullptr";
@@ -435,7 +436,7 @@ std::string Pointer::toDiagnosticString(const ASTContext
&Ctx) const {
if (isFunctionPointer())
return asFunctionPointer().toDiagnosticString(Ctx);
- return toAPValue(Ctx).getAsString(Ctx, getType());
+ return toAPValue(Ctx, P).getAsString(Ctx, getType());
}
bool Pointer::isInitialized() const {
@@ -683,6 +684,15 @@ bool Pointer::pointsToStringLiteral() const {
return isa_and_nonnull<StringLiteral>(E);
}
+bool Pointer::pointsToLabel() const {
+ if (isZero() || !isBlockPointer())
+ return false;
+
+ if (const Expr *E = BS.Pointee->getDescriptor()->asExpr())
+ return isa<AddrLabelExpr>(E);
+ return false;
+}
+
std::optional<std::pair<Pointer, Pointer>>
Pointer::computeSplitPoint(const Pointer &A, const Pointer &B) {
if (!A.isBlockPointer() || !B.isBlockPointer())
@@ -726,13 +736,14 @@ Pointer::computeSplitPoint(const Pointer &A, const
Pointer &B) {
}
std::optional<APValue> Pointer::toRValue(const Context &Ctx,
- QualType ResultType) const {
+ QualType ResultType,
+ const Program &P) const {
const ASTContext &ASTCtx = Ctx.getASTContext();
assert(!ResultType.isNull());
// Method to recursively traverse composites.
std::function<bool(QualType, const Pointer &, APValue &)> Composite;
- Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, const Pointer &Ptr,
- APValue &R) {
+ Composite = [&Composite, &Ctx, &ASTCtx, &P](QualType Ty, const Pointer &Ptr,
+ APValue &R) {
if (const auto *AT = Ty->getAs<AtomicType>())
Ty = AT->getValueType();
@@ -743,7 +754,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
// Primitive values.
if (OptPrimType T = Ctx.classify(Ty)) {
- TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx));
+ TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx, P));
return true;
}
@@ -760,7 +771,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
QualType FieldTy = F.Decl->getType();
if (FP.isActive()) {
if (OptPrimType T = Ctx.classify(FieldTy)) {
- TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
+ TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx, P));
} else {
Ok &= Composite(FieldTy, FP, Value);
}
@@ -783,7 +794,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
APValue &Value = R.getStructField(I);
if (OptPrimType T = Ctx.classify(FieldTy)) {
- TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
+ TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx, P));
} else {
Ok &= Composite(FieldTy, FP, Value);
}
@@ -822,7 +833,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
for (unsigned I = 0; I != NumElems; ++I) {
APValue &Slot = R.getArrayInitializedElt(I);
if (ElemT) {
- TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx));
+ TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx, P));
} else {
Ok &= Composite(ElemTy, Ptr.atIndex(I).narrow(), Slot);
}
@@ -864,7 +875,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
Values.reserve(VT->getNumElements());
for (unsigned I = 0; I != VT->getNumElements(); ++I) {
TYPE_SWITCH(ElemT,
- { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });
+ { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx, P));
});
}
assert(Values.size() == VT->getNumElements());
@@ -881,11 +892,11 @@ std::optional<APValue> Pointer::toRValue(const Context
&Ctx,
// We can return these as rvalues, but we can't deref() them.
if (isZero() || isIntegralPointer())
- return toAPValue(ASTCtx);
+ return toAPValue(ASTCtx, P);
// Just load primitive types.
if (OptPrimType T = Ctx.classify(ResultType)) {
- TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx));
+ TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx, P));
}
// Return the composite type.
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index 57c8e45609027..762051d2ec1e0 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -135,10 +135,10 @@ class Pointer {
bool operator!=(const Pointer &P) const { return !(P == *this); }
/// Converts the pointer to an APValue.
- APValue toAPValue(const ASTContext &ASTCtx) const;
+ APValue toAPValue(const ASTContext &ASTCtx, const Program &) const;
/// Converts the pointer to a string usable in diagnostics.
- std::string toDiagnosticString(const ASTContext &Ctx) const;
+ std::string toDiagnosticString(const ASTContext &Ctx, const Program &) const;
uint64_t getIntegerRepresentation() const {
if (isIntegralPointer())
@@ -149,8 +149,8 @@ class Pointer {
}
/// Converts the pointer to an APValue that is an rvalue.
- std::optional<APValue> toRValue(const Context &Ctx,
- QualType ResultType) const;
+ std::optional<APValue> toRValue(const Context &Ctx, QualType ResultType,
+ const Program &) const;
/// Offsets a pointer inside an array.
[[nodiscard]] Pointer atIndex(uint64_t Idx) const {
@@ -363,7 +363,7 @@ class Pointer {
if (isIntegralPointer()) {
if (!Int.Desc)
return 1;
- return Int.Desc->getElemSize();
+ return Int.Desc->getElemDataSize();
}
if (BS.Base == RootPtrMark)
@@ -776,6 +776,7 @@ class Pointer {
/// i.e. a non-MaterializeTemporaryExpr Expr.
bool pointsToLiteral() const;
bool pointsToStringLiteral() const;
+ bool pointsToLabel() const;
/// Prints the pointer.
void print(llvm::raw_ostream &OS) const;
diff --git a/clang/lib/AST/ByteCode/PrimType.h
b/clang/lib/AST/ByteCode/PrimType.h
index f0454b484ff98..9a83cd036b180 100644
--- a/clang/lib/AST/ByteCode/PrimType.h
+++ b/clang/lib/AST/ByteCode/PrimType.h
@@ -248,6 +248,22 @@ static inline bool aligned(const void *P) {
}
\
} while (0)
+#define FIXED_SIZE_INT_TYPE_SWITCH(Expr, B)
\
+ do {
\
+ switch (Expr) {
\
+ TYPE_SWITCH_CASE(PT_Sint8, B)
\
+ TYPE_SWITCH_CASE(PT_Uint8, B)
\
+ TYPE_SWITCH_CASE(PT_Sint16, B)
\
+ TYPE_SWITCH_CASE(PT_Uint16, B)
\
+ TYPE_SWITCH_CASE(PT_Sint32, B)
\
+ TYPE_SWITCH_CASE(PT_Uint32, B)
\
+ TYPE_SWITCH_CASE(PT_Sint64, B)
\
+ TYPE_SWITCH_CASE(PT_Uint64, B)
\
+ default:
\
+ llvm_unreachable("Not an integer value");
\
+ }
\
+ } while (0)
+
#define INT_TYPE_SWITCH_NO_BOOL(Expr, B)
\
do {
\
switch (Expr) {
\
diff --git a/clang/lib/AST/ByteCode/Primitives.h
b/clang/lib/AST/ByteCode/Primitives.h
index e935dbfd3691c..2784d5302c743 100644
--- a/clang/lib/AST/ByteCode/Primitives.h
+++ b/clang/lib/AST/ByteCode/Primitives.h
@@ -21,6 +21,14 @@
namespace clang {
namespace interp {
+enum class IntegralKind {
+ Number = 0,
+ Address,
+ BlockAddress,
+ LabelAddress,
+ AddrLabelDiff
+};
+
/// Helper to compare two comparable types.
template <typename T> ComparisonCategoryResult Compare(const T &X, const T &Y)
{
if (X < Y)
diff --git a/clang/lib/AST/ByteCode/Program.cpp
b/clang/lib/AST/ByteCode/Program.cpp
index d96934071cb60..1409fb2f15a7b 100644
--- a/clang/lib/AST/ByteCode/Program.cpp
+++ b/clang/lib/AST/ByteCode/Program.cpp
@@ -31,6 +31,20 @@ const void *Program::getNativePointer(unsigned Idx) const {
return NativePointers[Idx];
}
+unsigned Program::getOrCreateAddrLabelDiff(const AddrLabelExpr *LHS,
+ const AddrLabelExpr *RHS) {
+ auto [It, Inserted] = AddrLabelDiffIndices.try_emplace(
+ AddrLabelDiff{LHS, RHS}, AddrLabelDiffs.size());
+ if (Inserted)
+ AddrLabelDiffs.push_back(AddrLabelDiff{LHS, RHS});
+
+ return It->second;
+}
+
+AddrLabelDiff Program::getLabelDiff(unsigned Index) const {
+ return AddrLabelDiffs[Index];
+}
+
unsigned Program::createGlobalString(const StringLiteral *S, const Expr *Base)
{
const size_t CharWidth = S->getCharByteWidth();
const size_t BitWidth = CharWidth * Ctx.getCharBit();
@@ -49,7 +63,6 @@ unsigned Program::createGlobalString(const StringLiteral *S,
const Expr *Base) {
/*isConst=*/true,
/*isTemporary=*/false,
/*isMutable=*/false);
-
// Allocate storage for the string.
// The byte length does not include the null terminator.
unsigned GlobalIndex = Globals.size();
@@ -63,15 +76,10 @@ unsigned Program::createGlobalString(const StringLiteral
*S, const Expr *Base) {
Globals.push_back(G);
const Pointer Ptr(G->block());
- if (CharWidth == 1) {
- std::memcpy(&Ptr.elem<char>(0), S->getString().data(), StringLength);
- } else {
- // Construct the string in storage.
- for (unsigned I = 0; I <= StringLength; ++I) {
- uint32_t CodePoint = I == StringLength ? 0 : S->getCodeUnit(I);
- INT_TYPE_SWITCH_NO_BOOL(*CharType,
- Ptr.elem<T>(I) = T::from(CodePoint, BitWidth););
- }
+ for (unsigned I = 0; I <= StringLength; ++I) {
+ uint32_t CodePoint = I == StringLength ? 0 : S->getCodeUnit(I);
+ INT_TYPE_SWITCH_NO_BOOL(*CharType,
+ Ptr.elem<T>(I) = T::from(CodePoint, BitWidth););
}
Ptr.initializeAllElements();
diff --git a/clang/lib/AST/ByteCode/Program.h b/clang/lib/AST/ByteCode/Program.h
index c8795504391fa..e947aaf87e373 100644
--- a/clang/lib/AST/ByteCode/Program.h
+++ b/clang/lib/AST/ByteCode/Program.h
@@ -32,6 +32,14 @@ class VarDecl;
namespace interp {
class Context;
+struct AddrLabelDiff {
+ const AddrLabelExpr *LHS;
+ const AddrLabelExpr *RHS;
+ bool operator==(const AddrLabelDiff &Other) const {
+ return LHS == Other.LHS && RHS == Other.RHS;
+ }
+};
+
/// The program contains and links the bytecode for all functions.
class Program final {
public:
@@ -59,6 +67,9 @@ class Program final {
/// Returns the value of a marshalled native pointer.
const void *getNativePointer(unsigned Idx) const;
+ unsigned getOrCreateAddrLabelDiff(const AddrLabelExpr *LHS,
+ const AddrLabelExpr *RHS);
+ AddrLabelDiff getLabelDiff(unsigned Index) const;
/// Emits a string literal among global data.
unsigned createGlobalString(const StringLiteral *S,
@@ -181,6 +192,10 @@ class Program final {
/// Cached native pointer indices.
llvm::DenseMap<const void *, unsigned> NativePointerIndices;
+ std::vector<AddrLabelDiff> AddrLabelDiffs;
+ /// Cached native pointer indices.
+ llvm::DenseMap<AddrLabelDiff, unsigned> AddrLabelDiffIndices;
+
/// Custom allocator for global storage.
using PoolAllocTy = llvm::BumpPtrAllocator;
@@ -257,4 +272,28 @@ inline void *operator new[](size_t Bytes, const
clang::interp::Program &C,
return C.Allocate(Bytes, Alignment);
}
+namespace llvm {
+template <> struct DenseMapInfo<clang::interp::AddrLabelDiff> {
+ static clang::interp::AddrLabelDiff getEmptyKey() {
+ return clang::interp::AddrLabelDiff{};
+ }
+
+ static clang::interp::AddrLabelDiff getTombstoneKey() {
+ return clang::interp::AddrLabelDiff{
+ DenseMapInfo<const clang::AddrLabelExpr *>::getTombstoneKey(),
+ DenseMapInfo<const clang::AddrLabelExpr *>::getTombstoneKey()};
+ }
+
+ static unsigned getHashValue(const clang::interp::AddrLabelDiff &D) {
+ return DenseMapInfo<const clang::Expr *>::getHashValue(D.LHS) +
+ DenseMapInfo<const clang::Expr *>::getHashValue(D.RHS);
+ }
+
+ static bool isEqual(const clang::interp::AddrLabelDiff &LHS,
+ const clang::interp::AddrLabelDiff &RHS) {
+ return LHS == RHS;
+ }
+};
+} // namespace llvm
+
#endif
diff --git a/clang/test/AST/ByteCode/addr-label-diff.c
b/clang/test/AST/ByteCode/addr-label-diff.c
new file mode 100644
index 0000000000000..a87be4a75a784
--- /dev/null
+++ b/clang/test/AST/ByteCode/addr-label-diff.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple x86_64 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64 -emit-llvm %s -o -
-fexperimental-new-constant-interpreter | FileCheck %s
+
+typedef __typeof((int*) 0 - (int*) 0) intptr_t;
+
+// CHECK: @f1.l0 = internal global i64 ptrtoint (ptr @f1 to i64)
+void f1(void) { static intptr_t l0 = (intptr_t) f1; }
+
+
+// CHECK: @FoldableAddrLabelDiff.x = internal global i64 sub (i64 ptrtoint
(ptr blockaddress(@FoldableAddrLabelDiff, %a) to i64), i64 ptrtoint (ptr
blockaddress(@FoldableAddrLabelDiff, %b) to i64)), align 8
+void FoldableAddrLabelDiff() { static long x = (long)&&a-(long)&&b;
a:b:return;}
+
+// CHECK: @c.ar = internal global {{.*}} sub (i{{..}} ptrtoint (ptr
blockaddress(@c, %l2) to i{{..}}), i{{..}} ptrtoint (ptr blockaddress(@c, %l1)
to i{{..}}))
+int c(void) {
+ static int ar = &&l2 - &&l1;
+l1:
+ return 10;
+l2:
+ return 11;
+}
+
+
diff --git a/clang/test/AST/ByteCode/const-eval.c
b/clang/test/AST/ByteCode/const-eval.c
index d6cf600b378a8..15dd5933deea7 100644
--- a/clang/test/AST/ByteCode/const-eval.c
+++ b/clang/test/AST/ByteCode/const-eval.c
@@ -173,6 +173,9 @@ _Static_assert(A > B, "");
int * GH149500_p = &(*(int *)0x400);
static const void *GH149500_q = &(*(const struct sysrq_key_op *)0);
+
+void f0(void) { static intptr_t l0 = (unsigned)(intptr_t) f0;} // both-error
{{initializer element is not a compile-time constant}}
+
#else
#error :(
#endif
diff --git a/clang/test/CodeGen/const-label-addr.c
b/clang/test/CodeGen/const-label-addr.c
index 8030f96cb8aed..086971045d2ca 100644
--- a/clang/test/CodeGen/const-label-addr.c
+++ b/clang/test/CodeGen/const-label-addr.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -fexperimental-new-constant-interpreter
| FileCheck %s
// REQUIRES: asserts
// CHECK: @a.a = internal global ptr blockaddress(@a, %A)
diff --git a/clang/test/CodeGen/statements.c b/clang/test/CodeGen/statements.c
index 07ae075d6d807..bdfb5fc718755 100644
--- a/clang/test/CodeGen/statements.c
+++ b/clang/test/CodeGen/statements.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -Wno-error=return-type -Wno-error=int-conversion %s
-emit-llvm-only
+// RUN: %clang_cc1 -Wno-error=return-type -Wno-error=int-conversion %s
-emit-llvm-only -fexperimental-new-constant-interpreter
// REQUIRES: LP64
// Mismatched type between return and function result.
diff --git a/clang/test/CodeGen/staticinit.c b/clang/test/CodeGen/staticinit.c
index ec9b5b34d3ade..7ada59e220776 100644
--- a/clang/test/CodeGen/staticinit.c
+++ b/clang/test/CodeGen/staticinit.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm -o - %s
-fexperimental-new-constant-interpreter | FileCheck %s
struct AStruct {
int i;
diff --git a/clang/test/CodeGenCXX/2008-05-07-CrazyOffsetOf.cpp
b/clang/test/CodeGenCXX/2008-05-07-CrazyOffsetOf.cpp
index cb31a04c69fea..3be58ea1b7cae 100644
--- a/clang/test/CodeGenCXX/2008-05-07-CrazyOffsetOf.cpp
+++ b/clang/test/CodeGenCXX/2008-05-07-CrazyOffsetOf.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple=x86_64-unknown-linux -emit-llvm %s -o - | FileCheck
%s
+// RUN: %clang_cc1 -triple=x86_64-unknown-linux -emit-llvm %s -o -
-fexperimental-new-constant-interpreter | FileCheck %s
struct bork {
struct bork *next_local;
diff --git a/clang/test/CodeGenCXX/const-init-cxx11.cpp
b/clang/test/CodeGenCXX/const-init-cxx11.cpp
index 0795fb534af4b..125bf8c383a81 100644
--- a/clang/test/CodeGenCXX/const-init-cxx11.cpp
+++ b/clang/test/CodeGenCXX/const-init-cxx11.cpp
@@ -1,6 +1,9 @@
// RUN: %clang_cc1 -w -fmerge-all-constants -triple x86_64-elf-gnu -emit-llvm
-o - %s -std=c++11 | FileCheck %s
// RUN: %clang_cc1 -w -fmerge-all-constants -triple x86_64-elf-gnu -emit-llvm
-o - %s -std=c++20 | FileCheck -check-prefix=CHECK20 %s
+// RUN: %clang_cc1 -w -fmerge-all-constants -triple x86_64-elf-gnu -emit-llvm
-o - %s -std=c++11 -fexperimental-new-constant-interpreter | FileCheck %s
+// RUN: %clang_cc1 -w -fmerge-all-constants -triple x86_64-elf-gnu -emit-llvm
-o - %s -std=c++20 -fexperimental-new-constant-interpreter | FileCheck
-check-prefix=CHECK20 %s
+
// FIXME: The padding in all these objects should be zero-initialized.
namespace StructUnion {
struct A {
diff --git a/clang/test/Sema/compound-literal.c
b/clang/test/Sema/compound-literal.c
index 3ed53d670d38f..1026e5ece11b4 100644
--- a/clang/test/Sema/compound-literal.c
+++ b/clang/test/Sema/compound-literal.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -pedantic %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -pedantic %s
-fexperimental-new-constant-interpreter
// REQUIRES: LP64
struct foo { int a, b; };
diff --git a/clang/test/SemaCXX/constexpr-string.cpp
b/clang/test/SemaCXX/constexpr-string.cpp
index 93e234685d284..b49979bbc8ca0 100644
--- a/clang/test/SemaCXX/constexpr-string.cpp
+++ b/clang/test/SemaCXX/constexpr-string.cpp
@@ -8,6 +8,7 @@
// RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only
-verify -pedantic -Wno-vla-extension -fno-wchar -DNO_PREDEFINED_WCHAR_T
// RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only
-verify -pedantic -Wno-vla-extension -fno-signed-char
-fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only
-verify -pedantic -Wno-vla-extension -fno-wchar -DNO_PREDEFINED_WCHAR_T
-fexperimental-new-constant-interpreter
# 9 "/usr/include/string.h" 1 3 4 // expected-warning {{this style of line
directive is a GNU extension}}
extern "C" {
diff --git a/clang/unittests/AST/ByteCode/toAPValue.cpp
b/clang/unittests/AST/ByteCode/toAPValue.cpp
index 939d08601bb7d..9dbb47e3c3c3c 100644
--- a/clang/unittests/AST/ByteCode/toAPValue.cpp
+++ b/clang/unittests/AST/ByteCode/toAPValue.cpp
@@ -50,7 +50,7 @@ TEST(ToAPValue, Pointers) {
const Pointer &GP = getGlobalPtr("b");
const Pointer &P = GP.deref<Pointer>();
ASSERT_TRUE(P.isLive());
- APValue A = P.toAPValue(ASTCtx);
+ APValue A = P.toAPValue(ASTCtx, Prog);
ASSERT_TRUE(A.isLValue());
ASSERT_TRUE(A.hasLValuePath());
const auto &Path = A.getLValuePath();
@@ -65,7 +65,7 @@ TEST(ToAPValue, Pointers) {
const Pointer &GP = getGlobalPtr("p");
const Pointer &P = GP.deref<Pointer>();
ASSERT_TRUE(P.isIntegralPointer());
- APValue A = P.toAPValue(ASTCtx);
+ APValue A = P.toAPValue(ASTCtx, Prog);
ASSERT_TRUE(A.isLValue());
ASSERT_TRUE(A.getLValueBase().isNull());
APSInt I;
@@ -80,7 +80,7 @@ TEST(ToAPValue, Pointers) {
const Pointer &GP = getGlobalPtr("nullp");
const Pointer &P = GP.deref<Pointer>();
ASSERT_TRUE(P.isIntegralPointer());
- APValue A = P.toAPValue(ASTCtx);
+ APValue A = P.toAPValue(ASTCtx, Prog);
ASSERT_TRUE(A.isLValue());
ASSERT_TRUE(A.getLValueBase().isNull());
ASSERT_TRUE(A.isNullPointer());
@@ -95,7 +95,7 @@ TEST(ToAPValue, Pointers) {
const ValueDecl *D = getDecl("arrp");
ASSERT_NE(D, nullptr);
const Pointer &GP = getGlobalPtr("arrp").deref<Pointer>();
- APValue A = GP.toAPValue(ASTCtx);
+ APValue A = GP.toAPValue(ASTCtx, Prog);
ASSERT_TRUE(A.isLValue());
ASSERT_TRUE(A.hasLValuePath());
ASSERT_EQ(A.getLValuePath().size(), 2u);
@@ -137,7 +137,7 @@ TEST(ToAPValue, FunctionPointers) {
const Pointer &GP = getGlobalPtr("func");
const Pointer &FP = GP.deref<Pointer>();
ASSERT_FALSE(FP.isZero());
- APValue A = FP.toAPValue(ASTCtx);
+ APValue A = FP.toAPValue(ASTCtx, Prog);
ASSERT_TRUE(A.hasValue());
ASSERT_TRUE(A.isLValue());
ASSERT_TRUE(A.hasLValuePath());
@@ -195,7 +195,7 @@ TEST(ToAPValue, FunctionPointersC) {
ASSERT_TRUE(GP.isLive());
const Pointer &FP = GP.deref<Pointer>();
ASSERT_FALSE(FP.isZero());
- APValue A = FP.toAPValue(ASTCtx);
+ APValue A = FP.toAPValue(ASTCtx, Prog);
ASSERT_TRUE(A.hasValue());
ASSERT_TRUE(A.isLValue());
const auto &Path = A.getLValuePath();
@@ -240,7 +240,7 @@ TEST(ToAPValue, MemberPointers) {
const Pointer &GP = getGlobalPtr("pm");
ASSERT_TRUE(GP.isLive());
const MemberPointer &FP = GP.deref<MemberPointer>();
- APValue A = FP.toAPValue(ASTCtx);
+ APValue A = FP.toAPValue(ASTCtx, Prog);
ASSERT_EQ(A.getMemberPointerDecl(), getDecl("m"));
ASSERT_EQ(A.getKind(), APValue::MemberPointer);
}
@@ -250,7 +250,7 @@ TEST(ToAPValue, MemberPointers) {
ASSERT_TRUE(GP.isLive());
const MemberPointer &NP = GP.deref<MemberPointer>();
ASSERT_TRUE(NP.isZero());
- APValue A = NP.toAPValue(ASTCtx);
+ APValue A = NP.toAPValue(ASTCtx, Prog);
ASSERT_EQ(A.getKind(), APValue::MemberPointer);
}
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits