[clang] 16b9e6f - [clang][Interp] Add IntegralAP for arbitrary-precision integers (#65844)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Sep 30 11:08:26 PDT 2023
Author: Timm Baeder
Date: 2023-09-30T20:08:22+02:00
New Revision: 16b9e6fbac4c0bd94c66e7670a41b5c266cf7bff
URL: https://github.com/llvm/llvm-project/commit/16b9e6fbac4c0bd94c66e7670a41b5c266cf7bff
DIFF: https://github.com/llvm/llvm-project/commit/16b9e6fbac4c0bd94c66e7670a41b5c266cf7bff.diff
LOG: [clang][Interp] Add IntegralAP for arbitrary-precision integers (#65844)
This adds `IntegralAP` backing the two new primtypes `IntAP` (unsigned
arbitrary-precision int) and `IntAPS` (same but signed).
We use this for `int128` support (which isn't available on all host
systems we support AFAIK) and I think we can also use this for `_BitInt`
later.
Added:
clang/lib/AST/Interp/IntegralAP.h
Modified:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/lib/AST/Interp/Context.cpp
clang/lib/AST/Interp/Descriptor.cpp
clang/lib/AST/Interp/EvalEmitter.cpp
clang/lib/AST/Interp/Integral.h
clang/lib/AST/Interp/Interp.h
clang/lib/AST/Interp/InterpStack.h
clang/lib/AST/Interp/Opcodes.td
clang/lib/AST/Interp/PrimType.cpp
clang/lib/AST/Interp/PrimType.h
clang/test/AST/Interp/literals.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 46906377863bd74..4b251931aa01d8a 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -171,14 +171,17 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return this->discard(SubExpr);
std::optional<PrimType> FromT = classify(SubExpr->getType());
std::optional<PrimType> ToT = classify(CE->getType());
+
if (!FromT || !ToT)
return false;
if (!this->visit(SubExpr))
return false;
- if (FromT == ToT)
+ if (FromT == ToT) {
+ assert(ToT != PT_IntAP && ToT != PT_IntAPS);
return true;
+ }
return this->emitCast(*FromT, *ToT, CE);
}
@@ -1638,6 +1641,9 @@ bool ByteCodeExprGen<Emitter>::visitZeroInitializer(QualType QT,
return this->emitZeroSint64(E);
case PT_Uint64:
return this->emitZeroUint64(E);
+ case PT_IntAP:
+ case PT_IntAPS:
+ assert(false);
case PT_Ptr:
return this->emitNullPtr(E);
case PT_FnPtr:
@@ -1877,6 +1883,9 @@ bool ByteCodeExprGen<Emitter>::emitConst(T Value, PrimType Ty, const Expr *E) {
return this->emitConstSint64(Value, E);
case PT_Uint64:
return this->emitConstUint64(Value, E);
+ case PT_IntAP:
+ case PT_IntAPS:
+ assert(false);
case PT_Bool:
return this->emitConstBool(Value, E);
case PT_Ptr:
diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp
index e84c0f6aae7ee93..04710cd0f2c28ee 100644
--- a/clang/lib/AST/Interp/Context.cpp
+++ b/clang/lib/AST/Interp/Context.cpp
@@ -103,7 +103,7 @@ std::optional<PrimType> Context::classify(QualType T) const {
case 8:
return PT_Sint8;
default:
- return std::nullopt;
+ return PT_IntAPS;
}
}
@@ -118,7 +118,7 @@ std::optional<PrimType> Context::classify(QualType T) const {
case 8:
return PT_Uint8;
default:
- return std::nullopt;
+ return PT_IntAP;
}
}
diff --git a/clang/lib/AST/Interp/Descriptor.cpp b/clang/lib/AST/Interp/Descriptor.cpp
index db49a569eff33ea..4ecb7466998e705 100644
--- a/clang/lib/AST/Interp/Descriptor.cpp
+++ b/clang/lib/AST/Interp/Descriptor.cpp
@@ -10,6 +10,7 @@
#include "Boolean.h"
#include "Floating.h"
#include "FunctionPointer.h"
+#include "IntegralAP.h"
#include "Pointer.h"
#include "PrimType.h"
#include "Record.h"
@@ -182,6 +183,10 @@ static BlockCtorFn getCtorPrim(PrimType Type) {
// constructor called.
if (Type == PT_Float)
return ctorTy<PrimConv<PT_Float>::T>;
+ if (Type == PT_IntAP)
+ return ctorTy<PrimConv<PT_IntAP>::T>;
+ if (Type == PT_IntAPS)
+ return ctorTy<PrimConv<PT_IntAPS>::T>;
COMPOSITE_TYPE_SWITCH(Type, return ctorTy<T>, return nullptr);
}
@@ -191,6 +196,10 @@ static BlockDtorFn getDtorPrim(PrimType Type) {
// destructor called, since they might allocate memory.
if (Type == PT_Float)
return dtorTy<PrimConv<PT_Float>::T>;
+ if (Type == PT_IntAP)
+ return dtorTy<PrimConv<PT_IntAP>::T>;
+ if (Type == PT_IntAPS)
+ return dtorTy<PrimConv<PT_IntAPS>::T>;
COMPOSITE_TYPE_SWITCH(Type, return dtorTy<T>, return nullptr);
}
diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp
index bdf800c60f1723f..f46ef1067cf52a0 100644
--- a/clang/lib/AST/Interp/EvalEmitter.cpp
+++ b/clang/lib/AST/Interp/EvalEmitter.cpp
@@ -9,6 +9,7 @@
#include "EvalEmitter.h"
#include "ByteCodeGenError.h"
#include "Context.h"
+#include "IntegralAP.h"
#include "Interp.h"
#include "Opcode.h"
#include "clang/AST/DeclCXX.h"
diff --git a/clang/lib/AST/Interp/Integral.h b/clang/lib/AST/Interp/Integral.h
index 0295a9c3b5c898c..4dbe9c9bcb14b43 100644
--- a/clang/lib/AST/Interp/Integral.h
+++ b/clang/lib/AST/Interp/Integral.h
@@ -29,6 +29,8 @@ namespace interp {
using APInt = llvm::APInt;
using APSInt = llvm::APSInt;
+template <bool Signed> class IntegralAP;
+
// Helper structure to select the representation.
template <unsigned Bits, bool Signed> struct Repr;
template <> struct Repr<8, false> { using Type = uint8_t; };
@@ -61,6 +63,8 @@ template <unsigned Bits, bool Signed> class Integral final {
template <typename T> explicit Integral(T V) : V(V) {}
public:
+ using AsUnsigned = Integral<Bits, false>;
+
/// Zero-initializes an integral.
Integral() : V(0) {}
diff --git a/clang/lib/AST/Interp/IntegralAP.h b/clang/lib/AST/Interp/IntegralAP.h
new file mode 100644
index 000000000000000..a3a8dfda020960a
--- /dev/null
+++ b/clang/lib/AST/Interp/IntegralAP.h
@@ -0,0 +1,256 @@
+//===--- Integral.h - Wrapper for numeric types for the VM ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the VM types and helpers operating on types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_INTEGRAL_AP_H
+#define LLVM_CLANG_AST_INTERP_INTEGRAL_AP_H
+
+#include "clang/AST/APValue.h"
+#include "clang/AST/ComparisonCategories.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstddef>
+#include <cstdint>
+
+#include "Primitives.h"
+
+namespace clang {
+namespace interp {
+
+using APInt = llvm::APInt;
+using APSInt = llvm::APSInt;
+template <unsigned Bits, bool Signed> class Integral;
+class Boolean;
+
+template <bool Signed> class IntegralAP final {
+public:
+ APSInt V;
+
+public:
+ using AsUnsigned = IntegralAP<false>;
+
+ template <typename T>
+ IntegralAP(T Value) : V(APInt(sizeof(T) * 8, Value, std::is_signed_v<T>)) {}
+
+ IntegralAP(APInt V) : V(V) {}
+ IntegralAP(APSInt V) : V(V) {}
+ /// Arbitrary value for initialized variables.
+ IntegralAP() : V(APSInt::getMaxValue(1024, Signed)) {}
+
+ IntegralAP operator-() const { return IntegralAP(-V); }
+ bool operator>(IntegralAP RHS) const { return V > RHS.V; }
+ bool operator>=(IntegralAP RHS) const { return V >= RHS.V; }
+ bool operator<(IntegralAP RHS) const { return V < RHS.V; }
+ bool operator<=(IntegralAP RHS) const { return V <= RHS.V; }
+
+ explicit operator bool() const { return !V.isZero(); }
+ explicit operator int8_t() const { return V.getSExtValue(); }
+ explicit operator uint8_t() const { return V.getZExtValue(); }
+ explicit operator int16_t() const { return V.getSExtValue(); }
+ explicit operator uint16_t() const { return V.getZExtValue(); }
+ explicit operator int32_t() const { return V.getSExtValue(); }
+ explicit operator uint32_t() const { return V.getZExtValue(); }
+ explicit operator int64_t() const { return V.getSExtValue(); }
+ explicit operator uint64_t() const { return V.getZExtValue(); }
+
+ template <typename T> static IntegralAP from(T Value, unsigned NumBits = 0) {
+ assert(NumBits > 0);
+ APSInt Copy = APSInt(APInt(NumBits, Value, Signed), !Signed);
+
+ return IntegralAP<Signed>(Copy);
+ }
+
+ template <bool InputSigned>
+ static IntegralAP from(IntegralAP<InputSigned> V, unsigned NumBits = 0) {
+ if constexpr (Signed == InputSigned)
+ return V;
+
+ APSInt Copy = V.V;
+ Copy.setIsSigned(Signed);
+
+ return IntegralAP<Signed>(Copy);
+ }
+
+ template <unsigned Bits, bool InputSigned>
+ static IntegralAP from(Integral<Bits, InputSigned> I) {
+ // FIXME: Take bits parameter.
+ APSInt Copy =
+ APSInt(APInt(128, static_cast<int64_t>(I), InputSigned), !Signed);
+ Copy.setIsSigned(Signed);
+
+ assert(Copy.isSigned() == Signed);
+ return IntegralAP<Signed>(Copy);
+ }
+ static IntegralAP from(const Boolean &B) {
+ assert(false);
+ return IntegralAP::zero();
+ }
+
+ static IntegralAP zero() {
+ assert(false);
+ return IntegralAP(0);
+ }
+
+ // FIXME: This can't be static if the bitwidth depends on V.
+ static constexpr unsigned bitWidth() { return 128; }
+
+ APSInt toAPSInt(unsigned Bits = 0) const { return V; }
+ APValue toAPValue() const { return APValue(V); }
+
+ bool isZero() const { return V.isZero(); }
+ bool isPositive() const { return V.isNonNegative(); }
+ bool isNegative() const { return !V.isNonNegative(); }
+ bool isMin() const { return V.isMinValue(); }
+ bool isMax() const { return V.isMaxValue(); }
+ static bool isSigned() { return Signed; }
+ bool isMinusOne() const { return Signed && V == -1; }
+
+ unsigned countLeadingZeros() const { return V.countl_zero(); }
+
+ void print(llvm::raw_ostream &OS) const { OS << V; }
+
+ IntegralAP truncate(unsigned bitWidth) const {
+ assert(false);
+ return V;
+ }
+
+ IntegralAP<false> toUnsigned() const {
+ APSInt Copy = V;
+ Copy.setIsSigned(false);
+ return IntegralAP<false>(Copy);
+ }
+
+ ComparisonCategoryResult compare(const IntegralAP &RHS) const {
+ return Compare(V, RHS.V);
+ }
+
+ static bool increment(IntegralAP A, IntegralAP *R) {
+ assert(false);
+ *R = IntegralAP(A.V + 1);
+ return false;
+ }
+
+ static bool decrement(IntegralAP A, IntegralAP *R) {
+ assert(false);
+ *R = IntegralAP(A.V - 1);
+ return false;
+ }
+
+ static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
+ return CheckAddUB(A, B, OpBits, R);
+ }
+
+ static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
+ /// FIXME: Gotta check if the result fits into OpBits bits.
+ return CheckSubUB(A, B, R);
+ }
+
+ static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
+ assert(false);
+ // return CheckMulUB(A.V, B.V, R->V);
+ return false;
+ }
+
+ static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
+ assert(false);
+ *R = IntegralAP(A.V % B.V);
+ return false;
+ }
+
+ static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
+ assert(false);
+ *R = IntegralAP(A.V / B.V);
+ return false;
+ }
+
+ static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits,
+ IntegralAP *R) {
+ assert(false);
+ *R = IntegralAP(A.V & B.V);
+ return false;
+ }
+
+ static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits,
+ IntegralAP *R) {
+ assert(false);
+ *R = IntegralAP(A.V | B.V);
+ return false;
+ }
+
+ static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits,
+ IntegralAP *R) {
+ assert(false);
+ *R = IntegralAP(A.V ^ B.V);
+ return false;
+ }
+
+ static bool neg(const IntegralAP &A, IntegralAP *R) {
+ APSInt AI = A.V;
+
+ AI.setIsSigned(Signed);
+ *R = IntegralAP(AI);
+ return false;
+ }
+
+ static bool comp(IntegralAP A, IntegralAP *R) {
+ assert(false);
+ *R = IntegralAP(~A.V);
+ return false;
+ }
+
+ static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits,
+ IntegralAP *R) {
+ *R = IntegralAP(A.V << B.V.getZExtValue());
+ }
+
+ static void shiftRight(const IntegralAP A, const IntegralAP B,
+ unsigned OpBits, IntegralAP *R) {
+ *R = IntegralAP(A.V >> B.V.getZExtValue());
+ }
+
+private:
+ static bool CheckAddUB(const IntegralAP &A, const IntegralAP &B,
+ unsigned BitWidth, IntegralAP *R) {
+ if (!A.isSigned()) {
+ R->V = A.V + B.V;
+ return false;
+ }
+
+ const APSInt &LHS = A.V;
+ const APSInt &RHS = B.V;
+
+ APSInt Value(LHS.extend(BitWidth) + RHS.extend(BitWidth), false);
+ APSInt Result = Value.trunc(LHS.getBitWidth());
+ if (Result.extend(BitWidth) != Value)
+ return true;
+
+ R->V = Result;
+ return false;
+ }
+ static bool CheckSubUB(const IntegralAP &A, const IntegralAP &B,
+ IntegralAP *R) {
+ R->V = A.V - B.V;
+ return false; // Success!
+ }
+};
+
+template <bool Signed>
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+ IntegralAP<Signed> I) {
+ I.print(OS);
+ return OS;
+}
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index dd37150b63f6db0..9d5ec3315415cf7 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -294,7 +294,11 @@ bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
return true;
} else {
S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
- return S.noteUndefinedBehavior();
+ if (!S.noteUndefinedBehavior()) {
+ S.Stk.pop<T>();
+ return false;
+ }
+ return true;
}
}
@@ -1579,7 +1583,7 @@ bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) {
S.Stk.push<T>(T(F.isNonZero()));
return true;
} else {
- APSInt Result(std::max(8u, T::bitWidth() + 1),
+ APSInt Result(std::max(8u, T::bitWidth()),
/*IsUnsigned=*/!T::isSigned());
auto Status = F.convertToInteger(Result);
@@ -1665,9 +1669,11 @@ inline bool Shr(InterpState &S, CodePtr OpPC) {
if (!CheckShift(S, OpPC, LHS, RHS, Bits))
return false;
- Integral<LT::bitWidth(), false> R;
- Integral<LT::bitWidth(), false>::shiftRight(LHS.toUnsigned(), RHS, Bits, &R);
- S.Stk.push<LT>(R);
+ typename LT::AsUnsigned R;
+ LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
+ LT::AsUnsigned::from(RHS), Bits, &R);
+ S.Stk.push<LT>(LT::from(R));
+
return true;
}
@@ -1682,9 +1688,10 @@ inline bool Shl(InterpState &S, CodePtr OpPC) {
if (!CheckShift(S, OpPC, LHS, RHS, Bits))
return false;
- Integral<LT::bitWidth(), false> R;
- Integral<LT::bitWidth(), false>::shiftLeft(LHS.toUnsigned(), RHS, Bits, &R);
- S.Stk.push<LT>(R);
+ typename LT::AsUnsigned R;
+ LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
+ LT::AsUnsigned::from(RHS), Bits, &R);
+ S.Stk.push<LT>(LT::from(R));
return true;
}
diff --git a/clang/lib/AST/Interp/InterpStack.h b/clang/lib/AST/Interp/InterpStack.h
index ab4351a6dc679fd..3fd0f63c781fc70 100644
--- a/clang/lib/AST/Interp/InterpStack.h
+++ b/clang/lib/AST/Interp/InterpStack.h
@@ -14,6 +14,7 @@
#define LLVM_CLANG_AST_INTERP_INTERPSTACK_H
#include "FunctionPointer.h"
+#include "IntegralAP.h"
#include "PrimType.h"
#include <memory>
#include <vector>
@@ -183,6 +184,10 @@ class InterpStack final {
return PT_Float;
else if constexpr (std::is_same_v<T, FunctionPointer>)
return PT_FnPtr;
+ else if constexpr (std::is_same_v<T, IntegralAP<true>>)
+ return PT_IntAP;
+ else if constexpr (std::is_same_v<T, IntegralAP<false>>)
+ return PT_IntAP;
llvm_unreachable("unknown type push()'ed into InterpStack");
}
diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index 0ce64b769b01fb7..9fc4938bb37bde8 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -25,6 +25,8 @@ def Sint32 : Type;
def Uint32 : Type;
def Sint64 : Type;
def Uint64 : Type;
+def IntAP : Type;
+def IntAPS : Type;
def Float : Type;
def Ptr : Type;
def FnPtr : Type;
@@ -67,7 +69,7 @@ class TypeClass {
def IntegerTypeClass : TypeClass {
let Types = [Sint8, Uint8, Sint16, Uint16, Sint32,
- Uint32, Sint64, Uint64];
+ Uint32, Sint64, Uint64, IntAP, IntAPS];
}
def NumberTypeClass : TypeClass {
@@ -554,11 +556,11 @@ def Comp: Opcode {
//===----------------------------------------------------------------------===//
def FromCastTypeClass : TypeClass {
- let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool];
+ let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool, IntAP, IntAPS];
}
def ToCastTypeClass : TypeClass {
- let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool];
+ let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool, IntAP, IntAPS];
}
def Cast: Opcode {
diff --git a/clang/lib/AST/Interp/PrimType.cpp b/clang/lib/AST/Interp/PrimType.cpp
index a9b5d8ea8cc8c7c..9b96dcfe6a272fc 100644
--- a/clang/lib/AST/Interp/PrimType.cpp
+++ b/clang/lib/AST/Interp/PrimType.cpp
@@ -10,6 +10,7 @@
#include "Boolean.h"
#include "Floating.h"
#include "FunctionPointer.h"
+#include "IntegralAP.h"
#include "Pointer.h"
using namespace clang;
diff --git a/clang/lib/AST/Interp/PrimType.h b/clang/lib/AST/Interp/PrimType.h
index 7c7ee6120b89a4a..8c5e87f37be1867 100644
--- a/clang/lib/AST/Interp/PrimType.h
+++ b/clang/lib/AST/Interp/PrimType.h
@@ -25,6 +25,7 @@ class Pointer;
class Boolean;
class Floating;
class FunctionPointer;
+template <bool Signed> class IntegralAP;
template <unsigned Bits, bool Signed> class Integral;
/// Enumeration of the primitive types of the VM.
@@ -37,6 +38,8 @@ enum PrimType : unsigned {
PT_Uint32,
PT_Sint64,
PT_Uint64,
+ PT_IntAP,
+ PT_IntAPS,
PT_Bool,
PT_Float,
PT_Ptr,
@@ -68,6 +71,12 @@ template <> struct PrimConv<PT_Sint32> { using T = Integral<32, true>; };
template <> struct PrimConv<PT_Uint32> { using T = Integral<32, false>; };
template <> struct PrimConv<PT_Sint64> { using T = Integral<64, true>; };
template <> struct PrimConv<PT_Uint64> { using T = Integral<64, false>; };
+template <> struct PrimConv<PT_IntAP> {
+ using T = IntegralAP<false>;
+};
+template <> struct PrimConv<PT_IntAPS> {
+ using T = IntegralAP<true>;
+};
template <> struct PrimConv<PT_Float> { using T = Floating; };
template <> struct PrimConv<PT_Bool> { using T = Boolean; };
template <> struct PrimConv<PT_Ptr> { using T = Pointer; };
@@ -108,6 +117,8 @@ static inline bool aligned(const void *P) {
TYPE_SWITCH_CASE(PT_Uint32, B) \
TYPE_SWITCH_CASE(PT_Sint64, B) \
TYPE_SWITCH_CASE(PT_Uint64, B) \
+ TYPE_SWITCH_CASE(PT_IntAP, B) \
+ TYPE_SWITCH_CASE(PT_IntAPS, B) \
TYPE_SWITCH_CASE(PT_Float, B) \
TYPE_SWITCH_CASE(PT_Bool, B) \
TYPE_SWITCH_CASE(PT_Ptr, B) \
@@ -126,6 +137,8 @@ static inline bool aligned(const void *P) {
TYPE_SWITCH_CASE(PT_Uint32, B) \
TYPE_SWITCH_CASE(PT_Sint64, B) \
TYPE_SWITCH_CASE(PT_Uint64, B) \
+ TYPE_SWITCH_CASE(PT_IntAP, B) \
+ TYPE_SWITCH_CASE(PT_IntAPS, B) \
TYPE_SWITCH_CASE(PT_Bool, B) \
default: \
llvm_unreachable("Not an integer value"); \
diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index ceda59405ea9105..0dd036353fa7efd 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -7,6 +7,8 @@
#define INT_MAX __INT_MAX__
typedef __INTPTR_TYPE__ intptr_t;
+typedef __int128 int128_t;
+typedef unsigned __int128 uint128_t;
static_assert(true, "");
@@ -26,6 +28,66 @@ static_assert(number != 10, ""); // expected-error{{failed}} \
// expected-note{{evaluates to}} \
// ref-note{{evaluates to}}
+
+namespace i128 {
+ constexpr int128_t I128_1 = 12;
+ static_assert(I128_1 == 12, "");
+ static_assert(I128_1 != 10, "");
+ static_assert(I128_1 != 12, ""); // expected-error{{failed}} \
+ // ref-error{{failed}} \
+ // expected-note{{evaluates to}} \
+ // ref-note{{evaluates to}}
+
+ static const __uint128_t UINT128_MAX =__uint128_t(__int128_t(-1L));
+ static_assert(UINT128_MAX == -1, "");
+
+ static const __int128_t INT128_MAX = UINT128_MAX >> (__int128_t)1;
+ static_assert(INT128_MAX != 0, "");
+ static const __int128_t INT128_MIN = -INT128_MAX - 1;
+ constexpr __int128 A = INT128_MAX + 1; // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{outside the range}} \
+ // ref-error {{must be initialized by a constant expression}} \
+ // ref-note {{outside the range}}
+ constexpr int128_t Two = (int128_t)1 << 1ul;
+ static_assert(Two == 2, "");
+
+#if __cplusplus >= 201402L
+ template <typename T>
+ constexpr T CastFrom(__int128_t A) {
+ T B = (T)A;
+ return B;
+ }
+ static_assert(CastFrom<char>(12) == 12, "");
+ static_assert(CastFrom<unsigned char>(12) == 12, "");
+ static_assert(CastFrom<long>(12) == 12, "");
+ static_assert(CastFrom<unsigned short>(12) == 12, "");
+ static_assert(CastFrom<int128_t>(12) == 12, "");
+ static_assert(CastFrom<float>(12) == 12, "");
+ static_assert(CastFrom<double>(12) == 12, "");
+ static_assert(CastFrom<long double>(12) == 12, "");
+
+ template <typename T>
+ constexpr __int128 CastTo(T A) {
+ int128_t B = (int128_t)A;
+ return B;
+ }
+ static_assert(CastTo<char>(12) == 12, "");
+ static_assert(CastTo<unsigned char>(12) == 12, "");
+ static_assert(CastTo<long>(12) == 12, "");
+ static_assert(CastTo<unsigned long long>(12) == 12, "");
+ static_assert(CastTo<float>(12) == 12, "");
+ static_assert(CastTo<double>(12) == 12, "");
+ static_assert(CastTo<long double>(12) == 12, "");
+#endif
+
+constexpr int128_t Error = __LDBL_MAX__; // ref-warning {{implicit conversion of out of range value}} \
+ // ref-error {{must be initialized by a constant expression}} \
+ // ref-note {{is outside the range of representable values of type}} \
+ // expected-warning {{implicit conversion of out of range value}} \
+ // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{is outside the range of representable values of type}}
+}
+
constexpr bool b = number;
static_assert(b, "");
constexpr int one = true;
More information about the cfe-commits
mailing list