https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/185028
This is an alternative approach to https://github.com/llvm/llvm-project/pull/169769. We leave the old `Integral<Bits, Signed>` intact and don't increase its size at all, but then introduce a new `IntegralOrPtr<Bits, Signed>`, which either holds its value _or_ a pointer and an offset. To support address-label-diffs, the offset is always pointer sized as well, making everything `>= 32` bits `sizeof(void*) + sizeof(void*) + sizeof(uint8_t)` in size. The old approach did not work out in the end because we need to be able to do arithmetic (but essentially just `+` and `-`) on the offsets of such integers-that-are-actually-pointers. c-t-t-: https://llvm-compile-time-tracker.com/compare.php?from=e7448c3f4088cae61cb1bf8ade1a4a79d7cc4dbb&to=4aa23d5b4d8e6c43b0cf846f18f34ea967895fe5&stat=instructions:u >From 144ec0098f7887361c8120787a5bdd259a8344ec 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 | 3 +- clang/lib/AST/ByteCode/Context.cpp | 2 +- clang/lib/AST/ByteCode/Descriptor.cpp | 7 + clang/lib/AST/ByteCode/Descriptor.h | 5 + clang/lib/AST/ByteCode/Integral.h | 382 +++++++++++++++++- clang/lib/AST/ByteCode/IntegralAP.h | 1 + clang/lib/AST/ByteCode/Interp.cpp | 40 +- clang/lib/AST/ByteCode/Interp.h | 215 +++++++++- clang/lib/AST/ByteCode/InterpBuiltin.cpp | 60 ++- .../lib/AST/ByteCode/InterpBuiltinBitCast.cpp | 14 +- clang/lib/AST/ByteCode/InterpStack.h | 13 +- clang/lib/AST/ByteCode/Pointer.cpp | 9 + clang/lib/AST/ByteCode/Pointer.h | 4 +- clang/lib/AST/ByteCode/PrimType.h | 32 +- clang/lib/AST/ByteCode/Primitives.h | 8 + clang/test/AST/ByteCode/addr-label-diff.c | 19 + clang/test/AST/ByteCode/addr-label-diff.cpp | 16 + clang/test/AST/ByteCode/builtin-bit-cast.cpp | 8 + clang/test/AST/ByteCode/const-eval.c | 9 +- clang/test/AST/ByteCode/cxx11.cpp | 12 + clang/test/AST/ByteCode/int-as-ptr-arith.c | 17 + clang/test/CodeGen/const-init.c | 1 + 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/CodeGenCXX/const-init.cpp | 6 + clang/test/Sema/array-init.c | 2 + clang/test/Sema/compound-literal.c | 1 + clang/test/Sema/const-ptr-int-ptr-cast.c | 1 + clang/test/Sema/init.c | 1 + clang/test/SemaCXX/constexpr-string.cpp | 1 + 33 files changed, 807 insertions(+), 89 deletions(-) create mode 100644 clang/test/AST/ByteCode/addr-label-diff.c create mode 100644 clang/test/AST/ByteCode/addr-label-diff.cpp create mode 100644 clang/test/AST/ByteCode/int-as-ptr-arith.c diff --git a/clang/lib/AST/ByteCode/Boolean.h b/clang/lib/AST/ByteCode/Boolean.h index fd8d546656881..09eefee14a854 100644 --- a/clang/lib/AST/ByteCode/Boolean.h +++ b/clang/lib/AST/ByteCode/Boolean.h @@ -61,11 +61,10 @@ class Boolean final { bool isMin() const { return isZero(); } constexpr static bool isMinusOne() { return false; } - constexpr static bool isSigned() { return false; } - constexpr static bool isNegative() { return false; } constexpr static bool isPositive() { return !isNegative(); } + constexpr static bool isNumber() { return true; } ComparisonCategoryResult compare(const Boolean &RHS) const { return Compare(V, RHS.V); diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index 879d51e6a2c3e..cc391ba3327f8 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -186,7 +186,7 @@ bool Context::evaluateStringRepr(State &Parent, const Expr *SizeExpr, return false; // Must be char. - if (Ptr.getFieldDesc()->getElemSize() != 1 /*bytes*/) + if (Ptr.getFieldDesc()->getElemDataSize() != 1 /*bytes*/) return false; if (Size > Ptr.getNumElems()) { diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp b/clang/lib/AST/ByteCode/Descriptor.cpp index 5ebc726328fb7..6a192cad9bca2 100644 --- a/clang/lib/AST/ByteCode/Descriptor.cpp +++ b/clang/lib/AST/ByteCode/Descriptor.cpp @@ -483,3 +483,10 @@ bool Descriptor::hasTrivialDtor() const { } bool Descriptor::isUnion() const { return isRecord() && ElemRecord->isUnion(); } + +unsigned Descriptor::getElemDataSize() const { + if ((isPrimitive() || isPrimitiveArray()) && isIntegralType(getPrimType())) { + FIXED_SIZE_INT_TYPE_SWITCH(getPrimType(), { return T::bitWidth() / 8; }); + } + return ElemSize; +} diff --git a/clang/lib/AST/ByteCode/Descriptor.h b/clang/lib/AST/ByteCode/Descriptor.h index b052971733567..9046801f4ebef 100644 --- a/clang/lib/AST/ByteCode/Descriptor.h +++ b/clang/lib/AST/ByteCode/Descriptor.h @@ -246,6 +246,11 @@ struct Descriptor final { unsigned getAllocSize() const { return AllocSize; } /// returns the size of an element when the structure is viewed as an array. unsigned getElemSize() const { return ElemSize; } + /// Returns the element data size, i.e. not what the size of + /// our primitive data type is, but what the data size of that is. + /// E.g., for PT_SInt32, that's 4 bytes. + unsigned getElemDataSize() const; + /// Returns the size of the metadata. unsigned getMetadataSize() const { return MDSize; } diff --git a/clang/lib/AST/ByteCode/Integral.h b/clang/lib/AST/ByteCode/Integral.h index e90f1a9a74e1c..82b62f7969d12 100644 --- a/clang/lib/AST/ByteCode/Integral.h +++ b/clang/lib/AST/ByteCode/Integral.h @@ -14,6 +14,7 @@ #define LLVM_CLANG_AST_INTERP_INTEGRAL_H #include "clang/AST/APValue.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/ComparisonCategories.h" #include "llvm/ADT/APSInt.h" #include "llvm/Support/MathExtras.h" @@ -22,6 +23,7 @@ #include <cstdint> #include "Primitives.h" +#include "Program.h" namespace clang { namespace interp { @@ -69,7 +71,7 @@ template <unsigned Bits, bool Signed> class Integral final { // The primitive representing the integral. using ReprT = typename Repr<Bits, Signed>::Type; - ReprT V; + ReprT V = 0; static_assert(std::is_trivially_copyable_v<ReprT>); /// Primitive representing limits. @@ -83,7 +85,7 @@ template <unsigned Bits, bool Signed> class Integral final { using AsUnsigned = Integral<Bits, false>; /// Zero-initializes an integral. - Integral() : V(0) {} + Integral() = default; /// Constructs an integral from another integral. template <unsigned SrcBits, bool SrcSign> @@ -144,15 +146,12 @@ template <unsigned Bits, bool Signed> class Integral final { } constexpr static unsigned bitWidth() { return Bits; } + constexpr static bool isSigned() { return Signed; } + constexpr static bool isNumber() { return true; } bool isZero() const { return !V; } - bool isMin() const { return *this == min(bitWidth()); } - bool isMinusOne() const { return Signed && V == ReprT(-1); } - - constexpr static bool isSigned() { return Signed; } - bool isNegative() const { return V < ReprT(0); } bool isPositive() const { return !isNegative(); } @@ -205,7 +204,8 @@ template <unsigned Bits, bool Signed> class Integral final { static Integral zero(unsigned BitWidth = 0) { return from(0); } template <typename ValT> - static Integral from(ValT Value, unsigned NumBits = 0) { + static std::enable_if_t<!std::is_same_v<ValT, IntegralKind>, Integral> + from(ValT Value, unsigned NumBits = 0) { if constexpr (std::is_integral_v<ValT>) return Integral(Value); else @@ -213,7 +213,8 @@ template <unsigned Bits, bool Signed> class Integral final { } template <unsigned SrcBits, bool SrcSign> - static Integral from(Integral<SrcBits, SrcSign> Value) { + static std::enable_if_t<SrcBits != 0, Integral> + from(Integral<SrcBits, SrcSign> Value) { return Integral(Value.V); } @@ -287,7 +288,7 @@ template <unsigned Bits, bool Signed> class Integral final { *R = Integral::from(A.V >> B.V, OpBits); } -private: +public: template <typename T> static bool CheckAddUB(T A, T B, T &R) { if constexpr (std::is_signed_v<T>) { return llvm::AddOverflow<T>(A, B, R); @@ -327,6 +328,367 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Integral<Bits, Signed> I) { return OS; } +template <unsigned Bits, bool Signed> class IntegralOrPtr final { + static_assert(Bits >= 32); + +public: + // The primitive representing the integral. + using ReprT = typename Repr<Bits, Signed>::Type; + +private: + using OffsetT = intptr_t; + static_assert(std::is_trivially_copyable_v<ReprT>); + template <unsigned OtherBits, bool OtherSigned> friend class IntegralOrPtr; + + IntegralKind Kind = IntegralKind::Number; + union { + ReprT V; + struct { + const void *P; + OffsetT Offset; + } Ptr; + }; + + static_assert(sizeof(uintptr_t) >= sizeof(ReprT)); + + /// Primitive representing limits. + static const auto Min = std::numeric_limits<ReprT>::min(); + static const auto Max = std::numeric_limits<ReprT>::max(); + + /// Construct an integral from anything that is convertible to storage. + template <typename T> explicit IntegralOrPtr(T V) : V(V) {} + template <typename T> + explicit IntegralOrPtr(IntegralKind Kind, T V) : Kind(Kind), V(V) {} + +public: + using AsUnsigned = IntegralOrPtr<Bits, false>; + + /// Zero-initializes an integral. + IntegralOrPtr() = default; + + /// Constructs an integral from another integral. + template <unsigned SrcBits, bool SrcSign> + explicit IntegralOrPtr(Integral<SrcBits, SrcSign> V) : Kind(V.Kind), V(V) {} + + explicit IntegralOrPtr(IntegralKind Kind, const void *P, OffsetT Offset = 0) + : Kind(Kind) { + Ptr.P = P; + Ptr.Offset = Offset; + } + + explicit IntegralOrPtr(const void *P1, const void *P2) + : Kind(IntegralKind::AddrLabelDiff) { + Ptr.P = P1; + Ptr.Offset = reinterpret_cast<uintptr_t>(P2); + } + + IntegralKind getKind() const { return Kind; } + bool isNumber() const { return Kind == IntegralKind::Number; } + const void *getPtr() const { + assert(!isNumber()); + return Ptr.P; + } + ReprT getOffset() const { + assert(!isNumber()); + return Ptr.Offset; + } + + /// Construct an integral from a value based on signedness. + explicit IntegralOrPtr(const APSInt &V) + : V(V.isSigned() ? V.getSExtValue() : V.getZExtValue()) {} + + bool operator<(IntegralOrPtr RHS) const { return V < RHS.V; } + bool operator>(IntegralOrPtr RHS) const { return V > RHS.V; } + bool operator<=(IntegralOrPtr RHS) const { return V <= RHS.V; } + bool operator>=(IntegralOrPtr RHS) const { return V >= RHS.V; } + bool operator==(IntegralOrPtr RHS) const { return V == RHS.V; } + bool operator!=(IntegralOrPtr RHS) const { return V != RHS.V; } + bool operator>=(unsigned RHS) const { + return static_cast<unsigned>(V) >= RHS; + } + + bool operator>(unsigned RHS) const { + return V >= 0 && static_cast<unsigned>(V) > RHS; + } + + IntegralOrPtr operator-() const { return IntegralOrPtr(-V); } + IntegralOrPtr operator-(const IntegralOrPtr &Other) const { + return IntegralOrPtr(V - Other.V); + } + IntegralOrPtr operator~() const { return IntegralOrPtr(~V); } + + template <unsigned DstBits, bool DstSign> + explicit operator IntegralOrPtr<DstBits, DstSign>() const { + return IntegralOrPtr<DstBits, DstSign>(Kind, V); + } + + template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>> + explicit operator Ty() const { + return V; + } + + APSInt toAPSInt() const { + assert(isNumber()); + return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed); + } + + APSInt toAPSInt(unsigned BitWidth) const { + return APSInt(toAPInt(BitWidth), !Signed); + } + + APInt toAPInt(unsigned BitWidth) const { + assert(isNumber()); + if constexpr (Signed) + return APInt(Bits, static_cast<uint64_t>(V), Signed) + .sextOrTrunc(BitWidth); + else + return APInt(Bits, static_cast<uint64_t>(V), Signed) + .zextOrTrunc(BitWidth); + } + + APValue toAPValue(const ASTContext &) const { + switch (Kind) { + case IntegralKind::Address: { + return APValue((const ValueDecl *)Ptr.P, + CharUnits::fromQuantity(Ptr.Offset), + APValue::NoLValuePath{}); + } + case IntegralKind::LabelAddress: { + return APValue((const Expr *)Ptr.P, CharUnits::Zero(), + APValue::NoLValuePath{}); + } + case IntegralKind::BlockAddress: { + const Block *B = reinterpret_cast<const Block *>(Ptr.P); + const Descriptor *D = B->getDescriptor(); + if (const Expr *E = D->asExpr()) + return APValue(E, CharUnits::Zero(), APValue::NoLValuePath{}); + + return APValue(D->asValueDecl(), CharUnits::Zero(), + APValue::NoLValuePath{}); + } + case IntegralKind::AddrLabelDiff: { + return APValue( + (const AddrLabelExpr *)Ptr.P, + (const AddrLabelExpr *)reinterpret_cast<const void *>(Ptr.Offset)); + } + case IntegralKind::Number: + return APValue(toAPSInt()); + } + llvm_unreachable("Unhandled IntegralKind"); + } + + IntegralOrPtr<Bits, false> toUnsigned() const { + return IntegralOrPtr<Bits, false>(*this); + } + + constexpr static unsigned bitWidth() { return Bits; } + constexpr static bool isSigned() { return Signed; } + + bool isZero() const { return !V; } + bool isMin() const { return *this == min(bitWidth()); } + bool isMinusOne() const { return Signed && V == ReprT(-1); } + bool isNegative() const { return V < ReprT(0); } + bool isPositive() const { return !isNegative(); } + + ComparisonCategoryResult compare(const IntegralOrPtr &RHS) const { + return Compare(V, RHS.V); + } + + void bitcastToMemory(std::byte *Dest) const { + assert(isNumber()); + std::memcpy(Dest, &V, sizeof(V)); + } + + static IntegralOrPtr bitcastFromMemory(const std::byte *Src, + unsigned BitWidth) { + assert(BitWidth == sizeof(ReprT) * 8); + ReprT V; + + std::memcpy(&V, Src, sizeof(ReprT)); + return IntegralOrPtr(V); + } + + std::string toDiagnosticString(const ASTContext &Ctx) const { + std::string NameStr; + llvm::raw_string_ostream OS(NameStr); + OS << V; + return NameStr; + } + + unsigned countLeadingZeros() const { + assert(isNumber()); + if constexpr (!Signed) + return llvm::countl_zero<ReprT>(V); + if (isPositive()) + return llvm::countl_zero<typename AsUnsigned::ReprT>( + static_cast<typename AsUnsigned::ReprT>(V)); + llvm_unreachable("Don't call countLeadingZeros() on negative values."); + } + + IntegralOrPtr truncate(unsigned TruncBits) const { + assert(TruncBits >= 1); + if (TruncBits >= Bits) + return *this; + const ReprT BitMask = (ReprT(1) << ReprT(TruncBits)) - 1; + const ReprT SignBit = ReprT(1) << (TruncBits - 1); + const ReprT ExtMask = ~BitMask; + return IntegralOrPtr((V & BitMask) | + (Signed && (V & SignBit) ? ExtMask : 0)); + } + + void print(llvm::raw_ostream &OS) const { + switch (Kind) { + case IntegralKind::Number: + OS << V; + break; + case IntegralKind::AddrLabelDiff: + OS << Ptr.P << " - " << (const void *)Ptr.Offset << " (AddrLabelDiff)"; + break; + case IntegralKind::Address: + OS << Ptr.P << " + " << Ptr.Offset << " (Address)"; + break; + case IntegralKind::BlockAddress: + OS << Ptr.P << " + " << Ptr.Offset << " (BlockAddress)"; + break; + case IntegralKind::LabelAddress: + OS << Ptr.P << " + " << Ptr.Offset << " (LabelAddress)"; + } + } + + static IntegralOrPtr min(unsigned NumBits) { return IntegralOrPtr(Min); } + static IntegralOrPtr max(unsigned NumBits) { return IntegralOrPtr(Max); } + static IntegralOrPtr zero(unsigned BitWidth = 0) { return from(0); } + + template <typename ValT> + static std::enable_if_t<!std::is_same_v<ValT, IntegralKind>, IntegralOrPtr> + from(ValT V, unsigned NumBits = 0) { + if constexpr (std::is_integral_v<ValT>) + return IntegralOrPtr(V); + else + return IntegralOrPtr(static_cast<IntegralOrPtr::ReprT>(V)); + } + + template <unsigned SrcBits, bool SrcSign> + static std::enable_if_t<SrcBits != 0, IntegralOrPtr> + from(IntegralOrPtr<SrcBits, SrcSign> V) { + auto A = IntegralOrPtr(V.Kind, V.V); + switch (V.Kind) { + case IntegralKind::Number: + A.V = V.V; + break; + case IntegralKind::AddrLabelDiff: + case IntegralKind::Address: + case IntegralKind::BlockAddress: + case IntegralKind::LabelAddress: + A.Ptr.P = V.Ptr.P; + A.Ptr.Offset = V.Ptr.Offset; + break; + } + return A; + } + + template <typename T> static IntegralOrPtr from(IntegralKind Kind, T V) { + return IntegralOrPtr(Kind, V); + } + + static bool increment(IntegralOrPtr A, IntegralOrPtr *R) { + assert(A.isNumber()); + return add(A, IntegralOrPtr(ReprT(1)), A.bitWidth(), R); + } + + static bool decrement(IntegralOrPtr A, IntegralOrPtr *R) { + assert(A.isNumber()); + return sub(A, IntegralOrPtr(ReprT(1)), A.bitWidth(), R); + } + + static bool add(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits, + IntegralOrPtr *R) { + assert(A.isNumber() && B.isNumber()); + return Integral<Bits, Signed>::CheckAddUB(A.V, B.V, R->V); + } + + static bool sub(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits, + IntegralOrPtr *R) { + assert(A.isNumber() && B.isNumber()); + return Integral<Bits, Signed>::CheckSubUB(A.V, B.V, R->V); + } + + static bool mul(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits, + IntegralOrPtr *R) { + assert(A.isNumber() && B.isNumber()); + return Integral<Bits, Signed>::CheckMulUB(A.V, B.V, R->V); + } + + static bool rem(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits, + IntegralOrPtr *R) { + assert(A.isNumber() && B.isNumber()); + *R = IntegralOrPtr(A.V % B.V); + return false; + } + + static bool div(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits, + IntegralOrPtr *R) { + assert(A.isNumber() && B.isNumber()); + *R = IntegralOrPtr(A.V / B.V); + return false; + } + + static bool bitAnd(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits, + IntegralOrPtr *R) { + assert(A.isNumber() && B.isNumber()); + *R = IntegralOrPtr(A.V & B.V); + return false; + } + + static bool bitOr(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits, + IntegralOrPtr *R) { + assert(A.isNumber() && B.isNumber()); + *R = IntegralOrPtr(A.V | B.V); + return false; + } + + static bool bitXor(IntegralOrPtr A, IntegralOrPtr B, unsigned OpBits, + IntegralOrPtr *R) { + assert(A.isNumber() && B.isNumber()); + *R = IntegralOrPtr(A.V ^ B.V); + return false; + } + + static bool neg(IntegralOrPtr A, IntegralOrPtr *R) { + if (Signed && A.isMin()) + return true; + + *R = -A; + return false; + } + + static bool comp(IntegralOrPtr A, IntegralOrPtr *R) { + *R = IntegralOrPtr(~A.V); + return false; + } + + template <unsigned RHSBits, bool RHSSign> + static void shiftLeft(const IntegralOrPtr A, + const IntegralOrPtr<RHSBits, RHSSign> B, + unsigned OpBits, IntegralOrPtr *R) { + *R = IntegralOrPtr::from(A.V << B.V, OpBits); + } + + template <unsigned RHSBits, bool RHSSign> + static void shiftRight(const IntegralOrPtr A, + const IntegralOrPtr<RHSBits, RHSSign> B, + unsigned OpBits, IntegralOrPtr *R) { + *R = IntegralOrPtr::from(A.V >> B.V, OpBits); + } +}; + +template <unsigned Bits, bool Signed> +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + IntegralOrPtr<Bits, Signed> I) { + I.print(OS); + return OS; +} + } // namespace interp } // namespace clang diff --git a/clang/lib/AST/ByteCode/IntegralAP.h b/clang/lib/AST/ByteCode/IntegralAP.h index b11e6eea28e3f..9f53ac7716bba 100644 --- a/clang/lib/AST/ByteCode/IntegralAP.h +++ b/clang/lib/AST/ByteCode/IntegralAP.h @@ -139,6 +139,7 @@ template <bool Signed> class IntegralAP final { constexpr uint32_t bitWidth() const { return BitWidth; } constexpr unsigned numWords() const { return APInt::getNumWords(BitWidth); } constexpr bool singleWord() const { return numWords() == 1; } + constexpr static bool isNumber() { return true; } APSInt toAPSInt(unsigned Bits = 0) const { if (Bits == 0) diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index ebc7220aa5671..0f571f6789d10 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -88,20 +88,20 @@ static bool BCP(InterpState &S, CodePtr &RealPC, int32_t Offset, PrimType PT) { if (PT == PT_Ptr) { const auto &Ptr = S.Stk.pop<Pointer>(); assert(S.Stk.size() == StackSizeBefore); - S.Stk.push<Integral<32, true>>( - Integral<32, true>::from(CheckBCPResult(S, Ptr))); + S.Stk.push<IntegralOrPtr<32, true>>( + IntegralOrPtr<32, true>::from(CheckBCPResult(S, Ptr))); } else { // Pop the result from the stack and return success. TYPE_SWITCH(PT, S.Stk.pop<T>();); assert(S.Stk.size() == StackSizeBefore); - S.Stk.push<Integral<32, true>>(Integral<32, true>::from(1)); + S.Stk.push<IntegralOrPtr<32, true>>(IntegralOrPtr<32, true>::from(1)); } } else { if (!S.inConstantContext()) return Invalid(S, RealPC); S.Stk.clearTo(StackSizeBefore); - S.Stk.push<Integral<32, true>>(Integral<32, true>::from(0)); + S.Stk.push<IntegralOrPtr<32, true>>(IntegralOrPtr<32, true>::from(0)); } // RealPC should not have been modified. @@ -2187,12 +2187,15 @@ bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC, S.CCEDiag(E, diag::note_constexpr_invalid_cast) << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC); - if (Ptr.isDummy()) + if (S.getLangOpts().CPlusPlus && Ptr.isDummy() && !Ptr.pointsToLabel()) return false; - if (Ptr.isFunctionPointer()) + if (Ptr.isIntegralPointer()) + return true; + + if (Ptr.isDummy()) return true; - if (Ptr.isBlockPointer() && !Ptr.isZero()) { + if (!Ptr.isZero()) { // Only allow based lvalue casts if they are lossless. if (S.getASTContext().getTargetInfo().getPointerWidth(LangAS::Default) != BitWidth) @@ -2201,6 +2204,11 @@ bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC, return true; } +bool CheckIntegralAddressCast(InterpState &S, CodePtr OpPC, unsigned BitWidth) { + return (S.getASTContext().getTargetInfo().getPointerWidth(LangAS::Default) == + BitWidth); +} + bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { const Pointer &Ptr = S.Stk.pop<Pointer>(); @@ -2286,13 +2294,19 @@ bool DiagTypeid(InterpState &S, CodePtr OpPC) { bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS, const Pointer &RHS) { + if (!LHS.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) @@ -2308,11 +2322,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 7f30def20cc36..3df632ed45c5f 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -280,6 +280,11 @@ template <typename T, bool (*OpFW)(T, T, unsigned, T *), template <typename U> class OpAP> bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, const T &RHS) { + // Should've been handled before. + if constexpr (isIntegralOrPointer<T>()) { + assert(LHS.isNumber() && RHS.isNumber()); + } + // Fast path - add the numbers with fixed width. T Result; if constexpr (needsAlloc<T>()) @@ -318,12 +323,46 @@ bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, return true; } +// Add or subtract an integer-thats-actually-a-pointer and one real integer. +template <typename T, template <typename U> class Op> +static bool AddSubNonNumber(InterpState &S, CodePtr OpPC, T LHS, T RHS) { + assert(!LHS.isNumber() || !RHS.isNumber()); + + typename T::ReprT Number; + const void *Ptr; + typename T::ReprT Offset; + IntegralKind Kind; + if (LHS.isNumber()) { + Number = static_cast<typename T::ReprT>(LHS); + Ptr = RHS.getPtr(); + Offset = RHS.getOffset(); + Kind = RHS.getKind(); + } else { + assert(RHS.isNumber()); + Number = static_cast<typename T::ReprT>(RHS); + Ptr = LHS.getPtr(); + Offset = LHS.getOffset(); + Kind = LHS.getKind(); + } + S.Stk.push<T>(Kind, Ptr, Op<typename T::ReprT>()(Offset, Number)); + return true; +} + template <PrimType Name, class T = typename PrimConv<Name>::T> bool Add(InterpState &S, CodePtr OpPC) { const T &RHS = S.Stk.pop<T>(); const T &LHS = S.Stk.pop<T>(); const unsigned Bits = RHS.bitWidth() + 1; + if constexpr (isIntegralOrPointer<T>()) { + if (LHS.isNumber() != RHS.isNumber()) + return AddSubNonNumber<T, std::plus>(S, OpPC, LHS, RHS); + else if (LHS.isNumber() && RHS.isNumber()) + ; // Fall through to proper addition below. + else + return false; // Reject everything else. + } + return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS); } @@ -344,6 +383,35 @@ bool Sub(InterpState &S, CodePtr OpPC) { const T &LHS = S.Stk.pop<T>(); const unsigned Bits = RHS.bitWidth() + 1; + if constexpr (isIntegralOrPointer<T>()) { + // 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 *>(LHS.getPtr()); + const auto *B = reinterpret_cast<const Expr *>(RHS.getPtr()); + if (!isa<AddrLabelExpr>(A) || !isa<AddrLabelExpr>(B)) + return false; + const auto *LHSAddrExpr = cast<AddrLabelExpr>(A); + const auto *RHSAddrExpr = cast<AddrLabelExpr>(B); + + if (LHSAddrExpr->getLabel()->getDeclContext() != + RHSAddrExpr->getLabel()->getDeclContext()) + return Invalid(S, OpPC); + + S.Stk.push<T>(LHSAddrExpr, RHSAddrExpr); + return true; + } + + if (!LHS.isNumber() && RHS.isNumber()) + return AddSubNonNumber<T, std::minus>(S, OpPC, LHS, RHS); + else if (LHS.isNumber() && RHS.isNumber()) + ; // Fall through to proper addition below. + else + return false; // Reject everything else. + } + return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS); } @@ -364,6 +432,11 @@ bool Mul(InterpState &S, CodePtr OpPC) { const T &LHS = S.Stk.pop<T>(); const unsigned Bits = RHS.bitWidth() * 2; + if constexpr (isIntegralOrPointer<T>()) { + if (!LHS.isNumber() || !RHS.isNumber()) + return Invalid(S, OpPC); + } + return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS); } @@ -1049,6 +1122,12 @@ bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) { using BoolT = PrimConv<PT_Bool>::T; const T &RHS = S.Stk.pop<T>(); const T &LHS = S.Stk.pop<T>(); + + if constexpr (isIntegralOrPointer<T>()) { + if (!LHS.isNumber() || !RHS.isNumber()) + return Invalid(S, OpPC); + } + S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS)))); return true; } @@ -1376,7 +1455,20 @@ 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, uint32_t>) { + S.Stk.push<IntegralOrPtr<32, false>>(IntegralOrPtr<32, false>::from(Arg)); + } else if constexpr (std::is_same_v<T, int32_t>) { + S.Stk.push<IntegralOrPtr<32, true>>(IntegralOrPtr<32, true>::from(Arg)); + } else if constexpr (std::is_same_v<T, uint64_t>) { + S.Stk.push<IntegralOrPtr<64, false>>(IntegralOrPtr<64, false>::from(Arg)); + } else if constexpr (std::is_same_v<T, int64_t>) { + S.Stk.push<IntegralOrPtr<64, true>>(IntegralOrPtr<64, true>::from(Arg)); + } else { + // Bool. + S.Stk.push<T>(Arg); + } + return true; } @@ -2451,6 +2543,26 @@ 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()) { + if constexpr (isIntegralOrPointer<T>()) { + 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); + + S.Stk.push<T>(LHSAddrExpr, RHSAddrExpr); + return true; + } + // Can't represent an address-label-diff in these types. + return false; + } + if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) { S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_pointer_arith_unspecified) @@ -2520,7 +2632,27 @@ 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 constexpr (isIntegralOrPointer<T>()) { + if (In.getKind() != IntegralKind::Number && + In.getKind() != IntegralKind::AddrLabelDiff) { + if (!CheckIntegralAddressCast(S, OpPC, In.bitWidth())) + return Invalid(S, OpPC); + } else if (In.getKind() == IntegralKind::AddrLabelDiff) { + // Allow casts of address-of-label differences if they are no-ops + // or narrowing, if the result is at least 32 bits wide. + // (The narrowing case isn't actually guaranteed to + // be constant-evaluatable except in some narrow cases which are hard + // to detect here. We let it through on the assumption the user knows + // what they are doing.) + if (!(U::bitWidth() >= 32 && U::bitWidth() <= In.bitWidth())) + return false; + } + } + + S.Stk.push<U>(U::from(In)); return true; } @@ -2554,11 +2686,18 @@ inline bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS) { /// to know what bitwidth the result should be. template <PrimType Name, class T = typename PrimConv<Name>::T> bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { + T Source = S.Stk.pop<T>(); + + if constexpr (isIntegralOrPointer<T>()) { + if (!Source.isNumber()) + return false; + } + auto Result = S.allocAP<IntegralAP<false>>(BitWidth); // Copy data. { - APInt Source = S.Stk.pop<T>().toAPSInt().extOrTrunc(BitWidth); - Result.copy(Source); + APInt SourceInt = Source.toAPSInt().extOrTrunc(BitWidth); + Result.copy(SourceInt); } S.Stk.push<IntegralAP<false>>(Result); return true; @@ -2566,11 +2705,18 @@ bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { template <PrimType Name, class T = typename PrimConv<Name>::T> bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { + T Source = S.Stk.pop<T>(); + + if constexpr (isIntegralOrPointer<T>()) { + if (!Source.isNumber()) + return false; + } + auto Result = S.allocAP<IntegralAP<true>>(BitWidth); // Copy data. { - APInt Source = S.Stk.pop<T>().toAPSInt().extOrTrunc(BitWidth); - Result.copy(Source); + APInt SourceInt = Source.toAPSInt().extOrTrunc(BitWidth); + Result.copy(SourceInt); } S.Stk.push<IntegralAP<true>>(Result); return true; @@ -2668,6 +2814,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); @@ -2678,7 +2825,35 @@ 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 constexpr (isIntegralOrPointer<T>()) { + if (Ptr.isBlockPointer()) { + IntegralKind Kind = IntegralKind::Address; + const void *PtrVal; + if (Ptr.isDummy()) { + if (const Expr *E = Ptr.getDeclDesc()->asExpr()) { + PtrVal = E; + if (isa<AddrLabelExpr>(E)) + Kind = IntegralKind::LabelAddress; + } else { + PtrVal = Ptr.getDeclDesc()->asDecl(); + } + } else { + PtrVal = Ptr.block(); + Kind = IntegralKind::BlockAddress; + } + S.Stk.push<T>(Kind, PtrVal, /*Offset=*/0); + } else if (Ptr.isFunctionPointer()) { + const void *FuncDecl = Ptr.asFunctionPointer().getFunction()->getDecl(); + S.Stk.push<T>(IntegralKind::Address, FuncDecl, /*Offset=*/0); + } else { + // FIXME: Is this still possible? + S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation())); + } + } else { + return false; + } return true; } @@ -3253,7 +3428,28 @@ inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret << S.getLangOpts().CPlusPlus; - S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc); + if constexpr (isIntegralOrPointer<T>()) { + + if (IntVal.getKind() == IntegralKind::Address) { + if (IntVal.getOffset() != 0) { + return Invalid(S, OpPC); + } + const VarDecl *VD = (const VarDecl *)IntVal.getPtr(); + unsigned GlobalIndex = *S.P.getOrCreateGlobal(VD); + S.Stk.push<Pointer>(S.P.getGlobal(GlobalIndex)); + } else if (IntVal.getKind() == IntegralKind::BlockAddress) { + if (IntVal.getOffset() != 0) { + return Invalid(S, OpPC); + } + const Block *B = (const Block *)IntVal.getPtr(); + S.Stk.push<Pointer>(const_cast<Block *>(B)); + } else { + S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc); + } + } else { + S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc); + } + return true; } @@ -3396,7 +3592,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<IntegralOrPtr<64, true>>())); int64_t Result; if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result)) diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index c7d3c2e500592..82fe6cfebce5d 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -364,14 +364,15 @@ 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(); + unsigned ElemSize = StrPtr.getFieldDesc()->getElemDataSize(); if (ElemSize != 1 && ElemSize != 2 && ElemSize != 4) return Invalid(S, OpPC); if (ID == Builtin::BI__builtin_wcslen || ID == Builtin::BIwcslen) { const ASTContext &AC = S.getASTContext(); unsigned WCharSize = AC.getTypeSizeInChars(AC.getWCharType()).getQuantity(); - if (ElemSize != WCharSize) + if (StrPtr.getFieldDesc()->getElemDataSize() != WCharSize) return false; } @@ -383,19 +384,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; } @@ -1383,11 +1373,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; } @@ -1928,8 +1918,8 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC, Pointer SrcP = SrcPtr.stripBaseCasts(); Pointer DestP = DestPtr.stripBaseCasts(); - 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; if ((SrcIndex <= DstIndex && (SrcIndex + Size) > DstIndex) || (DstIndex <= SrcIndex && (DstIndex + Size) > SrcIndex)) { @@ -1997,6 +1987,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()) @@ -2023,21 +2014,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/InterpBuiltinBitCast.cpp b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp index 4bd9c66fc9974..12efd96128b71 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp @@ -311,7 +311,12 @@ bool clang::interp::readPointerToBuffer(const Context &Ctx, Buffer.markInitialized(BitOffset, NumBits); } else { - BITCAST_TYPE_SWITCH(T, { P.deref<T>().bitcastToMemory(Buff.get()); }); + BITCAST_TYPE_SWITCH(T, { + auto Val = P.deref<T>(); + if (!Val.isNumber()) + return false; + Val.bitcastToMemory(Buff.get()); + }); if (llvm::sys::IsBigEndianHost) swapBytes(Buff.get(), FullBitWidth.roundToBytes()); @@ -472,9 +477,10 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC, using PrimTypeVariant = std::variant<Pointer, FunctionPointer, MemberPointer, FixedPoint, Integral<8, false>, Integral<8, true>, Integral<16, false>, - Integral<16, true>, Integral<32, false>, Integral<32, true>, - Integral<64, false>, Integral<64, true>, IntegralAP<true>, - IntegralAP<false>, Boolean, Floating>; + Integral<16, true>, IntegralOrPtr<32, false>, + IntegralOrPtr<32, true>, IntegralOrPtr<64, false>, + IntegralOrPtr<64, true>, IntegralAP<true>, IntegralAP<false>, + Boolean, Floating>; // NB: This implementation isn't exactly ideal, but: // 1) We can't just do a bitcast here since we need to be able to diff --git a/clang/lib/AST/ByteCode/InterpStack.h b/clang/lib/AST/ByteCode/InterpStack.h index c647dfa6d85ea..77fa790ac046d 100644 --- a/clang/lib/AST/ByteCode/InterpStack.h +++ b/clang/lib/AST/ByteCode/InterpStack.h @@ -185,18 +185,15 @@ class InterpStack final { else if constexpr (std::is_same_v<T, uint16_t> || 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, IntegralOrPtr<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, IntegralOrPtr<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, IntegralOrPtr<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, IntegralOrPtr<64, false>>) return PT_Uint64; + else if constexpr (std::is_same_v<T, Floating>) return PT_Float; else if constexpr (std::is_same_v<T, IntegralAP<true>>) diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index f4352e7edf5f8..866a77cb25ce8 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -745,6 +745,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()) diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index 010e917de81b2..65af81817f9d3 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -366,7 +366,7 @@ class Pointer { if (isIntegralPointer()) { if (!Int.Desc) return 1; - return Int.Desc->getElemSize(); + return Int.Desc->getElemDataSize(); } if (BS.Base == RootPtrMark) @@ -809,6 +809,8 @@ class Pointer { /// i.e. a non-MaterializeTemporaryExpr Expr. bool pointsToLiteral() const; bool pointsToStringLiteral() const; + /// Whether this points to a block created for an AddrLabelExpr. + 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 2433eb33c47b1..5c68aa38399ea 100644 --- a/clang/lib/AST/ByteCode/PrimType.h +++ b/clang/lib/AST/ByteCode/PrimType.h @@ -29,6 +29,7 @@ class MemberPointer; class FixedPoint; template <bool Signed> class IntegralAP; template <unsigned Bits, bool Signed> class Integral; +template <unsigned Bits, bool Signed> class IntegralOrPtr; /// Enumeration of the primitive types of the VM. enum PrimType : uint8_t { @@ -135,6 +136,13 @@ constexpr bool needsAlloc(PrimType T) { return T == PT_IntAP || T == PT_IntAPS || T == PT_Float || T == PT_MemberPtr; } +template <typename T> constexpr bool isIntegralOrPointer() { + return std::is_same_v<T, IntegralOrPtr<32, false>> || + std::is_same_v<T, IntegralOrPtr<32, true>> || + std::is_same_v<T, IntegralOrPtr<64, false>> || + std::is_same_v<T, IntegralOrPtr<64, true>>; +} + /// Mapping from primitive types to their representation. template <PrimType T> struct PrimConv; template <> struct PrimConv<PT_Sint8> { @@ -150,16 +158,16 @@ template <> struct PrimConv<PT_Uint16> { using T = Integral<16, false>; }; template <> struct PrimConv<PT_Sint32> { - using T = Integral<32, true>; + using T = IntegralOrPtr<32, true>; }; template <> struct PrimConv<PT_Uint32> { - using T = Integral<32, false>; + using T = IntegralOrPtr<32, false>; }; template <> struct PrimConv<PT_Sint64> { - using T = Integral<64, true>; + using T = IntegralOrPtr<64, true>; }; template <> struct PrimConv<PT_Uint64> { - using T = Integral<64, false>; + using T = IntegralOrPtr<64, false>; }; template <> struct PrimConv<PT_IntAP> { using T = IntegralAP<false>; @@ -249,6 +257,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..424afb1f8007b 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 : uint8_t { + 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/test/AST/ByteCode/addr-label-diff.c b/clang/test/AST/ByteCode/addr-label-diff.c new file mode 100644 index 0000000000000..b8f77ecf041cd --- /dev/null +++ b/clang/test/AST/ByteCode/addr-label-diff.c @@ -0,0 +1,19 @@ +// 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/addr-label-diff.cpp b/clang/test/AST/ByteCode/addr-label-diff.cpp new file mode 100644 index 0000000000000..336a0fbe3de3e --- /dev/null +++ b/clang/test/AST/ByteCode/addr-label-diff.cpp @@ -0,0 +1,16 @@ +// 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 + + +// Make sure we don't try to fold this either. +// CHECK: @_ZZ23UnfoldableAddrLabelDiffvE1x = internal global i128 0 +void UnfoldableAddrLabelDiff() { static __int128_t x = (long)&&a-(long)&&b; a:b:return;} + +// CHECK: @_ZZ24UnfoldableAddrLabelDiff2vE1x = internal global i16 0 +void UnfoldableAddrLabelDiff2() { static short x = (long)&&a-(long)&&b; a:b:return;} + + +// But make sure we do fold this. +// CHECK: @_ZZ21FoldableAddrLabelDiffvE1x = internal global i64 sub (i64 ptrtoint (ptr blockaddress(@_Z21FoldableAddrLabelDiffv +void FoldableAddrLabelDiff() { static long x = (long)&&a-(long)&&b; a:b:return;} + diff --git a/clang/test/AST/ByteCode/builtin-bit-cast.cpp b/clang/test/AST/ByteCode/builtin-bit-cast.cpp index 09a67e60fb3be..4e3a5cd295458 100644 --- a/clang/test/AST/ByteCode/builtin-bit-cast.cpp +++ b/clang/test/AST/ByteCode/builtin-bit-cast.cpp @@ -590,3 +590,11 @@ namespace ToPrimPtrs { // both-note {{bit_cast to a member pointer type is not allowed in a constant expression}} #endif } + +namespace NonNumbers { +#define fold(x) (__builtin_constant_p(x) ? (x) : (x)) + constexpr long fn(void) { + return __builtin_bit_cast(long, fold((long)&fn)); + } + static_assert(fn() == 1); // both-error {{not an integral constant expression}} +} diff --git a/clang/test/AST/ByteCode/const-eval.c b/clang/test/AST/ByteCode/const-eval.c index 70b2a4dbd86e4..e61050e5e3040 100644 --- a/clang/test/AST/ByteCode/const-eval.c +++ b/clang/test/AST/ByteCode/const-eval.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -fsyntax-only -verify=both,ref -triple x86_64-linux %s -Wno-tautological-pointer-compare -Wno-pointer-to-int-cast -// RUN: %clang_cc1 -fsyntax-only -verify=both,expected -triple x86_64-linux %s -Wno-tautological-pointer-compare -Wno-pointer-to-int-cast -fexperimental-new-constant-interpreter -DNEW_INTERP +// RUN: %clang_cc1 -fsyntax-only -verify=both,ref -triple x86_64-linux %s -Wno-tautological-pointer-compare -Wno-pointer-to-int-cast +// RUN: %clang_cc1 -fsyntax-only -verify=both,expected -triple x86_64-linux %s -Wno-tautological-pointer-compare -Wno-pointer-to-int-cast -fexperimental-new-constant-interpreter -DNEW_INTERP // RUN: %clang_cc1 -fsyntax-only -verify=both,ref -triple powerpc64-ibm-aix-xcoff %s -Wno-tautological-pointer-compare -Wno-pointer-to-int-cast // RUN: %clang_cc1 -fsyntax-only -verify=both,expected -triple powerpc64-ibm-aix-xcoff %s -Wno-tautological-pointer-compare -Wno-pointer-to-int-cast -fexperimental-new-constant-interpreter -DNEW_INTERP @@ -127,7 +127,7 @@ EVAL_EXPR(43, varfloat && constfloat) // both-error {{not an integer constant ex EVAL_EXPR(45, ((char*)-1) + 1 == 0 ? 1 : -1) EVAL_EXPR(46, ((char*)-1) + 1 < (char*) -1 ? 1 : -1) EVAL_EXPR(47, &x < &x + 1 ? 1 : -1) -EVAL_EXPR(48, &x != &x - 1 ? 1 : -1) // expected-error {{declared as an array with a negative size}} +EVAL_EXPR(48, &x != &x - 1 ? 1 : -1) EVAL_EXPR(49, &x < &x - 100 ? 1 : -1) // ref-error {{not an integer constant expression}} extern struct Test50S Test50; @@ -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/AST/ByteCode/cxx11.cpp b/clang/test/AST/ByteCode/cxx11.cpp index e1fb5948b7708..91c828abd87a9 100644 --- a/clang/test/AST/ByteCode/cxx11.cpp +++ b/clang/test/AST/ByteCode/cxx11.cpp @@ -423,3 +423,15 @@ namespace DummyToGlobalBlockMove { Baz Bar::_m[] = {{0}}; const AP m = {&Bar ::m}; } + +namespace AddSubMulNonNumber { +#define fold(x) (__builtin_constant_p(x) ? (x) : (x)) + + typedef decltype(sizeof(int)) LabelDiffTy; + constexpr LabelDiffTy mulBy3(LabelDiffTy x) { return x * 3; } // both-note {{subexpression}} + void LabelDiffTest() { + static_assert(mulBy3(fold((LabelDiffTy)&&a-(LabelDiffTy)&&b)) == 3, ""); // both-error {{constant expression}} \ + // both-note {{call to 'mulBy3(&&a - &&b)'}} + a:b:return; + } +} diff --git a/clang/test/AST/ByteCode/int-as-ptr-arith.c b/clang/test/AST/ByteCode/int-as-ptr-arith.c new file mode 100644 index 0000000000000..af411607228ff --- /dev/null +++ b/clang/test/AST/ByteCode/int-as-ptr-arith.c @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -triple x86_64 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64 %s -fexperimental-new-constant-interpreter -emit-llvm -o - | FileCheck %s + +int a; +__UINTPTR_TYPE__ ptrasintadd1 = (__UINTPTR_TYPE__)&a - 4; +__UINTPTR_TYPE__ ptrasintadd2 = (__UINTPTR_TYPE__)&a + 4; +__UINTPTR_TYPE__ ptrasintadd3 = ((__UINTPTR_TYPE__)&a + 4) + 10; +__UINTPTR_TYPE__ ptrasintadd4 = (__UINTPTR_TYPE__)&a + ((__UINTPTR_TYPE__)-1); +__UINTPTR_TYPE__ ptrasintadd5 = 4 + (__UINTPTR_TYPE__)&a; +__UINTPTR_TYPE__ ptrasintadd6 = 10 + ((__UINTPTR_TYPE__)&a + 4); + +// CHECK: @ptrasintadd1 = global i64 ptrtoint (ptr getelementptr (i8, ptr @a, i64 -4) to i64) +// CHECK: @ptrasintadd2 = global i64 ptrtoint (ptr getelementptr (i8, ptr @a, i64 4) to i64) +// CHECK: @ptrasintadd3 = global i64 ptrtoint (ptr getelementptr (i8, ptr @a, i64 14) to i64) +// CHECK: @ptrasintadd4 = global i64 ptrtoint (ptr getelementptr (i8, ptr @a, i64 -1) to i64) +// CHECK: @ptrasintadd5 = global i64 ptrtoint (ptr getelementptr (i8, ptr @a, i64 4) to i64) +// CHECK: @ptrasintadd6 = global i64 ptrtoint (ptr getelementptr (i8, ptr @a, i64 14) to i64) diff --git a/clang/test/CodeGen/const-init.c b/clang/test/CodeGen/const-init.c index 175d221ad410a..930cfab1e62b5 100644 --- a/clang/test/CodeGen/const-init.c +++ b/clang/test/CodeGen/const-init.c @@ -1,5 +1,6 @@ // setting strict FP behaviour in the run line below tests that the compiler // does the right thing for global compound literals (compoundliteral test) +// RUN: %clang_cc1 -triple i386-pc-linux-gnu -ffreestanding -Wno-pointer-to-int-cast -Wno-int-conversion -ffp-exception-behavior=strict -emit-llvm -o - %s -fexperimental-new-constant-interpreter | FileCheck %s // RUN: %clang_cc1 -triple i386-pc-linux-gnu -ffreestanding -Wno-pointer-to-int-cast -Wno-int-conversion -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck %s #include <stdint.h> 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/CodeGenCXX/const-init.cpp b/clang/test/CodeGenCXX/const-init.cpp index f5b715949f23a..18ed3df22f425 100644 --- a/clang/test/CodeGenCXX/const-init.cpp +++ b/clang/test/CodeGenCXX/const-init.cpp @@ -2,6 +2,12 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -std=c++98 -o - %s | FileCheck %s // RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -std=c++11 -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fexperimental-new-constant-interpreter | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -std=c++98 -o - %s -fexperimental-new-constant-interpreter | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -std=c++11 -o - %s -fexperimental-new-constant-interpreter | FileCheck %s + + + // CHECK: @a = global i32 10 int a = 10; // CHECK: @ar = constant ptr @a diff --git a/clang/test/Sema/array-init.c b/clang/test/Sema/array-init.c index 54a7877e8f2e5..9482fa7722640 100644 --- a/clang/test/Sema/array-init.c +++ b/clang/test/Sema/array-init.c @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -std=gnu99 -fsyntax-only -pedantic -verify=expected,pedantic %s // RUN: %clang_cc1 -std=gnu99 -fsyntax-only -Wgnu -Wc11-extensions -verify %s +// RUN: %clang_cc1 -std=gnu99 -fsyntax-only -pedantic -verify=expected,pedantic %s -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -std=gnu99 -fsyntax-only -Wgnu -Wc11-extensions -verify %s -fexperimental-new-constant-interpreter // REQUIRES: LP64 extern int foof(void) = 1; // expected-error{{illegal initializer (only variables can be initialized)}} 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/Sema/const-ptr-int-ptr-cast.c b/clang/test/Sema/const-ptr-int-ptr-cast.c index 9e3db6eb6dae4..b1c06a723afc1 100644 --- a/clang/test/Sema/const-ptr-int-ptr-cast.c +++ b/clang/test/Sema/const-ptr-int-ptr-cast.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify -ffreestanding %s +// RUN: %clang_cc1 -fsyntax-only -verify -ffreestanding %s -fexperimental-new-constant-interpreter // expected-no-diagnostics typedef __UINTPTR_TYPE__ uintptr_t; diff --git a/clang/test/Sema/init.c b/clang/test/Sema/init.c index 249320f8445f5..cf3788bc21c93 100644 --- a/clang/test/Sema/init.c +++ b/clang/test/Sema/init.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 %s -Wno-pointer-to-int-cast -verify -fsyntax-only -ffreestanding +// RUN: %clang_cc1 %s -Wno-pointer-to-int-cast -verify -fsyntax-only -ffreestanding -fexperimental-new-constant-interpreter #include <stddef.h> #include <stdint.h> 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" { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
