[clang] [X86] Allow PSHUFD/PSHUFLW/PSHUFW intrinsics to be used in constexpr (#156611) (PR #161094)
Nagraj Gaonkar via cfe-commits
cfe-commits at lists.llvm.org
Sun Sep 28 13:21:40 PDT 2025
https://github.com/NagrajMG created https://github.com/llvm/llvm-project/pull/161094
## [Headers][X86] Allow PSHUFD/PSHUFLW/PSHUFW shuffle intrinsics to be used in `constexpr`
### PSHUFW — shuffle 4×i16 in MMX (64-bit)
| Intrinsic | X86 Builtin | CPUID Flags | Header |
|-----------|------------------------|------------|---------------|
| `_mm_shuffle_pi16` | `__builtin_ia32_pshufw` | MMX | `mmintrin.h` |
---
### PSHUFLW — shuffle low 4×i16 per 128-bit lane
| Intrinsics | X86 Builtins | CPUID Flags | Header |
|-----------|--------------|------------|-------|
| `_mm_shufflelo_epi16` | `__builtin_ia32_pshuflw` | SSE2 | `emmintrin.h` |
| `_mm256_shufflelo_epi16` | `__builtin_ia32_pshuflw256` | AVX2 | `avx2intrin.h` |
| `_mm512_shufflelo_epi16` | `__builtin_ia32_pshuflw512` | AVX-512BW | `avx512bwintrin.h` |
| `_mm_mask_shufflelo_epi16` | `__builtin_ia32_pshuflw128_mask` | AVX-512VL+BW | `avx512vlbwintrin.h` |
| `_mm256_mask_shufflelo_epi16` | `__builtin_ia32_pshuflw256_mask` | AVX-512VL+BW | `avx512vlbwintrin.h` |
| `_mm512_mask_shufflelo_epi16` | `__builtin_ia32_pshuflw512_mask` | AVX-512BW | `avx512bwintrin.h` |
| `_mm_maskz_shufflelo_epi16` | `__builtin_ia32_pshuflw128_maskz` | AVX-512VL+BW | `avx512vlbwintrin.h` |
| `_mm256_maskz_shufflelo_epi16` | `__builtin_ia32_pshuflw256_maskz` | AVX-512VL+BW | `avx512vlbwintrin.h` |
| `_mm512_maskz_shufflelo_epi16` | `__builtin_ia32_pshuflw512_maskz` | AVX-512BW | `avx512bwintrin.h` |
---
### PSHUFHW — shuffle high 4×i16 per 128-bit lane
| Intrinsics | X86 Builtins | CPUID Flags | Header |
|-----------|--------------|------------|-------|
| `_mm_shufflehi_epi16` | `__builtin_ia32_pshufhw` | SSE2 | `emmintrin.h` |
| `_mm256_shufflehi_epi16` | `__builtin_ia32_pshufhw256` | AVX2 | `avx2intrin.h` |
| `_mm512_shufflehi_epi16` | `__builtin_ia32_pshufhw512` | AVX-512BW | `avx512bwintrin.h` |
| `_mm_mask_shufflehi_epi16` | `__builtin_ia32_pshufhw128_mask` | AVX-512VL+BW | `avx512vlbwintrin.h` |
| `_mm256_mask_shufflehi_epi16` | `__builtin_ia32_pshufhw256_mask` | AVX-512VL+BW | `avx512vlbwintrin.h` |
| `_mm512_mask_shufflehi_epi16` | `__builtin_ia32_pshufhw512_mask` | AVX-512BW | `avx512bwintrin.h` |
| `_mm_maskz_shufflehi_epi16` | `__builtin_ia32_pshufhw128_maskz` | AVX-512VL+BW | `avx512vlbwintrin.h` |
| `_mm256_maskz_shufflehi_epi16` | `__builtin_ia32_pshufhw256_maskz` | AVX-512VL+BW | `avx512vlbwintrin.h` |
| `_mm512_maskz_shufflehi_epi16` | `__builtin_ia32_pshufhw512_maskz` | AVX-512BW | `avx512bwintrin.h` |
---
### PSHUFD — shuffle 4×i32 per 128-bit lane
| Intrinsics | X86 Builtins | CPUID Flags | Header |
|-----------|--------------|------------|-------|
| `_mm_shuffle_epi32` | `__builtin_ia32_pshufd` | SSE2 | `emmintrin.h` |
| `_mm256_shuffle_epi32` | `__builtin_ia32_pshufd256` | AVX2 | `avx2intrin.h` |
| `_mm512_shuffle_epi32` | `__builtin_ia32_pshufd512` | AVX-512F | `avx512fintrin.h` |
| `_mm_mask_shuffle_epi32` | `__builtin_ia32_pshufd128_mask` | AVX-512VL | `avx512vlintrin.h` |
| `_mm256_mask_shuffle_epi32` | `__builtin_ia32_pshufd256_mask` | AVX-512VL | `avx512vlintrin.h` |
| `_mm512_mask_shuffle_epi32` | `__builtin_ia32_pshufd512_mask` | AVX-512F | `avx512fintrin.h` |
| `_mm_maskz_shuffle_epi32` | `__builtin_ia32_pshufd128_maskz` | AVX-512VL | `avx512vlintrin.h` |
| `_mm256_maskz_shuffle_epi32` | `__builtin_ia32_pshufd256_maskz` | AVX-512VL | `avx512vlintrin.h` |
| `_mm512_maskz_shuffle_epi32` | `__builtin_ia32_pshufd512_maskz` | AVX-512F | `avx512fintrin.h` |
---
Fixes **#156611**
Adds constexpr evaluation to these intrinsics in both the **ExprConstant** evaluator and the **Bytecode Interpreter**, with tests for all unmasked, masked, and mask-zero variants across MMX, 128-bit, 256-bit, and 512-bit widths.
>From 51d2633b9f97b139728f21c2aad86877b6211948 Mon Sep 17 00:00:00 2001
From: NagrajMG <nagrajgaonkarmumbai749 at gmail.com>
Date: Mon, 29 Sep 2025 00:34:03 +0530
Subject: [PATCH 1/3] [X86] Allow PSHUFD/PSHUFLW/PSHUFW intrinsics in constexpr
Summary: Implements InterpBuiltin support and adds CodeGen tests. Issue:
#156611
---
clang/include/clang/Basic/BuiltinsX86.td | 63 +-
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 245 +
clang/lib/AST/ExprConstant.cpp | 4390 ++++++++++--------
clang/lib/Headers/mmintrin.h | 5 +
clang/test/CodeGen/X86/avx2-builtins.c | 4 +
clang/test/CodeGen/X86/avx512bw-builtins.c | 11 +-
clang/test/CodeGen/X86/avx512f-builtins.c | 13 +
clang/test/CodeGen/X86/avx512vl-builtins.c | 19 +
clang/test/CodeGen/X86/avx512vlbw-builtins.c | 60 +-
clang/test/CodeGen/X86/mmx-builtins.c | 2 +-
clang/test/CodeGen/X86/sse2-builtins.c | 15 +-
11 files changed, 2761 insertions(+), 2066 deletions(-)
diff --git a/clang/include/clang/Basic/BuiltinsX86.td b/clang/include/clang/Basic/BuiltinsX86.td
index 77e599587edc3..33d4d07fcfb5c 100644
--- a/clang/include/clang/Basic/BuiltinsX86.td
+++ b/clang/include/clang/Basic/BuiltinsX86.td
@@ -145,6 +145,10 @@ let Features = "mmx", Header = "mmintrin.h", Attributes = [NoThrow, Const] in {
def _m_prefetch : X86LibBuiltin<"void(void *)">;
}
+let Features = "mmx", Attributes = [NoThrow, Const, Constexpr] in {
+ def pshufw : X86Builtin<"_Vector<4, short>(_Vector<4, short>, _Constant int)">;
+}
+
// PRFCHW
let Features = "prfchw", Header = "intrin.h", Attributes = [NoThrow, Const] in {
def _m_prefetchw : X86LibBuiltin<"void(void volatile const *)">;
@@ -217,10 +221,13 @@ let Features = "sse2", Attributes = [NoThrow] in {
def movnti : X86Builtin<"void(int *, int)">;
}
-let Features = "sse2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def pshufd : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Constant int)">;
+let Features = "sse2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in {
def pshuflw : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Constant int)">;
+ def pshufd : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Constant int)">;
def pshufhw : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Constant int)">;
+}
+
+let Features = "sse2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
def psadbw128 : X86Builtin<"_Vector<2, long long int>(_Vector<16, char>, _Vector<16, char>)">;
def sqrtpd : X86Builtin<"_Vector<2, double>(_Vector<2, double>)">;
def sqrtsd : X86Builtin<"_Vector<2, double>(_Vector<2, double>)">;
@@ -569,6 +576,12 @@ let Features = "avx", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in
def vec_set_v8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, int, _Constant int)">;
}
+let Features = "avx2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
+ def pshuflw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Constant int)">;
+ def pshufhw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Constant int)">;
+ def pshufd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Constant int)">;
+}
+
let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
def mpsadbw256 : X86Builtin<"_Vector<32, char>(_Vector<32, char>, _Vector<32, char>, _Constant char)">;
def palignr256 : X86Builtin<"_Vector<32, char>(_Vector<32, char>, _Vector<32, char>, _Constant int)">;
@@ -584,9 +597,6 @@ let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] i
def pmulhrsw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>)">;
def psadbw256 : X86Builtin<"_Vector<4, long long int>(_Vector<32, char>, _Vector<32, char>)">;
def pshufb256 : X86Builtin<"_Vector<32, char>(_Vector<32, char>, _Vector<32, char>)">;
- def pshufd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Constant int)">;
- def pshuflw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Constant int)">;
- def pshufhw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Constant int)">;
def psignb256 : X86Builtin<"_Vector<32, char>(_Vector<32, char>, _Vector<32, char>)">;
def psignw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>)">;
def psignd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
@@ -1989,9 +1999,28 @@ let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVect
def prorq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Constant int)">;
}
-let Features = "avx512bw", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
+let Features = "avx512bw", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in {
def pshufhw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Constant int)">;
def pshuflw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Constant int)">;
+}
+
+let Features = "avx512f", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in {
+ def pshufd512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Constant int)">;
+ def pshufd512_mask : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Constant int, _Vector<16, int>, unsigned short)">;
+ def pshufd512_maskz : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Constant int, unsigned short)">;
+}
+
+let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
+ def pshufd256_mask : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Constant int, _Vector<8, int>, unsigned char)">;
+ def pshufd256_maskz : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Constant int, unsigned char)">;
+}
+
+let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in {
+ def pshufd128_mask : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Constant int, _Vector<4, int>, unsigned char)">;
+ def pshufd128_maskz : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Constant int, unsigned char)">;
+}
+
+let Features = "avx512bw", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
def psllw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<8, short>)">;
}
@@ -3266,7 +3295,6 @@ let Features = "avx512f", Attributes = [NoThrow, Const, RequiredVectorWidth<128>
}
let Features = "avx512f", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
- def pshufd512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Constant int)">;
def expanddf512_mask : X86Builtin<"_Vector<8, double>(_Vector<8, double>, _Vector<8, double>, unsigned char)">;
def expanddi512_mask : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Vector<8, long long int>, unsigned char)">;
}
@@ -5114,3 +5142,24 @@ let Features = "avx10.2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>
let Features = "avx10.2", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
def vsqrtbf16512 : X86Builtin<"_Vector<32, __bf16>(_Vector<32, __bf16>)">;
}
+
+let Features = "avx512bw", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in {
+ def pshuflw512_mask : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Constant int, _Vector<32, short>, unsigned int)">;
+ def pshuflw512_maskz : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Constant int, unsigned int)">;
+ def pshufhw512_mask : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Constant int, _Vector<32, short>, unsigned int)">;
+ def pshufhw512_maskz : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Constant int, unsigned int)">;
+}
+
+let Features = "avx512vl,avx512bw", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
+ def pshuflw256_mask : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Constant int, _Vector<16, short>, unsigned short)">;
+ def pshuflw256_maskz : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Constant int, unsigned short)">;
+ def pshufhw256_mask : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Constant int, _Vector<16, short>, unsigned short)">;
+ def pshufhw256_maskz : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Constant int, unsigned short)">;
+}
+
+let Features = "avx512vl,avx512bw", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in {
+ def pshuflw128_mask : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Constant int, _Vector<8, short>, unsigned char)">;
+ def pshuflw128_maskz : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Constant int, unsigned char)">;
+ def pshufhw128_mask : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Constant int, _Vector<8, short>, unsigned char)">;
+ def pshufhw128_maskz : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Constant int, unsigned char)">;
+}
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 891344d4e6ed0..e3b9acac6075e 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -2862,6 +2862,218 @@ static bool interp__builtin_blend(InterpState &S, CodePtr OpPC,
return true;
}
+static bool interp__builtin_ia32_pshuflw_common(InterpState &S, CodePtr OpPC,
+ const CallExpr *Call) {
+ const unsigned NumArgs = Call->getNumArgs();
+ assert(NumArgs == 2 || NumArgs == 3 || NumArgs == 4);
+ APSInt K;
+ Pointer SrcPT;
+ const bool HasMask = (NumArgs == 3) || (NumArgs == 4);
+ const bool IsMaskZ = (NumArgs == 3);
+ if (NumArgs == 4) {
+ K = popToAPSInt(S, Call->getArg(3));
+ SrcPT = S.Stk.pop<Pointer>();
+ } else if (NumArgs == 3) {
+ K = popToAPSInt(S, Call->getArg(2));
+ }
+
+ APSInt Imm = popToAPSInt(S, Call->getArg(1));
+ const Pointer &Src = S.Stk.pop<Pointer>();
+ const Pointer &Dst = S.Stk.peek<Pointer>();
+ const unsigned NumElems = Dst.getNumElems();
+ const PrimType ElemT = Dst.getFieldDesc()->getPrimType();
+ const unsigned ElemBits = 16;
+ const unsigned LaneElems = 128u / ElemBits;
+ const unsigned Half = 4;
+ assert(NumElems % LaneElems == 0 && "pshuflw expects 128-bit lanes");
+ const uint8_t Ctl = static_cast<uint8_t>(Imm.getZExtValue());
+
+ for (unsigned i = 0; i != NumElems; ++i) {
+ const unsigned laneBase = (i / LaneElems) * LaneElems;
+ const unsigned inLane = i % LaneElems;
+
+ unsigned srcIdx;
+ if (inLane < Half) {
+ const unsigned pos = inLane;
+ const unsigned sel = (Ctl >> (2 * pos)) & 0x3;
+ srcIdx = laneBase + sel;
+ } else {
+ srcIdx = i;
+ }
+
+ APSInt Chosen;
+ INT_TYPE_SWITCH(ElemT, { Chosen = Src.elem<T>(srcIdx).toAPSInt(); });
+
+ if (!HasMask) {
+ INT_TYPE_SWITCH_NO_BOOL(ElemT,
+ { Dst.elem<T>(i) = static_cast<T>(Chosen); });
+ continue;
+ }
+
+ const bool Keep =
+ (i < static_cast<unsigned>(K.getBitWidth())) ? K[i] : false;
+
+ if (Keep) {
+ INT_TYPE_SWITCH_NO_BOOL(ElemT,
+ { Dst.elem<T>(i) = static_cast<T>(Chosen); });
+ } else if (IsMaskZ) {
+ APSInt Zero(APInt(Chosen.getBitWidth(), 0));
+ Zero.setIsSigned(Chosen.isSigned());
+ INT_TYPE_SWITCH_NO_BOOL(ElemT,
+ { Dst.elem<T>(i) = static_cast<T>(Zero); });
+ } else {
+ APSInt PT;
+ INT_TYPE_SWITCH(ElemT, { PT = SrcPT.elem<T>(i).toAPSInt(); });
+ INT_TYPE_SWITCH_NO_BOOL(ElemT, { Dst.elem<T>(i) = static_cast<T>(PT); });
+ }
+ }
+
+ Dst.initializeAllElements();
+ return true;
+}
+
+static bool interp__builtin_ia32_pshufhw_common(InterpState &S, CodePtr OpPC,
+ const CallExpr *Call) {
+ (void)OpPC;
+ const unsigned NumArgs = Call->getNumArgs();
+ assert(NumArgs == 2 || NumArgs == 3 || NumArgs == 4);
+
+ APSInt K;
+ Pointer SrcPT;
+ const bool HasMask = (NumArgs == 3) || (NumArgs == 4);
+ const bool IsMaskZ = (NumArgs == 3);
+
+ if (NumArgs == 4) {
+ K = popToAPSInt(S, Call->getArg(3));
+ SrcPT = S.Stk.pop<Pointer>();
+ } else if (NumArgs == 3) {
+ K = popToAPSInt(S, Call->getArg(2));
+ }
+
+ APSInt Imm = popToAPSInt(S, Call->getArg(1));
+ const Pointer &Src = S.Stk.pop<Pointer>();
+ const Pointer &Dst = S.Stk.peek<Pointer>();
+
+ const unsigned NumElems = Dst.getNumElems();
+ const PrimType ElemT = Dst.getFieldDesc()->getPrimType();
+
+ const unsigned ElemBits = 16;
+ const unsigned LaneElems = 128u / ElemBits;
+ const unsigned HalfBase = 4;
+ assert(NumElems % LaneElems == 0);
+
+ const uint8_t Ctl = static_cast<uint8_t>(Imm.getZExtValue());
+
+ for (unsigned i = 0; i != NumElems; ++i) {
+ const unsigned laneBase = (i / LaneElems) * LaneElems;
+ const unsigned inLane = i % LaneElems;
+
+ unsigned srcIdx;
+ if (inLane >= HalfBase) {
+ const unsigned pos = inLane - HalfBase;
+ const unsigned sel = (Ctl >> (2 * pos)) & 0x3;
+ srcIdx = laneBase + HalfBase + sel;
+ } else {
+ srcIdx = i;
+ }
+
+ APSInt Chosen;
+ INT_TYPE_SWITCH(ElemT, { Chosen = Src.elem<T>(srcIdx).toAPSInt(); });
+
+ if (!HasMask) {
+ INT_TYPE_SWITCH_NO_BOOL(ElemT,
+ { Dst.elem<T>(i) = static_cast<T>(Chosen); });
+ continue;
+ }
+
+ const bool Keep =
+ (i < static_cast<unsigned>(K.getBitWidth())) ? K[i] : false;
+ if (Keep) {
+ INT_TYPE_SWITCH_NO_BOOL(ElemT,
+ { Dst.elem<T>(i) = static_cast<T>(Chosen); });
+ } else if (IsMaskZ) {
+ APSInt Zero(APInt(Chosen.getBitWidth(), 0));
+ Zero.setIsSigned(Chosen.isSigned());
+ INT_TYPE_SWITCH_NO_BOOL(ElemT,
+ { Dst.elem<T>(i) = static_cast<T>(Zero); });
+ } else {
+ APSInt PT;
+ INT_TYPE_SWITCH(ElemT, { PT = SrcPT.elem<T>(i).toAPSInt(); });
+ INT_TYPE_SWITCH_NO_BOOL(ElemT, { Dst.elem<T>(i) = static_cast<T>(PT); });
+ }
+ }
+
+ Dst.initializeAllElements();
+ return true;
+}
+
+static bool interp__builtin_ia32_pshufd_common(InterpState &S, CodePtr OpPC,
+ const CallExpr *Call) {
+ (void)OpPC;
+ const unsigned NumArgs = Call->getNumArgs();
+ assert(NumArgs == 2 || NumArgs == 3 || NumArgs == 4);
+
+ APSInt K;
+ Pointer SrcPT;
+ const bool HasMask = (NumArgs == 3) || (NumArgs == 4);
+ const bool IsMaskZ = (NumArgs == 3);
+
+ if (NumArgs == 4) {
+ K = popToAPSInt(S, Call->getArg(3));
+ SrcPT = S.Stk.pop<Pointer>();
+ } else if (NumArgs == 3) {
+ K = popToAPSInt(S, Call->getArg(2));
+ }
+
+ APSInt Imm = popToAPSInt(S, Call->getArg(1));
+ const Pointer &Src = S.Stk.pop<Pointer>();
+ const Pointer &Dst = S.Stk.peek<Pointer>();
+
+ const unsigned NumElems = Dst.getNumElems();
+ const PrimType ElemT = Dst.getFieldDesc()->getPrimType();
+
+ const unsigned ElemBits = 32;
+ const unsigned LaneElems = 128u / ElemBits;
+ assert(NumElems % LaneElems == 0);
+
+ const uint8_t Ctl = static_cast<uint8_t>(Imm.getZExtValue());
+
+ for (unsigned i = 0; i != NumElems; ++i) {
+ const unsigned laneBase = (i / LaneElems) * LaneElems;
+ const unsigned inLane = i % LaneElems;
+ const unsigned sel = (Ctl >> (2 * inLane)) & 0x3;
+ const unsigned srcIdx = laneBase + sel;
+
+ APSInt Chosen;
+ INT_TYPE_SWITCH(ElemT, { Chosen = Src.elem<T>(srcIdx).toAPSInt(); });
+
+ if (!HasMask) {
+ INT_TYPE_SWITCH_NO_BOOL(ElemT,
+ { Dst.elem<T>(i) = static_cast<T>(Chosen); });
+ continue;
+ }
+
+ const bool Keep =
+ (i < static_cast<unsigned>(K.getBitWidth())) ? K[i] : false;
+ if (Keep) {
+ INT_TYPE_SWITCH_NO_BOOL(ElemT,
+ { Dst.elem<T>(i) = static_cast<T>(Chosen); });
+ } else if (IsMaskZ) {
+ APSInt Zero(APInt(Chosen.getBitWidth(), 0));
+ Zero.setIsSigned(Chosen.isSigned());
+ INT_TYPE_SWITCH_NO_BOOL(ElemT,
+ { Dst.elem<T>(i) = static_cast<T>(Zero); });
+ } else {
+ APSInt PT;
+ INT_TYPE_SWITCH(ElemT, { PT = SrcPT.elem<T>(i).toAPSInt(); });
+ INT_TYPE_SWITCH_NO_BOOL(ElemT, { Dst.elem<T>(i) = static_cast<T>(PT); });
+ }
+ }
+
+ Dst.initializeAllElements();
+ return true;
+}
+
static bool interp__builtin_elementwise_triop(
InterpState &S, CodePtr OpPC, const CallExpr *Call,
llvm::function_ref<APInt(const APSInt &, const APSInt &, const APSInt &)>
@@ -3417,6 +3629,39 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
return interp__builtin_elementwise_int_binop(S, OpPC, Call,
llvm::APIntOps::mulhs);
+ case clang::X86::BI__builtin_ia32_pshuflw:
+ case clang::X86::BI__builtin_ia32_pshuflw256:
+ case clang::X86::BI__builtin_ia32_pshuflw512:
+ case clang::X86::BI__builtin_ia32_pshuflw128_mask:
+ case clang::X86::BI__builtin_ia32_pshuflw256_mask:
+ case clang::X86::BI__builtin_ia32_pshuflw512_mask:
+ case clang::X86::BI__builtin_ia32_pshuflw128_maskz:
+ case clang::X86::BI__builtin_ia32_pshuflw256_maskz:
+ case clang::X86::BI__builtin_ia32_pshuflw512_maskz:
+ return interp__builtin_ia32_pshuflw_common(S, OpPC, Call);
+
+ case clang::X86::BI__builtin_ia32_pshufhw:
+ case clang::X86::BI__builtin_ia32_pshufhw256:
+ case clang::X86::BI__builtin_ia32_pshufhw512:
+ case clang::X86::BI__builtin_ia32_pshufhw128_mask:
+ case clang::X86::BI__builtin_ia32_pshufhw256_mask:
+ case clang::X86::BI__builtin_ia32_pshufhw512_mask:
+ case clang::X86::BI__builtin_ia32_pshufhw128_maskz:
+ case clang::X86::BI__builtin_ia32_pshufhw256_maskz:
+ case clang::X86::BI__builtin_ia32_pshufhw512_maskz:
+ return interp__builtin_ia32_pshufhw_common(S, OpPC, Call);
+
+ case clang::X86::BI__builtin_ia32_pshufd:
+ case clang::X86::BI__builtin_ia32_pshufd256:
+ case clang::X86::BI__builtin_ia32_pshufd512:
+ case clang::X86::BI__builtin_ia32_pshufd128_mask:
+ case clang::X86::BI__builtin_ia32_pshufd256_mask:
+ case clang::X86::BI__builtin_ia32_pshufd512_mask:
+ case clang::X86::BI__builtin_ia32_pshufd128_maskz:
+ case clang::X86::BI__builtin_ia32_pshufd256_maskz:
+ case clang::X86::BI__builtin_ia32_pshufd512_maskz:
+ return interp__builtin_ia32_pshufd_common(S, OpPC, Call);
+
case clang::X86::BI__builtin_ia32_psllv2di:
case clang::X86::BI__builtin_ia32_psllv4di:
case clang::X86::BI__builtin_ia32_psllv4si:
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index b706b14945b6d..c1362200ee907 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -73,667 +73,651 @@
using namespace clang;
using llvm::APFixedPoint;
+using llvm::APFloat;
using llvm::APInt;
using llvm::APSInt;
-using llvm::APFloat;
using llvm::FixedPointSemantics;
namespace {
- struct LValue;
- class CallStackFrame;
- class EvalInfo;
+struct LValue;
+class CallStackFrame;
+class EvalInfo;
- using SourceLocExprScopeGuard =
- CurrentSourceLocExprScope::SourceLocExprScopeGuard;
+using SourceLocExprScopeGuard =
+ CurrentSourceLocExprScope::SourceLocExprScopeGuard;
- static QualType getType(APValue::LValueBase B) {
- return B.getType();
- }
+static QualType getType(APValue::LValueBase B) { return B.getType(); }
- /// Get an LValue path entry, which is known to not be an array index, as a
- /// field declaration.
- static const FieldDecl *getAsField(APValue::LValuePathEntry E) {
- return dyn_cast_or_null<FieldDecl>(E.getAsBaseOrMember().getPointer());
- }
- /// Get an LValue path entry, which is known to not be an array index, as a
- /// base class declaration.
- static const CXXRecordDecl *getAsBaseClass(APValue::LValuePathEntry E) {
- return dyn_cast_or_null<CXXRecordDecl>(E.getAsBaseOrMember().getPointer());
- }
- /// Determine whether this LValue path entry for a base class names a virtual
- /// base class.
- static bool isVirtualBaseClass(APValue::LValuePathEntry E) {
- return E.getAsBaseOrMember().getInt();
- }
+/// Get an LValue path entry, which is known to not be an array index, as a
+/// field declaration.
+static const FieldDecl *getAsField(APValue::LValuePathEntry E) {
+ return dyn_cast_or_null<FieldDecl>(E.getAsBaseOrMember().getPointer());
+}
+/// Get an LValue path entry, which is known to not be an array index, as a
+/// base class declaration.
+static const CXXRecordDecl *getAsBaseClass(APValue::LValuePathEntry E) {
+ return dyn_cast_or_null<CXXRecordDecl>(E.getAsBaseOrMember().getPointer());
+}
+/// Determine whether this LValue path entry for a base class names a virtual
+/// base class.
+static bool isVirtualBaseClass(APValue::LValuePathEntry E) {
+ return E.getAsBaseOrMember().getInt();
+}
- /// Given an expression, determine the type used to store the result of
- /// evaluating that expression.
- static QualType getStorageType(const ASTContext &Ctx, const Expr *E) {
- if (E->isPRValue())
- return E->getType();
- return Ctx.getLValueReferenceType(E->getType());
- }
+/// Given an expression, determine the type used to store the result of
+/// evaluating that expression.
+static QualType getStorageType(const ASTContext &Ctx, const Expr *E) {
+ if (E->isPRValue())
+ return E->getType();
+ return Ctx.getLValueReferenceType(E->getType());
+}
- /// Attempts to unwrap a CallExpr (with an alloc_size attribute) from an Expr.
- /// This will look through a single cast.
- ///
- /// Returns null if we couldn't unwrap a function with alloc_size.
- static const CallExpr *tryUnwrapAllocSizeCall(const Expr *E) {
- if (!E->getType()->isPointerType())
- return nullptr;
+/// Attempts to unwrap a CallExpr (with an alloc_size attribute) from an Expr.
+/// This will look through a single cast.
+///
+/// Returns null if we couldn't unwrap a function with alloc_size.
+static const CallExpr *tryUnwrapAllocSizeCall(const Expr *E) {
+ if (!E->getType()->isPointerType())
+ return nullptr;
- E = E->IgnoreParens();
- // If we're doing a variable assignment from e.g. malloc(N), there will
- // probably be a cast of some kind. In exotic cases, we might also see a
- // top-level ExprWithCleanups. Ignore them either way.
- if (const auto *FE = dyn_cast<FullExpr>(E))
- E = FE->getSubExpr()->IgnoreParens();
+ E = E->IgnoreParens();
+ // If we're doing a variable assignment from e.g. malloc(N), there will
+ // probably be a cast of some kind. In exotic cases, we might also see a
+ // top-level ExprWithCleanups. Ignore them either way.
+ if (const auto *FE = dyn_cast<FullExpr>(E))
+ E = FE->getSubExpr()->IgnoreParens();
- if (const auto *Cast = dyn_cast<CastExpr>(E))
- E = Cast->getSubExpr()->IgnoreParens();
+ if (const auto *Cast = dyn_cast<CastExpr>(E))
+ E = Cast->getSubExpr()->IgnoreParens();
- if (const auto *CE = dyn_cast<CallExpr>(E))
- return CE->getCalleeAllocSizeAttr() ? CE : nullptr;
- return nullptr;
- }
+ if (const auto *CE = dyn_cast<CallExpr>(E))
+ return CE->getCalleeAllocSizeAttr() ? CE : nullptr;
+ return nullptr;
+}
- /// Determines whether or not the given Base contains a call to a function
- /// with the alloc_size attribute.
- static bool isBaseAnAllocSizeCall(APValue::LValueBase Base) {
- const auto *E = Base.dyn_cast<const Expr *>();
- return E && E->getType()->isPointerType() && tryUnwrapAllocSizeCall(E);
- }
+/// Determines whether or not the given Base contains a call to a function
+/// with the alloc_size attribute.
+static bool isBaseAnAllocSizeCall(APValue::LValueBase Base) {
+ const auto *E = Base.dyn_cast<const Expr *>();
+ return E && E->getType()->isPointerType() && tryUnwrapAllocSizeCall(E);
+}
- /// Determines whether the given kind of constant expression is only ever
- /// used for name mangling. If so, it's permitted to reference things that we
- /// can't generate code for (in particular, dllimported functions).
- static bool isForManglingOnly(ConstantExprKind Kind) {
- switch (Kind) {
- case ConstantExprKind::Normal:
- case ConstantExprKind::ClassTemplateArgument:
- case ConstantExprKind::ImmediateInvocation:
- // Note that non-type template arguments of class type are emitted as
- // template parameter objects.
- return false;
+/// Determines whether the given kind of constant expression is only ever
+/// used for name mangling. If so, it's permitted to reference things that we
+/// can't generate code for (in particular, dllimported functions).
+static bool isForManglingOnly(ConstantExprKind Kind) {
+ switch (Kind) {
+ case ConstantExprKind::Normal:
+ case ConstantExprKind::ClassTemplateArgument:
+ case ConstantExprKind::ImmediateInvocation:
+ // Note that non-type template arguments of class type are emitted as
+ // template parameter objects.
+ return false;
- case ConstantExprKind::NonClassTemplateArgument:
- return true;
- }
- llvm_unreachable("unknown ConstantExprKind");
+ case ConstantExprKind::NonClassTemplateArgument:
+ return true;
}
+ llvm_unreachable("unknown ConstantExprKind");
+}
- static bool isTemplateArgument(ConstantExprKind Kind) {
- switch (Kind) {
- case ConstantExprKind::Normal:
- case ConstantExprKind::ImmediateInvocation:
- return false;
+static bool isTemplateArgument(ConstantExprKind Kind) {
+ switch (Kind) {
+ case ConstantExprKind::Normal:
+ case ConstantExprKind::ImmediateInvocation:
+ return false;
- case ConstantExprKind::ClassTemplateArgument:
- case ConstantExprKind::NonClassTemplateArgument:
- return true;
- }
- llvm_unreachable("unknown ConstantExprKind");
- }
-
- /// The bound to claim that an array of unknown bound has.
- /// The value in MostDerivedArraySize is undefined in this case. So, set it
- /// to an arbitrary value that's likely to loudly break things if it's used.
- static const uint64_t AssumedSizeForUnsizedArray =
- std::numeric_limits<uint64_t>::max() / 2;
-
- /// Determines if an LValue with the given LValueBase will have an unsized
- /// array in its designator.
- /// Find the path length and type of the most-derived subobject in the given
- /// path, and find the size of the containing array, if any.
- static unsigned
- findMostDerivedSubobject(const ASTContext &Ctx, APValue::LValueBase Base,
- ArrayRef<APValue::LValuePathEntry> Path,
- uint64_t &ArraySize, QualType &Type, bool &IsArray,
- bool &FirstEntryIsUnsizedArray) {
- // This only accepts LValueBases from APValues, and APValues don't support
- // arrays that lack size info.
- assert(!isBaseAnAllocSizeCall(Base) &&
- "Unsized arrays shouldn't appear here");
- unsigned MostDerivedLength = 0;
- // The type of Base is a reference type if the base is a constexpr-unknown
- // variable. In that case, look through the reference type.
- Type = getType(Base).getNonReferenceType();
-
- for (unsigned I = 0, N = Path.size(); I != N; ++I) {
- if (Type->isArrayType()) {
- const ArrayType *AT = Ctx.getAsArrayType(Type);
- Type = AT->getElementType();
- MostDerivedLength = I + 1;
- IsArray = true;
-
- if (auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
- ArraySize = CAT->getZExtSize();
- } else {
- assert(I == 0 && "unexpected unsized array designator");
- FirstEntryIsUnsizedArray = true;
- ArraySize = AssumedSizeForUnsizedArray;
- }
- } else if (Type->isAnyComplexType()) {
- const ComplexType *CT = Type->castAs<ComplexType>();
- Type = CT->getElementType();
- ArraySize = 2;
- MostDerivedLength = I + 1;
- IsArray = true;
- } else if (const auto *VT = Type->getAs<VectorType>()) {
- Type = VT->getElementType();
- ArraySize = VT->getNumElements();
- MostDerivedLength = I + 1;
- IsArray = true;
- } else if (const FieldDecl *FD = getAsField(Path[I])) {
- Type = FD->getType();
- ArraySize = 0;
- MostDerivedLength = I + 1;
- IsArray = false;
+ case ConstantExprKind::ClassTemplateArgument:
+ case ConstantExprKind::NonClassTemplateArgument:
+ return true;
+ }
+ llvm_unreachable("unknown ConstantExprKind");
+}
+
+/// The bound to claim that an array of unknown bound has.
+/// The value in MostDerivedArraySize is undefined in this case. So, set it
+/// to an arbitrary value that's likely to loudly break things if it's used.
+static const uint64_t AssumedSizeForUnsizedArray =
+ std::numeric_limits<uint64_t>::max() / 2;
+
+/// Determines if an LValue with the given LValueBase will have an unsized
+/// array in its designator.
+/// Find the path length and type of the most-derived subobject in the given
+/// path, and find the size of the containing array, if any.
+static unsigned
+findMostDerivedSubobject(const ASTContext &Ctx, APValue::LValueBase Base,
+ ArrayRef<APValue::LValuePathEntry> Path,
+ uint64_t &ArraySize, QualType &Type, bool &IsArray,
+ bool &FirstEntryIsUnsizedArray) {
+ // This only accepts LValueBases from APValues, and APValues don't support
+ // arrays that lack size info.
+ assert(!isBaseAnAllocSizeCall(Base) &&
+ "Unsized arrays shouldn't appear here");
+ unsigned MostDerivedLength = 0;
+ // The type of Base is a reference type if the base is a constexpr-unknown
+ // variable. In that case, look through the reference type.
+ Type = getType(Base).getNonReferenceType();
+
+ for (unsigned I = 0, N = Path.size(); I != N; ++I) {
+ if (Type->isArrayType()) {
+ const ArrayType *AT = Ctx.getAsArrayType(Type);
+ Type = AT->getElementType();
+ MostDerivedLength = I + 1;
+ IsArray = true;
+
+ if (auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
+ ArraySize = CAT->getZExtSize();
} else {
- // Path[I] describes a base class.
- ArraySize = 0;
- IsArray = false;
- }
- }
- return MostDerivedLength;
- }
-
- /// A path from a glvalue to a subobject of that glvalue.
- struct SubobjectDesignator {
- /// True if the subobject was named in a manner not supported by C++11. Such
- /// lvalues can still be folded, but they are not core constant expressions
- /// and we cannot perform lvalue-to-rvalue conversions on them.
- LLVM_PREFERRED_TYPE(bool)
- unsigned Invalid : 1;
-
- /// Is this a pointer one past the end of an object?
- LLVM_PREFERRED_TYPE(bool)
- unsigned IsOnePastTheEnd : 1;
-
- /// Indicator of whether the first entry is an unsized array.
- LLVM_PREFERRED_TYPE(bool)
- unsigned FirstEntryIsAnUnsizedArray : 1;
-
- /// Indicator of whether the most-derived object is an array element.
- LLVM_PREFERRED_TYPE(bool)
- unsigned MostDerivedIsArrayElement : 1;
-
- /// The length of the path to the most-derived object of which this is a
- /// subobject.
- unsigned MostDerivedPathLength : 28;
-
- /// The size of the array of which the most-derived object is an element.
- /// This will always be 0 if the most-derived object is not an array
- /// element. 0 is not an indicator of whether or not the most-derived object
- /// is an array, however, because 0-length arrays are allowed.
- ///
- /// If the current array is an unsized array, the value of this is
- /// undefined.
- uint64_t MostDerivedArraySize;
- /// The type of the most derived object referred to by this address.
- QualType MostDerivedType;
-
- typedef APValue::LValuePathEntry PathEntry;
-
- /// The entries on the path from the glvalue to the designated subobject.
- SmallVector<PathEntry, 8> Entries;
-
- SubobjectDesignator() : Invalid(true) {}
-
- explicit SubobjectDesignator(QualType T)
- : Invalid(false), IsOnePastTheEnd(false),
- FirstEntryIsAnUnsizedArray(false), MostDerivedIsArrayElement(false),
- MostDerivedPathLength(0), MostDerivedArraySize(0),
- MostDerivedType(T.isNull() ? QualType() : T.getNonReferenceType()) {}
-
- SubobjectDesignator(const ASTContext &Ctx, const APValue &V)
- : Invalid(!V.isLValue() || !V.hasLValuePath()), IsOnePastTheEnd(false),
- FirstEntryIsAnUnsizedArray(false), MostDerivedIsArrayElement(false),
- MostDerivedPathLength(0), MostDerivedArraySize(0) {
- assert(V.isLValue() && "Non-LValue used to make an LValue designator?");
- if (!Invalid) {
- IsOnePastTheEnd = V.isLValueOnePastTheEnd();
- llvm::append_range(Entries, V.getLValuePath());
- if (V.getLValueBase()) {
- bool IsArray = false;
- bool FirstIsUnsizedArray = false;
- MostDerivedPathLength = findMostDerivedSubobject(
- Ctx, V.getLValueBase(), V.getLValuePath(), MostDerivedArraySize,
- MostDerivedType, IsArray, FirstIsUnsizedArray);
- MostDerivedIsArrayElement = IsArray;
- FirstEntryIsAnUnsizedArray = FirstIsUnsizedArray;
- }
+ assert(I == 0 && "unexpected unsized array designator");
+ FirstEntryIsUnsizedArray = true;
+ ArraySize = AssumedSizeForUnsizedArray;
}
+ } else if (Type->isAnyComplexType()) {
+ const ComplexType *CT = Type->castAs<ComplexType>();
+ Type = CT->getElementType();
+ ArraySize = 2;
+ MostDerivedLength = I + 1;
+ IsArray = true;
+ } else if (const auto *VT = Type->getAs<VectorType>()) {
+ Type = VT->getElementType();
+ ArraySize = VT->getNumElements();
+ MostDerivedLength = I + 1;
+ IsArray = true;
+ } else if (const FieldDecl *FD = getAsField(Path[I])) {
+ Type = FD->getType();
+ ArraySize = 0;
+ MostDerivedLength = I + 1;
+ IsArray = false;
+ } else {
+ // Path[I] describes a base class.
+ ArraySize = 0;
+ IsArray = false;
}
+ }
+ return MostDerivedLength;
+}
- void truncate(ASTContext &Ctx, APValue::LValueBase Base,
- unsigned NewLength) {
- if (Invalid)
- return;
+/// A path from a glvalue to a subobject of that glvalue.
+struct SubobjectDesignator {
+ /// True if the subobject was named in a manner not supported by C++11. Such
+ /// lvalues can still be folded, but they are not core constant expressions
+ /// and we cannot perform lvalue-to-rvalue conversions on them.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned Invalid : 1;
- assert(Base && "cannot truncate path for null pointer");
- assert(NewLength <= Entries.size() && "not a truncation");
+ /// Is this a pointer one past the end of an object?
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned IsOnePastTheEnd : 1;
- if (NewLength == Entries.size())
- return;
- Entries.resize(NewLength);
+ /// Indicator of whether the first entry is an unsized array.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned FirstEntryIsAnUnsizedArray : 1;
- bool IsArray = false;
- bool FirstIsUnsizedArray = false;
- MostDerivedPathLength = findMostDerivedSubobject(
- Ctx, Base, Entries, MostDerivedArraySize, MostDerivedType, IsArray,
- FirstIsUnsizedArray);
- MostDerivedIsArrayElement = IsArray;
- FirstEntryIsAnUnsizedArray = FirstIsUnsizedArray;
- }
+ /// Indicator of whether the most-derived object is an array element.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned MostDerivedIsArrayElement : 1;
- void setInvalid() {
- Invalid = true;
- Entries.clear();
- }
+ /// The length of the path to the most-derived object of which this is a
+ /// subobject.
+ unsigned MostDerivedPathLength : 28;
- /// Determine whether the most derived subobject is an array without a
- /// known bound.
- bool isMostDerivedAnUnsizedArray() const {
- assert(!Invalid && "Calling this makes no sense on invalid designators");
- return Entries.size() == 1 && FirstEntryIsAnUnsizedArray;
+ /// The size of the array of which the most-derived object is an element.
+ /// This will always be 0 if the most-derived object is not an array
+ /// element. 0 is not an indicator of whether or not the most-derived object
+ /// is an array, however, because 0-length arrays are allowed.
+ ///
+ /// If the current array is an unsized array, the value of this is
+ /// undefined.
+ uint64_t MostDerivedArraySize;
+ /// The type of the most derived object referred to by this address.
+ QualType MostDerivedType;
+
+ typedef APValue::LValuePathEntry PathEntry;
+
+ /// The entries on the path from the glvalue to the designated subobject.
+ SmallVector<PathEntry, 8> Entries;
+
+ SubobjectDesignator() : Invalid(true) {}
+
+ explicit SubobjectDesignator(QualType T)
+ : Invalid(false), IsOnePastTheEnd(false),
+ FirstEntryIsAnUnsizedArray(false), MostDerivedIsArrayElement(false),
+ MostDerivedPathLength(0), MostDerivedArraySize(0),
+ MostDerivedType(T.isNull() ? QualType() : T.getNonReferenceType()) {}
+
+ SubobjectDesignator(const ASTContext &Ctx, const APValue &V)
+ : Invalid(!V.isLValue() || !V.hasLValuePath()), IsOnePastTheEnd(false),
+ FirstEntryIsAnUnsizedArray(false), MostDerivedIsArrayElement(false),
+ MostDerivedPathLength(0), MostDerivedArraySize(0) {
+ assert(V.isLValue() && "Non-LValue used to make an LValue designator?");
+ if (!Invalid) {
+ IsOnePastTheEnd = V.isLValueOnePastTheEnd();
+ llvm::append_range(Entries, V.getLValuePath());
+ if (V.getLValueBase()) {
+ bool IsArray = false;
+ bool FirstIsUnsizedArray = false;
+ MostDerivedPathLength = findMostDerivedSubobject(
+ Ctx, V.getLValueBase(), V.getLValuePath(), MostDerivedArraySize,
+ MostDerivedType, IsArray, FirstIsUnsizedArray);
+ MostDerivedIsArrayElement = IsArray;
+ FirstEntryIsAnUnsizedArray = FirstIsUnsizedArray;
+ }
}
+ }
- /// Determine what the most derived array's size is. Results in an assertion
- /// failure if the most derived array lacks a size.
- uint64_t getMostDerivedArraySize() const {
- assert(!isMostDerivedAnUnsizedArray() && "Unsized array has no size");
- return MostDerivedArraySize;
- }
+ void truncate(ASTContext &Ctx, APValue::LValueBase Base, unsigned NewLength) {
+ if (Invalid)
+ return;
- /// Determine whether this is a one-past-the-end pointer.
- bool isOnePastTheEnd() const {
- assert(!Invalid);
- if (IsOnePastTheEnd)
- return true;
- if (!isMostDerivedAnUnsizedArray() && MostDerivedIsArrayElement &&
- Entries[MostDerivedPathLength - 1].getAsArrayIndex() ==
- MostDerivedArraySize)
- return true;
- return false;
- }
+ assert(Base && "cannot truncate path for null pointer");
+ assert(NewLength <= Entries.size() && "not a truncation");
- /// Get the range of valid index adjustments in the form
- /// {maximum value that can be subtracted from this pointer,
- /// maximum value that can be added to this pointer}
- std::pair<uint64_t, uint64_t> validIndexAdjustments() {
- if (Invalid || isMostDerivedAnUnsizedArray())
- return {0, 0};
+ if (NewLength == Entries.size())
+ return;
+ Entries.resize(NewLength);
- // [expr.add]p4: For the purposes of these operators, a pointer to a
- // nonarray object behaves the same as a pointer to the first element of
- // an array of length one with the type of the object as its element type.
- bool IsArray = MostDerivedPathLength == Entries.size() &&
- MostDerivedIsArrayElement;
- uint64_t ArrayIndex = IsArray ? Entries.back().getAsArrayIndex()
- : (uint64_t)IsOnePastTheEnd;
- uint64_t ArraySize =
- IsArray ? getMostDerivedArraySize() : (uint64_t)1;
- return {ArrayIndex, ArraySize - ArrayIndex};
- }
+ bool IsArray = false;
+ bool FirstIsUnsizedArray = false;
+ MostDerivedPathLength =
+ findMostDerivedSubobject(Ctx, Base, Entries, MostDerivedArraySize,
+ MostDerivedType, IsArray, FirstIsUnsizedArray);
+ MostDerivedIsArrayElement = IsArray;
+ FirstEntryIsAnUnsizedArray = FirstIsUnsizedArray;
+ }
- /// Check that this refers to a valid subobject.
- bool isValidSubobject() const {
- if (Invalid)
- return false;
- return !isOnePastTheEnd();
- }
- /// Check that this refers to a valid subobject, and if not, produce a
- /// relevant diagnostic and set the designator as invalid.
- bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK);
+ void setInvalid() {
+ Invalid = true;
+ Entries.clear();
+ }
- /// Get the type of the designated object.
- QualType getType(ASTContext &Ctx) const {
- assert(!Invalid && "invalid designator has no subobject type");
- return MostDerivedPathLength == Entries.size()
- ? MostDerivedType
- : Ctx.getCanonicalTagType(getAsBaseClass(Entries.back()));
- }
+ /// Determine whether the most derived subobject is an array without a
+ /// known bound.
+ bool isMostDerivedAnUnsizedArray() const {
+ assert(!Invalid && "Calling this makes no sense on invalid designators");
+ return Entries.size() == 1 && FirstEntryIsAnUnsizedArray;
+ }
- /// Update this designator to refer to the first element within this array.
- void addArrayUnchecked(const ConstantArrayType *CAT) {
- Entries.push_back(PathEntry::ArrayIndex(0));
+ /// Determine what the most derived array's size is. Results in an assertion
+ /// failure if the most derived array lacks a size.
+ uint64_t getMostDerivedArraySize() const {
+ assert(!isMostDerivedAnUnsizedArray() && "Unsized array has no size");
+ return MostDerivedArraySize;
+ }
- // This is a most-derived object.
- MostDerivedType = CAT->getElementType();
- MostDerivedIsArrayElement = true;
- MostDerivedArraySize = CAT->getZExtSize();
- MostDerivedPathLength = Entries.size();
- }
- /// Update this designator to refer to the first element within the array of
- /// elements of type T. This is an array of unknown size.
- void addUnsizedArrayUnchecked(QualType ElemTy) {
- Entries.push_back(PathEntry::ArrayIndex(0));
-
- MostDerivedType = ElemTy;
- MostDerivedIsArrayElement = true;
- // The value in MostDerivedArraySize is undefined in this case. So, set it
- // to an arbitrary value that's likely to loudly break things if it's
- // used.
- MostDerivedArraySize = AssumedSizeForUnsizedArray;
- MostDerivedPathLength = Entries.size();
- }
- /// Update this designator to refer to the given base or member of this
- /// object.
- void addDeclUnchecked(const Decl *D, bool Virtual = false) {
- Entries.push_back(APValue::BaseOrMemberType(D, Virtual));
-
- // If this isn't a base class, it's a new most-derived object.
- if (const FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
- MostDerivedType = FD->getType();
- MostDerivedIsArrayElement = false;
- MostDerivedArraySize = 0;
- MostDerivedPathLength = Entries.size();
- }
- }
- /// Update this designator to refer to the given complex component.
- void addComplexUnchecked(QualType EltTy, bool Imag) {
- Entries.push_back(PathEntry::ArrayIndex(Imag));
+ /// Determine whether this is a one-past-the-end pointer.
+ bool isOnePastTheEnd() const {
+ assert(!Invalid);
+ if (IsOnePastTheEnd)
+ return true;
+ if (!isMostDerivedAnUnsizedArray() && MostDerivedIsArrayElement &&
+ Entries[MostDerivedPathLength - 1].getAsArrayIndex() ==
+ MostDerivedArraySize)
+ return true;
+ return false;
+ }
- // This is technically a most-derived object, though in practice this
- // is unlikely to matter.
- MostDerivedType = EltTy;
- MostDerivedIsArrayElement = true;
- MostDerivedArraySize = 2;
+ /// Get the range of valid index adjustments in the form
+ /// {maximum value that can be subtracted from this pointer,
+ /// maximum value that can be added to this pointer}
+ std::pair<uint64_t, uint64_t> validIndexAdjustments() {
+ if (Invalid || isMostDerivedAnUnsizedArray())
+ return {0, 0};
+
+ // [expr.add]p4: For the purposes of these operators, a pointer to a
+ // nonarray object behaves the same as a pointer to the first element of
+ // an array of length one with the type of the object as its element type.
+ bool IsArray =
+ MostDerivedPathLength == Entries.size() && MostDerivedIsArrayElement;
+ uint64_t ArrayIndex =
+ IsArray ? Entries.back().getAsArrayIndex() : (uint64_t)IsOnePastTheEnd;
+ uint64_t ArraySize = IsArray ? getMostDerivedArraySize() : (uint64_t)1;
+ return {ArrayIndex, ArraySize - ArrayIndex};
+ }
+
+ /// Check that this refers to a valid subobject.
+ bool isValidSubobject() const {
+ if (Invalid)
+ return false;
+ return !isOnePastTheEnd();
+ }
+ /// Check that this refers to a valid subobject, and if not, produce a
+ /// relevant diagnostic and set the designator as invalid.
+ bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK);
+
+ /// Get the type of the designated object.
+ QualType getType(ASTContext &Ctx) const {
+ assert(!Invalid && "invalid designator has no subobject type");
+ return MostDerivedPathLength == Entries.size()
+ ? MostDerivedType
+ : Ctx.getCanonicalTagType(getAsBaseClass(Entries.back()));
+ }
+
+ /// Update this designator to refer to the first element within this array.
+ void addArrayUnchecked(const ConstantArrayType *CAT) {
+ Entries.push_back(PathEntry::ArrayIndex(0));
+
+ // This is a most-derived object.
+ MostDerivedType = CAT->getElementType();
+ MostDerivedIsArrayElement = true;
+ MostDerivedArraySize = CAT->getZExtSize();
+ MostDerivedPathLength = Entries.size();
+ }
+ /// Update this designator to refer to the first element within the array of
+ /// elements of type T. This is an array of unknown size.
+ void addUnsizedArrayUnchecked(QualType ElemTy) {
+ Entries.push_back(PathEntry::ArrayIndex(0));
+
+ MostDerivedType = ElemTy;
+ MostDerivedIsArrayElement = true;
+ // The value in MostDerivedArraySize is undefined in this case. So, set it
+ // to an arbitrary value that's likely to loudly break things if it's
+ // used.
+ MostDerivedArraySize = AssumedSizeForUnsizedArray;
+ MostDerivedPathLength = Entries.size();
+ }
+ /// Update this designator to refer to the given base or member of this
+ /// object.
+ void addDeclUnchecked(const Decl *D, bool Virtual = false) {
+ Entries.push_back(APValue::BaseOrMemberType(D, Virtual));
+
+ // If this isn't a base class, it's a new most-derived object.
+ if (const FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
+ MostDerivedType = FD->getType();
+ MostDerivedIsArrayElement = false;
+ MostDerivedArraySize = 0;
MostDerivedPathLength = Entries.size();
}
+ }
+ /// Update this designator to refer to the given complex component.
+ void addComplexUnchecked(QualType EltTy, bool Imag) {
+ Entries.push_back(PathEntry::ArrayIndex(Imag));
- void addVectorElementUnchecked(QualType EltTy, uint64_t Size,
- uint64_t Idx) {
- Entries.push_back(PathEntry::ArrayIndex(Idx));
- MostDerivedType = EltTy;
- MostDerivedPathLength = Entries.size();
- MostDerivedArraySize = 0;
- MostDerivedIsArrayElement = false;
- }
+ // This is technically a most-derived object, though in practice this
+ // is unlikely to matter.
+ MostDerivedType = EltTy;
+ MostDerivedIsArrayElement = true;
+ MostDerivedArraySize = 2;
+ MostDerivedPathLength = Entries.size();
+ }
- void diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, const Expr *E);
- void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E,
- const APSInt &N);
- /// Add N to the address of this subobject.
- void adjustIndex(EvalInfo &Info, const Expr *E, APSInt N, const LValue &LV);
- };
+ void addVectorElementUnchecked(QualType EltTy, uint64_t Size, uint64_t Idx) {
+ Entries.push_back(PathEntry::ArrayIndex(Idx));
+ MostDerivedType = EltTy;
+ MostDerivedPathLength = Entries.size();
+ MostDerivedArraySize = 0;
+ MostDerivedIsArrayElement = false;
+ }
- /// A scope at the end of which an object can need to be destroyed.
- enum class ScopeKind {
- Block,
- FullExpression,
- Call
- };
+ void diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, const Expr *E);
+ void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E,
+ const APSInt &N);
+ /// Add N to the address of this subobject.
+ void adjustIndex(EvalInfo &Info, const Expr *E, APSInt N, const LValue &LV);
+};
- /// A reference to a particular call and its arguments.
- struct CallRef {
- CallRef() : OrigCallee(), CallIndex(0), Version() {}
- CallRef(const FunctionDecl *Callee, unsigned CallIndex, unsigned Version)
- : OrigCallee(Callee), CallIndex(CallIndex), Version(Version) {}
-
- explicit operator bool() const { return OrigCallee; }
-
- /// Get the parameter that the caller initialized, corresponding to the
- /// given parameter in the callee.
- const ParmVarDecl *getOrigParam(const ParmVarDecl *PVD) const {
- return OrigCallee ? OrigCallee->getParamDecl(PVD->getFunctionScopeIndex())
- : PVD;
- }
-
- /// The callee at the point where the arguments were evaluated. This might
- /// be different from the actual callee (a different redeclaration, or a
- /// virtual override), but this function's parameters are the ones that
- /// appear in the parameter map.
- const FunctionDecl *OrigCallee;
- /// The call index of the frame that holds the argument values.
- unsigned CallIndex;
- /// The version of the parameters corresponding to this call.
- unsigned Version;
- };
+/// A scope at the end of which an object can need to be destroyed.
+enum class ScopeKind { Block, FullExpression, Call };
+
+/// A reference to a particular call and its arguments.
+struct CallRef {
+ CallRef() : OrigCallee(), CallIndex(0), Version() {}
+ CallRef(const FunctionDecl *Callee, unsigned CallIndex, unsigned Version)
+ : OrigCallee(Callee), CallIndex(CallIndex), Version(Version) {}
+
+ explicit operator bool() const { return OrigCallee; }
+
+ /// Get the parameter that the caller initialized, corresponding to the
+ /// given parameter in the callee.
+ const ParmVarDecl *getOrigParam(const ParmVarDecl *PVD) const {
+ return OrigCallee ? OrigCallee->getParamDecl(PVD->getFunctionScopeIndex())
+ : PVD;
+ }
+
+ /// The callee at the point where the arguments were evaluated. This might
+ /// be different from the actual callee (a different redeclaration, or a
+ /// virtual override), but this function's parameters are the ones that
+ /// appear in the parameter map.
+ const FunctionDecl *OrigCallee;
+ /// The call index of the frame that holds the argument values.
+ unsigned CallIndex;
+ /// The version of the parameters corresponding to this call.
+ unsigned Version;
+};
- /// A stack frame in the constexpr call stack.
- class CallStackFrame : public interp::Frame {
- public:
- EvalInfo &Info;
+/// A stack frame in the constexpr call stack.
+class CallStackFrame : public interp::Frame {
+public:
+ EvalInfo &Info;
- /// Parent - The caller of this stack frame.
- CallStackFrame *Caller;
+ /// Parent - The caller of this stack frame.
+ CallStackFrame *Caller;
- /// Callee - The function which was called.
- const FunctionDecl *Callee;
+ /// Callee - The function which was called.
+ const FunctionDecl *Callee;
- /// This - The binding for the this pointer in this call, if any.
- const LValue *This;
+ /// This - The binding for the this pointer in this call, if any.
+ const LValue *This;
- /// CallExpr - The syntactical structure of member function calls
- const Expr *CallExpr;
+ /// CallExpr - The syntactical structure of member function calls
+ const Expr *CallExpr;
- /// Information on how to find the arguments to this call. Our arguments
- /// are stored in our parent's CallStackFrame, using the ParmVarDecl* as a
- /// key and this value as the version.
- CallRef Arguments;
+ /// Information on how to find the arguments to this call. Our arguments
+ /// are stored in our parent's CallStackFrame, using the ParmVarDecl* as a
+ /// key and this value as the version.
+ CallRef Arguments;
- /// Source location information about the default argument or default
- /// initializer expression we're evaluating, if any.
- CurrentSourceLocExprScope CurSourceLocExprScope;
+ /// Source location information about the default argument or default
+ /// initializer expression we're evaluating, if any.
+ CurrentSourceLocExprScope CurSourceLocExprScope;
- // Note that we intentionally use std::map here so that references to
- // values are stable.
- typedef std::pair<const void *, unsigned> MapKeyTy;
- typedef std::map<MapKeyTy, APValue> MapTy;
- /// Temporaries - Temporary lvalues materialized within this stack frame.
- MapTy Temporaries;
+ // Note that we intentionally use std::map here so that references to
+ // values are stable.
+ typedef std::pair<const void *, unsigned> MapKeyTy;
+ typedef std::map<MapKeyTy, APValue> MapTy;
+ /// Temporaries - Temporary lvalues materialized within this stack frame.
+ MapTy Temporaries;
- /// CallRange - The source range of the call expression for this call.
- SourceRange CallRange;
+ /// CallRange - The source range of the call expression for this call.
+ SourceRange CallRange;
- /// Index - The call index of this call.
- unsigned Index;
+ /// Index - The call index of this call.
+ unsigned Index;
- /// The stack of integers for tracking version numbers for temporaries.
- SmallVector<unsigned, 2> TempVersionStack = {1};
- unsigned CurTempVersion = TempVersionStack.back();
+ /// The stack of integers for tracking version numbers for temporaries.
+ SmallVector<unsigned, 2> TempVersionStack = {1};
+ unsigned CurTempVersion = TempVersionStack.back();
- unsigned getTempVersion() const { return TempVersionStack.back(); }
+ unsigned getTempVersion() const { return TempVersionStack.back(); }
- void pushTempVersion() {
- TempVersionStack.push_back(++CurTempVersion);
- }
+ void pushTempVersion() { TempVersionStack.push_back(++CurTempVersion); }
- void popTempVersion() {
- TempVersionStack.pop_back();
- }
+ void popTempVersion() { TempVersionStack.pop_back(); }
- CallRef createCall(const FunctionDecl *Callee) {
- return {Callee, Index, ++CurTempVersion};
- }
+ CallRef createCall(const FunctionDecl *Callee) {
+ return {Callee, Index, ++CurTempVersion};
+ }
- // FIXME: Adding this to every 'CallStackFrame' may have a nontrivial impact
- // on the overall stack usage of deeply-recursing constexpr evaluations.
- // (We should cache this map rather than recomputing it repeatedly.)
- // But let's try this and see how it goes; we can look into caching the map
- // as a later change.
+ // FIXME: Adding this to every 'CallStackFrame' may have a nontrivial impact
+ // on the overall stack usage of deeply-recursing constexpr evaluations.
+ // (We should cache this map rather than recomputing it repeatedly.)
+ // But let's try this and see how it goes; we can look into caching the map
+ // as a later change.
- /// LambdaCaptureFields - Mapping from captured variables/this to
- /// corresponding data members in the closure class.
- llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
- FieldDecl *LambdaThisCaptureField = nullptr;
+ /// LambdaCaptureFields - Mapping from captured variables/this to
+ /// corresponding data members in the closure class.
+ llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
+ FieldDecl *LambdaThisCaptureField = nullptr;
- CallStackFrame(EvalInfo &Info, SourceRange CallRange,
- const FunctionDecl *Callee, const LValue *This,
- const Expr *CallExpr, CallRef Arguments);
- ~CallStackFrame();
+ CallStackFrame(EvalInfo &Info, SourceRange CallRange,
+ const FunctionDecl *Callee, const LValue *This,
+ const Expr *CallExpr, CallRef Arguments);
+ ~CallStackFrame();
- // Return the temporary for Key whose version number is Version.
- APValue *getTemporary(const void *Key, unsigned Version) {
- MapKeyTy KV(Key, Version);
- auto LB = Temporaries.lower_bound(KV);
- if (LB != Temporaries.end() && LB->first == KV)
- return &LB->second;
- return nullptr;
- }
+ // Return the temporary for Key whose version number is Version.
+ APValue *getTemporary(const void *Key, unsigned Version) {
+ MapKeyTy KV(Key, Version);
+ auto LB = Temporaries.lower_bound(KV);
+ if (LB != Temporaries.end() && LB->first == KV)
+ return &LB->second;
+ return nullptr;
+ }
- // Return the current temporary for Key in the map.
- APValue *getCurrentTemporary(const void *Key) {
- auto UB = Temporaries.upper_bound(MapKeyTy(Key, UINT_MAX));
- if (UB != Temporaries.begin() && std::prev(UB)->first.first == Key)
- return &std::prev(UB)->second;
- return nullptr;
- }
+ // Return the current temporary for Key in the map.
+ APValue *getCurrentTemporary(const void *Key) {
+ auto UB = Temporaries.upper_bound(MapKeyTy(Key, UINT_MAX));
+ if (UB != Temporaries.begin() && std::prev(UB)->first.first == Key)
+ return &std::prev(UB)->second;
+ return nullptr;
+ }
- // Return the version number of the current temporary for Key.
- unsigned getCurrentTemporaryVersion(const void *Key) const {
- auto UB = Temporaries.upper_bound(MapKeyTy(Key, UINT_MAX));
- if (UB != Temporaries.begin() && std::prev(UB)->first.first == Key)
- return std::prev(UB)->first.second;
- return 0;
- }
+ // Return the version number of the current temporary for Key.
+ unsigned getCurrentTemporaryVersion(const void *Key) const {
+ auto UB = Temporaries.upper_bound(MapKeyTy(Key, UINT_MAX));
+ if (UB != Temporaries.begin() && std::prev(UB)->first.first == Key)
+ return std::prev(UB)->first.second;
+ return 0;
+ }
- /// Allocate storage for an object of type T in this stack frame.
- /// Populates LV with a handle to the created object. Key identifies
- /// the temporary within the stack frame, and must not be reused without
- /// bumping the temporary version number.
- template<typename KeyT>
- APValue &createTemporary(const KeyT *Key, QualType T,
- ScopeKind Scope, LValue &LV);
+ /// Allocate storage for an object of type T in this stack frame.
+ /// Populates LV with a handle to the created object. Key identifies
+ /// the temporary within the stack frame, and must not be reused without
+ /// bumping the temporary version number.
+ template <typename KeyT>
+ APValue &createTemporary(const KeyT *Key, QualType T, ScopeKind Scope,
+ LValue &LV);
- /// Allocate storage for a parameter of a function call made in this frame.
- APValue &createParam(CallRef Args, const ParmVarDecl *PVD, LValue &LV);
+ /// Allocate storage for a parameter of a function call made in this frame.
+ APValue &createParam(CallRef Args, const ParmVarDecl *PVD, LValue &LV);
- void describe(llvm::raw_ostream &OS) const override;
+ void describe(llvm::raw_ostream &OS) const override;
- Frame *getCaller() const override { return Caller; }
- SourceRange getCallRange() const override { return CallRange; }
- const FunctionDecl *getCallee() const override { return Callee; }
+ Frame *getCaller() const override { return Caller; }
+ SourceRange getCallRange() const override { return CallRange; }
+ const FunctionDecl *getCallee() const override { return Callee; }
- bool isStdFunction() const {
- for (const DeclContext *DC = Callee; DC; DC = DC->getParent())
- if (DC->isStdNamespace())
- return true;
- return false;
- }
+ bool isStdFunction() const {
+ for (const DeclContext *DC = Callee; DC; DC = DC->getParent())
+ if (DC->isStdNamespace())
+ return true;
+ return false;
+ }
- /// Whether we're in a context where [[msvc::constexpr]] evaluation is
- /// permitted. See MSConstexprDocs for description of permitted contexts.
- bool CanEvalMSConstexpr = false;
+ /// Whether we're in a context where [[msvc::constexpr]] evaluation is
+ /// permitted. See MSConstexprDocs for description of permitted contexts.
+ bool CanEvalMSConstexpr = false;
- private:
- APValue &createLocal(APValue::LValueBase Base, const void *Key, QualType T,
- ScopeKind Scope);
- };
+private:
+ APValue &createLocal(APValue::LValueBase Base, const void *Key, QualType T,
+ ScopeKind Scope);
+};
- /// Temporarily override 'this'.
- class ThisOverrideRAII {
- public:
- ThisOverrideRAII(CallStackFrame &Frame, const LValue *NewThis, bool Enable)
- : Frame(Frame), OldThis(Frame.This) {
- if (Enable)
- Frame.This = NewThis;
- }
- ~ThisOverrideRAII() {
- Frame.This = OldThis;
- }
- private:
- CallStackFrame &Frame;
- const LValue *OldThis;
- };
+/// Temporarily override 'this'.
+class ThisOverrideRAII {
+public:
+ ThisOverrideRAII(CallStackFrame &Frame, const LValue *NewThis, bool Enable)
+ : Frame(Frame), OldThis(Frame.This) {
+ if (Enable)
+ Frame.This = NewThis;
+ }
+ ~ThisOverrideRAII() { Frame.This = OldThis; }
- // A shorthand time trace scope struct, prints source range, for example
- // {"name":"EvaluateAsRValue","args":{"detail":"<test.cc:8:21, col:25>"}}}
- class ExprTimeTraceScope {
- public:
- ExprTimeTraceScope(const Expr *E, const ASTContext &Ctx, StringRef Name)
- : TimeScope(Name, [E, &Ctx] {
- return E->getSourceRange().printToString(Ctx.getSourceManager());
- }) {}
+private:
+ CallStackFrame &Frame;
+ const LValue *OldThis;
+};
- private:
- llvm::TimeTraceScope TimeScope;
- };
+// A shorthand time trace scope struct, prints source range, for example
+// {"name":"EvaluateAsRValue","args":{"detail":"<test.cc:8:21, col:25>"}}}
+class ExprTimeTraceScope {
+public:
+ ExprTimeTraceScope(const Expr *E, const ASTContext &Ctx, StringRef Name)
+ : TimeScope(Name, [E, &Ctx] {
+ return E->getSourceRange().printToString(Ctx.getSourceManager());
+ }) {}
- /// RAII object used to change the current ability of
- /// [[msvc::constexpr]] evaulation.
- struct MSConstexprContextRAII {
- CallStackFrame &Frame;
- bool OldValue;
- explicit MSConstexprContextRAII(CallStackFrame &Frame, bool Value)
- : Frame(Frame), OldValue(Frame.CanEvalMSConstexpr) {
- Frame.CanEvalMSConstexpr = Value;
- }
+private:
+ llvm::TimeTraceScope TimeScope;
+};
- ~MSConstexprContextRAII() { Frame.CanEvalMSConstexpr = OldValue; }
- };
-}
+/// RAII object used to change the current ability of
+/// [[msvc::constexpr]] evaulation.
+struct MSConstexprContextRAII {
+ CallStackFrame &Frame;
+ bool OldValue;
+ explicit MSConstexprContextRAII(CallStackFrame &Frame, bool Value)
+ : Frame(Frame), OldValue(Frame.CanEvalMSConstexpr) {
+ Frame.CanEvalMSConstexpr = Value;
+ }
+
+ ~MSConstexprContextRAII() { Frame.CanEvalMSConstexpr = OldValue; }
+};
+} // namespace
-static bool HandleDestruction(EvalInfo &Info, const Expr *E,
- const LValue &This, QualType ThisType);
+static bool HandleDestruction(EvalInfo &Info, const Expr *E, const LValue &This,
+ QualType ThisType);
static bool HandleDestruction(EvalInfo &Info, SourceLocation Loc,
APValue::LValueBase LVBase, APValue &Value,
QualType T);
namespace {
- /// A cleanup, and a flag indicating whether it is lifetime-extended.
- class Cleanup {
- llvm::PointerIntPair<APValue*, 2, ScopeKind> Value;
- APValue::LValueBase Base;
- QualType T;
+/// A cleanup, and a flag indicating whether it is lifetime-extended.
+class Cleanup {
+ llvm::PointerIntPair<APValue *, 2, ScopeKind> Value;
+ APValue::LValueBase Base;
+ QualType T;
- public:
- Cleanup(APValue *Val, APValue::LValueBase Base, QualType T,
- ScopeKind Scope)
- : Value(Val, Scope), Base(Base), T(T) {}
-
- /// Determine whether this cleanup should be performed at the end of the
- /// given kind of scope.
- bool isDestroyedAtEndOf(ScopeKind K) const {
- return (int)Value.getInt() >= (int)K;
- }
- bool endLifetime(EvalInfo &Info, bool RunDestructors) {
- if (RunDestructors) {
- SourceLocation Loc;
- if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>())
- Loc = VD->getLocation();
- else if (const Expr *E = Base.dyn_cast<const Expr*>())
- Loc = E->getExprLoc();
- return HandleDestruction(Info, Loc, Base, *Value.getPointer(), T);
- }
- *Value.getPointer() = APValue();
- return true;
- }
+public:
+ Cleanup(APValue *Val, APValue::LValueBase Base, QualType T, ScopeKind Scope)
+ : Value(Val, Scope), Base(Base), T(T) {}
+
+ /// Determine whether this cleanup should be performed at the end of the
+ /// given kind of scope.
+ bool isDestroyedAtEndOf(ScopeKind K) const {
+ return (int)Value.getInt() >= (int)K;
+ }
+ bool endLifetime(EvalInfo &Info, bool RunDestructors) {
+ if (RunDestructors) {
+ SourceLocation Loc;
+ if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl *>())
+ Loc = VD->getLocation();
+ else if (const Expr *E = Base.dyn_cast<const Expr *>())
+ Loc = E->getExprLoc();
+ return HandleDestruction(Info, Loc, Base, *Value.getPointer(), T);
+ }
+ *Value.getPointer() = APValue();
+ return true;
+ }
- bool hasSideEffect() {
- return T.isDestructedType();
- }
- };
+ bool hasSideEffect() { return T.isDestructedType(); }
+};
- /// A reference to an object whose construction we are currently evaluating.
- struct ObjectUnderConstruction {
- APValue::LValueBase Base;
- ArrayRef<APValue::LValuePathEntry> Path;
- friend bool operator==(const ObjectUnderConstruction &LHS,
- const ObjectUnderConstruction &RHS) {
- return LHS.Base == RHS.Base && LHS.Path == RHS.Path;
- }
- friend llvm::hash_code hash_value(const ObjectUnderConstruction &Obj) {
- return llvm::hash_combine(Obj.Base, Obj.Path);
- }
- };
- enum class ConstructionPhase {
- None,
- Bases,
- AfterBases,
- AfterFields,
- Destroying,
- DestroyingBases
- };
-}
+/// A reference to an object whose construction we are currently evaluating.
+struct ObjectUnderConstruction {
+ APValue::LValueBase Base;
+ ArrayRef<APValue::LValuePathEntry> Path;
+ friend bool operator==(const ObjectUnderConstruction &LHS,
+ const ObjectUnderConstruction &RHS) {
+ return LHS.Base == RHS.Base && LHS.Path == RHS.Path;
+ }
+ friend llvm::hash_code hash_value(const ObjectUnderConstruction &Obj) {
+ return llvm::hash_combine(Obj.Base, Obj.Path);
+ }
+};
+enum class ConstructionPhase {
+ None,
+ Bases,
+ AfterBases,
+ AfterFields,
+ Destroying,
+ DestroyingBases
+};
+} // namespace
namespace llvm {
-template<> struct DenseMapInfo<ObjectUnderConstruction> {
+template <> struct DenseMapInfo<ObjectUnderConstruction> {
using Base = DenseMapInfo<APValue::LValueBase>;
static ObjectUnderConstruction getEmptyKey() {
- return {Base::getEmptyKey(), {}}; }
+ return {Base::getEmptyKey(), {}};
+ }
static ObjectUnderConstruction getTombstoneKey() {
return {Base::getTombstoneKey(), {}};
}
@@ -745,651 +729,641 @@ template<> struct DenseMapInfo<ObjectUnderConstruction> {
return LHS == RHS;
}
};
-}
+} // namespace llvm
namespace {
- /// A dynamically-allocated heap object.
- struct DynAlloc {
- /// The value of this heap-allocated object.
- APValue Value;
- /// The allocating expression; used for diagnostics. Either a CXXNewExpr
- /// or a CallExpr (the latter is for direct calls to operator new inside
- /// std::allocator<T>::allocate).
- const Expr *AllocExpr = nullptr;
-
- enum Kind {
- New,
- ArrayNew,
- StdAllocator
- };
-
- /// Get the kind of the allocation. This must match between allocation
- /// and deallocation.
- Kind getKind() const {
- if (auto *NE = dyn_cast<CXXNewExpr>(AllocExpr))
- return NE->isArray() ? ArrayNew : New;
- assert(isa<CallExpr>(AllocExpr));
- return StdAllocator;
- }
- };
-
- struct DynAllocOrder {
- bool operator()(DynamicAllocLValue L, DynamicAllocLValue R) const {
- return L.getIndex() < R.getIndex();
- }
- };
+/// A dynamically-allocated heap object.
+struct DynAlloc {
+ /// The value of this heap-allocated object.
+ APValue Value;
+ /// The allocating expression; used for diagnostics. Either a CXXNewExpr
+ /// or a CallExpr (the latter is for direct calls to operator new inside
+ /// std::allocator<T>::allocate).
+ const Expr *AllocExpr = nullptr;
+
+ enum Kind { New, ArrayNew, StdAllocator };
+
+ /// Get the kind of the allocation. This must match between allocation
+ /// and deallocation.
+ Kind getKind() const {
+ if (auto *NE = dyn_cast<CXXNewExpr>(AllocExpr))
+ return NE->isArray() ? ArrayNew : New;
+ assert(isa<CallExpr>(AllocExpr));
+ return StdAllocator;
+ }
+};
- /// EvalInfo - This is a private struct used by the evaluator to capture
- /// information about a subexpression as it is folded. It retains information
- /// about the AST context, but also maintains information about the folded
- /// expression.
- ///
- /// If an expression could be evaluated, it is still possible it is not a C
- /// "integer constant expression" or constant expression. If not, this struct
- /// captures information about how and why not.
- ///
- /// One bit of information passed *into* the request for constant folding
- /// indicates whether the subexpression is "evaluated" or not according to C
- /// rules. For example, the RHS of (0 && foo()) is not evaluated. We can
- /// evaluate the expression regardless of what the RHS is, but C only allows
- /// certain things in certain situations.
- class EvalInfo : public interp::State {
- public:
- ASTContext &Ctx;
+struct DynAllocOrder {
+ bool operator()(DynamicAllocLValue L, DynamicAllocLValue R) const {
+ return L.getIndex() < R.getIndex();
+ }
+};
- /// EvalStatus - Contains information about the evaluation.
- Expr::EvalStatus &EvalStatus;
+/// EvalInfo - This is a private struct used by the evaluator to capture
+/// information about a subexpression as it is folded. It retains information
+/// about the AST context, but also maintains information about the folded
+/// expression.
+///
+/// If an expression could be evaluated, it is still possible it is not a C
+/// "integer constant expression" or constant expression. If not, this struct
+/// captures information about how and why not.
+///
+/// One bit of information passed *into* the request for constant folding
+/// indicates whether the subexpression is "evaluated" or not according to C
+/// rules. For example, the RHS of (0 && foo()) is not evaluated. We can
+/// evaluate the expression regardless of what the RHS is, but C only allows
+/// certain things in certain situations.
+class EvalInfo : public interp::State {
+public:
+ ASTContext &Ctx;
- /// CurrentCall - The top of the constexpr call stack.
- CallStackFrame *CurrentCall;
+ /// EvalStatus - Contains information about the evaluation.
+ Expr::EvalStatus &EvalStatus;
- /// CallStackDepth - The number of calls in the call stack right now.
- unsigned CallStackDepth;
+ /// CurrentCall - The top of the constexpr call stack.
+ CallStackFrame *CurrentCall;
- /// NextCallIndex - The next call index to assign.
- unsigned NextCallIndex;
+ /// CallStackDepth - The number of calls in the call stack right now.
+ unsigned CallStackDepth;
- /// StepsLeft - The remaining number of evaluation steps we're permitted
- /// to perform. This is essentially a limit for the number of statements
- /// we will evaluate.
- unsigned StepsLeft;
+ /// NextCallIndex - The next call index to assign.
+ unsigned NextCallIndex;
- /// Enable the experimental new constant interpreter. If an expression is
- /// not supported by the interpreter, an error is triggered.
- bool EnableNewConstInterp;
+ /// StepsLeft - The remaining number of evaluation steps we're permitted
+ /// to perform. This is essentially a limit for the number of statements
+ /// we will evaluate.
+ unsigned StepsLeft;
- /// BottomFrame - The frame in which evaluation started. This must be
- /// initialized after CurrentCall and CallStackDepth.
- CallStackFrame BottomFrame;
+ /// Enable the experimental new constant interpreter. If an expression is
+ /// not supported by the interpreter, an error is triggered.
+ bool EnableNewConstInterp;
- /// A stack of values whose lifetimes end at the end of some surrounding
- /// evaluation frame.
- llvm::SmallVector<Cleanup, 16> CleanupStack;
+ /// BottomFrame - The frame in which evaluation started. This must be
+ /// initialized after CurrentCall and CallStackDepth.
+ CallStackFrame BottomFrame;
- /// EvaluatingDecl - This is the declaration whose initializer is being
- /// evaluated, if any.
- APValue::LValueBase EvaluatingDecl;
+ /// A stack of values whose lifetimes end at the end of some surrounding
+ /// evaluation frame.
+ llvm::SmallVector<Cleanup, 16> CleanupStack;
- enum class EvaluatingDeclKind {
- None,
- /// We're evaluating the construction of EvaluatingDecl.
- Ctor,
- /// We're evaluating the destruction of EvaluatingDecl.
- Dtor,
- };
- EvaluatingDeclKind IsEvaluatingDecl = EvaluatingDeclKind::None;
-
- /// EvaluatingDeclValue - This is the value being constructed for the
- /// declaration whose initializer is being evaluated, if any.
- APValue *EvaluatingDeclValue;
-
- /// Stack of loops and 'switch' statements which we're currently
- /// breaking/continuing; null entries are used to mark unlabeled
- /// break/continue.
- SmallVector<const Stmt *> BreakContinueStack;
-
- /// Set of objects that are currently being constructed.
- llvm::DenseMap<ObjectUnderConstruction, ConstructionPhase>
- ObjectsUnderConstruction;
-
- /// Current heap allocations, along with the location where each was
- /// allocated. We use std::map here because we need stable addresses
- /// for the stored APValues.
- std::map<DynamicAllocLValue, DynAlloc, DynAllocOrder> HeapAllocs;
-
- /// The number of heap allocations performed so far in this evaluation.
- unsigned NumHeapAllocs = 0;
-
- struct EvaluatingConstructorRAII {
- EvalInfo &EI;
- ObjectUnderConstruction Object;
- bool DidInsert;
- EvaluatingConstructorRAII(EvalInfo &EI, ObjectUnderConstruction Object,
- bool HasBases)
- : EI(EI), Object(Object) {
- DidInsert =
- EI.ObjectsUnderConstruction
- .insert({Object, HasBases ? ConstructionPhase::Bases
- : ConstructionPhase::AfterBases})
- .second;
- }
- void finishedConstructingBases() {
- EI.ObjectsUnderConstruction[Object] = ConstructionPhase::AfterBases;
- }
- void finishedConstructingFields() {
- EI.ObjectsUnderConstruction[Object] = ConstructionPhase::AfterFields;
- }
- ~EvaluatingConstructorRAII() {
- if (DidInsert) EI.ObjectsUnderConstruction.erase(Object);
- }
- };
+ /// EvaluatingDecl - This is the declaration whose initializer is being
+ /// evaluated, if any.
+ APValue::LValueBase EvaluatingDecl;
- struct EvaluatingDestructorRAII {
- EvalInfo &EI;
- ObjectUnderConstruction Object;
- bool DidInsert;
- EvaluatingDestructorRAII(EvalInfo &EI, ObjectUnderConstruction Object)
- : EI(EI), Object(Object) {
- DidInsert = EI.ObjectsUnderConstruction
- .insert({Object, ConstructionPhase::Destroying})
- .second;
- }
- void startedDestroyingBases() {
- EI.ObjectsUnderConstruction[Object] =
- ConstructionPhase::DestroyingBases;
- }
- ~EvaluatingDestructorRAII() {
- if (DidInsert)
- EI.ObjectsUnderConstruction.erase(Object);
- }
- };
+ enum class EvaluatingDeclKind {
+ None,
+ /// We're evaluating the construction of EvaluatingDecl.
+ Ctor,
+ /// We're evaluating the destruction of EvaluatingDecl.
+ Dtor,
+ };
+ EvaluatingDeclKind IsEvaluatingDecl = EvaluatingDeclKind::None;
+
+ /// EvaluatingDeclValue - This is the value being constructed for the
+ /// declaration whose initializer is being evaluated, if any.
+ APValue *EvaluatingDeclValue;
+
+ /// Stack of loops and 'switch' statements which we're currently
+ /// breaking/continuing; null entries are used to mark unlabeled
+ /// break/continue.
+ SmallVector<const Stmt *> BreakContinueStack;
+
+ /// Set of objects that are currently being constructed.
+ llvm::DenseMap<ObjectUnderConstruction, ConstructionPhase>
+ ObjectsUnderConstruction;
+
+ /// Current heap allocations, along with the location where each was
+ /// allocated. We use std::map here because we need stable addresses
+ /// for the stored APValues.
+ std::map<DynamicAllocLValue, DynAlloc, DynAllocOrder> HeapAllocs;
+
+ /// The number of heap allocations performed so far in this evaluation.
+ unsigned NumHeapAllocs = 0;
+
+ struct EvaluatingConstructorRAII {
+ EvalInfo &EI;
+ ObjectUnderConstruction Object;
+ bool DidInsert;
+ EvaluatingConstructorRAII(EvalInfo &EI, ObjectUnderConstruction Object,
+ bool HasBases)
+ : EI(EI), Object(Object) {
+ DidInsert =
+ EI.ObjectsUnderConstruction
+ .insert({Object, HasBases ? ConstructionPhase::Bases
+ : ConstructionPhase::AfterBases})
+ .second;
+ }
+ void finishedConstructingBases() {
+ EI.ObjectsUnderConstruction[Object] = ConstructionPhase::AfterBases;
+ }
+ void finishedConstructingFields() {
+ EI.ObjectsUnderConstruction[Object] = ConstructionPhase::AfterFields;
+ }
+ ~EvaluatingConstructorRAII() {
+ if (DidInsert)
+ EI.ObjectsUnderConstruction.erase(Object);
+ }
+ };
- ConstructionPhase
- isEvaluatingCtorDtor(APValue::LValueBase Base,
- ArrayRef<APValue::LValuePathEntry> Path) {
- return ObjectsUnderConstruction.lookup({Base, Path});
+ struct EvaluatingDestructorRAII {
+ EvalInfo &EI;
+ ObjectUnderConstruction Object;
+ bool DidInsert;
+ EvaluatingDestructorRAII(EvalInfo &EI, ObjectUnderConstruction Object)
+ : EI(EI), Object(Object) {
+ DidInsert = EI.ObjectsUnderConstruction
+ .insert({Object, ConstructionPhase::Destroying})
+ .second;
+ }
+ void startedDestroyingBases() {
+ EI.ObjectsUnderConstruction[Object] = ConstructionPhase::DestroyingBases;
+ }
+ ~EvaluatingDestructorRAII() {
+ if (DidInsert)
+ EI.ObjectsUnderConstruction.erase(Object);
}
+ };
- /// If we're currently speculatively evaluating, the outermost call stack
- /// depth at which we can mutate state, otherwise 0.
- unsigned SpeculativeEvaluationDepth = 0;
+ ConstructionPhase
+ isEvaluatingCtorDtor(APValue::LValueBase Base,
+ ArrayRef<APValue::LValuePathEntry> Path) {
+ return ObjectsUnderConstruction.lookup({Base, Path});
+ }
- /// The current array initialization index, if we're performing array
- /// initialization.
- uint64_t ArrayInitIndex = -1;
+ /// If we're currently speculatively evaluating, the outermost call stack
+ /// depth at which we can mutate state, otherwise 0.
+ unsigned SpeculativeEvaluationDepth = 0;
- /// HasActiveDiagnostic - Was the previous diagnostic stored? If so, further
- /// notes attached to it will also be stored, otherwise they will not be.
- bool HasActiveDiagnostic;
+ /// The current array initialization index, if we're performing array
+ /// initialization.
+ uint64_t ArrayInitIndex = -1;
- /// Have we emitted a diagnostic explaining why we couldn't constant
- /// fold (not just why it's not strictly a constant expression)?
- bool HasFoldFailureDiagnostic;
+ /// HasActiveDiagnostic - Was the previous diagnostic stored? If so, further
+ /// notes attached to it will also be stored, otherwise they will not be.
+ bool HasActiveDiagnostic;
- EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode)
- : Ctx(const_cast<ASTContext &>(C)), EvalStatus(S), CurrentCall(nullptr),
- CallStackDepth(0), NextCallIndex(1),
- StepsLeft(C.getLangOpts().ConstexprStepLimit),
- EnableNewConstInterp(C.getLangOpts().EnableNewConstInterp),
- BottomFrame(*this, SourceLocation(), /*Callee=*/nullptr,
- /*This=*/nullptr,
- /*CallExpr=*/nullptr, CallRef()),
- EvaluatingDecl((const ValueDecl *)nullptr),
- EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
- HasFoldFailureDiagnostic(false) {
- EvalMode = Mode;
- }
+ /// Have we emitted a diagnostic explaining why we couldn't constant
+ /// fold (not just why it's not strictly a constant expression)?
+ bool HasFoldFailureDiagnostic;
- ~EvalInfo() {
- discardCleanups();
- }
+ EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode)
+ : Ctx(const_cast<ASTContext &>(C)), EvalStatus(S), CurrentCall(nullptr),
+ CallStackDepth(0), NextCallIndex(1),
+ StepsLeft(C.getLangOpts().ConstexprStepLimit),
+ EnableNewConstInterp(C.getLangOpts().EnableNewConstInterp),
+ BottomFrame(*this, SourceLocation(), /*Callee=*/nullptr,
+ /*This=*/nullptr,
+ /*CallExpr=*/nullptr, CallRef()),
+ EvaluatingDecl((const ValueDecl *)nullptr),
+ EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
+ HasFoldFailureDiagnostic(false) {
+ EvalMode = Mode;
+ }
- ASTContext &getASTContext() const override { return Ctx; }
- const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); }
+ ~EvalInfo() { discardCleanups(); }
- void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value,
- EvaluatingDeclKind EDK = EvaluatingDeclKind::Ctor) {
- EvaluatingDecl = Base;
- IsEvaluatingDecl = EDK;
- EvaluatingDeclValue = &Value;
- }
+ ASTContext &getASTContext() const override { return Ctx; }
+ const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); }
- bool CheckCallLimit(SourceLocation Loc) {
- // Don't perform any constexpr calls (other than the call we're checking)
- // when checking a potential constant expression.
- if (checkingPotentialConstantExpression() && CallStackDepth > 1)
- return false;
- if (NextCallIndex == 0) {
- // NextCallIndex has wrapped around.
- FFDiag(Loc, diag::note_constexpr_call_limit_exceeded);
- return false;
- }
- if (CallStackDepth <= getLangOpts().ConstexprCallDepth)
- return true;
- FFDiag(Loc, diag::note_constexpr_depth_limit_exceeded)
- << getLangOpts().ConstexprCallDepth;
+ void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value,
+ EvaluatingDeclKind EDK = EvaluatingDeclKind::Ctor) {
+ EvaluatingDecl = Base;
+ IsEvaluatingDecl = EDK;
+ EvaluatingDeclValue = &Value;
+ }
+
+ bool CheckCallLimit(SourceLocation Loc) {
+ // Don't perform any constexpr calls (other than the call we're checking)
+ // when checking a potential constant expression.
+ if (checkingPotentialConstantExpression() && CallStackDepth > 1)
+ return false;
+ if (NextCallIndex == 0) {
+ // NextCallIndex has wrapped around.
+ FFDiag(Loc, diag::note_constexpr_call_limit_exceeded);
return false;
}
-
- bool CheckArraySize(SourceLocation Loc, unsigned BitWidth,
- uint64_t ElemCount, bool Diag) {
- // FIXME: GH63562
- // APValue stores array extents as unsigned,
- // so anything that is greater that unsigned would overflow when
- // constructing the array, we catch this here.
- if (BitWidth > ConstantArrayType::getMaxSizeBits(Ctx) ||
- ElemCount > uint64_t(std::numeric_limits<unsigned>::max())) {
- if (Diag)
- FFDiag(Loc, diag::note_constexpr_new_too_large) << ElemCount;
- return false;
- }
-
- // FIXME: GH63562
- // Arrays allocate an APValue per element.
- // We use the number of constexpr steps as a proxy for the maximum size
- // of arrays to avoid exhausting the system resources, as initialization
- // of each element is likely to take some number of steps anyway.
- uint64_t Limit = Ctx.getLangOpts().ConstexprStepLimit;
- if (ElemCount > Limit) {
- if (Diag)
- FFDiag(Loc, diag::note_constexpr_new_exceeds_limits)
- << ElemCount << Limit;
- return false;
- }
+ if (CallStackDepth <= getLangOpts().ConstexprCallDepth)
return true;
- }
+ FFDiag(Loc, diag::note_constexpr_depth_limit_exceeded)
+ << getLangOpts().ConstexprCallDepth;
+ return false;
+ }
- std::pair<CallStackFrame *, unsigned>
- getCallFrameAndDepth(unsigned CallIndex) {
- assert(CallIndex && "no call index in getCallFrameAndDepth");
- // We will eventually hit BottomFrame, which has Index 1, so Frame can't
- // be null in this loop.
- unsigned Depth = CallStackDepth;
- CallStackFrame *Frame = CurrentCall;
- while (Frame->Index > CallIndex) {
- Frame = Frame->Caller;
- --Depth;
- }
- if (Frame->Index == CallIndex)
- return {Frame, Depth};
- return {nullptr, 0};
+ bool CheckArraySize(SourceLocation Loc, unsigned BitWidth, uint64_t ElemCount,
+ bool Diag) {
+ // FIXME: GH63562
+ // APValue stores array extents as unsigned,
+ // so anything that is greater that unsigned would overflow when
+ // constructing the array, we catch this here.
+ if (BitWidth > ConstantArrayType::getMaxSizeBits(Ctx) ||
+ ElemCount > uint64_t(std::numeric_limits<unsigned>::max())) {
+ if (Diag)
+ FFDiag(Loc, diag::note_constexpr_new_too_large) << ElemCount;
+ return false;
}
- bool nextStep(const Stmt *S) {
- if (!StepsLeft) {
- FFDiag(S->getBeginLoc(), diag::note_constexpr_step_limit_exceeded);
- return false;
- }
- --StepsLeft;
- return true;
+ // FIXME: GH63562
+ // Arrays allocate an APValue per element.
+ // We use the number of constexpr steps as a proxy for the maximum size
+ // of arrays to avoid exhausting the system resources, as initialization
+ // of each element is likely to take some number of steps anyway.
+ uint64_t Limit = Ctx.getLangOpts().ConstexprStepLimit;
+ if (ElemCount > Limit) {
+ if (Diag)
+ FFDiag(Loc, diag::note_constexpr_new_exceeds_limits)
+ << ElemCount << Limit;
+ return false;
}
+ return true;
+ }
- APValue *createHeapAlloc(const Expr *E, QualType T, LValue &LV);
-
- std::optional<DynAlloc *> lookupDynamicAlloc(DynamicAllocLValue DA) {
- std::optional<DynAlloc *> Result;
- auto It = HeapAllocs.find(DA);
- if (It != HeapAllocs.end())
- Result = &It->second;
- return Result;
+ std::pair<CallStackFrame *, unsigned>
+ getCallFrameAndDepth(unsigned CallIndex) {
+ assert(CallIndex && "no call index in getCallFrameAndDepth");
+ // We will eventually hit BottomFrame, which has Index 1, so Frame can't
+ // be null in this loop.
+ unsigned Depth = CallStackDepth;
+ CallStackFrame *Frame = CurrentCall;
+ while (Frame->Index > CallIndex) {
+ Frame = Frame->Caller;
+ --Depth;
}
+ if (Frame->Index == CallIndex)
+ return {Frame, Depth};
+ return {nullptr, 0};
+ }
- /// Get the allocated storage for the given parameter of the given call.
- APValue *getParamSlot(CallRef Call, const ParmVarDecl *PVD) {
- CallStackFrame *Frame = getCallFrameAndDepth(Call.CallIndex).first;
- return Frame ? Frame->getTemporary(Call.getOrigParam(PVD), Call.Version)
- : nullptr;
+ bool nextStep(const Stmt *S) {
+ if (!StepsLeft) {
+ FFDiag(S->getBeginLoc(), diag::note_constexpr_step_limit_exceeded);
+ return false;
}
+ --StepsLeft;
+ return true;
+ }
- /// Information about a stack frame for std::allocator<T>::[de]allocate.
- struct StdAllocatorCaller {
- unsigned FrameIndex;
- QualType ElemType;
- const Expr *Call;
- explicit operator bool() const { return FrameIndex != 0; };
- };
+ APValue *createHeapAlloc(const Expr *E, QualType T, LValue &LV);
- StdAllocatorCaller getStdAllocatorCaller(StringRef FnName) const {
- for (const CallStackFrame *Call = CurrentCall; Call != &BottomFrame;
- Call = Call->Caller) {
- const auto *MD = dyn_cast_or_null<CXXMethodDecl>(Call->Callee);
- if (!MD)
- continue;
- const IdentifierInfo *FnII = MD->getIdentifier();
- if (!FnII || !FnII->isStr(FnName))
- continue;
+ std::optional<DynAlloc *> lookupDynamicAlloc(DynamicAllocLValue DA) {
+ std::optional<DynAlloc *> Result;
+ auto It = HeapAllocs.find(DA);
+ if (It != HeapAllocs.end())
+ Result = &It->second;
+ return Result;
+ }
- const auto *CTSD =
- dyn_cast<ClassTemplateSpecializationDecl>(MD->getParent());
- if (!CTSD)
- continue;
+ /// Get the allocated storage for the given parameter of the given call.
+ APValue *getParamSlot(CallRef Call, const ParmVarDecl *PVD) {
+ CallStackFrame *Frame = getCallFrameAndDepth(Call.CallIndex).first;
+ return Frame ? Frame->getTemporary(Call.getOrigParam(PVD), Call.Version)
+ : nullptr;
+ }
- const IdentifierInfo *ClassII = CTSD->getIdentifier();
- const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
- if (CTSD->isInStdNamespace() && ClassII &&
- ClassII->isStr("allocator") && TAL.size() >= 1 &&
- TAL[0].getKind() == TemplateArgument::Type)
- return {Call->Index, TAL[0].getAsType(), Call->CallExpr};
- }
+ /// Information about a stack frame for std::allocator<T>::[de]allocate.
+ struct StdAllocatorCaller {
+ unsigned FrameIndex;
+ QualType ElemType;
+ const Expr *Call;
+ explicit operator bool() const { return FrameIndex != 0; };
+ };
- return {};
- }
+ StdAllocatorCaller getStdAllocatorCaller(StringRef FnName) const {
+ for (const CallStackFrame *Call = CurrentCall; Call != &BottomFrame;
+ Call = Call->Caller) {
+ const auto *MD = dyn_cast_or_null<CXXMethodDecl>(Call->Callee);
+ if (!MD)
+ continue;
+ const IdentifierInfo *FnII = MD->getIdentifier();
+ if (!FnII || !FnII->isStr(FnName))
+ continue;
- void performLifetimeExtension() {
- // Disable the cleanups for lifetime-extended temporaries.
- llvm::erase_if(CleanupStack, [](Cleanup &C) {
- return !C.isDestroyedAtEndOf(ScopeKind::FullExpression);
- });
- }
+ const auto *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(MD->getParent());
+ if (!CTSD)
+ continue;
- /// Throw away any remaining cleanups at the end of evaluation. If any
- /// cleanups would have had a side-effect, note that as an unmodeled
- /// side-effect and return false. Otherwise, return true.
- bool discardCleanups() {
- for (Cleanup &C : CleanupStack) {
- if (C.hasSideEffect() && !noteSideEffect()) {
- CleanupStack.clear();
- return false;
- }
- }
- CleanupStack.clear();
- return true;
+ const IdentifierInfo *ClassII = CTSD->getIdentifier();
+ const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
+ if (CTSD->isInStdNamespace() && ClassII && ClassII->isStr("allocator") &&
+ TAL.size() >= 1 && TAL[0].getKind() == TemplateArgument::Type)
+ return {Call->Index, TAL[0].getAsType(), Call->CallExpr};
}
- private:
- interp::Frame *getCurrentFrame() override { return CurrentCall; }
- const interp::Frame *getBottomFrame() const override { return &BottomFrame; }
+ return {};
+ }
- bool hasActiveDiagnostic() override { return HasActiveDiagnostic; }
- void setActiveDiagnostic(bool Flag) override { HasActiveDiagnostic = Flag; }
+ void performLifetimeExtension() {
+ // Disable the cleanups for lifetime-extended temporaries.
+ llvm::erase_if(CleanupStack, [](Cleanup &C) {
+ return !C.isDestroyedAtEndOf(ScopeKind::FullExpression);
+ });
+ }
- void setFoldFailureDiagnostic(bool Flag) override {
- HasFoldFailureDiagnostic = Flag;
+ /// Throw away any remaining cleanups at the end of evaluation. If any
+ /// cleanups would have had a side-effect, note that as an unmodeled
+ /// side-effect and return false. Otherwise, return true.
+ bool discardCleanups() {
+ for (Cleanup &C : CleanupStack) {
+ if (C.hasSideEffect() && !noteSideEffect()) {
+ CleanupStack.clear();
+ return false;
+ }
}
+ CleanupStack.clear();
+ return true;
+ }
- Expr::EvalStatus &getEvalStatus() const override { return EvalStatus; }
+private:
+ interp::Frame *getCurrentFrame() override { return CurrentCall; }
+ const interp::Frame *getBottomFrame() const override { return &BottomFrame; }
- // If we have a prior diagnostic, it will be noting that the expression
- // isn't a constant expression. This diagnostic is more important,
- // unless we require this evaluation to produce a constant expression.
- //
- // FIXME: We might want to show both diagnostics to the user in
- // EvaluationMode::ConstantFold mode.
- bool hasPriorDiagnostic() override {
- if (!EvalStatus.Diag->empty()) {
- switch (EvalMode) {
- case EvaluationMode::ConstantFold:
- case EvaluationMode::IgnoreSideEffects:
- if (!HasFoldFailureDiagnostic)
- break;
- // We've already failed to fold something. Keep that diagnostic.
- [[fallthrough]];
- case EvaluationMode::ConstantExpression:
- case EvaluationMode::ConstantExpressionUnevaluated:
- setActiveDiagnostic(false);
- return true;
- }
- }
- return false;
- }
+ bool hasActiveDiagnostic() override { return HasActiveDiagnostic; }
+ void setActiveDiagnostic(bool Flag) override { HasActiveDiagnostic = Flag; }
+
+ void setFoldFailureDiagnostic(bool Flag) override {
+ HasFoldFailureDiagnostic = Flag;
+ }
- unsigned getCallStackDepth() override { return CallStackDepth; }
+ Expr::EvalStatus &getEvalStatus() const override { return EvalStatus; }
- public:
- /// Should we continue evaluation after encountering a side-effect that we
- /// couldn't model?
- bool keepEvaluatingAfterSideEffect() const override {
+ // If we have a prior diagnostic, it will be noting that the expression
+ // isn't a constant expression. This diagnostic is more important,
+ // unless we require this evaluation to produce a constant expression.
+ //
+ // FIXME: We might want to show both diagnostics to the user in
+ // EvaluationMode::ConstantFold mode.
+ bool hasPriorDiagnostic() override {
+ if (!EvalStatus.Diag->empty()) {
switch (EvalMode) {
+ case EvaluationMode::ConstantFold:
case EvaluationMode::IgnoreSideEffects:
- return true;
-
+ if (!HasFoldFailureDiagnostic)
+ break;
+ // We've already failed to fold something. Keep that diagnostic.
+ [[fallthrough]];
case EvaluationMode::ConstantExpression:
case EvaluationMode::ConstantExpressionUnevaluated:
- case EvaluationMode::ConstantFold:
- // By default, assume any side effect might be valid in some other
- // evaluation of this expression from a different context.
- return checkingPotentialConstantExpression() ||
- checkingForUndefinedBehavior();
+ setActiveDiagnostic(false);
+ return true;
}
- llvm_unreachable("Missed EvalMode case");
}
+ return false;
+ }
- /// Note that we have had a side-effect, and determine whether we should
- /// keep evaluating.
- bool noteSideEffect() override {
- EvalStatus.HasSideEffects = true;
- return keepEvaluatingAfterSideEffect();
- }
+ unsigned getCallStackDepth() override { return CallStackDepth; }
- /// Should we continue evaluation after encountering undefined behavior?
- bool keepEvaluatingAfterUndefinedBehavior() {
- switch (EvalMode) {
- case EvaluationMode::IgnoreSideEffects:
- case EvaluationMode::ConstantFold:
- return true;
+public:
+ /// Should we continue evaluation after encountering a side-effect that we
+ /// couldn't model?
+ bool keepEvaluatingAfterSideEffect() const override {
+ switch (EvalMode) {
+ case EvaluationMode::IgnoreSideEffects:
+ return true;
- case EvaluationMode::ConstantExpression:
- case EvaluationMode::ConstantExpressionUnevaluated:
- return checkingForUndefinedBehavior();
- }
- llvm_unreachable("Missed EvalMode case");
+ case EvaluationMode::ConstantExpression:
+ case EvaluationMode::ConstantExpressionUnevaluated:
+ case EvaluationMode::ConstantFold:
+ // By default, assume any side effect might be valid in some other
+ // evaluation of this expression from a different context.
+ return checkingPotentialConstantExpression() ||
+ checkingForUndefinedBehavior();
}
+ llvm_unreachable("Missed EvalMode case");
+ }
- /// Note that we hit something that was technically undefined behavior, but
- /// that we can evaluate past it (such as signed overflow or floating-point
- /// division by zero.)
- bool noteUndefinedBehavior() override {
- EvalStatus.HasUndefinedBehavior = true;
- return keepEvaluatingAfterUndefinedBehavior();
+ /// Note that we have had a side-effect, and determine whether we should
+ /// keep evaluating.
+ bool noteSideEffect() override {
+ EvalStatus.HasSideEffects = true;
+ return keepEvaluatingAfterSideEffect();
+ }
+
+ /// Should we continue evaluation after encountering undefined behavior?
+ bool keepEvaluatingAfterUndefinedBehavior() {
+ switch (EvalMode) {
+ case EvaluationMode::IgnoreSideEffects:
+ case EvaluationMode::ConstantFold:
+ return true;
+
+ case EvaluationMode::ConstantExpression:
+ case EvaluationMode::ConstantExpressionUnevaluated:
+ return checkingForUndefinedBehavior();
}
+ llvm_unreachable("Missed EvalMode case");
+ }
- /// Should we continue evaluation as much as possible after encountering a
- /// construct which can't be reduced to a value?
- bool keepEvaluatingAfterFailure() const override {
- if (!StepsLeft)
- return false;
+ /// Note that we hit something that was technically undefined behavior, but
+ /// that we can evaluate past it (such as signed overflow or floating-point
+ /// division by zero.)
+ bool noteUndefinedBehavior() override {
+ EvalStatus.HasUndefinedBehavior = true;
+ return keepEvaluatingAfterUndefinedBehavior();
+ }
- switch (EvalMode) {
- case EvaluationMode::ConstantExpression:
- case EvaluationMode::ConstantExpressionUnevaluated:
- case EvaluationMode::ConstantFold:
- case EvaluationMode::IgnoreSideEffects:
- return checkingPotentialConstantExpression() ||
- checkingForUndefinedBehavior();
- }
- llvm_unreachable("Missed EvalMode case");
- }
-
- /// Notes that we failed to evaluate an expression that other expressions
- /// directly depend on, and determine if we should keep evaluating. This
- /// should only be called if we actually intend to keep evaluating.
- ///
- /// Call noteSideEffect() instead if we may be able to ignore the value that
- /// we failed to evaluate, e.g. if we failed to evaluate Foo() in:
- ///
- /// (Foo(), 1) // use noteSideEffect
- /// (Foo() || true) // use noteSideEffect
- /// Foo() + 1 // use noteFailure
- [[nodiscard]] bool noteFailure() {
- // Failure when evaluating some expression often means there is some
- // subexpression whose evaluation was skipped. Therefore, (because we
- // don't track whether we skipped an expression when unwinding after an
- // evaluation failure) every evaluation failure that bubbles up from a
- // subexpression implies that a side-effect has potentially happened. We
- // skip setting the HasSideEffects flag to true until we decide to
- // continue evaluating after that point, which happens here.
- bool KeepGoing = keepEvaluatingAfterFailure();
- EvalStatus.HasSideEffects |= KeepGoing;
- return KeepGoing;
- }
-
- class ArrayInitLoopIndex {
- EvalInfo &Info;
- uint64_t OuterIndex;
+ /// Should we continue evaluation as much as possible after encountering a
+ /// construct which can't be reduced to a value?
+ bool keepEvaluatingAfterFailure() const override {
+ if (!StepsLeft)
+ return false;
- public:
- ArrayInitLoopIndex(EvalInfo &Info)
- : Info(Info), OuterIndex(Info.ArrayInitIndex) {
- Info.ArrayInitIndex = 0;
- }
- ~ArrayInitLoopIndex() { Info.ArrayInitIndex = OuterIndex; }
+ switch (EvalMode) {
+ case EvaluationMode::ConstantExpression:
+ case EvaluationMode::ConstantExpressionUnevaluated:
+ case EvaluationMode::ConstantFold:
+ case EvaluationMode::IgnoreSideEffects:
+ return checkingPotentialConstantExpression() ||
+ checkingForUndefinedBehavior();
+ }
+ llvm_unreachable("Missed EvalMode case");
+ }
+
+ /// Notes that we failed to evaluate an expression that other expressions
+ /// directly depend on, and determine if we should keep evaluating. This
+ /// should only be called if we actually intend to keep evaluating.
+ ///
+ /// Call noteSideEffect() instead if we may be able to ignore the value that
+ /// we failed to evaluate, e.g. if we failed to evaluate Foo() in:
+ ///
+ /// (Foo(), 1) // use noteSideEffect
+ /// (Foo() || true) // use noteSideEffect
+ /// Foo() + 1 // use noteFailure
+ [[nodiscard]] bool noteFailure() {
+ // Failure when evaluating some expression often means there is some
+ // subexpression whose evaluation was skipped. Therefore, (because we
+ // don't track whether we skipped an expression when unwinding after an
+ // evaluation failure) every evaluation failure that bubbles up from a
+ // subexpression implies that a side-effect has potentially happened. We
+ // skip setting the HasSideEffects flag to true until we decide to
+ // continue evaluating after that point, which happens here.
+ bool KeepGoing = keepEvaluatingAfterFailure();
+ EvalStatus.HasSideEffects |= KeepGoing;
+ return KeepGoing;
+ }
+
+ class ArrayInitLoopIndex {
+ EvalInfo &Info;
+ uint64_t OuterIndex;
+
+ public:
+ ArrayInitLoopIndex(EvalInfo &Info)
+ : Info(Info), OuterIndex(Info.ArrayInitIndex) {
+ Info.ArrayInitIndex = 0;
+ }
+ ~ArrayInitLoopIndex() { Info.ArrayInitIndex = OuterIndex; }
- operator uint64_t&() { return Info.ArrayInitIndex; }
- };
+ operator uint64_t &() { return Info.ArrayInitIndex; }
};
+};
- /// Object used to treat all foldable expressions as constant expressions.
- struct FoldConstant {
- EvalInfo &Info;
- bool Enabled;
- bool HadNoPriorDiags;
- EvaluationMode OldMode;
+/// Object used to treat all foldable expressions as constant expressions.
+struct FoldConstant {
+ EvalInfo &Info;
+ bool Enabled;
+ bool HadNoPriorDiags;
+ EvaluationMode OldMode;
- explicit FoldConstant(EvalInfo &Info, bool Enabled)
- : Info(Info),
- Enabled(Enabled),
- HadNoPriorDiags(Info.EvalStatus.Diag &&
- Info.EvalStatus.Diag->empty() &&
+ explicit FoldConstant(EvalInfo &Info, bool Enabled)
+ : Info(Info), Enabled(Enabled),
+ HadNoPriorDiags(Info.EvalStatus.Diag && Info.EvalStatus.Diag->empty() &&
!Info.EvalStatus.HasSideEffects),
OldMode(Info.EvalMode) {
- if (Enabled)
- Info.EvalMode = EvaluationMode::ConstantFold;
- }
- void keepDiagnostics() { Enabled = false; }
- ~FoldConstant() {
- if (Enabled && HadNoPriorDiags && !Info.EvalStatus.Diag->empty() &&
- !Info.EvalStatus.HasSideEffects)
- Info.EvalStatus.Diag->clear();
- Info.EvalMode = OldMode;
- }
- };
+ if (Enabled)
+ Info.EvalMode = EvaluationMode::ConstantFold;
+ }
+ void keepDiagnostics() { Enabled = false; }
+ ~FoldConstant() {
+ if (Enabled && HadNoPriorDiags && !Info.EvalStatus.Diag->empty() &&
+ !Info.EvalStatus.HasSideEffects)
+ Info.EvalStatus.Diag->clear();
+ Info.EvalMode = OldMode;
+ }
+};
- /// RAII object used to set the current evaluation mode to ignore
- /// side-effects.
- struct IgnoreSideEffectsRAII {
- EvalInfo &Info;
- EvaluationMode OldMode;
- explicit IgnoreSideEffectsRAII(EvalInfo &Info)
- : Info(Info), OldMode(Info.EvalMode) {
- Info.EvalMode = EvaluationMode::IgnoreSideEffects;
- }
+/// RAII object used to set the current evaluation mode to ignore
+/// side-effects.
+struct IgnoreSideEffectsRAII {
+ EvalInfo &Info;
+ EvaluationMode OldMode;
+ explicit IgnoreSideEffectsRAII(EvalInfo &Info)
+ : Info(Info), OldMode(Info.EvalMode) {
+ Info.EvalMode = EvaluationMode::IgnoreSideEffects;
+ }
- ~IgnoreSideEffectsRAII() { Info.EvalMode = OldMode; }
- };
+ ~IgnoreSideEffectsRAII() { Info.EvalMode = OldMode; }
+};
- /// RAII object used to optionally suppress diagnostics and side-effects from
- /// a speculative evaluation.
- class SpeculativeEvaluationRAII {
- EvalInfo *Info = nullptr;
- Expr::EvalStatus OldStatus;
- unsigned OldSpeculativeEvaluationDepth = 0;
+/// RAII object used to optionally suppress diagnostics and side-effects from
+/// a speculative evaluation.
+class SpeculativeEvaluationRAII {
+ EvalInfo *Info = nullptr;
+ Expr::EvalStatus OldStatus;
+ unsigned OldSpeculativeEvaluationDepth = 0;
- void moveFromAndCancel(SpeculativeEvaluationRAII &&Other) {
- Info = Other.Info;
- OldStatus = Other.OldStatus;
- OldSpeculativeEvaluationDepth = Other.OldSpeculativeEvaluationDepth;
- Other.Info = nullptr;
- }
+ void moveFromAndCancel(SpeculativeEvaluationRAII &&Other) {
+ Info = Other.Info;
+ OldStatus = Other.OldStatus;
+ OldSpeculativeEvaluationDepth = Other.OldSpeculativeEvaluationDepth;
+ Other.Info = nullptr;
+ }
- void maybeRestoreState() {
- if (!Info)
- return;
+ void maybeRestoreState() {
+ if (!Info)
+ return;
- Info->EvalStatus = OldStatus;
- Info->SpeculativeEvaluationDepth = OldSpeculativeEvaluationDepth;
- }
+ Info->EvalStatus = OldStatus;
+ Info->SpeculativeEvaluationDepth = OldSpeculativeEvaluationDepth;
+ }
- public:
- SpeculativeEvaluationRAII() = default;
+public:
+ SpeculativeEvaluationRAII() = default;
- SpeculativeEvaluationRAII(
- EvalInfo &Info, SmallVectorImpl<PartialDiagnosticAt> *NewDiag = nullptr)
- : Info(&Info), OldStatus(Info.EvalStatus),
- OldSpeculativeEvaluationDepth(Info.SpeculativeEvaluationDepth) {
- Info.EvalStatus.Diag = NewDiag;
- Info.SpeculativeEvaluationDepth = Info.CallStackDepth + 1;
- }
+ SpeculativeEvaluationRAII(
+ EvalInfo &Info, SmallVectorImpl<PartialDiagnosticAt> *NewDiag = nullptr)
+ : Info(&Info), OldStatus(Info.EvalStatus),
+ OldSpeculativeEvaluationDepth(Info.SpeculativeEvaluationDepth) {
+ Info.EvalStatus.Diag = NewDiag;
+ Info.SpeculativeEvaluationDepth = Info.CallStackDepth + 1;
+ }
- SpeculativeEvaluationRAII(const SpeculativeEvaluationRAII &Other) = delete;
- SpeculativeEvaluationRAII(SpeculativeEvaluationRAII &&Other) {
- moveFromAndCancel(std::move(Other));
- }
+ SpeculativeEvaluationRAII(const SpeculativeEvaluationRAII &Other) = delete;
+ SpeculativeEvaluationRAII(SpeculativeEvaluationRAII &&Other) {
+ moveFromAndCancel(std::move(Other));
+ }
- SpeculativeEvaluationRAII &operator=(SpeculativeEvaluationRAII &&Other) {
- maybeRestoreState();
- moveFromAndCancel(std::move(Other));
- return *this;
- }
+ SpeculativeEvaluationRAII &operator=(SpeculativeEvaluationRAII &&Other) {
+ maybeRestoreState();
+ moveFromAndCancel(std::move(Other));
+ return *this;
+ }
- ~SpeculativeEvaluationRAII() { maybeRestoreState(); }
- };
+ ~SpeculativeEvaluationRAII() { maybeRestoreState(); }
+};
- /// RAII object wrapping a full-expression or block scope, and handling
- /// the ending of the lifetime of temporaries created within it.
- template<ScopeKind Kind>
- class ScopeRAII {
- EvalInfo &Info;
- unsigned OldStackSize;
- public:
- ScopeRAII(EvalInfo &Info)
- : Info(Info), OldStackSize(Info.CleanupStack.size()) {
- // Push a new temporary version. This is needed to distinguish between
- // temporaries created in different iterations of a loop.
- Info.CurrentCall->pushTempVersion();
- }
- bool destroy(bool RunDestructors = true) {
- bool OK = cleanup(Info, RunDestructors, OldStackSize);
- OldStackSize = std::numeric_limits<unsigned>::max();
- return OK;
- }
- ~ScopeRAII() {
- if (OldStackSize != std::numeric_limits<unsigned>::max())
- destroy(false);
- // Body moved to a static method to encourage the compiler to inline away
- // instances of this class.
- Info.CurrentCall->popTempVersion();
- }
- private:
- static bool cleanup(EvalInfo &Info, bool RunDestructors,
- unsigned OldStackSize) {
- assert(OldStackSize <= Info.CleanupStack.size() &&
- "running cleanups out of order?");
+/// RAII object wrapping a full-expression or block scope, and handling
+/// the ending of the lifetime of temporaries created within it.
+template <ScopeKind Kind> class ScopeRAII {
+ EvalInfo &Info;
+ unsigned OldStackSize;
- // Run all cleanups for a block scope, and non-lifetime-extended cleanups
- // for a full-expression scope.
- bool Success = true;
- for (unsigned I = Info.CleanupStack.size(); I > OldStackSize; --I) {
- if (Info.CleanupStack[I - 1].isDestroyedAtEndOf(Kind)) {
- if (!Info.CleanupStack[I - 1].endLifetime(Info, RunDestructors)) {
- Success = false;
- break;
- }
+public:
+ ScopeRAII(EvalInfo &Info)
+ : Info(Info), OldStackSize(Info.CleanupStack.size()) {
+ // Push a new temporary version. This is needed to distinguish between
+ // temporaries created in different iterations of a loop.
+ Info.CurrentCall->pushTempVersion();
+ }
+ bool destroy(bool RunDestructors = true) {
+ bool OK = cleanup(Info, RunDestructors, OldStackSize);
+ OldStackSize = std::numeric_limits<unsigned>::max();
+ return OK;
+ }
+ ~ScopeRAII() {
+ if (OldStackSize != std::numeric_limits<unsigned>::max())
+ destroy(false);
+ // Body moved to a static method to encourage the compiler to inline away
+ // instances of this class.
+ Info.CurrentCall->popTempVersion();
+ }
+
+private:
+ static bool cleanup(EvalInfo &Info, bool RunDestructors,
+ unsigned OldStackSize) {
+ assert(OldStackSize <= Info.CleanupStack.size() &&
+ "running cleanups out of order?");
+
+ // Run all cleanups for a block scope, and non-lifetime-extended cleanups
+ // for a full-expression scope.
+ bool Success = true;
+ for (unsigned I = Info.CleanupStack.size(); I > OldStackSize; --I) {
+ if (Info.CleanupStack[I - 1].isDestroyedAtEndOf(Kind)) {
+ if (!Info.CleanupStack[I - 1].endLifetime(Info, RunDestructors)) {
+ Success = false;
+ break;
}
}
-
- // Compact any retained cleanups.
- auto NewEnd = Info.CleanupStack.begin() + OldStackSize;
- if (Kind != ScopeKind::Block)
- NewEnd =
- std::remove_if(NewEnd, Info.CleanupStack.end(), [](Cleanup &C) {
- return C.isDestroyedAtEndOf(Kind);
- });
- Info.CleanupStack.erase(NewEnd, Info.CleanupStack.end());
- return Success;
}
- };
- typedef ScopeRAII<ScopeKind::Block> BlockScopeRAII;
- typedef ScopeRAII<ScopeKind::FullExpression> FullExpressionRAII;
- typedef ScopeRAII<ScopeKind::Call> CallScopeRAII;
-}
+
+ // Compact any retained cleanups.
+ auto NewEnd = Info.CleanupStack.begin() + OldStackSize;
+ if (Kind != ScopeKind::Block)
+ NewEnd = std::remove_if(NewEnd, Info.CleanupStack.end(), [](Cleanup &C) {
+ return C.isDestroyedAtEndOf(Kind);
+ });
+ Info.CleanupStack.erase(NewEnd, Info.CleanupStack.end());
+ return Success;
+ }
+};
+typedef ScopeRAII<ScopeKind::Block> BlockScopeRAII;
+typedef ScopeRAII<ScopeKind::FullExpression> FullExpressionRAII;
+typedef ScopeRAII<ScopeKind::Call> CallScopeRAII;
+} // namespace
bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E,
CheckSubobjectKind CSK) {
if (Invalid)
return false;
if (isOnePastTheEnd()) {
- Info.CCEDiag(E, diag::note_constexpr_past_end_subobject)
- << CSK;
+ Info.CCEDiag(E, diag::note_constexpr_past_end_subobject) << CSK;
setInvalid();
return false;
}
@@ -1413,11 +1387,9 @@ void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info,
// the most derived array.
if (MostDerivedPathLength == Entries.size() && MostDerivedIsArrayElement)
Info.CCEDiag(E, diag::note_constexpr_array_index)
- << N << /*array*/ 0
- << static_cast<unsigned>(getMostDerivedArraySize());
+ << N << /*array*/ 0 << static_cast<unsigned>(getMostDerivedArraySize());
else
- Info.CCEDiag(E, diag::note_constexpr_array_index)
- << N << /*non-array*/ 1;
+ Info.CCEDiag(E, diag::note_constexpr_array_index) << N << /*non-array*/ 1;
setInvalid();
}
@@ -1500,322 +1472,314 @@ static bool isValidIndeterminateAccess(AccessKinds AK) {
}
namespace {
- struct ComplexValue {
- private:
- bool IsInt;
+struct ComplexValue {
+private:
+ bool IsInt;
- public:
- APSInt IntReal, IntImag;
- APFloat FloatReal, FloatImag;
+public:
+ APSInt IntReal, IntImag;
+ APFloat FloatReal, FloatImag;
- ComplexValue() : FloatReal(APFloat::Bogus()), FloatImag(APFloat::Bogus()) {}
+ ComplexValue() : FloatReal(APFloat::Bogus()), FloatImag(APFloat::Bogus()) {}
- void makeComplexFloat() { IsInt = false; }
- bool isComplexFloat() const { return !IsInt; }
- APFloat &getComplexFloatReal() { return FloatReal; }
- APFloat &getComplexFloatImag() { return FloatImag; }
+ void makeComplexFloat() { IsInt = false; }
+ bool isComplexFloat() const { return !IsInt; }
+ APFloat &getComplexFloatReal() { return FloatReal; }
+ APFloat &getComplexFloatImag() { return FloatImag; }
- void makeComplexInt() { IsInt = true; }
- bool isComplexInt() const { return IsInt; }
- APSInt &getComplexIntReal() { return IntReal; }
- APSInt &getComplexIntImag() { return IntImag; }
+ void makeComplexInt() { IsInt = true; }
+ bool isComplexInt() const { return IsInt; }
+ APSInt &getComplexIntReal() { return IntReal; }
+ APSInt &getComplexIntImag() { return IntImag; }
- void moveInto(APValue &v) const {
- if (isComplexFloat())
- v = APValue(FloatReal, FloatImag);
- else
- v = APValue(IntReal, IntImag);
- }
- void setFrom(const APValue &v) {
- assert(v.isComplexFloat() || v.isComplexInt());
- if (v.isComplexFloat()) {
- makeComplexFloat();
- FloatReal = v.getComplexFloatReal();
- FloatImag = v.getComplexFloatImag();
- } else {
- makeComplexInt();
- IntReal = v.getComplexIntReal();
- IntImag = v.getComplexIntImag();
- }
+ void moveInto(APValue &v) const {
+ if (isComplexFloat())
+ v = APValue(FloatReal, FloatImag);
+ else
+ v = APValue(IntReal, IntImag);
+ }
+ void setFrom(const APValue &v) {
+ assert(v.isComplexFloat() || v.isComplexInt());
+ if (v.isComplexFloat()) {
+ makeComplexFloat();
+ FloatReal = v.getComplexFloatReal();
+ FloatImag = v.getComplexFloatImag();
+ } else {
+ makeComplexInt();
+ IntReal = v.getComplexIntReal();
+ IntImag = v.getComplexIntImag();
}
- };
+ }
+};
- struct LValue {
- APValue::LValueBase Base;
- CharUnits Offset;
- SubobjectDesignator Designator;
- bool IsNullPtr : 1;
- bool InvalidBase : 1;
- // P2280R4 track if we have an unknown reference or pointer.
- bool AllowConstexprUnknown = false;
-
- const APValue::LValueBase getLValueBase() const { return Base; }
- bool allowConstexprUnknown() const { return AllowConstexprUnknown; }
- CharUnits &getLValueOffset() { return Offset; }
- const CharUnits &getLValueOffset() const { return Offset; }
- SubobjectDesignator &getLValueDesignator() { return Designator; }
- const SubobjectDesignator &getLValueDesignator() const { return Designator;}
- bool isNullPointer() const { return IsNullPtr;}
-
- unsigned getLValueCallIndex() const { return Base.getCallIndex(); }
- unsigned getLValueVersion() const { return Base.getVersion(); }
-
- void moveInto(APValue &V) const {
- if (Designator.Invalid)
- V = APValue(Base, Offset, APValue::NoLValuePath(), IsNullPtr);
- else {
- assert(!InvalidBase && "APValues can't handle invalid LValue bases");
- V = APValue(Base, Offset, Designator.Entries,
- Designator.IsOnePastTheEnd, IsNullPtr);
- }
- if (AllowConstexprUnknown)
- V.setConstexprUnknown();
- }
- void setFrom(const ASTContext &Ctx, const APValue &V) {
- assert(V.isLValue() && "Setting LValue from a non-LValue?");
- Base = V.getLValueBase();
- Offset = V.getLValueOffset();
- InvalidBase = false;
- Designator = SubobjectDesignator(Ctx, V);
- IsNullPtr = V.isNullPointer();
- AllowConstexprUnknown = V.allowConstexprUnknown();
+struct LValue {
+ APValue::LValueBase Base;
+ CharUnits Offset;
+ SubobjectDesignator Designator;
+ bool IsNullPtr : 1;
+ bool InvalidBase : 1;
+ // P2280R4 track if we have an unknown reference or pointer.
+ bool AllowConstexprUnknown = false;
+
+ const APValue::LValueBase getLValueBase() const { return Base; }
+ bool allowConstexprUnknown() const { return AllowConstexprUnknown; }
+ CharUnits &getLValueOffset() { return Offset; }
+ const CharUnits &getLValueOffset() const { return Offset; }
+ SubobjectDesignator &getLValueDesignator() { return Designator; }
+ const SubobjectDesignator &getLValueDesignator() const { return Designator; }
+ bool isNullPointer() const { return IsNullPtr; }
+
+ unsigned getLValueCallIndex() const { return Base.getCallIndex(); }
+ unsigned getLValueVersion() const { return Base.getVersion(); }
+
+ void moveInto(APValue &V) const {
+ if (Designator.Invalid)
+ V = APValue(Base, Offset, APValue::NoLValuePath(), IsNullPtr);
+ else {
+ assert(!InvalidBase && "APValues can't handle invalid LValue bases");
+ V = APValue(Base, Offset, Designator.Entries, Designator.IsOnePastTheEnd,
+ IsNullPtr);
}
+ if (AllowConstexprUnknown)
+ V.setConstexprUnknown();
+ }
+ void setFrom(const ASTContext &Ctx, const APValue &V) {
+ assert(V.isLValue() && "Setting LValue from a non-LValue?");
+ Base = V.getLValueBase();
+ Offset = V.getLValueOffset();
+ InvalidBase = false;
+ Designator = SubobjectDesignator(Ctx, V);
+ IsNullPtr = V.isNullPointer();
+ AllowConstexprUnknown = V.allowConstexprUnknown();
+ }
- void set(APValue::LValueBase B, bool BInvalid = false) {
+ void set(APValue::LValueBase B, bool BInvalid = false) {
#ifndef NDEBUG
- // We only allow a few types of invalid bases. Enforce that here.
- if (BInvalid) {
- const auto *E = B.get<const Expr *>();
- assert((isa<MemberExpr>(E) || tryUnwrapAllocSizeCall(E)) &&
- "Unexpected type of invalid base");
- }
+ // We only allow a few types of invalid bases. Enforce that here.
+ if (BInvalid) {
+ const auto *E = B.get<const Expr *>();
+ assert((isa<MemberExpr>(E) || tryUnwrapAllocSizeCall(E)) &&
+ "Unexpected type of invalid base");
+ }
#endif
- Base = B;
- Offset = CharUnits::fromQuantity(0);
- InvalidBase = BInvalid;
- Designator = SubobjectDesignator(getType(B));
- IsNullPtr = false;
- AllowConstexprUnknown = false;
- }
+ Base = B;
+ Offset = CharUnits::fromQuantity(0);
+ InvalidBase = BInvalid;
+ Designator = SubobjectDesignator(getType(B));
+ IsNullPtr = false;
+ AllowConstexprUnknown = false;
+ }
- void setNull(ASTContext &Ctx, QualType PointerTy) {
- Base = (const ValueDecl *)nullptr;
- Offset =
- CharUnits::fromQuantity(Ctx.getTargetNullPointerValue(PointerTy));
- InvalidBase = false;
- Designator = SubobjectDesignator(PointerTy->getPointeeType());
- IsNullPtr = true;
- AllowConstexprUnknown = false;
- }
+ void setNull(ASTContext &Ctx, QualType PointerTy) {
+ Base = (const ValueDecl *)nullptr;
+ Offset = CharUnits::fromQuantity(Ctx.getTargetNullPointerValue(PointerTy));
+ InvalidBase = false;
+ Designator = SubobjectDesignator(PointerTy->getPointeeType());
+ IsNullPtr = true;
+ AllowConstexprUnknown = false;
+ }
- void setInvalid(APValue::LValueBase B, unsigned I = 0) {
- set(B, true);
- }
+ void setInvalid(APValue::LValueBase B, unsigned I = 0) { set(B, true); }
- std::string toString(ASTContext &Ctx, QualType T) const {
- APValue Printable;
- moveInto(Printable);
- return Printable.getAsString(Ctx, T);
- }
+ std::string toString(ASTContext &Ctx, QualType T) const {
+ APValue Printable;
+ moveInto(Printable);
+ return Printable.getAsString(Ctx, T);
+ }
- private:
- // Check that this LValue is not based on a null pointer. If it is, produce
- // a diagnostic and mark the designator as invalid.
- template <typename GenDiagType>
- bool checkNullPointerDiagnosingWith(const GenDiagType &GenDiag) {
- if (Designator.Invalid)
- return false;
- if (IsNullPtr) {
- GenDiag();
- Designator.setInvalid();
- return false;
- }
- return true;
+private:
+ // Check that this LValue is not based on a null pointer. If it is, produce
+ // a diagnostic and mark the designator as invalid.
+ template <typename GenDiagType>
+ bool checkNullPointerDiagnosingWith(const GenDiagType &GenDiag) {
+ if (Designator.Invalid)
+ return false;
+ if (IsNullPtr) {
+ GenDiag();
+ Designator.setInvalid();
+ return false;
}
+ return true;
+ }
- public:
- bool checkNullPointer(EvalInfo &Info, const Expr *E,
- CheckSubobjectKind CSK) {
- return checkNullPointerDiagnosingWith([&Info, E, CSK] {
- Info.CCEDiag(E, diag::note_constexpr_null_subobject) << CSK;
- });
- }
+public:
+ bool checkNullPointer(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK) {
+ return checkNullPointerDiagnosingWith([&Info, E, CSK] {
+ Info.CCEDiag(E, diag::note_constexpr_null_subobject) << CSK;
+ });
+ }
- bool checkNullPointerForFoldAccess(EvalInfo &Info, const Expr *E,
- AccessKinds AK) {
- return checkNullPointerDiagnosingWith([&Info, E, AK] {
- if (AK == AccessKinds::AK_Dereference)
- Info.FFDiag(E, diag::note_constexpr_dereferencing_null);
- else
- Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
- });
- }
+ bool checkNullPointerForFoldAccess(EvalInfo &Info, const Expr *E,
+ AccessKinds AK) {
+ return checkNullPointerDiagnosingWith([&Info, E, AK] {
+ if (AK == AccessKinds::AK_Dereference)
+ Info.FFDiag(E, diag::note_constexpr_dereferencing_null);
+ else
+ Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
+ });
+ }
- // Check this LValue refers to an object. If not, set the designator to be
- // invalid and emit a diagnostic.
- bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK) {
- return (CSK == CSK_ArrayToPointer || checkNullPointer(Info, E, CSK)) &&
- Designator.checkSubobject(Info, E, CSK);
- }
+ // Check this LValue refers to an object. If not, set the designator to be
+ // invalid and emit a diagnostic.
+ bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK) {
+ return (CSK == CSK_ArrayToPointer || checkNullPointer(Info, E, CSK)) &&
+ Designator.checkSubobject(Info, E, CSK);
+ }
- void addDecl(EvalInfo &Info, const Expr *E,
- const Decl *D, bool Virtual = false) {
- if (checkSubobject(Info, E, isa<FieldDecl>(D) ? CSK_Field : CSK_Base))
- Designator.addDeclUnchecked(D, Virtual);
- }
- void addUnsizedArray(EvalInfo &Info, const Expr *E, QualType ElemTy) {
- if (!Designator.Entries.empty()) {
- Info.CCEDiag(E, diag::note_constexpr_unsupported_unsized_array);
- Designator.setInvalid();
- return;
- }
- if (checkSubobject(Info, E, CSK_ArrayToPointer)) {
- assert(getType(Base).getNonReferenceType()->isPointerType() ||
- getType(Base).getNonReferenceType()->isArrayType());
- Designator.FirstEntryIsAnUnsizedArray = true;
- Designator.addUnsizedArrayUnchecked(ElemTy);
- }
- }
- void addArray(EvalInfo &Info, const Expr *E, const ConstantArrayType *CAT) {
- if (checkSubobject(Info, E, CSK_ArrayToPointer))
- Designator.addArrayUnchecked(CAT);
- }
- void addComplex(EvalInfo &Info, const Expr *E, QualType EltTy, bool Imag) {
- if (checkSubobject(Info, E, Imag ? CSK_Imag : CSK_Real))
- Designator.addComplexUnchecked(EltTy, Imag);
- }
- void addVectorElement(EvalInfo &Info, const Expr *E, QualType EltTy,
- uint64_t Size, uint64_t Idx) {
- if (checkSubobject(Info, E, CSK_VectorElement))
- Designator.addVectorElementUnchecked(EltTy, Size, Idx);
+ void addDecl(EvalInfo &Info, const Expr *E, const Decl *D,
+ bool Virtual = false) {
+ if (checkSubobject(Info, E, isa<FieldDecl>(D) ? CSK_Field : CSK_Base))
+ Designator.addDeclUnchecked(D, Virtual);
+ }
+ void addUnsizedArray(EvalInfo &Info, const Expr *E, QualType ElemTy) {
+ if (!Designator.Entries.empty()) {
+ Info.CCEDiag(E, diag::note_constexpr_unsupported_unsized_array);
+ Designator.setInvalid();
+ return;
}
- void clearIsNullPointer() {
- IsNullPtr = false;
+ if (checkSubobject(Info, E, CSK_ArrayToPointer)) {
+ assert(getType(Base).getNonReferenceType()->isPointerType() ||
+ getType(Base).getNonReferenceType()->isArrayType());
+ Designator.FirstEntryIsAnUnsizedArray = true;
+ Designator.addUnsizedArrayUnchecked(ElemTy);
}
- void adjustOffsetAndIndex(EvalInfo &Info, const Expr *E,
- const APSInt &Index, CharUnits ElementSize) {
- // An index of 0 has no effect. (In C, adding 0 to a null pointer is UB,
- // but we're not required to diagnose it and it's valid in C++.)
- if (!Index)
- return;
-
- // Compute the new offset in the appropriate width, wrapping at 64 bits.
- // FIXME: When compiling for a 32-bit target, we should use 32-bit
- // offsets.
- uint64_t Offset64 = Offset.getQuantity();
- uint64_t ElemSize64 = ElementSize.getQuantity();
- uint64_t Index64 = Index.extOrTrunc(64).getZExtValue();
- Offset = CharUnits::fromQuantity(Offset64 + ElemSize64 * Index64);
+ }
+ void addArray(EvalInfo &Info, const Expr *E, const ConstantArrayType *CAT) {
+ if (checkSubobject(Info, E, CSK_ArrayToPointer))
+ Designator.addArrayUnchecked(CAT);
+ }
+ void addComplex(EvalInfo &Info, const Expr *E, QualType EltTy, bool Imag) {
+ if (checkSubobject(Info, E, Imag ? CSK_Imag : CSK_Real))
+ Designator.addComplexUnchecked(EltTy, Imag);
+ }
+ void addVectorElement(EvalInfo &Info, const Expr *E, QualType EltTy,
+ uint64_t Size, uint64_t Idx) {
+ if (checkSubobject(Info, E, CSK_VectorElement))
+ Designator.addVectorElementUnchecked(EltTy, Size, Idx);
+ }
+ void clearIsNullPointer() { IsNullPtr = false; }
+ void adjustOffsetAndIndex(EvalInfo &Info, const Expr *E, const APSInt &Index,
+ CharUnits ElementSize) {
+ // An index of 0 has no effect. (In C, adding 0 to a null pointer is UB,
+ // but we're not required to diagnose it and it's valid in C++.)
+ if (!Index)
+ return;
- if (checkNullPointer(Info, E, CSK_ArrayIndex))
- Designator.adjustIndex(Info, E, Index, *this);
+ // Compute the new offset in the appropriate width, wrapping at 64 bits.
+ // FIXME: When compiling for a 32-bit target, we should use 32-bit
+ // offsets.
+ uint64_t Offset64 = Offset.getQuantity();
+ uint64_t ElemSize64 = ElementSize.getQuantity();
+ uint64_t Index64 = Index.extOrTrunc(64).getZExtValue();
+ Offset = CharUnits::fromQuantity(Offset64 + ElemSize64 * Index64);
+
+ if (checkNullPointer(Info, E, CSK_ArrayIndex))
+ Designator.adjustIndex(Info, E, Index, *this);
+ clearIsNullPointer();
+ }
+ void adjustOffset(CharUnits N) {
+ Offset += N;
+ if (N.getQuantity())
clearIsNullPointer();
- }
- void adjustOffset(CharUnits N) {
- Offset += N;
- if (N.getQuantity())
- clearIsNullPointer();
- }
- };
+ }
+};
- struct MemberPtr {
- MemberPtr() {}
- explicit MemberPtr(const ValueDecl *Decl)
- : DeclAndIsDerivedMember(Decl, false) {}
-
- /// The member or (direct or indirect) field referred to by this member
- /// pointer, or 0 if this is a null member pointer.
- const ValueDecl *getDecl() const {
- return DeclAndIsDerivedMember.getPointer();
- }
- /// Is this actually a member of some type derived from the relevant class?
- bool isDerivedMember() const {
- return DeclAndIsDerivedMember.getInt();
- }
- /// Get the class which the declaration actually lives in.
- const CXXRecordDecl *getContainingRecord() const {
- return cast<CXXRecordDecl>(
- DeclAndIsDerivedMember.getPointer()->getDeclContext());
- }
-
- void moveInto(APValue &V) const {
- V = APValue(getDecl(), isDerivedMember(), Path);
- }
- void setFrom(const APValue &V) {
- assert(V.isMemberPointer());
- DeclAndIsDerivedMember.setPointer(V.getMemberPointerDecl());
- DeclAndIsDerivedMember.setInt(V.isMemberPointerToDerivedMember());
- Path.clear();
- llvm::append_range(Path, V.getMemberPointerPath());
- }
-
- /// DeclAndIsDerivedMember - The member declaration, and a flag indicating
- /// whether the member is a member of some class derived from the class type
- /// of the member pointer.
- llvm::PointerIntPair<const ValueDecl*, 1, bool> DeclAndIsDerivedMember;
- /// Path - The path of base/derived classes from the member declaration's
- /// class (exclusive) to the class type of the member pointer (inclusive).
- SmallVector<const CXXRecordDecl*, 4> Path;
-
- /// Perform a cast towards the class of the Decl (either up or down the
- /// hierarchy).
- bool castBack(const CXXRecordDecl *Class) {
- assert(!Path.empty());
- const CXXRecordDecl *Expected;
- if (Path.size() >= 2)
- Expected = Path[Path.size() - 2];
- else
- Expected = getContainingRecord();
- if (Expected->getCanonicalDecl() != Class->getCanonicalDecl()) {
- // C++11 [expr.static.cast]p12: In a conversion from (D::*) to (B::*),
- // if B does not contain the original member and is not a base or
- // derived class of the class containing the original member, the result
- // of the cast is undefined.
- // C++11 [conv.mem]p2 does not cover this case for a cast from (B::*) to
- // (D::*). We consider that to be a language defect.
- return false;
- }
- Path.pop_back();
- return true;
+struct MemberPtr {
+ MemberPtr() {}
+ explicit MemberPtr(const ValueDecl *Decl)
+ : DeclAndIsDerivedMember(Decl, false) {}
+
+ /// The member or (direct or indirect) field referred to by this member
+ /// pointer, or 0 if this is a null member pointer.
+ const ValueDecl *getDecl() const {
+ return DeclAndIsDerivedMember.getPointer();
+ }
+ /// Is this actually a member of some type derived from the relevant class?
+ bool isDerivedMember() const { return DeclAndIsDerivedMember.getInt(); }
+ /// Get the class which the declaration actually lives in.
+ const CXXRecordDecl *getContainingRecord() const {
+ return cast<CXXRecordDecl>(
+ DeclAndIsDerivedMember.getPointer()->getDeclContext());
+ }
+
+ void moveInto(APValue &V) const {
+ V = APValue(getDecl(), isDerivedMember(), Path);
+ }
+ void setFrom(const APValue &V) {
+ assert(V.isMemberPointer());
+ DeclAndIsDerivedMember.setPointer(V.getMemberPointerDecl());
+ DeclAndIsDerivedMember.setInt(V.isMemberPointerToDerivedMember());
+ Path.clear();
+ llvm::append_range(Path, V.getMemberPointerPath());
+ }
+
+ /// DeclAndIsDerivedMember - The member declaration, and a flag indicating
+ /// whether the member is a member of some class derived from the class type
+ /// of the member pointer.
+ llvm::PointerIntPair<const ValueDecl *, 1, bool> DeclAndIsDerivedMember;
+ /// Path - The path of base/derived classes from the member declaration's
+ /// class (exclusive) to the class type of the member pointer (inclusive).
+ SmallVector<const CXXRecordDecl *, 4> Path;
+
+ /// Perform a cast towards the class of the Decl (either up or down the
+ /// hierarchy).
+ bool castBack(const CXXRecordDecl *Class) {
+ assert(!Path.empty());
+ const CXXRecordDecl *Expected;
+ if (Path.size() >= 2)
+ Expected = Path[Path.size() - 2];
+ else
+ Expected = getContainingRecord();
+ if (Expected->getCanonicalDecl() != Class->getCanonicalDecl()) {
+ // C++11 [expr.static.cast]p12: In a conversion from (D::*) to (B::*),
+ // if B does not contain the original member and is not a base or
+ // derived class of the class containing the original member, the result
+ // of the cast is undefined.
+ // C++11 [conv.mem]p2 does not cover this case for a cast from (B::*) to
+ // (D::*). We consider that to be a language defect.
+ return false;
}
- /// Perform a base-to-derived member pointer cast.
- bool castToDerived(const CXXRecordDecl *Derived) {
- if (!getDecl())
- return true;
- if (!isDerivedMember()) {
- Path.push_back(Derived);
- return true;
- }
- if (!castBack(Derived))
- return false;
- if (Path.empty())
- DeclAndIsDerivedMember.setInt(false);
+ Path.pop_back();
+ return true;
+ }
+ /// Perform a base-to-derived member pointer cast.
+ bool castToDerived(const CXXRecordDecl *Derived) {
+ if (!getDecl())
+ return true;
+ if (!isDerivedMember()) {
+ Path.push_back(Derived);
return true;
}
- /// Perform a derived-to-base member pointer cast.
- bool castToBase(const CXXRecordDecl *Base) {
- if (!getDecl())
- return true;
- if (Path.empty())
- DeclAndIsDerivedMember.setInt(true);
- if (isDerivedMember()) {
- Path.push_back(Base);
- return true;
- }
- return castBack(Base);
- }
- };
-
- /// Compare two member pointers, which are assumed to be of the same type.
- static bool operator==(const MemberPtr &LHS, const MemberPtr &RHS) {
- if (!LHS.getDecl() || !RHS.getDecl())
- return !LHS.getDecl() && !RHS.getDecl();
- if (LHS.getDecl()->getCanonicalDecl() != RHS.getDecl()->getCanonicalDecl())
+ if (!castBack(Derived))
return false;
- return LHS.Path == RHS.Path;
+ if (Path.empty())
+ DeclAndIsDerivedMember.setInt(false);
+ return true;
}
+ /// Perform a derived-to-base member pointer cast.
+ bool castToBase(const CXXRecordDecl *Base) {
+ if (!getDecl())
+ return true;
+ if (Path.empty())
+ DeclAndIsDerivedMember.setInt(true);
+ if (isDerivedMember()) {
+ Path.push_back(Base);
+ return true;
+ }
+ return castBack(Base);
+ }
+};
+
+/// Compare two member pointers, which are assumed to be of the same type.
+static bool operator==(const MemberPtr &LHS, const MemberPtr &RHS) {
+ if (!LHS.getDecl() || !RHS.getDecl())
+ return !LHS.getDecl() && !RHS.getDecl();
+ if (LHS.getDecl()->getCanonicalDecl() != RHS.getDecl()->getCanonicalDecl())
+ return false;
+ return LHS.Path == RHS.Path;
}
+} // namespace
void SubobjectDesignator::adjustIndex(EvalInfo &Info, const Expr *E, APSInt N,
const LValue &LV) {
@@ -1866,9 +1830,8 @@ void SubobjectDesignator::adjustIndex(EvalInfo &Info, const Expr *E, APSInt N,
}
static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E);
-static bool EvaluateInPlace(APValue &Result, EvalInfo &Info,
- const LValue &This, const Expr *E,
- bool AllowNonLiteralTypes = false);
+static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This,
+ const Expr *E, bool AllowNonLiteralTypes = false);
static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info,
bool InvalidBaseOK = false);
static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info,
@@ -1910,7 +1873,7 @@ static void negateAsSigned(APSInt &Int) {
Int = -Int;
}
-template<typename KeyT>
+template <typename KeyT>
APValue &CallStackFrame::createTemporary(const KeyT *Key, QualType T,
ScopeKind Scope, LValue &LV) {
unsigned Version = getTempVersion();
@@ -1983,9 +1946,9 @@ void CallStackFrame::describe(raw_ostream &Out) const {
Object->printPretty(Out, /*Helper=*/nullptr, Info.Ctx.getPrintingPolicy(),
/*Indentation=*/0);
if (Object->getType()->isPointerType())
- Out << "->";
+ Out << "->";
else
- Out << ".";
+ Out << ".";
} else if (const auto *OCE =
dyn_cast_if_present<CXXOperatorCallExpr>(CallExpr)) {
OCE->getArg(0)->printPretty(Out, /*Helper=*/nullptr,
@@ -2008,7 +1971,8 @@ void CallStackFrame::describe(raw_ostream &Out) const {
Out << '(';
for (FunctionDecl::param_const_iterator I = Callee->param_begin(),
- E = Callee->param_end(); I != E; ++I, ++ArgIndex) {
+ E = Callee->param_end();
+ I != E; ++I, ++ArgIndex) {
if (ArgIndex > (unsigned)IsMemberCall)
Out << ", ";
@@ -2062,7 +2026,7 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
if (!B)
return true;
- if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) {
+ if (const ValueDecl *D = B.dyn_cast<const ValueDecl *>()) {
// ... the address of an object with static storage duration,
if (const VarDecl *VD = dyn_cast<VarDecl>(D))
return VD->hasGlobalStorage();
@@ -2077,7 +2041,7 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
if (B.is<TypeInfoLValue>() || B.is<DynamicAllocLValue>())
return true;
- const Expr *E = B.get<const Expr*>();
+ const Expr *E = B.get<const Expr *>();
switch (E->getStmtClass()) {
default:
return false;
@@ -2122,7 +2086,7 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
}
static const ValueDecl *GetLValueBaseDecl(const LValue &LVal) {
- return LVal.Base.dyn_cast<const ValueDecl*>();
+ return LVal.Base.dyn_cast<const ValueDecl *>();
}
// Information about an LValueBase that is some kind of string.
@@ -2239,8 +2203,7 @@ static bool HasSameBase(const LValue &A, const LValue &B) {
if (!B.getLValueBase())
return false;
- if (A.getLValueBase().getOpaqueValue() !=
- B.getLValueBase().getOpaqueValue())
+ if (A.getLValueBase().getOpaqueValue() != B.getLValueBase().getOpaqueValue())
return false;
return A.getLValueCallIndex() == B.getLValueCallIndex() &&
@@ -2249,7 +2212,7 @@ static bool HasSameBase(const LValue &A, const LValue &B) {
static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
assert(Base && "no location for a null lvalue");
- const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
+ const ValueDecl *VD = Base.dyn_cast<const ValueDecl *>();
// For a parameter, find the corresponding call stack frame (if it still
// exists), and point at the parameter of the function definition we actually
@@ -2268,7 +2231,7 @@ static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
if (VD)
Info.Note(VD->getLocation(), diag::note_declared_at);
- else if (const Expr *E = Base.dyn_cast<const Expr*>())
+ else if (const Expr *E = Base.dyn_cast<const Expr *>())
Info.Note(E->getExprLoc(), diag::note_constexpr_temporary_here);
else if (DynamicAllocLValue DA = Base.dyn_cast<DynamicAllocLValue>()) {
// FIXME: Produce a note for dangling pointers too.
@@ -2310,7 +2273,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
const SubobjectDesignator &Designator = LVal.getLValueDesignator();
const Expr *BaseE = Base.dyn_cast<const Expr *>();
- const ValueDecl *BaseVD = Base.dyn_cast<const ValueDecl*>();
+ const ValueDecl *BaseVD = Base.dyn_cast<const ValueDecl *>();
// Additional restrictions apply in a template argument. We only enforce the
// C++20 restrictions here; additional syntactic and semantic restrictions
@@ -2471,7 +2434,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
// Does this refer one past the end of some object?
if (!Designator.Invalid && Designator.isOnePastTheEnd()) {
Info.FFDiag(Loc, diag::note_constexpr_past_end, 1)
- << !Designator.Entries.empty() << !!BaseVD << BaseVD;
+ << !Designator.Entries.empty() << !!BaseVD << BaseVD;
NoteLValueLocation(Info, Base);
}
@@ -2527,8 +2490,7 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E,
// Prvalue constant expressions must be of literal types.
if (Info.getLangOpts().CPlusPlus11)
- Info.FFDiag(E, diag::note_constexpr_nonliteral)
- << E->getType();
+ Info.FFDiag(E, diag::note_constexpr_nonliteral) << E->getType();
else
Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
return false;
@@ -2620,7 +2582,8 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
if (Value.isMemberPointer() &&
CERK == CheckEvaluationResultKind::ConstantExpression)
- return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value, Kind);
+ return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value,
+ Kind);
// Everything else is fine.
return true;
@@ -2678,7 +2641,7 @@ static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) {
// We have a non-null base. These are generally known to be true, but if it's
// a weak declaration it can be null at runtime.
Result = true;
- const ValueDecl *Decl = Value.getLValueBase().dyn_cast<const ValueDecl*>();
+ const ValueDecl *Decl = Value.getLValueBase().dyn_cast<const ValueDecl *>();
return !Decl || !Decl->isWeak();
}
@@ -2734,11 +2697,10 @@ static bool EvaluateAsBooleanCondition(const Expr *E, bool &Result,
return HandleConversionToBool(Val, Result);
}
-template<typename T>
-static bool HandleOverflow(EvalInfo &Info, const Expr *E,
- const T &SrcValue, QualType DestType) {
- Info.CCEDiag(E, diag::note_constexpr_overflow)
- << SrcValue << DestType;
+template <typename T>
+static bool HandleOverflow(EvalInfo &Info, const Expr *E, const T &SrcValue,
+ QualType DestType) {
+ Info.CCEDiag(E, diag::note_constexpr_overflow) << SrcValue << DestType;
return Info.noteUndefinedBehavior();
}
@@ -2751,8 +2713,8 @@ static bool HandleFloatToIntCast(EvalInfo &Info, const Expr *E,
Result = APSInt(DestWidth, !DestSigned);
bool ignored;
- if (Value.convertToInteger(Result, llvm::APFloat::rmTowardZero, &ignored)
- & APFloat::opInvalidOp)
+ if (Value.convertToInteger(Result, llvm::APFloat::rmTowardZero, &ignored) &
+ APFloat::opInvalidOp)
return HandleOverflow(Info, E, Value, DestType);
return true;
}
@@ -2841,17 +2803,17 @@ static APSInt HandleIntToIntCast(EvalInfo &Info, const Expr *E,
}
static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E,
- const FPOptions FPO,
- QualType SrcType, const APSInt &Value,
- QualType DestType, APFloat &Result) {
+ const FPOptions FPO, QualType SrcType,
+ const APSInt &Value, QualType DestType,
+ APFloat &Result) {
Result = APFloat(Info.Ctx.getFloatTypeSemantics(DestType), 1);
llvm::RoundingMode RM = getActiveRoundingMode(Info, E);
APFloat::opStatus St = Result.convertFromAPInt(Value, Value.isSigned(), RM);
return checkFloatingPointResult(Info, E, St);
}
-static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E,
- APValue &Value, const FieldDecl *FD) {
+static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E, APValue &Value,
+ const FieldDecl *FD) {
assert(FD->isBitField() && "truncateBitfieldValue on non-bitfield");
if (!Value.isInt()) {
@@ -2874,7 +2836,7 @@ static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E,
/// Perform the given integer operation, which is known to need at most BitWidth
/// bits, and check for overflow in the original type (if that type was not an
/// unsigned type).
-template<typename Operation>
+template <typename Operation>
static bool CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
const APSInt &LHS, const APSInt &RHS,
unsigned BitWidth, Operation Op,
@@ -2916,9 +2878,15 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
case BO_Sub:
return CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1,
std::minus<APSInt>(), Result);
- case BO_And: Result = LHS & RHS; return true;
- case BO_Xor: Result = LHS ^ RHS; return true;
- case BO_Or: Result = LHS | RHS; return true;
+ case BO_And:
+ Result = LHS & RHS;
+ return true;
+ case BO_Xor:
+ Result = LHS ^ RHS;
+ return true;
+ case BO_Or:
+ Result = LHS | RHS;
+ return true;
case BO_Div:
case BO_Rem:
if (RHS == 0) {
@@ -2938,7 +2906,7 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
if (Info.getLangOpts().OpenCL)
// OpenCL 6.3j: shift values are effectively % word size of LHS.
RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
- static_cast<uint64_t>(LHS.getBitWidth() - 1)),
+ static_cast<uint64_t>(LHS.getBitWidth() - 1)),
RHS.isUnsigned());
else if (RHS.isSigned() && RHS.isNegative()) {
// During constant-folding, a negative shift is an opposite shift. Such
@@ -2952,10 +2920,10 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
shift_left:
// C++11 [expr.shift]p1: Shift width must be less than the bit width of
// the shifted type.
- unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
+ unsigned SA = (unsigned)RHS.getLimitedValue(LHS.getBitWidth() - 1);
if (SA != RHS) {
Info.CCEDiag(E, diag::note_constexpr_large_shift)
- << RHS << E->getType() << LHS.getBitWidth();
+ << RHS << E->getType() << LHS.getBitWidth();
if (!Info.noteUndefinedBehavior())
return false;
} else if (LHS.isSigned() && !Info.getLangOpts().CPlusPlus20) {
@@ -2980,7 +2948,7 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
if (Info.getLangOpts().OpenCL)
// OpenCL 6.3j: shift values are effectively % word size of LHS.
RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
- static_cast<uint64_t>(LHS.getBitWidth() - 1)),
+ static_cast<uint64_t>(LHS.getBitWidth() - 1)),
RHS.isUnsigned());
else if (RHS.isSigned() && RHS.isNegative()) {
// During constant-folding, a negative shift is an opposite shift. Such a
@@ -2994,10 +2962,10 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
shift_right:
// C++11 [expr.shift]p1: Shift width must be less than the bit width of the
// shifted type.
- unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
+ unsigned SA = (unsigned)RHS.getLimitedValue(LHS.getBitWidth() - 1);
if (SA != RHS) {
Info.CCEDiag(E, diag::note_constexpr_large_shift)
- << RHS << E->getType() << LHS.getBitWidth();
+ << RHS << E->getType() << LHS.getBitWidth();
if (!Info.noteUndefinedBehavior())
return false;
}
@@ -3006,12 +2974,24 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
return true;
}
- case BO_LT: Result = LHS < RHS; return true;
- case BO_GT: Result = LHS > RHS; return true;
- case BO_LE: Result = LHS <= RHS; return true;
- case BO_GE: Result = LHS >= RHS; return true;
- case BO_EQ: Result = LHS == RHS; return true;
- case BO_NE: Result = LHS != RHS; return true;
+ case BO_LT:
+ Result = LHS < RHS;
+ return true;
+ case BO_GT:
+ Result = LHS > RHS;
+ return true;
+ case BO_LE:
+ Result = LHS <= RHS;
+ return true;
+ case BO_GE:
+ Result = LHS >= RHS;
+ return true;
+ case BO_EQ:
+ Result = LHS == RHS;
+ return true;
+ case BO_NE:
+ Result = LHS != RHS;
+ return true;
case BO_Cmp:
llvm_unreachable("BO_Cmp should be handled elsewhere");
}
@@ -3229,7 +3209,8 @@ static bool CastToDerivedClass(EvalInfo &Info, const Expr *E, LValue &Result,
// Truncate the path to the subobject, and remove any derived-to-base offsets.
const RecordDecl *RD = TruncatedType;
for (unsigned I = TruncatedElements, N = D.Entries.size(); I != N; ++I) {
- if (RD->isInvalidDecl()) return false;
+ if (RD->isInvalidDecl())
+ return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
const CXXRecordDecl *Base = getAsBaseClass(D.Entries[I]);
if (isVirtualBaseClass(D.Entries[I]))
@@ -3247,7 +3228,8 @@ static bool HandleLValueDirectBase(EvalInfo &Info, const Expr *E, LValue &Obj,
const CXXRecordDecl *Base,
const ASTRecordLayout *RL = nullptr) {
if (!RL) {
- if (Derived->isInvalidDecl()) return false;
+ if (Derived->isInvalidDecl())
+ return false;
RL = &Info.Ctx.getASTRecordLayout(Derived);
}
@@ -3278,7 +3260,8 @@ static bool HandleLValueBase(EvalInfo &Info, const Expr *E, LValue &Obj,
return false;
// Find the virtual base class.
- if (DerivedDecl->isInvalidDecl()) return false;
+ if (DerivedDecl->isInvalidDecl())
+ return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl);
Obj.addDecl(Info, E, BaseDecl, /*Virtual*/ true);
Obj.getLValueOffset() += Layout.getVBaseClassOffset(BaseDecl);
@@ -3290,8 +3273,7 @@ static bool HandleLValueBasePath(EvalInfo &Info, const CastExpr *E,
for (CastExpr::path_const_iterator PathI = E->path_begin(),
PathE = E->path_end();
PathI != PathE; ++PathI) {
- if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(),
- *PathI))
+ if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(), *PathI))
return false;
Type = (*PathI)->getType();
}
@@ -3319,7 +3301,8 @@ static bool HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal,
const FieldDecl *FD,
const ASTRecordLayout *RL = nullptr) {
if (!RL) {
- if (FD->getParent()->isInvalidDecl()) return false;
+ if (FD->getParent()->isInvalidDecl())
+ return false;
RL = &Info.Ctx.getASTRecordLayout(FD->getParent());
}
@@ -3517,8 +3500,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
!Info.CurrentCall->Callee ||
!Info.CurrentCall->Callee->Equals(VD->getDeclContext())) {
if (Info.getLangOpts().CPlusPlus11) {
- Info.FFDiag(E, diag::note_constexpr_function_param_value_unknown)
- << VD;
+ Info.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << VD;
NoteLValueLocation(Info, Base);
} else {
Info.FFDiag(E);
@@ -3542,8 +3524,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
// Don't diagnose during potential constant expression checking; an
// initializer might be added later.
if (!Info.checkingPotentialConstantExpression()) {
- Info.FFDiag(E, diag::note_constexpr_var_init_unknown, 1)
- << VD;
+ Info.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;
NoteLValueLocation(Info, Base);
}
return false;
@@ -3561,9 +3542,11 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
// have been value-dependent too), so diagnose that.
assert(!VD->mightBeUsableInConstantExpressions(Info.Ctx));
if (!Info.checkingPotentialConstantExpression()) {
- Info.FFDiag(E, Info.getLangOpts().CPlusPlus11
- ? diag::note_constexpr_ltor_non_constexpr
- : diag::note_constexpr_ltor_non_integral, 1)
+ Info.FFDiag(E,
+ Info.getLangOpts().CPlusPlus11
+ ? diag::note_constexpr_ltor_non_constexpr
+ : diag::note_constexpr_ltor_non_integral,
+ 1)
<< VD << VD->getType();
NoteLValueLocation(Info, Base);
}
@@ -3627,7 +3610,8 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived,
Base = Base->getCanonicalDecl();
unsigned Index = 0;
for (CXXRecordDecl::base_class_const_iterator I = Derived->bases_begin(),
- E = Derived->bases_end(); I != E; ++I, ++Index) {
+ E = Derived->bases_end();
+ I != E; ++I, ++Index) {
if (I->getType()->getAsCXXRecordDecl()->getCanonicalDecl() == Base)
return Index;
}
@@ -3652,8 +3636,7 @@ static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit,
if (auto PE = dyn_cast<PredefinedExpr>(Lit))
Lit = PE->getFunctionName();
const StringLiteral *S = cast<StringLiteral>(Lit);
- const ConstantArrayType *CAT =
- Info.Ctx.getAsConstantArrayType(S->getType());
+ const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(S->getType());
assert(CAT && "string literal isn't an array");
QualType CharType = CAT->getElementType();
assert(CharType->isIntegerType() && "unexpected character type");
@@ -3678,8 +3661,8 @@ static void expandStringLiteral(EvalInfo &Info, const StringLiteral *S,
assert(CharType->isIntegerType() && "unexpected character type");
unsigned Elts = CAT->getZExtSize();
- Result = APValue(APValue::UninitArray(),
- std::min(S->getLength(), Elts), Elts);
+ Result =
+ APValue(APValue::UninitArray(), std::min(S->getLength(), Elts), Elts);
APSInt Value(Info.Ctx.getTypeSize(CharType),
CharType->isUnsignedIntegerType());
if (Result.hasArrayFiller())
@@ -3697,7 +3680,7 @@ static void expandArray(APValue &Array, unsigned Index) {
// Always at least double the number of elements for which we store a value.
unsigned OldElts = Array.getArrayInitializedElts();
- unsigned NewElts = std::max(Index+1, OldElts * 2);
+ unsigned NewElts = std::max(Index + 1, OldElts * 2);
NewElts = std::min(Size, std::max(NewElts, 8u));
// Copy the data across.
@@ -3853,7 +3836,7 @@ struct CompleteObject {
if (!Info.getLangOpts().CPlusPlus14 &&
AK != AccessKinds::AK_IsWithinLifetime)
return false;
- return lifetimeStartedInEvaluation(Info, Base, /*MutableSubobject*/true);
+ return lifetimeStartedInEvaluation(Info, Base, /*MutableSubobject*/ true);
}
explicit operator bool() const { return !Type.isNull(); }
@@ -3900,7 +3883,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
// Walk the designator's path to find the subobject.
for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) {
- // Reading an indeterminate value is undefined, but assigning over one is OK.
+ // Reading an indeterminate value is undefined, but assigning over one is
+ // OK.
if ((O->isAbsent() && !(handler.AccessKind == AK_Construct && I == N)) ||
(O->isIndeterminate() &&
!isValidIndeterminateAccess(handler.AccessKind))) {
@@ -3942,7 +3926,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
DiagKind = 2;
Loc = VolatileField->getLocation();
Decl = VolatileField;
- } else if (auto *VD = Obj.Base.dyn_cast<const ValueDecl*>()) {
+ } else if (auto *VD = Obj.Base.dyn_cast<const ValueDecl *>()) {
DiagKind = 1;
Loc = VD->getLocation();
Decl = VD;
@@ -3975,8 +3959,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
return false;
// If we modified a bit-field, truncate it to the right width.
- if (isModification(handler.AccessKind) &&
- LastField && LastField->isBitField() &&
+ if (isModification(handler.AccessKind) && LastField &&
+ LastField->isBitField() &&
!truncateBitfieldValue(Info, E, *O, LastField))
return false;
@@ -3996,7 +3980,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
// designator which points more than one past the end of the array.
if (Info.getLangOpts().CPlusPlus11)
Info.FFDiag(E, diag::note_constexpr_access_past_end)
- << handler.AccessKind;
+ << handler.AccessKind;
else
Info.FFDiag(E);
return handler.failed();
@@ -4021,7 +4005,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
if (Index > 1) {
if (Info.getLangOpts().CPlusPlus11)
Info.FFDiag(E, diag::note_constexpr_access_past_end)
- << handler.AccessKind;
+ << handler.AccessKind;
else
Info.FFDiag(E);
return handler.failed();
@@ -4032,12 +4016,13 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
assert(I == N - 1 && "extracting subobject of scalar?");
if (O->isComplexInt()) {
- return handler.found(Index ? O->getComplexIntImag()
- : O->getComplexIntReal(), ObjType);
+ return handler.found(
+ Index ? O->getComplexIntImag() : O->getComplexIntReal(), ObjType);
} else {
assert(O->isComplexFloat());
return handler.found(Index ? O->getComplexFloatImag()
- : O->getComplexFloatReal(), ObjType);
+ : O->getComplexFloatReal(),
+ ObjType);
}
} else if (const auto *VT = ObjType->getAs<VectorType>()) {
uint64_t Index = Sub.Entries[I].getAsArrayIndex();
@@ -4064,7 +4049,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
if (Field->isMutable() &&
!Obj.mayAccessMutableMembers(Info, handler.AccessKind)) {
Info.FFDiag(E, diag::note_constexpr_access_mutable, 1)
- << handler.AccessKind << Field;
+ << handler.AccessKind << Field;
Info.Note(Field->getLocation(), diag::note_declared_at);
return handler.failed();
}
@@ -4198,9 +4183,8 @@ const AccessKinds ModifySubobjectHandler::AccessKind;
/// Update the designated sub-object of an rvalue to the given value.
static bool modifySubobject(EvalInfo &Info, const Expr *E,
const CompleteObject &Obj,
- const SubobjectDesignator &Sub,
- APValue &NewVal) {
- ModifySubobjectHandler Handler = { Info, NewVal, E };
+ const SubobjectDesignator &Sub, APValue &NewVal) {
+ ModifySubobjectHandler Handler = {Info, NewVal, E};
return findSubobject(Info, E, Obj, Sub, Handler);
}
@@ -4286,7 +4270,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
Info.getCallFrameAndDepth(LVal.getLValueCallIndex());
if (!Frame) {
Info.FFDiag(E, diag::note_constexpr_lifetime_ended, 1)
- << AK << LVal.Base.is<const ValueDecl*>();
+ << AK << LVal.Base.is<const ValueDecl *>();
NoteLValueLocation(Info, LVal.Base);
return CompleteObject();
}
@@ -4301,7 +4285,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
if (isFormalAccess(AK) && LValType.isVolatileQualified()) {
if (Info.getLangOpts().CPlusPlus)
Info.FFDiag(E, diag::note_constexpr_access_volatile_type)
- << AK << LValType;
+ << AK << LValType;
else
Info.FFDiag(E);
return CompleteObject();
@@ -4421,9 +4405,11 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
// folding of const floating-point types, in order to make static const
// data members of such types (supported as an extension) more useful.
if (Info.getLangOpts().CPlusPlus) {
- Info.CCEDiag(E, Info.getLangOpts().CPlusPlus11
- ? diag::note_constexpr_ltor_non_constexpr
- : diag::note_constexpr_ltor_non_integral, 1)
+ Info.CCEDiag(E,
+ Info.getLangOpts().CPlusPlus11
+ ? diag::note_constexpr_ltor_non_constexpr
+ : diag::note_constexpr_ltor_non_integral,
+ 1)
<< VD << BaseType;
Info.Note(VD->getLocation(), diag::note_declared_at);
} else {
@@ -4432,9 +4418,11 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
} else {
// Never allow reading a non-const value.
if (Info.getLangOpts().CPlusPlus) {
- Info.FFDiag(E, Info.getLangOpts().CPlusPlus11
- ? diag::note_constexpr_ltor_non_constexpr
- : diag::note_constexpr_ltor_non_integral, 1)
+ Info.FFDiag(E,
+ Info.getLangOpts().CPlusPlus11
+ ? diag::note_constexpr_ltor_non_constexpr
+ : diag::note_constexpr_ltor_non_integral,
+ 1)
<< VD << BaseType;
Info.Note(VD->getLocation(), diag::note_declared_at);
} else {
@@ -4473,7 +4461,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
// When binding to a reference, the variable does not need to be
// within its lifetime.
else if (AK != clang::AK_Dereference) {
- const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
+ const Expr *Base = LVal.Base.dyn_cast<const Expr *>();
if (!Frame) {
if (const MaterializeTemporaryExpr *MTE =
@@ -4600,7 +4588,7 @@ handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, QualType Type,
return false;
// Check for special cases where there is no existing APValue to look at.
- const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
+ const Expr *Base = LVal.Base.dyn_cast<const Expr *>();
AccessKinds AK =
WantObjectRepresentation ? AK_ReadObjectRepresentation : AK_Read;
@@ -4729,8 +4717,7 @@ struct CompoundAssignSubobjectHandler {
Value = HandleIntToIntCast(Info, E, SubobjType, PromotedLHSType, LHS);
return true;
} else if (RHS.isFloat()) {
- const FPOptions FPO = E->getFPFeaturesInEffect(
- Info.Ctx.getLangOpts());
+ const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts());
APFloat FValue(0.0);
return HandleIntToFloatCast(Info, E, FPO, SubobjType, Value,
PromotedLHSType, FValue) &&
@@ -4795,8 +4782,8 @@ static bool handleCompoundAssignment(EvalInfo &Info,
}
CompleteObject Obj = findCompleteObject(Info, E, AK_Assign, LVal, LValType);
- CompoundAssignSubobjectHandler Handler = { Info, E, PromotedLValType, Opcode,
- RVal };
+ CompoundAssignSubobjectHandler Handler = {Info, E, PromotedLValType, Opcode,
+ RVal};
return Obj && findSubobject(Info, E, Obj, LVal.Designator, Handler);
}
@@ -4833,13 +4820,15 @@ struct IncDecSubobjectHandler {
case APValue::Float:
return found(Subobj.getFloat(), SubobjType);
case APValue::ComplexInt:
- return found(Subobj.getComplexIntReal(),
- SubobjType->castAs<ComplexType>()->getElementType()
- .withCVRQualifiers(SubobjType.getCVRQualifiers()));
+ return found(
+ Subobj.getComplexIntReal(),
+ SubobjType->castAs<ComplexType>()->getElementType().withCVRQualifiers(
+ SubobjType.getCVRQualifiers()));
case APValue::ComplexFloat:
- return found(Subobj.getComplexFloatReal(),
- SubobjType->castAs<ComplexType>()->getElementType()
- .withCVRQualifiers(SubobjType.getCVRQualifiers()));
+ return found(
+ Subobj.getComplexFloatReal(),
+ SubobjType->castAs<ComplexType>()->getElementType().withCVRQualifiers(
+ SubobjType.getCVRQualifiers()));
case APValue::LValue:
return foundPointer(Subobj, SubobjType);
default:
@@ -4859,7 +4848,8 @@ struct IncDecSubobjectHandler {
return false;
}
- if (Old) *Old = APValue(Value);
+ if (Old)
+ *Old = APValue(Value);
// bool arithmetic promotes to int, and the conversion back to bool
// doesn't reduce mod 2^n, so special-case it.
@@ -4876,7 +4866,7 @@ struct IncDecSubobjectHandler {
++Value;
if (!WasNegative && Value.isNegative() && E->canOverflow()) {
- APSInt ActualValue(Value, /*IsUnsigned*/true);
+ APSInt ActualValue(Value, /*IsUnsigned*/ true);
return HandleOverflow(Info, E, ActualValue, SubobjType);
}
} else {
@@ -4884,7 +4874,7 @@ struct IncDecSubobjectHandler {
if (WasNegative && !Value.isNegative() && E->canOverflow()) {
unsigned BitWidth = Value.getBitWidth();
- APSInt ActualValue(Value.sext(BitWidth + 1), /*IsUnsigned*/false);
+ APSInt ActualValue(Value.sext(BitWidth + 1), /*IsUnsigned*/ false);
ActualValue.setBit(BitWidth);
return HandleOverflow(Info, E, ActualValue, SubobjType);
}
@@ -4895,7 +4885,8 @@ struct IncDecSubobjectHandler {
if (!checkConst(SubobjType))
return false;
- if (Old) *Old = APValue(Value);
+ if (Old)
+ *Old = APValue(Value);
APFloat One(Value.getSemantics(), 1);
llvm::RoundingMode RM = getActiveRoundingMode(Info, E);
@@ -4977,8 +4968,7 @@ static bool EvaluateObjectArgument(EvalInfo &Info, const Expr *Object,
/// \return The field or method declaration to which the member pointer refers,
/// or 0 if evaluation fails.
static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
- QualType LVType,
- LValue &LV,
+ QualType LVType, LValue &LV,
const Expr *RHS,
bool IncludeMember = true) {
MemberPtr MemPtr;
@@ -5008,8 +4998,8 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
unsigned PathLengthToMember =
LV.Designator.Entries.size() - MemPtr.Path.size();
for (unsigned I = 0, N = MemPtr.Path.size(); I != N; ++I) {
- const CXXRecordDecl *LVDecl = getAsBaseClass(
- LV.Designator.Entries[PathLengthToMember + I]);
+ const CXXRecordDecl *LVDecl =
+ getAsBaseClass(LV.Designator.Entries[PathLengthToMember + I]);
const CXXRecordDecl *MPDecl = MemPtr.Path[I];
if (LVDecl->getCanonicalDecl() != MPDecl->getCanonicalDecl()) {
Info.FFDiag(RHS);
@@ -5068,7 +5058,7 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
if (!HandleLValueMember(Info, RHS, LV, FD))
return nullptr;
} else if (const IndirectFieldDecl *IFD =
- dyn_cast<IndirectFieldDecl>(MemPtr.getDecl())) {
+ dyn_cast<IndirectFieldDecl>(MemPtr.getDecl())) {
if (!HandleLValueIndirectMember(Info, RHS, LV, IFD))
return nullptr;
} else {
@@ -5339,12 +5329,10 @@ struct TempVersionRAII {
Frame.pushTempVersion();
}
- ~TempVersionRAII() {
- Frame.popTempVersion();
- }
+ ~TempVersionRAII() { Frame.popTempVersion(); }
};
-}
+} // namespace
static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
const Stmt *S,
@@ -5449,8 +5437,8 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info,
const CaseStmt *CS = cast<CaseStmt>(SC);
APSInt LHS = CS->getLHS()->EvaluateKnownConstInt(Info.Ctx);
- APSInt RHS = CS->getRHS() ? CS->getRHS()->EvaluateKnownConstInt(Info.Ctx)
- : LHS;
+ APSInt RHS =
+ CS->getRHS() ? CS->getRHS()->EvaluateKnownConstInt(Info.Ctx) : LHS;
if (LHS <= Value && Value <= RHS) {
Found = SC;
break;
@@ -5588,8 +5576,7 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
}
}
- EvalStmtResult ESR =
- EvaluateLoopBody(Result, Info, FS->getBody(), Case);
+ EvalStmtResult ESR = EvaluateLoopBody(Result, Info, FS->getBody(), Case);
if (ShouldPropagateBreakContinue(Info, FS, /*Scopes=*/{}, ESR))
return ESR;
if (ESR != ESR_Continue)
@@ -5680,10 +5667,9 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
// We know we returned, but we don't know what the value is.
return ESR_Failed;
}
- if (RetExpr &&
- !(Result.Slot
- ? EvaluateInPlace(Result.Value, Info, *Result.Slot, RetExpr)
- : Evaluate(Result.Value, Info, RetExpr)))
+ if (RetExpr && !(Result.Slot ? EvaluateInPlace(Result.Value, Info,
+ *Result.Slot, RetExpr)
+ : Evaluate(Result.Value, Info, RetExpr)))
return ESR_Failed;
return Scope.destroy() ? ESR_Returned : ESR_Failed;
}
@@ -6008,7 +5994,7 @@ static bool CheckTrivialDefaultConstructor(EvalInfo &Info, SourceLocation Loc,
// FIXME: If DiagDecl is an implicitly-declared special member function,
// we should be much more explicit about why it's not constexpr.
Info.CCEDiag(Loc, diag::note_constexpr_invalid_function, 1)
- << /*IsConstexpr*/0 << /*IsConstructor*/1 << CD;
+ << /*IsConstexpr*/ 0 << /*IsConstructor*/ 1 << CD;
Info.Note(CD->getLocation(), diag::note_declared_at);
} else {
Info.CCEDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
@@ -6052,7 +6038,7 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
// Can we evaluate this function call?
if (Definition && Body &&
(Definition->isConstexpr() || (Info.CurrentCall->CanEvalMSConstexpr &&
- Definition->hasAttr<MSConstexprAttr>())))
+ Definition->hasAttr<MSConstexprAttr>())))
return true;
const FunctionDecl *DiagDecl = Definition ? Definition : Declaration;
@@ -6085,10 +6071,10 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
// it's not constexpr.
if (CD && CD->isInheritingConstructor())
Info.FFDiag(CallLoc, diag::note_constexpr_invalid_inhctor, 1)
- << CD->getInheritedConstructor().getConstructor()->getParent();
+ << CD->getInheritedConstructor().getConstructor()->getParent();
else
Info.FFDiag(CallLoc, diag::note_constexpr_invalid_function, 1)
- << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
+ << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
Info.Note(DiagDecl->getLocation(), diag::note_declared_at);
} else {
Info.FFDiag(CallLoc, diag::note_invalid_subexpr_in_const_expr);
@@ -6171,8 +6157,8 @@ struct DynamicType {
static const CXXRecordDecl *getBaseClassType(SubobjectDesignator &Designator,
unsigned PathLength) {
- assert(PathLength >= Designator.MostDerivedPathLength && PathLength <=
- Designator.Entries.size() && "invalid path length");
+ assert(PathLength >= Designator.MostDerivedPathLength &&
+ PathLength <= Designator.Entries.size() && "invalid path length");
return (PathLength == Designator.MostDerivedPathLength)
? Designator.MostDerivedType->getAsCXXRecordDecl()
: getAsBaseClass(Designator.Entries[PathLength - 1]);
@@ -6376,7 +6362,7 @@ static bool HandleDynamicCast(EvalInfo &Info, const ExplicitCastExpr *E,
assert(C && "dynamic_cast target is not void pointer nor class");
CanQualType CQT = Info.Ctx.getCanonicalTagType(C);
- auto RuntimeCheckFailed = [&] (CXXBasePaths *Paths) {
+ auto RuntimeCheckFailed = [&](CXXBasePaths *Paths) {
// C++ [expr.dynamic.cast]p9:
if (!E->isGLValue()) {
// The value of a failed cast to pointer type is the null pointer value
@@ -6500,7 +6486,7 @@ static bool MaybeHandleUnionActiveMemberChange(EvalInfo &Info,
if (LHS.InvalidBase || LHS.Designator.Invalid)
return false;
- llvm::SmallVector<std::pair<unsigned, const FieldDecl*>, 4> UnionPathLengths;
+ llvm::SmallVector<std::pair<unsigned, const FieldDecl *>, 4> UnionPathLengths;
// C++ [class.union]p5:
// define the set S(E) of subexpressions of E as follows:
unsigned PathLength = LHS.Designator.Entries.size();
@@ -6526,9 +6512,9 @@ static bool MaybeHandleUnionActiveMemberChange(EvalInfo &Info,
E = ME->getBase();
--PathLength;
- assert(declaresSameEntity(FD,
- LHS.Designator.Entries[PathLength]
- .getAsBaseOrMember().getPointer()));
+ assert(declaresSameEntity(
+ FD,
+ LHS.Designator.Entries[PathLength].getAsBaseOrMember().getPointer()));
// -- If E is of the form A[B] and is interpreted as a built-in array
// subscripting operator, S(E) is [S(the array operand, if any)].
@@ -6561,10 +6547,11 @@ static bool MaybeHandleUnionActiveMemberChange(EvalInfo &Info,
--PathLength;
assert(declaresSameEntity(Elt->getType()->getAsCXXRecordDecl(),
LHS.Designator.Entries[PathLength]
- .getAsBaseOrMember().getPointer()));
+ .getAsBaseOrMember()
+ .getPointer()));
}
- // -- Otherwise, S(E) is empty.
+ // -- Otherwise, S(E) is empty.
} else {
break;
}
@@ -6581,7 +6568,7 @@ static bool MaybeHandleUnionActiveMemberChange(EvalInfo &Info,
if (!Obj)
return false;
for (std::pair<unsigned, const FieldDecl *> LengthAndField :
- llvm::reverse(UnionPathLengths)) {
+ llvm::reverse(UnionPathLengths)) {
// Form a designator for the union object.
SubobjectDesignator D = LHS.Designator;
D.truncate(Info.Ctx, LHS.Base, LengthAndField.first);
@@ -6811,10 +6798,11 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
std::distance(RD->field_begin(), RD->field_end()));
else
// A union starts with no active member.
- Result = APValue((const FieldDecl*)nullptr);
+ Result = APValue((const FieldDecl *)nullptr);
}
- if (RD->isInvalidDecl()) return false;
+ if (RD->isInvalidDecl())
+ return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
// A scope for temporaries lifetime-extended by reference members.
@@ -6973,7 +6961,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
}
static bool HandleConstructorCall(const Expr *E, const LValue &This,
- ArrayRef<const Expr*> Args,
+ ArrayRef<const Expr *> Args,
const CXXConstructorDecl *Definition,
EvalInfo &Info, APValue &Result) {
CallScopeRAII CallScope(Info);
@@ -7120,7 +7108,7 @@ static bool HandleDestructionImpl(EvalInfo &Info, SourceRange CallRange,
// We don't have a good way to iterate fields in reverse, so collect all the
// fields first and then walk them backwards.
- SmallVector<FieldDecl*, 16> Fields(RD->fields());
+ SmallVector<FieldDecl *, 16> Fields(RD->fields());
for (const FieldDecl *FD : llvm::reverse(Fields)) {
if (FD->isUnnamedBitField())
continue;
@@ -7182,12 +7170,12 @@ struct DestroyObjectHandler {
return false;
}
};
-}
+} // namespace
/// Perform a destructor or pseudo-destructor call on the given object, which
/// might in general not be a complete object.
-static bool HandleDestruction(EvalInfo &Info, const Expr *E,
- const LValue &This, QualType ThisType) {
+static bool HandleDestruction(EvalInfo &Info, const Expr *E, const LValue &This,
+ QualType ThisType) {
CompleteObject Obj = findCompleteObject(Info, E, AK_Destroy, This, ThisType);
DestroyObjectHandler Handler = {Info, E, This, AK_Destroy};
return Obj && findSubobject(Info, E, Obj, This.Designator, Handler);
@@ -7391,8 +7379,8 @@ class BitCastBuffer {
public:
BitCastBuffer(CharUnits Width, bool TargetIsLittleEndian)
- : Bytes(Width.getQuantity()),
- TargetIsLittleEndian(TargetIsLittleEndian) {}
+ : Bytes(Width.getQuantity()), TargetIsLittleEndian(TargetIsLittleEndian) {
+ }
[[nodiscard]] bool readObject(CharUnits Offset, CharUnits Width,
SmallVectorImpl<unsigned char> &Output) const {
@@ -7716,8 +7704,7 @@ class BufferToAPValueConverter {
T->isSpecificBuiltinType(BuiltinType::Char_U));
if (!IsStdByte && !IsUChar) {
QualType DisplayType(EnumSugar ? (const Type *)EnumSugar : T, 0);
- Info.FFDiag(BCE->getExprLoc(),
- diag::note_constexpr_bit_cast_indet_dest)
+ Info.FFDiag(BCE->getExprLoc(), diag::note_constexpr_bit_cast_indet_dest)
<< DisplayType << Info.Ctx.getLangOpts().CharIsSigned;
return std::nullopt;
}
@@ -8071,10 +8058,9 @@ static bool handleLValueToRValueBitCast(EvalInfo &Info, APValue &DestValue,
}
template <class Derived>
-class ExprEvaluatorBase
- : public ConstStmtVisitor<Derived, bool> {
+class ExprEvaluatorBase : public ConstStmtVisitor<Derived, bool> {
private:
- Derived &getDerived() { return static_cast<Derived&>(*this); }
+ Derived &getDerived() { return static_cast<Derived &>(*this); }
bool DerivedSuccess(const APValue &V, const Expr *E) {
return getDerived().Success(V, E);
}
@@ -8085,7 +8071,7 @@ class ExprEvaluatorBase
// Check whether a conditional operator with a non-constant condition is a
// potential constant expression. If neither arm is a potential constant
// expression, then the conditional operator is not either.
- template<typename ConditionalOperator>
+ template <typename ConditionalOperator>
void CheckPotentialConstantConditional(const ConditionalOperator *E) {
assert(Info.checkingPotentialConstantExpression());
@@ -8109,8 +8095,7 @@ class ExprEvaluatorBase
Error(E, diag::note_constexpr_conditional_never_const);
}
-
- template<typename ConditionalOperator>
+ template <typename ConditionalOperator>
bool HandleConditionalOperator(const ConditionalOperator *E) {
bool BoolResult;
if (!EvaluateAsBooleanCondition(E->getCond(), BoolResult, Info)) {
@@ -8164,9 +8149,7 @@ class ExprEvaluatorBase
bool VisitStmt(const Stmt *) {
llvm_unreachable("Expression evaluator should not be called on stmts");
}
- bool VisitExpr(const Expr *E) {
- return Error(E);
- }
+ bool VisitExpr(const Expr *E) { return Error(E); }
bool VisitEmbedExpr(const EmbedExpr *E) {
const auto It = E->begin();
@@ -8183,18 +8166,25 @@ class ExprEvaluatorBase
return StmtVisitorTy::Visit(E->getSubExpr());
}
- bool VisitParenExpr(const ParenExpr *E)
- { return StmtVisitorTy::Visit(E->getSubExpr()); }
- bool VisitUnaryExtension(const UnaryOperator *E)
- { return StmtVisitorTy::Visit(E->getSubExpr()); }
- bool VisitUnaryPlus(const UnaryOperator *E)
- { return StmtVisitorTy::Visit(E->getSubExpr()); }
- bool VisitChooseExpr(const ChooseExpr *E)
- { return StmtVisitorTy::Visit(E->getChosenSubExpr()); }
- bool VisitGenericSelectionExpr(const GenericSelectionExpr *E)
- { return StmtVisitorTy::Visit(E->getResultExpr()); }
- bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E)
- { return StmtVisitorTy::Visit(E->getReplacement()); }
+ bool VisitParenExpr(const ParenExpr *E) {
+ return StmtVisitorTy::Visit(E->getSubExpr());
+ }
+ bool VisitUnaryExtension(const UnaryOperator *E) {
+ return StmtVisitorTy::Visit(E->getSubExpr());
+ }
+ bool VisitUnaryPlus(const UnaryOperator *E) {
+ return StmtVisitorTy::Visit(E->getSubExpr());
+ }
+ bool VisitChooseExpr(const ChooseExpr *E) {
+ return StmtVisitorTy::Visit(E->getChosenSubExpr());
+ }
+ bool VisitGenericSelectionExpr(const GenericSelectionExpr *E) {
+ return StmtVisitorTy::Visit(E->getResultExpr());
+ }
+ bool
+ VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E) {
+ return StmtVisitorTy::Visit(E->getReplacement());
+ }
bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) {
TempVersionRAII RAII(*Info.CurrentCall);
SourceLocExprScopeGuard Guard(E, Info.CurrentCall->CurSourceLocExprScope);
@@ -8223,16 +8213,16 @@ class ExprEvaluatorBase
bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E) {
CCEDiag(E, diag::note_constexpr_invalid_cast)
<< diag::ConstexprInvalidCastKind::Reinterpret;
- return static_cast<Derived*>(this)->VisitCastExpr(E);
+ return static_cast<Derived *>(this)->VisitCastExpr(E);
}
bool VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E) {
if (!Info.Ctx.getLangOpts().CPlusPlus20)
CCEDiag(E, diag::note_constexpr_invalid_cast)
<< diag::ConstexprInvalidCastKind::Dynamic;
- return static_cast<Derived*>(this)->VisitCastExpr(E);
+ return static_cast<Derived *>(this)->VisitCastExpr(E);
}
bool VisitBuiltinBitCastExpr(const BuiltinBitCastExpr *E) {
- return static_cast<Derived*>(this)->VisitCastExpr(E);
+ return static_cast<Derived *>(this)->VisitCastExpr(E);
}
bool VisitBinaryOperator(const BinaryOperator *E) {
@@ -8282,7 +8272,7 @@ class ExprEvaluatorBase
// side-effects. This is an important GNU extension. See GCC PR38377
// for discussion.
if (const CallExpr *CallCE =
- dyn_cast<CallExpr>(E->getCond()->IgnoreParenCasts()))
+ dyn_cast<CallExpr>(E->getCond()->IgnoreParenCasts()))
if (CallCE->getBuiltinCallee() == Builtin::BI__builtin_constant_p)
IsBcpCall = true;
@@ -8356,7 +8346,7 @@ class ExprEvaluatorBase
}
bool handleCallExpr(const CallExpr *E, APValue &Result,
- const LValue *ResultSlot) {
+ const LValue *ResultSlot) {
CallScopeRAII CallScope(Info);
const Expr *Callee = E->getCallee()->IgnoreParens();
@@ -8418,7 +8408,7 @@ class ExprEvaluatorBase
// Don't call function pointers which have been cast to some other type.
// Per DR (no number yet), the caller and callee can differ in noexcept.
if (!Info.Ctx.hasSameFunctionTypeIgnoringExceptionSpec(
- CalleeType->getPointeeType(), FD->getType())) {
+ CalleeType->getPointeeType(), FD->getType())) {
return Error(E);
}
@@ -8601,7 +8591,8 @@ class ExprEvaluatorBase
QualType BaseTy = E->getBase()->getType();
const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
- if (!FD) return Error(E);
+ if (!FD)
+ return Error(E);
assert(!FD->getType()->isReferenceType() && "prvalue reference?");
assert(BaseTy->castAsCanonical<RecordType>()->getOriginalDecl() ==
FD->getParent()->getCanonicalDecl() &&
@@ -8739,7 +8730,7 @@ class ExprEvaluatorBase
}
APValue ReturnValue;
- StmtResult Result = { ReturnValue, nullptr };
+ StmtResult Result = {ReturnValue, nullptr};
EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI);
if (ESR != ESR_Succeeded) {
// FIXME: If the statement-expression terminated due to 'return',
@@ -8760,9 +8751,7 @@ class ExprEvaluatorBase
}
/// Visit a value which is evaluated, but whose value is ignored.
- void VisitIgnoredValue(const Expr *E) {
- EvaluateIgnoredValue(Info, E);
- }
+ void VisitIgnoredValue(const Expr *E) { EvaluateIgnoredValue(Info, E); }
/// Potentially visit a MemberExpr's base expression.
void VisitIgnoredBaseExpression(const Expr *E) {
@@ -8780,9 +8769,8 @@ class ExprEvaluatorBase
// Common base class for lvalue and temporary evaluation.
//===----------------------------------------------------------------------===//
namespace {
-template<class Derived>
-class LValueExprEvaluatorBase
- : public ExprEvaluatorBase<Derived> {
+template <class Derived>
+class LValueExprEvaluatorBase : public ExprEvaluatorBase<Derived> {
protected:
LValue &Result;
bool InvalidBaseOK;
@@ -8882,7 +8870,7 @@ class LValueExprEvaluatorBase
}
}
};
-}
+} // namespace
//===----------------------------------------------------------------------===//
// LValue Evaluation
@@ -8919,10 +8907,10 @@ class LValueExprEvaluatorBase
//===----------------------------------------------------------------------===//
namespace {
class LValueExprEvaluator
- : public LValueExprEvaluatorBase<LValueExprEvaluator> {
+ : public LValueExprEvaluatorBase<LValueExprEvaluator> {
public:
- LValueExprEvaluator(EvalInfo &Info, LValue &Result, bool InvalidBaseOK) :
- LValueExprEvaluatorBaseTy(Info, Result, InvalidBaseOK) {}
+ LValueExprEvaluator(EvalInfo &Info, LValue &Result, bool InvalidBaseOK)
+ : LValueExprEvaluatorBaseTy(Info, Result, InvalidBaseOK) {}
bool VisitVarDecl(const Expr *E, const VarDecl *VD);
bool VisitUnaryPreIncDec(const UnaryOperator *UO);
@@ -9039,7 +9027,8 @@ static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info,
bool InvalidBaseOK) {
assert(!E->isValueDependent());
assert(E->isGLValue() || E->getType()->isFunctionType() ||
- E->getType()->isVoidType() || isa<ObjCSelectorExpr>(E->IgnoreParens()));
+ E->getType()->isVoidType() ||
+ isa<ObjCSelectorExpr>(E->IgnoreParens()));
return LValueExprEvaluator(Info, Result, InvalidBaseOK).Visit(E);
}
@@ -9221,8 +9210,8 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
return true;
}
-bool
-LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
+bool LValueExprEvaluator::VisitCompoundLiteralExpr(
+ const CompoundLiteralExpr *E) {
assert((!Info.getLangOpts().CPlusPlus || E->isFileScope()) &&
"lvalue compound literal in c++?");
APValue *Lit;
@@ -9261,8 +9250,8 @@ bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
} else {
if (!Info.Ctx.getLangOpts().CPlusPlus20) {
Info.CCEDiag(E, diag::note_constexpr_typeid_polymorphic)
- << E->getExprOperand()->getType()
- << E->getExprOperand()->getSourceRange();
+ << E->getExprOperand()->getType()
+ << E->getExprOperand()->getSourceRange();
}
if (!Visit(E->getExprOperand()))
@@ -9417,9 +9406,8 @@ bool LValueExprEvaluator::VisitUnaryPreIncDec(const UnaryOperator *UO) {
if (!this->Visit(UO->getSubExpr()))
return false;
- return handleIncDec(
- this->Info, UO, Result, UO->getSubExpr()->getType(),
- UO->isIncrementOp(), nullptr);
+ return handleIncDec(this->Info, UO, Result, UO->getSubExpr()->getType(),
+ UO->isIncrementOp(), nullptr);
}
bool LValueExprEvaluator::VisitCompoundAssignOperator(
@@ -9442,8 +9430,8 @@ bool LValueExprEvaluator::VisitCompoundAssignOperator(
return false;
return handleCompoundAssignment(
- this->Info, CAO,
- Result, CAO->getLHS()->getType(), CAO->getComputationLHSType(),
+ this->Info, CAO, Result, CAO->getLHS()->getType(),
+ CAO->getComputationLHSType(),
CAO->getOpForCompoundAssignment(CAO->getOpcode()), RHS);
}
@@ -9531,8 +9519,7 @@ static bool evaluateLValueAsAllocSize(EvalInfo &Info, APValue::LValueBase Base,
}
namespace {
-class PointerExprEvaluator
- : public ExprEvaluatorBase<PointerExprEvaluator> {
+class PointerExprEvaluator : public ExprEvaluatorBase<PointerExprEvaluator> {
LValue &Result;
bool InvalidBaseOK;
@@ -9550,8 +9537,8 @@ class PointerExprEvaluator
}
bool visitNonBuiltinCallExpr(const CallExpr *E);
-public:
+public:
PointerExprEvaluator(EvalInfo &info, LValue &Result, bool InvalidBaseOK)
: ExprEvaluatorBaseTy(info), Result(Result),
InvalidBaseOK(InvalidBaseOK) {}
@@ -9566,10 +9553,9 @@ class PointerExprEvaluator
}
bool VisitBinaryOperator(const BinaryOperator *E);
- bool VisitCastExpr(const CastExpr* E);
+ bool VisitCastExpr(const CastExpr *E);
bool VisitUnaryAddrOf(const UnaryOperator *E);
- bool VisitObjCStringLiteral(const ObjCStringLiteral *E)
- { return Success(E); }
+ bool VisitObjCStringLiteral(const ObjCStringLiteral *E) { return Success(E); }
bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E) {
if (E->isExpressibleAsConstantInitializer())
return Success(E);
@@ -9577,8 +9563,7 @@ class PointerExprEvaluator
EvaluateIgnoredValue(Info, E->getSubExpr());
return Error(E);
}
- bool VisitAddrLabelExpr(const AddrLabelExpr *E)
- { return Success(E); }
+ bool VisitAddrLabelExpr(const AddrLabelExpr *E) { return Success(E); }
bool VisitCallExpr(const CallExpr *E);
bool VisitBuiltinCallExpr(const CallExpr *E, unsigned BuiltinOp);
bool VisitBlockExpr(const BlockExpr *E) {
@@ -9668,7 +9653,7 @@ class PointerExprEvaluator
};
} // end anonymous namespace
-static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info,
+static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info,
bool InvalidBaseOK) {
assert(!E->isValueDependent());
assert(E->isPRValue() && E->getType()->hasPointerRepresentation());
@@ -9676,8 +9661,7 @@ static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info,
}
bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
- if (E->getOpcode() != BO_Add &&
- E->getOpcode() != BO_Sub)
+ if (E->getOpcode() != BO_Add && E->getOpcode() != BO_Sub)
return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
const Expr *PExp = E->getLHS();
@@ -9799,9 +9783,10 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
// Now figure out the necessary offset to add to the base LV to get from
// the derived class to the base class.
- return HandleLValueBasePath(Info, E, E->getSubExpr()->getType()->
- castAs<PointerType>()->getPointeeType(),
- Result);
+ return HandleLValueBasePath(
+ Info, E,
+ E->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType(),
+ Result);
case CK_BaseToDerived:
if (!Visit(E->getSubExpr()))
@@ -10127,8 +10112,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
if (!EvaluateInteger(E->getArg(1), Desired, Info))
return false;
uint64_t MaxLength = uint64_t(-1);
- if (BuiltinOp != Builtin::BIstrchr &&
- BuiltinOp != Builtin::BIwcschr &&
+ if (BuiltinOp != Builtin::BIstrchr && BuiltinOp != Builtin::BIwcschr &&
BuiltinOp != Builtin::BI__builtin_strchr &&
BuiltinOp != Builtin::BI__builtin_wcschr) {
APSInt N;
@@ -10145,9 +10129,8 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
QualType CharTy = Result.Designator.getType(Info.Ctx);
bool IsRawByte = BuiltinOp == Builtin::BImemchr ||
BuiltinOp == Builtin::BI__builtin_memchr;
- assert(IsRawByte ||
- Info.Ctx.hasSameUnqualifiedType(
- CharTy, E->getArg(0)->getType()->getPointeeType()));
+ assert(IsRawByte || Info.Ctx.hasSameUnqualifiedType(
+ CharTy, E->getArg(0)->getType()->getPointeeType()));
// Pointers to const void may point to objects of incomplete type.
if (IsRawByte && CharTy->isIncompleteType()) {
Info.FFDiag(E, diag::note_constexpr_ltor_incomplete_type) << CharTy;
@@ -10298,7 +10281,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
llvm::APInt::udivrem(OrigN, TSize, N, Remainder);
if (Remainder) {
Info.FFDiag(E, diag::note_constexpr_memcpy_unsupported)
- << Move << WChar << 0 << T << toString(OrigN, 10, /*Signed*/false)
+ << Move << WChar << 0 << T << toString(OrigN, 10, /*Signed*/ false)
<< (unsigned)TSize;
return false;
}
@@ -10312,7 +10295,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
if (N.ugt(RemainingSrcSize) || N.ugt(RemainingDestSize)) {
Info.FFDiag(E, diag::note_constexpr_memcpy_unsupported)
<< Move << WChar << (N.ugt(RemainingSrcSize) ? 1 : 2) << T
- << toString(N, 10, /*Signed*/false);
+ << toString(N, 10, /*Signed*/ false);
return false;
}
uint64_t NElems = N.getZExtValue();
@@ -10508,8 +10491,7 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
AllocType = Info.Ctx.getConstantArrayType(AllocType, ArrayBound, nullptr,
ArraySizeModifier::Normal, 0);
} else {
- assert(!AllocType->isArrayType() &&
- "array allocation with non-array new");
+ assert(!AllocType->isArrayType() && "array allocation with non-array new");
}
APValue *Val;
@@ -10612,24 +10594,24 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
namespace {
class MemberPointerExprEvaluator
- : public ExprEvaluatorBase<MemberPointerExprEvaluator> {
+ : public ExprEvaluatorBase<MemberPointerExprEvaluator> {
MemberPtr &Result;
bool Success(const ValueDecl *D) {
Result = MemberPtr(D);
return true;
}
-public:
+public:
MemberPointerExprEvaluator(EvalInfo &Info, MemberPtr &Result)
- : ExprEvaluatorBaseTy(Info), Result(Result) {}
+ : ExprEvaluatorBaseTy(Info), Result(Result) {}
bool Success(const APValue &V, const Expr *E) {
Result.setFrom(V);
return true;
}
bool ZeroInitialization(const Expr *E) {
- return Success((const ValueDecl*)nullptr);
+ return Success((const ValueDecl *)nullptr);
}
bool VisitCastExpr(const CastExpr *E);
@@ -10680,7 +10662,8 @@ bool MemberPointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (!Visit(E->getSubExpr()))
return false;
for (CastExpr::path_const_iterator PathI = E->path_begin(),
- PathE = E->path_end(); PathI != PathE; ++PathI) {
+ PathE = E->path_end();
+ PathI != PathE; ++PathI) {
assert(!(*PathI)->isVirtual() && "memptr cast through vbase");
const CXXRecordDecl *Base = (*PathI)->getType()->getAsCXXRecordDecl();
if (!Result.castToBase(Base))
@@ -10701,42 +10684,41 @@ bool MemberPointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
//===----------------------------------------------------------------------===//
namespace {
- class RecordExprEvaluator
- : public ExprEvaluatorBase<RecordExprEvaluator> {
- const LValue &This;
- APValue &Result;
- public:
+class RecordExprEvaluator : public ExprEvaluatorBase<RecordExprEvaluator> {
+ const LValue &This;
+ APValue &Result;
- RecordExprEvaluator(EvalInfo &info, const LValue &This, APValue &Result)
+public:
+ RecordExprEvaluator(EvalInfo &info, const LValue &This, APValue &Result)
: ExprEvaluatorBaseTy(info), This(This), Result(Result) {}
- bool Success(const APValue &V, const Expr *E) {
- Result = V;
- return true;
- }
- bool ZeroInitialization(const Expr *E) {
- return ZeroInitialization(E, E->getType());
- }
- bool ZeroInitialization(const Expr *E, QualType T);
+ bool Success(const APValue &V, const Expr *E) {
+ Result = V;
+ return true;
+ }
+ bool ZeroInitialization(const Expr *E) {
+ return ZeroInitialization(E, E->getType());
+ }
+ bool ZeroInitialization(const Expr *E, QualType T);
- bool VisitCallExpr(const CallExpr *E) {
- return handleCallExpr(E, Result, &This);
- }
- bool VisitCastExpr(const CastExpr *E);
- bool VisitInitListExpr(const InitListExpr *E);
- bool VisitCXXConstructExpr(const CXXConstructExpr *E) {
- return VisitCXXConstructExpr(E, E->getType());
- }
- bool VisitLambdaExpr(const LambdaExpr *E);
- bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
- bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T);
- bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
- bool VisitBinCmp(const BinaryOperator *E);
- bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
- bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit,
- ArrayRef<Expr *> Args);
- };
-}
+ bool VisitCallExpr(const CallExpr *E) {
+ return handleCallExpr(E, Result, &This);
+ }
+ bool VisitCastExpr(const CastExpr *E);
+ bool VisitInitListExpr(const InitListExpr *E);
+ bool VisitCXXConstructExpr(const CXXConstructExpr *E) {
+ return VisitCXXConstructExpr(E, E->getType());
+ }
+ bool VisitLambdaExpr(const LambdaExpr *E);
+ bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
+ bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T);
+ bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
+ bool VisitBinCmp(const BinaryOperator *E);
+ bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
+ bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit,
+ ArrayRef<Expr *> Args);
+};
+} // namespace
/// Perform zero-initialization on an object of non-union class type.
/// C++11 [dcl.init]p5:
@@ -10753,13 +10735,15 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E,
Result = APValue(APValue::UninitStruct(), CD ? CD->getNumBases() : 0,
std::distance(RD->field_begin(), RD->field_end()));
- if (RD->isInvalidDecl()) return false;
+ if (RD->isInvalidDecl())
+ return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
if (CD) {
unsigned Index = 0;
for (CXXRecordDecl::base_class_const_iterator I = CD->bases_begin(),
- End = CD->bases_end(); I != End; ++I, ++Index) {
+ End = CD->bases_end();
+ I != End; ++I, ++Index) {
const CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl();
LValue Subobject = This;
if (!HandleLValueDirectBase(Info, E, Subobject, CD, Base, &Layout))
@@ -10780,8 +10764,8 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E,
return false;
ImplicitValueInitExpr VIE(I->getType());
- if (!EvaluateInPlace(
- Result.getStructField(I->getFieldIndex()), Info, Subobject, &VIE))
+ if (!EvaluateInPlace(Result.getStructField(I->getFieldIndex()), Info,
+ Subobject, &VIE))
return false;
}
@@ -10790,7 +10774,8 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E,
bool RecordExprEvaluator::ZeroInitialization(const Expr *E, QualType T) {
const auto *RD = T->castAsRecordDecl();
- if (RD->isInvalidDecl()) return false;
+ if (RD->isInvalidDecl())
+ return false;
if (RD->isUnion()) {
// C++11 [dcl.init]p5: If T is a (possibly cv-qualified) union type, the
// object's first non-static named data member is zero-initialized
@@ -10798,7 +10783,7 @@ bool RecordExprEvaluator::ZeroInitialization(const Expr *E, QualType T) {
while (I != RD->field_end() && (*I)->isUnnamedBitField())
++I;
if (I == RD->field_end()) {
- Result = APValue((const FieldDecl*)nullptr);
+ Result = APValue((const FieldDecl *)nullptr);
return true;
}
@@ -10838,7 +10823,8 @@ bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) {
APValue *Value = &DerivedObject;
const CXXRecordDecl *RD = E->getSubExpr()->getType()->getAsCXXRecordDecl();
for (CastExpr::path_const_iterator PathI = E->path_begin(),
- PathE = E->path_end(); PathI != PathE; ++PathI) {
+ PathE = E->path_end();
+ PathI != PathE; ++PathI) {
assert(!(*PathI)->isVirtual() && "record rvalue with virtual base");
const CXXRecordDecl *Base = (*PathI)->getType()->getAsCXXRecordDecl();
Value = &Value->getStructBase(getBaseIndex(RD, Base));
@@ -10859,7 +10845,8 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
const Expr *ExprToVisit, ArrayRef<Expr *> Args) {
const auto *RD = ExprToVisit->getType()->castAsRecordDecl();
- if (RD->isInvalidDecl()) return false;
+ if (RD->isInvalidDecl())
+ return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
@@ -11002,7 +10989,8 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
// Note that E's type is not necessarily the type of our class here; we might
// be initializing an array element instead.
const CXXConstructorDecl *FD = E->getConstructor();
- if (FD->isInvalidDecl() || FD->getParent()->isInvalidDecl()) return false;
+ if (FD->isInvalidDecl() || FD->getParent()->isInvalidDecl())
+ return false;
bool ZeroInit = E->requiresZeroInitialization();
if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD, ZeroInit)) {
@@ -11036,10 +11024,9 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
if (ZeroInit && !ZeroInitialization(E, T))
return false;
- auto Args = ArrayRef(E->getArgs(), E->getNumArgs());
- return HandleConstructorCall(E, This, Args,
- cast<CXXConstructorDecl>(Definition), Info,
- Result);
+ auto Args = ArrayRef(E->getArgs(), E->getNumArgs());
+ return HandleConstructorCall(
+ E, This, Args, cast<CXXConstructorDecl>(Definition), Info, Result);
}
bool RecordExprEvaluator::VisitCXXInheritedCtorInitExpr(
@@ -11126,7 +11113,7 @@ bool RecordExprEvaluator::VisitLambdaExpr(const LambdaExpr *E) {
"The number of lambda capture initializers should equal the number of "
"fields within the closure type");
- Result = APValue(APValue::UninitStruct(), /*NumBases*/0, NumFields);
+ Result = APValue(APValue::UninitStruct(), /*NumBases*/ 0, NumFields);
// Iterate through all the lambda's closure object's fields and initialize
// them.
auto *CaptureInitIt = E->capture_init_begin();
@@ -11157,8 +11144,8 @@ bool RecordExprEvaluator::VisitLambdaExpr(const LambdaExpr *E) {
return Success;
}
-static bool EvaluateRecord(const Expr *E, const LValue &This,
- APValue &Result, EvalInfo &Info) {
+static bool EvaluateRecord(const Expr *E, const LValue &This, APValue &Result,
+ EvalInfo &Info) {
assert(!E->isValueDependent());
assert(E->isPRValue() && E->getType()->isRecordType() &&
"can't evaluate expression as a record rvalue");
@@ -11174,10 +11161,10 @@ static bool EvaluateRecord(const Expr *E, const LValue &This,
//===----------------------------------------------------------------------===//
namespace {
class TemporaryExprEvaluator
- : public LValueExprEvaluatorBase<TemporaryExprEvaluator> {
+ : public LValueExprEvaluatorBase<TemporaryExprEvaluator> {
public:
- TemporaryExprEvaluator(EvalInfo &Info, LValue &Result) :
- LValueExprEvaluatorBaseTy(Info, Result, false) {}
+ TemporaryExprEvaluator(EvalInfo &Info, LValue &Result)
+ : LValueExprEvaluatorBaseTy(Info, Result, false) {}
/// Visit an expression which constructs the value of this temporary.
bool VisitConstructExpr(const Expr *E) {
@@ -11201,15 +11188,11 @@ class TemporaryExprEvaluator
bool VisitCXXConstructExpr(const CXXConstructExpr *E) {
return VisitConstructExpr(E);
}
- bool VisitCallExpr(const CallExpr *E) {
- return VisitConstructExpr(E);
- }
+ bool VisitCallExpr(const CallExpr *E) { return VisitConstructExpr(E); }
bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E) {
return VisitConstructExpr(E);
}
- bool VisitLambdaExpr(const LambdaExpr *E) {
- return VisitConstructExpr(E);
- }
+ bool VisitLambdaExpr(const LambdaExpr *E) { return VisitConstructExpr(E); }
};
} // end anonymous namespace
@@ -11225,44 +11208,42 @@ static bool EvaluateTemporary(const Expr *E, LValue &Result, EvalInfo &Info) {
//===----------------------------------------------------------------------===//
namespace {
- class VectorExprEvaluator
- : public ExprEvaluatorBase<VectorExprEvaluator> {
- APValue &Result;
- public:
+class VectorExprEvaluator : public ExprEvaluatorBase<VectorExprEvaluator> {
+ APValue &Result;
- VectorExprEvaluator(EvalInfo &info, APValue &Result)
+public:
+ VectorExprEvaluator(EvalInfo &info, APValue &Result)
: ExprEvaluatorBaseTy(info), Result(Result) {}
- bool Success(ArrayRef<APValue> V, const Expr *E) {
- assert(V.size() == E->getType()->castAs<VectorType>()->getNumElements());
- // FIXME: remove this APValue copy.
- Result = APValue(V.data(), V.size());
- return true;
- }
- bool Success(const APValue &V, const Expr *E) {
- assert(V.isVector());
- Result = V;
- return true;
- }
- bool ZeroInitialization(const Expr *E);
-
- bool VisitUnaryReal(const UnaryOperator *E)
- { return Visit(E->getSubExpr()); }
- bool VisitCastExpr(const CastExpr* E);
- bool VisitInitListExpr(const InitListExpr *E);
- bool VisitUnaryImag(const UnaryOperator *E);
- bool VisitBinaryOperator(const BinaryOperator *E);
- bool VisitUnaryOperator(const UnaryOperator *E);
- bool VisitCallExpr(const CallExpr *E);
- bool VisitConvertVectorExpr(const ConvertVectorExpr *E);
- bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E);
-
- // FIXME: Missing: conditional operator (for GNU
- // conditional select), ExtVectorElementExpr
- };
+ bool Success(ArrayRef<APValue> V, const Expr *E) {
+ assert(V.size() == E->getType()->castAs<VectorType>()->getNumElements());
+ // FIXME: remove this APValue copy.
+ Result = APValue(V.data(), V.size());
+ return true;
+ }
+ bool Success(const APValue &V, const Expr *E) {
+ assert(V.isVector());
+ Result = V;
+ return true;
+ }
+ bool ZeroInitialization(const Expr *E);
+
+ bool VisitUnaryReal(const UnaryOperator *E) { return Visit(E->getSubExpr()); }
+ bool VisitCastExpr(const CastExpr *E);
+ bool VisitInitListExpr(const InitListExpr *E);
+ bool VisitUnaryImag(const UnaryOperator *E);
+ bool VisitBinaryOperator(const BinaryOperator *E);
+ bool VisitUnaryOperator(const UnaryOperator *E);
+ bool VisitCallExpr(const CallExpr *E);
+ bool VisitConvertVectorExpr(const ConvertVectorExpr *E);
+ bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E);
+
+ // FIXME: Missing: conditional operator (for GNU
+ // conditional select), ExtVectorElementExpr
+};
} // end anonymous namespace
-static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) {
+static bool EvaluateVector(const Expr *E, APValue &Result, EvalInfo &Info) {
assert(E->isPRValue() && E->getType()->isVectorType() &&
"not a vector prvalue");
return VectorExprEvaluator(Info, Result).Visit(E);
@@ -11347,8 +11328,7 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) {
}
}
-bool
-VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
+bool VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
const VectorType *VT = E->getType()->castAs<VectorType>();
unsigned NumInits = E->getNumInits();
unsigned NumElements = VT->getNumElements();
@@ -11368,8 +11348,8 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
unsigned CountInits = 0, CountElts = 0;
while (CountElts < NumElements) {
// Handle nested vector initialization.
- if (CountInits < NumInits
- && E->getInit(CountInits)->getType()->isVectorType()) {
+ if (CountInits < NumInits &&
+ E->getInit(CountInits)->getType()->isVectorType()) {
APValue v;
if (!EvaluateVector(E->getInit(CountInits), v, Info))
return Error(E);
@@ -11401,8 +11381,7 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
return Success(Elements, E);
}
-bool
-VectorExprEvaluator::ZeroInitialization(const Expr *E) {
+bool VectorExprEvaluator::ZeroInitialization(const Expr *E) {
const auto *VT = E->getType()->castAs<VectorType>();
QualType EltTy = VT->getElementType();
APValue ZeroElement;
@@ -11869,6 +11848,319 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
return Success(APValue(ResultElements.data(), ResultElements.size()), E);
}
+ case X86::BI__builtin_ia32_pshufw: {
+ APValue Src;
+ APSInt Imm;
+ if (!EvaluateAsRValue(Info, E->getArg(0), Src))
+ return false;
+ if (!EvaluateInteger(E->getArg(1), Imm, Info))
+ return false;
+
+ unsigned N = Src.getVectorLength();
+ SmallVector<APValue, 4> ResultElements;
+ ResultElements.reserve(N);
+
+ uint8_t C = static_cast<uint8_t>(Imm.getZExtValue());
+ for (unsigned i = 0; i != N; ++i) {
+ unsigned sel = (C >> (2 * i)) & 0x3;
+ ResultElements.push_back(Src.getVectorElt(sel));
+ }
+ return Success(APValue(ResultElements.data(), ResultElements.size()), E);
+ }
+
+ case clang::X86::BI__builtin_ia32_pshuflw:
+ case clang::X86::BI__builtin_ia32_pshuflw256:
+ case clang::X86::BI__builtin_ia32_pshuflw512:
+ case clang::X86::BI__builtin_ia32_pshuflw128_mask:
+ case clang::X86::BI__builtin_ia32_pshuflw256_mask:
+ case clang::X86::BI__builtin_ia32_pshuflw512_mask:
+ case clang::X86::BI__builtin_ia32_pshuflw128_maskz:
+ case clang::X86::BI__builtin_ia32_pshuflw256_maskz:
+ case clang::X86::BI__builtin_ia32_pshuflw512_maskz: {
+ const unsigned BID = E->getBuiltinCallee();
+
+ const bool IsMask = BID == clang::X86::BI__builtin_ia32_pshuflw128_mask ||
+ BID == clang::X86::BI__builtin_ia32_pshuflw256_mask ||
+ BID == clang::X86::BI__builtin_ia32_pshuflw512_mask;
+
+ const bool IsMaskZ = BID == clang::X86::BI__builtin_ia32_pshuflw128_maskz ||
+ BID == clang::X86::BI__builtin_ia32_pshuflw256_maskz ||
+ BID == clang::X86::BI__builtin_ia32_pshuflw512_maskz;
+
+ const unsigned AIdx = 0, ImmIdx = 1;
+ const unsigned SrcIdx = 2;
+ const unsigned KIdx = IsMaskZ ? 2 : 3;
+
+ APValue AVal, SrcVal;
+ APSInt Imm, K;
+ if (!EvaluateAsRValue(Info, E->getArg(AIdx), AVal))
+ return false;
+ if (!EvaluateInteger(E->getArg(ImmIdx), Imm, Info))
+ return false;
+
+ const APSInt *KPtr = nullptr;
+ const APValue *PassThru = nullptr;
+ bool ZeroInactive = false;
+
+ if (IsMask) {
+ if (!EvaluateAsRValue(Info, E->getArg(SrcIdx), SrcVal))
+ return false;
+ if (!EvaluateInteger(E->getArg(KIdx), K, Info))
+ return false;
+ KPtr = &K;
+ PassThru = &SrcVal;
+ ZeroInactive = false;
+ } else if (IsMaskZ) {
+ if (!EvaluateInteger(E->getArg(KIdx), K, Info))
+ return false;
+ KPtr = &K;
+ PassThru = nullptr;
+ ZeroInactive = true;
+ }
+
+ const auto *VT = E->getType()->getAs<VectorType>();
+ if (!VT)
+ return false;
+ const unsigned NumElts = VT->getNumElements();
+
+ const unsigned ElemBits = 16;
+ const unsigned LaneElems = std::min(NumElts, 128u / ElemBits);
+ const unsigned Half = 4;
+ const uint8_t Ctl = static_cast<uint8_t>(Imm.getZExtValue());
+ const bool DestUnsigned =
+ VT->getElementType()->isUnsignedIntegerOrEnumerationType();
+
+ auto MakeZero = [&]() -> APValue {
+ return APValue(APSInt(APInt(ElemBits, 0), DestUnsigned));
+ };
+
+ SmallVector<APValue, 32> ResultElements;
+ ResultElements.reserve(NumElts);
+
+ for (unsigned i = 0; i < NumElts; ++i) {
+ const unsigned laneBase = (i / LaneElems) * LaneElems;
+ const unsigned inLane = i % LaneElems;
+
+ APValue Chosen;
+ if (inLane < Half) {
+ const unsigned pos = inLane;
+ const unsigned sel = (Ctl >> (2 * pos)) & 0x3;
+ const unsigned srcIdx = laneBase + sel;
+ Chosen = AVal.getVectorElt(srcIdx);
+ } else {
+ Chosen = AVal.getVectorElt(i);
+ }
+
+ if (KPtr) {
+ const bool Keep = (i < KPtr->getBitWidth()) ? (*KPtr)[i] : false;
+ if (Keep) {
+ ResultElements.push_back(Chosen);
+ } else if (ZeroInactive) {
+ ResultElements.push_back(MakeZero());
+ } else {
+ const APValue &PT =
+ PassThru ? PassThru->getVectorElt(i) : AVal.getVectorElt(i);
+ ResultElements.push_back(PT);
+ }
+ } else {
+ ResultElements.push_back(Chosen);
+ }
+ }
+ return Success(APValue(ResultElements.data(), ResultElements.size()), E);
+ }
+
+ case clang::X86::BI__builtin_ia32_pshufhw:
+ case clang::X86::BI__builtin_ia32_pshufhw256:
+ case clang::X86::BI__builtin_ia32_pshufhw512:
+ case clang::X86::BI__builtin_ia32_pshufhw128_mask:
+ case clang::X86::BI__builtin_ia32_pshufhw256_mask:
+ case clang::X86::BI__builtin_ia32_pshufhw512_mask:
+ case clang::X86::BI__builtin_ia32_pshufhw128_maskz:
+ case clang::X86::BI__builtin_ia32_pshufhw256_maskz:
+ case clang::X86::BI__builtin_ia32_pshufhw512_maskz: {
+ const unsigned BID = E->getBuiltinCallee();
+
+ const bool IsMask = BID == clang::X86::BI__builtin_ia32_pshufhw128_mask ||
+ BID == clang::X86::BI__builtin_ia32_pshufhw256_mask ||
+ BID == clang::X86::BI__builtin_ia32_pshufhw512_mask;
+
+ const bool IsMaskZ = BID == clang::X86::BI__builtin_ia32_pshufhw128_maskz ||
+ BID == clang::X86::BI__builtin_ia32_pshufhw256_maskz ||
+ BID == clang::X86::BI__builtin_ia32_pshufhw512_maskz;
+
+ const unsigned AIdx = 0, ImmIdx = 1;
+ const unsigned SrcIdx = 2;
+ const unsigned KIdx = IsMaskZ ? 2 : 3;
+
+ APValue AVal, SrcVal;
+ APSInt Imm, K;
+ if (!EvaluateAsRValue(Info, E->getArg(AIdx), AVal))
+ return false;
+ if (!EvaluateInteger(E->getArg(ImmIdx), Imm, Info))
+ return false;
+
+ const APSInt *KPtr = nullptr;
+ const APValue *PassThru = nullptr;
+ bool ZeroInactive = false;
+ if (IsMask) {
+ if (!EvaluateAsRValue(Info, E->getArg(SrcIdx), SrcVal))
+ return false;
+ if (!EvaluateInteger(E->getArg(KIdx), K, Info))
+ return false;
+ KPtr = &K;
+ PassThru = &SrcVal;
+ ZeroInactive = false;
+ } else if (IsMaskZ) {
+ if (!EvaluateInteger(E->getArg(KIdx), K, Info))
+ return false;
+ KPtr = &K;
+ PassThru = nullptr;
+ ZeroInactive = true;
+ }
+
+ const auto *VT = E->getType()->getAs<VectorType>();
+ if (!VT)
+ return false;
+ const unsigned NumElts = VT->getNumElements();
+ const unsigned ElemBits = 16;
+ const unsigned LaneElems = std::min(NumElts, 128u / ElemBits);
+ const unsigned Half = 4;
+ const uint8_t Ctl = static_cast<uint8_t>(Imm.getZExtValue());
+ const bool DestUnsigned =
+ VT->getElementType()->isUnsignedIntegerOrEnumerationType();
+
+ auto MakeZero = [&]() -> APValue {
+ return APValue(APSInt(APInt(ElemBits, 0), DestUnsigned));
+ };
+
+ SmallVector<APValue, 32> Out;
+ Out.reserve(NumElts);
+
+ for (unsigned i = 0; i < NumElts; ++i) {
+ const unsigned laneBase = (i / LaneElems) * LaneElems;
+ const unsigned inLane = i % LaneElems;
+
+ APValue Chosen;
+ if (inLane >= Half) {
+ const unsigned pos = inLane - Half;
+ const unsigned sel = (Ctl >> (2 * pos)) & 0x3;
+ const unsigned srcIdx = laneBase + Half + sel;
+ Chosen = AVal.getVectorElt(srcIdx);
+ } else {
+ Chosen = AVal.getVectorElt(i);
+ }
+
+ if (KPtr) {
+ const bool Keep = (i < KPtr->getBitWidth()) ? (*KPtr)[i] : false;
+ if (Keep) {
+ Out.push_back(Chosen);
+ } else if (ZeroInactive) {
+ Out.push_back(MakeZero());
+ } else {
+ const APValue &PT =
+ PassThru ? PassThru->getVectorElt(i) : AVal.getVectorElt(i);
+ Out.push_back(PT);
+ }
+ } else {
+ Out.push_back(Chosen);
+ }
+ }
+ return Success(APValue(Out.data(), Out.size()), E);
+ }
+
+ case clang::X86::BI__builtin_ia32_pshufd:
+ case clang::X86::BI__builtin_ia32_pshufd256:
+ case clang::X86::BI__builtin_ia32_pshufd512:
+ case clang::X86::BI__builtin_ia32_pshufd128_mask:
+ case clang::X86::BI__builtin_ia32_pshufd256_mask:
+ case clang::X86::BI__builtin_ia32_pshufd512_mask:
+ case clang::X86::BI__builtin_ia32_pshufd128_maskz:
+ case clang::X86::BI__builtin_ia32_pshufd256_maskz:
+ case clang::X86::BI__builtin_ia32_pshufd512_maskz: {
+ const unsigned BID = E->getBuiltinCallee();
+
+ const bool IsMask = BID == clang::X86::BI__builtin_ia32_pshufd512_mask ||
+ BID == clang::X86::BI__builtin_ia32_pshufd128_mask ||
+ BID == clang::X86::BI__builtin_ia32_pshufd256_mask;
+
+ const bool IsMaskZ = BID == clang::X86::BI__builtin_ia32_pshufd512_maskz ||
+ BID == clang::X86::BI__builtin_ia32_pshufd128_maskz ||
+ BID == clang::X86::BI__builtin_ia32_pshufd256_maskz;
+
+ const unsigned AIdx = 0, ImmIdx = 1;
+ const unsigned SrcIdx = 2;
+ const unsigned KIdx = IsMaskZ ? 2 : 3;
+
+ APValue AVal, SrcVal;
+ APSInt Imm, K;
+ if (!EvaluateAsRValue(Info, E->getArg(AIdx), AVal))
+ return false;
+ if (!EvaluateInteger(E->getArg(ImmIdx), Imm, Info))
+ return false;
+
+ const APSInt *KPtr = nullptr;
+ const APValue *PassThru = nullptr;
+ bool ZeroInactive = false;
+ if (IsMask) {
+ if (!EvaluateAsRValue(Info, E->getArg(SrcIdx), SrcVal))
+ return false;
+ if (!EvaluateInteger(E->getArg(KIdx), K, Info))
+ return false;
+ KPtr = &K;
+ PassThru = &SrcVal;
+ ZeroInactive = false;
+ } else if (IsMaskZ) {
+ if (!EvaluateInteger(E->getArg(KIdx), K, Info))
+ return false;
+ KPtr = &K;
+ PassThru = nullptr;
+ ZeroInactive = true;
+ }
+
+ const auto *VT = E->getType()->getAs<VectorType>();
+ if (!VT)
+ return false;
+ const unsigned NumElts = VT->getNumElements();
+ const unsigned ElemBits = 32;
+ const unsigned LaneElems = std::min(NumElts, 128u / ElemBits);
+ const uint8_t Ctl = static_cast<uint8_t>(Imm.getZExtValue());
+ const bool DestUnsigned =
+ VT->getElementType()->isUnsignedIntegerOrEnumerationType();
+
+ auto MakeZero = [&]() -> APValue {
+ return APValue(APSInt(APInt(ElemBits, 0), DestUnsigned));
+ };
+
+ SmallVector<APValue, 32> Out;
+ Out.reserve(NumElts);
+
+ for (unsigned i = 0; i < NumElts; ++i) {
+ const unsigned laneBase = (i / LaneElems) * LaneElems;
+ const unsigned inLane = i % LaneElems;
+
+ const unsigned pos = inLane & 3;
+ const unsigned sel = (Ctl >> (2 * pos)) & 0x3;
+ const unsigned srcIdx = laneBase + sel;
+ APValue Chosen = AVal.getVectorElt(srcIdx);
+
+ if (KPtr) {
+ const bool Keep = (i < KPtr->getBitWidth()) ? (*KPtr)[i] : false;
+ if (Keep) {
+ Out.push_back(Chosen);
+ } else if (ZeroInactive) {
+ Out.push_back(MakeZero());
+ } else {
+ const APValue &PT =
+ PassThru ? PassThru->getVectorElt(i) : AVal.getVectorElt(i);
+ Out.push_back(PT);
+ }
+ } else {
+ Out.push_back(Chosen);
+ }
+ }
+ return Success(APValue(Out.data(), Out.size()), E);
+ }
+
case clang::X86::BI__builtin_ia32_vprotbi:
case clang::X86::BI__builtin_ia32_vprotdi:
case clang::X86::BI__builtin_ia32_vprotqi:
@@ -12329,72 +12621,70 @@ bool VectorExprEvaluator::VisitShuffleVectorExpr(const ShuffleVectorExpr *E) {
//===----------------------------------------------------------------------===//
namespace {
- class ArrayExprEvaluator
- : public ExprEvaluatorBase<ArrayExprEvaluator> {
- const LValue &This;
- APValue &Result;
- public:
+class ArrayExprEvaluator : public ExprEvaluatorBase<ArrayExprEvaluator> {
+ const LValue &This;
+ APValue &Result;
- ArrayExprEvaluator(EvalInfo &Info, const LValue &This, APValue &Result)
+public:
+ ArrayExprEvaluator(EvalInfo &Info, const LValue &This, APValue &Result)
: ExprEvaluatorBaseTy(Info), This(This), Result(Result) {}
- bool Success(const APValue &V, const Expr *E) {
- assert(V.isArray() && "expected array");
- Result = V;
- return true;
- }
-
- bool ZeroInitialization(const Expr *E) {
- const ConstantArrayType *CAT =
- Info.Ctx.getAsConstantArrayType(E->getType());
- if (!CAT) {
- if (E->getType()->isIncompleteArrayType()) {
- // We can be asked to zero-initialize a flexible array member; this
- // is represented as an ImplicitValueInitExpr of incomplete array
- // type. In this case, the array has zero elements.
- Result = APValue(APValue::UninitArray(), 0, 0);
- return true;
- }
- // FIXME: We could handle VLAs here.
- return Error(E);
- }
+ bool Success(const APValue &V, const Expr *E) {
+ assert(V.isArray() && "expected array");
+ Result = V;
+ return true;
+ }
- Result = APValue(APValue::UninitArray(), 0, CAT->getZExtSize());
- if (!Result.hasArrayFiller())
+ bool ZeroInitialization(const Expr *E) {
+ const ConstantArrayType *CAT =
+ Info.Ctx.getAsConstantArrayType(E->getType());
+ if (!CAT) {
+ if (E->getType()->isIncompleteArrayType()) {
+ // We can be asked to zero-initialize a flexible array member; this
+ // is represented as an ImplicitValueInitExpr of incomplete array
+ // type. In this case, the array has zero elements.
+ Result = APValue(APValue::UninitArray(), 0, 0);
return true;
+ }
+ // FIXME: We could handle VLAs here.
+ return Error(E);
+ }
- // Zero-initialize all elements.
- LValue Subobject = This;
- Subobject.addArray(Info, E, CAT);
- ImplicitValueInitExpr VIE(CAT->getElementType());
- return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, &VIE);
- }
-
- bool VisitCallExpr(const CallExpr *E) {
- return handleCallExpr(E, Result, &This);
- }
- bool VisitInitListExpr(const InitListExpr *E,
- QualType AllocType = QualType());
- bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E);
- bool VisitCXXConstructExpr(const CXXConstructExpr *E);
- bool VisitCXXConstructExpr(const CXXConstructExpr *E,
- const LValue &Subobject,
- APValue *Value, QualType Type);
- bool VisitStringLiteral(const StringLiteral *E,
- QualType AllocType = QualType()) {
- expandStringLiteral(Info, E, Result, AllocType);
+ Result = APValue(APValue::UninitArray(), 0, CAT->getZExtSize());
+ if (!Result.hasArrayFiller())
return true;
- }
- bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
- bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit,
- ArrayRef<Expr *> Args,
- const Expr *ArrayFiller,
- QualType AllocType = QualType());
- };
+
+ // Zero-initialize all elements.
+ LValue Subobject = This;
+ Subobject.addArray(Info, E, CAT);
+ ImplicitValueInitExpr VIE(CAT->getElementType());
+ return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, &VIE);
+ }
+
+ bool VisitCallExpr(const CallExpr *E) {
+ return handleCallExpr(E, Result, &This);
+ }
+ bool VisitInitListExpr(const InitListExpr *E,
+ QualType AllocType = QualType());
+ bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E);
+ bool VisitCXXConstructExpr(const CXXConstructExpr *E);
+ bool VisitCXXConstructExpr(const CXXConstructExpr *E, const LValue &Subobject,
+ APValue *Value, QualType Type);
+ bool VisitStringLiteral(const StringLiteral *E,
+ QualType AllocType = QualType()) {
+ expandStringLiteral(Info, E, Result, AllocType);
+ return true;
+ }
+ bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
+ bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit,
+ ArrayRef<Expr *> Args,
+ const Expr *ArrayFiller,
+ QualType AllocType = QualType());
+};
} // end anonymous namespace
-static bool EvaluateArray(const Expr *E, const LValue &This,
- APValue &Result, EvalInfo &Info) {
+static bool EvaluateArray(const Expr *E, const LValue &This, APValue &Result,
+ EvalInfo &Info) {
assert(!E->isValueDependent());
assert(E->isPRValue() && E->getType()->isArrayType() &&
"not an array prvalue");
@@ -12605,10 +12895,10 @@ bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
// array element, if any.
FullExpressionRAII Scope(Info);
- if (!EvaluateInPlace(Result.getArrayInitializedElt(Index),
- Info, Subobject, E->getSubExpr()) ||
- !HandleLValueArrayAdjustment(Info, E, Subobject,
- CAT->getElementType(), 1)) {
+ if (!EvaluateInPlace(Result.getArrayInitializedElt(Index), Info, Subobject,
+ E->getSubExpr()) ||
+ !HandleLValueArrayAdjustment(Info, E, Subobject, CAT->getElementType(),
+ 1)) {
if (!Info.noteFailure())
return false;
Success = false;
@@ -12627,17 +12917,16 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
const LValue &Subobject,
- APValue *Value,
- QualType Type) {
+ APValue *Value, QualType Type) {
bool HadZeroInit = Value->hasValue();
if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(Type)) {
unsigned FinalSize = CAT->getZExtSize();
// Preserve the array filler if we had prior zero-initialization.
- APValue Filler =
- HadZeroInit && Value->hasArrayFiller() ? Value->getArrayFiller()
- : APValue();
+ APValue Filler = HadZeroInit && Value->hasArrayFiller()
+ ? Value->getArrayFiller()
+ : APValue();
*Value = APValue(APValue::UninitArray(), 0, FinalSize);
if (FinalSize == 0)
@@ -12699,7 +12988,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
return Error(E);
return RecordExprEvaluator(Info, Subobject, *Value)
- .VisitCXXConstructExpr(E, Type);
+ .VisitCXXConstructExpr(E, Type);
}
bool ArrayExprEvaluator::VisitCXXParenListInitExpr(
@@ -12720,9 +13009,9 @@ bool ArrayExprEvaluator::VisitCXXParenListInitExpr(
//===----------------------------------------------------------------------===//
namespace {
-class IntExprEvaluator
- : public ExprEvaluatorBase<IntExprEvaluator> {
+class IntExprEvaluator : public ExprEvaluatorBase<IntExprEvaluator> {
APValue &Result;
+
public:
IntExprEvaluator(EvalInfo &info, APValue &result)
: ExprEvaluatorBaseTy(info), Result(result) {}
@@ -12748,7 +13037,7 @@ class IntExprEvaluator
"Invalid evaluation result.");
Result = APValue(APSInt(I));
Result.getInt().setIsUnsigned(
- E->getType()->isUnsignedIntegerOrEnumerationType());
+ E->getType()->isUnsignedIntegerOrEnumerationType());
return true;
}
bool Success(const llvm::APInt &I, const Expr *E) {
@@ -12818,7 +13107,7 @@ class IntExprEvaluator
bool VisitOffsetOfExpr(const OffsetOfExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
- bool VisitCastExpr(const CastExpr* E);
+ bool VisitCastExpr(const CastExpr *E);
bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) {
@@ -12840,9 +13129,7 @@ class IntExprEvaluator
}
// Note, GNU defines __null as an integer, not a pointer.
- bool VisitGNUNullExpr(const GNUNullExpr *E) {
- return ZeroInitialization(E);
- }
+ bool VisitGNUNullExpr(const GNUNullExpr *E) { return ZeroInitialization(E); }
bool VisitTypeTraitExpr(const TypeTraitExpr *E) {
if (E->isStoredAsBoolean())
@@ -12883,7 +13170,7 @@ class FixedPointExprEvaluator
: public ExprEvaluatorBase<FixedPointExprEvaluator> {
APValue &Result;
- public:
+public:
FixedPointExprEvaluator(EvalInfo &info, APValue &result)
: ExprEvaluatorBaseTy(info), Result(result) {}
@@ -12909,9 +13196,7 @@ class FixedPointExprEvaluator
return true;
}
- bool ZeroInitialization(const Expr *E) {
- return Success(0, E);
- }
+ bool ZeroInitialization(const Expr *E) { return Success(0, E); }
//===--------------------------------------------------------------------===//
// Visitor Methods
@@ -12998,14 +13283,14 @@ static bool EvaluateFixedPointOrInteger(const Expr *E, APFixedPoint &Result,
/// Check whether the given declaration can be directly converted to an integral
/// rvalue. If not, no diagnostic is produced; there are other things we can
/// try.
-bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) {
+bool IntExprEvaluator::CheckReferencedDecl(const Expr *E, const Decl *D) {
// Enums are integer constant exprs.
if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) {
// Check for signedness/width mismatches between E type and ECD value.
- bool SameSign = (ECD->getInitVal().isSigned()
- == E->getType()->isSignedIntegerOrEnumerationType());
- bool SameWidth = (ECD->getInitVal().getBitWidth()
- == Info.Ctx.getIntWidth(E->getType()));
+ bool SameSign = (ECD->getInitVal().isSigned() ==
+ E->getType()->isSignedIntegerOrEnumerationType());
+ bool SameWidth =
+ (ECD->getInitVal().getBitWidth() == Info.Ctx.getIntWidth(E->getType()));
if (SameSign && SameWidth)
return Success(ECD->getInitVal(), E);
else {
@@ -13038,17 +13323,20 @@ GCCTypeClass EvaluateBuiltinClassifyType(QualType T,
#include "clang/AST/TypeNodes.inc"
case Type::Auto:
case Type::DeducedTemplateSpecialization:
- llvm_unreachable("unexpected non-canonical or dependent type");
+ llvm_unreachable("unexpected non-canonical or dependent type");
case Type::Builtin:
- switch (cast<BuiltinType>(CanTy)->getKind()) {
+ switch (cast<BuiltinType>(CanTy)->getKind()) {
#define BUILTIN_TYPE(ID, SINGLETON_ID)
-#define SIGNED_TYPE(ID, SINGLETON_ID) \
- case BuiltinType::ID: return GCCTypeClass::Integer;
-#define FLOATING_TYPE(ID, SINGLETON_ID) \
- case BuiltinType::ID: return GCCTypeClass::RealFloat;
-#define PLACEHOLDER_TYPE(ID, SINGLETON_ID) \
- case BuiltinType::ID: break;
+#define SIGNED_TYPE(ID, SINGLETON_ID) \
+ case BuiltinType::ID: \
+ return GCCTypeClass::Integer;
+#define FLOATING_TYPE(ID, SINGLETON_ID) \
+ case BuiltinType::ID: \
+ return GCCTypeClass::RealFloat;
+#define PLACEHOLDER_TYPE(ID, SINGLETON_ID) \
+ case BuiltinType::ID: \
+ break;
#include "clang/AST/BuiltinTypes.def"
case BuiltinType::Void:
return GCCTypeClass::Void;
@@ -13088,22 +13376,19 @@ GCCTypeClass EvaluateBuiltinClassifyType(QualType T,
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
-#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
- case BuiltinType::Id:
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
+ case BuiltinType::Id:
#include "clang/Basic/OpenCLImageTypes.def"
-#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
- case BuiltinType::Id:
+#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) case BuiltinType::Id:
#include "clang/Basic/OpenCLExtensionTypes.def"
case BuiltinType::OCLSampler:
case BuiltinType::OCLEvent:
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
case BuiltinType::OCLReserveID:
-#define SVE_TYPE(Name, Id, SingletonId) \
- case BuiltinType::Id:
+#define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
#include "clang/Basic/AArch64ACLETypes.def"
-#define PPC_VECTOR_TYPE(Name, Id, Size) \
- case BuiltinType::Id:
+#define PPC_VECTOR_TYPE(Name, Id, Size) case BuiltinType::Id:
#include "clang/Basic/PPCTypes.def"
#define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
#include "clang/Basic/RISCVVTypes.def"
@@ -13178,8 +13463,8 @@ GCCTypeClass EvaluateBuiltinClassifyType(QualType T,
/// EvaluateBuiltinClassifyType - Evaluate __builtin_classify_type the same way
/// as GCC.
-static GCCTypeClass
-EvaluateBuiltinClassifyType(const CallExpr *E, const LangOptions &LangOpts) {
+static GCCTypeClass EvaluateBuiltinClassifyType(const CallExpr *E,
+ const LangOptions &LangOpts) {
// If no argument was supplied, default to None. This isn't
// ideal, however it is what gcc does.
if (E->getNumArgs() == 0)
@@ -13267,10 +13552,10 @@ static bool EvaluateBuiltinConstantP(EvalInfo &Info, const Expr *Arg) {
/// Retrieves the "underlying object type" of the given expression,
/// as used by __builtin_object_size.
static QualType getObjectType(APValue::LValueBase B) {
- if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) {
+ if (const ValueDecl *D = B.dyn_cast<const ValueDecl *>()) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D))
return VD->getType();
- } else if (const Expr *E = B.dyn_cast<const Expr*>()) {
+ } else if (const Expr *E = B.dyn_cast<const Expr *>()) {
if (isa<CompoundLiteralExpr>(E))
return E->getType();
} else if (B.is<TypeInfoLValue>()) {
@@ -13976,10 +14261,18 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return false;
unsigned Arg;
switch (Val.getCategory()) {
- case APFloat::fcNaN: Arg = 0; break;
- case APFloat::fcInfinity: Arg = 1; break;
- case APFloat::fcNormal: Arg = Val.isDenormal() ? 3 : 2; break;
- case APFloat::fcZero: Arg = 4; break;
+ case APFloat::fcNaN:
+ Arg = 0;
+ break;
+ case APFloat::fcInfinity:
+ Arg = 1;
+ break;
+ case APFloat::fcNormal:
+ Arg = Val.isDenormal() ? 3 : 2;
+ break;
+ case APFloat::fcZero:
+ Arg = 4;
+ break;
}
return Visit(E->getArg(Arg));
}
@@ -14273,8 +14566,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return false;
uint64_t MaxLength = uint64_t(-1);
- if (BuiltinOp != Builtin::BIstrcmp &&
- BuiltinOp != Builtin::BIwcscmp &&
+ if (BuiltinOp != Builtin::BIstrcmp && BuiltinOp != Builtin::BIwcscmp &&
BuiltinOp != Builtin::BI__builtin_strcmp &&
BuiltinOp != Builtin::BI__builtin_wcscmp) {
APSInt N;
@@ -14416,8 +14708,8 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
}
}
- return BuiltinOp == Builtin::BI__atomic_always_lock_free ?
- Success(0, E) : Error(E);
+ return BuiltinOp == Builtin::BI__atomic_always_lock_free ? Success(0, E)
+ : Error(E);
}
case Builtin::BI__builtin_addcb:
case Builtin::BI__builtin_addcs:
@@ -14512,7 +14804,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
bool IsSigned = LHS.isSigned() || RHS.isSigned() ||
ResultType->isSignedIntegerOrEnumerationType();
bool AllSigned = LHS.isSigned() && RHS.isSigned() &&
- ResultType->isSignedIntegerOrEnumerationType();
+ ResultType->isSignedIntegerOrEnumerationType();
uint64_t LHSSize = LHS.getBitWidth();
uint64_t RHSSize = RHS.getBitWidth();
uint64_t ResultSize = Info.Ctx.getTypeSize(ResultType);
@@ -14901,7 +15193,7 @@ class DataRecursiveIntBinOpEvaluator {
public:
DataRecursiveIntBinOpEvaluator(IntExprEvaluator &IntEval, APValue &Result)
- : IntEval(IntEval), Info(IntEval.getEvalInfo()), FinalResult(Result) { }
+ : IntEval(IntEval), Info(IntEval.getEvalInfo()), FinalResult(Result) {}
/// True if \param E is a binary operator that we are going to handle
/// data recursively.
@@ -14920,7 +15212,8 @@ class DataRecursiveIntBinOpEvaluator {
while (!Queue.empty())
process(PrevResult);
- if (PrevResult.Failed) return false;
+ if (PrevResult.Failed)
+ return false;
FinalResult.swap(PrevResult.Val);
return true;
@@ -14933,12 +15226,8 @@ class DataRecursiveIntBinOpEvaluator {
bool Success(const APSInt &Value, const Expr *E, APValue &Result) {
return IntEval.Success(Value, E, Result);
}
- bool Error(const Expr *E) {
- return IntEval.Error(E);
- }
- bool Error(const Expr *E, diag::kind D) {
- return IntEval.Error(E, D);
- }
+ bool Error(const Expr *E) { return IntEval.Error(E); }
+ bool Error(const Expr *E, diag::kind D) { return IntEval.Error(E, D); }
OptionalDiagnostic CCEDiag(const Expr *E, diag::kind D) {
return Info.CCEDiag(E, D);
@@ -14961,17 +15250,17 @@ class DataRecursiveIntBinOpEvaluator {
void enqueue(const Expr *E) {
E = E->IgnoreParens();
- Queue.resize(Queue.size()+1);
+ Queue.resize(Queue.size() + 1);
Queue.back().E = E;
Queue.back().Kind = Job::AnyExprKind;
}
};
-}
+} // namespace
-bool DataRecursiveIntBinOpEvaluator::
- VisitBinOpLHSOnly(EvalResult &LHSResult, const BinaryOperator *E,
- bool &SuppressRHSDiags) {
+bool DataRecursiveIntBinOpEvaluator::VisitBinOpLHSOnly(EvalResult &LHSResult,
+ const BinaryOperator *E,
+ bool &SuppressRHSDiags) {
if (E->getOpcode() == BO_Comma) {
// Ignore LHS but note if we could not evaluate it.
if (LHSResult.Failed)
@@ -15023,13 +15312,14 @@ static void addOrSubLValueAsInteger(APValue &LVal, const APSInt &Index,
CharUnits &Offset = LVal.getLValueOffset();
uint64_t Offset64 = Offset.getQuantity();
uint64_t Index64 = Index.extOrTrunc(64).getZExtValue();
- Offset = CharUnits::fromQuantity(IsSub ? Offset64 - Index64
- : Offset64 + Index64);
+ Offset =
+ CharUnits::fromQuantity(IsSub ? Offset64 - Index64 : Offset64 + Index64);
}
-bool DataRecursiveIntBinOpEvaluator::
- VisitBinOp(const EvalResult &LHSResult, const EvalResult &RHSResult,
- const BinaryOperator *E, APValue &Result) {
+bool DataRecursiveIntBinOpEvaluator::VisitBinOp(const EvalResult &LHSResult,
+ const EvalResult &RHSResult,
+ const BinaryOperator *E,
+ APValue &Result) {
if (E->getOpcode() == BO_Comma) {
if (RHSResult.Failed)
return false;
@@ -15078,10 +15368,9 @@ bool DataRecursiveIntBinOpEvaluator::
}
// Handle cases like 4 + (unsigned long)&a
- if (E->getOpcode() == BO_Add &&
- RHSVal.isLValue() && LHSVal.isInt()) {
+ if (E->getOpcode() == BO_Add && RHSVal.isLValue() && LHSVal.isInt()) {
Result = RHSVal;
- addOrSubLValueAsInteger(Result, LHSVal.getInt(), /*IsSub*/false);
+ addOrSubLValueAsInteger(Result, LHSVal.getInt(), /*IsSub*/ false);
return true;
}
@@ -15090,8 +15379,8 @@ bool DataRecursiveIntBinOpEvaluator::
if (!LHSVal.getLValueOffset().isZero() ||
!RHSVal.getLValueOffset().isZero())
return false;
- const Expr *LHSExpr = LHSVal.getLValueBase().dyn_cast<const Expr*>();
- const Expr *RHSExpr = RHSVal.getLValueBase().dyn_cast<const Expr*>();
+ const Expr *LHSExpr = LHSVal.getLValueBase().dyn_cast<const Expr *>();
+ const Expr *RHSExpr = RHSVal.getLValueBase().dyn_cast<const Expr *>();
if (!LHSExpr || !RHSExpr)
return false;
const AddrLabelExpr *LHSAddrExpr = dyn_cast<AddrLabelExpr>(LHSExpr);
@@ -15125,43 +15414,43 @@ void DataRecursiveIntBinOpEvaluator::process(EvalResult &Result) {
Job &job = Queue.back();
switch (job.Kind) {
- case Job::AnyExprKind: {
- if (const BinaryOperator *Bop = dyn_cast<BinaryOperator>(job.E)) {
- if (shouldEnqueue(Bop)) {
- job.Kind = Job::BinOpKind;
- enqueue(Bop->getLHS());
- return;
- }
- }
-
- EvaluateExpr(job.E, Result);
- Queue.pop_back();
- return;
- }
-
- case Job::BinOpKind: {
- const BinaryOperator *Bop = cast<BinaryOperator>(job.E);
- bool SuppressRHSDiags = false;
- if (!VisitBinOpLHSOnly(Result, Bop, SuppressRHSDiags)) {
- Queue.pop_back();
+ case Job::AnyExprKind: {
+ if (const BinaryOperator *Bop = dyn_cast<BinaryOperator>(job.E)) {
+ if (shouldEnqueue(Bop)) {
+ job.Kind = Job::BinOpKind;
+ enqueue(Bop->getLHS());
return;
}
- if (SuppressRHSDiags)
- job.startSpeculativeEval(Info);
- job.LHSResult.swap(Result);
- job.Kind = Job::BinOpVisitedLHSKind;
- enqueue(Bop->getRHS());
- return;
}
- case Job::BinOpVisitedLHSKind: {
- const BinaryOperator *Bop = cast<BinaryOperator>(job.E);
- EvalResult RHS;
- RHS.swap(Result);
- Result.Failed = !VisitBinOp(job.LHSResult, RHS, Bop, Result.Val);
+ EvaluateExpr(job.E, Result);
+ Queue.pop_back();
+ return;
+ }
+
+ case Job::BinOpKind: {
+ const BinaryOperator *Bop = cast<BinaryOperator>(job.E);
+ bool SuppressRHSDiags = false;
+ if (!VisitBinOpLHSOnly(Result, Bop, SuppressRHSDiags)) {
Queue.pop_back();
return;
}
+ if (SuppressRHSDiags)
+ job.startSpeculativeEval(Info);
+ job.LHSResult.swap(Result);
+ job.Kind = Job::BinOpVisitedLHSKind;
+ enqueue(Bop->getRHS());
+ return;
+ }
+
+ case Job::BinOpVisitedLHSKind: {
+ const BinaryOperator *Bop = cast<BinaryOperator>(job.E);
+ EvalResult RHS;
+ RHS.swap(Result);
+ Result.Failed = !VisitBinOp(job.LHSResult, RHS, Bop, Result.Val);
+ Queue.pop_back();
+ return;
+ }
}
llvm_unreachable("Invalid Job::Kind!");
@@ -15257,9 +15546,9 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
if (LHS.isComplexFloat()) {
APFloat::cmpResult CR_r =
- LHS.getComplexFloatReal().compare(RHS.getComplexFloatReal());
+ LHS.getComplexFloatReal().compare(RHS.getComplexFloatReal());
APFloat::cmpResult CR_i =
- LHS.getComplexFloatImag().compare(RHS.getComplexFloatImag());
+ LHS.getComplexFloatImag().compare(RHS.getComplexFloatImag());
bool IsEqual = CR_r == APFloat::cmpEqual && CR_i == APFloat::cmpEqual;
return Success(IsEqual ? CmpResult::Equal : CmpResult::Unequal, E);
} else {
@@ -15270,8 +15559,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
}
}
- if (LHSTy->isRealFloatingType() &&
- RHSTy->isRealFloatingType()) {
+ if (LHSTy->isRealFloatingType() && RHSTy->isRealFloatingType()) {
APFloat RHS(0.0), LHS(0.0);
bool LHSOK = EvaluateFloat(E->getRHS(), RHS, Info);
@@ -15283,8 +15571,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
assert(E->isComparisonOp() && "Invalid binary operator!");
llvm::APFloatBase::cmpResult APFloatCmpResult = LHS.compare(RHS);
- if (!Info.InConstantContext &&
- APFloatCmpResult == APFloat::cmpUnordered &&
+ if (!Info.InConstantContext && APFloatCmpResult == APFloat::cmpUnordered &&
E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()).isFPConstrained()) {
// Note: Compares may raise invalid in some cases involving NaN or sNaN.
Info.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
@@ -15324,7 +15611,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
if (Info.checkingPotentialConstantExpression() &&
(LHSValue.AllowConstexprUnknown || RHSValue.AllowConstexprUnknown))
return false;
- auto DiagComparison = [&] (unsigned DiagID, bool Reversed = false) {
+ auto DiagComparison = [&](unsigned DiagID, bool Reversed = false) {
std::string LHS = LHSValue.toString(Info.Ctx, E->getLHS()->getType());
std::string RHS = RHSValue.toString(Info.Ctx, E->getRHS()->getType());
Info.FFDiag(E, DiagID)
@@ -15373,7 +15660,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
return DiagComparison(diag::note_constexpr_pointer_comparison_past_end,
true);
if (RHSValue.Base && RHSValue.Offset.isZero() &&
- isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue))
+ isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue))
return DiagComparison(diag::note_constexpr_pointer_comparison_past_end,
false);
// We can't tell whether an object is at the same address as another
@@ -15602,8 +15889,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
auto OnSuccess = [&](CmpResult CR, const BinaryOperator *E) {
assert((CR != CmpResult::Unequal || E->isEqualityOp()) &&
"should only produce Unequal for equality comparisons");
- bool IsEqual = CR == CmpResult::Equal,
- IsLess = CR == CmpResult::Less,
+ bool IsEqual = CR == CmpResult::Equal, IsLess = CR == CmpResult::Less,
IsGreater = CR == CmpResult::Greater;
auto Op = E->getOpcode();
switch (Op) {
@@ -15736,8 +16022,8 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
/// VisitUnaryExprOrTypeTraitExpr - Evaluate a sizeof, alignof or vec_step with
/// a result as the expression's type.
bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
- const UnaryExprOrTypeTraitExpr *E) {
- switch(E->getKind()) {
+ const UnaryExprOrTypeTraitExpr *E) {
+ switch (E->getKind()) {
case UETT_PreferredAlignOf:
case UETT_AlignOf: {
if (E->isArgumentType())
@@ -15788,11 +16074,11 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
}
case UETT_OpenMPRequiredSimdAlign:
assert(E->isArgumentType());
- return Success(
- Info.Ctx.toCharUnitsFromBits(
- Info.Ctx.getOpenMPDefaultSimdAlign(E->getArgumentType()))
- .getQuantity(),
- E);
+ return Success(Info.Ctx
+ .toCharUnitsFromBits(Info.Ctx.getOpenMPDefaultSimdAlign(
+ E->getArgumentType()))
+ .getQuantity(),
+ E);
case UETT_VectorElements: {
QualType Ty = E->getTypeOfArgument();
// If the vector has a fixed size, we can determine the number of elements
@@ -15883,7 +16169,8 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) {
const auto *RD = CurrentType->getAsRecordDecl();
if (!RD)
return Error(OOE);
- if (RD->isInvalidDecl()) return false;
+ if (RD->isInvalidDecl())
+ return false;
const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
unsigned i = MemberDecl->getFieldIndex();
assert(i < RL.getFieldCount() && "offsetof field in wrong type");
@@ -15904,7 +16191,8 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) {
const auto *RD = CurrentType->getAsCXXRecordDecl();
if (!RD)
return Error(OOE);
- if (RD->isInvalidDecl()) return false;
+ if (RD->isInvalidDecl())
+ return false;
const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
// Find the base class itself.
@@ -15938,7 +16226,8 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
case UO_Minus: {
if (!Visit(E->getSubExpr()))
return false;
- if (!Result.isInt()) return Error(E);
+ if (!Result.isInt())
+ return Error(E);
const APSInt &Value = Result.getInt();
if (Value.isSigned() && Value.isMinSignedValue() && E->canOverflow()) {
if (Info.checkingForUndefinedBehavior())
@@ -15957,7 +16246,8 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
case UO_Not: {
if (!Visit(E->getSubExpr()))
return false;
- if (!Result.isInt()) return Error(E);
+ if (!Result.isInt())
+ return Error(E);
return Success(~Result.getInt(), E);
}
case UO_LNot: {
@@ -16124,8 +16414,8 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
}
}
- return Success(HandleIntToIntCast(Info, E, DestType, SrcType,
- Result.getInt()), E);
+ return Success(
+ HandleIntToIntCast(Info, E, DestType, SrcType, Result.getInt()), E);
}
case CK_PointerToIntegral: {
@@ -16223,7 +16513,7 @@ bool IntExprEvaluator::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) {
}
bool IntExprEvaluator::VisitConceptSpecializationExpr(
- const ConceptSpecializationExpr *E) {
+ const ConceptSpecializationExpr *E) {
return Success(E->isSatisfied(), E);
}
@@ -16233,28 +16523,29 @@ bool IntExprEvaluator::VisitRequiresExpr(const RequiresExpr *E) {
bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
switch (E->getOpcode()) {
- default:
- // Invalid unary operators
+ default:
+ // Invalid unary operators
+ return Error(E);
+ case UO_Plus:
+ // The result is just the value.
+ return Visit(E->getSubExpr());
+ case UO_Minus: {
+ if (!Visit(E->getSubExpr()))
+ return false;
+ if (!Result.isFixedPoint())
return Error(E);
- case UO_Plus:
- // The result is just the value.
- return Visit(E->getSubExpr());
- case UO_Minus: {
- if (!Visit(E->getSubExpr())) return false;
- if (!Result.isFixedPoint())
- return Error(E);
- bool Overflowed;
- APFixedPoint Negated = Result.getFixedPoint().negate(&Overflowed);
- if (Overflowed && !HandleOverflow(Info, E, Negated, E->getType()))
- return false;
- return Success(Negated, E);
- }
- case UO_LNot: {
- bool bres;
- if (!EvaluateAsBooleanCondition(E->getSubExpr(), bres, Info))
- return false;
- return Success(!bres, E);
- }
+ bool Overflowed;
+ APFixedPoint Negated = Result.getFixedPoint().negate(&Overflowed);
+ if (Overflowed && !HandleOverflow(Info, E, Negated, E->getType()))
+ return false;
+ return Success(Negated, E);
+ }
+ case UO_LNot: {
+ bool bres;
+ if (!EvaluateAsBooleanCondition(E->getSubExpr(), bres, Info))
+ return false;
+ return Success(!bres, E);
+ }
}
}
@@ -16274,9 +16565,9 @@ bool FixedPointExprEvaluator::VisitCastExpr(const CastExpr *E) {
APFixedPoint Result = Src.convert(DestFXSema, &Overflowed);
if (Overflowed) {
if (Info.checkingForUndefinedBehavior())
- Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
- diag::warn_fixedpoint_constant_overflow)
- << Result.toString() << E->getType();
+ Info.Ctx.getDiagnostics().Report(
+ E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
+ << Result.toString() << E->getType();
if (!HandleOverflow(Info, E, Result, E->getType()))
return false;
}
@@ -16293,9 +16584,9 @@ bool FixedPointExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (Overflowed) {
if (Info.checkingForUndefinedBehavior())
- Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
- diag::warn_fixedpoint_constant_overflow)
- << IntResult.toString() << E->getType();
+ Info.Ctx.getDiagnostics().Report(
+ E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
+ << IntResult.toString() << E->getType();
if (!HandleOverflow(Info, E, IntResult, E->getType()))
return false;
}
@@ -16313,9 +16604,9 @@ bool FixedPointExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (Overflowed) {
if (Info.checkingForUndefinedBehavior())
- Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
- diag::warn_fixedpoint_constant_overflow)
- << Result.toString() << E->getType();
+ Info.Ctx.getDiagnostics().Report(
+ E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
+ << Result.toString() << E->getType();
if (!HandleOverflow(Info, E, Result, E->getType()))
return false;
}
@@ -16351,17 +16642,17 @@ bool FixedPointExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
switch (E->getOpcode()) {
case BO_Add: {
Result = LHSFX.add(RHSFX, &OpOverflow)
- .convert(ResultFXSema, &ConversionOverflow);
+ .convert(ResultFXSema, &ConversionOverflow);
break;
}
case BO_Sub: {
Result = LHSFX.sub(RHSFX, &OpOverflow)
- .convert(ResultFXSema, &ConversionOverflow);
+ .convert(ResultFXSema, &ConversionOverflow);
break;
}
case BO_Mul: {
Result = LHSFX.mul(RHSFX, &OpOverflow)
- .convert(ResultFXSema, &ConversionOverflow);
+ .convert(ResultFXSema, &ConversionOverflow);
break;
}
case BO_Div: {
@@ -16370,7 +16661,7 @@ bool FixedPointExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
return false;
}
Result = LHSFX.div(RHSFX, &OpOverflow)
- .convert(ResultFXSema, &ConversionOverflow);
+ .convert(ResultFXSema, &ConversionOverflow);
break;
}
case BO_Shl:
@@ -16403,7 +16694,7 @@ bool FixedPointExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (Info.checkingForUndefinedBehavior())
Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
diag::warn_fixedpoint_constant_overflow)
- << Result.toString() << E->getType();
+ << Result.toString() << E->getType();
if (!HandleOverflow(Info, E, Result, E->getType()))
return false;
}
@@ -16415,12 +16706,12 @@ bool FixedPointExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
//===----------------------------------------------------------------------===//
namespace {
-class FloatExprEvaluator
- : public ExprEvaluatorBase<FloatExprEvaluator> {
+class FloatExprEvaluator : public ExprEvaluatorBase<FloatExprEvaluator> {
APFloat &Result;
+
public:
FloatExprEvaluator(EvalInfo &info, APFloat &result)
- : ExprEvaluatorBaseTy(info), Result(result) {}
+ : ExprEvaluatorBaseTy(info), Result(result) {}
bool Success(const APValue &V, const Expr *e) {
Result = V.getFloat();
@@ -16446,19 +16737,18 @@ class FloatExprEvaluator
};
} // end anonymous namespace
-static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) {
+static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info) {
assert(!E->isValueDependent());
assert(E->isPRValue() && E->getType()->isRealFloatingType());
return FloatExprEvaluator(Info, Result).Visit(E);
}
-static bool TryEvaluateBuiltinNaN(const ASTContext &Context,
- QualType ResultTy,
- const Expr *Arg,
- bool SNaN,
+static bool TryEvaluateBuiltinNaN(const ASTContext &Context, QualType ResultTy,
+ const Expr *Arg, bool SNaN,
llvm::APFloat &Result) {
const StringLiteral *S = dyn_cast<StringLiteral>(Arg->IgnoreParenCasts());
- if (!S) return false;
+ if (!S)
+ return false;
const llvm::fltSemantics &Sem = Context.getFloatTypeSemantics(ResultTy);
@@ -16509,7 +16799,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_inff16:
case Builtin::BI__builtin_inff128: {
const llvm::fltSemantics &Sem =
- Info.Ctx.getFloatTypeSemantics(E->getType());
+ Info.Ctx.getFloatTypeSemantics(E->getType());
Result = llvm::APFloat::getInf(Sem);
return true;
}
@@ -16519,8 +16809,8 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_nansl:
case Builtin::BI__builtin_nansf16:
case Builtin::BI__builtin_nansf128:
- if (!TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0),
- true, Result))
+ if (!TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0), true,
+ Result))
return Error(E);
return true;
@@ -16531,8 +16821,8 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_nanf128:
// If this is __builtin_nan() turn this into a nan, otherwise we
// can't constant fold it.
- if (!TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0),
- false, Result))
+ if (!TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0), false,
+ Result))
return Error(E);
return true;
@@ -16556,9 +16846,9 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__arithmetic_fence:
return EvaluateFloat(E->getArg(0), Result, Info);
- // FIXME: Builtin::BI__builtin_powi
- // FIXME: Builtin::BI__builtin_powif
- // FIXME: Builtin::BI__builtin_powil
+ // FIXME: Builtin::BI__builtin_powi
+ // FIXME: Builtin::BI__builtin_powif
+ // FIXME: Builtin::BI__builtin_powil
case Builtin::BI__builtin_copysign:
case Builtin::BI__builtin_copysignf:
@@ -16670,7 +16960,8 @@ bool FloatExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
switch (E->getOpcode()) {
- default: return Error(E);
+ default:
+ return Error(E);
case UO_Plus:
return EvaluateFloat(E->getSubExpr(), Result, Info);
case UO_Minus:
@@ -16702,7 +16993,7 @@ bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) {
}
bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
- const Expr* SubExpr = E->getSubExpr();
+ const Expr *SubExpr = E->getSubExpr();
switch (E->getCastKind()) {
default:
@@ -16710,11 +17001,10 @@ bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_IntegralToFloating: {
APSInt IntResult;
- const FPOptions FPO = E->getFPFeaturesInEffect(
- Info.Ctx.getLangOpts());
+ const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts());
return EvaluateInteger(SubExpr, IntResult, Info) &&
- HandleIntToFloatCast(Info, E, FPO, SubExpr->getType(),
- IntResult, E->getType(), Result);
+ HandleIntToFloatCast(Info, E, FPO, SubExpr->getType(), IntResult,
+ E->getType(), Result);
}
case CK_FixedPointToFloating: {
@@ -16754,13 +17044,12 @@ bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
//===----------------------------------------------------------------------===//
namespace {
-class ComplexExprEvaluator
- : public ExprEvaluatorBase<ComplexExprEvaluator> {
+class ComplexExprEvaluator : public ExprEvaluatorBase<ComplexExprEvaluator> {
ComplexValue &Result;
public:
ComplexExprEvaluator(EvalInfo &info, ComplexValue &Result)
- : ExprEvaluatorBaseTy(info), Result(Result) {}
+ : ExprEvaluatorBaseTy(info), Result(Result) {}
bool Success(const APValue &V, const Expr *e) {
Result.setFrom(V);
@@ -16806,7 +17095,7 @@ bool ComplexExprEvaluator::ZeroInitialization(const Expr *E) {
}
bool ComplexExprEvaluator::VisitImaginaryLiteral(const ImaginaryLiteral *E) {
- const Expr* SubExpr = E->getSubExpr();
+ const Expr *SubExpr = E->getSubExpr();
if (SubExpr->getType()->isRealFloatingType()) {
Result.makeComplexFloat();
@@ -16917,8 +17206,8 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
return false;
QualType To = E->getType()->castAs<ComplexType>()->getElementType();
- QualType From
- = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
+ QualType From =
+ E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
return HandleFloatToFloatCast(Info, E, From, To, Result.FloatReal) &&
HandleFloatToFloatCast(Info, E, From, To, Result.FloatImag);
@@ -16929,13 +17218,13 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
return false;
QualType To = E->getType()->castAs<ComplexType>()->getElementType();
- QualType From
- = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
+ QualType From =
+ E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
Result.makeComplexInt();
- return HandleFloatToIntCast(Info, E, From, Result.FloatReal,
- To, Result.IntReal) &&
- HandleFloatToIntCast(Info, E, From, Result.FloatImag,
- To, Result.IntImag);
+ return HandleFloatToIntCast(Info, E, From, Result.FloatReal, To,
+ Result.IntReal) &&
+ HandleFloatToIntCast(Info, E, From, Result.FloatImag, To,
+ Result.IntImag);
}
case CK_IntegralRealToComplex: {
@@ -16953,8 +17242,8 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
return false;
QualType To = E->getType()->castAs<ComplexType>()->getElementType();
- QualType From
- = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
+ QualType From =
+ E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
Result.IntReal = HandleIntToIntCast(Info, E, To, From, Result.IntReal);
Result.IntImag = HandleIntToIntCast(Info, E, To, From, Result.IntImag);
@@ -16965,16 +17254,15 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (!Visit(E->getSubExpr()))
return false;
- const FPOptions FPO = E->getFPFeaturesInEffect(
- Info.Ctx.getLangOpts());
+ const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts());
QualType To = E->getType()->castAs<ComplexType>()->getElementType();
- QualType From
- = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
+ QualType From =
+ E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
Result.makeComplexFloat();
- return HandleIntToFloatCast(Info, E, FPO, From, Result.IntReal,
- To, Result.FloatReal) &&
- HandleIntToFloatCast(Info, E, FPO, From, Result.IntImag,
- To, Result.FloatImag);
+ return HandleIntToFloatCast(Info, E, FPO, From, Result.IntReal, To,
+ Result.FloatReal) &&
+ HandleIntToFloatCast(Info, E, FPO, From, Result.IntImag, To,
+ Result.FloatImag);
}
}
@@ -17116,7 +17404,8 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
assert(!(LHSReal && RHSReal) &&
"Cannot have both operands of a complex operation be real.");
switch (E->getOpcode()) {
- default: return Error(E);
+ default:
+ return Error(E);
case BO_Add:
if (Result.isComplexFloat()) {
Result.getComplexFloatReal().add(RHS.getComplexFloatReal(),
@@ -17183,11 +17472,11 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
} else {
ComplexValue LHS = Result;
Result.getComplexIntReal() =
- (LHS.getComplexIntReal() * RHS.getComplexIntReal() -
- LHS.getComplexIntImag() * RHS.getComplexIntImag());
+ (LHS.getComplexIntReal() * RHS.getComplexIntReal() -
+ LHS.getComplexIntImag() * RHS.getComplexIntImag());
Result.getComplexIntImag() =
- (LHS.getComplexIntReal() * RHS.getComplexIntImag() +
- LHS.getComplexIntImag() * RHS.getComplexIntReal());
+ (LHS.getComplexIntReal() * RHS.getComplexIntImag() +
+ LHS.getComplexIntImag() * RHS.getComplexIntReal());
}
break;
case BO_Div:
@@ -17221,16 +17510,18 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
} else {
ComplexValue LHS = Result;
APSInt Den = RHS.getComplexIntReal() * RHS.getComplexIntReal() +
- RHS.getComplexIntImag() * RHS.getComplexIntImag();
+ RHS.getComplexIntImag() * RHS.getComplexIntImag();
if (Den.isZero())
return Error(E, diag::note_expr_divide_by_zero);
Result.getComplexIntReal() =
- (LHS.getComplexIntReal() * RHS.getComplexIntReal() +
- LHS.getComplexIntImag() * RHS.getComplexIntImag()) / Den;
+ (LHS.getComplexIntReal() * RHS.getComplexIntReal() +
+ LHS.getComplexIntImag() * RHS.getComplexIntImag()) /
+ Den;
Result.getComplexIntImag() =
- (LHS.getComplexIntImag() * RHS.getComplexIntReal() -
- LHS.getComplexIntReal() * RHS.getComplexIntImag()) / Den;
+ (LHS.getComplexIntImag() * RHS.getComplexIntReal() -
+ LHS.getComplexIntReal() * RHS.getComplexIntImag()) /
+ Den;
}
break;
}
@@ -17255,8 +17546,7 @@ bool ComplexExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
if (Result.isComplexFloat()) {
Result.getComplexFloatReal().changeSign();
Result.getComplexFloatImag().changeSign();
- }
- else {
+ } else {
Result.getComplexIntReal() = -Result.getComplexIntReal();
Result.getComplexIntImag() = -Result.getComplexIntImag();
}
@@ -17314,10 +17604,10 @@ bool ComplexExprEvaluator::VisitCallExpr(const CallExpr *E) {
//===----------------------------------------------------------------------===//
namespace {
-class AtomicExprEvaluator :
- public ExprEvaluatorBase<AtomicExprEvaluator> {
+class AtomicExprEvaluator : public ExprEvaluatorBase<AtomicExprEvaluator> {
const LValue *This;
APValue &Result;
+
public:
AtomicExprEvaluator(EvalInfo &Info, const LValue *This, APValue &Result)
: ExprEvaluatorBaseTy(Info), This(This), Result(Result) {}
@@ -17364,8 +17654,7 @@ static bool EvaluateAtomic(const Expr *E, const LValue *This, APValue &Result,
//===----------------------------------------------------------------------===//
namespace {
-class VoidExprEvaluator
- : public ExprEvaluatorBase<VoidExprEvaluator> {
+class VoidExprEvaluator : public ExprEvaluatorBase<VoidExprEvaluator> {
public:
VoidExprEvaluator(EvalInfo &Info) : ExprEvaluatorBaseTy(Info) {}
@@ -17522,7 +17811,8 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
return false;
C.moveInto(Result);
} else if (T->isFixedPointType()) {
- if (!FixedPointExprEvaluator(Info, Result).Visit(E)) return false;
+ if (!FixedPointExprEvaluator(Info, Result).Visit(E))
+ return false;
} else if (T->isMemberPointerType()) {
MemberPtr P;
if (!EvaluateMemberPointer(E, P, Info))
@@ -17545,8 +17835,7 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
Result = Value;
} else if (T->isVoidType()) {
if (!Info.getLangOpts().CPlusPlus11)
- Info.CCEDiag(E, diag::note_constexpr_nonliteral)
- << E->getType();
+ Info.CCEDiag(E, diag::note_constexpr_nonliteral) << E->getType();
if (!EvaluateVoid(E, Info))
return false;
} else if (T->isAtomicType()) {
@@ -17899,7 +18188,7 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx,
// If we're evaluating a prvalue, fake up a MaterializeTemporaryExpr to
// represent the result of the evaluation. CheckConstantExpression ensures
// this doesn't escape.
- MaterializeTemporaryExpr BaseMTE(T, const_cast<Expr*>(this), true);
+ MaterializeTemporaryExpr BaseMTE(T, const_cast<Expr *>(this), true);
APValue::LValueBase Base(&BaseMTE);
Info.setEvaluatingDecl(Base, Result.Val);
@@ -18136,13 +18425,13 @@ struct ICEDiag {
ICEDiag(ICEKind IK, SourceLocation l) : Kind(IK), Loc(l) {}
};
-}
+} // namespace
static ICEDiag NoDiag() { return ICEDiag(IK_ICE, SourceLocation()); }
static ICEDiag Worst(ICEDiag A, ICEDiag B) { return A.Kind >= B.Kind ? A : B; }
-static ICEDiag CheckEvalInICE(const Expr* E, const ASTContext &Ctx) {
+static ICEDiag CheckEvalInICE(const Expr *E, const ASTContext &Ctx) {
Expr::EvalResult EVResult;
Expr::EvalStatus Status;
EvalInfo Info(Ctx, Status, EvaluationMode::ConstantExpression);
@@ -18155,7 +18444,7 @@ static ICEDiag CheckEvalInICE(const Expr* E, const ASTContext &Ctx) {
return NoDiag();
}
-static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
+static ICEDiag CheckICE(const Expr *E, const ASTContext &Ctx) {
assert(!E->isValueDependent() && "Should not see value dependent exprs!");
if (!E->getType()->isIntegralOrEnumerationType())
return ICEDiag(IK_NotICE, E->getBeginLoc());
@@ -18273,8 +18562,8 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
return CheckICE(cast<PackIndexingExpr>(E)->getSelectedExpr(), Ctx);
case Expr::SubstNonTypeTemplateParmExprClass:
- return
- CheckICE(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(), Ctx);
+ return CheckICE(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(),
+ Ctx);
case Expr::ConstantExprClass:
return CheckICE(cast<ConstantExpr>(E)->getSubExpr(), Ctx);
@@ -18366,7 +18655,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
}
case Expr::UnaryExprOrTypeTraitExprClass: {
const UnaryExprOrTypeTraitExpr *Exp = cast<UnaryExprOrTypeTraitExpr>(E);
- if ((Exp->getKind() == UETT_SizeOf) &&
+ if ((Exp->getKind() == UETT_SizeOf) &&
Exp->getTypeOfArgument()->isVariableArrayType())
return ICEDiag(IK_NotICE, E->getBeginLoc());
if (Exp->getKind() == UETT_CountOf) {
@@ -18429,8 +18718,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case BO_Cmp: {
ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx);
ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx);
- if (Exp->getOpcode() == BO_Div ||
- Exp->getOpcode() == BO_Rem) {
+ if (Exp->getOpcode() == BO_Div || Exp->getOpcode() == BO_Rem) {
// EvaluateAsRValue gives an error for undefined Div/Rem, so make sure
// we don't evaluate one.
if (LHSResult.Kind == IK_ICE && RHSResult.Kind == IK_ICE) {
@@ -18485,8 +18773,8 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::ObjCBridgedCastExprClass: {
const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr();
if (isa<ExplicitCastExpr>(E)) {
- if (const FloatingLiteral *FL
- = dyn_cast<FloatingLiteral>(SubExpr->IgnoreParenImpCasts())) {
+ if (const FloatingLiteral *FL =
+ dyn_cast<FloatingLiteral>(SubExpr->IgnoreParenImpCasts())) {
unsigned DestWidth = Ctx.getIntWidth(E->getType());
bool DestSigned = E->getType()->isSignedIntegerOrEnumerationType();
APSInt IgnoredVal(DestWidth, !DestSigned);
@@ -18494,9 +18782,9 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
// If the value does not fit in the destination type, the behavior is
// undefined, so we are not required to treat it as a constant
// expression.
- if (FL->getValue().convertToInteger(IgnoredVal,
- llvm::APFloat::rmTowardZero,
- &Ignored) & APFloat::opInvalidOp)
+ if (FL->getValue().convertToInteger(
+ IgnoredVal, llvm::APFloat::rmTowardZero, &Ignored) &
+ APFloat::opInvalidOp)
return ICEDiag(IK_NotICE, E->getBeginLoc());
return NoDiag();
}
@@ -18516,12 +18804,16 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::BinaryConditionalOperatorClass: {
const BinaryConditionalOperator *Exp = cast<BinaryConditionalOperator>(E);
ICEDiag CommonResult = CheckICE(Exp->getCommon(), Ctx);
- if (CommonResult.Kind == IK_NotICE) return CommonResult;
+ if (CommonResult.Kind == IK_NotICE)
+ return CommonResult;
ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
- if (FalseResult.Kind == IK_NotICE) return FalseResult;
- if (CommonResult.Kind == IK_ICEIfUnevaluated) return CommonResult;
+ if (FalseResult.Kind == IK_NotICE)
+ return FalseResult;
+ if (CommonResult.Kind == IK_ICEIfUnevaluated)
+ return CommonResult;
if (FalseResult.Kind == IK_ICEIfUnevaluated &&
- Exp->getCommon()->EvaluateKnownConstInt(Ctx) != 0) return NoDiag();
+ Exp->getCommon()->EvaluateKnownConstInt(Ctx) != 0)
+ return NoDiag();
return FalseResult;
}
case Expr::ConditionalOperatorClass: {
@@ -18530,8 +18822,8 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
// then only the true side is actually considered in an integer constant
// expression, and it is fully evaluated. This is an important GNU
// extension. See GCC PR38377 for discussion.
- if (const CallExpr *CallCE
- = dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts()))
+ if (const CallExpr *CallCE =
+ dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts()))
if (CallCE->getBuiltinCallee() == Builtin::BI__builtin_constant_p)
return CheckEvalInICE(E, Ctx);
ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx);
@@ -18587,7 +18879,8 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx,
if (!Result.isInt())
return false;
- if (Value) *Value = Result.getInt();
+ if (Value)
+ *Value = Result.getInt();
return true;
}
@@ -18678,7 +18971,7 @@ bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result) const {
bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
const FunctionDecl *Callee,
- ArrayRef<const Expr*> Args,
+ ArrayRef<const Expr *> Args,
const Expr *This) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
@@ -18715,14 +19008,13 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
}
CallRef Call = Info.CurrentCall->createCall(Callee);
- for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
+ for (ArrayRef<const Expr *>::iterator I = Args.begin(), E = Args.end();
I != E; ++I) {
unsigned Idx = I - Args.begin();
if (Idx >= Callee->getNumParams())
break;
const ParmVarDecl *PVD = Callee->getParamDecl(Idx);
- if ((*I)->isValueDependent() ||
- !EvaluateCallArg(PVD, *I, Call, Info) ||
+ if ((*I)->isValueDependent() || !EvaluateCallArg(PVD, *I, Call, Info) ||
Info.EvalStatus.HasSideEffects) {
// If evaluation fails, throw away the argument entirely.
if (APValue *Slot = Info.getParamSlot(Call, PVD))
@@ -18748,9 +19040,8 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
!Info.EvalStatus.HasSideEffects;
}
-bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
- SmallVectorImpl<
- PartialDiagnosticAt> &Diags) {
+bool Expr::isPotentialConstantExpr(
+ const FunctionDecl *FD, SmallVectorImpl<PartialDiagnosticAt> &Diags) {
// FIXME: It would be useful to check constexpr function templates, but at the
// moment the constant expression evaluator cannot cope with the non-rigorous
// ASTs which we build for dependent expressions.
@@ -18789,7 +19080,7 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
: Info.Ctx.IntTy);
This.set({&VIE, Info.CurrentCall->Index});
- ArrayRef<const Expr*> Args;
+ ArrayRef<const Expr *> Args;
APValue Scratch;
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
@@ -18808,10 +19099,9 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
return Diags.empty();
}
-bool Expr::isPotentialConstantExprUnevaluated(Expr *E,
- const FunctionDecl *FD,
- SmallVectorImpl<
- PartialDiagnosticAt> &Diags) {
+bool Expr::isPotentialConstantExprUnevaluated(
+ Expr *E, const FunctionDecl *FD,
+ SmallVectorImpl<PartialDiagnosticAt> &Diags) {
assert(!E->isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
diff --git a/clang/lib/Headers/mmintrin.h b/clang/lib/Headers/mmintrin.h
index 5f617530b6f78..f031f83011424 100644
--- a/clang/lib/Headers/mmintrin.h
+++ b/clang/lib/Headers/mmintrin.h
@@ -43,10 +43,15 @@ typedef char __v16qi __attribute__((__vector_size__(16)));
__attribute__((__always_inline__, __nodebug__, __target__("sse2"), \
__min_vector_width__(128)))
+#define __DEFAULT_FN_ATTRS_MMX \
+ __attribute__((__always_inline__, __nodebug__, __target__("mmx")))
+
#if defined(__cplusplus) && (__cplusplus >= 201103L)
#define __DEFAULT_FN_ATTRS_SSE2_CONSTEXPR __DEFAULT_FN_ATTRS_SSE2 constexpr
+#define __DEFAULT_FN_ATTRS_MMX_CONSTEXPR __DEFAULT_FN_ATTRS_MMX constexpr
#else
#define __DEFAULT_FN_ATTRS_SSE2_CONSTEXPR __DEFAULT_FN_ATTRS_SSE2
+#define __DEFAULT_FN_ATTRS_MMX_CONSTEXPR __DEFAULT_FN_ATTRS_MMX
#endif
#define __trunc64(x) \
diff --git a/clang/test/CodeGen/X86/avx2-builtins.c b/clang/test/CodeGen/X86/avx2-builtins.c
index eff2797e87c75..e5e78257fe534 100644
--- a/clang/test/CodeGen/X86/avx2-builtins.c
+++ b/clang/test/CodeGen/X86/avx2-builtins.c
@@ -1122,6 +1122,10 @@ __m256i test_mm256_shufflelo_epi16(__m256i a) {
return _mm256_shufflelo_epi16(a, 83);
}
+TEST_CONSTEXPR(match_v8si(_mm256_shuffle_epi32((((__m256i)(__v8si){0,1,2,3,4,5,6,7})), 15), 3,3,0,0, 7,7,4,4));
+TEST_CONSTEXPR(match_v16hi(_mm256_shufflehi_epi16((((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15})), 107), 0,1,2,3, 7,6,6,5, 8,9,10,11, 15,14,14,13));
+TEST_CONSTEXPR(match_v16hi(_mm256_shufflelo_epi16(((__m256i)(__v16hi){ 0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15}), 83), 3,0,1,1, 4,5,6,7, 11,8,9,9, 12,13,14,15) );
+
__m256i test_mm256_sign_epi8(__m256i a, __m256i b) {
// CHECK-LABEL: test_mm256_sign_epi8
// CHECK: call <32 x i8> @llvm.x86.avx2.psign.b(<32 x i8> %{{.*}}, <32 x i8> %{{.*}})
diff --git a/clang/test/CodeGen/X86/avx512bw-builtins.c b/clang/test/CodeGen/X86/avx512bw-builtins.c
index 3f42ac0268978..69df9b5d73302 100644
--- a/clang/test/CodeGen/X86/avx512bw-builtins.c
+++ b/clang/test/CodeGen/X86/avx512bw-builtins.c
@@ -1890,7 +1890,6 @@ __m512i test_mm512_maskz_shufflehi_epi16(__mmask32 __U, __m512i __A) {
// CHECK: select <32 x i1> %{{.*}}, <32 x i16> %{{.*}}, <32 x i16> %{{.*}}
return _mm512_maskz_shufflehi_epi16(__U, __A, 5);
}
-
__m512i test_mm512_shufflelo_epi16(__m512i __A) {
// CHECK-LABEL: test_mm512_shufflelo_epi16
// CHECK: shufflevector <32 x i16> %{{.*}}, <32 x i16> poison, <32 x i32> <i32 1, i32 1, i32 0, i32 0, i32 4, i32 5, i32 6, i32 7, i32 9, i32 9, i32 8, i32 8, i32 12, i32 13, i32 14, i32 15, i32 17, i32 17, i32 16, i32 16, i32 20, i32 21, i32 22, i32 23, i32 25, i32 25, i32 24, i32 24, i32 28, i32 29, i32 30, i32 31>
@@ -1911,6 +1910,16 @@ __m512i test_mm512_maskz_shufflelo_epi16(__mmask32 __U, __m512i __A) {
return _mm512_maskz_shufflelo_epi16(__U, __A, 5);
}
+//_mm512_shufflehi_epi16 , _mm512_mask_shufflehi_epi16 , _mm512_maskz_shufflehi_epi16
+TEST_CONSTEXPR(match_v32hi(_mm512_shufflehi_epi16((((__m512i)(__v32hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31})), 5), 0,1,2,3, 5,5,4,4, 8,9,10,11, 13,13,12,12, 16,17,18,19, 21,21,20,20, 24,25,26,27, 29,29,28,28));
+TEST_CONSTEXPR(match_v32hi(_mm512_mask_shufflehi_epi16((((__m512i)(__v32hi){100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131})), 0xFFFF0000u, (((__m512i)(__v32hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31})), 5), 100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115, 16,17,18,19,21,21,20,20, 24,25,26,27,29,29,28,28));
+TEST_CONSTEXPR(match_v32hi(_mm512_maskz_shufflehi_epi16(0xAAAAAAAAu, (((__m512i)(__v32hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31})), 5), 0,1,0,3,0,5,0,4, 0,9,0,11,0,13,0,12, 0,17,0,19,0,21,0,20, 0,25,0,27,0,29,0,28));
+
+// _mm512_shufflelo_epi16, _mm512_mask_shufflelo_epi16, _mm512_maskz_shufflelo_epi16
+TEST_CONSTEXPR( match_v32hi(_mm512_shufflelo_epi16(((__m512i)(__v32hi){ 0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15, 16,17,18,19, 20,21,22,23, 24,25,26,27, 28,29,30,31}), 5), 1,1,0,0, 4,5,6,7, 9,9,8,8, 12,13,14,15, 17,17,16,16, 20,21,22,23, 25,25,24,24, 28,29,30,31));
+TEST_CONSTEXPR(match_v32hi(_mm512_mask_shufflelo_epi16((((__m512i)(__v32hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31})), 0xFFFFFFFF, (((__m512i)(__v32hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31})), 5), 1,1,0,0, 4,5,6,7, 9,9,8,8, 12,13,14,15, 17,17,16,16, 20,21,22,23, 25,25,24,24, 28,29,30,31));
+TEST_CONSTEXPR(match_v32hi(_mm512_maskz_shufflelo_epi16(0xFFFFFFFF, (((__m512i)(__v32hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31})), 5), 1,1,0,0, 4,5,6,7, 9,9,8,8, 12,13,14,15, 17,17,16,16, 20,21,22,23, 25,25,24,24, 28,29,30,31));
+
__m512i test_mm512_sllv_epi16(__m512i __A, __m512i __B) {
// CHECK-LABEL: test_mm512_sllv_epi16
// CHECK: @llvm.x86.avx512.psllv.w.512(
diff --git a/clang/test/CodeGen/X86/avx512f-builtins.c b/clang/test/CodeGen/X86/avx512f-builtins.c
index 84eaad8d99e61..90330970a3e1c 100644
--- a/clang/test/CodeGen/X86/avx512f-builtins.c
+++ b/clang/test/CodeGen/X86/avx512f-builtins.c
@@ -9088,6 +9088,19 @@ __m512i test_mm512_maskz_shuffle_epi32(__mmask16 __U, __m512i __A) {
return _mm512_maskz_shuffle_epi32(__U, __A, 1);
}
+// _mm512_shuffle_epi32
+TEST_CONSTEXPR(match_v16si(_mm512_shuffle_epi32((((__m512i)(__v16si){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15})), 1), 1,0,0,0, 5,4,4,4, 9,8,8,8, 13,12,12,12));
+
+// _mm512_mask_shuffle_epi32
+TEST_CONSTEXPR(match_v16si(_mm512_mask_shuffle_epi32(((__m512i)(__v16si){100,101,102,103,104,105,106,107,200,201,202,203,204,205,206,207}), 0xFFFFu, ((__m512i)(__v16si){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}), 1), 1,0,0,0, 5,4,4,4, 9,8,8,8, 13,12,12,12));
+TEST_CONSTEXPR(match_v16si(_mm512_mask_shuffle_epi32(((__m512i)(__v16si){100,101,102,103,104,105,106,107,200,201,202,203,204,205,206,207}), 0x0000u, ((__m512i)(__v16si){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}), 1), 100,101,102,103,104,105,106,107,200,201,202,203,204,205,206,207));
+TEST_CONSTEXPR(match_v16si(_mm512_mask_shuffle_epi32(((__m512i)(__v16si){100,101,102,103,104,105,106,107,200,201,202,203,204,205,206,207}), 0x00FFu, ((__m512i)(__v16si){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}), 1), 1,0,0,0, 5,4,4,4, 200,201,202,203,204,205,206,207));
+
+// _mm512_maskz_shuffle_epi32
+TEST_CONSTEXPR(match_v16si(_mm512_maskz_shuffle_epi32(0xFFFFu, ((__m512i)(__v16si){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}), 1), 1,0,0,0, 5,4,4,4, 9,8,8,8, 13,12,12,12));
+TEST_CONSTEXPR(match_v16si(_mm512_maskz_shuffle_epi32(0x5555u, ((__m512i)(__v16si){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}), 1), 1,0,0,0, 5,0,4,0, 9,0,8,0, 13,0,12,0));
+TEST_CONSTEXPR(match_v16si(_mm512_maskz_shuffle_epi32(0x8001u, ((__m512i)(__v16si){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}), 1), 1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,12));
+
__m512d test_mm512_mask_expand_pd(__m512d __W, __mmask8 __U, __m512d __A) {
// CHECK-LABEL: test_mm512_mask_expand_pd
// CHECK: @llvm.x86.avx512.mask.expand
diff --git a/clang/test/CodeGen/X86/avx512vl-builtins.c b/clang/test/CodeGen/X86/avx512vl-builtins.c
index 5282c7ab06dea..b344ad7f8aade 100644
--- a/clang/test/CodeGen/X86/avx512vl-builtins.c
+++ b/clang/test/CodeGen/X86/avx512vl-builtins.c
@@ -10046,6 +10046,25 @@ __m256i test_mm256_maskz_shuffle_epi32(__mmask8 __U, __m256i __A) {
return _mm256_maskz_shuffle_epi32(__U, __A, 2);
}
+// 128-bit (_mm_mask_shuffle_epi32 / _mm_maskz_shuffle_epi32)
+TEST_CONSTEXPR(match_v4si(_mm_mask_shuffle_epi32(((__m128i)(__v4si){100,101,102,103}), 0x0Fu, ((__m128i)(__v4si){0,1,2,3}), 1), 1,0,0,0));
+TEST_CONSTEXPR(match_v4si(_mm_mask_shuffle_epi32(((__m128i)(__v4si){100,101,102,103}), 0x0Au, ((__m128i)(__v4si){0,1,2,3}), 1), 100,0,102,0));
+TEST_CONSTEXPR(match_v4si(_mm_mask_shuffle_epi32(((__m128i)(__v4si){100,101,102,103}), 0x05u, ((__m128i)(__v4si){0,1,2,3}), 1), 1,101,0,103));
+TEST_CONSTEXPR(match_v4si(_mm_mask_shuffle_epi32(((__m128i)(__v4si){100,101,102,103}), 0x00u, ((__m128i)(__v4si){0,1,2,3}), 1), 100,101,102,103));
+
+TEST_CONSTEXPR(match_v4si(_mm_maskz_shuffle_epi32(0x01u, ((__m128i)(__v4si){0,1,2,3}), 2), 2,0,0,0));
+TEST_CONSTEXPR(match_v4si(_mm_maskz_shuffle_epi32(0x0Au, ((__m128i)(__v4si){0,1,2,3}), 2), 0,0,0,0));
+TEST_CONSTEXPR(match_v4si(_mm_maskz_shuffle_epi32(0x0Fu, ((__m128i)(__v4si){0,1,2,3}), 2), 2,0,0,0));
+
+// 256-bit (_mm256_mask_shuffle_epi32 / _mm256_maskz_shuffle_epi32)
+TEST_CONSTEXPR(match_v8si(_mm256_mask_shuffle_epi32(((__m256i)(__v8si){100,101,102,103,104,105,106,107}), 0xF0u, ((__m256i)(__v8si){0,1,2,3,4,5,6,7}), 2), 100,101,102,103, 6,4,4,4));
+TEST_CONSTEXPR(match_v8si(_mm256_mask_shuffle_epi32(((__m256i)(__v8si){100,101,102,103,104,105,106,107}), 0x33u, ((__m256i)(__v8si){0,1,2,3,4,5,6,7}), 2), 2,0,102,103, 6,4,106,107));
+TEST_CONSTEXPR(match_v8si(_mm256_mask_shuffle_epi32(((__m256i)(__v8si){100,101,102,103,104,105,106,107}), 0x00u, ((__m256i)(__v8si){0,1,2,3,4,5,6,7}), 2), 100,101,102,103,104,105,106,107));
+
+TEST_CONSTEXPR(match_v8si(_mm256_maskz_shuffle_epi32(0x33u, ((__m256i)(__v8si){0,1,2,3,4,5,6,7}), 2), 2,0,0,0, 6,4,0,0));
+TEST_CONSTEXPR(match_v8si(_mm256_maskz_shuffle_epi32(0xAAu, ((__m256i)(__v8si){0,1,2,3,4,5,6,7}), 2), 0,0,0,0, 0,4,0,4));
+TEST_CONSTEXPR(match_v8si(_mm256_maskz_shuffle_epi32(0xFFu, ((__m256i)(__v8si){0,1,2,3,4,5,6,7}), 2), 2,0,0,0, 6,4,4,4));
+
__m128d test_mm_mask_mov_pd(__m128d __W, __mmask8 __U, __m128d __A) {
// CHECK-LABEL: test_mm_mask_mov_pd
// CHECK: select <2 x i1> %{{.*}}, <2 x double> %{{.*}}, <2 x double> %{{.*}}
diff --git a/clang/test/CodeGen/X86/avx512vlbw-builtins.c b/clang/test/CodeGen/X86/avx512vlbw-builtins.c
index 6c9c80efcef9d..4d539e5da33dc 100644
--- a/clang/test/CodeGen/X86/avx512vlbw-builtins.c
+++ b/clang/test/CodeGen/X86/avx512vlbw-builtins.c
@@ -3420,7 +3420,6 @@ __m256i test_mm256_mask_shufflehi_epi16(__m256i __W, __mmask16 __U, __m256i __A)
// CHECK: select <16 x i1> %{{.*}}, <16 x i16> %{{.*}}, <16 x i16> %{{.*}}
return _mm256_mask_shufflehi_epi16(__W, __U, __A, 5);
}
-
__m256i test_mm256_maskz_shufflehi_epi16(__mmask16 __U, __m256i __A) {
// CHECK-LABEL: test_mm256_maskz_shufflehi_epi16
// CHECK: shufflevector <16 x i16> %{{.*}}, <16 x i16> poison, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 5, i32 5, i32 4, i32 4, i32 8, i32 9, i32 10, i32 11, i32 13, i32 13, i32 12, i32 12>
@@ -3442,6 +3441,65 @@ __m256i test_mm256_maskz_shufflelo_epi16(__mmask16 __U, __m256i __A) {
return _mm256_maskz_shufflelo_epi16(__U, __A, 5);
}
+// 128-bit shufflelo (mask)
+TEST_CONSTEXPR(match_v8hi(_mm_mask_shufflelo_epi16(((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),0xFF,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),1,1,0,0,4,5,6,7));
+TEST_CONSTEXPR(match_v8hi(_mm_mask_shufflelo_epi16(((__m128i)(__v8hi){100,101,102,103,104,105,106,107}),0x00u,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),100,101,102,103,104,105,106,107));
+TEST_CONSTEXPR(match_v8hi(_mm_mask_shufflelo_epi16(((__m128i)(__v8hi){100,101,102,103,104,105,106,107}),0x0Fu,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),1,1,0,0,104,105,106,107));
+TEST_CONSTEXPR(match_v8hi(_mm_mask_shufflelo_epi16(((__m128i)(__v8hi){100,101,102,103,104,105,106,107}),0xF0u,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),100,101,102,103,4,5,6,7));
+TEST_CONSTEXPR(match_v8hi(_mm_mask_shufflelo_epi16(((__m128i)(__v8hi){100,101,102,103,104,105,106,107}),0xAAu,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),100,1,102,0,104,5,106,7));
+TEST_CONSTEXPR(match_v8hi(_mm_mask_shufflelo_epi16(((__m128i)(__v8hi){100,101,102,103,104,105,106,107}),0x55u,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),1,101,0,103,4,105,6,107));
+
+// 128-bit shufflelo (maskz)
+TEST_CONSTEXPR(match_v8hi(_mm_maskz_shufflelo_epi16(0xFF,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),1,1,0,0,4,5,6,7));
+TEST_CONSTEXPR(match_v8hi(_mm_maskz_shufflelo_epi16(0x0Fu,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),1,1,0,0,0,0,0,0));
+TEST_CONSTEXPR(match_v8hi(_mm_maskz_shufflelo_epi16(0xF0u,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),0,0,0,0,4,5,6,7));
+TEST_CONSTEXPR(match_v8hi(_mm_maskz_shufflelo_epi16(0xAAu,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),0,1,0,0,0,5,0,7));
+TEST_CONSTEXPR(match_v8hi(_mm_maskz_shufflelo_epi16(0x55u,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),1,0,0,0,4,0,6,0));
+
+// 128-bit shufflehi (mask))
+TEST_CONSTEXPR(match_v8hi(_mm_mask_shufflehi_epi16(((__m128i)(__v8hi){100,101,102,103,104,105,106,107}),0xF0u,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),100,101,102,103,5,5,4,4));
+TEST_CONSTEXPR(match_v8hi(_mm_mask_shufflehi_epi16(((__m128i)(__v8hi){100,101,102,103,104,105,106,107}),0x00u,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),100,101,102,103,104,105,106,107));
+TEST_CONSTEXPR(match_v8hi(_mm_mask_shufflehi_epi16(((__m128i)(__v8hi){100,101,102,103,104,105,106,107}),0xFFu,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),0,1,2,3,5,5,4,4));
+TEST_CONSTEXPR(match_v8hi(_mm_mask_shufflehi_epi16(((__m128i)(__v8hi){100,101,102,103,104,105,106,107}),0x0Fu,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),0,1,2,3,104,105,106,107));
+TEST_CONSTEXPR(match_v8hi(_mm_mask_shufflehi_epi16(((__m128i)(__v8hi){100,101,102,103,104,105,106,107}),0x55u,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),0,101,2,103,5,105,4,107));
+TEST_CONSTEXPR(match_v8hi(_mm_mask_shufflehi_epi16(((__m128i)(__v8hi){100,101,102,103,104,105,106,107}),0xAAu,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),100,1,102,3,104,5,106,4));
+
+// 128-bit shufflehi (maskz)
+TEST_CONSTEXPR(match_v8hi(_mm_maskz_shufflehi_epi16(0xF0u,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),0,0,0,0,5,5,4,4));
+TEST_CONSTEXPR(match_v8hi(_mm_maskz_shufflehi_epi16(0x00u,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),0,0,0,0,0,0,0,0));
+TEST_CONSTEXPR(match_v8hi(_mm_maskz_shufflehi_epi16(0xFFu,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),0,1,2,3,5,5,4,4));
+TEST_CONSTEXPR(match_v8hi(_mm_maskz_shufflehi_epi16(0x0Fu,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),0,1,2,3,0,0,0,0));
+TEST_CONSTEXPR(match_v8hi(_mm_maskz_shufflehi_epi16(0x55u,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),0,0,2,0,5,0,4,0));
+TEST_CONSTEXPR(match_v8hi(_mm_maskz_shufflehi_epi16(0xAAu,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),0,1,0,3,0,5,0,4));
+
+// 256-bit shufflelo (mask)
+TEST_CONSTEXPR(match_v16hi(_mm256_mask_shufflelo_epi16(((__m256i)(__v16hi){100,101,102,103,104,105,106,107,200,201,202,203,204,205,206,207}),0xFFFF,((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}),5),1,1,0,0,4,5,6,7,9,9,8,8,12,13,14,15));
+TEST_CONSTEXPR(match_v16hi(_mm256_mask_shufflelo_epi16(((__m256i)(__v16hi){100,101,102,103,104,105,106,107,200,201,202,203,204,205,206,207}),0x000Fu,((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}),5),1,1,0,0,104,105,106,107,200,201,202,203,204,205,206,207));
+TEST_CONSTEXPR(match_v16hi(_mm256_mask_shufflelo_epi16(((__m256i)(__v16hi){100,101,102,103,104,105,106,107,200,201,202,203,204,205,206,207}),0x00FFu,((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}),5),1,1,0,0,4,5,6,7,200,201,202,203,204,205,206,207));
+TEST_CONSTEXPR(match_v16hi(_mm256_mask_shufflelo_epi16(((__m256i)(__v16hi){100,101,102,103,104,105,106,107,200,201,202,203,204,205,206,207}),0xF00Fu,((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}),5),1,1,0,0,104,105,106,107,200,201,202,203,12,13,14,15));
+
+
+// 256-bit shufflelo (maskz)
+TEST_CONSTEXPR(match_v16hi(_mm256_maskz_shufflelo_epi16(0xFFFF,((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}),5),1,1,0,0,4,5,6,7,9,9,8,8,12,13,14,15));
+TEST_CONSTEXPR(match_v16hi(_mm256_maskz_shufflelo_epi16(0x000Fu,((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}),5),1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0));
+TEST_CONSTEXPR(match_v16hi(_mm256_maskz_shufflelo_epi16(0x00FFu,((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}),5),1,1,0,0,4,5,6,7,0,0,0,0,0,0,0,0));
+TEST_CONSTEXPR(match_v16hi(_mm256_maskz_shufflelo_epi16(0xF0F0u,((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}),5),0,0,0,0,4,5,6,7,0,0,0,0,12,13,14,15));
+
+// 256-bit shufflehi (mask)
+TEST_CONSTEXPR(match_v16hi(_mm256_mask_shufflehi_epi16(((__m256i)(__v16hi){100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115}),0xFF00u,((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}),5),100,101,102,103,104,105,106,107,8,9,10,11,13,13,12,12));
+TEST_CONSTEXPR(match_v16hi(_mm256_mask_shufflehi_epi16(((__m256i)(__v16hi){100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115}),0x0000u,((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}),5),100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115));
+TEST_CONSTEXPR(match_v16hi(_mm256_mask_shufflehi_epi16(((__m256i)(__v16hi){100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115}),0xFFFFu,((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}),5),0,1,2,3,5,5,4,4,8,9,10,11,13,13,12,12));
+TEST_CONSTEXPR(match_v16hi(_mm256_mask_shufflehi_epi16(((__m256i)(__v16hi){100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115}),0x00FFu,((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}),5),0,1,2,3,5,5,4,4,108,109,110,111,112,113,114,115));
+TEST_CONSTEXPR(match_v16hi(_mm256_mask_shufflehi_epi16(((__m256i)(__v16hi){100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115}),0x5555u,((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}),5),0,101,2,103,5,105,4,107,8,109,10,111,13,113,12,115));
+
+// 256-bit shufflehi (maskz)
+TEST_CONSTEXPR(match_v16hi(_mm256_maskz_shufflehi_epi16(0x0000u,((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}),5),0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0));
+TEST_CONSTEXPR(match_v16hi(_mm256_maskz_shufflehi_epi16(0xFFFFu,((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}),5),0,1,2,3,5,5,4,4,8,9,10,11,13,13,12,12));
+TEST_CONSTEXPR(match_v16hi(_mm256_maskz_shufflehi_epi16(0x00FFu,((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}),5),0,1,2,3,5,5,4,4,0,0,0,0,0,0,0,0));
+TEST_CONSTEXPR(match_v16hi(_mm256_maskz_shufflehi_epi16(0xFF00u,((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}),5),0,0,0,0,0,0,0,0,8,9,10,11,13,13,12,12));
+TEST_CONSTEXPR(match_v16hi(_mm256_maskz_shufflehi_epi16(0x5555u,((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}),5),0,0,2,0,5,0,4,0,8,0,10,0,13,0,12,0));
+TEST_CONSTEXPR(match_v16hi(_mm256_maskz_shufflehi_epi16(0xAAAAu,((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}),5),0,1,0,3,0,5,0,4,0,9,0,11,0,13,0,12));
+
void test_mm_mask_cvtepi16_storeu_epi8 (void * __P, __mmask8 __M, __m128i __A)
{
// CHECK-LABEL: test_mm_mask_cvtepi16_storeu_epi8
diff --git a/clang/test/CodeGen/X86/mmx-builtins.c b/clang/test/CodeGen/X86/mmx-builtins.c
index 26c5f7315457e..5156d070bcde7 100644
--- a/clang/test/CodeGen/X86/mmx-builtins.c
+++ b/clang/test/CodeGen/X86/mmx-builtins.c
@@ -584,7 +584,7 @@ __m64 test_mm_shuffle_pi16(__m64 a) {
// CHECK: shufflevector <4 x i16> {{%.*}}, <4 x i16> {{%.*}}, <4 x i32> <i32 3, i32 0, i32 0, i32 0>
return _mm_shuffle_pi16(a, 3);
}
-
+TEST_CONSTEXPR(match_v4hi(_mm_shuffle_pi16(((__m64)(__v4hi){0,1,2,3}), 3), 3,0,0,0));
__m64 test_mm_sign_pi8(__m64 a, __m64 b) {
// CHECK-LABEL: test_mm_sign_pi8
// CHECK: call <16 x i8> @llvm.x86.ssse3.psign.b.128(
diff --git a/clang/test/CodeGen/X86/sse2-builtins.c b/clang/test/CodeGen/X86/sse2-builtins.c
index 84b90c09444c2..84c77b4377c86 100644
--- a/clang/test/CodeGen/X86/sse2-builtins.c
+++ b/clang/test/CodeGen/X86/sse2-builtins.c
@@ -1294,12 +1294,6 @@ __m128i test_mm_setzero_si128(void) {
}
TEST_CONSTEXPR(match_m128i(_mm_setzero_si128(), 0, 0));
-__m128i test_mm_shuffle_epi32(__m128i A) {
- // CHECK-LABEL: test_mm_shuffle_epi32
- // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> poison, <4 x i32> zeroinitializer
- return _mm_shuffle_epi32(A, 0);
-}
-
__m128d test_mm_shuffle_pd(__m128d A, __m128d B) {
// CHECK-LABEL: test_mm_shuffle_pd
// CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x i32> <i32 1, i32 2>
@@ -1317,6 +1311,15 @@ __m128i test_mm_shufflelo_epi16(__m128i A) {
// CHECK: shufflevector <8 x i16> %{{.*}}, <8 x i16> poison, <8 x i32> <i32 0, i32 0, i32 0, i32 0, i32 4, i32 5, i32 6, i32 7>
return _mm_shufflelo_epi16(A, 0);
}
+__m128i test_mm_shuffle_epi32(__m128i A) {
+ // CHECK-LABEL: test_mm_shuffle_epi32
+ // CHECK: shufflevector <4 x i32> %{{.*}}, <4 x i32> poison, <4 x i32> zeroinitializer
+ return _mm_shuffle_epi32(A, 0);
+}
+
+TEST_CONSTEXPR(match_v4si(_mm_shuffle_epi32(((__m128i)(__v4si){0,1,2,3}), 0), 0,0,0,0));
+TEST_CONSTEXPR(match_v8hi(_mm_shufflehi_epi16(((__m128i)(__v8hi){0,1,2,3,4,5,6,7}), 0), 0,1,2,3, 4,4,4,4));
+TEST_CONSTEXPR(match_v8hi(_mm_shufflelo_epi16(((__m128i)(__v8hi){0,1,2,3,4,5,6,7}), 0), 0,0,0,0, 4,5,6,7));
__m128i test_mm_sll_epi16(__m128i A, __m128i B) {
// CHECK-LABEL: test_mm_sll_epi16
>From 2d0c3f8181ba1828dd684e35070d472774dfbe5a Mon Sep 17 00:00:00 2001
From: NagrajMG <nagrajgaonkarmumbai749 at gmail.com>
Date: Mon, 29 Sep 2025 00:46:16 +0530
Subject: [PATCH 2/3] [X86] Allow PSHUFD/PSHUFLW/PSHUFW intrinsics in
constexpr, Fixes Issue: #156611
---
clang/lib/AST/ExprConstant.cpp | 4616 ++++++++++++++++----------------
1 file changed, 2306 insertions(+), 2310 deletions(-)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index c1362200ee907..b6cf3c545c36d 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -73,651 +73,667 @@
using namespace clang;
using llvm::APFixedPoint;
-using llvm::APFloat;
using llvm::APInt;
using llvm::APSInt;
+using llvm::APFloat;
using llvm::FixedPointSemantics;
namespace {
-struct LValue;
-class CallStackFrame;
-class EvalInfo;
+ struct LValue;
+ class CallStackFrame;
+ class EvalInfo;
-using SourceLocExprScopeGuard =
- CurrentSourceLocExprScope::SourceLocExprScopeGuard;
+ using SourceLocExprScopeGuard =
+ CurrentSourceLocExprScope::SourceLocExprScopeGuard;
-static QualType getType(APValue::LValueBase B) { return B.getType(); }
+ static QualType getType(APValue::LValueBase B) {
+ return B.getType();
+ }
-/// Get an LValue path entry, which is known to not be an array index, as a
-/// field declaration.
-static const FieldDecl *getAsField(APValue::LValuePathEntry E) {
- return dyn_cast_or_null<FieldDecl>(E.getAsBaseOrMember().getPointer());
-}
-/// Get an LValue path entry, which is known to not be an array index, as a
-/// base class declaration.
-static const CXXRecordDecl *getAsBaseClass(APValue::LValuePathEntry E) {
- return dyn_cast_or_null<CXXRecordDecl>(E.getAsBaseOrMember().getPointer());
-}
-/// Determine whether this LValue path entry for a base class names a virtual
-/// base class.
-static bool isVirtualBaseClass(APValue::LValuePathEntry E) {
- return E.getAsBaseOrMember().getInt();
-}
+ /// Get an LValue path entry, which is known to not be an array index, as a
+ /// field declaration.
+ static const FieldDecl *getAsField(APValue::LValuePathEntry E) {
+ return dyn_cast_or_null<FieldDecl>(E.getAsBaseOrMember().getPointer());
+ }
+ /// Get an LValue path entry, which is known to not be an array index, as a
+ /// base class declaration.
+ static const CXXRecordDecl *getAsBaseClass(APValue::LValuePathEntry E) {
+ return dyn_cast_or_null<CXXRecordDecl>(E.getAsBaseOrMember().getPointer());
+ }
+ /// Determine whether this LValue path entry for a base class names a virtual
+ /// base class.
+ static bool isVirtualBaseClass(APValue::LValuePathEntry E) {
+ return E.getAsBaseOrMember().getInt();
+ }
-/// Given an expression, determine the type used to store the result of
-/// evaluating that expression.
-static QualType getStorageType(const ASTContext &Ctx, const Expr *E) {
- if (E->isPRValue())
- return E->getType();
- return Ctx.getLValueReferenceType(E->getType());
-}
+ /// Given an expression, determine the type used to store the result of
+ /// evaluating that expression.
+ static QualType getStorageType(const ASTContext &Ctx, const Expr *E) {
+ if (E->isPRValue())
+ return E->getType();
+ return Ctx.getLValueReferenceType(E->getType());
+ }
-/// Attempts to unwrap a CallExpr (with an alloc_size attribute) from an Expr.
-/// This will look through a single cast.
-///
-/// Returns null if we couldn't unwrap a function with alloc_size.
-static const CallExpr *tryUnwrapAllocSizeCall(const Expr *E) {
- if (!E->getType()->isPointerType())
- return nullptr;
+ /// Attempts to unwrap a CallExpr (with an alloc_size attribute) from an Expr.
+ /// This will look through a single cast.
+ ///
+ /// Returns null if we couldn't unwrap a function with alloc_size.
+ static const CallExpr *tryUnwrapAllocSizeCall(const Expr *E) {
+ if (!E->getType()->isPointerType())
+ return nullptr;
- E = E->IgnoreParens();
- // If we're doing a variable assignment from e.g. malloc(N), there will
- // probably be a cast of some kind. In exotic cases, we might also see a
- // top-level ExprWithCleanups. Ignore them either way.
- if (const auto *FE = dyn_cast<FullExpr>(E))
- E = FE->getSubExpr()->IgnoreParens();
+ E = E->IgnoreParens();
+ // If we're doing a variable assignment from e.g. malloc(N), there will
+ // probably be a cast of some kind. In exotic cases, we might also see a
+ // top-level ExprWithCleanups. Ignore them either way.
+ if (const auto *FE = dyn_cast<FullExpr>(E))
+ E = FE->getSubExpr()->IgnoreParens();
- if (const auto *Cast = dyn_cast<CastExpr>(E))
- E = Cast->getSubExpr()->IgnoreParens();
+ if (const auto *Cast = dyn_cast<CastExpr>(E))
+ E = Cast->getSubExpr()->IgnoreParens();
- if (const auto *CE = dyn_cast<CallExpr>(E))
- return CE->getCalleeAllocSizeAttr() ? CE : nullptr;
- return nullptr;
-}
+ if (const auto *CE = dyn_cast<CallExpr>(E))
+ return CE->getCalleeAllocSizeAttr() ? CE : nullptr;
+ return nullptr;
+ }
-/// Determines whether or not the given Base contains a call to a function
-/// with the alloc_size attribute.
-static bool isBaseAnAllocSizeCall(APValue::LValueBase Base) {
- const auto *E = Base.dyn_cast<const Expr *>();
- return E && E->getType()->isPointerType() && tryUnwrapAllocSizeCall(E);
-}
+ /// Determines whether or not the given Base contains a call to a function
+ /// with the alloc_size attribute.
+ static bool isBaseAnAllocSizeCall(APValue::LValueBase Base) {
+ const auto *E = Base.dyn_cast<const Expr *>();
+ return E && E->getType()->isPointerType() && tryUnwrapAllocSizeCall(E);
+ }
-/// Determines whether the given kind of constant expression is only ever
-/// used for name mangling. If so, it's permitted to reference things that we
-/// can't generate code for (in particular, dllimported functions).
-static bool isForManglingOnly(ConstantExprKind Kind) {
- switch (Kind) {
- case ConstantExprKind::Normal:
- case ConstantExprKind::ClassTemplateArgument:
- case ConstantExprKind::ImmediateInvocation:
- // Note that non-type template arguments of class type are emitted as
- // template parameter objects.
- return false;
+ /// Determines whether the given kind of constant expression is only ever
+ /// used for name mangling. If so, it's permitted to reference things that we
+ /// can't generate code for (in particular, dllimported functions).
+ static bool isForManglingOnly(ConstantExprKind Kind) {
+ switch (Kind) {
+ case ConstantExprKind::Normal:
+ case ConstantExprKind::ClassTemplateArgument:
+ case ConstantExprKind::ImmediateInvocation:
+ // Note that non-type template arguments of class type are emitted as
+ // template parameter objects.
+ return false;
- case ConstantExprKind::NonClassTemplateArgument:
- return true;
+ case ConstantExprKind::NonClassTemplateArgument:
+ return true;
+ }
+ llvm_unreachable("unknown ConstantExprKind");
}
- llvm_unreachable("unknown ConstantExprKind");
-}
-static bool isTemplateArgument(ConstantExprKind Kind) {
- switch (Kind) {
- case ConstantExprKind::Normal:
- case ConstantExprKind::ImmediateInvocation:
- return false;
+ static bool isTemplateArgument(ConstantExprKind Kind) {
+ switch (Kind) {
+ case ConstantExprKind::Normal:
+ case ConstantExprKind::ImmediateInvocation:
+ return false;
- case ConstantExprKind::ClassTemplateArgument:
- case ConstantExprKind::NonClassTemplateArgument:
- return true;
- }
- llvm_unreachable("unknown ConstantExprKind");
-}
-
-/// The bound to claim that an array of unknown bound has.
-/// The value in MostDerivedArraySize is undefined in this case. So, set it
-/// to an arbitrary value that's likely to loudly break things if it's used.
-static const uint64_t AssumedSizeForUnsizedArray =
- std::numeric_limits<uint64_t>::max() / 2;
-
-/// Determines if an LValue with the given LValueBase will have an unsized
-/// array in its designator.
-/// Find the path length and type of the most-derived subobject in the given
-/// path, and find the size of the containing array, if any.
-static unsigned
-findMostDerivedSubobject(const ASTContext &Ctx, APValue::LValueBase Base,
- ArrayRef<APValue::LValuePathEntry> Path,
- uint64_t &ArraySize, QualType &Type, bool &IsArray,
- bool &FirstEntryIsUnsizedArray) {
- // This only accepts LValueBases from APValues, and APValues don't support
- // arrays that lack size info.
- assert(!isBaseAnAllocSizeCall(Base) &&
- "Unsized arrays shouldn't appear here");
- unsigned MostDerivedLength = 0;
- // The type of Base is a reference type if the base is a constexpr-unknown
- // variable. In that case, look through the reference type.
- Type = getType(Base).getNonReferenceType();
-
- for (unsigned I = 0, N = Path.size(); I != N; ++I) {
- if (Type->isArrayType()) {
- const ArrayType *AT = Ctx.getAsArrayType(Type);
- Type = AT->getElementType();
- MostDerivedLength = I + 1;
- IsArray = true;
-
- if (auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
- ArraySize = CAT->getZExtSize();
+ case ConstantExprKind::ClassTemplateArgument:
+ case ConstantExprKind::NonClassTemplateArgument:
+ return true;
+ }
+ llvm_unreachable("unknown ConstantExprKind");
+ }
+
+ /// The bound to claim that an array of unknown bound has.
+ /// The value in MostDerivedArraySize is undefined in this case. So, set it
+ /// to an arbitrary value that's likely to loudly break things if it's used.
+ static const uint64_t AssumedSizeForUnsizedArray =
+ std::numeric_limits<uint64_t>::max() / 2;
+
+ /// Determines if an LValue with the given LValueBase will have an unsized
+ /// array in its designator.
+ /// Find the path length and type of the most-derived subobject in the given
+ /// path, and find the size of the containing array, if any.
+ static unsigned
+ findMostDerivedSubobject(const ASTContext &Ctx, APValue::LValueBase Base,
+ ArrayRef<APValue::LValuePathEntry> Path,
+ uint64_t &ArraySize, QualType &Type, bool &IsArray,
+ bool &FirstEntryIsUnsizedArray) {
+ // This only accepts LValueBases from APValues, and APValues don't support
+ // arrays that lack size info.
+ assert(!isBaseAnAllocSizeCall(Base) &&
+ "Unsized arrays shouldn't appear here");
+ unsigned MostDerivedLength = 0;
+ // The type of Base is a reference type if the base is a constexpr-unknown
+ // variable. In that case, look through the reference type.
+ Type = getType(Base).getNonReferenceType();
+
+ for (unsigned I = 0, N = Path.size(); I != N; ++I) {
+ if (Type->isArrayType()) {
+ const ArrayType *AT = Ctx.getAsArrayType(Type);
+ Type = AT->getElementType();
+ MostDerivedLength = I + 1;
+ IsArray = true;
+
+ if (auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
+ ArraySize = CAT->getZExtSize();
+ } else {
+ assert(I == 0 && "unexpected unsized array designator");
+ FirstEntryIsUnsizedArray = true;
+ ArraySize = AssumedSizeForUnsizedArray;
+ }
+ } else if (Type->isAnyComplexType()) {
+ const ComplexType *CT = Type->castAs<ComplexType>();
+ Type = CT->getElementType();
+ ArraySize = 2;
+ MostDerivedLength = I + 1;
+ IsArray = true;
+ } else if (const auto *VT = Type->getAs<VectorType>()) {
+ Type = VT->getElementType();
+ ArraySize = VT->getNumElements();
+ MostDerivedLength = I + 1;
+ IsArray = true;
+ } else if (const FieldDecl *FD = getAsField(Path[I])) {
+ Type = FD->getType();
+ ArraySize = 0;
+ MostDerivedLength = I + 1;
+ IsArray = false;
} else {
- assert(I == 0 && "unexpected unsized array designator");
- FirstEntryIsUnsizedArray = true;
- ArraySize = AssumedSizeForUnsizedArray;
+ // Path[I] describes a base class.
+ ArraySize = 0;
+ IsArray = false;
+ }
+ }
+ return MostDerivedLength;
+ }
+
+ /// A path from a glvalue to a subobject of that glvalue.
+ struct SubobjectDesignator {
+ /// True if the subobject was named in a manner not supported by C++11. Such
+ /// lvalues can still be folded, but they are not core constant expressions
+ /// and we cannot perform lvalue-to-rvalue conversions on them.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned Invalid : 1;
+
+ /// Is this a pointer one past the end of an object?
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned IsOnePastTheEnd : 1;
+
+ /// Indicator of whether the first entry is an unsized array.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned FirstEntryIsAnUnsizedArray : 1;
+
+ /// Indicator of whether the most-derived object is an array element.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned MostDerivedIsArrayElement : 1;
+
+ /// The length of the path to the most-derived object of which this is a
+ /// subobject.
+ unsigned MostDerivedPathLength : 28;
+
+ /// The size of the array of which the most-derived object is an element.
+ /// This will always be 0 if the most-derived object is not an array
+ /// element. 0 is not an indicator of whether or not the most-derived object
+ /// is an array, however, because 0-length arrays are allowed.
+ ///
+ /// If the current array is an unsized array, the value of this is
+ /// undefined.
+ uint64_t MostDerivedArraySize;
+ /// The type of the most derived object referred to by this address.
+ QualType MostDerivedType;
+
+ typedef APValue::LValuePathEntry PathEntry;
+
+ /// The entries on the path from the glvalue to the designated subobject.
+ SmallVector<PathEntry, 8> Entries;
+
+ SubobjectDesignator() : Invalid(true) {}
+
+ explicit SubobjectDesignator(QualType T)
+ : Invalid(false), IsOnePastTheEnd(false),
+ FirstEntryIsAnUnsizedArray(false), MostDerivedIsArrayElement(false),
+ MostDerivedPathLength(0), MostDerivedArraySize(0),
+ MostDerivedType(T.isNull() ? QualType() : T.getNonReferenceType()) {}
+
+ SubobjectDesignator(const ASTContext &Ctx, const APValue &V)
+ : Invalid(!V.isLValue() || !V.hasLValuePath()), IsOnePastTheEnd(false),
+ FirstEntryIsAnUnsizedArray(false), MostDerivedIsArrayElement(false),
+ MostDerivedPathLength(0), MostDerivedArraySize(0) {
+ assert(V.isLValue() && "Non-LValue used to make an LValue designator?");
+ if (!Invalid) {
+ IsOnePastTheEnd = V.isLValueOnePastTheEnd();
+ llvm::append_range(Entries, V.getLValuePath());
+ if (V.getLValueBase()) {
+ bool IsArray = false;
+ bool FirstIsUnsizedArray = false;
+ MostDerivedPathLength = findMostDerivedSubobject(
+ Ctx, V.getLValueBase(), V.getLValuePath(), MostDerivedArraySize,
+ MostDerivedType, IsArray, FirstIsUnsizedArray);
+ MostDerivedIsArrayElement = IsArray;
+ FirstEntryIsAnUnsizedArray = FirstIsUnsizedArray;
+ }
}
- } else if (Type->isAnyComplexType()) {
- const ComplexType *CT = Type->castAs<ComplexType>();
- Type = CT->getElementType();
- ArraySize = 2;
- MostDerivedLength = I + 1;
- IsArray = true;
- } else if (const auto *VT = Type->getAs<VectorType>()) {
- Type = VT->getElementType();
- ArraySize = VT->getNumElements();
- MostDerivedLength = I + 1;
- IsArray = true;
- } else if (const FieldDecl *FD = getAsField(Path[I])) {
- Type = FD->getType();
- ArraySize = 0;
- MostDerivedLength = I + 1;
- IsArray = false;
- } else {
- // Path[I] describes a base class.
- ArraySize = 0;
- IsArray = false;
}
- }
- return MostDerivedLength;
-}
-
-/// A path from a glvalue to a subobject of that glvalue.
-struct SubobjectDesignator {
- /// True if the subobject was named in a manner not supported by C++11. Such
- /// lvalues can still be folded, but they are not core constant expressions
- /// and we cannot perform lvalue-to-rvalue conversions on them.
- LLVM_PREFERRED_TYPE(bool)
- unsigned Invalid : 1;
- /// Is this a pointer one past the end of an object?
- LLVM_PREFERRED_TYPE(bool)
- unsigned IsOnePastTheEnd : 1;
+ void truncate(ASTContext &Ctx, APValue::LValueBase Base,
+ unsigned NewLength) {
+ if (Invalid)
+ return;
- /// Indicator of whether the first entry is an unsized array.
- LLVM_PREFERRED_TYPE(bool)
- unsigned FirstEntryIsAnUnsizedArray : 1;
+ assert(Base && "cannot truncate path for null pointer");
+ assert(NewLength <= Entries.size() && "not a truncation");
- /// Indicator of whether the most-derived object is an array element.
- LLVM_PREFERRED_TYPE(bool)
- unsigned MostDerivedIsArrayElement : 1;
+ if (NewLength == Entries.size())
+ return;
+ Entries.resize(NewLength);
- /// The length of the path to the most-derived object of which this is a
- /// subobject.
- unsigned MostDerivedPathLength : 28;
+ bool IsArray = false;
+ bool FirstIsUnsizedArray = false;
+ MostDerivedPathLength = findMostDerivedSubobject(
+ Ctx, Base, Entries, MostDerivedArraySize, MostDerivedType, IsArray,
+ FirstIsUnsizedArray);
+ MostDerivedIsArrayElement = IsArray;
+ FirstEntryIsAnUnsizedArray = FirstIsUnsizedArray;
+ }
- /// The size of the array of which the most-derived object is an element.
- /// This will always be 0 if the most-derived object is not an array
- /// element. 0 is not an indicator of whether or not the most-derived object
- /// is an array, however, because 0-length arrays are allowed.
- ///
- /// If the current array is an unsized array, the value of this is
- /// undefined.
- uint64_t MostDerivedArraySize;
- /// The type of the most derived object referred to by this address.
- QualType MostDerivedType;
-
- typedef APValue::LValuePathEntry PathEntry;
-
- /// The entries on the path from the glvalue to the designated subobject.
- SmallVector<PathEntry, 8> Entries;
-
- SubobjectDesignator() : Invalid(true) {}
-
- explicit SubobjectDesignator(QualType T)
- : Invalid(false), IsOnePastTheEnd(false),
- FirstEntryIsAnUnsizedArray(false), MostDerivedIsArrayElement(false),
- MostDerivedPathLength(0), MostDerivedArraySize(0),
- MostDerivedType(T.isNull() ? QualType() : T.getNonReferenceType()) {}
-
- SubobjectDesignator(const ASTContext &Ctx, const APValue &V)
- : Invalid(!V.isLValue() || !V.hasLValuePath()), IsOnePastTheEnd(false),
- FirstEntryIsAnUnsizedArray(false), MostDerivedIsArrayElement(false),
- MostDerivedPathLength(0), MostDerivedArraySize(0) {
- assert(V.isLValue() && "Non-LValue used to make an LValue designator?");
- if (!Invalid) {
- IsOnePastTheEnd = V.isLValueOnePastTheEnd();
- llvm::append_range(Entries, V.getLValuePath());
- if (V.getLValueBase()) {
- bool IsArray = false;
- bool FirstIsUnsizedArray = false;
- MostDerivedPathLength = findMostDerivedSubobject(
- Ctx, V.getLValueBase(), V.getLValuePath(), MostDerivedArraySize,
- MostDerivedType, IsArray, FirstIsUnsizedArray);
- MostDerivedIsArrayElement = IsArray;
- FirstEntryIsAnUnsizedArray = FirstIsUnsizedArray;
- }
+ void setInvalid() {
+ Invalid = true;
+ Entries.clear();
}
- }
- void truncate(ASTContext &Ctx, APValue::LValueBase Base, unsigned NewLength) {
- if (Invalid)
- return;
+ /// Determine whether the most derived subobject is an array without a
+ /// known bound.
+ bool isMostDerivedAnUnsizedArray() const {
+ assert(!Invalid && "Calling this makes no sense on invalid designators");
+ return Entries.size() == 1 && FirstEntryIsAnUnsizedArray;
+ }
- assert(Base && "cannot truncate path for null pointer");
- assert(NewLength <= Entries.size() && "not a truncation");
+ /// Determine what the most derived array's size is. Results in an assertion
+ /// failure if the most derived array lacks a size.
+ uint64_t getMostDerivedArraySize() const {
+ assert(!isMostDerivedAnUnsizedArray() && "Unsized array has no size");
+ return MostDerivedArraySize;
+ }
- if (NewLength == Entries.size())
- return;
- Entries.resize(NewLength);
+ /// Determine whether this is a one-past-the-end pointer.
+ bool isOnePastTheEnd() const {
+ assert(!Invalid);
+ if (IsOnePastTheEnd)
+ return true;
+ if (!isMostDerivedAnUnsizedArray() && MostDerivedIsArrayElement &&
+ Entries[MostDerivedPathLength - 1].getAsArrayIndex() ==
+ MostDerivedArraySize)
+ return true;
+ return false;
+ }
- bool IsArray = false;
- bool FirstIsUnsizedArray = false;
- MostDerivedPathLength =
- findMostDerivedSubobject(Ctx, Base, Entries, MostDerivedArraySize,
- MostDerivedType, IsArray, FirstIsUnsizedArray);
- MostDerivedIsArrayElement = IsArray;
- FirstEntryIsAnUnsizedArray = FirstIsUnsizedArray;
- }
+ /// Get the range of valid index adjustments in the form
+ /// {maximum value that can be subtracted from this pointer,
+ /// maximum value that can be added to this pointer}
+ std::pair<uint64_t, uint64_t> validIndexAdjustments() {
+ if (Invalid || isMostDerivedAnUnsizedArray())
+ return {0, 0};
- void setInvalid() {
- Invalid = true;
- Entries.clear();
- }
+ // [expr.add]p4: For the purposes of these operators, a pointer to a
+ // nonarray object behaves the same as a pointer to the first element of
+ // an array of length one with the type of the object as its element type.
+ bool IsArray = MostDerivedPathLength == Entries.size() &&
+ MostDerivedIsArrayElement;
+ uint64_t ArrayIndex = IsArray ? Entries.back().getAsArrayIndex()
+ : (uint64_t)IsOnePastTheEnd;
+ uint64_t ArraySize =
+ IsArray ? getMostDerivedArraySize() : (uint64_t)1;
+ return {ArrayIndex, ArraySize - ArrayIndex};
+ }
- /// Determine whether the most derived subobject is an array without a
- /// known bound.
- bool isMostDerivedAnUnsizedArray() const {
- assert(!Invalid && "Calling this makes no sense on invalid designators");
- return Entries.size() == 1 && FirstEntryIsAnUnsizedArray;
- }
+ /// Check that this refers to a valid subobject.
+ bool isValidSubobject() const {
+ if (Invalid)
+ return false;
+ return !isOnePastTheEnd();
+ }
+ /// Check that this refers to a valid subobject, and if not, produce a
+ /// relevant diagnostic and set the designator as invalid.
+ bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK);
- /// Determine what the most derived array's size is. Results in an assertion
- /// failure if the most derived array lacks a size.
- uint64_t getMostDerivedArraySize() const {
- assert(!isMostDerivedAnUnsizedArray() && "Unsized array has no size");
- return MostDerivedArraySize;
- }
+ /// Get the type of the designated object.
+ QualType getType(ASTContext &Ctx) const {
+ assert(!Invalid && "invalid designator has no subobject type");
+ return MostDerivedPathLength == Entries.size()
+ ? MostDerivedType
+ : Ctx.getCanonicalTagType(getAsBaseClass(Entries.back()));
+ }
- /// Determine whether this is a one-past-the-end pointer.
- bool isOnePastTheEnd() const {
- assert(!Invalid);
- if (IsOnePastTheEnd)
- return true;
- if (!isMostDerivedAnUnsizedArray() && MostDerivedIsArrayElement &&
- Entries[MostDerivedPathLength - 1].getAsArrayIndex() ==
- MostDerivedArraySize)
- return true;
- return false;
- }
+ /// Update this designator to refer to the first element within this array.
+ void addArrayUnchecked(const ConstantArrayType *CAT) {
+ Entries.push_back(PathEntry::ArrayIndex(0));
- /// Get the range of valid index adjustments in the form
- /// {maximum value that can be subtracted from this pointer,
- /// maximum value that can be added to this pointer}
- std::pair<uint64_t, uint64_t> validIndexAdjustments() {
- if (Invalid || isMostDerivedAnUnsizedArray())
- return {0, 0};
-
- // [expr.add]p4: For the purposes of these operators, a pointer to a
- // nonarray object behaves the same as a pointer to the first element of
- // an array of length one with the type of the object as its element type.
- bool IsArray =
- MostDerivedPathLength == Entries.size() && MostDerivedIsArrayElement;
- uint64_t ArrayIndex =
- IsArray ? Entries.back().getAsArrayIndex() : (uint64_t)IsOnePastTheEnd;
- uint64_t ArraySize = IsArray ? getMostDerivedArraySize() : (uint64_t)1;
- return {ArrayIndex, ArraySize - ArrayIndex};
- }
-
- /// Check that this refers to a valid subobject.
- bool isValidSubobject() const {
- if (Invalid)
- return false;
- return !isOnePastTheEnd();
- }
- /// Check that this refers to a valid subobject, and if not, produce a
- /// relevant diagnostic and set the designator as invalid.
- bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK);
-
- /// Get the type of the designated object.
- QualType getType(ASTContext &Ctx) const {
- assert(!Invalid && "invalid designator has no subobject type");
- return MostDerivedPathLength == Entries.size()
- ? MostDerivedType
- : Ctx.getCanonicalTagType(getAsBaseClass(Entries.back()));
- }
-
- /// Update this designator to refer to the first element within this array.
- void addArrayUnchecked(const ConstantArrayType *CAT) {
- Entries.push_back(PathEntry::ArrayIndex(0));
-
- // This is a most-derived object.
- MostDerivedType = CAT->getElementType();
- MostDerivedIsArrayElement = true;
- MostDerivedArraySize = CAT->getZExtSize();
- MostDerivedPathLength = Entries.size();
- }
- /// Update this designator to refer to the first element within the array of
- /// elements of type T. This is an array of unknown size.
- void addUnsizedArrayUnchecked(QualType ElemTy) {
- Entries.push_back(PathEntry::ArrayIndex(0));
-
- MostDerivedType = ElemTy;
- MostDerivedIsArrayElement = true;
- // The value in MostDerivedArraySize is undefined in this case. So, set it
- // to an arbitrary value that's likely to loudly break things if it's
- // used.
- MostDerivedArraySize = AssumedSizeForUnsizedArray;
- MostDerivedPathLength = Entries.size();
- }
- /// Update this designator to refer to the given base or member of this
- /// object.
- void addDeclUnchecked(const Decl *D, bool Virtual = false) {
- Entries.push_back(APValue::BaseOrMemberType(D, Virtual));
-
- // If this isn't a base class, it's a new most-derived object.
- if (const FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
- MostDerivedType = FD->getType();
- MostDerivedIsArrayElement = false;
- MostDerivedArraySize = 0;
+ // This is a most-derived object.
+ MostDerivedType = CAT->getElementType();
+ MostDerivedIsArrayElement = true;
+ MostDerivedArraySize = CAT->getZExtSize();
MostDerivedPathLength = Entries.size();
}
- }
- /// Update this designator to refer to the given complex component.
- void addComplexUnchecked(QualType EltTy, bool Imag) {
- Entries.push_back(PathEntry::ArrayIndex(Imag));
+ /// Update this designator to refer to the first element within the array of
+ /// elements of type T. This is an array of unknown size.
+ void addUnsizedArrayUnchecked(QualType ElemTy) {
+ Entries.push_back(PathEntry::ArrayIndex(0));
+
+ MostDerivedType = ElemTy;
+ MostDerivedIsArrayElement = true;
+ // The value in MostDerivedArraySize is undefined in this case. So, set it
+ // to an arbitrary value that's likely to loudly break things if it's
+ // used.
+ MostDerivedArraySize = AssumedSizeForUnsizedArray;
+ MostDerivedPathLength = Entries.size();
+ }
+ /// Update this designator to refer to the given base or member of this
+ /// object.
+ void addDeclUnchecked(const Decl *D, bool Virtual = false) {
+ Entries.push_back(APValue::BaseOrMemberType(D, Virtual));
+
+ // If this isn't a base class, it's a new most-derived object.
+ if (const FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
+ MostDerivedType = FD->getType();
+ MostDerivedIsArrayElement = false;
+ MostDerivedArraySize = 0;
+ MostDerivedPathLength = Entries.size();
+ }
+ }
+ /// Update this designator to refer to the given complex component.
+ void addComplexUnchecked(QualType EltTy, bool Imag) {
+ Entries.push_back(PathEntry::ArrayIndex(Imag));
- // This is technically a most-derived object, though in practice this
- // is unlikely to matter.
- MostDerivedType = EltTy;
- MostDerivedIsArrayElement = true;
- MostDerivedArraySize = 2;
- MostDerivedPathLength = Entries.size();
- }
+ // This is technically a most-derived object, though in practice this
+ // is unlikely to matter.
+ MostDerivedType = EltTy;
+ MostDerivedIsArrayElement = true;
+ MostDerivedArraySize = 2;
+ MostDerivedPathLength = Entries.size();
+ }
- void addVectorElementUnchecked(QualType EltTy, uint64_t Size, uint64_t Idx) {
- Entries.push_back(PathEntry::ArrayIndex(Idx));
- MostDerivedType = EltTy;
- MostDerivedPathLength = Entries.size();
- MostDerivedArraySize = 0;
- MostDerivedIsArrayElement = false;
- }
+ void addVectorElementUnchecked(QualType EltTy, uint64_t Size,
+ uint64_t Idx) {
+ Entries.push_back(PathEntry::ArrayIndex(Idx));
+ MostDerivedType = EltTy;
+ MostDerivedPathLength = Entries.size();
+ MostDerivedArraySize = 0;
+ MostDerivedIsArrayElement = false;
+ }
- void diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, const Expr *E);
- void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E,
- const APSInt &N);
- /// Add N to the address of this subobject.
- void adjustIndex(EvalInfo &Info, const Expr *E, APSInt N, const LValue &LV);
-};
+ void diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, const Expr *E);
+ void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E,
+ const APSInt &N);
+ /// Add N to the address of this subobject.
+ void adjustIndex(EvalInfo &Info, const Expr *E, APSInt N, const LValue &LV);
+ };
-/// A scope at the end of which an object can need to be destroyed.
-enum class ScopeKind { Block, FullExpression, Call };
-
-/// A reference to a particular call and its arguments.
-struct CallRef {
- CallRef() : OrigCallee(), CallIndex(0), Version() {}
- CallRef(const FunctionDecl *Callee, unsigned CallIndex, unsigned Version)
- : OrigCallee(Callee), CallIndex(CallIndex), Version(Version) {}
-
- explicit operator bool() const { return OrigCallee; }
-
- /// Get the parameter that the caller initialized, corresponding to the
- /// given parameter in the callee.
- const ParmVarDecl *getOrigParam(const ParmVarDecl *PVD) const {
- return OrigCallee ? OrigCallee->getParamDecl(PVD->getFunctionScopeIndex())
- : PVD;
- }
-
- /// The callee at the point where the arguments were evaluated. This might
- /// be different from the actual callee (a different redeclaration, or a
- /// virtual override), but this function's parameters are the ones that
- /// appear in the parameter map.
- const FunctionDecl *OrigCallee;
- /// The call index of the frame that holds the argument values.
- unsigned CallIndex;
- /// The version of the parameters corresponding to this call.
- unsigned Version;
-};
+ /// A scope at the end of which an object can need to be destroyed.
+ enum class ScopeKind {
+ Block,
+ FullExpression,
+ Call
+ };
-/// A stack frame in the constexpr call stack.
-class CallStackFrame : public interp::Frame {
-public:
- EvalInfo &Info;
+ /// A reference to a particular call and its arguments.
+ struct CallRef {
+ CallRef() : OrigCallee(), CallIndex(0), Version() {}
+ CallRef(const FunctionDecl *Callee, unsigned CallIndex, unsigned Version)
+ : OrigCallee(Callee), CallIndex(CallIndex), Version(Version) {}
+
+ explicit operator bool() const { return OrigCallee; }
+
+ /// Get the parameter that the caller initialized, corresponding to the
+ /// given parameter in the callee.
+ const ParmVarDecl *getOrigParam(const ParmVarDecl *PVD) const {
+ return OrigCallee ? OrigCallee->getParamDecl(PVD->getFunctionScopeIndex())
+ : PVD;
+ }
+
+ /// The callee at the point where the arguments were evaluated. This might
+ /// be different from the actual callee (a different redeclaration, or a
+ /// virtual override), but this function's parameters are the ones that
+ /// appear in the parameter map.
+ const FunctionDecl *OrigCallee;
+ /// The call index of the frame that holds the argument values.
+ unsigned CallIndex;
+ /// The version of the parameters corresponding to this call.
+ unsigned Version;
+ };
- /// Parent - The caller of this stack frame.
- CallStackFrame *Caller;
+ /// A stack frame in the constexpr call stack.
+ class CallStackFrame : public interp::Frame {
+ public:
+ EvalInfo &Info;
- /// Callee - The function which was called.
- const FunctionDecl *Callee;
+ /// Parent - The caller of this stack frame.
+ CallStackFrame *Caller;
- /// This - The binding for the this pointer in this call, if any.
- const LValue *This;
+ /// Callee - The function which was called.
+ const FunctionDecl *Callee;
- /// CallExpr - The syntactical structure of member function calls
- const Expr *CallExpr;
+ /// This - The binding for the this pointer in this call, if any.
+ const LValue *This;
- /// Information on how to find the arguments to this call. Our arguments
- /// are stored in our parent's CallStackFrame, using the ParmVarDecl* as a
- /// key and this value as the version.
- CallRef Arguments;
+ /// CallExpr - The syntactical structure of member function calls
+ const Expr *CallExpr;
- /// Source location information about the default argument or default
- /// initializer expression we're evaluating, if any.
- CurrentSourceLocExprScope CurSourceLocExprScope;
+ /// Information on how to find the arguments to this call. Our arguments
+ /// are stored in our parent's CallStackFrame, using the ParmVarDecl* as a
+ /// key and this value as the version.
+ CallRef Arguments;
- // Note that we intentionally use std::map here so that references to
- // values are stable.
- typedef std::pair<const void *, unsigned> MapKeyTy;
- typedef std::map<MapKeyTy, APValue> MapTy;
- /// Temporaries - Temporary lvalues materialized within this stack frame.
- MapTy Temporaries;
+ /// Source location information about the default argument or default
+ /// initializer expression we're evaluating, if any.
+ CurrentSourceLocExprScope CurSourceLocExprScope;
- /// CallRange - The source range of the call expression for this call.
- SourceRange CallRange;
+ // Note that we intentionally use std::map here so that references to
+ // values are stable.
+ typedef std::pair<const void *, unsigned> MapKeyTy;
+ typedef std::map<MapKeyTy, APValue> MapTy;
+ /// Temporaries - Temporary lvalues materialized within this stack frame.
+ MapTy Temporaries;
- /// Index - The call index of this call.
- unsigned Index;
+ /// CallRange - The source range of the call expression for this call.
+ SourceRange CallRange;
- /// The stack of integers for tracking version numbers for temporaries.
- SmallVector<unsigned, 2> TempVersionStack = {1};
- unsigned CurTempVersion = TempVersionStack.back();
+ /// Index - The call index of this call.
+ unsigned Index;
- unsigned getTempVersion() const { return TempVersionStack.back(); }
+ /// The stack of integers for tracking version numbers for temporaries.
+ SmallVector<unsigned, 2> TempVersionStack = {1};
+ unsigned CurTempVersion = TempVersionStack.back();
- void pushTempVersion() { TempVersionStack.push_back(++CurTempVersion); }
+ unsigned getTempVersion() const { return TempVersionStack.back(); }
- void popTempVersion() { TempVersionStack.pop_back(); }
+ void pushTempVersion() {
+ TempVersionStack.push_back(++CurTempVersion);
+ }
- CallRef createCall(const FunctionDecl *Callee) {
- return {Callee, Index, ++CurTempVersion};
- }
+ void popTempVersion() {
+ TempVersionStack.pop_back();
+ }
- // FIXME: Adding this to every 'CallStackFrame' may have a nontrivial impact
- // on the overall stack usage of deeply-recursing constexpr evaluations.
- // (We should cache this map rather than recomputing it repeatedly.)
- // But let's try this and see how it goes; we can look into caching the map
- // as a later change.
+ CallRef createCall(const FunctionDecl *Callee) {
+ return {Callee, Index, ++CurTempVersion};
+ }
- /// LambdaCaptureFields - Mapping from captured variables/this to
- /// corresponding data members in the closure class.
- llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
- FieldDecl *LambdaThisCaptureField = nullptr;
+ // FIXME: Adding this to every 'CallStackFrame' may have a nontrivial impact
+ // on the overall stack usage of deeply-recursing constexpr evaluations.
+ // (We should cache this map rather than recomputing it repeatedly.)
+ // But let's try this and see how it goes; we can look into caching the map
+ // as a later change.
- CallStackFrame(EvalInfo &Info, SourceRange CallRange,
- const FunctionDecl *Callee, const LValue *This,
- const Expr *CallExpr, CallRef Arguments);
- ~CallStackFrame();
+ /// LambdaCaptureFields - Mapping from captured variables/this to
+ /// corresponding data members in the closure class.
+ llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
+ FieldDecl *LambdaThisCaptureField = nullptr;
- // Return the temporary for Key whose version number is Version.
- APValue *getTemporary(const void *Key, unsigned Version) {
- MapKeyTy KV(Key, Version);
- auto LB = Temporaries.lower_bound(KV);
- if (LB != Temporaries.end() && LB->first == KV)
- return &LB->second;
- return nullptr;
- }
+ CallStackFrame(EvalInfo &Info, SourceRange CallRange,
+ const FunctionDecl *Callee, const LValue *This,
+ const Expr *CallExpr, CallRef Arguments);
+ ~CallStackFrame();
- // Return the current temporary for Key in the map.
- APValue *getCurrentTemporary(const void *Key) {
- auto UB = Temporaries.upper_bound(MapKeyTy(Key, UINT_MAX));
- if (UB != Temporaries.begin() && std::prev(UB)->first.first == Key)
- return &std::prev(UB)->second;
- return nullptr;
- }
+ // Return the temporary for Key whose version number is Version.
+ APValue *getTemporary(const void *Key, unsigned Version) {
+ MapKeyTy KV(Key, Version);
+ auto LB = Temporaries.lower_bound(KV);
+ if (LB != Temporaries.end() && LB->first == KV)
+ return &LB->second;
+ return nullptr;
+ }
- // Return the version number of the current temporary for Key.
- unsigned getCurrentTemporaryVersion(const void *Key) const {
- auto UB = Temporaries.upper_bound(MapKeyTy(Key, UINT_MAX));
- if (UB != Temporaries.begin() && std::prev(UB)->first.first == Key)
- return std::prev(UB)->first.second;
- return 0;
- }
+ // Return the current temporary for Key in the map.
+ APValue *getCurrentTemporary(const void *Key) {
+ auto UB = Temporaries.upper_bound(MapKeyTy(Key, UINT_MAX));
+ if (UB != Temporaries.begin() && std::prev(UB)->first.first == Key)
+ return &std::prev(UB)->second;
+ return nullptr;
+ }
- /// Allocate storage for an object of type T in this stack frame.
- /// Populates LV with a handle to the created object. Key identifies
- /// the temporary within the stack frame, and must not be reused without
- /// bumping the temporary version number.
- template <typename KeyT>
- APValue &createTemporary(const KeyT *Key, QualType T, ScopeKind Scope,
- LValue &LV);
+ // Return the version number of the current temporary for Key.
+ unsigned getCurrentTemporaryVersion(const void *Key) const {
+ auto UB = Temporaries.upper_bound(MapKeyTy(Key, UINT_MAX));
+ if (UB != Temporaries.begin() && std::prev(UB)->first.first == Key)
+ return std::prev(UB)->first.second;
+ return 0;
+ }
- /// Allocate storage for a parameter of a function call made in this frame.
- APValue &createParam(CallRef Args, const ParmVarDecl *PVD, LValue &LV);
+ /// Allocate storage for an object of type T in this stack frame.
+ /// Populates LV with a handle to the created object. Key identifies
+ /// the temporary within the stack frame, and must not be reused without
+ /// bumping the temporary version number.
+ template<typename KeyT>
+ APValue &createTemporary(const KeyT *Key, QualType T,
+ ScopeKind Scope, LValue &LV);
- void describe(llvm::raw_ostream &OS) const override;
+ /// Allocate storage for a parameter of a function call made in this frame.
+ APValue &createParam(CallRef Args, const ParmVarDecl *PVD, LValue &LV);
- Frame *getCaller() const override { return Caller; }
- SourceRange getCallRange() const override { return CallRange; }
- const FunctionDecl *getCallee() const override { return Callee; }
+ void describe(llvm::raw_ostream &OS) const override;
- bool isStdFunction() const {
- for (const DeclContext *DC = Callee; DC; DC = DC->getParent())
- if (DC->isStdNamespace())
- return true;
- return false;
- }
+ Frame *getCaller() const override { return Caller; }
+ SourceRange getCallRange() const override { return CallRange; }
+ const FunctionDecl *getCallee() const override { return Callee; }
- /// Whether we're in a context where [[msvc::constexpr]] evaluation is
- /// permitted. See MSConstexprDocs for description of permitted contexts.
- bool CanEvalMSConstexpr = false;
+ bool isStdFunction() const {
+ for (const DeclContext *DC = Callee; DC; DC = DC->getParent())
+ if (DC->isStdNamespace())
+ return true;
+ return false;
+ }
-private:
- APValue &createLocal(APValue::LValueBase Base, const void *Key, QualType T,
- ScopeKind Scope);
-};
+ /// Whether we're in a context where [[msvc::constexpr]] evaluation is
+ /// permitted. See MSConstexprDocs for description of permitted contexts.
+ bool CanEvalMSConstexpr = false;
-/// Temporarily override 'this'.
-class ThisOverrideRAII {
-public:
- ThisOverrideRAII(CallStackFrame &Frame, const LValue *NewThis, bool Enable)
- : Frame(Frame), OldThis(Frame.This) {
- if (Enable)
- Frame.This = NewThis;
- }
- ~ThisOverrideRAII() { Frame.This = OldThis; }
+ private:
+ APValue &createLocal(APValue::LValueBase Base, const void *Key, QualType T,
+ ScopeKind Scope);
+ };
-private:
- CallStackFrame &Frame;
- const LValue *OldThis;
-};
+ /// Temporarily override 'this'.
+ class ThisOverrideRAII {
+ public:
+ ThisOverrideRAII(CallStackFrame &Frame, const LValue *NewThis, bool Enable)
+ : Frame(Frame), OldThis(Frame.This) {
+ if (Enable)
+ Frame.This = NewThis;
+ }
+ ~ThisOverrideRAII() {
+ Frame.This = OldThis;
+ }
+ private:
+ CallStackFrame &Frame;
+ const LValue *OldThis;
+ };
-// A shorthand time trace scope struct, prints source range, for example
-// {"name":"EvaluateAsRValue","args":{"detail":"<test.cc:8:21, col:25>"}}}
-class ExprTimeTraceScope {
-public:
- ExprTimeTraceScope(const Expr *E, const ASTContext &Ctx, StringRef Name)
- : TimeScope(Name, [E, &Ctx] {
- return E->getSourceRange().printToString(Ctx.getSourceManager());
- }) {}
+ // A shorthand time trace scope struct, prints source range, for example
+ // {"name":"EvaluateAsRValue","args":{"detail":"<test.cc:8:21, col:25>"}}}
+ class ExprTimeTraceScope {
+ public:
+ ExprTimeTraceScope(const Expr *E, const ASTContext &Ctx, StringRef Name)
+ : TimeScope(Name, [E, &Ctx] {
+ return E->getSourceRange().printToString(Ctx.getSourceManager());
+ }) {}
-private:
- llvm::TimeTraceScope TimeScope;
-};
+ private:
+ llvm::TimeTraceScope TimeScope;
+ };
-/// RAII object used to change the current ability of
-/// [[msvc::constexpr]] evaulation.
-struct MSConstexprContextRAII {
- CallStackFrame &Frame;
- bool OldValue;
- explicit MSConstexprContextRAII(CallStackFrame &Frame, bool Value)
- : Frame(Frame), OldValue(Frame.CanEvalMSConstexpr) {
- Frame.CanEvalMSConstexpr = Value;
- }
+ /// RAII object used to change the current ability of
+ /// [[msvc::constexpr]] evaulation.
+ struct MSConstexprContextRAII {
+ CallStackFrame &Frame;
+ bool OldValue;
+ explicit MSConstexprContextRAII(CallStackFrame &Frame, bool Value)
+ : Frame(Frame), OldValue(Frame.CanEvalMSConstexpr) {
+ Frame.CanEvalMSConstexpr = Value;
+ }
- ~MSConstexprContextRAII() { Frame.CanEvalMSConstexpr = OldValue; }
-};
-} // namespace
+ ~MSConstexprContextRAII() { Frame.CanEvalMSConstexpr = OldValue; }
+ };
+}
-static bool HandleDestruction(EvalInfo &Info, const Expr *E, const LValue &This,
- QualType ThisType);
+static bool HandleDestruction(EvalInfo &Info, const Expr *E,
+ const LValue &This, QualType ThisType);
static bool HandleDestruction(EvalInfo &Info, SourceLocation Loc,
APValue::LValueBase LVBase, APValue &Value,
QualType T);
namespace {
-/// A cleanup, and a flag indicating whether it is lifetime-extended.
-class Cleanup {
- llvm::PointerIntPair<APValue *, 2, ScopeKind> Value;
- APValue::LValueBase Base;
- QualType T;
+ /// A cleanup, and a flag indicating whether it is lifetime-extended.
+ class Cleanup {
+ llvm::PointerIntPair<APValue*, 2, ScopeKind> Value;
+ APValue::LValueBase Base;
+ QualType T;
-public:
- Cleanup(APValue *Val, APValue::LValueBase Base, QualType T, ScopeKind Scope)
- : Value(Val, Scope), Base(Base), T(T) {}
-
- /// Determine whether this cleanup should be performed at the end of the
- /// given kind of scope.
- bool isDestroyedAtEndOf(ScopeKind K) const {
- return (int)Value.getInt() >= (int)K;
- }
- bool endLifetime(EvalInfo &Info, bool RunDestructors) {
- if (RunDestructors) {
- SourceLocation Loc;
- if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl *>())
- Loc = VD->getLocation();
- else if (const Expr *E = Base.dyn_cast<const Expr *>())
- Loc = E->getExprLoc();
- return HandleDestruction(Info, Loc, Base, *Value.getPointer(), T);
- }
- *Value.getPointer() = APValue();
- return true;
- }
+ public:
+ Cleanup(APValue *Val, APValue::LValueBase Base, QualType T,
+ ScopeKind Scope)
+ : Value(Val, Scope), Base(Base), T(T) {}
+
+ /// Determine whether this cleanup should be performed at the end of the
+ /// given kind of scope.
+ bool isDestroyedAtEndOf(ScopeKind K) const {
+ return (int)Value.getInt() >= (int)K;
+ }
+ bool endLifetime(EvalInfo &Info, bool RunDestructors) {
+ if (RunDestructors) {
+ SourceLocation Loc;
+ if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>())
+ Loc = VD->getLocation();
+ else if (const Expr *E = Base.dyn_cast<const Expr*>())
+ Loc = E->getExprLoc();
+ return HandleDestruction(Info, Loc, Base, *Value.getPointer(), T);
+ }
+ *Value.getPointer() = APValue();
+ return true;
+ }
- bool hasSideEffect() { return T.isDestructedType(); }
-};
+ bool hasSideEffect() {
+ return T.isDestructedType();
+ }
+ };
-/// A reference to an object whose construction we are currently evaluating.
-struct ObjectUnderConstruction {
- APValue::LValueBase Base;
- ArrayRef<APValue::LValuePathEntry> Path;
- friend bool operator==(const ObjectUnderConstruction &LHS,
- const ObjectUnderConstruction &RHS) {
- return LHS.Base == RHS.Base && LHS.Path == RHS.Path;
- }
- friend llvm::hash_code hash_value(const ObjectUnderConstruction &Obj) {
- return llvm::hash_combine(Obj.Base, Obj.Path);
- }
-};
-enum class ConstructionPhase {
- None,
- Bases,
- AfterBases,
- AfterFields,
- Destroying,
- DestroyingBases
-};
-} // namespace
+ /// A reference to an object whose construction we are currently evaluating.
+ struct ObjectUnderConstruction {
+ APValue::LValueBase Base;
+ ArrayRef<APValue::LValuePathEntry> Path;
+ friend bool operator==(const ObjectUnderConstruction &LHS,
+ const ObjectUnderConstruction &RHS) {
+ return LHS.Base == RHS.Base && LHS.Path == RHS.Path;
+ }
+ friend llvm::hash_code hash_value(const ObjectUnderConstruction &Obj) {
+ return llvm::hash_combine(Obj.Base, Obj.Path);
+ }
+ };
+ enum class ConstructionPhase {
+ None,
+ Bases,
+ AfterBases,
+ AfterFields,
+ Destroying,
+ DestroyingBases
+ };
+}
namespace llvm {
-template <> struct DenseMapInfo<ObjectUnderConstruction> {
+template<> struct DenseMapInfo<ObjectUnderConstruction> {
using Base = DenseMapInfo<APValue::LValueBase>;
static ObjectUnderConstruction getEmptyKey() {
- return {Base::getEmptyKey(), {}};
- }
+ return {Base::getEmptyKey(), {}}; }
static ObjectUnderConstruction getTombstoneKey() {
return {Base::getTombstoneKey(), {}};
}
@@ -729,641 +745,651 @@ template <> struct DenseMapInfo<ObjectUnderConstruction> {
return LHS == RHS;
}
};
-} // namespace llvm
+}
namespace {
-/// A dynamically-allocated heap object.
-struct DynAlloc {
- /// The value of this heap-allocated object.
- APValue Value;
- /// The allocating expression; used for diagnostics. Either a CXXNewExpr
- /// or a CallExpr (the latter is for direct calls to operator new inside
- /// std::allocator<T>::allocate).
- const Expr *AllocExpr = nullptr;
-
- enum Kind { New, ArrayNew, StdAllocator };
-
- /// Get the kind of the allocation. This must match between allocation
- /// and deallocation.
- Kind getKind() const {
- if (auto *NE = dyn_cast<CXXNewExpr>(AllocExpr))
- return NE->isArray() ? ArrayNew : New;
- assert(isa<CallExpr>(AllocExpr));
- return StdAllocator;
- }
-};
+ /// A dynamically-allocated heap object.
+ struct DynAlloc {
+ /// The value of this heap-allocated object.
+ APValue Value;
+ /// The allocating expression; used for diagnostics. Either a CXXNewExpr
+ /// or a CallExpr (the latter is for direct calls to operator new inside
+ /// std::allocator<T>::allocate).
+ const Expr *AllocExpr = nullptr;
+
+ enum Kind {
+ New,
+ ArrayNew,
+ StdAllocator
+ };
-struct DynAllocOrder {
- bool operator()(DynamicAllocLValue L, DynamicAllocLValue R) const {
- return L.getIndex() < R.getIndex();
- }
-};
+ /// Get the kind of the allocation. This must match between allocation
+ /// and deallocation.
+ Kind getKind() const {
+ if (auto *NE = dyn_cast<CXXNewExpr>(AllocExpr))
+ return NE->isArray() ? ArrayNew : New;
+ assert(isa<CallExpr>(AllocExpr));
+ return StdAllocator;
+ }
+ };
-/// EvalInfo - This is a private struct used by the evaluator to capture
-/// information about a subexpression as it is folded. It retains information
-/// about the AST context, but also maintains information about the folded
-/// expression.
-///
-/// If an expression could be evaluated, it is still possible it is not a C
-/// "integer constant expression" or constant expression. If not, this struct
-/// captures information about how and why not.
-///
-/// One bit of information passed *into* the request for constant folding
-/// indicates whether the subexpression is "evaluated" or not according to C
-/// rules. For example, the RHS of (0 && foo()) is not evaluated. We can
-/// evaluate the expression regardless of what the RHS is, but C only allows
-/// certain things in certain situations.
-class EvalInfo : public interp::State {
-public:
- ASTContext &Ctx;
+ struct DynAllocOrder {
+ bool operator()(DynamicAllocLValue L, DynamicAllocLValue R) const {
+ return L.getIndex() < R.getIndex();
+ }
+ };
- /// EvalStatus - Contains information about the evaluation.
- Expr::EvalStatus &EvalStatus;
+ /// EvalInfo - This is a private struct used by the evaluator to capture
+ /// information about a subexpression as it is folded. It retains information
+ /// about the AST context, but also maintains information about the folded
+ /// expression.
+ ///
+ /// If an expression could be evaluated, it is still possible it is not a C
+ /// "integer constant expression" or constant expression. If not, this struct
+ /// captures information about how and why not.
+ ///
+ /// One bit of information passed *into* the request for constant folding
+ /// indicates whether the subexpression is "evaluated" or not according to C
+ /// rules. For example, the RHS of (0 && foo()) is not evaluated. We can
+ /// evaluate the expression regardless of what the RHS is, but C only allows
+ /// certain things in certain situations.
+ class EvalInfo : public interp::State {
+ public:
+ ASTContext &Ctx;
- /// CurrentCall - The top of the constexpr call stack.
- CallStackFrame *CurrentCall;
+ /// EvalStatus - Contains information about the evaluation.
+ Expr::EvalStatus &EvalStatus;
- /// CallStackDepth - The number of calls in the call stack right now.
- unsigned CallStackDepth;
+ /// CurrentCall - The top of the constexpr call stack.
+ CallStackFrame *CurrentCall;
- /// NextCallIndex - The next call index to assign.
- unsigned NextCallIndex;
+ /// CallStackDepth - The number of calls in the call stack right now.
+ unsigned CallStackDepth;
- /// StepsLeft - The remaining number of evaluation steps we're permitted
- /// to perform. This is essentially a limit for the number of statements
- /// we will evaluate.
- unsigned StepsLeft;
+ /// NextCallIndex - The next call index to assign.
+ unsigned NextCallIndex;
- /// Enable the experimental new constant interpreter. If an expression is
- /// not supported by the interpreter, an error is triggered.
- bool EnableNewConstInterp;
+ /// StepsLeft - The remaining number of evaluation steps we're permitted
+ /// to perform. This is essentially a limit for the number of statements
+ /// we will evaluate.
+ unsigned StepsLeft;
- /// BottomFrame - The frame in which evaluation started. This must be
- /// initialized after CurrentCall and CallStackDepth.
- CallStackFrame BottomFrame;
+ /// Enable the experimental new constant interpreter. If an expression is
+ /// not supported by the interpreter, an error is triggered.
+ bool EnableNewConstInterp;
- /// A stack of values whose lifetimes end at the end of some surrounding
- /// evaluation frame.
- llvm::SmallVector<Cleanup, 16> CleanupStack;
+ /// BottomFrame - The frame in which evaluation started. This must be
+ /// initialized after CurrentCall and CallStackDepth.
+ CallStackFrame BottomFrame;
- /// EvaluatingDecl - This is the declaration whose initializer is being
- /// evaluated, if any.
- APValue::LValueBase EvaluatingDecl;
+ /// A stack of values whose lifetimes end at the end of some surrounding
+ /// evaluation frame.
+ llvm::SmallVector<Cleanup, 16> CleanupStack;
- enum class EvaluatingDeclKind {
- None,
- /// We're evaluating the construction of EvaluatingDecl.
- Ctor,
- /// We're evaluating the destruction of EvaluatingDecl.
- Dtor,
- };
- EvaluatingDeclKind IsEvaluatingDecl = EvaluatingDeclKind::None;
-
- /// EvaluatingDeclValue - This is the value being constructed for the
- /// declaration whose initializer is being evaluated, if any.
- APValue *EvaluatingDeclValue;
-
- /// Stack of loops and 'switch' statements which we're currently
- /// breaking/continuing; null entries are used to mark unlabeled
- /// break/continue.
- SmallVector<const Stmt *> BreakContinueStack;
-
- /// Set of objects that are currently being constructed.
- llvm::DenseMap<ObjectUnderConstruction, ConstructionPhase>
- ObjectsUnderConstruction;
-
- /// Current heap allocations, along with the location where each was
- /// allocated. We use std::map here because we need stable addresses
- /// for the stored APValues.
- std::map<DynamicAllocLValue, DynAlloc, DynAllocOrder> HeapAllocs;
-
- /// The number of heap allocations performed so far in this evaluation.
- unsigned NumHeapAllocs = 0;
-
- struct EvaluatingConstructorRAII {
- EvalInfo &EI;
- ObjectUnderConstruction Object;
- bool DidInsert;
- EvaluatingConstructorRAII(EvalInfo &EI, ObjectUnderConstruction Object,
- bool HasBases)
- : EI(EI), Object(Object) {
- DidInsert =
- EI.ObjectsUnderConstruction
- .insert({Object, HasBases ? ConstructionPhase::Bases
- : ConstructionPhase::AfterBases})
- .second;
- }
- void finishedConstructingBases() {
- EI.ObjectsUnderConstruction[Object] = ConstructionPhase::AfterBases;
- }
- void finishedConstructingFields() {
- EI.ObjectsUnderConstruction[Object] = ConstructionPhase::AfterFields;
- }
- ~EvaluatingConstructorRAII() {
- if (DidInsert)
- EI.ObjectsUnderConstruction.erase(Object);
- }
- };
+ /// EvaluatingDecl - This is the declaration whose initializer is being
+ /// evaluated, if any.
+ APValue::LValueBase EvaluatingDecl;
- struct EvaluatingDestructorRAII {
- EvalInfo &EI;
- ObjectUnderConstruction Object;
- bool DidInsert;
- EvaluatingDestructorRAII(EvalInfo &EI, ObjectUnderConstruction Object)
- : EI(EI), Object(Object) {
- DidInsert = EI.ObjectsUnderConstruction
- .insert({Object, ConstructionPhase::Destroying})
- .second;
- }
- void startedDestroyingBases() {
- EI.ObjectsUnderConstruction[Object] = ConstructionPhase::DestroyingBases;
- }
- ~EvaluatingDestructorRAII() {
- if (DidInsert)
- EI.ObjectsUnderConstruction.erase(Object);
- }
- };
+ enum class EvaluatingDeclKind {
+ None,
+ /// We're evaluating the construction of EvaluatingDecl.
+ Ctor,
+ /// We're evaluating the destruction of EvaluatingDecl.
+ Dtor,
+ };
+ EvaluatingDeclKind IsEvaluatingDecl = EvaluatingDeclKind::None;
+
+ /// EvaluatingDeclValue - This is the value being constructed for the
+ /// declaration whose initializer is being evaluated, if any.
+ APValue *EvaluatingDeclValue;
+
+ /// Stack of loops and 'switch' statements which we're currently
+ /// breaking/continuing; null entries are used to mark unlabeled
+ /// break/continue.
+ SmallVector<const Stmt *> BreakContinueStack;
+
+ /// Set of objects that are currently being constructed.
+ llvm::DenseMap<ObjectUnderConstruction, ConstructionPhase>
+ ObjectsUnderConstruction;
+
+ /// Current heap allocations, along with the location where each was
+ /// allocated. We use std::map here because we need stable addresses
+ /// for the stored APValues.
+ std::map<DynamicAllocLValue, DynAlloc, DynAllocOrder> HeapAllocs;
+
+ /// The number of heap allocations performed so far in this evaluation.
+ unsigned NumHeapAllocs = 0;
+
+ struct EvaluatingConstructorRAII {
+ EvalInfo &EI;
+ ObjectUnderConstruction Object;
+ bool DidInsert;
+ EvaluatingConstructorRAII(EvalInfo &EI, ObjectUnderConstruction Object,
+ bool HasBases)
+ : EI(EI), Object(Object) {
+ DidInsert =
+ EI.ObjectsUnderConstruction
+ .insert({Object, HasBases ? ConstructionPhase::Bases
+ : ConstructionPhase::AfterBases})
+ .second;
+ }
+ void finishedConstructingBases() {
+ EI.ObjectsUnderConstruction[Object] = ConstructionPhase::AfterBases;
+ }
+ void finishedConstructingFields() {
+ EI.ObjectsUnderConstruction[Object] = ConstructionPhase::AfterFields;
+ }
+ ~EvaluatingConstructorRAII() {
+ if (DidInsert) EI.ObjectsUnderConstruction.erase(Object);
+ }
+ };
- ConstructionPhase
- isEvaluatingCtorDtor(APValue::LValueBase Base,
- ArrayRef<APValue::LValuePathEntry> Path) {
- return ObjectsUnderConstruction.lookup({Base, Path});
- }
+ struct EvaluatingDestructorRAII {
+ EvalInfo &EI;
+ ObjectUnderConstruction Object;
+ bool DidInsert;
+ EvaluatingDestructorRAII(EvalInfo &EI, ObjectUnderConstruction Object)
+ : EI(EI), Object(Object) {
+ DidInsert = EI.ObjectsUnderConstruction
+ .insert({Object, ConstructionPhase::Destroying})
+ .second;
+ }
+ void startedDestroyingBases() {
+ EI.ObjectsUnderConstruction[Object] =
+ ConstructionPhase::DestroyingBases;
+ }
+ ~EvaluatingDestructorRAII() {
+ if (DidInsert)
+ EI.ObjectsUnderConstruction.erase(Object);
+ }
+ };
- /// If we're currently speculatively evaluating, the outermost call stack
- /// depth at which we can mutate state, otherwise 0.
- unsigned SpeculativeEvaluationDepth = 0;
+ ConstructionPhase
+ isEvaluatingCtorDtor(APValue::LValueBase Base,
+ ArrayRef<APValue::LValuePathEntry> Path) {
+ return ObjectsUnderConstruction.lookup({Base, Path});
+ }
- /// The current array initialization index, if we're performing array
- /// initialization.
- uint64_t ArrayInitIndex = -1;
+ /// If we're currently speculatively evaluating, the outermost call stack
+ /// depth at which we can mutate state, otherwise 0.
+ unsigned SpeculativeEvaluationDepth = 0;
- /// HasActiveDiagnostic - Was the previous diagnostic stored? If so, further
- /// notes attached to it will also be stored, otherwise they will not be.
- bool HasActiveDiagnostic;
+ /// The current array initialization index, if we're performing array
+ /// initialization.
+ uint64_t ArrayInitIndex = -1;
- /// Have we emitted a diagnostic explaining why we couldn't constant
- /// fold (not just why it's not strictly a constant expression)?
- bool HasFoldFailureDiagnostic;
+ /// HasActiveDiagnostic - Was the previous diagnostic stored? If so, further
+ /// notes attached to it will also be stored, otherwise they will not be.
+ bool HasActiveDiagnostic;
- EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode)
- : Ctx(const_cast<ASTContext &>(C)), EvalStatus(S), CurrentCall(nullptr),
- CallStackDepth(0), NextCallIndex(1),
- StepsLeft(C.getLangOpts().ConstexprStepLimit),
- EnableNewConstInterp(C.getLangOpts().EnableNewConstInterp),
- BottomFrame(*this, SourceLocation(), /*Callee=*/nullptr,
- /*This=*/nullptr,
- /*CallExpr=*/nullptr, CallRef()),
- EvaluatingDecl((const ValueDecl *)nullptr),
- EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
- HasFoldFailureDiagnostic(false) {
- EvalMode = Mode;
- }
+ /// Have we emitted a diagnostic explaining why we couldn't constant
+ /// fold (not just why it's not strictly a constant expression)?
+ bool HasFoldFailureDiagnostic;
- ~EvalInfo() { discardCleanups(); }
+ EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode)
+ : Ctx(const_cast<ASTContext &>(C)), EvalStatus(S), CurrentCall(nullptr),
+ CallStackDepth(0), NextCallIndex(1),
+ StepsLeft(C.getLangOpts().ConstexprStepLimit),
+ EnableNewConstInterp(C.getLangOpts().EnableNewConstInterp),
+ BottomFrame(*this, SourceLocation(), /*Callee=*/nullptr,
+ /*This=*/nullptr,
+ /*CallExpr=*/nullptr, CallRef()),
+ EvaluatingDecl((const ValueDecl *)nullptr),
+ EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
+ HasFoldFailureDiagnostic(false) {
+ EvalMode = Mode;
+ }
- ASTContext &getASTContext() const override { return Ctx; }
- const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); }
+ ~EvalInfo() {
+ discardCleanups();
+ }
- void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value,
- EvaluatingDeclKind EDK = EvaluatingDeclKind::Ctor) {
- EvaluatingDecl = Base;
- IsEvaluatingDecl = EDK;
- EvaluatingDeclValue = &Value;
- }
+ ASTContext &getASTContext() const override { return Ctx; }
+ const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); }
- bool CheckCallLimit(SourceLocation Loc) {
- // Don't perform any constexpr calls (other than the call we're checking)
- // when checking a potential constant expression.
- if (checkingPotentialConstantExpression() && CallStackDepth > 1)
- return false;
- if (NextCallIndex == 0) {
- // NextCallIndex has wrapped around.
- FFDiag(Loc, diag::note_constexpr_call_limit_exceeded);
- return false;
+ void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value,
+ EvaluatingDeclKind EDK = EvaluatingDeclKind::Ctor) {
+ EvaluatingDecl = Base;
+ IsEvaluatingDecl = EDK;
+ EvaluatingDeclValue = &Value;
}
- if (CallStackDepth <= getLangOpts().ConstexprCallDepth)
- return true;
- FFDiag(Loc, diag::note_constexpr_depth_limit_exceeded)
- << getLangOpts().ConstexprCallDepth;
- return false;
- }
- bool CheckArraySize(SourceLocation Loc, unsigned BitWidth, uint64_t ElemCount,
- bool Diag) {
- // FIXME: GH63562
- // APValue stores array extents as unsigned,
- // so anything that is greater that unsigned would overflow when
- // constructing the array, we catch this here.
- if (BitWidth > ConstantArrayType::getMaxSizeBits(Ctx) ||
- ElemCount > uint64_t(std::numeric_limits<unsigned>::max())) {
- if (Diag)
- FFDiag(Loc, diag::note_constexpr_new_too_large) << ElemCount;
+ bool CheckCallLimit(SourceLocation Loc) {
+ // Don't perform any constexpr calls (other than the call we're checking)
+ // when checking a potential constant expression.
+ if (checkingPotentialConstantExpression() && CallStackDepth > 1)
+ return false;
+ if (NextCallIndex == 0) {
+ // NextCallIndex has wrapped around.
+ FFDiag(Loc, diag::note_constexpr_call_limit_exceeded);
+ return false;
+ }
+ if (CallStackDepth <= getLangOpts().ConstexprCallDepth)
+ return true;
+ FFDiag(Loc, diag::note_constexpr_depth_limit_exceeded)
+ << getLangOpts().ConstexprCallDepth;
return false;
}
- // FIXME: GH63562
- // Arrays allocate an APValue per element.
- // We use the number of constexpr steps as a proxy for the maximum size
- // of arrays to avoid exhausting the system resources, as initialization
- // of each element is likely to take some number of steps anyway.
- uint64_t Limit = Ctx.getLangOpts().ConstexprStepLimit;
- if (ElemCount > Limit) {
- if (Diag)
- FFDiag(Loc, diag::note_constexpr_new_exceeds_limits)
- << ElemCount << Limit;
- return false;
+ bool CheckArraySize(SourceLocation Loc, unsigned BitWidth,
+ uint64_t ElemCount, bool Diag) {
+ // FIXME: GH63562
+ // APValue stores array extents as unsigned,
+ // so anything that is greater that unsigned would overflow when
+ // constructing the array, we catch this here.
+ if (BitWidth > ConstantArrayType::getMaxSizeBits(Ctx) ||
+ ElemCount > uint64_t(std::numeric_limits<unsigned>::max())) {
+ if (Diag)
+ FFDiag(Loc, diag::note_constexpr_new_too_large) << ElemCount;
+ return false;
+ }
+
+ // FIXME: GH63562
+ // Arrays allocate an APValue per element.
+ // We use the number of constexpr steps as a proxy for the maximum size
+ // of arrays to avoid exhausting the system resources, as initialization
+ // of each element is likely to take some number of steps anyway.
+ uint64_t Limit = Ctx.getLangOpts().ConstexprStepLimit;
+ if (ElemCount > Limit) {
+ if (Diag)
+ FFDiag(Loc, diag::note_constexpr_new_exceeds_limits)
+ << ElemCount << Limit;
+ return false;
+ }
+ return true;
}
- return true;
- }
- std::pair<CallStackFrame *, unsigned>
- getCallFrameAndDepth(unsigned CallIndex) {
- assert(CallIndex && "no call index in getCallFrameAndDepth");
- // We will eventually hit BottomFrame, which has Index 1, so Frame can't
- // be null in this loop.
- unsigned Depth = CallStackDepth;
- CallStackFrame *Frame = CurrentCall;
- while (Frame->Index > CallIndex) {
- Frame = Frame->Caller;
- --Depth;
+ std::pair<CallStackFrame *, unsigned>
+ getCallFrameAndDepth(unsigned CallIndex) {
+ assert(CallIndex && "no call index in getCallFrameAndDepth");
+ // We will eventually hit BottomFrame, which has Index 1, so Frame can't
+ // be null in this loop.
+ unsigned Depth = CallStackDepth;
+ CallStackFrame *Frame = CurrentCall;
+ while (Frame->Index > CallIndex) {
+ Frame = Frame->Caller;
+ --Depth;
+ }
+ if (Frame->Index == CallIndex)
+ return {Frame, Depth};
+ return {nullptr, 0};
}
- if (Frame->Index == CallIndex)
- return {Frame, Depth};
- return {nullptr, 0};
- }
- bool nextStep(const Stmt *S) {
- if (!StepsLeft) {
- FFDiag(S->getBeginLoc(), diag::note_constexpr_step_limit_exceeded);
- return false;
+ bool nextStep(const Stmt *S) {
+ if (!StepsLeft) {
+ FFDiag(S->getBeginLoc(), diag::note_constexpr_step_limit_exceeded);
+ return false;
+ }
+ --StepsLeft;
+ return true;
}
- --StepsLeft;
- return true;
- }
- APValue *createHeapAlloc(const Expr *E, QualType T, LValue &LV);
+ APValue *createHeapAlloc(const Expr *E, QualType T, LValue &LV);
- std::optional<DynAlloc *> lookupDynamicAlloc(DynamicAllocLValue DA) {
- std::optional<DynAlloc *> Result;
- auto It = HeapAllocs.find(DA);
- if (It != HeapAllocs.end())
- Result = &It->second;
- return Result;
- }
+ std::optional<DynAlloc *> lookupDynamicAlloc(DynamicAllocLValue DA) {
+ std::optional<DynAlloc *> Result;
+ auto It = HeapAllocs.find(DA);
+ if (It != HeapAllocs.end())
+ Result = &It->second;
+ return Result;
+ }
- /// Get the allocated storage for the given parameter of the given call.
- APValue *getParamSlot(CallRef Call, const ParmVarDecl *PVD) {
- CallStackFrame *Frame = getCallFrameAndDepth(Call.CallIndex).first;
- return Frame ? Frame->getTemporary(Call.getOrigParam(PVD), Call.Version)
- : nullptr;
- }
+ /// Get the allocated storage for the given parameter of the given call.
+ APValue *getParamSlot(CallRef Call, const ParmVarDecl *PVD) {
+ CallStackFrame *Frame = getCallFrameAndDepth(Call.CallIndex).first;
+ return Frame ? Frame->getTemporary(Call.getOrigParam(PVD), Call.Version)
+ : nullptr;
+ }
- /// Information about a stack frame for std::allocator<T>::[de]allocate.
- struct StdAllocatorCaller {
- unsigned FrameIndex;
- QualType ElemType;
- const Expr *Call;
- explicit operator bool() const { return FrameIndex != 0; };
- };
+ /// Information about a stack frame for std::allocator<T>::[de]allocate.
+ struct StdAllocatorCaller {
+ unsigned FrameIndex;
+ QualType ElemType;
+ const Expr *Call;
+ explicit operator bool() const { return FrameIndex != 0; };
+ };
- StdAllocatorCaller getStdAllocatorCaller(StringRef FnName) const {
- for (const CallStackFrame *Call = CurrentCall; Call != &BottomFrame;
- Call = Call->Caller) {
- const auto *MD = dyn_cast_or_null<CXXMethodDecl>(Call->Callee);
- if (!MD)
- continue;
- const IdentifierInfo *FnII = MD->getIdentifier();
- if (!FnII || !FnII->isStr(FnName))
- continue;
+ StdAllocatorCaller getStdAllocatorCaller(StringRef FnName) const {
+ for (const CallStackFrame *Call = CurrentCall; Call != &BottomFrame;
+ Call = Call->Caller) {
+ const auto *MD = dyn_cast_or_null<CXXMethodDecl>(Call->Callee);
+ if (!MD)
+ continue;
+ const IdentifierInfo *FnII = MD->getIdentifier();
+ if (!FnII || !FnII->isStr(FnName))
+ continue;
- const auto *CTSD =
- dyn_cast<ClassTemplateSpecializationDecl>(MD->getParent());
- if (!CTSD)
- continue;
+ const auto *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(MD->getParent());
+ if (!CTSD)
+ continue;
- const IdentifierInfo *ClassII = CTSD->getIdentifier();
- const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
- if (CTSD->isInStdNamespace() && ClassII && ClassII->isStr("allocator") &&
- TAL.size() >= 1 && TAL[0].getKind() == TemplateArgument::Type)
- return {Call->Index, TAL[0].getAsType(), Call->CallExpr};
- }
+ const IdentifierInfo *ClassII = CTSD->getIdentifier();
+ const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
+ if (CTSD->isInStdNamespace() && ClassII &&
+ ClassII->isStr("allocator") && TAL.size() >= 1 &&
+ TAL[0].getKind() == TemplateArgument::Type)
+ return {Call->Index, TAL[0].getAsType(), Call->CallExpr};
+ }
- return {};
- }
+ return {};
+ }
- void performLifetimeExtension() {
- // Disable the cleanups for lifetime-extended temporaries.
- llvm::erase_if(CleanupStack, [](Cleanup &C) {
- return !C.isDestroyedAtEndOf(ScopeKind::FullExpression);
- });
- }
+ void performLifetimeExtension() {
+ // Disable the cleanups for lifetime-extended temporaries.
+ llvm::erase_if(CleanupStack, [](Cleanup &C) {
+ return !C.isDestroyedAtEndOf(ScopeKind::FullExpression);
+ });
+ }
- /// Throw away any remaining cleanups at the end of evaluation. If any
- /// cleanups would have had a side-effect, note that as an unmodeled
- /// side-effect and return false. Otherwise, return true.
- bool discardCleanups() {
- for (Cleanup &C : CleanupStack) {
- if (C.hasSideEffect() && !noteSideEffect()) {
- CleanupStack.clear();
- return false;
+ /// Throw away any remaining cleanups at the end of evaluation. If any
+ /// cleanups would have had a side-effect, note that as an unmodeled
+ /// side-effect and return false. Otherwise, return true.
+ bool discardCleanups() {
+ for (Cleanup &C : CleanupStack) {
+ if (C.hasSideEffect() && !noteSideEffect()) {
+ CleanupStack.clear();
+ return false;
+ }
}
+ CleanupStack.clear();
+ return true;
}
- CleanupStack.clear();
- return true;
- }
-private:
- interp::Frame *getCurrentFrame() override { return CurrentCall; }
- const interp::Frame *getBottomFrame() const override { return &BottomFrame; }
+ private:
+ interp::Frame *getCurrentFrame() override { return CurrentCall; }
+ const interp::Frame *getBottomFrame() const override { return &BottomFrame; }
- bool hasActiveDiagnostic() override { return HasActiveDiagnostic; }
- void setActiveDiagnostic(bool Flag) override { HasActiveDiagnostic = Flag; }
+ bool hasActiveDiagnostic() override { return HasActiveDiagnostic; }
+ void setActiveDiagnostic(bool Flag) override { HasActiveDiagnostic = Flag; }
- void setFoldFailureDiagnostic(bool Flag) override {
- HasFoldFailureDiagnostic = Flag;
- }
+ void setFoldFailureDiagnostic(bool Flag) override {
+ HasFoldFailureDiagnostic = Flag;
+ }
- Expr::EvalStatus &getEvalStatus() const override { return EvalStatus; }
+ Expr::EvalStatus &getEvalStatus() const override { return EvalStatus; }
- // If we have a prior diagnostic, it will be noting that the expression
- // isn't a constant expression. This diagnostic is more important,
- // unless we require this evaluation to produce a constant expression.
- //
- // FIXME: We might want to show both diagnostics to the user in
- // EvaluationMode::ConstantFold mode.
- bool hasPriorDiagnostic() override {
- if (!EvalStatus.Diag->empty()) {
+ // If we have a prior diagnostic, it will be noting that the expression
+ // isn't a constant expression. This diagnostic is more important,
+ // unless we require this evaluation to produce a constant expression.
+ //
+ // FIXME: We might want to show both diagnostics to the user in
+ // EvaluationMode::ConstantFold mode.
+ bool hasPriorDiagnostic() override {
+ if (!EvalStatus.Diag->empty()) {
+ switch (EvalMode) {
+ case EvaluationMode::ConstantFold:
+ case EvaluationMode::IgnoreSideEffects:
+ if (!HasFoldFailureDiagnostic)
+ break;
+ // We've already failed to fold something. Keep that diagnostic.
+ [[fallthrough]];
+ case EvaluationMode::ConstantExpression:
+ case EvaluationMode::ConstantExpressionUnevaluated:
+ setActiveDiagnostic(false);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ unsigned getCallStackDepth() override { return CallStackDepth; }
+
+ public:
+ /// Should we continue evaluation after encountering a side-effect that we
+ /// couldn't model?
+ bool keepEvaluatingAfterSideEffect() const override {
switch (EvalMode) {
- case EvaluationMode::ConstantFold:
case EvaluationMode::IgnoreSideEffects:
- if (!HasFoldFailureDiagnostic)
- break;
- // We've already failed to fold something. Keep that diagnostic.
- [[fallthrough]];
+ return true;
+
case EvaluationMode::ConstantExpression:
case EvaluationMode::ConstantExpressionUnevaluated:
- setActiveDiagnostic(false);
- return true;
+ case EvaluationMode::ConstantFold:
+ // By default, assume any side effect might be valid in some other
+ // evaluation of this expression from a different context.
+ return checkingPotentialConstantExpression() ||
+ checkingForUndefinedBehavior();
}
+ llvm_unreachable("Missed EvalMode case");
}
- return false;
- }
-
- unsigned getCallStackDepth() override { return CallStackDepth; }
-public:
- /// Should we continue evaluation after encountering a side-effect that we
- /// couldn't model?
- bool keepEvaluatingAfterSideEffect() const override {
- switch (EvalMode) {
- case EvaluationMode::IgnoreSideEffects:
- return true;
-
- case EvaluationMode::ConstantExpression:
- case EvaluationMode::ConstantExpressionUnevaluated:
- case EvaluationMode::ConstantFold:
- // By default, assume any side effect might be valid in some other
- // evaluation of this expression from a different context.
- return checkingPotentialConstantExpression() ||
- checkingForUndefinedBehavior();
+ /// Note that we have had a side-effect, and determine whether we should
+ /// keep evaluating.
+ bool noteSideEffect() override {
+ EvalStatus.HasSideEffects = true;
+ return keepEvaluatingAfterSideEffect();
}
- llvm_unreachable("Missed EvalMode case");
- }
-
- /// Note that we have had a side-effect, and determine whether we should
- /// keep evaluating.
- bool noteSideEffect() override {
- EvalStatus.HasSideEffects = true;
- return keepEvaluatingAfterSideEffect();
- }
- /// Should we continue evaluation after encountering undefined behavior?
- bool keepEvaluatingAfterUndefinedBehavior() {
- switch (EvalMode) {
- case EvaluationMode::IgnoreSideEffects:
- case EvaluationMode::ConstantFold:
- return true;
+ /// Should we continue evaluation after encountering undefined behavior?
+ bool keepEvaluatingAfterUndefinedBehavior() {
+ switch (EvalMode) {
+ case EvaluationMode::IgnoreSideEffects:
+ case EvaluationMode::ConstantFold:
+ return true;
- case EvaluationMode::ConstantExpression:
- case EvaluationMode::ConstantExpressionUnevaluated:
- return checkingForUndefinedBehavior();
+ case EvaluationMode::ConstantExpression:
+ case EvaluationMode::ConstantExpressionUnevaluated:
+ return checkingForUndefinedBehavior();
+ }
+ llvm_unreachable("Missed EvalMode case");
}
- llvm_unreachable("Missed EvalMode case");
- }
-
- /// Note that we hit something that was technically undefined behavior, but
- /// that we can evaluate past it (such as signed overflow or floating-point
- /// division by zero.)
- bool noteUndefinedBehavior() override {
- EvalStatus.HasUndefinedBehavior = true;
- return keepEvaluatingAfterUndefinedBehavior();
- }
- /// Should we continue evaluation as much as possible after encountering a
- /// construct which can't be reduced to a value?
- bool keepEvaluatingAfterFailure() const override {
- if (!StepsLeft)
- return false;
-
- switch (EvalMode) {
- case EvaluationMode::ConstantExpression:
- case EvaluationMode::ConstantExpressionUnevaluated:
- case EvaluationMode::ConstantFold:
- case EvaluationMode::IgnoreSideEffects:
- return checkingPotentialConstantExpression() ||
- checkingForUndefinedBehavior();
+ /// Note that we hit something that was technically undefined behavior, but
+ /// that we can evaluate past it (such as signed overflow or floating-point
+ /// division by zero.)
+ bool noteUndefinedBehavior() override {
+ EvalStatus.HasUndefinedBehavior = true;
+ return keepEvaluatingAfterUndefinedBehavior();
}
- llvm_unreachable("Missed EvalMode case");
- }
- /// Notes that we failed to evaluate an expression that other expressions
- /// directly depend on, and determine if we should keep evaluating. This
- /// should only be called if we actually intend to keep evaluating.
- ///
- /// Call noteSideEffect() instead if we may be able to ignore the value that
- /// we failed to evaluate, e.g. if we failed to evaluate Foo() in:
- ///
- /// (Foo(), 1) // use noteSideEffect
- /// (Foo() || true) // use noteSideEffect
- /// Foo() + 1 // use noteFailure
- [[nodiscard]] bool noteFailure() {
- // Failure when evaluating some expression often means there is some
- // subexpression whose evaluation was skipped. Therefore, (because we
- // don't track whether we skipped an expression when unwinding after an
- // evaluation failure) every evaluation failure that bubbles up from a
- // subexpression implies that a side-effect has potentially happened. We
- // skip setting the HasSideEffects flag to true until we decide to
- // continue evaluating after that point, which happens here.
- bool KeepGoing = keepEvaluatingAfterFailure();
- EvalStatus.HasSideEffects |= KeepGoing;
- return KeepGoing;
- }
-
- class ArrayInitLoopIndex {
- EvalInfo &Info;
- uint64_t OuterIndex;
+ /// Should we continue evaluation as much as possible after encountering a
+ /// construct which can't be reduced to a value?
+ bool keepEvaluatingAfterFailure() const override {
+ if (!StepsLeft)
+ return false;
+
+ switch (EvalMode) {
+ case EvaluationMode::ConstantExpression:
+ case EvaluationMode::ConstantExpressionUnevaluated:
+ case EvaluationMode::ConstantFold:
+ case EvaluationMode::IgnoreSideEffects:
+ return checkingPotentialConstantExpression() ||
+ checkingForUndefinedBehavior();
+ }
+ llvm_unreachable("Missed EvalMode case");
+ }
+
+ /// Notes that we failed to evaluate an expression that other expressions
+ /// directly depend on, and determine if we should keep evaluating. This
+ /// should only be called if we actually intend to keep evaluating.
+ ///
+ /// Call noteSideEffect() instead if we may be able to ignore the value that
+ /// we failed to evaluate, e.g. if we failed to evaluate Foo() in:
+ ///
+ /// (Foo(), 1) // use noteSideEffect
+ /// (Foo() || true) // use noteSideEffect
+ /// Foo() + 1 // use noteFailure
+ [[nodiscard]] bool noteFailure() {
+ // Failure when evaluating some expression often means there is some
+ // subexpression whose evaluation was skipped. Therefore, (because we
+ // don't track whether we skipped an expression when unwinding after an
+ // evaluation failure) every evaluation failure that bubbles up from a
+ // subexpression implies that a side-effect has potentially happened. We
+ // skip setting the HasSideEffects flag to true until we decide to
+ // continue evaluating after that point, which happens here.
+ bool KeepGoing = keepEvaluatingAfterFailure();
+ EvalStatus.HasSideEffects |= KeepGoing;
+ return KeepGoing;
+ }
+
+ class ArrayInitLoopIndex {
+ EvalInfo &Info;
+ uint64_t OuterIndex;
- public:
- ArrayInitLoopIndex(EvalInfo &Info)
- : Info(Info), OuterIndex(Info.ArrayInitIndex) {
- Info.ArrayInitIndex = 0;
- }
- ~ArrayInitLoopIndex() { Info.ArrayInitIndex = OuterIndex; }
+ public:
+ ArrayInitLoopIndex(EvalInfo &Info)
+ : Info(Info), OuterIndex(Info.ArrayInitIndex) {
+ Info.ArrayInitIndex = 0;
+ }
+ ~ArrayInitLoopIndex() { Info.ArrayInitIndex = OuterIndex; }
- operator uint64_t &() { return Info.ArrayInitIndex; }
+ operator uint64_t&() { return Info.ArrayInitIndex; }
+ };
};
-};
-/// Object used to treat all foldable expressions as constant expressions.
-struct FoldConstant {
- EvalInfo &Info;
- bool Enabled;
- bool HadNoPriorDiags;
- EvaluationMode OldMode;
+ /// Object used to treat all foldable expressions as constant expressions.
+ struct FoldConstant {
+ EvalInfo &Info;
+ bool Enabled;
+ bool HadNoPriorDiags;
+ EvaluationMode OldMode;
- explicit FoldConstant(EvalInfo &Info, bool Enabled)
- : Info(Info), Enabled(Enabled),
- HadNoPriorDiags(Info.EvalStatus.Diag && Info.EvalStatus.Diag->empty() &&
+ explicit FoldConstant(EvalInfo &Info, bool Enabled)
+ : Info(Info),
+ Enabled(Enabled),
+ HadNoPriorDiags(Info.EvalStatus.Diag &&
+ Info.EvalStatus.Diag->empty() &&
!Info.EvalStatus.HasSideEffects),
OldMode(Info.EvalMode) {
- if (Enabled)
- Info.EvalMode = EvaluationMode::ConstantFold;
- }
- void keepDiagnostics() { Enabled = false; }
- ~FoldConstant() {
- if (Enabled && HadNoPriorDiags && !Info.EvalStatus.Diag->empty() &&
- !Info.EvalStatus.HasSideEffects)
- Info.EvalStatus.Diag->clear();
- Info.EvalMode = OldMode;
- }
-};
-
-/// RAII object used to set the current evaluation mode to ignore
-/// side-effects.
-struct IgnoreSideEffectsRAII {
- EvalInfo &Info;
- EvaluationMode OldMode;
- explicit IgnoreSideEffectsRAII(EvalInfo &Info)
- : Info(Info), OldMode(Info.EvalMode) {
- Info.EvalMode = EvaluationMode::IgnoreSideEffects;
- }
+ if (Enabled)
+ Info.EvalMode = EvaluationMode::ConstantFold;
+ }
+ void keepDiagnostics() { Enabled = false; }
+ ~FoldConstant() {
+ if (Enabled && HadNoPriorDiags && !Info.EvalStatus.Diag->empty() &&
+ !Info.EvalStatus.HasSideEffects)
+ Info.EvalStatus.Diag->clear();
+ Info.EvalMode = OldMode;
+ }
+ };
- ~IgnoreSideEffectsRAII() { Info.EvalMode = OldMode; }
-};
+ /// RAII object used to set the current evaluation mode to ignore
+ /// side-effects.
+ struct IgnoreSideEffectsRAII {
+ EvalInfo &Info;
+ EvaluationMode OldMode;
+ explicit IgnoreSideEffectsRAII(EvalInfo &Info)
+ : Info(Info), OldMode(Info.EvalMode) {
+ Info.EvalMode = EvaluationMode::IgnoreSideEffects;
+ }
-/// RAII object used to optionally suppress diagnostics and side-effects from
-/// a speculative evaluation.
-class SpeculativeEvaluationRAII {
- EvalInfo *Info = nullptr;
- Expr::EvalStatus OldStatus;
- unsigned OldSpeculativeEvaluationDepth = 0;
+ ~IgnoreSideEffectsRAII() { Info.EvalMode = OldMode; }
+ };
- void moveFromAndCancel(SpeculativeEvaluationRAII &&Other) {
- Info = Other.Info;
- OldStatus = Other.OldStatus;
- OldSpeculativeEvaluationDepth = Other.OldSpeculativeEvaluationDepth;
- Other.Info = nullptr;
- }
+ /// RAII object used to optionally suppress diagnostics and side-effects from
+ /// a speculative evaluation.
+ class SpeculativeEvaluationRAII {
+ EvalInfo *Info = nullptr;
+ Expr::EvalStatus OldStatus;
+ unsigned OldSpeculativeEvaluationDepth = 0;
- void maybeRestoreState() {
- if (!Info)
- return;
+ void moveFromAndCancel(SpeculativeEvaluationRAII &&Other) {
+ Info = Other.Info;
+ OldStatus = Other.OldStatus;
+ OldSpeculativeEvaluationDepth = Other.OldSpeculativeEvaluationDepth;
+ Other.Info = nullptr;
+ }
- Info->EvalStatus = OldStatus;
- Info->SpeculativeEvaluationDepth = OldSpeculativeEvaluationDepth;
- }
+ void maybeRestoreState() {
+ if (!Info)
+ return;
-public:
- SpeculativeEvaluationRAII() = default;
+ Info->EvalStatus = OldStatus;
+ Info->SpeculativeEvaluationDepth = OldSpeculativeEvaluationDepth;
+ }
- SpeculativeEvaluationRAII(
- EvalInfo &Info, SmallVectorImpl<PartialDiagnosticAt> *NewDiag = nullptr)
- : Info(&Info), OldStatus(Info.EvalStatus),
- OldSpeculativeEvaluationDepth(Info.SpeculativeEvaluationDepth) {
- Info.EvalStatus.Diag = NewDiag;
- Info.SpeculativeEvaluationDepth = Info.CallStackDepth + 1;
- }
+ public:
+ SpeculativeEvaluationRAII() = default;
- SpeculativeEvaluationRAII(const SpeculativeEvaluationRAII &Other) = delete;
- SpeculativeEvaluationRAII(SpeculativeEvaluationRAII &&Other) {
- moveFromAndCancel(std::move(Other));
- }
+ SpeculativeEvaluationRAII(
+ EvalInfo &Info, SmallVectorImpl<PartialDiagnosticAt> *NewDiag = nullptr)
+ : Info(&Info), OldStatus(Info.EvalStatus),
+ OldSpeculativeEvaluationDepth(Info.SpeculativeEvaluationDepth) {
+ Info.EvalStatus.Diag = NewDiag;
+ Info.SpeculativeEvaluationDepth = Info.CallStackDepth + 1;
+ }
- SpeculativeEvaluationRAII &operator=(SpeculativeEvaluationRAII &&Other) {
- maybeRestoreState();
- moveFromAndCancel(std::move(Other));
- return *this;
- }
+ SpeculativeEvaluationRAII(const SpeculativeEvaluationRAII &Other) = delete;
+ SpeculativeEvaluationRAII(SpeculativeEvaluationRAII &&Other) {
+ moveFromAndCancel(std::move(Other));
+ }
- ~SpeculativeEvaluationRAII() { maybeRestoreState(); }
-};
+ SpeculativeEvaluationRAII &operator=(SpeculativeEvaluationRAII &&Other) {
+ maybeRestoreState();
+ moveFromAndCancel(std::move(Other));
+ return *this;
+ }
-/// RAII object wrapping a full-expression or block scope, and handling
-/// the ending of the lifetime of temporaries created within it.
-template <ScopeKind Kind> class ScopeRAII {
- EvalInfo &Info;
- unsigned OldStackSize;
+ ~SpeculativeEvaluationRAII() { maybeRestoreState(); }
+ };
-public:
- ScopeRAII(EvalInfo &Info)
- : Info(Info), OldStackSize(Info.CleanupStack.size()) {
- // Push a new temporary version. This is needed to distinguish between
- // temporaries created in different iterations of a loop.
- Info.CurrentCall->pushTempVersion();
- }
- bool destroy(bool RunDestructors = true) {
- bool OK = cleanup(Info, RunDestructors, OldStackSize);
- OldStackSize = std::numeric_limits<unsigned>::max();
- return OK;
- }
- ~ScopeRAII() {
- if (OldStackSize != std::numeric_limits<unsigned>::max())
- destroy(false);
- // Body moved to a static method to encourage the compiler to inline away
- // instances of this class.
- Info.CurrentCall->popTempVersion();
- }
+ /// RAII object wrapping a full-expression or block scope, and handling
+ /// the ending of the lifetime of temporaries created within it.
+ template<ScopeKind Kind>
+ class ScopeRAII {
+ EvalInfo &Info;
+ unsigned OldStackSize;
+ public:
+ ScopeRAII(EvalInfo &Info)
+ : Info(Info), OldStackSize(Info.CleanupStack.size()) {
+ // Push a new temporary version. This is needed to distinguish between
+ // temporaries created in different iterations of a loop.
+ Info.CurrentCall->pushTempVersion();
+ }
+ bool destroy(bool RunDestructors = true) {
+ bool OK = cleanup(Info, RunDestructors, OldStackSize);
+ OldStackSize = std::numeric_limits<unsigned>::max();
+ return OK;
+ }
+ ~ScopeRAII() {
+ if (OldStackSize != std::numeric_limits<unsigned>::max())
+ destroy(false);
+ // Body moved to a static method to encourage the compiler to inline away
+ // instances of this class.
+ Info.CurrentCall->popTempVersion();
+ }
+ private:
+ static bool cleanup(EvalInfo &Info, bool RunDestructors,
+ unsigned OldStackSize) {
+ assert(OldStackSize <= Info.CleanupStack.size() &&
+ "running cleanups out of order?");
-private:
- static bool cleanup(EvalInfo &Info, bool RunDestructors,
- unsigned OldStackSize) {
- assert(OldStackSize <= Info.CleanupStack.size() &&
- "running cleanups out of order?");
-
- // Run all cleanups for a block scope, and non-lifetime-extended cleanups
- // for a full-expression scope.
- bool Success = true;
- for (unsigned I = Info.CleanupStack.size(); I > OldStackSize; --I) {
- if (Info.CleanupStack[I - 1].isDestroyedAtEndOf(Kind)) {
- if (!Info.CleanupStack[I - 1].endLifetime(Info, RunDestructors)) {
- Success = false;
- break;
+ // Run all cleanups for a block scope, and non-lifetime-extended cleanups
+ // for a full-expression scope.
+ bool Success = true;
+ for (unsigned I = Info.CleanupStack.size(); I > OldStackSize; --I) {
+ if (Info.CleanupStack[I - 1].isDestroyedAtEndOf(Kind)) {
+ if (!Info.CleanupStack[I - 1].endLifetime(Info, RunDestructors)) {
+ Success = false;
+ break;
+ }
}
}
- }
- // Compact any retained cleanups.
- auto NewEnd = Info.CleanupStack.begin() + OldStackSize;
- if (Kind != ScopeKind::Block)
- NewEnd = std::remove_if(NewEnd, Info.CleanupStack.end(), [](Cleanup &C) {
- return C.isDestroyedAtEndOf(Kind);
- });
- Info.CleanupStack.erase(NewEnd, Info.CleanupStack.end());
- return Success;
- }
-};
-typedef ScopeRAII<ScopeKind::Block> BlockScopeRAII;
-typedef ScopeRAII<ScopeKind::FullExpression> FullExpressionRAII;
-typedef ScopeRAII<ScopeKind::Call> CallScopeRAII;
-} // namespace
+ // Compact any retained cleanups.
+ auto NewEnd = Info.CleanupStack.begin() + OldStackSize;
+ if (Kind != ScopeKind::Block)
+ NewEnd =
+ std::remove_if(NewEnd, Info.CleanupStack.end(), [](Cleanup &C) {
+ return C.isDestroyedAtEndOf(Kind);
+ });
+ Info.CleanupStack.erase(NewEnd, Info.CleanupStack.end());
+ return Success;
+ }
+ };
+ typedef ScopeRAII<ScopeKind::Block> BlockScopeRAII;
+ typedef ScopeRAII<ScopeKind::FullExpression> FullExpressionRAII;
+ typedef ScopeRAII<ScopeKind::Call> CallScopeRAII;
+}
bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E,
CheckSubobjectKind CSK) {
if (Invalid)
return false;
if (isOnePastTheEnd()) {
- Info.CCEDiag(E, diag::note_constexpr_past_end_subobject) << CSK;
+ Info.CCEDiag(E, diag::note_constexpr_past_end_subobject)
+ << CSK;
setInvalid();
return false;
}
@@ -1387,9 +1413,11 @@ void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info,
// the most derived array.
if (MostDerivedPathLength == Entries.size() && MostDerivedIsArrayElement)
Info.CCEDiag(E, diag::note_constexpr_array_index)
- << N << /*array*/ 0 << static_cast<unsigned>(getMostDerivedArraySize());
+ << N << /*array*/ 0
+ << static_cast<unsigned>(getMostDerivedArraySize());
else
- Info.CCEDiag(E, diag::note_constexpr_array_index) << N << /*non-array*/ 1;
+ Info.CCEDiag(E, diag::note_constexpr_array_index)
+ << N << /*non-array*/ 1;
setInvalid();
}
@@ -1472,314 +1500,322 @@ static bool isValidIndeterminateAccess(AccessKinds AK) {
}
namespace {
-struct ComplexValue {
-private:
- bool IsInt;
+ struct ComplexValue {
+ private:
+ bool IsInt;
-public:
- APSInt IntReal, IntImag;
- APFloat FloatReal, FloatImag;
+ public:
+ APSInt IntReal, IntImag;
+ APFloat FloatReal, FloatImag;
- ComplexValue() : FloatReal(APFloat::Bogus()), FloatImag(APFloat::Bogus()) {}
+ ComplexValue() : FloatReal(APFloat::Bogus()), FloatImag(APFloat::Bogus()) {}
- void makeComplexFloat() { IsInt = false; }
- bool isComplexFloat() const { return !IsInt; }
- APFloat &getComplexFloatReal() { return FloatReal; }
- APFloat &getComplexFloatImag() { return FloatImag; }
+ void makeComplexFloat() { IsInt = false; }
+ bool isComplexFloat() const { return !IsInt; }
+ APFloat &getComplexFloatReal() { return FloatReal; }
+ APFloat &getComplexFloatImag() { return FloatImag; }
- void makeComplexInt() { IsInt = true; }
- bool isComplexInt() const { return IsInt; }
- APSInt &getComplexIntReal() { return IntReal; }
- APSInt &getComplexIntImag() { return IntImag; }
+ void makeComplexInt() { IsInt = true; }
+ bool isComplexInt() const { return IsInt; }
+ APSInt &getComplexIntReal() { return IntReal; }
+ APSInt &getComplexIntImag() { return IntImag; }
- void moveInto(APValue &v) const {
- if (isComplexFloat())
- v = APValue(FloatReal, FloatImag);
- else
- v = APValue(IntReal, IntImag);
- }
- void setFrom(const APValue &v) {
- assert(v.isComplexFloat() || v.isComplexInt());
- if (v.isComplexFloat()) {
- makeComplexFloat();
- FloatReal = v.getComplexFloatReal();
- FloatImag = v.getComplexFloatImag();
- } else {
- makeComplexInt();
- IntReal = v.getComplexIntReal();
- IntImag = v.getComplexIntImag();
+ void moveInto(APValue &v) const {
+ if (isComplexFloat())
+ v = APValue(FloatReal, FloatImag);
+ else
+ v = APValue(IntReal, IntImag);
+ }
+ void setFrom(const APValue &v) {
+ assert(v.isComplexFloat() || v.isComplexInt());
+ if (v.isComplexFloat()) {
+ makeComplexFloat();
+ FloatReal = v.getComplexFloatReal();
+ FloatImag = v.getComplexFloatImag();
+ } else {
+ makeComplexInt();
+ IntReal = v.getComplexIntReal();
+ IntImag = v.getComplexIntImag();
+ }
}
- }
-};
+ };
-struct LValue {
- APValue::LValueBase Base;
- CharUnits Offset;
- SubobjectDesignator Designator;
- bool IsNullPtr : 1;
- bool InvalidBase : 1;
- // P2280R4 track if we have an unknown reference or pointer.
- bool AllowConstexprUnknown = false;
-
- const APValue::LValueBase getLValueBase() const { return Base; }
- bool allowConstexprUnknown() const { return AllowConstexprUnknown; }
- CharUnits &getLValueOffset() { return Offset; }
- const CharUnits &getLValueOffset() const { return Offset; }
- SubobjectDesignator &getLValueDesignator() { return Designator; }
- const SubobjectDesignator &getLValueDesignator() const { return Designator; }
- bool isNullPointer() const { return IsNullPtr; }
-
- unsigned getLValueCallIndex() const { return Base.getCallIndex(); }
- unsigned getLValueVersion() const { return Base.getVersion(); }
-
- void moveInto(APValue &V) const {
- if (Designator.Invalid)
- V = APValue(Base, Offset, APValue::NoLValuePath(), IsNullPtr);
- else {
- assert(!InvalidBase && "APValues can't handle invalid LValue bases");
- V = APValue(Base, Offset, Designator.Entries, Designator.IsOnePastTheEnd,
- IsNullPtr);
+ struct LValue {
+ APValue::LValueBase Base;
+ CharUnits Offset;
+ SubobjectDesignator Designator;
+ bool IsNullPtr : 1;
+ bool InvalidBase : 1;
+ // P2280R4 track if we have an unknown reference or pointer.
+ bool AllowConstexprUnknown = false;
+
+ const APValue::LValueBase getLValueBase() const { return Base; }
+ bool allowConstexprUnknown() const { return AllowConstexprUnknown; }
+ CharUnits &getLValueOffset() { return Offset; }
+ const CharUnits &getLValueOffset() const { return Offset; }
+ SubobjectDesignator &getLValueDesignator() { return Designator; }
+ const SubobjectDesignator &getLValueDesignator() const { return Designator;}
+ bool isNullPointer() const { return IsNullPtr;}
+
+ unsigned getLValueCallIndex() const { return Base.getCallIndex(); }
+ unsigned getLValueVersion() const { return Base.getVersion(); }
+
+ void moveInto(APValue &V) const {
+ if (Designator.Invalid)
+ V = APValue(Base, Offset, APValue::NoLValuePath(), IsNullPtr);
+ else {
+ assert(!InvalidBase && "APValues can't handle invalid LValue bases");
+ V = APValue(Base, Offset, Designator.Entries,
+ Designator.IsOnePastTheEnd, IsNullPtr);
+ }
+ if (AllowConstexprUnknown)
+ V.setConstexprUnknown();
+ }
+ void setFrom(const ASTContext &Ctx, const APValue &V) {
+ assert(V.isLValue() && "Setting LValue from a non-LValue?");
+ Base = V.getLValueBase();
+ Offset = V.getLValueOffset();
+ InvalidBase = false;
+ Designator = SubobjectDesignator(Ctx, V);
+ IsNullPtr = V.isNullPointer();
+ AllowConstexprUnknown = V.allowConstexprUnknown();
}
- if (AllowConstexprUnknown)
- V.setConstexprUnknown();
- }
- void setFrom(const ASTContext &Ctx, const APValue &V) {
- assert(V.isLValue() && "Setting LValue from a non-LValue?");
- Base = V.getLValueBase();
- Offset = V.getLValueOffset();
- InvalidBase = false;
- Designator = SubobjectDesignator(Ctx, V);
- IsNullPtr = V.isNullPointer();
- AllowConstexprUnknown = V.allowConstexprUnknown();
- }
- void set(APValue::LValueBase B, bool BInvalid = false) {
+ void set(APValue::LValueBase B, bool BInvalid = false) {
#ifndef NDEBUG
- // We only allow a few types of invalid bases. Enforce that here.
- if (BInvalid) {
- const auto *E = B.get<const Expr *>();
- assert((isa<MemberExpr>(E) || tryUnwrapAllocSizeCall(E)) &&
- "Unexpected type of invalid base");
- }
+ // We only allow a few types of invalid bases. Enforce that here.
+ if (BInvalid) {
+ const auto *E = B.get<const Expr *>();
+ assert((isa<MemberExpr>(E) || tryUnwrapAllocSizeCall(E)) &&
+ "Unexpected type of invalid base");
+ }
#endif
- Base = B;
- Offset = CharUnits::fromQuantity(0);
- InvalidBase = BInvalid;
- Designator = SubobjectDesignator(getType(B));
- IsNullPtr = false;
- AllowConstexprUnknown = false;
- }
+ Base = B;
+ Offset = CharUnits::fromQuantity(0);
+ InvalidBase = BInvalid;
+ Designator = SubobjectDesignator(getType(B));
+ IsNullPtr = false;
+ AllowConstexprUnknown = false;
+ }
- void setNull(ASTContext &Ctx, QualType PointerTy) {
- Base = (const ValueDecl *)nullptr;
- Offset = CharUnits::fromQuantity(Ctx.getTargetNullPointerValue(PointerTy));
- InvalidBase = false;
- Designator = SubobjectDesignator(PointerTy->getPointeeType());
- IsNullPtr = true;
- AllowConstexprUnknown = false;
- }
+ void setNull(ASTContext &Ctx, QualType PointerTy) {
+ Base = (const ValueDecl *)nullptr;
+ Offset =
+ CharUnits::fromQuantity(Ctx.getTargetNullPointerValue(PointerTy));
+ InvalidBase = false;
+ Designator = SubobjectDesignator(PointerTy->getPointeeType());
+ IsNullPtr = true;
+ AllowConstexprUnknown = false;
+ }
- void setInvalid(APValue::LValueBase B, unsigned I = 0) { set(B, true); }
+ void setInvalid(APValue::LValueBase B, unsigned I = 0) {
+ set(B, true);
+ }
- std::string toString(ASTContext &Ctx, QualType T) const {
- APValue Printable;
- moveInto(Printable);
- return Printable.getAsString(Ctx, T);
- }
+ std::string toString(ASTContext &Ctx, QualType T) const {
+ APValue Printable;
+ moveInto(Printable);
+ return Printable.getAsString(Ctx, T);
+ }
-private:
- // Check that this LValue is not based on a null pointer. If it is, produce
- // a diagnostic and mark the designator as invalid.
- template <typename GenDiagType>
- bool checkNullPointerDiagnosingWith(const GenDiagType &GenDiag) {
- if (Designator.Invalid)
- return false;
- if (IsNullPtr) {
- GenDiag();
- Designator.setInvalid();
- return false;
+ private:
+ // Check that this LValue is not based on a null pointer. If it is, produce
+ // a diagnostic and mark the designator as invalid.
+ template <typename GenDiagType>
+ bool checkNullPointerDiagnosingWith(const GenDiagType &GenDiag) {
+ if (Designator.Invalid)
+ return false;
+ if (IsNullPtr) {
+ GenDiag();
+ Designator.setInvalid();
+ return false;
+ }
+ return true;
}
- return true;
- }
-public:
- bool checkNullPointer(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK) {
- return checkNullPointerDiagnosingWith([&Info, E, CSK] {
- Info.CCEDiag(E, diag::note_constexpr_null_subobject) << CSK;
- });
- }
+ public:
+ bool checkNullPointer(EvalInfo &Info, const Expr *E,
+ CheckSubobjectKind CSK) {
+ return checkNullPointerDiagnosingWith([&Info, E, CSK] {
+ Info.CCEDiag(E, diag::note_constexpr_null_subobject) << CSK;
+ });
+ }
- bool checkNullPointerForFoldAccess(EvalInfo &Info, const Expr *E,
- AccessKinds AK) {
- return checkNullPointerDiagnosingWith([&Info, E, AK] {
- if (AK == AccessKinds::AK_Dereference)
- Info.FFDiag(E, diag::note_constexpr_dereferencing_null);
- else
- Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
- });
- }
+ bool checkNullPointerForFoldAccess(EvalInfo &Info, const Expr *E,
+ AccessKinds AK) {
+ return checkNullPointerDiagnosingWith([&Info, E, AK] {
+ if (AK == AccessKinds::AK_Dereference)
+ Info.FFDiag(E, diag::note_constexpr_dereferencing_null);
+ else
+ Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
+ });
+ }
- // Check this LValue refers to an object. If not, set the designator to be
- // invalid and emit a diagnostic.
- bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK) {
- return (CSK == CSK_ArrayToPointer || checkNullPointer(Info, E, CSK)) &&
- Designator.checkSubobject(Info, E, CSK);
- }
+ // Check this LValue refers to an object. If not, set the designator to be
+ // invalid and emit a diagnostic.
+ bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK) {
+ return (CSK == CSK_ArrayToPointer || checkNullPointer(Info, E, CSK)) &&
+ Designator.checkSubobject(Info, E, CSK);
+ }
- void addDecl(EvalInfo &Info, const Expr *E, const Decl *D,
- bool Virtual = false) {
- if (checkSubobject(Info, E, isa<FieldDecl>(D) ? CSK_Field : CSK_Base))
- Designator.addDeclUnchecked(D, Virtual);
- }
- void addUnsizedArray(EvalInfo &Info, const Expr *E, QualType ElemTy) {
- if (!Designator.Entries.empty()) {
- Info.CCEDiag(E, diag::note_constexpr_unsupported_unsized_array);
- Designator.setInvalid();
- return;
+ void addDecl(EvalInfo &Info, const Expr *E,
+ const Decl *D, bool Virtual = false) {
+ if (checkSubobject(Info, E, isa<FieldDecl>(D) ? CSK_Field : CSK_Base))
+ Designator.addDeclUnchecked(D, Virtual);
}
- if (checkSubobject(Info, E, CSK_ArrayToPointer)) {
- assert(getType(Base).getNonReferenceType()->isPointerType() ||
- getType(Base).getNonReferenceType()->isArrayType());
- Designator.FirstEntryIsAnUnsizedArray = true;
- Designator.addUnsizedArrayUnchecked(ElemTy);
+ void addUnsizedArray(EvalInfo &Info, const Expr *E, QualType ElemTy) {
+ if (!Designator.Entries.empty()) {
+ Info.CCEDiag(E, diag::note_constexpr_unsupported_unsized_array);
+ Designator.setInvalid();
+ return;
+ }
+ if (checkSubobject(Info, E, CSK_ArrayToPointer)) {
+ assert(getType(Base).getNonReferenceType()->isPointerType() ||
+ getType(Base).getNonReferenceType()->isArrayType());
+ Designator.FirstEntryIsAnUnsizedArray = true;
+ Designator.addUnsizedArrayUnchecked(ElemTy);
+ }
}
- }
- void addArray(EvalInfo &Info, const Expr *E, const ConstantArrayType *CAT) {
- if (checkSubobject(Info, E, CSK_ArrayToPointer))
- Designator.addArrayUnchecked(CAT);
- }
- void addComplex(EvalInfo &Info, const Expr *E, QualType EltTy, bool Imag) {
- if (checkSubobject(Info, E, Imag ? CSK_Imag : CSK_Real))
- Designator.addComplexUnchecked(EltTy, Imag);
- }
- void addVectorElement(EvalInfo &Info, const Expr *E, QualType EltTy,
- uint64_t Size, uint64_t Idx) {
- if (checkSubobject(Info, E, CSK_VectorElement))
- Designator.addVectorElementUnchecked(EltTy, Size, Idx);
- }
- void clearIsNullPointer() { IsNullPtr = false; }
- void adjustOffsetAndIndex(EvalInfo &Info, const Expr *E, const APSInt &Index,
- CharUnits ElementSize) {
- // An index of 0 has no effect. (In C, adding 0 to a null pointer is UB,
- // but we're not required to diagnose it and it's valid in C++.)
- if (!Index)
- return;
+ void addArray(EvalInfo &Info, const Expr *E, const ConstantArrayType *CAT) {
+ if (checkSubobject(Info, E, CSK_ArrayToPointer))
+ Designator.addArrayUnchecked(CAT);
+ }
+ void addComplex(EvalInfo &Info, const Expr *E, QualType EltTy, bool Imag) {
+ if (checkSubobject(Info, E, Imag ? CSK_Imag : CSK_Real))
+ Designator.addComplexUnchecked(EltTy, Imag);
+ }
+ void addVectorElement(EvalInfo &Info, const Expr *E, QualType EltTy,
+ uint64_t Size, uint64_t Idx) {
+ if (checkSubobject(Info, E, CSK_VectorElement))
+ Designator.addVectorElementUnchecked(EltTy, Size, Idx);
+ }
+ void clearIsNullPointer() {
+ IsNullPtr = false;
+ }
+ void adjustOffsetAndIndex(EvalInfo &Info, const Expr *E,
+ const APSInt &Index, CharUnits ElementSize) {
+ // An index of 0 has no effect. (In C, adding 0 to a null pointer is UB,
+ // but we're not required to diagnose it and it's valid in C++.)
+ if (!Index)
+ return;
- // Compute the new offset in the appropriate width, wrapping at 64 bits.
- // FIXME: When compiling for a 32-bit target, we should use 32-bit
- // offsets.
- uint64_t Offset64 = Offset.getQuantity();
- uint64_t ElemSize64 = ElementSize.getQuantity();
- uint64_t Index64 = Index.extOrTrunc(64).getZExtValue();
- Offset = CharUnits::fromQuantity(Offset64 + ElemSize64 * Index64);
-
- if (checkNullPointer(Info, E, CSK_ArrayIndex))
- Designator.adjustIndex(Info, E, Index, *this);
- clearIsNullPointer();
- }
- void adjustOffset(CharUnits N) {
- Offset += N;
- if (N.getQuantity())
- clearIsNullPointer();
- }
-};
+ // Compute the new offset in the appropriate width, wrapping at 64 bits.
+ // FIXME: When compiling for a 32-bit target, we should use 32-bit
+ // offsets.
+ uint64_t Offset64 = Offset.getQuantity();
+ uint64_t ElemSize64 = ElementSize.getQuantity();
+ uint64_t Index64 = Index.extOrTrunc(64).getZExtValue();
+ Offset = CharUnits::fromQuantity(Offset64 + ElemSize64 * Index64);
-struct MemberPtr {
- MemberPtr() {}
- explicit MemberPtr(const ValueDecl *Decl)
- : DeclAndIsDerivedMember(Decl, false) {}
-
- /// The member or (direct or indirect) field referred to by this member
- /// pointer, or 0 if this is a null member pointer.
- const ValueDecl *getDecl() const {
- return DeclAndIsDerivedMember.getPointer();
- }
- /// Is this actually a member of some type derived from the relevant class?
- bool isDerivedMember() const { return DeclAndIsDerivedMember.getInt(); }
- /// Get the class which the declaration actually lives in.
- const CXXRecordDecl *getContainingRecord() const {
- return cast<CXXRecordDecl>(
- DeclAndIsDerivedMember.getPointer()->getDeclContext());
- }
-
- void moveInto(APValue &V) const {
- V = APValue(getDecl(), isDerivedMember(), Path);
- }
- void setFrom(const APValue &V) {
- assert(V.isMemberPointer());
- DeclAndIsDerivedMember.setPointer(V.getMemberPointerDecl());
- DeclAndIsDerivedMember.setInt(V.isMemberPointerToDerivedMember());
- Path.clear();
- llvm::append_range(Path, V.getMemberPointerPath());
- }
-
- /// DeclAndIsDerivedMember - The member declaration, and a flag indicating
- /// whether the member is a member of some class derived from the class type
- /// of the member pointer.
- llvm::PointerIntPair<const ValueDecl *, 1, bool> DeclAndIsDerivedMember;
- /// Path - The path of base/derived classes from the member declaration's
- /// class (exclusive) to the class type of the member pointer (inclusive).
- SmallVector<const CXXRecordDecl *, 4> Path;
-
- /// Perform a cast towards the class of the Decl (either up or down the
- /// hierarchy).
- bool castBack(const CXXRecordDecl *Class) {
- assert(!Path.empty());
- const CXXRecordDecl *Expected;
- if (Path.size() >= 2)
- Expected = Path[Path.size() - 2];
- else
- Expected = getContainingRecord();
- if (Expected->getCanonicalDecl() != Class->getCanonicalDecl()) {
- // C++11 [expr.static.cast]p12: In a conversion from (D::*) to (B::*),
- // if B does not contain the original member and is not a base or
- // derived class of the class containing the original member, the result
- // of the cast is undefined.
- // C++11 [conv.mem]p2 does not cover this case for a cast from (B::*) to
- // (D::*). We consider that to be a language defect.
- return false;
+ if (checkNullPointer(Info, E, CSK_ArrayIndex))
+ Designator.adjustIndex(Info, E, Index, *this);
+ clearIsNullPointer();
}
- Path.pop_back();
- return true;
- }
- /// Perform a base-to-derived member pointer cast.
- bool castToDerived(const CXXRecordDecl *Derived) {
- if (!getDecl())
- return true;
- if (!isDerivedMember()) {
- Path.push_back(Derived);
- return true;
+ void adjustOffset(CharUnits N) {
+ Offset += N;
+ if (N.getQuantity())
+ clearIsNullPointer();
}
- if (!castBack(Derived))
- return false;
- if (Path.empty())
- DeclAndIsDerivedMember.setInt(false);
- return true;
- }
- /// Perform a derived-to-base member pointer cast.
- bool castToBase(const CXXRecordDecl *Base) {
- if (!getDecl())
+ };
+
+ struct MemberPtr {
+ MemberPtr() {}
+ explicit MemberPtr(const ValueDecl *Decl)
+ : DeclAndIsDerivedMember(Decl, false) {}
+
+ /// The member or (direct or indirect) field referred to by this member
+ /// pointer, or 0 if this is a null member pointer.
+ const ValueDecl *getDecl() const {
+ return DeclAndIsDerivedMember.getPointer();
+ }
+ /// Is this actually a member of some type derived from the relevant class?
+ bool isDerivedMember() const {
+ return DeclAndIsDerivedMember.getInt();
+ }
+ /// Get the class which the declaration actually lives in.
+ const CXXRecordDecl *getContainingRecord() const {
+ return cast<CXXRecordDecl>(
+ DeclAndIsDerivedMember.getPointer()->getDeclContext());
+ }
+
+ void moveInto(APValue &V) const {
+ V = APValue(getDecl(), isDerivedMember(), Path);
+ }
+ void setFrom(const APValue &V) {
+ assert(V.isMemberPointer());
+ DeclAndIsDerivedMember.setPointer(V.getMemberPointerDecl());
+ DeclAndIsDerivedMember.setInt(V.isMemberPointerToDerivedMember());
+ Path.clear();
+ llvm::append_range(Path, V.getMemberPointerPath());
+ }
+
+ /// DeclAndIsDerivedMember - The member declaration, and a flag indicating
+ /// whether the member is a member of some class derived from the class type
+ /// of the member pointer.
+ llvm::PointerIntPair<const ValueDecl*, 1, bool> DeclAndIsDerivedMember;
+ /// Path - The path of base/derived classes from the member declaration's
+ /// class (exclusive) to the class type of the member pointer (inclusive).
+ SmallVector<const CXXRecordDecl*, 4> Path;
+
+ /// Perform a cast towards the class of the Decl (either up or down the
+ /// hierarchy).
+ bool castBack(const CXXRecordDecl *Class) {
+ assert(!Path.empty());
+ const CXXRecordDecl *Expected;
+ if (Path.size() >= 2)
+ Expected = Path[Path.size() - 2];
+ else
+ Expected = getContainingRecord();
+ if (Expected->getCanonicalDecl() != Class->getCanonicalDecl()) {
+ // C++11 [expr.static.cast]p12: In a conversion from (D::*) to (B::*),
+ // if B does not contain the original member and is not a base or
+ // derived class of the class containing the original member, the result
+ // of the cast is undefined.
+ // C++11 [conv.mem]p2 does not cover this case for a cast from (B::*) to
+ // (D::*). We consider that to be a language defect.
+ return false;
+ }
+ Path.pop_back();
return true;
- if (Path.empty())
- DeclAndIsDerivedMember.setInt(true);
- if (isDerivedMember()) {
- Path.push_back(Base);
+ }
+ /// Perform a base-to-derived member pointer cast.
+ bool castToDerived(const CXXRecordDecl *Derived) {
+ if (!getDecl())
+ return true;
+ if (!isDerivedMember()) {
+ Path.push_back(Derived);
+ return true;
+ }
+ if (!castBack(Derived))
+ return false;
+ if (Path.empty())
+ DeclAndIsDerivedMember.setInt(false);
return true;
}
- return castBack(Base);
- }
-};
+ /// Perform a derived-to-base member pointer cast.
+ bool castToBase(const CXXRecordDecl *Base) {
+ if (!getDecl())
+ return true;
+ if (Path.empty())
+ DeclAndIsDerivedMember.setInt(true);
+ if (isDerivedMember()) {
+ Path.push_back(Base);
+ return true;
+ }
+ return castBack(Base);
+ }
+ };
-/// Compare two member pointers, which are assumed to be of the same type.
-static bool operator==(const MemberPtr &LHS, const MemberPtr &RHS) {
- if (!LHS.getDecl() || !RHS.getDecl())
- return !LHS.getDecl() && !RHS.getDecl();
- if (LHS.getDecl()->getCanonicalDecl() != RHS.getDecl()->getCanonicalDecl())
- return false;
- return LHS.Path == RHS.Path;
+ /// Compare two member pointers, which are assumed to be of the same type.
+ static bool operator==(const MemberPtr &LHS, const MemberPtr &RHS) {
+ if (!LHS.getDecl() || !RHS.getDecl())
+ return !LHS.getDecl() && !RHS.getDecl();
+ if (LHS.getDecl()->getCanonicalDecl() != RHS.getDecl()->getCanonicalDecl())
+ return false;
+ return LHS.Path == RHS.Path;
+ }
}
-} // namespace
void SubobjectDesignator::adjustIndex(EvalInfo &Info, const Expr *E, APSInt N,
const LValue &LV) {
@@ -1830,8 +1866,9 @@ void SubobjectDesignator::adjustIndex(EvalInfo &Info, const Expr *E, APSInt N,
}
static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E);
-static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This,
- const Expr *E, bool AllowNonLiteralTypes = false);
+static bool EvaluateInPlace(APValue &Result, EvalInfo &Info,
+ const LValue &This, const Expr *E,
+ bool AllowNonLiteralTypes = false);
static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info,
bool InvalidBaseOK = false);
static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info,
@@ -1873,7 +1910,7 @@ static void negateAsSigned(APSInt &Int) {
Int = -Int;
}
-template <typename KeyT>
+template<typename KeyT>
APValue &CallStackFrame::createTemporary(const KeyT *Key, QualType T,
ScopeKind Scope, LValue &LV) {
unsigned Version = getTempVersion();
@@ -1946,9 +1983,9 @@ void CallStackFrame::describe(raw_ostream &Out) const {
Object->printPretty(Out, /*Helper=*/nullptr, Info.Ctx.getPrintingPolicy(),
/*Indentation=*/0);
if (Object->getType()->isPointerType())
- Out << "->";
+ Out << "->";
else
- Out << ".";
+ Out << ".";
} else if (const auto *OCE =
dyn_cast_if_present<CXXOperatorCallExpr>(CallExpr)) {
OCE->getArg(0)->printPretty(Out, /*Helper=*/nullptr,
@@ -1971,8 +2008,7 @@ void CallStackFrame::describe(raw_ostream &Out) const {
Out << '(';
for (FunctionDecl::param_const_iterator I = Callee->param_begin(),
- E = Callee->param_end();
- I != E; ++I, ++ArgIndex) {
+ E = Callee->param_end(); I != E; ++I, ++ArgIndex) {
if (ArgIndex > (unsigned)IsMemberCall)
Out << ", ";
@@ -2026,7 +2062,7 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
if (!B)
return true;
- if (const ValueDecl *D = B.dyn_cast<const ValueDecl *>()) {
+ if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) {
// ... the address of an object with static storage duration,
if (const VarDecl *VD = dyn_cast<VarDecl>(D))
return VD->hasGlobalStorage();
@@ -2041,7 +2077,7 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
if (B.is<TypeInfoLValue>() || B.is<DynamicAllocLValue>())
return true;
- const Expr *E = B.get<const Expr *>();
+ const Expr *E = B.get<const Expr*>();
switch (E->getStmtClass()) {
default:
return false;
@@ -2086,7 +2122,7 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
}
static const ValueDecl *GetLValueBaseDecl(const LValue &LVal) {
- return LVal.Base.dyn_cast<const ValueDecl *>();
+ return LVal.Base.dyn_cast<const ValueDecl*>();
}
// Information about an LValueBase that is some kind of string.
@@ -2203,7 +2239,8 @@ static bool HasSameBase(const LValue &A, const LValue &B) {
if (!B.getLValueBase())
return false;
- if (A.getLValueBase().getOpaqueValue() != B.getLValueBase().getOpaqueValue())
+ if (A.getLValueBase().getOpaqueValue() !=
+ B.getLValueBase().getOpaqueValue())
return false;
return A.getLValueCallIndex() == B.getLValueCallIndex() &&
@@ -2212,7 +2249,7 @@ static bool HasSameBase(const LValue &A, const LValue &B) {
static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
assert(Base && "no location for a null lvalue");
- const ValueDecl *VD = Base.dyn_cast<const ValueDecl *>();
+ const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
// For a parameter, find the corresponding call stack frame (if it still
// exists), and point at the parameter of the function definition we actually
@@ -2231,7 +2268,7 @@ static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
if (VD)
Info.Note(VD->getLocation(), diag::note_declared_at);
- else if (const Expr *E = Base.dyn_cast<const Expr *>())
+ else if (const Expr *E = Base.dyn_cast<const Expr*>())
Info.Note(E->getExprLoc(), diag::note_constexpr_temporary_here);
else if (DynamicAllocLValue DA = Base.dyn_cast<DynamicAllocLValue>()) {
// FIXME: Produce a note for dangling pointers too.
@@ -2273,7 +2310,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
const SubobjectDesignator &Designator = LVal.getLValueDesignator();
const Expr *BaseE = Base.dyn_cast<const Expr *>();
- const ValueDecl *BaseVD = Base.dyn_cast<const ValueDecl *>();
+ const ValueDecl *BaseVD = Base.dyn_cast<const ValueDecl*>();
// Additional restrictions apply in a template argument. We only enforce the
// C++20 restrictions here; additional syntactic and semantic restrictions
@@ -2434,7 +2471,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
// Does this refer one past the end of some object?
if (!Designator.Invalid && Designator.isOnePastTheEnd()) {
Info.FFDiag(Loc, diag::note_constexpr_past_end, 1)
- << !Designator.Entries.empty() << !!BaseVD << BaseVD;
+ << !Designator.Entries.empty() << !!BaseVD << BaseVD;
NoteLValueLocation(Info, Base);
}
@@ -2490,7 +2527,8 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E,
// Prvalue constant expressions must be of literal types.
if (Info.getLangOpts().CPlusPlus11)
- Info.FFDiag(E, diag::note_constexpr_nonliteral) << E->getType();
+ Info.FFDiag(E, diag::note_constexpr_nonliteral)
+ << E->getType();
else
Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
return false;
@@ -2582,8 +2620,7 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
if (Value.isMemberPointer() &&
CERK == CheckEvaluationResultKind::ConstantExpression)
- return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value,
- Kind);
+ return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value, Kind);
// Everything else is fine.
return true;
@@ -2641,7 +2678,7 @@ static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) {
// We have a non-null base. These are generally known to be true, but if it's
// a weak declaration it can be null at runtime.
Result = true;
- const ValueDecl *Decl = Value.getLValueBase().dyn_cast<const ValueDecl *>();
+ const ValueDecl *Decl = Value.getLValueBase().dyn_cast<const ValueDecl*>();
return !Decl || !Decl->isWeak();
}
@@ -2697,10 +2734,11 @@ static bool EvaluateAsBooleanCondition(const Expr *E, bool &Result,
return HandleConversionToBool(Val, Result);
}
-template <typename T>
-static bool HandleOverflow(EvalInfo &Info, const Expr *E, const T &SrcValue,
- QualType DestType) {
- Info.CCEDiag(E, diag::note_constexpr_overflow) << SrcValue << DestType;
+template<typename T>
+static bool HandleOverflow(EvalInfo &Info, const Expr *E,
+ const T &SrcValue, QualType DestType) {
+ Info.CCEDiag(E, diag::note_constexpr_overflow)
+ << SrcValue << DestType;
return Info.noteUndefinedBehavior();
}
@@ -2713,8 +2751,8 @@ static bool HandleFloatToIntCast(EvalInfo &Info, const Expr *E,
Result = APSInt(DestWidth, !DestSigned);
bool ignored;
- if (Value.convertToInteger(Result, llvm::APFloat::rmTowardZero, &ignored) &
- APFloat::opInvalidOp)
+ if (Value.convertToInteger(Result, llvm::APFloat::rmTowardZero, &ignored)
+ & APFloat::opInvalidOp)
return HandleOverflow(Info, E, Value, DestType);
return true;
}
@@ -2803,17 +2841,17 @@ static APSInt HandleIntToIntCast(EvalInfo &Info, const Expr *E,
}
static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E,
- const FPOptions FPO, QualType SrcType,
- const APSInt &Value, QualType DestType,
- APFloat &Result) {
+ const FPOptions FPO,
+ QualType SrcType, const APSInt &Value,
+ QualType DestType, APFloat &Result) {
Result = APFloat(Info.Ctx.getFloatTypeSemantics(DestType), 1);
llvm::RoundingMode RM = getActiveRoundingMode(Info, E);
APFloat::opStatus St = Result.convertFromAPInt(Value, Value.isSigned(), RM);
return checkFloatingPointResult(Info, E, St);
}
-static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E, APValue &Value,
- const FieldDecl *FD) {
+static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E,
+ APValue &Value, const FieldDecl *FD) {
assert(FD->isBitField() && "truncateBitfieldValue on non-bitfield");
if (!Value.isInt()) {
@@ -2836,7 +2874,7 @@ static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E, APValue &Value,
/// Perform the given integer operation, which is known to need at most BitWidth
/// bits, and check for overflow in the original type (if that type was not an
/// unsigned type).
-template <typename Operation>
+template<typename Operation>
static bool CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
const APSInt &LHS, const APSInt &RHS,
unsigned BitWidth, Operation Op,
@@ -2878,15 +2916,9 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
case BO_Sub:
return CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1,
std::minus<APSInt>(), Result);
- case BO_And:
- Result = LHS & RHS;
- return true;
- case BO_Xor:
- Result = LHS ^ RHS;
- return true;
- case BO_Or:
- Result = LHS | RHS;
- return true;
+ case BO_And: Result = LHS & RHS; return true;
+ case BO_Xor: Result = LHS ^ RHS; return true;
+ case BO_Or: Result = LHS | RHS; return true;
case BO_Div:
case BO_Rem:
if (RHS == 0) {
@@ -2906,7 +2938,7 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
if (Info.getLangOpts().OpenCL)
// OpenCL 6.3j: shift values are effectively % word size of LHS.
RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
- static_cast<uint64_t>(LHS.getBitWidth() - 1)),
+ static_cast<uint64_t>(LHS.getBitWidth() - 1)),
RHS.isUnsigned());
else if (RHS.isSigned() && RHS.isNegative()) {
// During constant-folding, a negative shift is an opposite shift. Such
@@ -2920,10 +2952,10 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
shift_left:
// C++11 [expr.shift]p1: Shift width must be less than the bit width of
// the shifted type.
- unsigned SA = (unsigned)RHS.getLimitedValue(LHS.getBitWidth() - 1);
+ unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
if (SA != RHS) {
Info.CCEDiag(E, diag::note_constexpr_large_shift)
- << RHS << E->getType() << LHS.getBitWidth();
+ << RHS << E->getType() << LHS.getBitWidth();
if (!Info.noteUndefinedBehavior())
return false;
} else if (LHS.isSigned() && !Info.getLangOpts().CPlusPlus20) {
@@ -2948,7 +2980,7 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
if (Info.getLangOpts().OpenCL)
// OpenCL 6.3j: shift values are effectively % word size of LHS.
RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
- static_cast<uint64_t>(LHS.getBitWidth() - 1)),
+ static_cast<uint64_t>(LHS.getBitWidth() - 1)),
RHS.isUnsigned());
else if (RHS.isSigned() && RHS.isNegative()) {
// During constant-folding, a negative shift is an opposite shift. Such a
@@ -2962,10 +2994,10 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
shift_right:
// C++11 [expr.shift]p1: Shift width must be less than the bit width of the
// shifted type.
- unsigned SA = (unsigned)RHS.getLimitedValue(LHS.getBitWidth() - 1);
+ unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
if (SA != RHS) {
Info.CCEDiag(E, diag::note_constexpr_large_shift)
- << RHS << E->getType() << LHS.getBitWidth();
+ << RHS << E->getType() << LHS.getBitWidth();
if (!Info.noteUndefinedBehavior())
return false;
}
@@ -2974,24 +3006,12 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
return true;
}
- case BO_LT:
- Result = LHS < RHS;
- return true;
- case BO_GT:
- Result = LHS > RHS;
- return true;
- case BO_LE:
- Result = LHS <= RHS;
- return true;
- case BO_GE:
- Result = LHS >= RHS;
- return true;
- case BO_EQ:
- Result = LHS == RHS;
- return true;
- case BO_NE:
- Result = LHS != RHS;
- return true;
+ case BO_LT: Result = LHS < RHS; return true;
+ case BO_GT: Result = LHS > RHS; return true;
+ case BO_LE: Result = LHS <= RHS; return true;
+ case BO_GE: Result = LHS >= RHS; return true;
+ case BO_EQ: Result = LHS == RHS; return true;
+ case BO_NE: Result = LHS != RHS; return true;
case BO_Cmp:
llvm_unreachable("BO_Cmp should be handled elsewhere");
}
@@ -3209,8 +3229,7 @@ static bool CastToDerivedClass(EvalInfo &Info, const Expr *E, LValue &Result,
// Truncate the path to the subobject, and remove any derived-to-base offsets.
const RecordDecl *RD = TruncatedType;
for (unsigned I = TruncatedElements, N = D.Entries.size(); I != N; ++I) {
- if (RD->isInvalidDecl())
- return false;
+ if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
const CXXRecordDecl *Base = getAsBaseClass(D.Entries[I]);
if (isVirtualBaseClass(D.Entries[I]))
@@ -3228,8 +3247,7 @@ static bool HandleLValueDirectBase(EvalInfo &Info, const Expr *E, LValue &Obj,
const CXXRecordDecl *Base,
const ASTRecordLayout *RL = nullptr) {
if (!RL) {
- if (Derived->isInvalidDecl())
- return false;
+ if (Derived->isInvalidDecl()) return false;
RL = &Info.Ctx.getASTRecordLayout(Derived);
}
@@ -3260,8 +3278,7 @@ static bool HandleLValueBase(EvalInfo &Info, const Expr *E, LValue &Obj,
return false;
// Find the virtual base class.
- if (DerivedDecl->isInvalidDecl())
- return false;
+ if (DerivedDecl->isInvalidDecl()) return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl);
Obj.addDecl(Info, E, BaseDecl, /*Virtual*/ true);
Obj.getLValueOffset() += Layout.getVBaseClassOffset(BaseDecl);
@@ -3273,7 +3290,8 @@ static bool HandleLValueBasePath(EvalInfo &Info, const CastExpr *E,
for (CastExpr::path_const_iterator PathI = E->path_begin(),
PathE = E->path_end();
PathI != PathE; ++PathI) {
- if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(), *PathI))
+ if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(),
+ *PathI))
return false;
Type = (*PathI)->getType();
}
@@ -3301,8 +3319,7 @@ static bool HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal,
const FieldDecl *FD,
const ASTRecordLayout *RL = nullptr) {
if (!RL) {
- if (FD->getParent()->isInvalidDecl())
- return false;
+ if (FD->getParent()->isInvalidDecl()) return false;
RL = &Info.Ctx.getASTRecordLayout(FD->getParent());
}
@@ -3500,7 +3517,8 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
!Info.CurrentCall->Callee ||
!Info.CurrentCall->Callee->Equals(VD->getDeclContext())) {
if (Info.getLangOpts().CPlusPlus11) {
- Info.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << VD;
+ Info.FFDiag(E, diag::note_constexpr_function_param_value_unknown)
+ << VD;
NoteLValueLocation(Info, Base);
} else {
Info.FFDiag(E);
@@ -3524,7 +3542,8 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
// Don't diagnose during potential constant expression checking; an
// initializer might be added later.
if (!Info.checkingPotentialConstantExpression()) {
- Info.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;
+ Info.FFDiag(E, diag::note_constexpr_var_init_unknown, 1)
+ << VD;
NoteLValueLocation(Info, Base);
}
return false;
@@ -3542,11 +3561,9 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
// have been value-dependent too), so diagnose that.
assert(!VD->mightBeUsableInConstantExpressions(Info.Ctx));
if (!Info.checkingPotentialConstantExpression()) {
- Info.FFDiag(E,
- Info.getLangOpts().CPlusPlus11
- ? diag::note_constexpr_ltor_non_constexpr
- : diag::note_constexpr_ltor_non_integral,
- 1)
+ Info.FFDiag(E, Info.getLangOpts().CPlusPlus11
+ ? diag::note_constexpr_ltor_non_constexpr
+ : diag::note_constexpr_ltor_non_integral, 1)
<< VD << VD->getType();
NoteLValueLocation(Info, Base);
}
@@ -3610,8 +3627,7 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived,
Base = Base->getCanonicalDecl();
unsigned Index = 0;
for (CXXRecordDecl::base_class_const_iterator I = Derived->bases_begin(),
- E = Derived->bases_end();
- I != E; ++I, ++Index) {
+ E = Derived->bases_end(); I != E; ++I, ++Index) {
if (I->getType()->getAsCXXRecordDecl()->getCanonicalDecl() == Base)
return Index;
}
@@ -3636,7 +3652,8 @@ static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit,
if (auto PE = dyn_cast<PredefinedExpr>(Lit))
Lit = PE->getFunctionName();
const StringLiteral *S = cast<StringLiteral>(Lit);
- const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(S->getType());
+ const ConstantArrayType *CAT =
+ Info.Ctx.getAsConstantArrayType(S->getType());
assert(CAT && "string literal isn't an array");
QualType CharType = CAT->getElementType();
assert(CharType->isIntegerType() && "unexpected character type");
@@ -3661,8 +3678,8 @@ static void expandStringLiteral(EvalInfo &Info, const StringLiteral *S,
assert(CharType->isIntegerType() && "unexpected character type");
unsigned Elts = CAT->getZExtSize();
- Result =
- APValue(APValue::UninitArray(), std::min(S->getLength(), Elts), Elts);
+ Result = APValue(APValue::UninitArray(),
+ std::min(S->getLength(), Elts), Elts);
APSInt Value(Info.Ctx.getTypeSize(CharType),
CharType->isUnsignedIntegerType());
if (Result.hasArrayFiller())
@@ -3680,7 +3697,7 @@ static void expandArray(APValue &Array, unsigned Index) {
// Always at least double the number of elements for which we store a value.
unsigned OldElts = Array.getArrayInitializedElts();
- unsigned NewElts = std::max(Index + 1, OldElts * 2);
+ unsigned NewElts = std::max(Index+1, OldElts * 2);
NewElts = std::min(Size, std::max(NewElts, 8u));
// Copy the data across.
@@ -3836,7 +3853,7 @@ struct CompleteObject {
if (!Info.getLangOpts().CPlusPlus14 &&
AK != AccessKinds::AK_IsWithinLifetime)
return false;
- return lifetimeStartedInEvaluation(Info, Base, /*MutableSubobject*/ true);
+ return lifetimeStartedInEvaluation(Info, Base, /*MutableSubobject*/true);
}
explicit operator bool() const { return !Type.isNull(); }
@@ -3883,8 +3900,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
// Walk the designator's path to find the subobject.
for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) {
- // Reading an indeterminate value is undefined, but assigning over one is
- // OK.
+ // Reading an indeterminate value is undefined, but assigning over one is OK.
if ((O->isAbsent() && !(handler.AccessKind == AK_Construct && I == N)) ||
(O->isIndeterminate() &&
!isValidIndeterminateAccess(handler.AccessKind))) {
@@ -3926,7 +3942,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
DiagKind = 2;
Loc = VolatileField->getLocation();
Decl = VolatileField;
- } else if (auto *VD = Obj.Base.dyn_cast<const ValueDecl *>()) {
+ } else if (auto *VD = Obj.Base.dyn_cast<const ValueDecl*>()) {
DiagKind = 1;
Loc = VD->getLocation();
Decl = VD;
@@ -3959,8 +3975,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
return false;
// If we modified a bit-field, truncate it to the right width.
- if (isModification(handler.AccessKind) && LastField &&
- LastField->isBitField() &&
+ if (isModification(handler.AccessKind) &&
+ LastField && LastField->isBitField() &&
!truncateBitfieldValue(Info, E, *O, LastField))
return false;
@@ -3980,7 +3996,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
// designator which points more than one past the end of the array.
if (Info.getLangOpts().CPlusPlus11)
Info.FFDiag(E, diag::note_constexpr_access_past_end)
- << handler.AccessKind;
+ << handler.AccessKind;
else
Info.FFDiag(E);
return handler.failed();
@@ -4005,7 +4021,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
if (Index > 1) {
if (Info.getLangOpts().CPlusPlus11)
Info.FFDiag(E, diag::note_constexpr_access_past_end)
- << handler.AccessKind;
+ << handler.AccessKind;
else
Info.FFDiag(E);
return handler.failed();
@@ -4016,13 +4032,12 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
assert(I == N - 1 && "extracting subobject of scalar?");
if (O->isComplexInt()) {
- return handler.found(
- Index ? O->getComplexIntImag() : O->getComplexIntReal(), ObjType);
+ return handler.found(Index ? O->getComplexIntImag()
+ : O->getComplexIntReal(), ObjType);
} else {
assert(O->isComplexFloat());
return handler.found(Index ? O->getComplexFloatImag()
- : O->getComplexFloatReal(),
- ObjType);
+ : O->getComplexFloatReal(), ObjType);
}
} else if (const auto *VT = ObjType->getAs<VectorType>()) {
uint64_t Index = Sub.Entries[I].getAsArrayIndex();
@@ -4049,7 +4064,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
if (Field->isMutable() &&
!Obj.mayAccessMutableMembers(Info, handler.AccessKind)) {
Info.FFDiag(E, diag::note_constexpr_access_mutable, 1)
- << handler.AccessKind << Field;
+ << handler.AccessKind << Field;
Info.Note(Field->getLocation(), diag::note_declared_at);
return handler.failed();
}
@@ -4183,8 +4198,9 @@ const AccessKinds ModifySubobjectHandler::AccessKind;
/// Update the designated sub-object of an rvalue to the given value.
static bool modifySubobject(EvalInfo &Info, const Expr *E,
const CompleteObject &Obj,
- const SubobjectDesignator &Sub, APValue &NewVal) {
- ModifySubobjectHandler Handler = {Info, NewVal, E};
+ const SubobjectDesignator &Sub,
+ APValue &NewVal) {
+ ModifySubobjectHandler Handler = { Info, NewVal, E };
return findSubobject(Info, E, Obj, Sub, Handler);
}
@@ -4270,7 +4286,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
Info.getCallFrameAndDepth(LVal.getLValueCallIndex());
if (!Frame) {
Info.FFDiag(E, diag::note_constexpr_lifetime_ended, 1)
- << AK << LVal.Base.is<const ValueDecl *>();
+ << AK << LVal.Base.is<const ValueDecl*>();
NoteLValueLocation(Info, LVal.Base);
return CompleteObject();
}
@@ -4285,7 +4301,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
if (isFormalAccess(AK) && LValType.isVolatileQualified()) {
if (Info.getLangOpts().CPlusPlus)
Info.FFDiag(E, diag::note_constexpr_access_volatile_type)
- << AK << LValType;
+ << AK << LValType;
else
Info.FFDiag(E);
return CompleteObject();
@@ -4405,11 +4421,9 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
// folding of const floating-point types, in order to make static const
// data members of such types (supported as an extension) more useful.
if (Info.getLangOpts().CPlusPlus) {
- Info.CCEDiag(E,
- Info.getLangOpts().CPlusPlus11
- ? diag::note_constexpr_ltor_non_constexpr
- : diag::note_constexpr_ltor_non_integral,
- 1)
+ Info.CCEDiag(E, Info.getLangOpts().CPlusPlus11
+ ? diag::note_constexpr_ltor_non_constexpr
+ : diag::note_constexpr_ltor_non_integral, 1)
<< VD << BaseType;
Info.Note(VD->getLocation(), diag::note_declared_at);
} else {
@@ -4418,11 +4432,9 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
} else {
// Never allow reading a non-const value.
if (Info.getLangOpts().CPlusPlus) {
- Info.FFDiag(E,
- Info.getLangOpts().CPlusPlus11
- ? diag::note_constexpr_ltor_non_constexpr
- : diag::note_constexpr_ltor_non_integral,
- 1)
+ Info.FFDiag(E, Info.getLangOpts().CPlusPlus11
+ ? diag::note_constexpr_ltor_non_constexpr
+ : diag::note_constexpr_ltor_non_integral, 1)
<< VD << BaseType;
Info.Note(VD->getLocation(), diag::note_declared_at);
} else {
@@ -4461,7 +4473,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
// When binding to a reference, the variable does not need to be
// within its lifetime.
else if (AK != clang::AK_Dereference) {
- const Expr *Base = LVal.Base.dyn_cast<const Expr *>();
+ const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
if (!Frame) {
if (const MaterializeTemporaryExpr *MTE =
@@ -4588,7 +4600,7 @@ handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, QualType Type,
return false;
// Check for special cases where there is no existing APValue to look at.
- const Expr *Base = LVal.Base.dyn_cast<const Expr *>();
+ const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
AccessKinds AK =
WantObjectRepresentation ? AK_ReadObjectRepresentation : AK_Read;
@@ -4717,7 +4729,8 @@ struct CompoundAssignSubobjectHandler {
Value = HandleIntToIntCast(Info, E, SubobjType, PromotedLHSType, LHS);
return true;
} else if (RHS.isFloat()) {
- const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts());
+ const FPOptions FPO = E->getFPFeaturesInEffect(
+ Info.Ctx.getLangOpts());
APFloat FValue(0.0);
return HandleIntToFloatCast(Info, E, FPO, SubobjType, Value,
PromotedLHSType, FValue) &&
@@ -4782,8 +4795,8 @@ static bool handleCompoundAssignment(EvalInfo &Info,
}
CompleteObject Obj = findCompleteObject(Info, E, AK_Assign, LVal, LValType);
- CompoundAssignSubobjectHandler Handler = {Info, E, PromotedLValType, Opcode,
- RVal};
+ CompoundAssignSubobjectHandler Handler = { Info, E, PromotedLValType, Opcode,
+ RVal };
return Obj && findSubobject(Info, E, Obj, LVal.Designator, Handler);
}
@@ -4820,15 +4833,13 @@ struct IncDecSubobjectHandler {
case APValue::Float:
return found(Subobj.getFloat(), SubobjType);
case APValue::ComplexInt:
- return found(
- Subobj.getComplexIntReal(),
- SubobjType->castAs<ComplexType>()->getElementType().withCVRQualifiers(
- SubobjType.getCVRQualifiers()));
+ return found(Subobj.getComplexIntReal(),
+ SubobjType->castAs<ComplexType>()->getElementType()
+ .withCVRQualifiers(SubobjType.getCVRQualifiers()));
case APValue::ComplexFloat:
- return found(
- Subobj.getComplexFloatReal(),
- SubobjType->castAs<ComplexType>()->getElementType().withCVRQualifiers(
- SubobjType.getCVRQualifiers()));
+ return found(Subobj.getComplexFloatReal(),
+ SubobjType->castAs<ComplexType>()->getElementType()
+ .withCVRQualifiers(SubobjType.getCVRQualifiers()));
case APValue::LValue:
return foundPointer(Subobj, SubobjType);
default:
@@ -4848,8 +4859,7 @@ struct IncDecSubobjectHandler {
return false;
}
- if (Old)
- *Old = APValue(Value);
+ if (Old) *Old = APValue(Value);
// bool arithmetic promotes to int, and the conversion back to bool
// doesn't reduce mod 2^n, so special-case it.
@@ -4866,7 +4876,7 @@ struct IncDecSubobjectHandler {
++Value;
if (!WasNegative && Value.isNegative() && E->canOverflow()) {
- APSInt ActualValue(Value, /*IsUnsigned*/ true);
+ APSInt ActualValue(Value, /*IsUnsigned*/true);
return HandleOverflow(Info, E, ActualValue, SubobjType);
}
} else {
@@ -4874,7 +4884,7 @@ struct IncDecSubobjectHandler {
if (WasNegative && !Value.isNegative() && E->canOverflow()) {
unsigned BitWidth = Value.getBitWidth();
- APSInt ActualValue(Value.sext(BitWidth + 1), /*IsUnsigned*/ false);
+ APSInt ActualValue(Value.sext(BitWidth + 1), /*IsUnsigned*/false);
ActualValue.setBit(BitWidth);
return HandleOverflow(Info, E, ActualValue, SubobjType);
}
@@ -4885,8 +4895,7 @@ struct IncDecSubobjectHandler {
if (!checkConst(SubobjType))
return false;
- if (Old)
- *Old = APValue(Value);
+ if (Old) *Old = APValue(Value);
APFloat One(Value.getSemantics(), 1);
llvm::RoundingMode RM = getActiveRoundingMode(Info, E);
@@ -4968,7 +4977,8 @@ static bool EvaluateObjectArgument(EvalInfo &Info, const Expr *Object,
/// \return The field or method declaration to which the member pointer refers,
/// or 0 if evaluation fails.
static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
- QualType LVType, LValue &LV,
+ QualType LVType,
+ LValue &LV,
const Expr *RHS,
bool IncludeMember = true) {
MemberPtr MemPtr;
@@ -4998,8 +5008,8 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
unsigned PathLengthToMember =
LV.Designator.Entries.size() - MemPtr.Path.size();
for (unsigned I = 0, N = MemPtr.Path.size(); I != N; ++I) {
- const CXXRecordDecl *LVDecl =
- getAsBaseClass(LV.Designator.Entries[PathLengthToMember + I]);
+ const CXXRecordDecl *LVDecl = getAsBaseClass(
+ LV.Designator.Entries[PathLengthToMember + I]);
const CXXRecordDecl *MPDecl = MemPtr.Path[I];
if (LVDecl->getCanonicalDecl() != MPDecl->getCanonicalDecl()) {
Info.FFDiag(RHS);
@@ -5058,7 +5068,7 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
if (!HandleLValueMember(Info, RHS, LV, FD))
return nullptr;
} else if (const IndirectFieldDecl *IFD =
- dyn_cast<IndirectFieldDecl>(MemPtr.getDecl())) {
+ dyn_cast<IndirectFieldDecl>(MemPtr.getDecl())) {
if (!HandleLValueIndirectMember(Info, RHS, LV, IFD))
return nullptr;
} else {
@@ -5329,10 +5339,12 @@ struct TempVersionRAII {
Frame.pushTempVersion();
}
- ~TempVersionRAII() { Frame.popTempVersion(); }
+ ~TempVersionRAII() {
+ Frame.popTempVersion();
+ }
};
-} // namespace
+}
static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
const Stmt *S,
@@ -5437,8 +5449,8 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info,
const CaseStmt *CS = cast<CaseStmt>(SC);
APSInt LHS = CS->getLHS()->EvaluateKnownConstInt(Info.Ctx);
- APSInt RHS =
- CS->getRHS() ? CS->getRHS()->EvaluateKnownConstInt(Info.Ctx) : LHS;
+ APSInt RHS = CS->getRHS() ? CS->getRHS()->EvaluateKnownConstInt(Info.Ctx)
+ : LHS;
if (LHS <= Value && Value <= RHS) {
Found = SC;
break;
@@ -5576,7 +5588,8 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
}
}
- EvalStmtResult ESR = EvaluateLoopBody(Result, Info, FS->getBody(), Case);
+ EvalStmtResult ESR =
+ EvaluateLoopBody(Result, Info, FS->getBody(), Case);
if (ShouldPropagateBreakContinue(Info, FS, /*Scopes=*/{}, ESR))
return ESR;
if (ESR != ESR_Continue)
@@ -5667,9 +5680,10 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
// We know we returned, but we don't know what the value is.
return ESR_Failed;
}
- if (RetExpr && !(Result.Slot ? EvaluateInPlace(Result.Value, Info,
- *Result.Slot, RetExpr)
- : Evaluate(Result.Value, Info, RetExpr)))
+ if (RetExpr &&
+ !(Result.Slot
+ ? EvaluateInPlace(Result.Value, Info, *Result.Slot, RetExpr)
+ : Evaluate(Result.Value, Info, RetExpr)))
return ESR_Failed;
return Scope.destroy() ? ESR_Returned : ESR_Failed;
}
@@ -5994,7 +6008,7 @@ static bool CheckTrivialDefaultConstructor(EvalInfo &Info, SourceLocation Loc,
// FIXME: If DiagDecl is an implicitly-declared special member function,
// we should be much more explicit about why it's not constexpr.
Info.CCEDiag(Loc, diag::note_constexpr_invalid_function, 1)
- << /*IsConstexpr*/ 0 << /*IsConstructor*/ 1 << CD;
+ << /*IsConstexpr*/0 << /*IsConstructor*/1 << CD;
Info.Note(CD->getLocation(), diag::note_declared_at);
} else {
Info.CCEDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
@@ -6038,7 +6052,7 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
// Can we evaluate this function call?
if (Definition && Body &&
(Definition->isConstexpr() || (Info.CurrentCall->CanEvalMSConstexpr &&
- Definition->hasAttr<MSConstexprAttr>())))
+ Definition->hasAttr<MSConstexprAttr>())))
return true;
const FunctionDecl *DiagDecl = Definition ? Definition : Declaration;
@@ -6071,10 +6085,10 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
// it's not constexpr.
if (CD && CD->isInheritingConstructor())
Info.FFDiag(CallLoc, diag::note_constexpr_invalid_inhctor, 1)
- << CD->getInheritedConstructor().getConstructor()->getParent();
+ << CD->getInheritedConstructor().getConstructor()->getParent();
else
Info.FFDiag(CallLoc, diag::note_constexpr_invalid_function, 1)
- << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
+ << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
Info.Note(DiagDecl->getLocation(), diag::note_declared_at);
} else {
Info.FFDiag(CallLoc, diag::note_invalid_subexpr_in_const_expr);
@@ -6157,8 +6171,8 @@ struct DynamicType {
static const CXXRecordDecl *getBaseClassType(SubobjectDesignator &Designator,
unsigned PathLength) {
- assert(PathLength >= Designator.MostDerivedPathLength &&
- PathLength <= Designator.Entries.size() && "invalid path length");
+ assert(PathLength >= Designator.MostDerivedPathLength && PathLength <=
+ Designator.Entries.size() && "invalid path length");
return (PathLength == Designator.MostDerivedPathLength)
? Designator.MostDerivedType->getAsCXXRecordDecl()
: getAsBaseClass(Designator.Entries[PathLength - 1]);
@@ -6362,7 +6376,7 @@ static bool HandleDynamicCast(EvalInfo &Info, const ExplicitCastExpr *E,
assert(C && "dynamic_cast target is not void pointer nor class");
CanQualType CQT = Info.Ctx.getCanonicalTagType(C);
- auto RuntimeCheckFailed = [&](CXXBasePaths *Paths) {
+ auto RuntimeCheckFailed = [&] (CXXBasePaths *Paths) {
// C++ [expr.dynamic.cast]p9:
if (!E->isGLValue()) {
// The value of a failed cast to pointer type is the null pointer value
@@ -6486,7 +6500,7 @@ static bool MaybeHandleUnionActiveMemberChange(EvalInfo &Info,
if (LHS.InvalidBase || LHS.Designator.Invalid)
return false;
- llvm::SmallVector<std::pair<unsigned, const FieldDecl *>, 4> UnionPathLengths;
+ llvm::SmallVector<std::pair<unsigned, const FieldDecl*>, 4> UnionPathLengths;
// C++ [class.union]p5:
// define the set S(E) of subexpressions of E as follows:
unsigned PathLength = LHS.Designator.Entries.size();
@@ -6512,9 +6526,9 @@ static bool MaybeHandleUnionActiveMemberChange(EvalInfo &Info,
E = ME->getBase();
--PathLength;
- assert(declaresSameEntity(
- FD,
- LHS.Designator.Entries[PathLength].getAsBaseOrMember().getPointer()));
+ assert(declaresSameEntity(FD,
+ LHS.Designator.Entries[PathLength]
+ .getAsBaseOrMember().getPointer()));
// -- If E is of the form A[B] and is interpreted as a built-in array
// subscripting operator, S(E) is [S(the array operand, if any)].
@@ -6547,11 +6561,10 @@ static bool MaybeHandleUnionActiveMemberChange(EvalInfo &Info,
--PathLength;
assert(declaresSameEntity(Elt->getType()->getAsCXXRecordDecl(),
LHS.Designator.Entries[PathLength]
- .getAsBaseOrMember()
- .getPointer()));
+ .getAsBaseOrMember().getPointer()));
}
- // -- Otherwise, S(E) is empty.
+ // -- Otherwise, S(E) is empty.
} else {
break;
}
@@ -6568,7 +6581,7 @@ static bool MaybeHandleUnionActiveMemberChange(EvalInfo &Info,
if (!Obj)
return false;
for (std::pair<unsigned, const FieldDecl *> LengthAndField :
- llvm::reverse(UnionPathLengths)) {
+ llvm::reverse(UnionPathLengths)) {
// Form a designator for the union object.
SubobjectDesignator D = LHS.Designator;
D.truncate(Info.Ctx, LHS.Base, LengthAndField.first);
@@ -6798,11 +6811,10 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
std::distance(RD->field_begin(), RD->field_end()));
else
// A union starts with no active member.
- Result = APValue((const FieldDecl *)nullptr);
+ Result = APValue((const FieldDecl*)nullptr);
}
- if (RD->isInvalidDecl())
- return false;
+ if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
// A scope for temporaries lifetime-extended by reference members.
@@ -6961,7 +6973,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
}
static bool HandleConstructorCall(const Expr *E, const LValue &This,
- ArrayRef<const Expr *> Args,
+ ArrayRef<const Expr*> Args,
const CXXConstructorDecl *Definition,
EvalInfo &Info, APValue &Result) {
CallScopeRAII CallScope(Info);
@@ -7108,7 +7120,7 @@ static bool HandleDestructionImpl(EvalInfo &Info, SourceRange CallRange,
// We don't have a good way to iterate fields in reverse, so collect all the
// fields first and then walk them backwards.
- SmallVector<FieldDecl *, 16> Fields(RD->fields());
+ SmallVector<FieldDecl*, 16> Fields(RD->fields());
for (const FieldDecl *FD : llvm::reverse(Fields)) {
if (FD->isUnnamedBitField())
continue;
@@ -7170,12 +7182,12 @@ struct DestroyObjectHandler {
return false;
}
};
-} // namespace
+}
/// Perform a destructor or pseudo-destructor call on the given object, which
/// might in general not be a complete object.
-static bool HandleDestruction(EvalInfo &Info, const Expr *E, const LValue &This,
- QualType ThisType) {
+static bool HandleDestruction(EvalInfo &Info, const Expr *E,
+ const LValue &This, QualType ThisType) {
CompleteObject Obj = findCompleteObject(Info, E, AK_Destroy, This, ThisType);
DestroyObjectHandler Handler = {Info, E, This, AK_Destroy};
return Obj && findSubobject(Info, E, Obj, This.Designator, Handler);
@@ -7379,8 +7391,8 @@ class BitCastBuffer {
public:
BitCastBuffer(CharUnits Width, bool TargetIsLittleEndian)
- : Bytes(Width.getQuantity()), TargetIsLittleEndian(TargetIsLittleEndian) {
- }
+ : Bytes(Width.getQuantity()),
+ TargetIsLittleEndian(TargetIsLittleEndian) {}
[[nodiscard]] bool readObject(CharUnits Offset, CharUnits Width,
SmallVectorImpl<unsigned char> &Output) const {
@@ -7704,7 +7716,8 @@ class BufferToAPValueConverter {
T->isSpecificBuiltinType(BuiltinType::Char_U));
if (!IsStdByte && !IsUChar) {
QualType DisplayType(EnumSugar ? (const Type *)EnumSugar : T, 0);
- Info.FFDiag(BCE->getExprLoc(), diag::note_constexpr_bit_cast_indet_dest)
+ Info.FFDiag(BCE->getExprLoc(),
+ diag::note_constexpr_bit_cast_indet_dest)
<< DisplayType << Info.Ctx.getLangOpts().CharIsSigned;
return std::nullopt;
}
@@ -8058,9 +8071,10 @@ static bool handleLValueToRValueBitCast(EvalInfo &Info, APValue &DestValue,
}
template <class Derived>
-class ExprEvaluatorBase : public ConstStmtVisitor<Derived, bool> {
+class ExprEvaluatorBase
+ : public ConstStmtVisitor<Derived, bool> {
private:
- Derived &getDerived() { return static_cast<Derived &>(*this); }
+ Derived &getDerived() { return static_cast<Derived&>(*this); }
bool DerivedSuccess(const APValue &V, const Expr *E) {
return getDerived().Success(V, E);
}
@@ -8071,7 +8085,7 @@ class ExprEvaluatorBase : public ConstStmtVisitor<Derived, bool> {
// Check whether a conditional operator with a non-constant condition is a
// potential constant expression. If neither arm is a potential constant
// expression, then the conditional operator is not either.
- template <typename ConditionalOperator>
+ template<typename ConditionalOperator>
void CheckPotentialConstantConditional(const ConditionalOperator *E) {
assert(Info.checkingPotentialConstantExpression());
@@ -8095,7 +8109,8 @@ class ExprEvaluatorBase : public ConstStmtVisitor<Derived, bool> {
Error(E, diag::note_constexpr_conditional_never_const);
}
- template <typename ConditionalOperator>
+
+ template<typename ConditionalOperator>
bool HandleConditionalOperator(const ConditionalOperator *E) {
bool BoolResult;
if (!EvaluateAsBooleanCondition(E->getCond(), BoolResult, Info)) {
@@ -8149,7 +8164,9 @@ class ExprEvaluatorBase : public ConstStmtVisitor<Derived, bool> {
bool VisitStmt(const Stmt *) {
llvm_unreachable("Expression evaluator should not be called on stmts");
}
- bool VisitExpr(const Expr *E) { return Error(E); }
+ bool VisitExpr(const Expr *E) {
+ return Error(E);
+ }
bool VisitEmbedExpr(const EmbedExpr *E) {
const auto It = E->begin();
@@ -8166,25 +8183,18 @@ class ExprEvaluatorBase : public ConstStmtVisitor<Derived, bool> {
return StmtVisitorTy::Visit(E->getSubExpr());
}
- bool VisitParenExpr(const ParenExpr *E) {
- return StmtVisitorTy::Visit(E->getSubExpr());
- }
- bool VisitUnaryExtension(const UnaryOperator *E) {
- return StmtVisitorTy::Visit(E->getSubExpr());
- }
- bool VisitUnaryPlus(const UnaryOperator *E) {
- return StmtVisitorTy::Visit(E->getSubExpr());
- }
- bool VisitChooseExpr(const ChooseExpr *E) {
- return StmtVisitorTy::Visit(E->getChosenSubExpr());
- }
- bool VisitGenericSelectionExpr(const GenericSelectionExpr *E) {
- return StmtVisitorTy::Visit(E->getResultExpr());
- }
- bool
- VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E) {
- return StmtVisitorTy::Visit(E->getReplacement());
- }
+ bool VisitParenExpr(const ParenExpr *E)
+ { return StmtVisitorTy::Visit(E->getSubExpr()); }
+ bool VisitUnaryExtension(const UnaryOperator *E)
+ { return StmtVisitorTy::Visit(E->getSubExpr()); }
+ bool VisitUnaryPlus(const UnaryOperator *E)
+ { return StmtVisitorTy::Visit(E->getSubExpr()); }
+ bool VisitChooseExpr(const ChooseExpr *E)
+ { return StmtVisitorTy::Visit(E->getChosenSubExpr()); }
+ bool VisitGenericSelectionExpr(const GenericSelectionExpr *E)
+ { return StmtVisitorTy::Visit(E->getResultExpr()); }
+ bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E)
+ { return StmtVisitorTy::Visit(E->getReplacement()); }
bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) {
TempVersionRAII RAII(*Info.CurrentCall);
SourceLocExprScopeGuard Guard(E, Info.CurrentCall->CurSourceLocExprScope);
@@ -8213,16 +8223,16 @@ class ExprEvaluatorBase : public ConstStmtVisitor<Derived, bool> {
bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E) {
CCEDiag(E, diag::note_constexpr_invalid_cast)
<< diag::ConstexprInvalidCastKind::Reinterpret;
- return static_cast<Derived *>(this)->VisitCastExpr(E);
+ return static_cast<Derived*>(this)->VisitCastExpr(E);
}
bool VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E) {
if (!Info.Ctx.getLangOpts().CPlusPlus20)
CCEDiag(E, diag::note_constexpr_invalid_cast)
<< diag::ConstexprInvalidCastKind::Dynamic;
- return static_cast<Derived *>(this)->VisitCastExpr(E);
+ return static_cast<Derived*>(this)->VisitCastExpr(E);
}
bool VisitBuiltinBitCastExpr(const BuiltinBitCastExpr *E) {
- return static_cast<Derived *>(this)->VisitCastExpr(E);
+ return static_cast<Derived*>(this)->VisitCastExpr(E);
}
bool VisitBinaryOperator(const BinaryOperator *E) {
@@ -8272,7 +8282,7 @@ class ExprEvaluatorBase : public ConstStmtVisitor<Derived, bool> {
// side-effects. This is an important GNU extension. See GCC PR38377
// for discussion.
if (const CallExpr *CallCE =
- dyn_cast<CallExpr>(E->getCond()->IgnoreParenCasts()))
+ dyn_cast<CallExpr>(E->getCond()->IgnoreParenCasts()))
if (CallCE->getBuiltinCallee() == Builtin::BI__builtin_constant_p)
IsBcpCall = true;
@@ -8346,7 +8356,7 @@ class ExprEvaluatorBase : public ConstStmtVisitor<Derived, bool> {
}
bool handleCallExpr(const CallExpr *E, APValue &Result,
- const LValue *ResultSlot) {
+ const LValue *ResultSlot) {
CallScopeRAII CallScope(Info);
const Expr *Callee = E->getCallee()->IgnoreParens();
@@ -8408,7 +8418,7 @@ class ExprEvaluatorBase : public ConstStmtVisitor<Derived, bool> {
// Don't call function pointers which have been cast to some other type.
// Per DR (no number yet), the caller and callee can differ in noexcept.
if (!Info.Ctx.hasSameFunctionTypeIgnoringExceptionSpec(
- CalleeType->getPointeeType(), FD->getType())) {
+ CalleeType->getPointeeType(), FD->getType())) {
return Error(E);
}
@@ -8591,8 +8601,7 @@ class ExprEvaluatorBase : public ConstStmtVisitor<Derived, bool> {
QualType BaseTy = E->getBase()->getType();
const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
- if (!FD)
- return Error(E);
+ if (!FD) return Error(E);
assert(!FD->getType()->isReferenceType() && "prvalue reference?");
assert(BaseTy->castAsCanonical<RecordType>()->getOriginalDecl() ==
FD->getParent()->getCanonicalDecl() &&
@@ -8730,7 +8739,7 @@ class ExprEvaluatorBase : public ConstStmtVisitor<Derived, bool> {
}
APValue ReturnValue;
- StmtResult Result = {ReturnValue, nullptr};
+ StmtResult Result = { ReturnValue, nullptr };
EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI);
if (ESR != ESR_Succeeded) {
// FIXME: If the statement-expression terminated due to 'return',
@@ -8751,7 +8760,9 @@ class ExprEvaluatorBase : public ConstStmtVisitor<Derived, bool> {
}
/// Visit a value which is evaluated, but whose value is ignored.
- void VisitIgnoredValue(const Expr *E) { EvaluateIgnoredValue(Info, E); }
+ void VisitIgnoredValue(const Expr *E) {
+ EvaluateIgnoredValue(Info, E);
+ }
/// Potentially visit a MemberExpr's base expression.
void VisitIgnoredBaseExpression(const Expr *E) {
@@ -8769,8 +8780,9 @@ class ExprEvaluatorBase : public ConstStmtVisitor<Derived, bool> {
// Common base class for lvalue and temporary evaluation.
//===----------------------------------------------------------------------===//
namespace {
-template <class Derived>
-class LValueExprEvaluatorBase : public ExprEvaluatorBase<Derived> {
+template<class Derived>
+class LValueExprEvaluatorBase
+ : public ExprEvaluatorBase<Derived> {
protected:
LValue &Result;
bool InvalidBaseOK;
@@ -8870,7 +8882,7 @@ class LValueExprEvaluatorBase : public ExprEvaluatorBase<Derived> {
}
}
};
-} // namespace
+}
//===----------------------------------------------------------------------===//
// LValue Evaluation
@@ -8907,10 +8919,10 @@ class LValueExprEvaluatorBase : public ExprEvaluatorBase<Derived> {
//===----------------------------------------------------------------------===//
namespace {
class LValueExprEvaluator
- : public LValueExprEvaluatorBase<LValueExprEvaluator> {
+ : public LValueExprEvaluatorBase<LValueExprEvaluator> {
public:
- LValueExprEvaluator(EvalInfo &Info, LValue &Result, bool InvalidBaseOK)
- : LValueExprEvaluatorBaseTy(Info, Result, InvalidBaseOK) {}
+ LValueExprEvaluator(EvalInfo &Info, LValue &Result, bool InvalidBaseOK) :
+ LValueExprEvaluatorBaseTy(Info, Result, InvalidBaseOK) {}
bool VisitVarDecl(const Expr *E, const VarDecl *VD);
bool VisitUnaryPreIncDec(const UnaryOperator *UO);
@@ -9027,8 +9039,7 @@ static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info,
bool InvalidBaseOK) {
assert(!E->isValueDependent());
assert(E->isGLValue() || E->getType()->isFunctionType() ||
- E->getType()->isVoidType() ||
- isa<ObjCSelectorExpr>(E->IgnoreParens()));
+ E->getType()->isVoidType() || isa<ObjCSelectorExpr>(E->IgnoreParens()));
return LValueExprEvaluator(Info, Result, InvalidBaseOK).Visit(E);
}
@@ -9210,8 +9221,8 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
return true;
}
-bool LValueExprEvaluator::VisitCompoundLiteralExpr(
- const CompoundLiteralExpr *E) {
+bool
+LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
assert((!Info.getLangOpts().CPlusPlus || E->isFileScope()) &&
"lvalue compound literal in c++?");
APValue *Lit;
@@ -9250,8 +9261,8 @@ bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
} else {
if (!Info.Ctx.getLangOpts().CPlusPlus20) {
Info.CCEDiag(E, diag::note_constexpr_typeid_polymorphic)
- << E->getExprOperand()->getType()
- << E->getExprOperand()->getSourceRange();
+ << E->getExprOperand()->getType()
+ << E->getExprOperand()->getSourceRange();
}
if (!Visit(E->getExprOperand()))
@@ -9406,8 +9417,9 @@ bool LValueExprEvaluator::VisitUnaryPreIncDec(const UnaryOperator *UO) {
if (!this->Visit(UO->getSubExpr()))
return false;
- return handleIncDec(this->Info, UO, Result, UO->getSubExpr()->getType(),
- UO->isIncrementOp(), nullptr);
+ return handleIncDec(
+ this->Info, UO, Result, UO->getSubExpr()->getType(),
+ UO->isIncrementOp(), nullptr);
}
bool LValueExprEvaluator::VisitCompoundAssignOperator(
@@ -9430,8 +9442,8 @@ bool LValueExprEvaluator::VisitCompoundAssignOperator(
return false;
return handleCompoundAssignment(
- this->Info, CAO, Result, CAO->getLHS()->getType(),
- CAO->getComputationLHSType(),
+ this->Info, CAO,
+ Result, CAO->getLHS()->getType(), CAO->getComputationLHSType(),
CAO->getOpForCompoundAssignment(CAO->getOpcode()), RHS);
}
@@ -9519,7 +9531,8 @@ static bool evaluateLValueAsAllocSize(EvalInfo &Info, APValue::LValueBase Base,
}
namespace {
-class PointerExprEvaluator : public ExprEvaluatorBase<PointerExprEvaluator> {
+class PointerExprEvaluator
+ : public ExprEvaluatorBase<PointerExprEvaluator> {
LValue &Result;
bool InvalidBaseOK;
@@ -9537,8 +9550,8 @@ class PointerExprEvaluator : public ExprEvaluatorBase<PointerExprEvaluator> {
}
bool visitNonBuiltinCallExpr(const CallExpr *E);
-
public:
+
PointerExprEvaluator(EvalInfo &info, LValue &Result, bool InvalidBaseOK)
: ExprEvaluatorBaseTy(info), Result(Result),
InvalidBaseOK(InvalidBaseOK) {}
@@ -9553,9 +9566,10 @@ class PointerExprEvaluator : public ExprEvaluatorBase<PointerExprEvaluator> {
}
bool VisitBinaryOperator(const BinaryOperator *E);
- bool VisitCastExpr(const CastExpr *E);
+ bool VisitCastExpr(const CastExpr* E);
bool VisitUnaryAddrOf(const UnaryOperator *E);
- bool VisitObjCStringLiteral(const ObjCStringLiteral *E) { return Success(E); }
+ bool VisitObjCStringLiteral(const ObjCStringLiteral *E)
+ { return Success(E); }
bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E) {
if (E->isExpressibleAsConstantInitializer())
return Success(E);
@@ -9563,7 +9577,8 @@ class PointerExprEvaluator : public ExprEvaluatorBase<PointerExprEvaluator> {
EvaluateIgnoredValue(Info, E->getSubExpr());
return Error(E);
}
- bool VisitAddrLabelExpr(const AddrLabelExpr *E) { return Success(E); }
+ bool VisitAddrLabelExpr(const AddrLabelExpr *E)
+ { return Success(E); }
bool VisitCallExpr(const CallExpr *E);
bool VisitBuiltinCallExpr(const CallExpr *E, unsigned BuiltinOp);
bool VisitBlockExpr(const BlockExpr *E) {
@@ -9653,7 +9668,7 @@ class PointerExprEvaluator : public ExprEvaluatorBase<PointerExprEvaluator> {
};
} // end anonymous namespace
-static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info,
+static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info,
bool InvalidBaseOK) {
assert(!E->isValueDependent());
assert(E->isPRValue() && E->getType()->hasPointerRepresentation());
@@ -9661,7 +9676,8 @@ static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info,
}
bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
- if (E->getOpcode() != BO_Add && E->getOpcode() != BO_Sub)
+ if (E->getOpcode() != BO_Add &&
+ E->getOpcode() != BO_Sub)
return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
const Expr *PExp = E->getLHS();
@@ -9783,10 +9799,9 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
// Now figure out the necessary offset to add to the base LV to get from
// the derived class to the base class.
- return HandleLValueBasePath(
- Info, E,
- E->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType(),
- Result);
+ return HandleLValueBasePath(Info, E, E->getSubExpr()->getType()->
+ castAs<PointerType>()->getPointeeType(),
+ Result);
case CK_BaseToDerived:
if (!Visit(E->getSubExpr()))
@@ -10112,7 +10127,8 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
if (!EvaluateInteger(E->getArg(1), Desired, Info))
return false;
uint64_t MaxLength = uint64_t(-1);
- if (BuiltinOp != Builtin::BIstrchr && BuiltinOp != Builtin::BIwcschr &&
+ if (BuiltinOp != Builtin::BIstrchr &&
+ BuiltinOp != Builtin::BIwcschr &&
BuiltinOp != Builtin::BI__builtin_strchr &&
BuiltinOp != Builtin::BI__builtin_wcschr) {
APSInt N;
@@ -10129,8 +10145,9 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
QualType CharTy = Result.Designator.getType(Info.Ctx);
bool IsRawByte = BuiltinOp == Builtin::BImemchr ||
BuiltinOp == Builtin::BI__builtin_memchr;
- assert(IsRawByte || Info.Ctx.hasSameUnqualifiedType(
- CharTy, E->getArg(0)->getType()->getPointeeType()));
+ assert(IsRawByte ||
+ Info.Ctx.hasSameUnqualifiedType(
+ CharTy, E->getArg(0)->getType()->getPointeeType()));
// Pointers to const void may point to objects of incomplete type.
if (IsRawByte && CharTy->isIncompleteType()) {
Info.FFDiag(E, diag::note_constexpr_ltor_incomplete_type) << CharTy;
@@ -10281,7 +10298,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
llvm::APInt::udivrem(OrigN, TSize, N, Remainder);
if (Remainder) {
Info.FFDiag(E, diag::note_constexpr_memcpy_unsupported)
- << Move << WChar << 0 << T << toString(OrigN, 10, /*Signed*/ false)
+ << Move << WChar << 0 << T << toString(OrigN, 10, /*Signed*/false)
<< (unsigned)TSize;
return false;
}
@@ -10295,7 +10312,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
if (N.ugt(RemainingSrcSize) || N.ugt(RemainingDestSize)) {
Info.FFDiag(E, diag::note_constexpr_memcpy_unsupported)
<< Move << WChar << (N.ugt(RemainingSrcSize) ? 1 : 2) << T
- << toString(N, 10, /*Signed*/ false);
+ << toString(N, 10, /*Signed*/false);
return false;
}
uint64_t NElems = N.getZExtValue();
@@ -10491,7 +10508,8 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
AllocType = Info.Ctx.getConstantArrayType(AllocType, ArrayBound, nullptr,
ArraySizeModifier::Normal, 0);
} else {
- assert(!AllocType->isArrayType() && "array allocation with non-array new");
+ assert(!AllocType->isArrayType() &&
+ "array allocation with non-array new");
}
APValue *Val;
@@ -10594,24 +10612,24 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
namespace {
class MemberPointerExprEvaluator
- : public ExprEvaluatorBase<MemberPointerExprEvaluator> {
+ : public ExprEvaluatorBase<MemberPointerExprEvaluator> {
MemberPtr &Result;
bool Success(const ValueDecl *D) {
Result = MemberPtr(D);
return true;
}
-
public:
+
MemberPointerExprEvaluator(EvalInfo &Info, MemberPtr &Result)
- : ExprEvaluatorBaseTy(Info), Result(Result) {}
+ : ExprEvaluatorBaseTy(Info), Result(Result) {}
bool Success(const APValue &V, const Expr *E) {
Result.setFrom(V);
return true;
}
bool ZeroInitialization(const Expr *E) {
- return Success((const ValueDecl *)nullptr);
+ return Success((const ValueDecl*)nullptr);
}
bool VisitCastExpr(const CastExpr *E);
@@ -10662,8 +10680,7 @@ bool MemberPointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (!Visit(E->getSubExpr()))
return false;
for (CastExpr::path_const_iterator PathI = E->path_begin(),
- PathE = E->path_end();
- PathI != PathE; ++PathI) {
+ PathE = E->path_end(); PathI != PathE; ++PathI) {
assert(!(*PathI)->isVirtual() && "memptr cast through vbase");
const CXXRecordDecl *Base = (*PathI)->getType()->getAsCXXRecordDecl();
if (!Result.castToBase(Base))
@@ -10684,41 +10701,42 @@ bool MemberPointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
//===----------------------------------------------------------------------===//
namespace {
-class RecordExprEvaluator : public ExprEvaluatorBase<RecordExprEvaluator> {
- const LValue &This;
- APValue &Result;
+ class RecordExprEvaluator
+ : public ExprEvaluatorBase<RecordExprEvaluator> {
+ const LValue &This;
+ APValue &Result;
+ public:
-public:
- RecordExprEvaluator(EvalInfo &info, const LValue &This, APValue &Result)
+ RecordExprEvaluator(EvalInfo &info, const LValue &This, APValue &Result)
: ExprEvaluatorBaseTy(info), This(This), Result(Result) {}
- bool Success(const APValue &V, const Expr *E) {
- Result = V;
- return true;
- }
- bool ZeroInitialization(const Expr *E) {
- return ZeroInitialization(E, E->getType());
- }
- bool ZeroInitialization(const Expr *E, QualType T);
+ bool Success(const APValue &V, const Expr *E) {
+ Result = V;
+ return true;
+ }
+ bool ZeroInitialization(const Expr *E) {
+ return ZeroInitialization(E, E->getType());
+ }
+ bool ZeroInitialization(const Expr *E, QualType T);
- bool VisitCallExpr(const CallExpr *E) {
- return handleCallExpr(E, Result, &This);
- }
- bool VisitCastExpr(const CastExpr *E);
- bool VisitInitListExpr(const InitListExpr *E);
- bool VisitCXXConstructExpr(const CXXConstructExpr *E) {
- return VisitCXXConstructExpr(E, E->getType());
- }
- bool VisitLambdaExpr(const LambdaExpr *E);
- bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
- bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T);
- bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
- bool VisitBinCmp(const BinaryOperator *E);
- bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
- bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit,
- ArrayRef<Expr *> Args);
-};
-} // namespace
+ bool VisitCallExpr(const CallExpr *E) {
+ return handleCallExpr(E, Result, &This);
+ }
+ bool VisitCastExpr(const CastExpr *E);
+ bool VisitInitListExpr(const InitListExpr *E);
+ bool VisitCXXConstructExpr(const CXXConstructExpr *E) {
+ return VisitCXXConstructExpr(E, E->getType());
+ }
+ bool VisitLambdaExpr(const LambdaExpr *E);
+ bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
+ bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T);
+ bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
+ bool VisitBinCmp(const BinaryOperator *E);
+ bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
+ bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit,
+ ArrayRef<Expr *> Args);
+ };
+}
/// Perform zero-initialization on an object of non-union class type.
/// C++11 [dcl.init]p5:
@@ -10735,15 +10753,13 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E,
Result = APValue(APValue::UninitStruct(), CD ? CD->getNumBases() : 0,
std::distance(RD->field_begin(), RD->field_end()));
- if (RD->isInvalidDecl())
- return false;
+ if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
if (CD) {
unsigned Index = 0;
for (CXXRecordDecl::base_class_const_iterator I = CD->bases_begin(),
- End = CD->bases_end();
- I != End; ++I, ++Index) {
+ End = CD->bases_end(); I != End; ++I, ++Index) {
const CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl();
LValue Subobject = This;
if (!HandleLValueDirectBase(Info, E, Subobject, CD, Base, &Layout))
@@ -10764,8 +10780,8 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E,
return false;
ImplicitValueInitExpr VIE(I->getType());
- if (!EvaluateInPlace(Result.getStructField(I->getFieldIndex()), Info,
- Subobject, &VIE))
+ if (!EvaluateInPlace(
+ Result.getStructField(I->getFieldIndex()), Info, Subobject, &VIE))
return false;
}
@@ -10774,8 +10790,7 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E,
bool RecordExprEvaluator::ZeroInitialization(const Expr *E, QualType T) {
const auto *RD = T->castAsRecordDecl();
- if (RD->isInvalidDecl())
- return false;
+ if (RD->isInvalidDecl()) return false;
if (RD->isUnion()) {
// C++11 [dcl.init]p5: If T is a (possibly cv-qualified) union type, the
// object's first non-static named data member is zero-initialized
@@ -10783,7 +10798,7 @@ bool RecordExprEvaluator::ZeroInitialization(const Expr *E, QualType T) {
while (I != RD->field_end() && (*I)->isUnnamedBitField())
++I;
if (I == RD->field_end()) {
- Result = APValue((const FieldDecl *)nullptr);
+ Result = APValue((const FieldDecl*)nullptr);
return true;
}
@@ -10823,8 +10838,7 @@ bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) {
APValue *Value = &DerivedObject;
const CXXRecordDecl *RD = E->getSubExpr()->getType()->getAsCXXRecordDecl();
for (CastExpr::path_const_iterator PathI = E->path_begin(),
- PathE = E->path_end();
- PathI != PathE; ++PathI) {
+ PathE = E->path_end(); PathI != PathE; ++PathI) {
assert(!(*PathI)->isVirtual() && "record rvalue with virtual base");
const CXXRecordDecl *Base = (*PathI)->getType()->getAsCXXRecordDecl();
Value = &Value->getStructBase(getBaseIndex(RD, Base));
@@ -10845,8 +10859,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
const Expr *ExprToVisit, ArrayRef<Expr *> Args) {
const auto *RD = ExprToVisit->getType()->castAsRecordDecl();
- if (RD->isInvalidDecl())
- return false;
+ if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
@@ -10989,8 +11002,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
// Note that E's type is not necessarily the type of our class here; we might
// be initializing an array element instead.
const CXXConstructorDecl *FD = E->getConstructor();
- if (FD->isInvalidDecl() || FD->getParent()->isInvalidDecl())
- return false;
+ if (FD->isInvalidDecl() || FD->getParent()->isInvalidDecl()) return false;
bool ZeroInit = E->requiresZeroInitialization();
if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD, ZeroInit)) {
@@ -11025,8 +11037,9 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
return false;
auto Args = ArrayRef(E->getArgs(), E->getNumArgs());
- return HandleConstructorCall(
- E, This, Args, cast<CXXConstructorDecl>(Definition), Info, Result);
+ return HandleConstructorCall(E, This, Args,
+ cast<CXXConstructorDecl>(Definition), Info,
+ Result);
}
bool RecordExprEvaluator::VisitCXXInheritedCtorInitExpr(
@@ -11113,7 +11126,7 @@ bool RecordExprEvaluator::VisitLambdaExpr(const LambdaExpr *E) {
"The number of lambda capture initializers should equal the number of "
"fields within the closure type");
- Result = APValue(APValue::UninitStruct(), /*NumBases*/ 0, NumFields);
+ Result = APValue(APValue::UninitStruct(), /*NumBases*/0, NumFields);
// Iterate through all the lambda's closure object's fields and initialize
// them.
auto *CaptureInitIt = E->capture_init_begin();
@@ -11144,8 +11157,8 @@ bool RecordExprEvaluator::VisitLambdaExpr(const LambdaExpr *E) {
return Success;
}
-static bool EvaluateRecord(const Expr *E, const LValue &This, APValue &Result,
- EvalInfo &Info) {
+static bool EvaluateRecord(const Expr *E, const LValue &This,
+ APValue &Result, EvalInfo &Info) {
assert(!E->isValueDependent());
assert(E->isPRValue() && E->getType()->isRecordType() &&
"can't evaluate expression as a record rvalue");
@@ -11161,10 +11174,10 @@ static bool EvaluateRecord(const Expr *E, const LValue &This, APValue &Result,
//===----------------------------------------------------------------------===//
namespace {
class TemporaryExprEvaluator
- : public LValueExprEvaluatorBase<TemporaryExprEvaluator> {
+ : public LValueExprEvaluatorBase<TemporaryExprEvaluator> {
public:
- TemporaryExprEvaluator(EvalInfo &Info, LValue &Result)
- : LValueExprEvaluatorBaseTy(Info, Result, false) {}
+ TemporaryExprEvaluator(EvalInfo &Info, LValue &Result) :
+ LValueExprEvaluatorBaseTy(Info, Result, false) {}
/// Visit an expression which constructs the value of this temporary.
bool VisitConstructExpr(const Expr *E) {
@@ -11188,11 +11201,15 @@ class TemporaryExprEvaluator
bool VisitCXXConstructExpr(const CXXConstructExpr *E) {
return VisitConstructExpr(E);
}
- bool VisitCallExpr(const CallExpr *E) { return VisitConstructExpr(E); }
+ bool VisitCallExpr(const CallExpr *E) {
+ return VisitConstructExpr(E);
+ }
bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E) {
return VisitConstructExpr(E);
}
- bool VisitLambdaExpr(const LambdaExpr *E) { return VisitConstructExpr(E); }
+ bool VisitLambdaExpr(const LambdaExpr *E) {
+ return VisitConstructExpr(E);
+ }
};
} // end anonymous namespace
@@ -11208,42 +11225,44 @@ static bool EvaluateTemporary(const Expr *E, LValue &Result, EvalInfo &Info) {
//===----------------------------------------------------------------------===//
namespace {
-class VectorExprEvaluator : public ExprEvaluatorBase<VectorExprEvaluator> {
- APValue &Result;
+ class VectorExprEvaluator
+ : public ExprEvaluatorBase<VectorExprEvaluator> {
+ APValue &Result;
+ public:
-public:
- VectorExprEvaluator(EvalInfo &info, APValue &Result)
+ VectorExprEvaluator(EvalInfo &info, APValue &Result)
: ExprEvaluatorBaseTy(info), Result(Result) {}
- bool Success(ArrayRef<APValue> V, const Expr *E) {
- assert(V.size() == E->getType()->castAs<VectorType>()->getNumElements());
- // FIXME: remove this APValue copy.
- Result = APValue(V.data(), V.size());
- return true;
- }
- bool Success(const APValue &V, const Expr *E) {
- assert(V.isVector());
- Result = V;
- return true;
- }
- bool ZeroInitialization(const Expr *E);
-
- bool VisitUnaryReal(const UnaryOperator *E) { return Visit(E->getSubExpr()); }
- bool VisitCastExpr(const CastExpr *E);
- bool VisitInitListExpr(const InitListExpr *E);
- bool VisitUnaryImag(const UnaryOperator *E);
- bool VisitBinaryOperator(const BinaryOperator *E);
- bool VisitUnaryOperator(const UnaryOperator *E);
- bool VisitCallExpr(const CallExpr *E);
- bool VisitConvertVectorExpr(const ConvertVectorExpr *E);
- bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E);
-
- // FIXME: Missing: conditional operator (for GNU
- // conditional select), ExtVectorElementExpr
-};
+ bool Success(ArrayRef<APValue> V, const Expr *E) {
+ assert(V.size() == E->getType()->castAs<VectorType>()->getNumElements());
+ // FIXME: remove this APValue copy.
+ Result = APValue(V.data(), V.size());
+ return true;
+ }
+ bool Success(const APValue &V, const Expr *E) {
+ assert(V.isVector());
+ Result = V;
+ return true;
+ }
+ bool ZeroInitialization(const Expr *E);
+
+ bool VisitUnaryReal(const UnaryOperator *E)
+ { return Visit(E->getSubExpr()); }
+ bool VisitCastExpr(const CastExpr* E);
+ bool VisitInitListExpr(const InitListExpr *E);
+ bool VisitUnaryImag(const UnaryOperator *E);
+ bool VisitBinaryOperator(const BinaryOperator *E);
+ bool VisitUnaryOperator(const UnaryOperator *E);
+ bool VisitCallExpr(const CallExpr *E);
+ bool VisitConvertVectorExpr(const ConvertVectorExpr *E);
+ bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E);
+
+ // FIXME: Missing: conditional operator (for GNU
+ // conditional select), ExtVectorElementExpr
+ };
} // end anonymous namespace
-static bool EvaluateVector(const Expr *E, APValue &Result, EvalInfo &Info) {
+static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) {
assert(E->isPRValue() && E->getType()->isVectorType() &&
"not a vector prvalue");
return VectorExprEvaluator(Info, Result).Visit(E);
@@ -11328,7 +11347,8 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) {
}
}
-bool VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
+bool
+VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
const VectorType *VT = E->getType()->castAs<VectorType>();
unsigned NumInits = E->getNumInits();
unsigned NumElements = VT->getNumElements();
@@ -11348,8 +11368,8 @@ bool VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
unsigned CountInits = 0, CountElts = 0;
while (CountElts < NumElements) {
// Handle nested vector initialization.
- if (CountInits < NumInits &&
- E->getInit(CountInits)->getType()->isVectorType()) {
+ if (CountInits < NumInits
+ && E->getInit(CountInits)->getType()->isVectorType()) {
APValue v;
if (!EvaluateVector(E->getInit(CountInits), v, Info))
return Error(E);
@@ -11381,7 +11401,8 @@ bool VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
return Success(Elements, E);
}
-bool VectorExprEvaluator::ZeroInitialization(const Expr *E) {
+bool
+VectorExprEvaluator::ZeroInitialization(const Expr *E) {
const auto *VT = E->getType()->castAs<VectorType>();
QualType EltTy = VT->getElementType();
APValue ZeroElement;
@@ -11847,319 +11868,292 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
return Success(APValue(ResultElements.data(), ResultElements.size()), E);
}
+case X86::BI__builtin_ia32_pshufw: {
+ APValue Src;
+ APSInt Imm;
+ if (!EvaluateAsRValue(Info, E->getArg(0), Src)) return false;
+ if (!EvaluateInteger(E->getArg(1), Imm, Info)) return false;
- case X86::BI__builtin_ia32_pshufw: {
- APValue Src;
- APSInt Imm;
- if (!EvaluateAsRValue(Info, E->getArg(0), Src))
- return false;
- if (!EvaluateInteger(E->getArg(1), Imm, Info))
- return false;
-
- unsigned N = Src.getVectorLength();
- SmallVector<APValue, 4> ResultElements;
- ResultElements.reserve(N);
+ unsigned N = Src.getVectorLength();
+ SmallVector<APValue, 4> ResultElements;
+ ResultElements.reserve(N);
- uint8_t C = static_cast<uint8_t>(Imm.getZExtValue());
- for (unsigned i = 0; i != N; ++i) {
- unsigned sel = (C >> (2 * i)) & 0x3;
- ResultElements.push_back(Src.getVectorElt(sel));
- }
- return Success(APValue(ResultElements.data(), ResultElements.size()), E);
+ uint8_t C = static_cast<uint8_t>(Imm.getZExtValue());
+ for (unsigned i = 0; i != N; ++i) {
+ unsigned sel = (C >> (2 * i)) & 0x3;
+ ResultElements.push_back(Src.getVectorElt(sel));
}
+ return Success(APValue(ResultElements.data(), ResultElements.size()), E);
+}
- case clang::X86::BI__builtin_ia32_pshuflw:
- case clang::X86::BI__builtin_ia32_pshuflw256:
- case clang::X86::BI__builtin_ia32_pshuflw512:
- case clang::X86::BI__builtin_ia32_pshuflw128_mask:
- case clang::X86::BI__builtin_ia32_pshuflw256_mask:
- case clang::X86::BI__builtin_ia32_pshuflw512_mask:
- case clang::X86::BI__builtin_ia32_pshuflw128_maskz:
- case clang::X86::BI__builtin_ia32_pshuflw256_maskz:
- case clang::X86::BI__builtin_ia32_pshuflw512_maskz: {
- const unsigned BID = E->getBuiltinCallee();
-
- const bool IsMask = BID == clang::X86::BI__builtin_ia32_pshuflw128_mask ||
- BID == clang::X86::BI__builtin_ia32_pshuflw256_mask ||
- BID == clang::X86::BI__builtin_ia32_pshuflw512_mask;
-
- const bool IsMaskZ = BID == clang::X86::BI__builtin_ia32_pshuflw128_maskz ||
- BID == clang::X86::BI__builtin_ia32_pshuflw256_maskz ||
- BID == clang::X86::BI__builtin_ia32_pshuflw512_maskz;
-
- const unsigned AIdx = 0, ImmIdx = 1;
- const unsigned SrcIdx = 2;
- const unsigned KIdx = IsMaskZ ? 2 : 3;
+case clang::X86::BI__builtin_ia32_pshuflw:
+case clang::X86::BI__builtin_ia32_pshuflw256:
+case clang::X86::BI__builtin_ia32_pshuflw512:
+case clang::X86::BI__builtin_ia32_pshuflw128_mask:
+case clang::X86::BI__builtin_ia32_pshuflw256_mask:
+case clang::X86::BI__builtin_ia32_pshuflw512_mask:
+case clang::X86::BI__builtin_ia32_pshuflw128_maskz:
+case clang::X86::BI__builtin_ia32_pshuflw256_maskz:
+case clang::X86::BI__builtin_ia32_pshuflw512_maskz: {
+ const unsigned BID = E->getBuiltinCallee();
+
+ const bool IsMask =
+ BID == clang::X86::BI__builtin_ia32_pshuflw128_mask ||
+ BID == clang::X86::BI__builtin_ia32_pshuflw256_mask ||
+ BID == clang::X86::BI__builtin_ia32_pshuflw512_mask;
+
+ const bool IsMaskZ =
+ BID == clang::X86::BI__builtin_ia32_pshuflw128_maskz ||
+ BID == clang::X86::BI__builtin_ia32_pshuflw256_maskz ||
+ BID == clang::X86::BI__builtin_ia32_pshuflw512_maskz;
+
+ const unsigned AIdx = 0, ImmIdx = 1;
+ const unsigned SrcIdx = 2;
+ const unsigned KIdx = IsMaskZ ? 2 : 3;
+
+ APValue AVal, SrcVal;
+ APSInt Imm, K;
+ if (!EvaluateAsRValue(Info, E->getArg(AIdx), AVal)) return false;
+ if (!EvaluateInteger(E->getArg(ImmIdx), Imm, Info)) return false;
+
+ const APSInt *KPtr = nullptr;
+ const APValue *PassThru = nullptr;
+ bool ZeroInactive = false;
+
+ if (IsMask) {
+ if (!EvaluateAsRValue(Info, E->getArg(SrcIdx), SrcVal)) return false;
+ if (!EvaluateInteger(E->getArg(KIdx), K, Info)) return false;
+ KPtr = &K; PassThru = &SrcVal; ZeroInactive = false;
+ } else if (IsMaskZ) {
+ if (!EvaluateInteger(E->getArg(KIdx), K, Info)) return false;
+ KPtr = &K; PassThru = nullptr; ZeroInactive = true;
+ }
+
+ const auto *VT = E->getType()->getAs<VectorType>();
+ if (!VT) return false;
+ const unsigned NumElts = VT->getNumElements();
+
+ const unsigned ElemBits = 16;
+ const unsigned LaneElems = std::min(NumElts, 128u / ElemBits);
+ const unsigned Half = 4;
+ const uint8_t Ctl = static_cast<uint8_t>(Imm.getZExtValue());
+ const bool DestUnsigned =
+ VT->getElementType()->isUnsignedIntegerOrEnumerationType();
+
+ auto MakeZero = [&]() -> APValue {
+ return APValue(APSInt(APInt(ElemBits, 0), DestUnsigned));
+ };
- APValue AVal, SrcVal;
- APSInt Imm, K;
- if (!EvaluateAsRValue(Info, E->getArg(AIdx), AVal))
- return false;
- if (!EvaluateInteger(E->getArg(ImmIdx), Imm, Info))
- return false;
+ SmallVector<APValue, 32> ResultElements;
+ ResultElements.reserve(NumElts);
- const APSInt *KPtr = nullptr;
- const APValue *PassThru = nullptr;
- bool ZeroInactive = false;
+ for (unsigned i = 0; i < NumElts; ++i) {
+ const unsigned laneBase = (i / LaneElems) * LaneElems;
+ const unsigned inLane = i % LaneElems;
- if (IsMask) {
- if (!EvaluateAsRValue(Info, E->getArg(SrcIdx), SrcVal))
- return false;
- if (!EvaluateInteger(E->getArg(KIdx), K, Info))
- return false;
- KPtr = &K;
- PassThru = &SrcVal;
- ZeroInactive = false;
- } else if (IsMaskZ) {
- if (!EvaluateInteger(E->getArg(KIdx), K, Info))
- return false;
- KPtr = &K;
- PassThru = nullptr;
- ZeroInactive = true;
+ APValue Chosen;
+ if (inLane < Half) {
+ const unsigned pos = inLane;
+ const unsigned sel = (Ctl >> (2 * pos)) & 0x3;
+ const unsigned srcIdx = laneBase + sel;
+ Chosen = AVal.getVectorElt(srcIdx);
+ } else {
+ Chosen = AVal.getVectorElt(i);
}
- const auto *VT = E->getType()->getAs<VectorType>();
- if (!VT)
- return false;
- const unsigned NumElts = VT->getNumElements();
-
- const unsigned ElemBits = 16;
- const unsigned LaneElems = std::min(NumElts, 128u / ElemBits);
- const unsigned Half = 4;
- const uint8_t Ctl = static_cast<uint8_t>(Imm.getZExtValue());
- const bool DestUnsigned =
- VT->getElementType()->isUnsignedIntegerOrEnumerationType();
-
- auto MakeZero = [&]() -> APValue {
- return APValue(APSInt(APInt(ElemBits, 0), DestUnsigned));
- };
-
- SmallVector<APValue, 32> ResultElements;
- ResultElements.reserve(NumElts);
-
- for (unsigned i = 0; i < NumElts; ++i) {
- const unsigned laneBase = (i / LaneElems) * LaneElems;
- const unsigned inLane = i % LaneElems;
-
- APValue Chosen;
- if (inLane < Half) {
- const unsigned pos = inLane;
- const unsigned sel = (Ctl >> (2 * pos)) & 0x3;
- const unsigned srcIdx = laneBase + sel;
- Chosen = AVal.getVectorElt(srcIdx);
- } else {
- Chosen = AVal.getVectorElt(i);
- }
-
- if (KPtr) {
- const bool Keep = (i < KPtr->getBitWidth()) ? (*KPtr)[i] : false;
- if (Keep) {
- ResultElements.push_back(Chosen);
- } else if (ZeroInactive) {
- ResultElements.push_back(MakeZero());
- } else {
- const APValue &PT =
- PassThru ? PassThru->getVectorElt(i) : AVal.getVectorElt(i);
- ResultElements.push_back(PT);
- }
- } else {
+ if (KPtr) {
+ const bool Keep = (i < KPtr->getBitWidth()) ? (*KPtr)[i] : false;
+ if (Keep) {
ResultElements.push_back(Chosen);
+ } else if (ZeroInactive) {
+ ResultElements.push_back(MakeZero());
+ } else {
+ const APValue &PT = PassThru ? PassThru->getVectorElt(i)
+ : AVal.getVectorElt(i);
+ ResultElements.push_back(PT);
}
+ } else {
+ ResultElements.push_back(Chosen);
}
- return Success(APValue(ResultElements.data(), ResultElements.size()), E);
}
+ return Success(APValue(ResultElements.data(), ResultElements.size()), E);
+}
- case clang::X86::BI__builtin_ia32_pshufhw:
- case clang::X86::BI__builtin_ia32_pshufhw256:
- case clang::X86::BI__builtin_ia32_pshufhw512:
- case clang::X86::BI__builtin_ia32_pshufhw128_mask:
- case clang::X86::BI__builtin_ia32_pshufhw256_mask:
- case clang::X86::BI__builtin_ia32_pshufhw512_mask:
- case clang::X86::BI__builtin_ia32_pshufhw128_maskz:
- case clang::X86::BI__builtin_ia32_pshufhw256_maskz:
- case clang::X86::BI__builtin_ia32_pshufhw512_maskz: {
- const unsigned BID = E->getBuiltinCallee();
-
- const bool IsMask = BID == clang::X86::BI__builtin_ia32_pshufhw128_mask ||
- BID == clang::X86::BI__builtin_ia32_pshufhw256_mask ||
- BID == clang::X86::BI__builtin_ia32_pshufhw512_mask;
-
- const bool IsMaskZ = BID == clang::X86::BI__builtin_ia32_pshufhw128_maskz ||
- BID == clang::X86::BI__builtin_ia32_pshufhw256_maskz ||
- BID == clang::X86::BI__builtin_ia32_pshufhw512_maskz;
+case clang::X86::BI__builtin_ia32_pshufhw:
+case clang::X86::BI__builtin_ia32_pshufhw256:
+case clang::X86::BI__builtin_ia32_pshufhw512:
+case clang::X86::BI__builtin_ia32_pshufhw128_mask:
+case clang::X86::BI__builtin_ia32_pshufhw256_mask:
+case clang::X86::BI__builtin_ia32_pshufhw512_mask:
+case clang::X86::BI__builtin_ia32_pshufhw128_maskz:
+case clang::X86::BI__builtin_ia32_pshufhw256_maskz:
+case clang::X86::BI__builtin_ia32_pshufhw512_maskz: {
+ const unsigned BID = E->getBuiltinCallee();
+
+ const bool IsMask =
+ BID == clang::X86::BI__builtin_ia32_pshufhw128_mask ||
+ BID == clang::X86::BI__builtin_ia32_pshufhw256_mask ||
+ BID == clang::X86::BI__builtin_ia32_pshufhw512_mask;
+
+ const bool IsMaskZ =
+ BID == clang::X86::BI__builtin_ia32_pshufhw128_maskz ||
+ BID == clang::X86::BI__builtin_ia32_pshufhw256_maskz ||
+ BID == clang::X86::BI__builtin_ia32_pshufhw512_maskz;
+
+ const unsigned AIdx = 0, ImmIdx = 1;
+ const unsigned SrcIdx = 2;
+ const unsigned KIdx = IsMaskZ ? 2 : 3;
+
+ APValue AVal, SrcVal;
+ APSInt Imm, K;
+ if (!EvaluateAsRValue(Info, E->getArg(AIdx), AVal)) return false;
+ if (!EvaluateInteger(E->getArg(ImmIdx), Imm, Info)) return false;
+
+ const APSInt *KPtr = nullptr;
+ const APValue *PassThru = nullptr;
+ bool ZeroInactive = false;
+ if (IsMask) {
+ if (!EvaluateAsRValue(Info, E->getArg(SrcIdx), SrcVal)) return false;
+ if (!EvaluateInteger(E->getArg(KIdx), K, Info)) return false;
+ KPtr = &K; PassThru = &SrcVal; ZeroInactive = false;
+ } else if (IsMaskZ) {
+ if (!EvaluateInteger(E->getArg(KIdx), K, Info)) return false;
+ KPtr = &K; PassThru = nullptr; ZeroInactive = true;
+ }
+
+ const auto *VT = E->getType()->getAs<VectorType>();
+ if (!VT) return false;
+ const unsigned NumElts = VT->getNumElements();
+ const unsigned ElemBits = 16;
+ const unsigned LaneElems = std::min(NumElts, 128u / ElemBits);
+ const unsigned Half = 4;
+ const uint8_t Ctl = static_cast<uint8_t>(Imm.getZExtValue());
+ const bool DestUnsigned =
+ VT->getElementType()->isUnsignedIntegerOrEnumerationType();
+
+ auto MakeZero = [&]() -> APValue {
+ return APValue(APSInt(APInt(ElemBits, 0), DestUnsigned));
+ };
- const unsigned AIdx = 0, ImmIdx = 1;
- const unsigned SrcIdx = 2;
- const unsigned KIdx = IsMaskZ ? 2 : 3;
+ SmallVector<APValue, 32> Out;
+ Out.reserve(NumElts);
- APValue AVal, SrcVal;
- APSInt Imm, K;
- if (!EvaluateAsRValue(Info, E->getArg(AIdx), AVal))
- return false;
- if (!EvaluateInteger(E->getArg(ImmIdx), Imm, Info))
- return false;
+ for (unsigned i = 0; i < NumElts; ++i) {
+ const unsigned laneBase = (i / LaneElems) * LaneElems;
+ const unsigned inLane = i % LaneElems;
- const APSInt *KPtr = nullptr;
- const APValue *PassThru = nullptr;
- bool ZeroInactive = false;
- if (IsMask) {
- if (!EvaluateAsRValue(Info, E->getArg(SrcIdx), SrcVal))
- return false;
- if (!EvaluateInteger(E->getArg(KIdx), K, Info))
- return false;
- KPtr = &K;
- PassThru = &SrcVal;
- ZeroInactive = false;
- } else if (IsMaskZ) {
- if (!EvaluateInteger(E->getArg(KIdx), K, Info))
- return false;
- KPtr = &K;
- PassThru = nullptr;
- ZeroInactive = true;
+ APValue Chosen;
+ if (inLane >= Half) {
+ const unsigned pos = inLane - Half;
+ const unsigned sel = (Ctl >> (2 * pos)) & 0x3;
+ const unsigned srcIdx = laneBase + Half + sel;
+ Chosen = AVal.getVectorElt(srcIdx);
+ } else {
+ Chosen = AVal.getVectorElt(i);
}
- const auto *VT = E->getType()->getAs<VectorType>();
- if (!VT)
- return false;
- const unsigned NumElts = VT->getNumElements();
- const unsigned ElemBits = 16;
- const unsigned LaneElems = std::min(NumElts, 128u / ElemBits);
- const unsigned Half = 4;
- const uint8_t Ctl = static_cast<uint8_t>(Imm.getZExtValue());
- const bool DestUnsigned =
- VT->getElementType()->isUnsignedIntegerOrEnumerationType();
-
- auto MakeZero = [&]() -> APValue {
- return APValue(APSInt(APInt(ElemBits, 0), DestUnsigned));
- };
-
- SmallVector<APValue, 32> Out;
- Out.reserve(NumElts);
-
- for (unsigned i = 0; i < NumElts; ++i) {
- const unsigned laneBase = (i / LaneElems) * LaneElems;
- const unsigned inLane = i % LaneElems;
-
- APValue Chosen;
- if (inLane >= Half) {
- const unsigned pos = inLane - Half;
- const unsigned sel = (Ctl >> (2 * pos)) & 0x3;
- const unsigned srcIdx = laneBase + Half + sel;
- Chosen = AVal.getVectorElt(srcIdx);
- } else {
- Chosen = AVal.getVectorElt(i);
- }
-
- if (KPtr) {
- const bool Keep = (i < KPtr->getBitWidth()) ? (*KPtr)[i] : false;
- if (Keep) {
- Out.push_back(Chosen);
- } else if (ZeroInactive) {
- Out.push_back(MakeZero());
- } else {
- const APValue &PT =
- PassThru ? PassThru->getVectorElt(i) : AVal.getVectorElt(i);
- Out.push_back(PT);
- }
- } else {
+ if (KPtr) {
+ const bool Keep = (i < KPtr->getBitWidth()) ? (*KPtr)[i] : false;
+ if (Keep) {
Out.push_back(Chosen);
+ } else if (ZeroInactive) {
+ Out.push_back(MakeZero());
+ } else {
+ const APValue &PT = PassThru ? PassThru->getVectorElt(i)
+ : AVal.getVectorElt(i);
+ Out.push_back(PT);
}
- }
- return Success(APValue(Out.data(), Out.size()), E);
- }
-
- case clang::X86::BI__builtin_ia32_pshufd:
- case clang::X86::BI__builtin_ia32_pshufd256:
- case clang::X86::BI__builtin_ia32_pshufd512:
- case clang::X86::BI__builtin_ia32_pshufd128_mask:
- case clang::X86::BI__builtin_ia32_pshufd256_mask:
- case clang::X86::BI__builtin_ia32_pshufd512_mask:
- case clang::X86::BI__builtin_ia32_pshufd128_maskz:
- case clang::X86::BI__builtin_ia32_pshufd256_maskz:
- case clang::X86::BI__builtin_ia32_pshufd512_maskz: {
- const unsigned BID = E->getBuiltinCallee();
-
- const bool IsMask = BID == clang::X86::BI__builtin_ia32_pshufd512_mask ||
- BID == clang::X86::BI__builtin_ia32_pshufd128_mask ||
- BID == clang::X86::BI__builtin_ia32_pshufd256_mask;
-
- const bool IsMaskZ = BID == clang::X86::BI__builtin_ia32_pshufd512_maskz ||
- BID == clang::X86::BI__builtin_ia32_pshufd128_maskz ||
- BID == clang::X86::BI__builtin_ia32_pshufd256_maskz;
-
- const unsigned AIdx = 0, ImmIdx = 1;
- const unsigned SrcIdx = 2;
- const unsigned KIdx = IsMaskZ ? 2 : 3;
-
- APValue AVal, SrcVal;
- APSInt Imm, K;
- if (!EvaluateAsRValue(Info, E->getArg(AIdx), AVal))
- return false;
- if (!EvaluateInteger(E->getArg(ImmIdx), Imm, Info))
- return false;
-
- const APSInt *KPtr = nullptr;
- const APValue *PassThru = nullptr;
- bool ZeroInactive = false;
- if (IsMask) {
- if (!EvaluateAsRValue(Info, E->getArg(SrcIdx), SrcVal))
- return false;
- if (!EvaluateInteger(E->getArg(KIdx), K, Info))
- return false;
- KPtr = &K;
- PassThru = &SrcVal;
- ZeroInactive = false;
- } else if (IsMaskZ) {
- if (!EvaluateInteger(E->getArg(KIdx), K, Info))
- return false;
- KPtr = &K;
- PassThru = nullptr;
- ZeroInactive = true;
- }
-
- const auto *VT = E->getType()->getAs<VectorType>();
- if (!VT)
- return false;
- const unsigned NumElts = VT->getNumElements();
- const unsigned ElemBits = 32;
- const unsigned LaneElems = std::min(NumElts, 128u / ElemBits);
- const uint8_t Ctl = static_cast<uint8_t>(Imm.getZExtValue());
- const bool DestUnsigned =
- VT->getElementType()->isUnsignedIntegerOrEnumerationType();
+ } else {
+ Out.push_back(Chosen);
+ }
+ }
+ return Success(APValue(Out.data(), Out.size()), E);
+}
+
+case clang::X86::BI__builtin_ia32_pshufd:
+case clang::X86::BI__builtin_ia32_pshufd256:
+case clang::X86::BI__builtin_ia32_pshufd512:
+case clang::X86::BI__builtin_ia32_pshufd128_mask:
+case clang::X86::BI__builtin_ia32_pshufd256_mask:
+case clang::X86::BI__builtin_ia32_pshufd512_mask:
+case clang::X86::BI__builtin_ia32_pshufd128_maskz:
+case clang::X86::BI__builtin_ia32_pshufd256_maskz:
+case clang::X86::BI__builtin_ia32_pshufd512_maskz: {
+ const unsigned BID = E->getBuiltinCallee();
+
+ const bool IsMask =
+ BID == clang::X86::BI__builtin_ia32_pshufd512_mask ||
+ BID == clang::X86::BI__builtin_ia32_pshufd128_mask ||
+ BID == clang::X86::BI__builtin_ia32_pshufd256_mask;
+
+ const bool IsMaskZ =
+ BID == clang::X86::BI__builtin_ia32_pshufd512_maskz ||
+ BID == clang::X86::BI__builtin_ia32_pshufd128_maskz ||
+ BID == clang::X86::BI__builtin_ia32_pshufd256_maskz;
+
+ const unsigned AIdx = 0, ImmIdx = 1;
+ const unsigned SrcIdx = 2;
+ const unsigned KIdx = IsMaskZ ? 2 : 3;
+
+ APValue AVal, SrcVal;
+ APSInt Imm, K;
+ if (!EvaluateAsRValue(Info, E->getArg(AIdx), AVal)) return false;
+ if (!EvaluateInteger(E->getArg(ImmIdx), Imm, Info)) return false;
+
+ const APSInt *KPtr = nullptr;
+ const APValue *PassThru = nullptr;
+ bool ZeroInactive = false;
+ if (IsMask) {
+ if (!EvaluateAsRValue(Info, E->getArg(SrcIdx), SrcVal)) return false;
+ if (!EvaluateInteger(E->getArg(KIdx), K, Info)) return false;
+ KPtr = &K; PassThru = &SrcVal; ZeroInactive = false;
+ } else if (IsMaskZ) {
+ if (!EvaluateInteger(E->getArg(KIdx), K, Info)) return false;
+ KPtr = &K; PassThru = nullptr; ZeroInactive = true;
+ }
+
+ const auto *VT = E->getType()->getAs<VectorType>();
+ if (!VT) return false;
+ const unsigned NumElts = VT->getNumElements();
+ const unsigned ElemBits = 32;
+ const unsigned LaneElems = std::min(NumElts, 128u / ElemBits);
+ const uint8_t Ctl = static_cast<uint8_t>(Imm.getZExtValue());
+ const bool DestUnsigned =
+ VT->getElementType()->isUnsignedIntegerOrEnumerationType();
+
+ auto MakeZero = [&]() -> APValue {
+ return APValue(APSInt(APInt(ElemBits, 0), DestUnsigned));
+ };
- auto MakeZero = [&]() -> APValue {
- return APValue(APSInt(APInt(ElemBits, 0), DestUnsigned));
- };
+ SmallVector<APValue, 32> Out;
+ Out.reserve(NumElts);
- SmallVector<APValue, 32> Out;
- Out.reserve(NumElts);
+ for (unsigned i = 0; i < NumElts; ++i) {
+ const unsigned laneBase = (i / LaneElems) * LaneElems;
+ const unsigned inLane = i % LaneElems;
- for (unsigned i = 0; i < NumElts; ++i) {
- const unsigned laneBase = (i / LaneElems) * LaneElems;
- const unsigned inLane = i % LaneElems;
+ const unsigned pos = inLane & 3;
+ const unsigned sel = (Ctl >> (2 * pos)) & 0x3;
+ const unsigned srcIdx = laneBase + sel;
+ APValue Chosen = AVal.getVectorElt(srcIdx);
- const unsigned pos = inLane & 3;
- const unsigned sel = (Ctl >> (2 * pos)) & 0x3;
- const unsigned srcIdx = laneBase + sel;
- APValue Chosen = AVal.getVectorElt(srcIdx);
-
- if (KPtr) {
- const bool Keep = (i < KPtr->getBitWidth()) ? (*KPtr)[i] : false;
- if (Keep) {
- Out.push_back(Chosen);
- } else if (ZeroInactive) {
- Out.push_back(MakeZero());
- } else {
- const APValue &PT =
- PassThru ? PassThru->getVectorElt(i) : AVal.getVectorElt(i);
- Out.push_back(PT);
- }
- } else {
+ if (KPtr) {
+ const bool Keep = (i < KPtr->getBitWidth()) ? (*KPtr)[i] : false;
+ if (Keep) {
Out.push_back(Chosen);
+ } else if (ZeroInactive) {
+ Out.push_back(MakeZero());
+ } else {
+ const APValue &PT = PassThru ? PassThru->getVectorElt(i)
+ : AVal.getVectorElt(i);
+ Out.push_back(PT);
}
+ } else {
+ Out.push_back(Chosen);
}
- return Success(APValue(Out.data(), Out.size()), E);
}
+ return Success(APValue(Out.data(), Out.size()), E);
+}
case clang::X86::BI__builtin_ia32_vprotbi:
case clang::X86::BI__builtin_ia32_vprotdi:
@@ -12621,70 +12615,72 @@ bool VectorExprEvaluator::VisitShuffleVectorExpr(const ShuffleVectorExpr *E) {
//===----------------------------------------------------------------------===//
namespace {
-class ArrayExprEvaluator : public ExprEvaluatorBase<ArrayExprEvaluator> {
- const LValue &This;
- APValue &Result;
+ class ArrayExprEvaluator
+ : public ExprEvaluatorBase<ArrayExprEvaluator> {
+ const LValue &This;
+ APValue &Result;
+ public:
-public:
- ArrayExprEvaluator(EvalInfo &Info, const LValue &This, APValue &Result)
+ ArrayExprEvaluator(EvalInfo &Info, const LValue &This, APValue &Result)
: ExprEvaluatorBaseTy(Info), This(This), Result(Result) {}
- bool Success(const APValue &V, const Expr *E) {
- assert(V.isArray() && "expected array");
- Result = V;
- return true;
- }
-
- bool ZeroInitialization(const Expr *E) {
- const ConstantArrayType *CAT =
- Info.Ctx.getAsConstantArrayType(E->getType());
- if (!CAT) {
- if (E->getType()->isIncompleteArrayType()) {
- // We can be asked to zero-initialize a flexible array member; this
- // is represented as an ImplicitValueInitExpr of incomplete array
- // type. In this case, the array has zero elements.
- Result = APValue(APValue::UninitArray(), 0, 0);
- return true;
- }
- // FIXME: We could handle VLAs here.
- return Error(E);
+ bool Success(const APValue &V, const Expr *E) {
+ assert(V.isArray() && "expected array");
+ Result = V;
+ return true;
}
- Result = APValue(APValue::UninitArray(), 0, CAT->getZExtSize());
- if (!Result.hasArrayFiller())
- return true;
+ bool ZeroInitialization(const Expr *E) {
+ const ConstantArrayType *CAT =
+ Info.Ctx.getAsConstantArrayType(E->getType());
+ if (!CAT) {
+ if (E->getType()->isIncompleteArrayType()) {
+ // We can be asked to zero-initialize a flexible array member; this
+ // is represented as an ImplicitValueInitExpr of incomplete array
+ // type. In this case, the array has zero elements.
+ Result = APValue(APValue::UninitArray(), 0, 0);
+ return true;
+ }
+ // FIXME: We could handle VLAs here.
+ return Error(E);
+ }
- // Zero-initialize all elements.
- LValue Subobject = This;
- Subobject.addArray(Info, E, CAT);
- ImplicitValueInitExpr VIE(CAT->getElementType());
- return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, &VIE);
- }
+ Result = APValue(APValue::UninitArray(), 0, CAT->getZExtSize());
+ if (!Result.hasArrayFiller())
+ return true;
- bool VisitCallExpr(const CallExpr *E) {
- return handleCallExpr(E, Result, &This);
- }
- bool VisitInitListExpr(const InitListExpr *E,
- QualType AllocType = QualType());
- bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E);
- bool VisitCXXConstructExpr(const CXXConstructExpr *E);
- bool VisitCXXConstructExpr(const CXXConstructExpr *E, const LValue &Subobject,
- APValue *Value, QualType Type);
- bool VisitStringLiteral(const StringLiteral *E,
- QualType AllocType = QualType()) {
- expandStringLiteral(Info, E, Result, AllocType);
- return true;
- }
- bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
- bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit,
- ArrayRef<Expr *> Args,
- const Expr *ArrayFiller,
- QualType AllocType = QualType());
-};
+ // Zero-initialize all elements.
+ LValue Subobject = This;
+ Subobject.addArray(Info, E, CAT);
+ ImplicitValueInitExpr VIE(CAT->getElementType());
+ return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, &VIE);
+ }
+
+ bool VisitCallExpr(const CallExpr *E) {
+ return handleCallExpr(E, Result, &This);
+ }
+ bool VisitInitListExpr(const InitListExpr *E,
+ QualType AllocType = QualType());
+ bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E);
+ bool VisitCXXConstructExpr(const CXXConstructExpr *E);
+ bool VisitCXXConstructExpr(const CXXConstructExpr *E,
+ const LValue &Subobject,
+ APValue *Value, QualType Type);
+ bool VisitStringLiteral(const StringLiteral *E,
+ QualType AllocType = QualType()) {
+ expandStringLiteral(Info, E, Result, AllocType);
+ return true;
+ }
+ bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
+ bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit,
+ ArrayRef<Expr *> Args,
+ const Expr *ArrayFiller,
+ QualType AllocType = QualType());
+ };
} // end anonymous namespace
-static bool EvaluateArray(const Expr *E, const LValue &This, APValue &Result,
- EvalInfo &Info) {
+static bool EvaluateArray(const Expr *E, const LValue &This,
+ APValue &Result, EvalInfo &Info) {
assert(!E->isValueDependent());
assert(E->isPRValue() && E->getType()->isArrayType() &&
"not an array prvalue");
@@ -12895,10 +12891,10 @@ bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
// array element, if any.
FullExpressionRAII Scope(Info);
- if (!EvaluateInPlace(Result.getArrayInitializedElt(Index), Info, Subobject,
- E->getSubExpr()) ||
- !HandleLValueArrayAdjustment(Info, E, Subobject, CAT->getElementType(),
- 1)) {
+ if (!EvaluateInPlace(Result.getArrayInitializedElt(Index),
+ Info, Subobject, E->getSubExpr()) ||
+ !HandleLValueArrayAdjustment(Info, E, Subobject,
+ CAT->getElementType(), 1)) {
if (!Info.noteFailure())
return false;
Success = false;
@@ -12917,16 +12913,17 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
const LValue &Subobject,
- APValue *Value, QualType Type) {
+ APValue *Value,
+ QualType Type) {
bool HadZeroInit = Value->hasValue();
if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(Type)) {
unsigned FinalSize = CAT->getZExtSize();
// Preserve the array filler if we had prior zero-initialization.
- APValue Filler = HadZeroInit && Value->hasArrayFiller()
- ? Value->getArrayFiller()
- : APValue();
+ APValue Filler =
+ HadZeroInit && Value->hasArrayFiller() ? Value->getArrayFiller()
+ : APValue();
*Value = APValue(APValue::UninitArray(), 0, FinalSize);
if (FinalSize == 0)
@@ -12988,7 +12985,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
return Error(E);
return RecordExprEvaluator(Info, Subobject, *Value)
- .VisitCXXConstructExpr(E, Type);
+ .VisitCXXConstructExpr(E, Type);
}
bool ArrayExprEvaluator::VisitCXXParenListInitExpr(
@@ -13009,9 +13006,9 @@ bool ArrayExprEvaluator::VisitCXXParenListInitExpr(
//===----------------------------------------------------------------------===//
namespace {
-class IntExprEvaluator : public ExprEvaluatorBase<IntExprEvaluator> {
+class IntExprEvaluator
+ : public ExprEvaluatorBase<IntExprEvaluator> {
APValue &Result;
-
public:
IntExprEvaluator(EvalInfo &info, APValue &result)
: ExprEvaluatorBaseTy(info), Result(result) {}
@@ -13037,7 +13034,7 @@ class IntExprEvaluator : public ExprEvaluatorBase<IntExprEvaluator> {
"Invalid evaluation result.");
Result = APValue(APSInt(I));
Result.getInt().setIsUnsigned(
- E->getType()->isUnsignedIntegerOrEnumerationType());
+ E->getType()->isUnsignedIntegerOrEnumerationType());
return true;
}
bool Success(const llvm::APInt &I, const Expr *E) {
@@ -13107,7 +13104,7 @@ class IntExprEvaluator : public ExprEvaluatorBase<IntExprEvaluator> {
bool VisitOffsetOfExpr(const OffsetOfExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
- bool VisitCastExpr(const CastExpr *E);
+ bool VisitCastExpr(const CastExpr* E);
bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) {
@@ -13129,7 +13126,9 @@ class IntExprEvaluator : public ExprEvaluatorBase<IntExprEvaluator> {
}
// Note, GNU defines __null as an integer, not a pointer.
- bool VisitGNUNullExpr(const GNUNullExpr *E) { return ZeroInitialization(E); }
+ bool VisitGNUNullExpr(const GNUNullExpr *E) {
+ return ZeroInitialization(E);
+ }
bool VisitTypeTraitExpr(const TypeTraitExpr *E) {
if (E->isStoredAsBoolean())
@@ -13170,7 +13169,7 @@ class FixedPointExprEvaluator
: public ExprEvaluatorBase<FixedPointExprEvaluator> {
APValue &Result;
-public:
+ public:
FixedPointExprEvaluator(EvalInfo &info, APValue &result)
: ExprEvaluatorBaseTy(info), Result(result) {}
@@ -13196,7 +13195,9 @@ class FixedPointExprEvaluator
return true;
}
- bool ZeroInitialization(const Expr *E) { return Success(0, E); }
+ bool ZeroInitialization(const Expr *E) {
+ return Success(0, E);
+ }
//===--------------------------------------------------------------------===//
// Visitor Methods
@@ -13283,14 +13284,14 @@ static bool EvaluateFixedPointOrInteger(const Expr *E, APFixedPoint &Result,
/// Check whether the given declaration can be directly converted to an integral
/// rvalue. If not, no diagnostic is produced; there are other things we can
/// try.
-bool IntExprEvaluator::CheckReferencedDecl(const Expr *E, const Decl *D) {
+bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) {
// Enums are integer constant exprs.
if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) {
// Check for signedness/width mismatches between E type and ECD value.
- bool SameSign = (ECD->getInitVal().isSigned() ==
- E->getType()->isSignedIntegerOrEnumerationType());
- bool SameWidth =
- (ECD->getInitVal().getBitWidth() == Info.Ctx.getIntWidth(E->getType()));
+ bool SameSign = (ECD->getInitVal().isSigned()
+ == E->getType()->isSignedIntegerOrEnumerationType());
+ bool SameWidth = (ECD->getInitVal().getBitWidth()
+ == Info.Ctx.getIntWidth(E->getType()));
if (SameSign && SameWidth)
return Success(ECD->getInitVal(), E);
else {
@@ -13323,20 +13324,17 @@ GCCTypeClass EvaluateBuiltinClassifyType(QualType T,
#include "clang/AST/TypeNodes.inc"
case Type::Auto:
case Type::DeducedTemplateSpecialization:
- llvm_unreachable("unexpected non-canonical or dependent type");
+ llvm_unreachable("unexpected non-canonical or dependent type");
case Type::Builtin:
- switch (cast<BuiltinType>(CanTy)->getKind()) {
+ switch (cast<BuiltinType>(CanTy)->getKind()) {
#define BUILTIN_TYPE(ID, SINGLETON_ID)
-#define SIGNED_TYPE(ID, SINGLETON_ID) \
- case BuiltinType::ID: \
- return GCCTypeClass::Integer;
-#define FLOATING_TYPE(ID, SINGLETON_ID) \
- case BuiltinType::ID: \
- return GCCTypeClass::RealFloat;
-#define PLACEHOLDER_TYPE(ID, SINGLETON_ID) \
- case BuiltinType::ID: \
- break;
+#define SIGNED_TYPE(ID, SINGLETON_ID) \
+ case BuiltinType::ID: return GCCTypeClass::Integer;
+#define FLOATING_TYPE(ID, SINGLETON_ID) \
+ case BuiltinType::ID: return GCCTypeClass::RealFloat;
+#define PLACEHOLDER_TYPE(ID, SINGLETON_ID) \
+ case BuiltinType::ID: break;
#include "clang/AST/BuiltinTypes.def"
case BuiltinType::Void:
return GCCTypeClass::Void;
@@ -13376,19 +13374,22 @@ GCCTypeClass EvaluateBuiltinClassifyType(QualType T,
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
-#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
- case BuiltinType::Id:
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
+ case BuiltinType::Id:
#include "clang/Basic/OpenCLImageTypes.def"
-#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) case BuiltinType::Id:
+#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
+ case BuiltinType::Id:
#include "clang/Basic/OpenCLExtensionTypes.def"
case BuiltinType::OCLSampler:
case BuiltinType::OCLEvent:
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
case BuiltinType::OCLReserveID:
-#define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
#include "clang/Basic/AArch64ACLETypes.def"
-#define PPC_VECTOR_TYPE(Name, Id, Size) case BuiltinType::Id:
+#define PPC_VECTOR_TYPE(Name, Id, Size) \
+ case BuiltinType::Id:
#include "clang/Basic/PPCTypes.def"
#define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
#include "clang/Basic/RISCVVTypes.def"
@@ -13463,8 +13464,8 @@ GCCTypeClass EvaluateBuiltinClassifyType(QualType T,
/// EvaluateBuiltinClassifyType - Evaluate __builtin_classify_type the same way
/// as GCC.
-static GCCTypeClass EvaluateBuiltinClassifyType(const CallExpr *E,
- const LangOptions &LangOpts) {
+static GCCTypeClass
+EvaluateBuiltinClassifyType(const CallExpr *E, const LangOptions &LangOpts) {
// If no argument was supplied, default to None. This isn't
// ideal, however it is what gcc does.
if (E->getNumArgs() == 0)
@@ -13552,10 +13553,10 @@ static bool EvaluateBuiltinConstantP(EvalInfo &Info, const Expr *Arg) {
/// Retrieves the "underlying object type" of the given expression,
/// as used by __builtin_object_size.
static QualType getObjectType(APValue::LValueBase B) {
- if (const ValueDecl *D = B.dyn_cast<const ValueDecl *>()) {
+ if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D))
return VD->getType();
- } else if (const Expr *E = B.dyn_cast<const Expr *>()) {
+ } else if (const Expr *E = B.dyn_cast<const Expr*>()) {
if (isa<CompoundLiteralExpr>(E))
return E->getType();
} else if (B.is<TypeInfoLValue>()) {
@@ -14261,18 +14262,10 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return false;
unsigned Arg;
switch (Val.getCategory()) {
- case APFloat::fcNaN:
- Arg = 0;
- break;
- case APFloat::fcInfinity:
- Arg = 1;
- break;
- case APFloat::fcNormal:
- Arg = Val.isDenormal() ? 3 : 2;
- break;
- case APFloat::fcZero:
- Arg = 4;
- break;
+ case APFloat::fcNaN: Arg = 0; break;
+ case APFloat::fcInfinity: Arg = 1; break;
+ case APFloat::fcNormal: Arg = Val.isDenormal() ? 3 : 2; break;
+ case APFloat::fcZero: Arg = 4; break;
}
return Visit(E->getArg(Arg));
}
@@ -14566,7 +14559,8 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return false;
uint64_t MaxLength = uint64_t(-1);
- if (BuiltinOp != Builtin::BIstrcmp && BuiltinOp != Builtin::BIwcscmp &&
+ if (BuiltinOp != Builtin::BIstrcmp &&
+ BuiltinOp != Builtin::BIwcscmp &&
BuiltinOp != Builtin::BI__builtin_strcmp &&
BuiltinOp != Builtin::BI__builtin_wcscmp) {
APSInt N;
@@ -14708,8 +14702,8 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
}
}
- return BuiltinOp == Builtin::BI__atomic_always_lock_free ? Success(0, E)
- : Error(E);
+ return BuiltinOp == Builtin::BI__atomic_always_lock_free ?
+ Success(0, E) : Error(E);
}
case Builtin::BI__builtin_addcb:
case Builtin::BI__builtin_addcs:
@@ -14804,7 +14798,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
bool IsSigned = LHS.isSigned() || RHS.isSigned() ||
ResultType->isSignedIntegerOrEnumerationType();
bool AllSigned = LHS.isSigned() && RHS.isSigned() &&
- ResultType->isSignedIntegerOrEnumerationType();
+ ResultType->isSignedIntegerOrEnumerationType();
uint64_t LHSSize = LHS.getBitWidth();
uint64_t RHSSize = RHS.getBitWidth();
uint64_t ResultSize = Info.Ctx.getTypeSize(ResultType);
@@ -15193,7 +15187,7 @@ class DataRecursiveIntBinOpEvaluator {
public:
DataRecursiveIntBinOpEvaluator(IntExprEvaluator &IntEval, APValue &Result)
- : IntEval(IntEval), Info(IntEval.getEvalInfo()), FinalResult(Result) {}
+ : IntEval(IntEval), Info(IntEval.getEvalInfo()), FinalResult(Result) { }
/// True if \param E is a binary operator that we are going to handle
/// data recursively.
@@ -15212,8 +15206,7 @@ class DataRecursiveIntBinOpEvaluator {
while (!Queue.empty())
process(PrevResult);
- if (PrevResult.Failed)
- return false;
+ if (PrevResult.Failed) return false;
FinalResult.swap(PrevResult.Val);
return true;
@@ -15226,8 +15219,12 @@ class DataRecursiveIntBinOpEvaluator {
bool Success(const APSInt &Value, const Expr *E, APValue &Result) {
return IntEval.Success(Value, E, Result);
}
- bool Error(const Expr *E) { return IntEval.Error(E); }
- bool Error(const Expr *E, diag::kind D) { return IntEval.Error(E, D); }
+ bool Error(const Expr *E) {
+ return IntEval.Error(E);
+ }
+ bool Error(const Expr *E, diag::kind D) {
+ return IntEval.Error(E, D);
+ }
OptionalDiagnostic CCEDiag(const Expr *E, diag::kind D) {
return Info.CCEDiag(E, D);
@@ -15250,17 +15247,17 @@ class DataRecursiveIntBinOpEvaluator {
void enqueue(const Expr *E) {
E = E->IgnoreParens();
- Queue.resize(Queue.size() + 1);
+ Queue.resize(Queue.size()+1);
Queue.back().E = E;
Queue.back().Kind = Job::AnyExprKind;
}
};
-} // namespace
+}
-bool DataRecursiveIntBinOpEvaluator::VisitBinOpLHSOnly(EvalResult &LHSResult,
- const BinaryOperator *E,
- bool &SuppressRHSDiags) {
+bool DataRecursiveIntBinOpEvaluator::
+ VisitBinOpLHSOnly(EvalResult &LHSResult, const BinaryOperator *E,
+ bool &SuppressRHSDiags) {
if (E->getOpcode() == BO_Comma) {
// Ignore LHS but note if we could not evaluate it.
if (LHSResult.Failed)
@@ -15312,14 +15309,13 @@ static void addOrSubLValueAsInteger(APValue &LVal, const APSInt &Index,
CharUnits &Offset = LVal.getLValueOffset();
uint64_t Offset64 = Offset.getQuantity();
uint64_t Index64 = Index.extOrTrunc(64).getZExtValue();
- Offset =
- CharUnits::fromQuantity(IsSub ? Offset64 - Index64 : Offset64 + Index64);
+ Offset = CharUnits::fromQuantity(IsSub ? Offset64 - Index64
+ : Offset64 + Index64);
}
-bool DataRecursiveIntBinOpEvaluator::VisitBinOp(const EvalResult &LHSResult,
- const EvalResult &RHSResult,
- const BinaryOperator *E,
- APValue &Result) {
+bool DataRecursiveIntBinOpEvaluator::
+ VisitBinOp(const EvalResult &LHSResult, const EvalResult &RHSResult,
+ const BinaryOperator *E, APValue &Result) {
if (E->getOpcode() == BO_Comma) {
if (RHSResult.Failed)
return false;
@@ -15368,9 +15364,10 @@ bool DataRecursiveIntBinOpEvaluator::VisitBinOp(const EvalResult &LHSResult,
}
// Handle cases like 4 + (unsigned long)&a
- if (E->getOpcode() == BO_Add && RHSVal.isLValue() && LHSVal.isInt()) {
+ if (E->getOpcode() == BO_Add &&
+ RHSVal.isLValue() && LHSVal.isInt()) {
Result = RHSVal;
- addOrSubLValueAsInteger(Result, LHSVal.getInt(), /*IsSub*/ false);
+ addOrSubLValueAsInteger(Result, LHSVal.getInt(), /*IsSub*/false);
return true;
}
@@ -15379,8 +15376,8 @@ bool DataRecursiveIntBinOpEvaluator::VisitBinOp(const EvalResult &LHSResult,
if (!LHSVal.getLValueOffset().isZero() ||
!RHSVal.getLValueOffset().isZero())
return false;
- const Expr *LHSExpr = LHSVal.getLValueBase().dyn_cast<const Expr *>();
- const Expr *RHSExpr = RHSVal.getLValueBase().dyn_cast<const Expr *>();
+ const Expr *LHSExpr = LHSVal.getLValueBase().dyn_cast<const Expr*>();
+ const Expr *RHSExpr = RHSVal.getLValueBase().dyn_cast<const Expr*>();
if (!LHSExpr || !RHSExpr)
return false;
const AddrLabelExpr *LHSAddrExpr = dyn_cast<AddrLabelExpr>(LHSExpr);
@@ -15414,43 +15411,43 @@ void DataRecursiveIntBinOpEvaluator::process(EvalResult &Result) {
Job &job = Queue.back();
switch (job.Kind) {
- case Job::AnyExprKind: {
- if (const BinaryOperator *Bop = dyn_cast<BinaryOperator>(job.E)) {
- if (shouldEnqueue(Bop)) {
- job.Kind = Job::BinOpKind;
- enqueue(Bop->getLHS());
- return;
+ case Job::AnyExprKind: {
+ if (const BinaryOperator *Bop = dyn_cast<BinaryOperator>(job.E)) {
+ if (shouldEnqueue(Bop)) {
+ job.Kind = Job::BinOpKind;
+ enqueue(Bop->getLHS());
+ return;
+ }
}
+
+ EvaluateExpr(job.E, Result);
+ Queue.pop_back();
+ return;
}
- EvaluateExpr(job.E, Result);
- Queue.pop_back();
- return;
- }
+ case Job::BinOpKind: {
+ const BinaryOperator *Bop = cast<BinaryOperator>(job.E);
+ bool SuppressRHSDiags = false;
+ if (!VisitBinOpLHSOnly(Result, Bop, SuppressRHSDiags)) {
+ Queue.pop_back();
+ return;
+ }
+ if (SuppressRHSDiags)
+ job.startSpeculativeEval(Info);
+ job.LHSResult.swap(Result);
+ job.Kind = Job::BinOpVisitedLHSKind;
+ enqueue(Bop->getRHS());
+ return;
+ }
- case Job::BinOpKind: {
- const BinaryOperator *Bop = cast<BinaryOperator>(job.E);
- bool SuppressRHSDiags = false;
- if (!VisitBinOpLHSOnly(Result, Bop, SuppressRHSDiags)) {
+ case Job::BinOpVisitedLHSKind: {
+ const BinaryOperator *Bop = cast<BinaryOperator>(job.E);
+ EvalResult RHS;
+ RHS.swap(Result);
+ Result.Failed = !VisitBinOp(job.LHSResult, RHS, Bop, Result.Val);
Queue.pop_back();
return;
}
- if (SuppressRHSDiags)
- job.startSpeculativeEval(Info);
- job.LHSResult.swap(Result);
- job.Kind = Job::BinOpVisitedLHSKind;
- enqueue(Bop->getRHS());
- return;
- }
-
- case Job::BinOpVisitedLHSKind: {
- const BinaryOperator *Bop = cast<BinaryOperator>(job.E);
- EvalResult RHS;
- RHS.swap(Result);
- Result.Failed = !VisitBinOp(job.LHSResult, RHS, Bop, Result.Val);
- Queue.pop_back();
- return;
- }
}
llvm_unreachable("Invalid Job::Kind!");
@@ -15546,9 +15543,9 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
if (LHS.isComplexFloat()) {
APFloat::cmpResult CR_r =
- LHS.getComplexFloatReal().compare(RHS.getComplexFloatReal());
+ LHS.getComplexFloatReal().compare(RHS.getComplexFloatReal());
APFloat::cmpResult CR_i =
- LHS.getComplexFloatImag().compare(RHS.getComplexFloatImag());
+ LHS.getComplexFloatImag().compare(RHS.getComplexFloatImag());
bool IsEqual = CR_r == APFloat::cmpEqual && CR_i == APFloat::cmpEqual;
return Success(IsEqual ? CmpResult::Equal : CmpResult::Unequal, E);
} else {
@@ -15559,7 +15556,8 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
}
}
- if (LHSTy->isRealFloatingType() && RHSTy->isRealFloatingType()) {
+ if (LHSTy->isRealFloatingType() &&
+ RHSTy->isRealFloatingType()) {
APFloat RHS(0.0), LHS(0.0);
bool LHSOK = EvaluateFloat(E->getRHS(), RHS, Info);
@@ -15571,7 +15569,8 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
assert(E->isComparisonOp() && "Invalid binary operator!");
llvm::APFloatBase::cmpResult APFloatCmpResult = LHS.compare(RHS);
- if (!Info.InConstantContext && APFloatCmpResult == APFloat::cmpUnordered &&
+ if (!Info.InConstantContext &&
+ APFloatCmpResult == APFloat::cmpUnordered &&
E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()).isFPConstrained()) {
// Note: Compares may raise invalid in some cases involving NaN or sNaN.
Info.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
@@ -15611,7 +15610,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
if (Info.checkingPotentialConstantExpression() &&
(LHSValue.AllowConstexprUnknown || RHSValue.AllowConstexprUnknown))
return false;
- auto DiagComparison = [&](unsigned DiagID, bool Reversed = false) {
+ auto DiagComparison = [&] (unsigned DiagID, bool Reversed = false) {
std::string LHS = LHSValue.toString(Info.Ctx, E->getLHS()->getType());
std::string RHS = RHSValue.toString(Info.Ctx, E->getRHS()->getType());
Info.FFDiag(E, DiagID)
@@ -15660,7 +15659,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
return DiagComparison(diag::note_constexpr_pointer_comparison_past_end,
true);
if (RHSValue.Base && RHSValue.Offset.isZero() &&
- isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue))
+ isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue))
return DiagComparison(diag::note_constexpr_pointer_comparison_past_end,
false);
// We can't tell whether an object is at the same address as another
@@ -15889,7 +15888,8 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
auto OnSuccess = [&](CmpResult CR, const BinaryOperator *E) {
assert((CR != CmpResult::Unequal || E->isEqualityOp()) &&
"should only produce Unequal for equality comparisons");
- bool IsEqual = CR == CmpResult::Equal, IsLess = CR == CmpResult::Less,
+ bool IsEqual = CR == CmpResult::Equal,
+ IsLess = CR == CmpResult::Less,
IsGreater = CR == CmpResult::Greater;
auto Op = E->getOpcode();
switch (Op) {
@@ -16022,8 +16022,8 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
/// VisitUnaryExprOrTypeTraitExpr - Evaluate a sizeof, alignof or vec_step with
/// a result as the expression's type.
bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
- const UnaryExprOrTypeTraitExpr *E) {
- switch (E->getKind()) {
+ const UnaryExprOrTypeTraitExpr *E) {
+ switch(E->getKind()) {
case UETT_PreferredAlignOf:
case UETT_AlignOf: {
if (E->isArgumentType())
@@ -16074,11 +16074,11 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
}
case UETT_OpenMPRequiredSimdAlign:
assert(E->isArgumentType());
- return Success(Info.Ctx
- .toCharUnitsFromBits(Info.Ctx.getOpenMPDefaultSimdAlign(
- E->getArgumentType()))
- .getQuantity(),
- E);
+ return Success(
+ Info.Ctx.toCharUnitsFromBits(
+ Info.Ctx.getOpenMPDefaultSimdAlign(E->getArgumentType()))
+ .getQuantity(),
+ E);
case UETT_VectorElements: {
QualType Ty = E->getTypeOfArgument();
// If the vector has a fixed size, we can determine the number of elements
@@ -16169,8 +16169,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) {
const auto *RD = CurrentType->getAsRecordDecl();
if (!RD)
return Error(OOE);
- if (RD->isInvalidDecl())
- return false;
+ if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
unsigned i = MemberDecl->getFieldIndex();
assert(i < RL.getFieldCount() && "offsetof field in wrong type");
@@ -16191,8 +16190,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) {
const auto *RD = CurrentType->getAsCXXRecordDecl();
if (!RD)
return Error(OOE);
- if (RD->isInvalidDecl())
- return false;
+ if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
// Find the base class itself.
@@ -16226,8 +16224,7 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
case UO_Minus: {
if (!Visit(E->getSubExpr()))
return false;
- if (!Result.isInt())
- return Error(E);
+ if (!Result.isInt()) return Error(E);
const APSInt &Value = Result.getInt();
if (Value.isSigned() && Value.isMinSignedValue() && E->canOverflow()) {
if (Info.checkingForUndefinedBehavior())
@@ -16246,8 +16243,7 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
case UO_Not: {
if (!Visit(E->getSubExpr()))
return false;
- if (!Result.isInt())
- return Error(E);
+ if (!Result.isInt()) return Error(E);
return Success(~Result.getInt(), E);
}
case UO_LNot: {
@@ -16414,8 +16410,8 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
}
}
- return Success(
- HandleIntToIntCast(Info, E, DestType, SrcType, Result.getInt()), E);
+ return Success(HandleIntToIntCast(Info, E, DestType, SrcType,
+ Result.getInt()), E);
}
case CK_PointerToIntegral: {
@@ -16513,7 +16509,7 @@ bool IntExprEvaluator::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) {
}
bool IntExprEvaluator::VisitConceptSpecializationExpr(
- const ConceptSpecializationExpr *E) {
+ const ConceptSpecializationExpr *E) {
return Success(E->isSatisfied(), E);
}
@@ -16523,29 +16519,28 @@ bool IntExprEvaluator::VisitRequiresExpr(const RequiresExpr *E) {
bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
switch (E->getOpcode()) {
- default:
- // Invalid unary operators
- return Error(E);
- case UO_Plus:
- // The result is just the value.
- return Visit(E->getSubExpr());
- case UO_Minus: {
- if (!Visit(E->getSubExpr()))
- return false;
- if (!Result.isFixedPoint())
+ default:
+ // Invalid unary operators
return Error(E);
- bool Overflowed;
- APFixedPoint Negated = Result.getFixedPoint().negate(&Overflowed);
- if (Overflowed && !HandleOverflow(Info, E, Negated, E->getType()))
- return false;
- return Success(Negated, E);
- }
- case UO_LNot: {
- bool bres;
- if (!EvaluateAsBooleanCondition(E->getSubExpr(), bres, Info))
- return false;
- return Success(!bres, E);
- }
+ case UO_Plus:
+ // The result is just the value.
+ return Visit(E->getSubExpr());
+ case UO_Minus: {
+ if (!Visit(E->getSubExpr())) return false;
+ if (!Result.isFixedPoint())
+ return Error(E);
+ bool Overflowed;
+ APFixedPoint Negated = Result.getFixedPoint().negate(&Overflowed);
+ if (Overflowed && !HandleOverflow(Info, E, Negated, E->getType()))
+ return false;
+ return Success(Negated, E);
+ }
+ case UO_LNot: {
+ bool bres;
+ if (!EvaluateAsBooleanCondition(E->getSubExpr(), bres, Info))
+ return false;
+ return Success(!bres, E);
+ }
}
}
@@ -16565,9 +16560,9 @@ bool FixedPointExprEvaluator::VisitCastExpr(const CastExpr *E) {
APFixedPoint Result = Src.convert(DestFXSema, &Overflowed);
if (Overflowed) {
if (Info.checkingForUndefinedBehavior())
- Info.Ctx.getDiagnostics().Report(
- E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
- << Result.toString() << E->getType();
+ Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
+ diag::warn_fixedpoint_constant_overflow)
+ << Result.toString() << E->getType();
if (!HandleOverflow(Info, E, Result, E->getType()))
return false;
}
@@ -16584,9 +16579,9 @@ bool FixedPointExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (Overflowed) {
if (Info.checkingForUndefinedBehavior())
- Info.Ctx.getDiagnostics().Report(
- E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
- << IntResult.toString() << E->getType();
+ Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
+ diag::warn_fixedpoint_constant_overflow)
+ << IntResult.toString() << E->getType();
if (!HandleOverflow(Info, E, IntResult, E->getType()))
return false;
}
@@ -16604,9 +16599,9 @@ bool FixedPointExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (Overflowed) {
if (Info.checkingForUndefinedBehavior())
- Info.Ctx.getDiagnostics().Report(
- E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
- << Result.toString() << E->getType();
+ Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
+ diag::warn_fixedpoint_constant_overflow)
+ << Result.toString() << E->getType();
if (!HandleOverflow(Info, E, Result, E->getType()))
return false;
}
@@ -16642,17 +16637,17 @@ bool FixedPointExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
switch (E->getOpcode()) {
case BO_Add: {
Result = LHSFX.add(RHSFX, &OpOverflow)
- .convert(ResultFXSema, &ConversionOverflow);
+ .convert(ResultFXSema, &ConversionOverflow);
break;
}
case BO_Sub: {
Result = LHSFX.sub(RHSFX, &OpOverflow)
- .convert(ResultFXSema, &ConversionOverflow);
+ .convert(ResultFXSema, &ConversionOverflow);
break;
}
case BO_Mul: {
Result = LHSFX.mul(RHSFX, &OpOverflow)
- .convert(ResultFXSema, &ConversionOverflow);
+ .convert(ResultFXSema, &ConversionOverflow);
break;
}
case BO_Div: {
@@ -16661,7 +16656,7 @@ bool FixedPointExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
return false;
}
Result = LHSFX.div(RHSFX, &OpOverflow)
- .convert(ResultFXSema, &ConversionOverflow);
+ .convert(ResultFXSema, &ConversionOverflow);
break;
}
case BO_Shl:
@@ -16694,7 +16689,7 @@ bool FixedPointExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (Info.checkingForUndefinedBehavior())
Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
diag::warn_fixedpoint_constant_overflow)
- << Result.toString() << E->getType();
+ << Result.toString() << E->getType();
if (!HandleOverflow(Info, E, Result, E->getType()))
return false;
}
@@ -16706,12 +16701,12 @@ bool FixedPointExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
//===----------------------------------------------------------------------===//
namespace {
-class FloatExprEvaluator : public ExprEvaluatorBase<FloatExprEvaluator> {
+class FloatExprEvaluator
+ : public ExprEvaluatorBase<FloatExprEvaluator> {
APFloat &Result;
-
public:
FloatExprEvaluator(EvalInfo &info, APFloat &result)
- : ExprEvaluatorBaseTy(info), Result(result) {}
+ : ExprEvaluatorBaseTy(info), Result(result) {}
bool Success(const APValue &V, const Expr *e) {
Result = V.getFloat();
@@ -16737,18 +16732,19 @@ class FloatExprEvaluator : public ExprEvaluatorBase<FloatExprEvaluator> {
};
} // end anonymous namespace
-static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info) {
+static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) {
assert(!E->isValueDependent());
assert(E->isPRValue() && E->getType()->isRealFloatingType());
return FloatExprEvaluator(Info, Result).Visit(E);
}
-static bool TryEvaluateBuiltinNaN(const ASTContext &Context, QualType ResultTy,
- const Expr *Arg, bool SNaN,
+static bool TryEvaluateBuiltinNaN(const ASTContext &Context,
+ QualType ResultTy,
+ const Expr *Arg,
+ bool SNaN,
llvm::APFloat &Result) {
const StringLiteral *S = dyn_cast<StringLiteral>(Arg->IgnoreParenCasts());
- if (!S)
- return false;
+ if (!S) return false;
const llvm::fltSemantics &Sem = Context.getFloatTypeSemantics(ResultTy);
@@ -16799,7 +16795,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_inff16:
case Builtin::BI__builtin_inff128: {
const llvm::fltSemantics &Sem =
- Info.Ctx.getFloatTypeSemantics(E->getType());
+ Info.Ctx.getFloatTypeSemantics(E->getType());
Result = llvm::APFloat::getInf(Sem);
return true;
}
@@ -16809,8 +16805,8 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_nansl:
case Builtin::BI__builtin_nansf16:
case Builtin::BI__builtin_nansf128:
- if (!TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0), true,
- Result))
+ if (!TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0),
+ true, Result))
return Error(E);
return true;
@@ -16821,8 +16817,8 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_nanf128:
// If this is __builtin_nan() turn this into a nan, otherwise we
// can't constant fold it.
- if (!TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0), false,
- Result))
+ if (!TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0),
+ false, Result))
return Error(E);
return true;
@@ -16846,9 +16842,9 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__arithmetic_fence:
return EvaluateFloat(E->getArg(0), Result, Info);
- // FIXME: Builtin::BI__builtin_powi
- // FIXME: Builtin::BI__builtin_powif
- // FIXME: Builtin::BI__builtin_powil
+ // FIXME: Builtin::BI__builtin_powi
+ // FIXME: Builtin::BI__builtin_powif
+ // FIXME: Builtin::BI__builtin_powil
case Builtin::BI__builtin_copysign:
case Builtin::BI__builtin_copysignf:
@@ -16960,8 +16956,7 @@ bool FloatExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
switch (E->getOpcode()) {
- default:
- return Error(E);
+ default: return Error(E);
case UO_Plus:
return EvaluateFloat(E->getSubExpr(), Result, Info);
case UO_Minus:
@@ -16993,7 +16988,7 @@ bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) {
}
bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
- const Expr *SubExpr = E->getSubExpr();
+ const Expr* SubExpr = E->getSubExpr();
switch (E->getCastKind()) {
default:
@@ -17001,10 +16996,11 @@ bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_IntegralToFloating: {
APSInt IntResult;
- const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts());
+ const FPOptions FPO = E->getFPFeaturesInEffect(
+ Info.Ctx.getLangOpts());
return EvaluateInteger(SubExpr, IntResult, Info) &&
- HandleIntToFloatCast(Info, E, FPO, SubExpr->getType(), IntResult,
- E->getType(), Result);
+ HandleIntToFloatCast(Info, E, FPO, SubExpr->getType(),
+ IntResult, E->getType(), Result);
}
case CK_FixedPointToFloating: {
@@ -17044,12 +17040,13 @@ bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
//===----------------------------------------------------------------------===//
namespace {
-class ComplexExprEvaluator : public ExprEvaluatorBase<ComplexExprEvaluator> {
+class ComplexExprEvaluator
+ : public ExprEvaluatorBase<ComplexExprEvaluator> {
ComplexValue &Result;
public:
ComplexExprEvaluator(EvalInfo &info, ComplexValue &Result)
- : ExprEvaluatorBaseTy(info), Result(Result) {}
+ : ExprEvaluatorBaseTy(info), Result(Result) {}
bool Success(const APValue &V, const Expr *e) {
Result.setFrom(V);
@@ -17095,7 +17092,7 @@ bool ComplexExprEvaluator::ZeroInitialization(const Expr *E) {
}
bool ComplexExprEvaluator::VisitImaginaryLiteral(const ImaginaryLiteral *E) {
- const Expr *SubExpr = E->getSubExpr();
+ const Expr* SubExpr = E->getSubExpr();
if (SubExpr->getType()->isRealFloatingType()) {
Result.makeComplexFloat();
@@ -17206,8 +17203,8 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
return false;
QualType To = E->getType()->castAs<ComplexType>()->getElementType();
- QualType From =
- E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
+ QualType From
+ = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
return HandleFloatToFloatCast(Info, E, From, To, Result.FloatReal) &&
HandleFloatToFloatCast(Info, E, From, To, Result.FloatImag);
@@ -17218,13 +17215,13 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
return false;
QualType To = E->getType()->castAs<ComplexType>()->getElementType();
- QualType From =
- E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
+ QualType From
+ = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
Result.makeComplexInt();
- return HandleFloatToIntCast(Info, E, From, Result.FloatReal, To,
- Result.IntReal) &&
- HandleFloatToIntCast(Info, E, From, Result.FloatImag, To,
- Result.IntImag);
+ return HandleFloatToIntCast(Info, E, From, Result.FloatReal,
+ To, Result.IntReal) &&
+ HandleFloatToIntCast(Info, E, From, Result.FloatImag,
+ To, Result.IntImag);
}
case CK_IntegralRealToComplex: {
@@ -17242,8 +17239,8 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
return false;
QualType To = E->getType()->castAs<ComplexType>()->getElementType();
- QualType From =
- E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
+ QualType From
+ = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
Result.IntReal = HandleIntToIntCast(Info, E, To, From, Result.IntReal);
Result.IntImag = HandleIntToIntCast(Info, E, To, From, Result.IntImag);
@@ -17254,15 +17251,16 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (!Visit(E->getSubExpr()))
return false;
- const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts());
+ const FPOptions FPO = E->getFPFeaturesInEffect(
+ Info.Ctx.getLangOpts());
QualType To = E->getType()->castAs<ComplexType>()->getElementType();
- QualType From =
- E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
+ QualType From
+ = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
Result.makeComplexFloat();
- return HandleIntToFloatCast(Info, E, FPO, From, Result.IntReal, To,
- Result.FloatReal) &&
- HandleIntToFloatCast(Info, E, FPO, From, Result.IntImag, To,
- Result.FloatImag);
+ return HandleIntToFloatCast(Info, E, FPO, From, Result.IntReal,
+ To, Result.FloatReal) &&
+ HandleIntToFloatCast(Info, E, FPO, From, Result.IntImag,
+ To, Result.FloatImag);
}
}
@@ -17404,8 +17402,7 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
assert(!(LHSReal && RHSReal) &&
"Cannot have both operands of a complex operation be real.");
switch (E->getOpcode()) {
- default:
- return Error(E);
+ default: return Error(E);
case BO_Add:
if (Result.isComplexFloat()) {
Result.getComplexFloatReal().add(RHS.getComplexFloatReal(),
@@ -17472,11 +17469,11 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
} else {
ComplexValue LHS = Result;
Result.getComplexIntReal() =
- (LHS.getComplexIntReal() * RHS.getComplexIntReal() -
- LHS.getComplexIntImag() * RHS.getComplexIntImag());
+ (LHS.getComplexIntReal() * RHS.getComplexIntReal() -
+ LHS.getComplexIntImag() * RHS.getComplexIntImag());
Result.getComplexIntImag() =
- (LHS.getComplexIntReal() * RHS.getComplexIntImag() +
- LHS.getComplexIntImag() * RHS.getComplexIntReal());
+ (LHS.getComplexIntReal() * RHS.getComplexIntImag() +
+ LHS.getComplexIntImag() * RHS.getComplexIntReal());
}
break;
case BO_Div:
@@ -17510,18 +17507,16 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
} else {
ComplexValue LHS = Result;
APSInt Den = RHS.getComplexIntReal() * RHS.getComplexIntReal() +
- RHS.getComplexIntImag() * RHS.getComplexIntImag();
+ RHS.getComplexIntImag() * RHS.getComplexIntImag();
if (Den.isZero())
return Error(E, diag::note_expr_divide_by_zero);
Result.getComplexIntReal() =
- (LHS.getComplexIntReal() * RHS.getComplexIntReal() +
- LHS.getComplexIntImag() * RHS.getComplexIntImag()) /
- Den;
+ (LHS.getComplexIntReal() * RHS.getComplexIntReal() +
+ LHS.getComplexIntImag() * RHS.getComplexIntImag()) / Den;
Result.getComplexIntImag() =
- (LHS.getComplexIntImag() * RHS.getComplexIntReal() -
- LHS.getComplexIntReal() * RHS.getComplexIntImag()) /
- Den;
+ (LHS.getComplexIntImag() * RHS.getComplexIntReal() -
+ LHS.getComplexIntReal() * RHS.getComplexIntImag()) / Den;
}
break;
}
@@ -17546,7 +17541,8 @@ bool ComplexExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
if (Result.isComplexFloat()) {
Result.getComplexFloatReal().changeSign();
Result.getComplexFloatImag().changeSign();
- } else {
+ }
+ else {
Result.getComplexIntReal() = -Result.getComplexIntReal();
Result.getComplexIntImag() = -Result.getComplexIntImag();
}
@@ -17604,10 +17600,10 @@ bool ComplexExprEvaluator::VisitCallExpr(const CallExpr *E) {
//===----------------------------------------------------------------------===//
namespace {
-class AtomicExprEvaluator : public ExprEvaluatorBase<AtomicExprEvaluator> {
+class AtomicExprEvaluator :
+ public ExprEvaluatorBase<AtomicExprEvaluator> {
const LValue *This;
APValue &Result;
-
public:
AtomicExprEvaluator(EvalInfo &Info, const LValue *This, APValue &Result)
: ExprEvaluatorBaseTy(Info), This(This), Result(Result) {}
@@ -17654,7 +17650,8 @@ static bool EvaluateAtomic(const Expr *E, const LValue *This, APValue &Result,
//===----------------------------------------------------------------------===//
namespace {
-class VoidExprEvaluator : public ExprEvaluatorBase<VoidExprEvaluator> {
+class VoidExprEvaluator
+ : public ExprEvaluatorBase<VoidExprEvaluator> {
public:
VoidExprEvaluator(EvalInfo &Info) : ExprEvaluatorBaseTy(Info) {}
@@ -17811,8 +17808,7 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
return false;
C.moveInto(Result);
} else if (T->isFixedPointType()) {
- if (!FixedPointExprEvaluator(Info, Result).Visit(E))
- return false;
+ if (!FixedPointExprEvaluator(Info, Result).Visit(E)) return false;
} else if (T->isMemberPointerType()) {
MemberPtr P;
if (!EvaluateMemberPointer(E, P, Info))
@@ -17835,7 +17831,8 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
Result = Value;
} else if (T->isVoidType()) {
if (!Info.getLangOpts().CPlusPlus11)
- Info.CCEDiag(E, diag::note_constexpr_nonliteral) << E->getType();
+ Info.CCEDiag(E, diag::note_constexpr_nonliteral)
+ << E->getType();
if (!EvaluateVoid(E, Info))
return false;
} else if (T->isAtomicType()) {
@@ -18188,7 +18185,7 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx,
// If we're evaluating a prvalue, fake up a MaterializeTemporaryExpr to
// represent the result of the evaluation. CheckConstantExpression ensures
// this doesn't escape.
- MaterializeTemporaryExpr BaseMTE(T, const_cast<Expr *>(this), true);
+ MaterializeTemporaryExpr BaseMTE(T, const_cast<Expr*>(this), true);
APValue::LValueBase Base(&BaseMTE);
Info.setEvaluatingDecl(Base, Result.Val);
@@ -18425,13 +18422,13 @@ struct ICEDiag {
ICEDiag(ICEKind IK, SourceLocation l) : Kind(IK), Loc(l) {}
};
-} // namespace
+}
static ICEDiag NoDiag() { return ICEDiag(IK_ICE, SourceLocation()); }
static ICEDiag Worst(ICEDiag A, ICEDiag B) { return A.Kind >= B.Kind ? A : B; }
-static ICEDiag CheckEvalInICE(const Expr *E, const ASTContext &Ctx) {
+static ICEDiag CheckEvalInICE(const Expr* E, const ASTContext &Ctx) {
Expr::EvalResult EVResult;
Expr::EvalStatus Status;
EvalInfo Info(Ctx, Status, EvaluationMode::ConstantExpression);
@@ -18444,7 +18441,7 @@ static ICEDiag CheckEvalInICE(const Expr *E, const ASTContext &Ctx) {
return NoDiag();
}
-static ICEDiag CheckICE(const Expr *E, const ASTContext &Ctx) {
+static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
assert(!E->isValueDependent() && "Should not see value dependent exprs!");
if (!E->getType()->isIntegralOrEnumerationType())
return ICEDiag(IK_NotICE, E->getBeginLoc());
@@ -18562,8 +18559,8 @@ static ICEDiag CheckICE(const Expr *E, const ASTContext &Ctx) {
return CheckICE(cast<PackIndexingExpr>(E)->getSelectedExpr(), Ctx);
case Expr::SubstNonTypeTemplateParmExprClass:
- return CheckICE(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(),
- Ctx);
+ return
+ CheckICE(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(), Ctx);
case Expr::ConstantExprClass:
return CheckICE(cast<ConstantExpr>(E)->getSubExpr(), Ctx);
@@ -18655,7 +18652,7 @@ static ICEDiag CheckICE(const Expr *E, const ASTContext &Ctx) {
}
case Expr::UnaryExprOrTypeTraitExprClass: {
const UnaryExprOrTypeTraitExpr *Exp = cast<UnaryExprOrTypeTraitExpr>(E);
- if ((Exp->getKind() == UETT_SizeOf) &&
+ if ((Exp->getKind() == UETT_SizeOf) &&
Exp->getTypeOfArgument()->isVariableArrayType())
return ICEDiag(IK_NotICE, E->getBeginLoc());
if (Exp->getKind() == UETT_CountOf) {
@@ -18718,7 +18715,8 @@ static ICEDiag CheckICE(const Expr *E, const ASTContext &Ctx) {
case BO_Cmp: {
ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx);
ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx);
- if (Exp->getOpcode() == BO_Div || Exp->getOpcode() == BO_Rem) {
+ if (Exp->getOpcode() == BO_Div ||
+ Exp->getOpcode() == BO_Rem) {
// EvaluateAsRValue gives an error for undefined Div/Rem, so make sure
// we don't evaluate one.
if (LHSResult.Kind == IK_ICE && RHSResult.Kind == IK_ICE) {
@@ -18773,8 +18771,8 @@ static ICEDiag CheckICE(const Expr *E, const ASTContext &Ctx) {
case Expr::ObjCBridgedCastExprClass: {
const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr();
if (isa<ExplicitCastExpr>(E)) {
- if (const FloatingLiteral *FL =
- dyn_cast<FloatingLiteral>(SubExpr->IgnoreParenImpCasts())) {
+ if (const FloatingLiteral *FL
+ = dyn_cast<FloatingLiteral>(SubExpr->IgnoreParenImpCasts())) {
unsigned DestWidth = Ctx.getIntWidth(E->getType());
bool DestSigned = E->getType()->isSignedIntegerOrEnumerationType();
APSInt IgnoredVal(DestWidth, !DestSigned);
@@ -18782,9 +18780,9 @@ static ICEDiag CheckICE(const Expr *E, const ASTContext &Ctx) {
// If the value does not fit in the destination type, the behavior is
// undefined, so we are not required to treat it as a constant
// expression.
- if (FL->getValue().convertToInteger(
- IgnoredVal, llvm::APFloat::rmTowardZero, &Ignored) &
- APFloat::opInvalidOp)
+ if (FL->getValue().convertToInteger(IgnoredVal,
+ llvm::APFloat::rmTowardZero,
+ &Ignored) & APFloat::opInvalidOp)
return ICEDiag(IK_NotICE, E->getBeginLoc());
return NoDiag();
}
@@ -18804,16 +18802,12 @@ static ICEDiag CheckICE(const Expr *E, const ASTContext &Ctx) {
case Expr::BinaryConditionalOperatorClass: {
const BinaryConditionalOperator *Exp = cast<BinaryConditionalOperator>(E);
ICEDiag CommonResult = CheckICE(Exp->getCommon(), Ctx);
- if (CommonResult.Kind == IK_NotICE)
- return CommonResult;
+ if (CommonResult.Kind == IK_NotICE) return CommonResult;
ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
- if (FalseResult.Kind == IK_NotICE)
- return FalseResult;
- if (CommonResult.Kind == IK_ICEIfUnevaluated)
- return CommonResult;
+ if (FalseResult.Kind == IK_NotICE) return FalseResult;
+ if (CommonResult.Kind == IK_ICEIfUnevaluated) return CommonResult;
if (FalseResult.Kind == IK_ICEIfUnevaluated &&
- Exp->getCommon()->EvaluateKnownConstInt(Ctx) != 0)
- return NoDiag();
+ Exp->getCommon()->EvaluateKnownConstInt(Ctx) != 0) return NoDiag();
return FalseResult;
}
case Expr::ConditionalOperatorClass: {
@@ -18822,8 +18816,8 @@ static ICEDiag CheckICE(const Expr *E, const ASTContext &Ctx) {
// then only the true side is actually considered in an integer constant
// expression, and it is fully evaluated. This is an important GNU
// extension. See GCC PR38377 for discussion.
- if (const CallExpr *CallCE =
- dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts()))
+ if (const CallExpr *CallCE
+ = dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts()))
if (CallCE->getBuiltinCallee() == Builtin::BI__builtin_constant_p)
return CheckEvalInICE(E, Ctx);
ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx);
@@ -18879,8 +18873,7 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx,
if (!Result.isInt())
return false;
- if (Value)
- *Value = Result.getInt();
+ if (Value) *Value = Result.getInt();
return true;
}
@@ -18971,7 +18964,7 @@ bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result) const {
bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
const FunctionDecl *Callee,
- ArrayRef<const Expr *> Args,
+ ArrayRef<const Expr*> Args,
const Expr *This) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
@@ -19008,13 +19001,14 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
}
CallRef Call = Info.CurrentCall->createCall(Callee);
- for (ArrayRef<const Expr *>::iterator I = Args.begin(), E = Args.end();
+ for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
I != E; ++I) {
unsigned Idx = I - Args.begin();
if (Idx >= Callee->getNumParams())
break;
const ParmVarDecl *PVD = Callee->getParamDecl(Idx);
- if ((*I)->isValueDependent() || !EvaluateCallArg(PVD, *I, Call, Info) ||
+ if ((*I)->isValueDependent() ||
+ !EvaluateCallArg(PVD, *I, Call, Info) ||
Info.EvalStatus.HasSideEffects) {
// If evaluation fails, throw away the argument entirely.
if (APValue *Slot = Info.getParamSlot(Call, PVD))
@@ -19040,8 +19034,9 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
!Info.EvalStatus.HasSideEffects;
}
-bool Expr::isPotentialConstantExpr(
- const FunctionDecl *FD, SmallVectorImpl<PartialDiagnosticAt> &Diags) {
+bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
+ SmallVectorImpl<
+ PartialDiagnosticAt> &Diags) {
// FIXME: It would be useful to check constexpr function templates, but at the
// moment the constant expression evaluator cannot cope with the non-rigorous
// ASTs which we build for dependent expressions.
@@ -19080,7 +19075,7 @@ bool Expr::isPotentialConstantExpr(
: Info.Ctx.IntTy);
This.set({&VIE, Info.CurrentCall->Index});
- ArrayRef<const Expr *> Args;
+ ArrayRef<const Expr*> Args;
APValue Scratch;
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
@@ -19099,9 +19094,10 @@ bool Expr::isPotentialConstantExpr(
return Diags.empty();
}
-bool Expr::isPotentialConstantExprUnevaluated(
- Expr *E, const FunctionDecl *FD,
- SmallVectorImpl<PartialDiagnosticAt> &Diags) {
+bool Expr::isPotentialConstantExprUnevaluated(Expr *E,
+ const FunctionDecl *FD,
+ SmallVectorImpl<
+ PartialDiagnosticAt> &Diags) {
assert(!E->isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
>From 1ddbdbb7f707daab06d8ff25e60a541b244dfbc4 Mon Sep 17 00:00:00 2001
From: NagrajMG <nagrajgaonkarmumbai749 at gmail.com>
Date: Mon, 29 Sep 2025 00:59:22 +0530
Subject: [PATCH 3/3] [X86] Allow PSHUFD/PSHUFLW/PSHUFW intrinsics in
constexpr, Fixes Issue: #156611
---
clang/include/clang/Basic/BuiltinsX86.td | 1 +
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 1 +
clang/lib/AST/ExprConstant.cpp | 1 +
clang/lib/Headers/mmintrin.h | 1 +
clang/test/CodeGen/X86/avx2-builtins.c | 1 +
clang/test/CodeGen/X86/avx512bw-builtins.c | 1 +
clang/test/CodeGen/X86/avx512f-builtins.c | 1 +
clang/test/CodeGen/X86/avx512vl-builtins.c | 1 +
clang/test/CodeGen/X86/avx512vlbw-builtins.c | 1 +
clang/test/CodeGen/X86/mmx-builtins.c | 1 +
clang/test/CodeGen/X86/sse2-builtins.c | 1 +
11 files changed, 11 insertions(+)
diff --git a/clang/include/clang/Basic/BuiltinsX86.td b/clang/include/clang/Basic/BuiltinsX86.td
index 33d4d07fcfb5c..08b82b03b7865 100644
--- a/clang/include/clang/Basic/BuiltinsX86.td
+++ b/clang/include/clang/Basic/BuiltinsX86.td
@@ -5150,6 +5150,7 @@ let Features = "avx512bw", Attributes = [NoThrow, Const, Constexpr, RequiredVect
def pshufhw512_maskz : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Constant int, unsigned int)">;
}
+
let Features = "avx512vl,avx512bw", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
def pshuflw256_mask : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Constant int, _Vector<16, short>, unsigned short)">;
def pshuflw256_maskz : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Constant int, unsigned short)">;
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index e3b9acac6075e..1156626a30c8a 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -3179,6 +3179,7 @@ static bool interp__builtin_x86_insert_subvector(InterpState &S, CodePtr OpPC,
return true;
}
+
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
uint32_t BuiltinID) {
if (!S.getASTContext().BuiltinInfo.isConstantEvaluated(BuiltinID))
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index b6cf3c545c36d..3fee702120abc 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -12477,6 +12477,7 @@ case clang::X86::BI__builtin_ia32_pshufd512_maskz: {
return Success(APValue(ResultElements.data(), ResultElements.size()), E);
}
+
case X86::BI__builtin_ia32_insertf32x4_256:
case X86::BI__builtin_ia32_inserti32x4_256:
case X86::BI__builtin_ia32_insertf64x2_256:
diff --git a/clang/lib/Headers/mmintrin.h b/clang/lib/Headers/mmintrin.h
index f031f83011424..039f8c5cacddb 100644
--- a/clang/lib/Headers/mmintrin.h
+++ b/clang/lib/Headers/mmintrin.h
@@ -192,6 +192,7 @@ _mm_packs_pi32(__m64 __m1, __m64 __m2) {
(__v4si)__builtin_shufflevector(__m1, __m2, 0, 1), (__v4si){}));
}
+
/// Converts, with saturation, 16-bit signed integers from both 64-bit integer
/// vector parameters of [4 x i16] into 8-bit unsigned integer values, and
/// constructs a 64-bit integer vector of [8 x i8] as the result.
diff --git a/clang/test/CodeGen/X86/avx2-builtins.c b/clang/test/CodeGen/X86/avx2-builtins.c
index e5e78257fe534..2e34bd83524a8 100644
--- a/clang/test/CodeGen/X86/avx2-builtins.c
+++ b/clang/test/CodeGen/X86/avx2-builtins.c
@@ -1126,6 +1126,7 @@ TEST_CONSTEXPR(match_v8si(_mm256_shuffle_epi32((((__m256i)(__v8si){0,1,2,3,4,5,6
TEST_CONSTEXPR(match_v16hi(_mm256_shufflehi_epi16((((__m256i)(__v16hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15})), 107), 0,1,2,3, 7,6,6,5, 8,9,10,11, 15,14,14,13));
TEST_CONSTEXPR(match_v16hi(_mm256_shufflelo_epi16(((__m256i)(__v16hi){ 0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15}), 83), 3,0,1,1, 4,5,6,7, 11,8,9,9, 12,13,14,15) );
+
__m256i test_mm256_sign_epi8(__m256i a, __m256i b) {
// CHECK-LABEL: test_mm256_sign_epi8
// CHECK: call <32 x i8> @llvm.x86.avx2.psign.b(<32 x i8> %{{.*}}, <32 x i8> %{{.*}})
diff --git a/clang/test/CodeGen/X86/avx512bw-builtins.c b/clang/test/CodeGen/X86/avx512bw-builtins.c
index 69df9b5d73302..b388d2f0e668d 100644
--- a/clang/test/CodeGen/X86/avx512bw-builtins.c
+++ b/clang/test/CodeGen/X86/avx512bw-builtins.c
@@ -1910,6 +1910,7 @@ __m512i test_mm512_maskz_shufflelo_epi16(__mmask32 __U, __m512i __A) {
return _mm512_maskz_shufflelo_epi16(__U, __A, 5);
}
+
//_mm512_shufflehi_epi16 , _mm512_mask_shufflehi_epi16 , _mm512_maskz_shufflehi_epi16
TEST_CONSTEXPR(match_v32hi(_mm512_shufflehi_epi16((((__m512i)(__v32hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31})), 5), 0,1,2,3, 5,5,4,4, 8,9,10,11, 13,13,12,12, 16,17,18,19, 21,21,20,20, 24,25,26,27, 29,29,28,28));
TEST_CONSTEXPR(match_v32hi(_mm512_mask_shufflehi_epi16((((__m512i)(__v32hi){100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131})), 0xFFFF0000u, (((__m512i)(__v32hi){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31})), 5), 100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115, 16,17,18,19,21,21,20,20, 24,25,26,27,29,29,28,28));
diff --git a/clang/test/CodeGen/X86/avx512f-builtins.c b/clang/test/CodeGen/X86/avx512f-builtins.c
index 90330970a3e1c..6a1ccacc8caeb 100644
--- a/clang/test/CodeGen/X86/avx512f-builtins.c
+++ b/clang/test/CodeGen/X86/avx512f-builtins.c
@@ -9101,6 +9101,7 @@ TEST_CONSTEXPR(match_v16si(_mm512_maskz_shuffle_epi32(0xFFFFu, ((__m512i)(__v16s
TEST_CONSTEXPR(match_v16si(_mm512_maskz_shuffle_epi32(0x5555u, ((__m512i)(__v16si){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}), 1), 1,0,0,0, 5,0,4,0, 9,0,8,0, 13,0,12,0));
TEST_CONSTEXPR(match_v16si(_mm512_maskz_shuffle_epi32(0x8001u, ((__m512i)(__v16si){0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}), 1), 1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,12));
+
__m512d test_mm512_mask_expand_pd(__m512d __W, __mmask8 __U, __m512d __A) {
// CHECK-LABEL: test_mm512_mask_expand_pd
// CHECK: @llvm.x86.avx512.mask.expand
diff --git a/clang/test/CodeGen/X86/avx512vl-builtins.c b/clang/test/CodeGen/X86/avx512vl-builtins.c
index b344ad7f8aade..ed26bb3d35fde 100644
--- a/clang/test/CodeGen/X86/avx512vl-builtins.c
+++ b/clang/test/CodeGen/X86/avx512vl-builtins.c
@@ -10046,6 +10046,7 @@ __m256i test_mm256_maskz_shuffle_epi32(__mmask8 __U, __m256i __A) {
return _mm256_maskz_shuffle_epi32(__U, __A, 2);
}
+
// 128-bit (_mm_mask_shuffle_epi32 / _mm_maskz_shuffle_epi32)
TEST_CONSTEXPR(match_v4si(_mm_mask_shuffle_epi32(((__m128i)(__v4si){100,101,102,103}), 0x0Fu, ((__m128i)(__v4si){0,1,2,3}), 1), 1,0,0,0));
TEST_CONSTEXPR(match_v4si(_mm_mask_shuffle_epi32(((__m128i)(__v4si){100,101,102,103}), 0x0Au, ((__m128i)(__v4si){0,1,2,3}), 1), 100,0,102,0));
diff --git a/clang/test/CodeGen/X86/avx512vlbw-builtins.c b/clang/test/CodeGen/X86/avx512vlbw-builtins.c
index 4d539e5da33dc..f21ba94d05800 100644
--- a/clang/test/CodeGen/X86/avx512vlbw-builtins.c
+++ b/clang/test/CodeGen/X86/avx512vlbw-builtins.c
@@ -3441,6 +3441,7 @@ __m256i test_mm256_maskz_shufflelo_epi16(__mmask16 __U, __m256i __A) {
return _mm256_maskz_shufflelo_epi16(__U, __A, 5);
}
+
// 128-bit shufflelo (mask)
TEST_CONSTEXPR(match_v8hi(_mm_mask_shufflelo_epi16(((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),0xFF,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),1,1,0,0,4,5,6,7));
TEST_CONSTEXPR(match_v8hi(_mm_mask_shufflelo_epi16(((__m128i)(__v8hi){100,101,102,103,104,105,106,107}),0x00u,((__m128i)(__v8hi){0,1,2,3,4,5,6,7}),5),100,101,102,103,104,105,106,107));
diff --git a/clang/test/CodeGen/X86/mmx-builtins.c b/clang/test/CodeGen/X86/mmx-builtins.c
index 5156d070bcde7..539de13d44e6a 100644
--- a/clang/test/CodeGen/X86/mmx-builtins.c
+++ b/clang/test/CodeGen/X86/mmx-builtins.c
@@ -579,6 +579,7 @@ __m64 test_mm_shuffle_pi8(__m64 a, __m64 b) {
return _mm_shuffle_pi8(a, b);
}
+
__m64 test_mm_shuffle_pi16(__m64 a) {
// CHECK-LABEL: test_mm_shuffle_pi16
// CHECK: shufflevector <4 x i16> {{%.*}}, <4 x i16> {{%.*}}, <4 x i32> <i32 3, i32 0, i32 0, i32 0>
diff --git a/clang/test/CodeGen/X86/sse2-builtins.c b/clang/test/CodeGen/X86/sse2-builtins.c
index 84c77b4377c86..b8423bdea4c54 100644
--- a/clang/test/CodeGen/X86/sse2-builtins.c
+++ b/clang/test/CodeGen/X86/sse2-builtins.c
@@ -1317,6 +1317,7 @@ __m128i test_mm_shuffle_epi32(__m128i A) {
return _mm_shuffle_epi32(A, 0);
}
+
TEST_CONSTEXPR(match_v4si(_mm_shuffle_epi32(((__m128i)(__v4si){0,1,2,3}), 0), 0,0,0,0));
TEST_CONSTEXPR(match_v8hi(_mm_shufflehi_epi16(((__m128i)(__v8hi){0,1,2,3,4,5,6,7}), 0), 0,1,2,3, 4,4,4,4));
TEST_CONSTEXPR(match_v8hi(_mm_shufflelo_epi16(((__m128i)(__v8hi){0,1,2,3,4,5,6,7}), 0), 0,0,0,0, 4,5,6,7));
More information about the cfe-commits
mailing list