https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/169769
>From 67b563cd4493db1bc79114fd27199857696d6a53 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..f35d3789c8798 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
