1//===--- Interp.h - Interpreter for the constexpr VM ------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Definition of the interpreter state and entry point.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CLANG_AST_INTERP_INTERP_H
14#define LLVM_CLANG_AST_INTERP_INTERP_H
15
16#include "../ExprConstShared.h"
17#include "BitcastBuffer.h"
18#include "Boolean.h"
19#include "DynamicAllocator.h"
20#include "FixedPoint.h"
21#include "Floating.h"
22#include "Function.h"
23#include "InterpBuiltinBitCast.h"
24#include "InterpFrame.h"
25#include "InterpHelpers.h"
26#include "InterpStack.h"
27#include "InterpState.h"
28#include "MemberPointer.h"
29#include "PrimType.h"
30#include "Program.h"
31#include "State.h"
32#include "clang/AST/ASTContext.h"
33#include "clang/AST/Expr.h"
34#include "llvm/ADT/APFloat.h"
35#include "llvm/ADT/APSInt.h"
36#include <type_traits>
37
38namespace clang {
39namespace interp {
40
41using APSInt = llvm::APSInt;
42using FixedPointSemantics = llvm::FixedPointSemantics;
43
44/// Checks if the variable has externally defined storage.
45bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
46
47/// Checks if a pointer is null.
48bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
49 CheckSubobjectKind CSK);
50
51/// Checks if Ptr is a one-past-the-end pointer.
52bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
53 CheckSubobjectKind CSK);
54
55/// Checks if the dowcast using the given offset is possible with the given
56/// pointer.
57bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
58 uint32_t Offset);
59
60/// Checks if a pointer points to const storage.
61bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
62
63/// Checks if the Descriptor is of a constexpr or const global variable.
64bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc);
65
66bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
67
68bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
69 AccessKinds AK);
70bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, bool Extern,
71 const Descriptor *Desc, AccessKinds AK);
72
73/// Checks a direct load of a primitive value from a global or local variable.
74bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B);
75bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B);
76
77/// Checks if a value can be stored in a block.
78bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
79 bool WillBeActivated = false);
80
81/// Checks if a value can be initialized.
82bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
83
84/// Checks the 'this' pointer.
85bool CheckThis(InterpState &S, CodePtr OpPC);
86
87/// Checks if dynamic memory allocation is available in the current
88/// language mode.
89bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC);
90
91/// Check the source of the pointer passed to delete/delete[] has actually
92/// been heap allocated by us.
93bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
94 const Pointer &Ptr);
95
96bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
97 AccessKinds AK, bool WillActivate = false);
98
99/// Sets the given integral value to the pointer, which is of
100/// a std::{weak,partial,strong}_ordering type.
101bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
102 const Pointer &Ptr, const APSInt &IntValue);
103
104bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
105 uint32_t VarArgSize);
106bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
107 uint32_t VarArgSize);
108bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
109 uint32_t VarArgSize);
110bool CallBI(InterpState &S, CodePtr OpPC, const CallExpr *CE,
111 uint32_t BuiltinID);
112bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
113 const CallExpr *CE);
114bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T);
115bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index);
116bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,
117 bool TargetIsUCharOrByte);
118bool CheckBCPResult(InterpState &S, const Pointer &Ptr);
119bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
120bool CheckFunctionDecl(InterpState &S, CodePtr OpPC, const FunctionDecl *FD);
121bool CheckBitCast(InterpState &S, CodePtr OpPC, const Type *TargetType,
122 bool SrcIsVoidPtr);
123bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind, bool Fatal);
124
125bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC,
126 const FixedPoint &FP);
127
128bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I);
129bool isConstexprUnknown(const Pointer &P);
130
131enum class ShiftDir { Left, Right };
132
133/// Checks if the shift operation is legal.
134template <ShiftDir Dir, typename LT, typename RT>
135bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
136 unsigned Bits) {
137 if (RHS.isNegative()) {
138 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
139 S.CCEDiag(SI: Loc, DiagId: diag::note_constexpr_negative_shift) << RHS.toAPSInt();
140 if (!S.noteUndefinedBehavior())
141 return false;
142 }
143
144 // C++11 [expr.shift]p1: Shift width must be less than the bit width of
145 // the shifted type.
146 if (Bits > 1 && RHS >= Bits) {
147 const Expr *E = S.Current->getExpr(PC: OpPC);
148 const APSInt Val = RHS.toAPSInt();
149 QualType Ty = E->getType();
150 S.CCEDiag(E, DiagId: diag::note_constexpr_large_shift) << Val << Ty << Bits;
151 if (!S.noteUndefinedBehavior())
152 return false;
153 }
154
155 if constexpr (Dir == ShiftDir::Left) {
156 if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
157 // C++11 [expr.shift]p2: A signed left shift must have a non-negative
158 // operand, and must not overflow the corresponding unsigned type.
159 if (LHS.isNegative()) {
160 const Expr *E = S.Current->getExpr(PC: OpPC);
161 S.CCEDiag(E, DiagId: diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
162 if (!S.noteUndefinedBehavior())
163 return false;
164 } else if (LHS.toUnsigned().countLeadingZeros() <
165 static_cast<unsigned>(RHS)) {
166 const Expr *E = S.Current->getExpr(PC: OpPC);
167 S.CCEDiag(E, DiagId: diag::note_constexpr_lshift_discards);
168 if (!S.noteUndefinedBehavior())
169 return false;
170 }
171 }
172 }
173
174 // C++2a [expr.shift]p2: [P0907R4]:
175 // E1 << E2 is the unique value congruent to
176 // E1 x 2^E2 module 2^N.
177 return true;
178}
179
180/// Checks if Div/Rem operation on LHS and RHS is valid.
181template <typename T>
182bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
183 if (RHS.isZero()) {
184 const auto *Op = cast<BinaryOperator>(Val: S.Current->getExpr(PC: OpPC));
185 if constexpr (std::is_same_v<T, Floating>) {
186 S.CCEDiag(E: Op, DiagId: diag::note_expr_divide_by_zero)
187 << Op->getRHS()->getSourceRange();
188 return true;
189 }
190
191 S.FFDiag(E: Op, DiagId: diag::note_expr_divide_by_zero)
192 << Op->getRHS()->getSourceRange();
193 return false;
194 }
195
196 if constexpr (!std::is_same_v<T, FixedPoint>) {
197 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
198 APSInt LHSInt = LHS.toAPSInt();
199 SmallString<32> Trunc;
200 (-LHSInt.extend(width: LHSInt.getBitWidth() + 1)).toString(Str&: Trunc, Radix: 10);
201 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
202 const Expr *E = S.Current->getExpr(PC: OpPC);
203 S.CCEDiag(SI: Loc, DiagId: diag::note_constexpr_overflow) << Trunc << E->getType();
204 return false;
205 }
206 }
207 return true;
208}
209
210/// Checks if the result of a floating-point operation is valid
211/// in the current context.
212bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
213 APFloat::opStatus Status, FPOptions FPO);
214
215/// Checks why the given DeclRefExpr is invalid.
216bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);
217bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR,
218 bool InitializerFailed);
219
220/// DerivedToBaseMemberPointer
221bool CastMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off,
222 const RecordDecl *BaseDecl);
223/// BaseToDerivedMemberPointer
224bool CastMemberPtrDerivedPop(InterpState &S, CodePtr OpPC, int32_t Off,
225 const RecordDecl *BaseDecl);
226enum class ArithOp { Add, Sub };
227
228//===----------------------------------------------------------------------===//
229// Returning values
230//===----------------------------------------------------------------------===//
231
232void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC,
233 const Function *Func);
234
235template <PrimType Name, class T = typename PrimConv<Name>::T>
236bool Ret(InterpState &S, CodePtr &PC) {
237 const T &Ret = S.Stk.pop<T>();
238
239 assert(S.Current);
240 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
241 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
242 cleanupAfterFunctionCall(S, OpPC: PC, Func: S.Current->getFunction());
243
244 if (InterpFrame *Caller = S.Current->Caller) {
245 PC = S.Current->getRetPC();
246 InterpFrame::free(F: S.Current);
247 S.Current = Caller;
248 S.Stk.push<T>(Ret);
249 } else {
250 InterpFrame::free(F: S.Current);
251 S.Current = nullptr;
252 // The topmost frame should come from an EvalEmitter,
253 // which has its own implementation of the Ret<> instruction.
254 }
255 return true;
256}
257
258inline bool RetVoid(InterpState &S, CodePtr &PC) {
259 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
260
261 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
262 cleanupAfterFunctionCall(S, OpPC: PC, Func: S.Current->getFunction());
263
264 if (InterpFrame *Caller = S.Current->Caller) {
265 PC = S.Current->getRetPC();
266 InterpFrame::free(F: S.Current);
267 S.Current = Caller;
268 } else {
269 InterpFrame::free(F: S.Current);
270 S.Current = nullptr;
271 }
272 return true;
273}
274
275//===----------------------------------------------------------------------===//
276// Add, Sub, Mul
277//===----------------------------------------------------------------------===//
278
279template <typename T, bool (*OpFW)(T, T, unsigned, T *),
280 template <typename U> class OpAP>
281bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
282 const T &RHS) {
283 // Fast path - add the numbers with fixed width.
284 T Result;
285 if constexpr (needsAlloc<T>())
286 Result = S.allocAP<T>(LHS.bitWidth());
287
288 if (!OpFW(LHS, RHS, Bits, &Result)) {
289 S.Stk.push<T>(Result);
290 return true;
291 }
292 // If for some reason evaluation continues, use the truncated results.
293 S.Stk.push<T>(Result);
294
295 // Short-circuit fixed-points here since the error handling is easier.
296 if constexpr (std::is_same_v<T, FixedPoint>)
297 return handleFixedPointOverflow(S, OpPC, Result);
298
299 // Slow path - compute the result using another bit of precision.
300 APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
301
302 // Report undefined behaviour, stopping if required.
303 if (S.checkingForUndefinedBehavior()) {
304 const Expr *E = S.Current->getExpr(PC: OpPC);
305 QualType Type = E->getType();
306 SmallString<32> Trunc;
307 Value.trunc(width: Result.bitWidth())
308 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
309 /*UpperCase=*/true, /*InsertSeparators=*/true);
310 S.report(Loc: E->getExprLoc(), DiagId: diag::warn_integer_constant_overflow)
311 << Trunc << Type << E->getSourceRange();
312 }
313
314 if (!handleOverflow(S, OpPC, SrcValue: Value)) {
315 S.Stk.pop<T>();
316 return false;
317 }
318 return true;
319}
320
321template <PrimType Name, class T = typename PrimConv<Name>::T>
322bool Add(InterpState &S, CodePtr OpPC) {
323 const T &RHS = S.Stk.pop<T>();
324 const T &LHS = S.Stk.pop<T>();
325 const unsigned Bits = RHS.bitWidth() + 1;
326
327 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
328}
329
330inline bool Addf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
331 const Floating &RHS = S.Stk.pop<Floating>();
332 const Floating &LHS = S.Stk.pop<Floating>();
333
334 FPOptions FPO = FPOptions::getFromOpaqueInt(Value: FPOI);
335 Floating Result = S.allocFloat(Sem: LHS.getSemantics());
336 auto Status = Floating::add(A: LHS, B: RHS, RM: getRoundingMode(FPO), R: &Result);
337 S.Stk.push<Floating>(Args&: Result);
338 return CheckFloatResult(S, OpPC, Result, Status, FPO);
339}
340
341template <PrimType Name, class T = typename PrimConv<Name>::T>
342bool Sub(InterpState &S, CodePtr OpPC) {
343 const T &RHS = S.Stk.pop<T>();
344 const T &LHS = S.Stk.pop<T>();
345 const unsigned Bits = RHS.bitWidth() + 1;
346
347 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
348}
349
350inline bool Subf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
351 const Floating &RHS = S.Stk.pop<Floating>();
352 const Floating &LHS = S.Stk.pop<Floating>();
353
354 FPOptions FPO = FPOptions::getFromOpaqueInt(Value: FPOI);
355 Floating Result = S.allocFloat(Sem: LHS.getSemantics());
356 auto Status = Floating::sub(A: LHS, B: RHS, RM: getRoundingMode(FPO), R: &Result);
357 S.Stk.push<Floating>(Args&: Result);
358 return CheckFloatResult(S, OpPC, Result, Status, FPO);
359}
360
361template <PrimType Name, class T = typename PrimConv<Name>::T>
362bool Mul(InterpState &S, CodePtr OpPC) {
363 const T &RHS = S.Stk.pop<T>();
364 const T &LHS = S.Stk.pop<T>();
365 const unsigned Bits = RHS.bitWidth() * 2;
366
367 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
368}
369
370inline bool Mulf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
371 const Floating &RHS = S.Stk.pop<Floating>();
372 const Floating &LHS = S.Stk.pop<Floating>();
373
374 FPOptions FPO = FPOptions::getFromOpaqueInt(Value: FPOI);
375 Floating Result = S.allocFloat(Sem: LHS.getSemantics());
376
377 auto Status = Floating::mul(A: LHS, B: RHS, RM: getRoundingMode(FPO), R: &Result);
378
379 S.Stk.push<Floating>(Args&: Result);
380 return CheckFloatResult(S, OpPC, Result, Status, FPO);
381}
382
383template <PrimType Name, class T = typename PrimConv<Name>::T>
384inline bool Mulc(InterpState &S, CodePtr OpPC) {
385 const Pointer &RHS = S.Stk.pop<Pointer>();
386 const Pointer &LHS = S.Stk.pop<Pointer>();
387 const Pointer &Result = S.Stk.peek<Pointer>();
388
389 if constexpr (std::is_same_v<T, Floating>) {
390 APFloat A = LHS.elem<Floating>(I: 0).getAPFloat();
391 APFloat B = LHS.elem<Floating>(I: 1).getAPFloat();
392 APFloat C = RHS.elem<Floating>(I: 0).getAPFloat();
393 APFloat D = RHS.elem<Floating>(I: 1).getAPFloat();
394
395 APFloat ResR(A.getSemantics());
396 APFloat ResI(A.getSemantics());
397 HandleComplexComplexMul(A, B, C, D, ResR, ResI);
398
399 // Copy into the result.
400 Floating RA = S.allocFloat(Sem: A.getSemantics());
401 RA.copy(F: ResR);
402 Result.elem<Floating>(I: 0) = RA; // Floating(ResR);
403
404 Floating RI = S.allocFloat(Sem: A.getSemantics());
405 RI.copy(F: ResI);
406 Result.elem<Floating>(I: 1) = RI; // Floating(ResI);
407 Result.initializeAllElements();
408 } else {
409 // Integer element type.
410 const T &LHSR = LHS.elem<T>(0);
411 const T &LHSI = LHS.elem<T>(1);
412 const T &RHSR = RHS.elem<T>(0);
413 const T &RHSI = RHS.elem<T>(1);
414 unsigned Bits = LHSR.bitWidth();
415
416 // real(Result) = (real(LHS) * real(RHS)) - (imag(LHS) * imag(RHS))
417 T A;
418 if constexpr (needsAlloc<T>())
419 A = S.allocAP<T>(Bits);
420 if (T::mul(LHSR, RHSR, Bits, &A))
421 return false;
422
423 T B;
424 if constexpr (needsAlloc<T>())
425 B = S.allocAP<T>(Bits);
426 if (T::mul(LHSI, RHSI, Bits, &B))
427 return false;
428
429 if constexpr (needsAlloc<T>())
430 Result.elem<T>(0) = S.allocAP<T>(Bits);
431 if (T::sub(A, B, Bits, &Result.elem<T>(0)))
432 return false;
433
434 // imag(Result) = (real(LHS) * imag(RHS)) + (imag(LHS) * real(RHS))
435 if (T::mul(LHSR, RHSI, Bits, &A))
436 return false;
437 if (T::mul(LHSI, RHSR, Bits, &B))
438 return false;
439
440 if constexpr (needsAlloc<T>())
441 Result.elem<T>(1) = S.allocAP<T>(Bits);
442 if (T::add(A, B, Bits, &Result.elem<T>(1)))
443 return false;
444 Result.initialize();
445 Result.initializeAllElements();
446 }
447
448 return true;
449}
450
451template <PrimType Name, class T = typename PrimConv<Name>::T>
452inline bool Divc(InterpState &S, CodePtr OpPC) {
453 const Pointer &RHS = S.Stk.pop<Pointer>();
454 const Pointer &LHS = S.Stk.pop<Pointer>();
455 const Pointer &Result = S.Stk.peek<Pointer>();
456
457 if constexpr (std::is_same_v<T, Floating>) {
458 APFloat A = LHS.elem<Floating>(I: 0).getAPFloat();
459 APFloat B = LHS.elem<Floating>(I: 1).getAPFloat();
460 APFloat C = RHS.elem<Floating>(I: 0).getAPFloat();
461 APFloat D = RHS.elem<Floating>(I: 1).getAPFloat();
462
463 APFloat ResR(A.getSemantics());
464 APFloat ResI(A.getSemantics());
465 HandleComplexComplexDiv(A, B, C, D, ResR, ResI);
466
467 // Copy into the result.
468 Floating RA = S.allocFloat(Sem: A.getSemantics());
469 RA.copy(F: ResR);
470 Result.elem<Floating>(I: 0) = RA; // Floating(ResR);
471
472 Floating RI = S.allocFloat(Sem: A.getSemantics());
473 RI.copy(F: ResI);
474 Result.elem<Floating>(I: 1) = RI; // Floating(ResI);
475
476 Result.initializeAllElements();
477 } else {
478 // Integer element type.
479 const T &LHSR = LHS.elem<T>(0);
480 const T &LHSI = LHS.elem<T>(1);
481 const T &RHSR = RHS.elem<T>(0);
482 const T &RHSI = RHS.elem<T>(1);
483 unsigned Bits = LHSR.bitWidth();
484
485 if (RHSR.isZero() && RHSI.isZero()) {
486 const SourceInfo &E = S.Current->getSource(PC: OpPC);
487 S.FFDiag(SI: E, DiagId: diag::note_expr_divide_by_zero);
488 return false;
489 }
490
491 // Den = real(RHS)² + imag(RHS)²
492 T A, B;
493 if constexpr (needsAlloc<T>()) {
494 A = S.allocAP<T>(Bits);
495 B = S.allocAP<T>(Bits);
496 }
497
498 if (T::mul(RHSR, RHSR, Bits, &A) || T::mul(RHSI, RHSI, Bits, &B)) {
499 // Ignore overflow here, because that's what the current interpeter does.
500 }
501 T Den;
502 if constexpr (needsAlloc<T>())
503 Den = S.allocAP<T>(Bits);
504
505 if (T::add(A, B, Bits, &Den))
506 return false;
507
508 if (Den.isZero()) {
509 const SourceInfo &E = S.Current->getSource(PC: OpPC);
510 S.FFDiag(SI: E, DiagId: diag::note_expr_divide_by_zero);
511 return false;
512 }
513
514 // real(Result) = ((real(LHS) * real(RHS)) + (imag(LHS) * imag(RHS))) / Den
515 T &ResultR = Result.elem<T>(0);
516 T &ResultI = Result.elem<T>(1);
517 if constexpr (needsAlloc<T>()) {
518 ResultR = S.allocAP<T>(Bits);
519 ResultI = S.allocAP<T>(Bits);
520 }
521 if (T::mul(LHSR, RHSR, Bits, &A) || T::mul(LHSI, RHSI, Bits, &B))
522 return false;
523 if (T::add(A, B, Bits, &ResultR))
524 return false;
525 if (T::div(ResultR, Den, Bits, &ResultR))
526 return false;
527
528 // imag(Result) = ((imag(LHS) * real(RHS)) - (real(LHS) * imag(RHS))) / Den
529 if (T::mul(LHSI, RHSR, Bits, &A) || T::mul(LHSR, RHSI, Bits, &B))
530 return false;
531 if (T::sub(A, B, Bits, &ResultI))
532 return false;
533 if (T::div(ResultI, Den, Bits, &ResultI))
534 return false;
535 Result.initializeAllElements();
536 }
537
538 return true;
539}
540
541/// 1) Pops the RHS from the stack.
542/// 2) Pops the LHS from the stack.
543/// 3) Pushes 'LHS & RHS' on the stack
544template <PrimType Name, class T = typename PrimConv<Name>::T>
545bool BitAnd(InterpState &S, CodePtr OpPC) {
546 const T &RHS = S.Stk.pop<T>();
547 const T &LHS = S.Stk.pop<T>();
548 unsigned Bits = RHS.bitWidth();
549
550 T Result;
551 if constexpr (needsAlloc<T>())
552 Result = S.allocAP<T>(Bits);
553
554 if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
555 S.Stk.push<T>(Result);
556 return true;
557 }
558 return false;
559}
560
561/// 1) Pops the RHS from the stack.
562/// 2) Pops the LHS from the stack.
563/// 3) Pushes 'LHS | RHS' on the stack
564template <PrimType Name, class T = typename PrimConv<Name>::T>
565bool BitOr(InterpState &S, CodePtr OpPC) {
566 const T &RHS = S.Stk.pop<T>();
567 const T &LHS = S.Stk.pop<T>();
568 unsigned Bits = RHS.bitWidth();
569
570 T Result;
571 if constexpr (needsAlloc<T>())
572 Result = S.allocAP<T>(Bits);
573
574 if (!T::bitOr(LHS, RHS, Bits, &Result)) {
575 S.Stk.push<T>(Result);
576 return true;
577 }
578 return false;
579}
580
581/// 1) Pops the RHS from the stack.
582/// 2) Pops the LHS from the stack.
583/// 3) Pushes 'LHS ^ RHS' on the stack
584template <PrimType Name, class T = typename PrimConv<Name>::T>
585bool BitXor(InterpState &S, CodePtr OpPC) {
586 const T &RHS = S.Stk.pop<T>();
587 const T &LHS = S.Stk.pop<T>();
588
589 unsigned Bits = RHS.bitWidth();
590
591 T Result;
592 if constexpr (needsAlloc<T>())
593 Result = S.allocAP<T>(Bits);
594
595 if (!T::bitXor(LHS, RHS, Bits, &Result)) {
596 S.Stk.push<T>(Result);
597 return true;
598 }
599 return false;
600}
601
602/// 1) Pops the RHS from the stack.
603/// 2) Pops the LHS from the stack.
604/// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
605template <PrimType Name, class T = typename PrimConv<Name>::T>
606bool Rem(InterpState &S, CodePtr OpPC) {
607 const T &RHS = S.Stk.pop<T>();
608 const T &LHS = S.Stk.pop<T>();
609 const unsigned Bits = RHS.bitWidth() * 2;
610
611 if (!CheckDivRem(S, OpPC, LHS, RHS))
612 return false;
613
614 T Result;
615 if constexpr (needsAlloc<T>())
616 Result = S.allocAP<T>(LHS.bitWidth());
617
618 if (!T::rem(LHS, RHS, Bits, &Result)) {
619 S.Stk.push<T>(Result);
620 return true;
621 }
622 return false;
623}
624
625/// 1) Pops the RHS from the stack.
626/// 2) Pops the LHS from the stack.
627/// 3) Pushes 'LHS / RHS' on the stack
628template <PrimType Name, class T = typename PrimConv<Name>::T>
629bool Div(InterpState &S, CodePtr OpPC) {
630 const T &RHS = S.Stk.pop<T>();
631 const T &LHS = S.Stk.pop<T>();
632 const unsigned Bits = RHS.bitWidth() * 2;
633
634 if (!CheckDivRem(S, OpPC, LHS, RHS))
635 return false;
636
637 T Result;
638 if constexpr (needsAlloc<T>())
639 Result = S.allocAP<T>(LHS.bitWidth());
640
641 if (!T::div(LHS, RHS, Bits, &Result)) {
642 S.Stk.push<T>(Result);
643 return true;
644 }
645
646 if constexpr (std::is_same_v<T, FixedPoint>) {
647 if (handleFixedPointOverflow(S, OpPC, Result)) {
648 S.Stk.push<T>(Result);
649 return true;
650 }
651 }
652 return false;
653}
654
655inline bool Divf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
656 const Floating &RHS = S.Stk.pop<Floating>();
657 const Floating &LHS = S.Stk.pop<Floating>();
658
659 if (!CheckDivRem(S, OpPC, LHS, RHS))
660 return false;
661
662 FPOptions FPO = FPOptions::getFromOpaqueInt(Value: FPOI);
663
664 Floating Result = S.allocFloat(Sem: LHS.getSemantics());
665 auto Status = Floating::div(A: LHS, B: RHS, RM: getRoundingMode(FPO), R: &Result);
666
667 S.Stk.push<Floating>(Args&: Result);
668 return CheckFloatResult(S, OpPC, Result, Status, FPO);
669}
670
671//===----------------------------------------------------------------------===//
672// Inv
673//===----------------------------------------------------------------------===//
674
675inline bool Inv(InterpState &S, CodePtr OpPC) {
676 const auto &Val = S.Stk.pop<Boolean>();
677 S.Stk.push<Boolean>(Args: !Val);
678 return true;
679}
680
681//===----------------------------------------------------------------------===//
682// Neg
683//===----------------------------------------------------------------------===//
684
685template <PrimType Name, class T = typename PrimConv<Name>::T>
686bool Neg(InterpState &S, CodePtr OpPC) {
687 const T &Value = S.Stk.pop<T>();
688
689 if constexpr (std::is_same_v<T, Floating>) {
690 T Result = S.allocFloat(Sem: Value.getSemantics());
691
692 if (!T::neg(Value, &Result)) {
693 S.Stk.push<T>(Result);
694 return true;
695 }
696 return false;
697 } else {
698 T Result;
699 if constexpr (needsAlloc<T>())
700 Result = S.allocAP<T>(Value.bitWidth());
701
702 if (!T::neg(Value, &Result)) {
703 S.Stk.push<T>(Result);
704 return true;
705 }
706
707 assert(isIntegralType(Name) &&
708 "don't expect other types to fail at constexpr negation");
709 S.Stk.push<T>(Result);
710
711 APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
712 if (S.checkingForUndefinedBehavior()) {
713 const Expr *E = S.Current->getExpr(PC: OpPC);
714 QualType Type = E->getType();
715 SmallString<32> Trunc;
716 NegatedValue.trunc(width: Result.bitWidth())
717 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
718 /*UpperCase=*/true, /*InsertSeparators=*/true);
719 S.report(Loc: E->getExprLoc(), DiagId: diag::warn_integer_constant_overflow)
720 << Trunc << Type << E->getSourceRange();
721 return true;
722 }
723
724 return handleOverflow(S, OpPC, SrcValue: NegatedValue);
725 }
726}
727
728enum class PushVal : bool {
729 No,
730 Yes,
731};
732enum class IncDecOp {
733 Inc,
734 Dec,
735};
736
737template <typename T, IncDecOp Op, PushVal DoPush>
738bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
739 bool CanOverflow, UnsignedOrNone BitWidth = std::nullopt) {
740 assert(!Ptr.isDummy());
741
742 if (!S.inConstantContext()) {
743 if (isConstexprUnknown(P: Ptr))
744 return false;
745 }
746
747 if constexpr (std::is_same_v<T, Boolean>) {
748 if (!S.getLangOpts().CPlusPlus14)
749 return Invalid(S, OpPC);
750 }
751
752 const T &Value = Ptr.deref<T>();
753 T Result;
754 if constexpr (needsAlloc<T>())
755 Result = S.allocAP<T>(Value.bitWidth());
756
757 if constexpr (DoPush == PushVal::Yes)
758 S.Stk.push<T>(Value);
759
760 if constexpr (Op == IncDecOp::Inc) {
761 if (!T::increment(Value, &Result) || !CanOverflow) {
762 if (BitWidth)
763 Ptr.deref<T>() = Result.truncate(*BitWidth);
764 else
765 Ptr.deref<T>() = Result;
766 return true;
767 }
768 } else {
769 if (!T::decrement(Value, &Result) || !CanOverflow) {
770 if (BitWidth)
771 Ptr.deref<T>() = Result.truncate(*BitWidth);
772 else
773 Ptr.deref<T>() = Result;
774 return true;
775 }
776 }
777 assert(CanOverflow);
778
779 // Something went wrong with the previous operation. Compute the
780 // result with another bit of precision.
781 unsigned Bits = Value.bitWidth() + 1;
782 APSInt APResult;
783 if constexpr (Op == IncDecOp::Inc)
784 APResult = ++Value.toAPSInt(Bits);
785 else
786 APResult = --Value.toAPSInt(Bits);
787
788 // Report undefined behaviour, stopping if required.
789 if (S.checkingForUndefinedBehavior()) {
790 const Expr *E = S.Current->getExpr(PC: OpPC);
791 QualType Type = E->getType();
792 SmallString<32> Trunc;
793 APResult.trunc(width: Result.bitWidth())
794 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
795 /*UpperCase=*/true, /*InsertSeparators=*/true);
796 S.report(Loc: E->getExprLoc(), DiagId: diag::warn_integer_constant_overflow)
797 << Trunc << Type << E->getSourceRange();
798 return true;
799 }
800 return handleOverflow(S, OpPC, SrcValue: APResult);
801}
802
803/// 1) Pops a pointer from the stack
804/// 2) Load the value from the pointer
805/// 3) Writes the value increased by one back to the pointer
806/// 4) Pushes the original (pre-inc) value on the stack.
807template <PrimType Name, class T = typename PrimConv<Name>::T>
808bool Inc(InterpState &S, CodePtr OpPC, bool CanOverflow) {
809 const Pointer &Ptr = S.Stk.pop<Pointer>();
810 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Increment))
811 return false;
812 if (!CheckConst(S, OpPC, Ptr))
813 return false;
814
815 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr,
816 CanOverflow);
817}
818
819template <PrimType Name, class T = typename PrimConv<Name>::T>
820bool IncBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
821 unsigned BitWidth) {
822 const Pointer &Ptr = S.Stk.pop<Pointer>();
823 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Increment))
824 return false;
825 if (!CheckConst(S, OpPC, Ptr))
826 return false;
827
828 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, CanOverflow,
829 BitWidth);
830}
831
832/// 1) Pops a pointer from the stack
833/// 2) Load the value from the pointer
834/// 3) Writes the value increased by one back to the pointer
835template <PrimType Name, class T = typename PrimConv<Name>::T>
836bool IncPop(InterpState &S, CodePtr OpPC, bool CanOverflow) {
837 const Pointer &Ptr = S.Stk.pop<Pointer>();
838 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Increment))
839 return false;
840 if (!CheckConst(S, OpPC, Ptr))
841 return false;
842
843 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow);
844}
845
846template <PrimType Name, class T = typename PrimConv<Name>::T>
847bool IncPopBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
848 uint32_t BitWidth) {
849 const Pointer &Ptr = S.Stk.pop<Pointer>();
850 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Increment))
851 return false;
852 if (!CheckConst(S, OpPC, Ptr))
853 return false;
854
855 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow,
856 BitWidth);
857}
858
859template <PrimType Name, class T = typename PrimConv<Name>::T>
860bool PreInc(InterpState &S, CodePtr OpPC, bool CanOverflow) {
861 const Pointer &Ptr = S.Stk.peek<Pointer>();
862 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Increment))
863 return false;
864 if (!CheckConst(S, OpPC, Ptr))
865 return false;
866
867 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow);
868}
869
870template <PrimType Name, class T = typename PrimConv<Name>::T>
871bool PreIncBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
872 uint32_t BitWidth) {
873 const Pointer &Ptr = S.Stk.peek<Pointer>();
874 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Increment))
875 return false;
876 if (!CheckConst(S, OpPC, Ptr))
877 return false;
878
879 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow,
880 BitWidth);
881}
882
883/// 1) Pops a pointer from the stack
884/// 2) Load the value from the pointer
885/// 3) Writes the value decreased by one back to the pointer
886/// 4) Pushes the original (pre-dec) value on the stack.
887template <PrimType Name, class T = typename PrimConv<Name>::T>
888bool Dec(InterpState &S, CodePtr OpPC, bool CanOverflow) {
889 const Pointer &Ptr = S.Stk.pop<Pointer>();
890 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Decrement))
891 return false;
892 if (!CheckConst(S, OpPC, Ptr))
893 return false;
894
895 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr,
896 CanOverflow);
897}
898template <PrimType Name, class T = typename PrimConv<Name>::T>
899bool DecBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
900 uint32_t BitWidth) {
901 const Pointer &Ptr = S.Stk.pop<Pointer>();
902 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Decrement))
903 return false;
904 if (!CheckConst(S, OpPC, Ptr))
905 return false;
906
907 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, CanOverflow,
908 BitWidth);
909}
910
911/// 1) Pops a pointer from the stack
912/// 2) Load the value from the pointer
913/// 3) Writes the value decreased by one back to the pointer
914template <PrimType Name, class T = typename PrimConv<Name>::T>
915bool DecPop(InterpState &S, CodePtr OpPC, bool CanOverflow) {
916 const Pointer &Ptr = S.Stk.pop<Pointer>();
917 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Decrement))
918 return false;
919 if (!CheckConst(S, OpPC, Ptr))
920 return false;
921
922 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow);
923}
924
925template <PrimType Name, class T = typename PrimConv<Name>::T>
926bool DecPopBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
927 uint32_t BitWidth) {
928 const Pointer &Ptr = S.Stk.pop<Pointer>();
929 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Decrement))
930 return false;
931 if (!CheckConst(S, OpPC, Ptr))
932 return false;
933
934 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow,
935 BitWidth);
936}
937
938template <PrimType Name, class T = typename PrimConv<Name>::T>
939bool PreDec(InterpState &S, CodePtr OpPC, bool CanOverflow) {
940 const Pointer &Ptr = S.Stk.peek<Pointer>();
941 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Decrement))
942 return false;
943 if (!CheckConst(S, OpPC, Ptr))
944 return false;
945 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow);
946}
947
948template <PrimType Name, class T = typename PrimConv<Name>::T>
949bool PreDecBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,
950 uint32_t BitWidth) {
951 const Pointer &Ptr = S.Stk.peek<Pointer>();
952 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Decrement))
953 return false;
954 if (!CheckConst(S, OpPC, Ptr))
955 return false;
956 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow,
957 BitWidth);
958}
959
960template <IncDecOp Op, PushVal DoPush>
961bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
962 uint32_t FPOI) {
963 Floating Value = Ptr.deref<Floating>();
964 Floating Result = S.allocFloat(Sem: Value.getSemantics());
965
966 if constexpr (DoPush == PushVal::Yes)
967 S.Stk.push<Floating>(Args&: Value);
968
969 FPOptions FPO = FPOptions::getFromOpaqueInt(Value: FPOI);
970 llvm::APFloat::opStatus Status;
971 if constexpr (Op == IncDecOp::Inc)
972 Status = Floating::increment(A: Value, RM: getRoundingMode(FPO), R: &Result);
973 else
974 Status = Floating::decrement(A: Value, RM: getRoundingMode(FPO), R: &Result);
975
976 Ptr.deref<Floating>() = Result;
977
978 return CheckFloatResult(S, OpPC, Result, Status, FPO);
979}
980
981inline bool Incf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
982 const Pointer &Ptr = S.Stk.pop<Pointer>();
983 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Increment))
984 return false;
985 if (!CheckConst(S, OpPC, Ptr))
986 return false;
987
988 return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, FPOI);
989}
990
991inline bool IncfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
992 const Pointer &Ptr = S.Stk.pop<Pointer>();
993 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Increment))
994 return false;
995 if (!CheckConst(S, OpPC, Ptr))
996 return false;
997
998 return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, FPOI);
999}
1000
1001inline bool Decf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
1002 const Pointer &Ptr = S.Stk.pop<Pointer>();
1003 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Decrement))
1004 return false;
1005 if (!CheckConst(S, OpPC, Ptr))
1006 return false;
1007
1008 return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, FPOI);
1009}
1010
1011inline bool DecfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
1012 const Pointer &Ptr = S.Stk.pop<Pointer>();
1013 if (!CheckLoad(S, OpPC, Ptr, AK: AK_Decrement))
1014 return false;
1015 if (!CheckConst(S, OpPC, Ptr))
1016 return false;
1017
1018 return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, FPOI);
1019}
1020
1021/// 1) Pops the value from the stack.
1022/// 2) Pushes the bitwise complemented value on the stack (~V).
1023template <PrimType Name, class T = typename PrimConv<Name>::T>
1024bool Comp(InterpState &S, CodePtr OpPC) {
1025 const T &Val = S.Stk.pop<T>();
1026
1027 T Result;
1028 if constexpr (needsAlloc<T>())
1029 Result = S.allocAP<T>(Val.bitWidth());
1030
1031 if (!T::comp(Val, &Result)) {
1032 S.Stk.push<T>(Result);
1033 return true;
1034 }
1035 return false;
1036}
1037
1038//===----------------------------------------------------------------------===//
1039// EQ, NE, GT, GE, LT, LE
1040//===----------------------------------------------------------------------===//
1041
1042using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
1043
1044template <typename T>
1045bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
1046 assert((!std::is_same_v<T, MemberPointer>) &&
1047 "Non-equality comparisons on member pointer types should already be "
1048 "rejected in Sema.");
1049 using BoolT = PrimConv<PT_Bool>::T;
1050 const T &RHS = S.Stk.pop<T>();
1051 const T &LHS = S.Stk.pop<T>();
1052 S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
1053 return true;
1054}
1055
1056template <typename T>
1057bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
1058 return CmpHelper<T>(S, OpPC, Fn);
1059}
1060
1061template <>
1062inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
1063 using BoolT = PrimConv<PT_Bool>::T;
1064 const Pointer &RHS = S.Stk.pop<Pointer>();
1065 const Pointer &LHS = S.Stk.pop<Pointer>();
1066
1067 // Function pointers cannot be compared in an ordered way.
1068 if (LHS.isFunctionPointer() || RHS.isFunctionPointer() ||
1069 LHS.isTypeidPointer() || RHS.isTypeidPointer()) {
1070 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1071 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_comparison_unspecified)
1072 << LHS.toDiagnosticString(Ctx: S.getASTContext())
1073 << RHS.toDiagnosticString(Ctx: S.getASTContext());
1074 return false;
1075 }
1076
1077 if (!Pointer::hasSameBase(A: LHS, B: RHS)) {
1078 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1079 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_comparison_unspecified)
1080 << LHS.toDiagnosticString(Ctx: S.getASTContext())
1081 << RHS.toDiagnosticString(Ctx: S.getASTContext());
1082 return false;
1083 }
1084
1085 // Diagnose comparisons between fields with different access specifiers.
1086 if (std::optional<std::pair<Pointer, Pointer>> Split =
1087 Pointer::computeSplitPoint(A: LHS, B: RHS)) {
1088 const FieldDecl *LF = Split->first.getField();
1089 const FieldDecl *RF = Split->second.getField();
1090 if (LF && RF && !LF->getParent()->isUnion() &&
1091 LF->getAccess() != RF->getAccess()) {
1092 S.CCEDiag(SI: S.Current->getSource(PC: OpPC),
1093 DiagId: diag::note_constexpr_pointer_comparison_differing_access)
1094 << LF << LF->getAccess() << RF << RF->getAccess() << LF->getParent();
1095 }
1096 }
1097
1098 unsigned VL = LHS.getByteOffset();
1099 unsigned VR = RHS.getByteOffset();
1100 S.Stk.push<BoolT>(Args: BoolT::from(Value: Fn(Compare(X: VL, Y: VR))));
1101 return true;
1102}
1103
1104static inline bool IsOpaqueConstantCall(const CallExpr *E) {
1105 unsigned Builtin = E->getBuiltinCallee();
1106 return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
1107 Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
1108 Builtin == Builtin::BI__builtin_ptrauth_sign_constant ||
1109 Builtin == Builtin::BI__builtin_function_start);
1110}
1111
1112bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS,
1113 const Pointer &RHS);
1114
1115template <>
1116inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
1117 using BoolT = PrimConv<PT_Bool>::T;
1118 const Pointer &RHS = S.Stk.pop<Pointer>();
1119 const Pointer &LHS = S.Stk.pop<Pointer>();
1120
1121 if (LHS.isZero() && RHS.isZero()) {
1122 S.Stk.push<BoolT>(Args: BoolT::from(Value: Fn(ComparisonCategoryResult::Equal)));
1123 return true;
1124 }
1125
1126 // Reject comparisons to weak pointers.
1127 for (const auto &P : {LHS, RHS}) {
1128 if (P.isZero())
1129 continue;
1130 if (P.isWeak()) {
1131 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1132 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_weak_comparison)
1133 << P.toDiagnosticString(Ctx: S.getASTContext());
1134 return false;
1135 }
1136 }
1137
1138 if (!S.inConstantContext()) {
1139 if (isConstexprUnknown(P: LHS) || isConstexprUnknown(P: RHS))
1140 return false;
1141 }
1142
1143 if (LHS.isFunctionPointer() && RHS.isFunctionPointer()) {
1144 S.Stk.push<BoolT>(Args: BoolT::from(Value: Fn(Compare(X: LHS.getIntegerRepresentation(),
1145 Y: RHS.getIntegerRepresentation()))));
1146 return true;
1147 }
1148
1149 // FIXME: The source check here isn't entirely correct.
1150 if (LHS.pointsToStringLiteral() && RHS.pointsToStringLiteral() &&
1151 LHS.getFieldDesc()->asExpr() != RHS.getFieldDesc()->asExpr()) {
1152 if (arePotentiallyOverlappingStringLiterals(LHS, RHS)) {
1153 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1154 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_literal_comparison)
1155 << LHS.toDiagnosticString(Ctx: S.getASTContext())
1156 << RHS.toDiagnosticString(Ctx: S.getASTContext());
1157 return false;
1158 }
1159 }
1160
1161 if (Pointer::hasSameBase(A: LHS, B: RHS)) {
1162 size_t A = LHS.computeOffsetForComparison(ASTCtx: S.getASTContext());
1163 size_t B = RHS.computeOffsetForComparison(ASTCtx: S.getASTContext());
1164
1165 S.Stk.push<BoolT>(Args: BoolT::from(Value: Fn(Compare(X: A, Y: B))));
1166 return true;
1167 }
1168
1169 // Otherwise we need to do a bunch of extra checks before returning Unordered.
1170 if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() &&
1171 RHS.isBlockPointer() && RHS.getOffset() == 0) {
1172 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1173 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_comparison_past_end)
1174 << LHS.toDiagnosticString(Ctx: S.getASTContext());
1175 return false;
1176 }
1177 if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
1178 LHS.isBlockPointer() && LHS.getOffset() == 0) {
1179 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1180 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_comparison_past_end)
1181 << RHS.toDiagnosticString(Ctx: S.getASTContext());
1182 return false;
1183 }
1184
1185 bool BothNonNull = !LHS.isZero() && !RHS.isZero();
1186 // Reject comparisons to literals.
1187 for (const auto &P : {LHS, RHS}) {
1188 if (P.isZero())
1189 continue;
1190 if (BothNonNull && P.pointsToLiteral()) {
1191 const Expr *E = P.getDeclDesc()->asExpr();
1192 if (isa<StringLiteral>(Val: E)) {
1193 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1194 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_literal_comparison);
1195 return false;
1196 }
1197 if (const auto *CE = dyn_cast<CallExpr>(Val: E);
1198 CE && IsOpaqueConstantCall(E: CE)) {
1199 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1200 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_opaque_call_comparison)
1201 << P.toDiagnosticString(Ctx: S.getASTContext());
1202 return false;
1203 }
1204 } else if (BothNonNull && P.isIntegralPointer()) {
1205 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1206 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_constant_comparison)
1207 << LHS.toDiagnosticString(Ctx: S.getASTContext())
1208 << RHS.toDiagnosticString(Ctx: S.getASTContext());
1209 return false;
1210 }
1211 }
1212
1213 if (LHS.isUnknownSizeArray() && RHS.isUnknownSizeArray()) {
1214 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1215 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_comparison_zero_sized)
1216 << LHS.toDiagnosticString(Ctx: S.getASTContext())
1217 << RHS.toDiagnosticString(Ctx: S.getASTContext());
1218 return false;
1219 }
1220
1221 S.Stk.push<BoolT>(Args: BoolT::from(Value: Fn(ComparisonCategoryResult::Unordered)));
1222 return true;
1223}
1224
1225template <>
1226inline bool CmpHelperEQ<MemberPointer>(InterpState &S, CodePtr OpPC,
1227 CompareFn Fn) {
1228 const auto &RHS = S.Stk.pop<MemberPointer>();
1229 const auto &LHS = S.Stk.pop<MemberPointer>();
1230
1231 // If either operand is a pointer to a weak function, the comparison is not
1232 // constant.
1233 for (const auto &MP : {LHS, RHS}) {
1234 if (MP.isWeak()) {
1235 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1236 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_mem_pointer_weak_comparison)
1237 << MP.getMemberFunction();
1238 return false;
1239 }
1240 }
1241
1242 // C++11 [expr.eq]p2:
1243 // If both operands are null, they compare equal. Otherwise if only one is
1244 // null, they compare unequal.
1245 if (LHS.isZero() && RHS.isZero()) {
1246 S.Stk.push<Boolean>(Args: Fn(ComparisonCategoryResult::Equal));
1247 return true;
1248 }
1249 if (LHS.isZero() || RHS.isZero()) {
1250 S.Stk.push<Boolean>(Args: Fn(ComparisonCategoryResult::Unordered));
1251 return true;
1252 }
1253
1254 // We cannot compare against virtual declarations at compile time.
1255 for (const auto &MP : {LHS, RHS}) {
1256 if (const CXXMethodDecl *MD = MP.getMemberFunction();
1257 MD && MD->isVirtual()) {
1258 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1259 S.CCEDiag(SI: Loc, DiagId: diag::note_constexpr_compare_virtual_mem_ptr) << MD;
1260 }
1261 }
1262
1263 S.Stk.push<Boolean>(Args: Boolean::from(Value: Fn(LHS.compare(RHS))));
1264 return true;
1265}
1266
1267template <PrimType Name, class T = typename PrimConv<Name>::T>
1268bool EQ(InterpState &S, CodePtr OpPC) {
1269 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1270 return R == ComparisonCategoryResult::Equal;
1271 });
1272}
1273
1274template <PrimType Name, class T = typename PrimConv<Name>::T>
1275bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
1276 const T &RHS = S.Stk.pop<T>();
1277 const T &LHS = S.Stk.pop<T>();
1278 const Pointer &P = S.Stk.peek<Pointer>();
1279
1280 ComparisonCategoryResult CmpResult = LHS.compare(RHS);
1281 if constexpr (std::is_same_v<T, Pointer>) {
1282 if (CmpResult == ComparisonCategoryResult::Unordered) {
1283 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
1284 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_pointer_comparison_unspecified)
1285 << LHS.toDiagnosticString(S.getASTContext())
1286 << RHS.toDiagnosticString(S.getASTContext());
1287 return false;
1288 }
1289 }
1290
1291 assert(CmpInfo);
1292 const auto *CmpValueInfo =
1293 CmpInfo->getValueInfo(ValueKind: CmpInfo->makeWeakResult(Res: CmpResult));
1294 assert(CmpValueInfo);
1295 assert(CmpValueInfo->hasValidIntValue());
1296 return SetThreeWayComparisonField(S, OpPC, Ptr: P, IntValue: CmpValueInfo->getIntValue());
1297}
1298
1299template <PrimType Name, class T = typename PrimConv<Name>::T>
1300bool NE(InterpState &S, CodePtr OpPC) {
1301 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1302 return R != ComparisonCategoryResult::Equal;
1303 });
1304}
1305
1306template <PrimType Name, class T = typename PrimConv<Name>::T>
1307bool LT(InterpState &S, CodePtr OpPC) {
1308 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1309 return R == ComparisonCategoryResult::Less;
1310 });
1311}
1312
1313template <PrimType Name, class T = typename PrimConv<Name>::T>
1314bool LE(InterpState &S, CodePtr OpPC) {
1315 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1316 return R == ComparisonCategoryResult::Less ||
1317 R == ComparisonCategoryResult::Equal;
1318 });
1319}
1320
1321template <PrimType Name, class T = typename PrimConv<Name>::T>
1322bool GT(InterpState &S, CodePtr OpPC) {
1323 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1324 return R == ComparisonCategoryResult::Greater;
1325 });
1326}
1327
1328template <PrimType Name, class T = typename PrimConv<Name>::T>
1329bool GE(InterpState &S, CodePtr OpPC) {
1330 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1331 return R == ComparisonCategoryResult::Greater ||
1332 R == ComparisonCategoryResult::Equal;
1333 });
1334}
1335
1336//===----------------------------------------------------------------------===//
1337// Dup, Pop, Test
1338//===----------------------------------------------------------------------===//
1339
1340template <PrimType Name, class T = typename PrimConv<Name>::T>
1341bool Dup(InterpState &S, CodePtr OpPC) {
1342 S.Stk.push<T>(S.Stk.peek<T>());
1343 return true;
1344}
1345
1346template <PrimType Name, class T = typename PrimConv<Name>::T>
1347bool Pop(InterpState &S, CodePtr OpPC) {
1348 S.Stk.discard<T>();
1349 return true;
1350}
1351
1352/// [Value1, Value2] -> [Value2, Value1]
1353template <PrimType TopName, PrimType BottomName>
1354bool Flip(InterpState &S, CodePtr OpPC) {
1355 using TopT = typename PrimConv<TopName>::T;
1356 using BottomT = typename PrimConv<BottomName>::T;
1357
1358 const auto &Top = S.Stk.pop<TopT>();
1359 const auto &Bottom = S.Stk.pop<BottomT>();
1360
1361 S.Stk.push<TopT>(Top);
1362 S.Stk.push<BottomT>(Bottom);
1363
1364 return true;
1365}
1366
1367//===----------------------------------------------------------------------===//
1368// Const
1369//===----------------------------------------------------------------------===//
1370
1371template <PrimType Name, class T = typename PrimConv<Name>::T>
1372bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
1373 if constexpr (needsAlloc<T>()) {
1374 T Result = S.allocAP<T>(Arg.bitWidth());
1375 Result.copy(Arg.toAPSInt());
1376 S.Stk.push<T>(Result);
1377 return true;
1378 }
1379 S.Stk.push<T>(Arg);
1380 return true;
1381}
1382
1383inline bool ConstFloat(InterpState &S, CodePtr OpPC, const Floating &F) {
1384 Floating Result = S.allocFloat(Sem: F.getSemantics());
1385 Result.copy(F: F.getAPFloat());
1386 S.Stk.push<Floating>(Args&: Result);
1387 return true;
1388}
1389
1390//===----------------------------------------------------------------------===//
1391// Get/Set Local/Param/Global/This
1392//===----------------------------------------------------------------------===//
1393
1394template <PrimType Name, class T = typename PrimConv<Name>::T>
1395bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1396 const Block *B = S.Current->getLocalBlock(Offset: I);
1397 if (!CheckLocalLoad(S, OpPC, B))
1398 return false;
1399 S.Stk.push<T>(B->deref<T>());
1400 return true;
1401}
1402
1403bool EndLifetime(InterpState &S, CodePtr OpPC);
1404bool EndLifetimePop(InterpState &S, CodePtr OpPC);
1405bool StartLifetime(InterpState &S, CodePtr OpPC);
1406
1407/// 1) Pops the value from the stack.
1408/// 2) Writes the value to the local variable with the
1409/// given offset.
1410template <PrimType Name, class T = typename PrimConv<Name>::T>
1411bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1412 S.Current->setLocal<T>(I, S.Stk.pop<T>());
1413 return true;
1414}
1415
1416template <PrimType Name, class T = typename PrimConv<Name>::T>
1417bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1418 if (S.checkingPotentialConstantExpression()) {
1419 return false;
1420 }
1421 S.Stk.push<T>(S.Current->getParam<T>(I));
1422 return true;
1423}
1424
1425template <PrimType Name, class T = typename PrimConv<Name>::T>
1426bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1427 S.Current->setParam<T>(I, S.Stk.pop<T>());
1428 return true;
1429}
1430
1431/// 1) Peeks a pointer on the stack
1432/// 2) Pushes the value of the pointer's field on the stack
1433template <PrimType Name, class T = typename PrimConv<Name>::T>
1434bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1435 const Pointer &Obj = S.Stk.peek<Pointer>();
1436 if (!CheckNull(S, OpPC, Ptr: Obj, CSK: CSK_Field))
1437 return false;
1438 if (!CheckRange(S, OpPC, Ptr: Obj, CSK: CSK_Field))
1439 return false;
1440 const Pointer &Field = Obj.atField(Off: I);
1441 if (!CheckLoad(S, OpPC, Ptr: Field))
1442 return false;
1443 S.Stk.push<T>(Field.deref<T>());
1444 return true;
1445}
1446
1447template <PrimType Name, class T = typename PrimConv<Name>::T>
1448bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1449 const T &Value = S.Stk.pop<T>();
1450 const Pointer &Obj = S.Stk.peek<Pointer>();
1451 if (!CheckNull(S, OpPC, Ptr: Obj, CSK: CSK_Field))
1452 return false;
1453 if (!CheckRange(S, OpPC, Ptr: Obj, CSK: CSK_Field))
1454 return false;
1455 const Pointer &Field = Obj.atField(Off: I);
1456 if (!CheckStore(S, OpPC, Ptr: Field))
1457 return false;
1458 Field.initialize();
1459 Field.deref<T>() = Value;
1460 return true;
1461}
1462
1463/// 1) Pops a pointer from the stack
1464/// 2) Pushes the value of the pointer's field on the stack
1465template <PrimType Name, class T = typename PrimConv<Name>::T>
1466bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
1467 const Pointer &Obj = S.Stk.pop<Pointer>();
1468 if (!CheckNull(S, OpPC, Ptr: Obj, CSK: CSK_Field))
1469 return false;
1470 if (!CheckRange(S, OpPC, Ptr: Obj, CSK: CSK_Field))
1471 return false;
1472 const Pointer &Field = Obj.atField(Off: I);
1473 if (!CheckLoad(S, OpPC, Ptr: Field))
1474 return false;
1475 S.Stk.push<T>(Field.deref<T>());
1476 return true;
1477}
1478
1479template <PrimType Name, class T = typename PrimConv<Name>::T>
1480bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1481 if (S.checkingPotentialConstantExpression())
1482 return false;
1483 if (!CheckThis(S, OpPC))
1484 return false;
1485 const Pointer &This = S.Current->getThis();
1486 const Pointer &Field = This.atField(Off: I);
1487 if (!CheckLoad(S, OpPC, Ptr: Field))
1488 return false;
1489 S.Stk.push<T>(Field.deref<T>());
1490 return true;
1491}
1492
1493template <PrimType Name, class T = typename PrimConv<Name>::T>
1494bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1495 if (S.checkingPotentialConstantExpression())
1496 return false;
1497 if (!CheckThis(S, OpPC))
1498 return false;
1499 const T &Value = S.Stk.pop<T>();
1500 const Pointer &This = S.Current->getThis();
1501 const Pointer &Field = This.atField(Off: I);
1502 if (!CheckStore(S, OpPC, Ptr: Field))
1503 return false;
1504 Field.deref<T>() = Value;
1505 return true;
1506}
1507
1508template <PrimType Name, class T = typename PrimConv<Name>::T>
1509bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1510 const Block *B = S.P.getGlobal(Idx: I);
1511
1512 if (!CheckGlobalLoad(S, OpPC, B))
1513 return false;
1514
1515 S.Stk.push<T>(B->deref<T>());
1516 return true;
1517}
1518
1519/// Same as GetGlobal, but without the checks.
1520template <PrimType Name, class T = typename PrimConv<Name>::T>
1521bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {
1522 const Block *B = S.P.getGlobal(Idx: I);
1523 const auto &Desc = B->getBlockDesc<GlobalInlineDescriptor>();
1524 if (Desc.InitState != GlobalInitState::Initialized)
1525 return DiagnoseUninitialized(S, OpPC, Extern: B->isExtern(), Desc: B->getDescriptor(),
1526 AK: AK_Read);
1527
1528 S.Stk.push<T>(B->deref<T>());
1529 return true;
1530}
1531
1532template <PrimType Name, class T = typename PrimConv<Name>::T>
1533bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1534 // TODO: emit warning.
1535 return false;
1536}
1537
1538template <PrimType Name, class T = typename PrimConv<Name>::T>
1539bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1540 const Pointer &P = S.P.getGlobal(Idx: I);
1541
1542 P.deref<T>() = S.Stk.pop<T>();
1543
1544 if constexpr (std::is_same_v<T, Floating>) {
1545 auto &Val = P.deref<Floating>();
1546 if (!Val.singleWord()) {
1547 uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
1548 Val.take(NewMemory);
1549 }
1550
1551 } else if constexpr (std::is_same_v<T, MemberPointer>) {
1552 auto &Val = P.deref<MemberPointer>();
1553 unsigned PathLength = Val.getPathLength();
1554 auto *NewPath = new (S.P) const CXXRecordDecl *[PathLength];
1555 for (unsigned I = 0; I != PathLength; ++I) {
1556 NewPath[I] = Val.getPathEntry(Index: I);
1557 }
1558 Val.takePath(NewPath);
1559 } else if constexpr (needsAlloc<T>()) {
1560 auto &Val = P.deref<T>();
1561 if (!Val.singleWord()) {
1562 uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
1563 Val.take(NewMemory);
1564 }
1565 }
1566
1567 P.initialize();
1568 return true;
1569}
1570
1571/// 1) Converts the value on top of the stack to an APValue
1572/// 2) Sets that APValue on \Temp
1573/// 3) Initializes global with index \I with that
1574template <PrimType Name, class T = typename PrimConv<Name>::T>
1575bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
1576 const LifetimeExtendedTemporaryDecl *Temp) {
1577 if (S.EvalMode == EvaluationMode::ConstantFold)
1578 return false;
1579 assert(Temp);
1580
1581 const Pointer &Ptr = S.P.getGlobal(Idx: I);
1582 assert(Ptr.getDeclDesc()->asExpr());
1583 S.SeenGlobalTemporaries.push_back(
1584 Elt: std::make_pair(x: Ptr.getDeclDesc()->asExpr(), y&: Temp));
1585
1586 Ptr.deref<T>() = S.Stk.pop<T>();
1587 Ptr.initialize();
1588 return true;
1589}
1590
1591/// 1) Converts the value on top of the stack to an APValue
1592/// 2) Sets that APValue on \Temp
1593/// 3) Initialized global with index \I with that
1594inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC,
1595 const LifetimeExtendedTemporaryDecl *Temp) {
1596 if (S.EvalMode == EvaluationMode::ConstantFold)
1597 return false;
1598 assert(Temp);
1599
1600 const Pointer &Ptr = S.Stk.peek<Pointer>();
1601 S.SeenGlobalTemporaries.push_back(
1602 Elt: std::make_pair(x: Ptr.getDeclDesc()->asExpr(), y&: Temp));
1603 return true;
1604}
1605
1606template <PrimType Name, class T = typename PrimConv<Name>::T>
1607bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1608 if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)
1609 return false;
1610 if (!CheckThis(S, OpPC))
1611 return false;
1612 const Pointer &This = S.Current->getThis();
1613 const Pointer &Field = This.atField(Off: I);
1614 assert(Field.canBeInitialized());
1615 Field.deref<T>() = S.Stk.pop<T>();
1616 Field.initialize();
1617 return true;
1618}
1619
1620template <PrimType Name, class T = typename PrimConv<Name>::T>
1621bool InitThisFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I) {
1622 if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)
1623 return false;
1624 if (!CheckThis(S, OpPC))
1625 return false;
1626 const Pointer &This = S.Current->getThis();
1627 const Pointer &Field = This.atField(Off: I);
1628 assert(Field.canBeInitialized());
1629 Field.deref<T>() = S.Stk.pop<T>();
1630 Field.activate();
1631 Field.initialize();
1632 return true;
1633}
1634
1635// FIXME: The Field pointer here is too much IMO and we could instead just
1636// pass an Offset + BitWidth pair.
1637template <PrimType Name, class T = typename PrimConv<Name>::T>
1638bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,
1639 uint32_t FieldOffset) {
1640 assert(F->isBitField());
1641 if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)
1642 return false;
1643 if (!CheckThis(S, OpPC))
1644 return false;
1645 const Pointer &This = S.Current->getThis();
1646 const Pointer &Field = This.atField(Off: FieldOffset);
1647 assert(Field.canBeInitialized());
1648 const auto &Value = S.Stk.pop<T>();
1649 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());
1650 Field.initialize();
1651 return true;
1652}
1653
1654template <PrimType Name, class T = typename PrimConv<Name>::T>
1655bool InitThisBitFieldActivate(InterpState &S, CodePtr OpPC,
1656 const Record::Field *F, uint32_t FieldOffset) {
1657 assert(F->isBitField());
1658 if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)
1659 return false;
1660 if (!CheckThis(S, OpPC))
1661 return false;
1662 const Pointer &This = S.Current->getThis();
1663 const Pointer &Field = This.atField(Off: FieldOffset);
1664 assert(Field.canBeInitialized());
1665 const auto &Value = S.Stk.pop<T>();
1666 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());
1667 Field.initialize();
1668 Field.activate();
1669 return true;
1670}
1671
1672/// 1) Pops the value from the stack
1673/// 2) Peeks a pointer from the stack
1674/// 3) Pushes the value to field I of the pointer on the stack
1675template <PrimType Name, class T = typename PrimConv<Name>::T>
1676bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
1677 const T &Value = S.Stk.pop<T>();
1678 const Pointer &Ptr = S.Stk.peek<Pointer>();
1679 if (!CheckRange(S, OpPC, Ptr, CSK: CSK_Field))
1680 return false;
1681 if (!CheckArray(S, OpPC, Ptr))
1682 return false;
1683
1684 const Pointer &Field = Ptr.atField(Off: I);
1685 Field.deref<T>() = Value;
1686 Field.initialize();
1687 return true;
1688}
1689
1690template <PrimType Name, class T = typename PrimConv<Name>::T>
1691bool InitFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I) {
1692 const T &Value = S.Stk.pop<T>();
1693 const Pointer &Ptr = S.Stk.peek<Pointer>();
1694 if (!CheckRange(S, OpPC, Ptr, CSK: CSK_Field))
1695 return false;
1696 if (!CheckArray(S, OpPC, Ptr))
1697 return false;
1698
1699 const Pointer &Field = Ptr.atField(Off: I);
1700 Field.deref<T>() = Value;
1701 Field.activate();
1702 Field.initialize();
1703 return true;
1704}
1705
1706template <PrimType Name, class T = typename PrimConv<Name>::T>
1707bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
1708 assert(F->isBitField());
1709 const T &Value = S.Stk.pop<T>();
1710 const Pointer &Ptr = S.Stk.peek<Pointer>();
1711 if (!CheckRange(S, OpPC, Ptr, CSK: CSK_Field))
1712 return false;
1713 if (!CheckArray(S, OpPC, Ptr))
1714 return false;
1715
1716 const Pointer &Field = Ptr.atField(Off: F->Offset);
1717
1718 unsigned BitWidth = std::min(F->Decl->getBitWidthValue(), Value.bitWidth());
1719 if constexpr (needsAlloc<T>()) {
1720 T Result = S.allocAP<T>(Value.bitWidth());
1721 if constexpr (T::isSigned())
1722 Result.copy(
1723 Value.toAPSInt().trunc(BitWidth).sextOrTrunc(Value.bitWidth()));
1724 else
1725 Result.copy(
1726 Value.toAPSInt().trunc(BitWidth).zextOrTrunc(Value.bitWidth()));
1727
1728 Field.deref<T>() = Result;
1729 } else {
1730 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());
1731 }
1732 Field.initialize();
1733 return true;
1734}
1735
1736template <PrimType Name, class T = typename PrimConv<Name>::T>
1737bool InitBitFieldActivate(InterpState &S, CodePtr OpPC,
1738 const Record::Field *F) {
1739 assert(F->isBitField());
1740 const T &Value = S.Stk.pop<T>();
1741 const Pointer &Ptr = S.Stk.peek<Pointer>();
1742 if (!CheckRange(S, OpPC, Ptr, CSK: CSK_Field))
1743 return false;
1744 if (!CheckArray(S, OpPC, Ptr))
1745 return false;
1746
1747 const Pointer &Field = Ptr.atField(Off: F->Offset);
1748
1749 unsigned BitWidth = std::min(F->Decl->getBitWidthValue(), Value.bitWidth());
1750 if constexpr (needsAlloc<T>()) {
1751 T Result = S.allocAP<T>(Value.bitWidth());
1752 if constexpr (T::isSigned())
1753 Result.copy(
1754 Value.toAPSInt().trunc(BitWidth).sextOrTrunc(Value.bitWidth()));
1755 else
1756 Result.copy(
1757 Value.toAPSInt().trunc(BitWidth).zextOrTrunc(Value.bitWidth()));
1758
1759 Field.deref<T>() = Result;
1760 } else {
1761 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());
1762 }
1763 Field.activate();
1764 Field.initialize();
1765 return true;
1766}
1767
1768//===----------------------------------------------------------------------===//
1769// GetPtr Local/Param/Global/Field/This
1770//===----------------------------------------------------------------------===//
1771
1772inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1773 S.Stk.push<Pointer>(Args: S.Current->getLocalPointer(Offset: I));
1774 return true;
1775}
1776
1777inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1778 if (S.Current->isBottomFrame())
1779 return false;
1780 S.Stk.push<Pointer>(Args: S.Current->getParamPointer(Offset: I));
1781 return true;
1782}
1783
1784inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1785 S.Stk.push<Pointer>(Args: S.P.getPtrGlobal(Idx: I));
1786 return true;
1787}
1788
1789/// 1) Peeks a Pointer
1790/// 2) Pushes Pointer.atField(Off) on the stack
1791bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off);
1792bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off);
1793
1794inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1795 if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)
1796 return false;
1797 if (!CheckThis(S, OpPC))
1798 return false;
1799 const Pointer &This = S.Current->getThis();
1800 S.Stk.push<Pointer>(Args: This.atField(Off));
1801 return true;
1802}
1803
1804inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off,
1805 bool NullOK, const Type *TargetType) {
1806 const Pointer &Ptr = S.Stk.pop<Pointer>();
1807 if (!NullOK && !CheckNull(S, OpPC, Ptr, CSK: CSK_Derived))
1808 return false;
1809
1810 if (!Ptr.isBlockPointer()) {
1811 // FIXME: We don't have the necessary information in integral pointers.
1812 // The Descriptor only has a record, but that does of course not include
1813 // the potential derived classes of said record.
1814 S.Stk.push<Pointer>(Args: Ptr);
1815 return true;
1816 }
1817
1818 if (!CheckSubobject(S, OpPC, Ptr, CSK: CSK_Derived))
1819 return false;
1820 if (!CheckDowncast(S, OpPC, Ptr, Offset: Off))
1821 return false;
1822
1823 const Record *TargetRecord = Ptr.atFieldSub(Off).getRecord();
1824 assert(TargetRecord);
1825
1826 if (TargetRecord->getDecl()->getCanonicalDecl() !=
1827 TargetType->getAsCXXRecordDecl()->getCanonicalDecl()) {
1828 QualType MostDerivedType = Ptr.getDeclDesc()->getType();
1829 S.CCEDiag(SI: S.Current->getSource(PC: OpPC), DiagId: diag::note_constexpr_invalid_downcast)
1830 << MostDerivedType << QualType(TargetType, 0);
1831 return false;
1832 }
1833
1834 S.Stk.push<Pointer>(Args: Ptr.atFieldSub(Off));
1835 return true;
1836}
1837
1838inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1839 const Pointer &Ptr = S.Stk.peek<Pointer>();
1840 if (!CheckNull(S, OpPC, Ptr, CSK: CSK_Base))
1841 return false;
1842
1843 if (!Ptr.isBlockPointer()) {
1844 if (!Ptr.isIntegralPointer())
1845 return false;
1846 S.Stk.push<Pointer>(Args: Ptr.asIntPointer().baseCast(ASTCtx: S.getASTContext(), BaseOffset: Off));
1847 return true;
1848 }
1849
1850 if (!CheckSubobject(S, OpPC, Ptr, CSK: CSK_Base))
1851 return false;
1852 const Pointer &Result = Ptr.atField(Off);
1853 if (Result.isPastEnd() || !Result.isBaseClass())
1854 return false;
1855 S.Stk.push<Pointer>(Args: Result);
1856 return true;
1857}
1858
1859inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off,
1860 bool NullOK) {
1861 const Pointer &Ptr = S.Stk.pop<Pointer>();
1862
1863 if (!NullOK && !CheckNull(S, OpPC, Ptr, CSK: CSK_Base))
1864 return false;
1865
1866 if (!Ptr.isBlockPointer()) {
1867 if (!Ptr.isIntegralPointer())
1868 return false;
1869 S.Stk.push<Pointer>(Args: Ptr.asIntPointer().baseCast(ASTCtx: S.getASTContext(), BaseOffset: Off));
1870 return true;
1871 }
1872
1873 if (!CheckSubobject(S, OpPC, Ptr, CSK: CSK_Base))
1874 return false;
1875 const Pointer &Result = Ptr.atField(Off);
1876 if (Result.isPastEnd() || !Result.isBaseClass())
1877 return false;
1878 S.Stk.push<Pointer>(Args: Result);
1879 return true;
1880}
1881
1882inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1883 if (S.checkingPotentialConstantExpression())
1884 return false;
1885 if (!CheckThis(S, OpPC))
1886 return false;
1887 const Pointer &This = S.Current->getThis();
1888 S.Stk.push<Pointer>(Args: This.atField(Off));
1889 return true;
1890}
1891
1892inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {
1893 const Pointer &Ptr = S.Stk.pop<Pointer>();
1894 if (Ptr.canBeInitialized())
1895 Ptr.initialize();
1896 return true;
1897}
1898
1899inline bool FinishInit(InterpState &S, CodePtr OpPC) {
1900 const Pointer &Ptr = S.Stk.peek<Pointer>();
1901 if (Ptr.canBeInitialized())
1902 Ptr.initialize();
1903 return true;
1904}
1905
1906inline bool FinishInitActivate(InterpState &S, CodePtr OpPC) {
1907 const Pointer &Ptr = S.Stk.peek<Pointer>();
1908 if (Ptr.canBeInitialized()) {
1909 Ptr.initialize();
1910 Ptr.activate();
1911 }
1912 return true;
1913}
1914
1915inline bool FinishInitActivatePop(InterpState &S, CodePtr OpPC) {
1916 const Pointer &Ptr = S.Stk.pop<Pointer>();
1917 if (Ptr.canBeInitialized()) {
1918 Ptr.initialize();
1919 Ptr.activate();
1920 }
1921 return true;
1922}
1923
1924bool FinishInitGlobal(InterpState &S, CodePtr OpPC);
1925
1926inline bool Dump(InterpState &S, CodePtr OpPC) {
1927 S.Stk.dump();
1928 return true;
1929}
1930
1931inline bool CheckNull(InterpState &S, CodePtr OpPC) {
1932 const auto &Ptr = S.Stk.peek<Pointer>();
1933 if (Ptr.isZero()) {
1934 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
1935 DiagId: diag::note_constexpr_dereferencing_null);
1936 return S.noteUndefinedBehavior();
1937 }
1938 return true;
1939}
1940
1941inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1942 const Pointer &Ptr) {
1943 Pointer Base = Ptr.stripBaseCasts();
1944 const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(RD: Decl);
1945 S.Stk.push<Pointer>(Args: Base.atField(Off: VirtBase->Offset));
1946 return true;
1947}
1948
1949inline bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC,
1950 const RecordDecl *D) {
1951 assert(D);
1952 const Pointer &Ptr = S.Stk.pop<Pointer>();
1953 if (!CheckNull(S, OpPC, Ptr, CSK: CSK_Base))
1954 return false;
1955 return VirtBaseHelper(S, OpPC, Decl: D, Ptr);
1956}
1957
1958inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
1959 const RecordDecl *D) {
1960 assert(D);
1961 if (S.checkingPotentialConstantExpression())
1962 return false;
1963 if (!CheckThis(S, OpPC))
1964 return false;
1965 const Pointer &This = S.Current->getThis();
1966 return VirtBaseHelper(S, OpPC, Decl: D, Ptr: This);
1967}
1968
1969//===----------------------------------------------------------------------===//
1970// Load, Store, Init
1971//===----------------------------------------------------------------------===//
1972
1973template <PrimType Name, class T = typename PrimConv<Name>::T>
1974bool Load(InterpState &S, CodePtr OpPC) {
1975 const Pointer &Ptr = S.Stk.peek<Pointer>();
1976 if (!CheckLoad(S, OpPC, Ptr))
1977 return false;
1978 if (!Ptr.isBlockPointer())
1979 return false;
1980 if (!Ptr.canDeref(T: Name))
1981 return false;
1982 S.Stk.push<T>(Ptr.deref<T>());
1983 return true;
1984}
1985
1986template <PrimType Name, class T = typename PrimConv<Name>::T>
1987bool LoadPop(InterpState &S, CodePtr OpPC) {
1988 const Pointer &Ptr = S.Stk.pop<Pointer>();
1989 if (!CheckLoad(S, OpPC, Ptr))
1990 return false;
1991 if (!Ptr.isBlockPointer())
1992 return false;
1993 if (!Ptr.canDeref(T: Name))
1994 return false;
1995 S.Stk.push<T>(Ptr.deref<T>());
1996 return true;
1997}
1998
1999template <PrimType Name, class T = typename PrimConv<Name>::T>
2000bool Store(InterpState &S, CodePtr OpPC) {
2001 const T &Value = S.Stk.pop<T>();
2002 const Pointer &Ptr = S.Stk.peek<Pointer>();
2003 if (!CheckStore(S, OpPC, Ptr))
2004 return false;
2005 if (Ptr.canBeInitialized())
2006 Ptr.initialize();
2007 Ptr.deref<T>() = Value;
2008 return true;
2009}
2010
2011template <PrimType Name, class T = typename PrimConv<Name>::T>
2012bool StorePop(InterpState &S, CodePtr OpPC) {
2013 const T &Value = S.Stk.pop<T>();
2014 const Pointer &Ptr = S.Stk.pop<Pointer>();
2015 if (!CheckStore(S, OpPC, Ptr))
2016 return false;
2017 if (Ptr.canBeInitialized())
2018 Ptr.initialize();
2019 Ptr.deref<T>() = Value;
2020 return true;
2021}
2022
2023static inline bool Activate(InterpState &S, CodePtr OpPC) {
2024 const Pointer &Ptr = S.Stk.peek<Pointer>();
2025 if (Ptr.canBeInitialized())
2026 Ptr.activate();
2027 return true;
2028}
2029
2030static inline bool ActivateThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
2031 if (S.checkingPotentialConstantExpression())
2032 return false;
2033 if (!S.Current->hasThisPointer())
2034 return false;
2035
2036 const Pointer &Ptr = S.Current->getThis();
2037 assert(Ptr.atField(I).canBeInitialized());
2038 Ptr.atField(Off: I).activate();
2039 return true;
2040}
2041
2042template <PrimType Name, class T = typename PrimConv<Name>::T>
2043bool StoreActivate(InterpState &S, CodePtr OpPC) {
2044 const T &Value = S.Stk.pop<T>();
2045 const Pointer &Ptr = S.Stk.peek<Pointer>();
2046
2047 if (!CheckStore(S, OpPC, Ptr, /*WillBeActivated=*/WillBeActivated: true))
2048 return false;
2049 if (Ptr.canBeInitialized()) {
2050 Ptr.initialize();
2051 Ptr.activate();
2052 }
2053 Ptr.deref<T>() = Value;
2054 return true;
2055}
2056
2057template <PrimType Name, class T = typename PrimConv<Name>::T>
2058bool StoreActivatePop(InterpState &S, CodePtr OpPC) {
2059 const T &Value = S.Stk.pop<T>();
2060 const Pointer &Ptr = S.Stk.pop<Pointer>();
2061
2062 if (!CheckStore(S, OpPC, Ptr, /*WillBeActivated=*/WillBeActivated: true))
2063 return false;
2064 if (Ptr.canBeInitialized()) {
2065 Ptr.initialize();
2066 Ptr.activate();
2067 }
2068 Ptr.deref<T>() = Value;
2069 return true;
2070}
2071
2072template <PrimType Name, class T = typename PrimConv<Name>::T>
2073bool StoreBitField(InterpState &S, CodePtr OpPC) {
2074 const T &Value = S.Stk.pop<T>();
2075 const Pointer &Ptr = S.Stk.peek<Pointer>();
2076
2077 if (!CheckStore(S, OpPC, Ptr))
2078 return false;
2079 if (Ptr.canBeInitialized())
2080 Ptr.initialize();
2081 if (const auto *FD = Ptr.getField())
2082 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());
2083 else
2084 Ptr.deref<T>() = Value;
2085 return true;
2086}
2087
2088template <PrimType Name, class T = typename PrimConv<Name>::T>
2089bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
2090 const T &Value = S.Stk.pop<T>();
2091 const Pointer &Ptr = S.Stk.pop<Pointer>();
2092 if (!CheckStore(S, OpPC, Ptr))
2093 return false;
2094 if (Ptr.canBeInitialized())
2095 Ptr.initialize();
2096 if (const auto *FD = Ptr.getField())
2097 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());
2098 else
2099 Ptr.deref<T>() = Value;
2100 return true;
2101}
2102
2103template <PrimType Name, class T = typename PrimConv<Name>::T>
2104bool StoreBitFieldActivate(InterpState &S, CodePtr OpPC) {
2105 const T &Value = S.Stk.pop<T>();
2106 const Pointer &Ptr = S.Stk.peek<Pointer>();
2107
2108 if (!CheckStore(S, OpPC, Ptr, /*WillBeActivated=*/WillBeActivated: true))
2109 return false;
2110 if (Ptr.canBeInitialized()) {
2111 Ptr.initialize();
2112 Ptr.activate();
2113 }
2114 if (const auto *FD = Ptr.getField())
2115 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());
2116 else
2117 Ptr.deref<T>() = Value;
2118 return true;
2119}
2120
2121template <PrimType Name, class T = typename PrimConv<Name>::T>
2122bool StoreBitFieldActivatePop(InterpState &S, CodePtr OpPC) {
2123 const T &Value = S.Stk.pop<T>();
2124 const Pointer &Ptr = S.Stk.pop<Pointer>();
2125
2126 if (!CheckStore(S, OpPC, Ptr, /*WillBeActivated=*/WillBeActivated: true))
2127 return false;
2128 if (Ptr.canBeInitialized()) {
2129 Ptr.initialize();
2130 Ptr.activate();
2131 }
2132 if (const auto *FD = Ptr.getField())
2133 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());
2134 else
2135 Ptr.deref<T>() = Value;
2136 return true;
2137}
2138
2139template <PrimType Name, class T = typename PrimConv<Name>::T>
2140bool Init(InterpState &S, CodePtr OpPC) {
2141 const T &Value = S.Stk.pop<T>();
2142 const Pointer &Ptr = S.Stk.peek<Pointer>();
2143 if (!CheckInit(S, OpPC, Ptr))
2144 return false;
2145 Ptr.initialize();
2146 new (&Ptr.deref<T>()) T(Value);
2147 return true;
2148}
2149
2150template <PrimType Name, class T = typename PrimConv<Name>::T>
2151bool InitPop(InterpState &S, CodePtr OpPC) {
2152 const T &Value = S.Stk.pop<T>();
2153 const Pointer &Ptr = S.Stk.pop<Pointer>();
2154 if (!CheckInit(S, OpPC, Ptr))
2155 return false;
2156 Ptr.initialize();
2157 new (&Ptr.deref<T>()) T(Value);
2158 return true;
2159}
2160
2161/// 1) Pops the value from the stack
2162/// 2) Peeks a pointer and gets its index \Idx
2163/// 3) Sets the value on the pointer, leaving the pointer on the stack.
2164template <PrimType Name, class T = typename PrimConv<Name>::T>
2165bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
2166 const T &Value = S.Stk.pop<T>();
2167 const Pointer &Ptr = S.Stk.peek<Pointer>();
2168
2169 const Descriptor *Desc = Ptr.getFieldDesc();
2170 if (Desc->isUnknownSizeArray())
2171 return false;
2172
2173 // In the unlikely event that we're initializing the first item of
2174 // a non-array, skip the atIndex().
2175 if (Idx == 0 && !Desc->isArray()) {
2176 Ptr.initialize();
2177 new (&Ptr.deref<T>()) T(Value);
2178 return true;
2179 }
2180
2181 if (!CheckLive(S, OpPC, Ptr, AK: AK_Assign))
2182 return false;
2183 if (Idx >= Desc->getNumElems()) {
2184 // CheckRange.
2185 if (S.getLangOpts().CPlusPlus) {
2186 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
2187 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_access_past_end)
2188 << AK_Assign << S.Current->getRange(PC: OpPC);
2189 }
2190 return false;
2191 }
2192 Ptr.initializeElement(Index: Idx);
2193 new (&Ptr.elem<T>(Idx)) T(Value);
2194 return true;
2195}
2196
2197/// The same as InitElem, but pops the pointer as well.
2198template <PrimType Name, class T = typename PrimConv<Name>::T>
2199bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
2200 const T &Value = S.Stk.pop<T>();
2201 const Pointer &Ptr = S.Stk.pop<Pointer>();
2202
2203 const Descriptor *Desc = Ptr.getFieldDesc();
2204 if (Desc->isUnknownSizeArray())
2205 return false;
2206
2207 // In the unlikely event that we're initializing the first item of
2208 // a non-array, skip the atIndex().
2209 if (Idx == 0 && !Desc->isArray()) {
2210 Ptr.initialize();
2211 new (&Ptr.deref<T>()) T(Value);
2212 return true;
2213 }
2214
2215 if (!CheckLive(S, OpPC, Ptr, AK: AK_Assign))
2216 return false;
2217 if (Idx >= Desc->getNumElems()) {
2218 // CheckRange.
2219 if (S.getLangOpts().CPlusPlus) {
2220 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
2221 S.FFDiag(SI: Loc, DiagId: diag::note_constexpr_access_past_end)
2222 << AK_Assign << S.Current->getRange(PC: OpPC);
2223 }
2224 return false;
2225 }
2226 Ptr.initializeElement(Index: Idx);
2227 new (&Ptr.elem<T>(Idx)) T(Value);
2228 return true;
2229}
2230
2231inline bool Memcpy(InterpState &S, CodePtr OpPC) {
2232 const Pointer &Src = S.Stk.pop<Pointer>();
2233 Pointer &Dest = S.Stk.peek<Pointer>();
2234
2235 if (!CheckLoad(S, OpPC, Ptr: Src))
2236 return false;
2237
2238 return DoMemcpy(S, OpPC, Src, Dest);
2239}
2240
2241inline bool ToMemberPtr(InterpState &S, CodePtr OpPC) {
2242 const auto &Member = S.Stk.pop<MemberPointer>();
2243 const auto &Base = S.Stk.pop<Pointer>();
2244
2245 S.Stk.push<MemberPointer>(Args: Member.takeInstance(Instance: Base));
2246 return true;
2247}
2248
2249inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) {
2250 const auto &MP = S.Stk.pop<MemberPointer>();
2251
2252 if (std::optional<Pointer> Ptr = MP.toPointer(Ctx: S.Ctx)) {
2253 S.Stk.push<Pointer>(Args&: *Ptr);
2254 return true;
2255 }
2256 return Invalid(S, OpPC);
2257}
2258
2259//===----------------------------------------------------------------------===//
2260// AddOffset, SubOffset
2261//===----------------------------------------------------------------------===//
2262
2263template <class T, ArithOp Op>
2264std::optional<Pointer> OffsetHelper(InterpState &S, CodePtr OpPC,
2265 const T &Offset, const Pointer &Ptr,
2266 bool IsPointerArith = false) {
2267 // A zero offset does not change the pointer.
2268 if (Offset.isZero())
2269 return Ptr;
2270
2271 if (IsPointerArith && !CheckNull(S, OpPC, Ptr, CSK: CSK_ArrayIndex)) {
2272 // The CheckNull will have emitted a note already, but we only
2273 // abort in C++, since this is fine in C.
2274 if (S.getLangOpts().CPlusPlus)
2275 return std::nullopt;
2276 }
2277
2278 // Arrays of unknown bounds cannot have pointers into them.
2279 if (!CheckArray(S, OpPC, Ptr))
2280 return std::nullopt;
2281
2282 // This is much simpler for integral pointers, so handle them first.
2283 if (Ptr.isIntegralPointer()) {
2284 uint64_t V = Ptr.getIntegerRepresentation();
2285 uint64_t O = static_cast<uint64_t>(Offset) * Ptr.elemSize();
2286 if constexpr (Op == ArithOp::Add)
2287 return Pointer(V + O, Ptr.asIntPointer().Desc);
2288 else
2289 return Pointer(V - O, Ptr.asIntPointer().Desc);
2290 } else if (Ptr.isFunctionPointer()) {
2291 uint64_t O = static_cast<uint64_t>(Offset);
2292 uint64_t N;
2293 if constexpr (Op == ArithOp::Add)
2294 N = Ptr.getByteOffset() + O;
2295 else
2296 N = Ptr.getByteOffset() - O;
2297
2298 if (N > 1)
2299 S.CCEDiag(SI: S.Current->getSource(PC: OpPC), DiagId: diag::note_constexpr_array_index)
2300 << N << /*non-array*/ true << 0;
2301 return Pointer(Ptr.asFunctionPointer().getFunction(), N);
2302 } else if (!Ptr.isBlockPointer()) {
2303 return std::nullopt;
2304 }
2305
2306 assert(Ptr.isBlockPointer());
2307
2308 uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());
2309 uint64_t Index;
2310 if (Ptr.isOnePastEnd())
2311 Index = MaxIndex;
2312 else
2313 Index = Ptr.getIndex();
2314
2315 bool Invalid = false;
2316 // Helper to report an invalid offset, computed as APSInt.
2317 auto DiagInvalidOffset = [&]() -> void {
2318 const unsigned Bits = Offset.bitWidth();
2319 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false);
2320 APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true),
2321 /*IsUnsigned=*/false);
2322 APSInt NewIndex =
2323 (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
2324 S.CCEDiag(SI: S.Current->getSource(PC: OpPC), DiagId: diag::note_constexpr_array_index)
2325 << NewIndex << /*array*/ static_cast<int>(!Ptr.inArray()) << MaxIndex;
2326 Invalid = true;
2327 };
2328
2329 if (Ptr.isBlockPointer()) {
2330 uint64_t IOffset = static_cast<uint64_t>(Offset);
2331 uint64_t MaxOffset = MaxIndex - Index;
2332
2333 if constexpr (Op == ArithOp::Add) {
2334 // If the new offset would be negative, bail out.
2335 if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
2336 DiagInvalidOffset();
2337
2338 // If the new offset would be out of bounds, bail out.
2339 if (Offset.isPositive() && IOffset > MaxOffset)
2340 DiagInvalidOffset();
2341 } else {
2342 // If the new offset would be negative, bail out.
2343 if (Offset.isPositive() && Index < IOffset)
2344 DiagInvalidOffset();
2345
2346 // If the new offset would be out of bounds, bail out.
2347 if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
2348 DiagInvalidOffset();
2349 }
2350 }
2351
2352 if (Invalid && (S.getLangOpts().CPlusPlus || Ptr.inArray()))
2353 return std::nullopt;
2354
2355 // Offset is valid - compute it on unsigned.
2356 int64_t WideIndex = static_cast<int64_t>(Index);
2357 int64_t WideOffset = static_cast<int64_t>(Offset);
2358 int64_t Result;
2359 if constexpr (Op == ArithOp::Add)
2360 Result = WideIndex + WideOffset;
2361 else
2362 Result = WideIndex - WideOffset;
2363
2364 // When the pointer is one-past-end, going back to index 0 is the only
2365 // useful thing we can do. Any other index has been diagnosed before and
2366 // we don't get here.
2367 if (Result == 0 && Ptr.isOnePastEnd()) {
2368 if (Ptr.getFieldDesc()->isArray())
2369 return Ptr.atIndex(Idx: 0);
2370 return Pointer(Ptr.asBlockPointer().Pointee, Ptr.asBlockPointer().Base);
2371 }
2372
2373 return Ptr.atIndex(Idx: static_cast<uint64_t>(Result));
2374}
2375
2376template <PrimType Name, class T = typename PrimConv<Name>::T>
2377bool AddOffset(InterpState &S, CodePtr OpPC) {
2378 const T &Offset = S.Stk.pop<T>();
2379 const Pointer &Ptr = S.Stk.pop<Pointer>().expand();
2380
2381 if (std::optional<Pointer> Result = OffsetHelper<T, ArithOp::Add>(
2382 S, OpPC, Offset, Ptr, /*IsPointerArith=*/true)) {
2383 S.Stk.push<Pointer>(Args: Result->narrow());
2384 return true;
2385 }
2386 return false;
2387}
2388
2389template <PrimType Name, class T = typename PrimConv<Name>::T>
2390bool SubOffset(InterpState &S, CodePtr OpPC) {
2391 const T &Offset = S.Stk.pop<T>();
2392 const Pointer &Ptr = S.Stk.pop<Pointer>().expand();
2393
2394 if (std::optional<Pointer> Result = OffsetHelper<T, ArithOp::Sub>(
2395 S, OpPC, Offset, Ptr, /*IsPointerArith=*/true)) {
2396 S.Stk.push<Pointer>(Args: Result->narrow());
2397 return true;
2398 }
2399 return false;
2400}
2401
2402template <ArithOp Op>
2403static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
2404 const Pointer &Ptr) {
2405 if (Ptr.isDummy())
2406 return false;
2407
2408 using OneT = Integral<8, false>;
2409
2410 const Pointer &P = Ptr.deref<Pointer>();
2411 if (!CheckNull(S, OpPC, Ptr: P, CSK: CSK_ArrayIndex))
2412 return false;
2413
2414 // Get the current value on the stack.
2415 S.Stk.push<Pointer>(Args: P);
2416
2417 // Now the current Ptr again and a constant 1.
2418 OneT One = OneT::from(Value: 1);
2419 if (std::optional<Pointer> Result =
2420 OffsetHelper<OneT, Op>(S, OpPC, One, P, /*IsPointerArith=*/true)) {
2421 // Store the new value.
2422 Ptr.deref<Pointer>() = Result->narrow();
2423 return true;
2424 }
2425 return false;
2426}
2427
2428static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
2429 const Pointer &Ptr = S.Stk.pop<Pointer>();
2430
2431 if (!Ptr.isInitialized())
2432 return DiagnoseUninitialized(S, OpPC, Ptr, AK: AK_Increment);
2433
2434 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
2435}
2436
2437static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
2438 const Pointer &Ptr = S.Stk.pop<Pointer>();
2439
2440 if (!Ptr.isInitialized())
2441 return DiagnoseUninitialized(S, OpPC, Ptr, AK: AK_Decrement);
2442
2443 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
2444}
2445
2446/// 1) Pops a Pointer from the stack.
2447/// 2) Pops another Pointer from the stack.
2448/// 3) Pushes the difference of the indices of the two pointers on the stack.
2449template <PrimType Name, class T = typename PrimConv<Name>::T>
2450inline bool SubPtr(InterpState &S, CodePtr OpPC, bool ElemSizeIsZero) {
2451 const Pointer &LHS = S.Stk.pop<Pointer>().expand();
2452 const Pointer &RHS = S.Stk.pop<Pointer>().expand();
2453
2454 if (!Pointer::hasSameBase(A: LHS, B: RHS) && S.getLangOpts().CPlusPlus) {
2455 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
2456 DiagId: diag::note_constexpr_pointer_arith_unspecified)
2457 << LHS.toDiagnosticString(Ctx: S.getASTContext())
2458 << RHS.toDiagnosticString(Ctx: S.getASTContext());
2459 return false;
2460 }
2461
2462 if (ElemSizeIsZero) {
2463 QualType PtrT = LHS.getType();
2464 while (auto *AT = dyn_cast<ArrayType>(Val&: PtrT))
2465 PtrT = AT->getElementType();
2466
2467 QualType ArrayTy = S.getASTContext().getConstantArrayType(
2468 EltTy: PtrT, ArySize: APInt::getZero(numBits: 1), SizeExpr: nullptr, ASM: ArraySizeModifier::Normal, IndexTypeQuals: 0);
2469 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
2470 DiagId: diag::note_constexpr_pointer_subtraction_zero_size)
2471 << ArrayTy;
2472
2473 return false;
2474 }
2475
2476 if (LHS == RHS) {
2477 S.Stk.push<T>();
2478 return true;
2479 }
2480
2481 int64_t A64 =
2482 LHS.isBlockPointer()
2483 ? (LHS.isElementPastEnd() ? LHS.getNumElems() : LHS.getIndex())
2484 : LHS.getIntegerRepresentation();
2485
2486 int64_t B64 =
2487 RHS.isBlockPointer()
2488 ? (RHS.isElementPastEnd() ? RHS.getNumElems() : RHS.getIndex())
2489 : RHS.getIntegerRepresentation();
2490
2491 int64_t R64 = A64 - B64;
2492 if (static_cast<int64_t>(T::from(R64)) != R64)
2493 return handleOverflow(S, OpPC, SrcValue: R64);
2494
2495 S.Stk.push<T>(T::from(R64));
2496 return true;
2497}
2498
2499inline bool InitScope(InterpState &S, CodePtr OpPC, uint32_t I) {
2500 S.Current->initScope(Idx: I);
2501 return true;
2502}
2503
2504inline bool EnableLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
2505 assert(!S.Current->isLocalEnabled(I));
2506 S.Current->enableLocal(Idx: I);
2507 return true;
2508}
2509
2510inline bool GetLocalEnabled(InterpState &S, CodePtr OpPC, uint32_t I) {
2511 assert(S.Current);
2512 S.Stk.push<bool>(Args: S.Current->isLocalEnabled(Idx: I));
2513 return true;
2514}
2515
2516//===----------------------------------------------------------------------===//
2517// Cast, CastFP
2518//===----------------------------------------------------------------------===//
2519
2520template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
2521 using T = typename PrimConv<TIn>::T;
2522 using U = typename PrimConv<TOut>::T;
2523 S.Stk.push<U>(U::from(S.Stk.pop<T>()));
2524 return true;
2525}
2526
2527/// 1) Pops a Floating from the stack.
2528/// 2) Pushes a new floating on the stack that uses the given semantics.
2529inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
2530 llvm::RoundingMode RM) {
2531 Floating F = S.Stk.pop<Floating>();
2532 Floating Result = S.allocFloat(Sem: *Sem);
2533 F.toSemantics(Sem, RM, Result: &Result);
2534 S.Stk.push<Floating>(Args&: Result);
2535 return true;
2536}
2537
2538inline bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS) {
2539 FixedPointSemantics TargetSemantics =
2540 FixedPointSemantics::getFromOpaqueInt(FPS);
2541 const auto &Source = S.Stk.pop<FixedPoint>();
2542
2543 bool Overflow;
2544 FixedPoint Result = Source.toSemantics(Sem: TargetSemantics, Overflow: &Overflow);
2545
2546 if (Overflow && !handleFixedPointOverflow(S, OpPC, FP: Result))
2547 return false;
2548
2549 S.Stk.push<FixedPoint>(Args&: Result);
2550 return true;
2551}
2552
2553/// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
2554/// to know what bitwidth the result should be.
2555template <PrimType Name, class T = typename PrimConv<Name>::T>
2556bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2557 auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
2558 // Copy data.
2559 {
2560 APInt Source = S.Stk.pop<T>().toAPSInt().extOrTrunc(BitWidth);
2561 Result.copy(V: Source);
2562 }
2563 S.Stk.push<IntegralAP<false>>(Args&: Result);
2564 return true;
2565}
2566
2567template <PrimType Name, class T = typename PrimConv<Name>::T>
2568bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2569 auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
2570 // Copy data.
2571 {
2572 APInt Source = S.Stk.pop<T>().toAPSInt().extOrTrunc(BitWidth);
2573 Result.copy(V: Source);
2574 }
2575 S.Stk.push<IntegralAP<true>>(Args&: Result);
2576 return true;
2577}
2578
2579template <PrimType Name, class T = typename PrimConv<Name>::T>
2580bool CastIntegralFloating(InterpState &S, CodePtr OpPC,
2581 const llvm::fltSemantics *Sem, uint32_t FPOI) {
2582 const T &From = S.Stk.pop<T>();
2583 APSInt FromAP = From.toAPSInt();
2584
2585 FPOptions FPO = FPOptions::getFromOpaqueInt(Value: FPOI);
2586 Floating Result = S.allocFloat(Sem: *Sem);
2587 auto Status =
2588 Floating::fromIntegral(Val: FromAP, Sem: *Sem, RM: getRoundingMode(FPO), Result: &Result);
2589 S.Stk.push<Floating>(Args&: Result);
2590
2591 return CheckFloatResult(S, OpPC, Result, Status, FPO);
2592}
2593
2594template <PrimType Name, class T = typename PrimConv<Name>::T>
2595bool CastFloatingIntegral(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
2596 const Floating &F = S.Stk.pop<Floating>();
2597
2598 if constexpr (std::is_same_v<T, Boolean>) {
2599 S.Stk.push<T>(T(F.isNonZero()));
2600 return true;
2601 } else {
2602 APSInt Result(std::max(8u, T::bitWidth()),
2603 /*IsUnsigned=*/!T::isSigned());
2604 auto Status = F.convertToInteger(Result);
2605
2606 // Float-to-Integral overflow check.
2607 if ((Status & APFloat::opStatus::opInvalidOp)) {
2608 const Expr *E = S.Current->getExpr(PC: OpPC);
2609 QualType Type = E->getType();
2610
2611 S.CCEDiag(E, DiagId: diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2612 if (S.noteUndefinedBehavior()) {
2613 S.Stk.push<T>(T(Result));
2614 return true;
2615 }
2616 return false;
2617 }
2618
2619 FPOptions FPO = FPOptions::getFromOpaqueInt(Value: FPOI);
2620 S.Stk.push<T>(T(Result));
2621 return CheckFloatResult(S, OpPC, Result: F, Status, FPO);
2622 }
2623}
2624
2625static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
2626 uint32_t BitWidth, uint32_t FPOI) {
2627 const Floating &F = S.Stk.pop<Floating>();
2628
2629 APSInt Result(BitWidth, /*IsUnsigned=*/true);
2630 auto Status = F.convertToInteger(Result);
2631
2632 // Float-to-Integral overflow check.
2633 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite() &&
2634 !handleOverflow(S, OpPC, SrcValue: F.getAPFloat()))
2635 return false;
2636
2637 FPOptions FPO = FPOptions::getFromOpaqueInt(Value: FPOI);
2638
2639 auto ResultAP = S.allocAP<IntegralAP<false>>(BitWidth);
2640 ResultAP.copy(V: Result);
2641
2642 S.Stk.push<IntegralAP<false>>(Args&: ResultAP);
2643
2644 return CheckFloatResult(S, OpPC, Result: F, Status, FPO);
2645}
2646
2647static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
2648 uint32_t BitWidth, uint32_t FPOI) {
2649 const Floating &F = S.Stk.pop<Floating>();
2650
2651 APSInt Result(BitWidth, /*IsUnsigned=*/false);
2652 auto Status = F.convertToInteger(Result);
2653
2654 // Float-to-Integral overflow check.
2655 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite() &&
2656 !handleOverflow(S, OpPC, SrcValue: F.getAPFloat()))
2657 return false;
2658
2659 FPOptions FPO = FPOptions::getFromOpaqueInt(Value: FPOI);
2660
2661 auto ResultAP = S.allocAP<IntegralAP<true>>(BitWidth);
2662 ResultAP.copy(V: Result);
2663
2664 S.Stk.push<IntegralAP<true>>(Args&: ResultAP);
2665
2666 return CheckFloatResult(S, OpPC, Result: F, Status, FPO);
2667}
2668
2669bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,
2670 const Pointer &Ptr, unsigned BitWidth);
2671bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth);
2672bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth);
2673
2674template <PrimType Name, class T = typename PrimConv<Name>::T>
2675bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
2676 const Pointer &Ptr = S.Stk.pop<Pointer>();
2677
2678 if (!CheckPointerToIntegralCast(S, OpPC, Ptr, T::bitWidth()))
2679 return Invalid(S, OpPC);
2680
2681 S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
2682 return true;
2683}
2684
2685template <PrimType Name, class T = typename PrimConv<Name>::T>
2686static inline bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC,
2687 uint32_t FPS) {
2688 const T &Int = S.Stk.pop<T>();
2689
2690 FixedPointSemantics Sem = FixedPointSemantics::getFromOpaqueInt(FPS);
2691
2692 bool Overflow;
2693 FixedPoint Result = FixedPoint::from(Int.toAPSInt(), Sem, &Overflow);
2694
2695 if (Overflow && !handleFixedPointOverflow(S, OpPC, FP: Result))
2696 return false;
2697
2698 S.Stk.push<FixedPoint>(Args&: Result);
2699 return true;
2700}
2701
2702static inline bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC,
2703 uint32_t FPS) {
2704 const auto &Float = S.Stk.pop<Floating>();
2705
2706 FixedPointSemantics Sem = FixedPointSemantics::getFromOpaqueInt(FPS);
2707
2708 bool Overflow;
2709 FixedPoint Result = FixedPoint::from(I: Float.getAPFloat(), Sem, Overflow: &Overflow);
2710
2711 if (Overflow && !handleFixedPointOverflow(S, OpPC, FP: Result))
2712 return false;
2713
2714 S.Stk.push<FixedPoint>(Args&: Result);
2715 return true;
2716}
2717
2718static inline bool CastFixedPointFloating(InterpState &S, CodePtr OpPC,
2719 const llvm::fltSemantics *Sem) {
2720 const auto &Fixed = S.Stk.pop<FixedPoint>();
2721 Floating Result = S.allocFloat(Sem: *Sem);
2722 Result.copy(F: Fixed.toFloat(Sem));
2723 S.Stk.push<Floating>(Args&: Result);
2724 return true;
2725}
2726
2727template <PrimType Name, class T = typename PrimConv<Name>::T>
2728static inline bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC) {
2729 const auto &Fixed = S.Stk.pop<FixedPoint>();
2730
2731 bool Overflow;
2732 APSInt Int = Fixed.toInt(BitWidth: T::bitWidth(), Signed: T::isSigned(), Overflow: &Overflow);
2733
2734 if (Overflow && !handleOverflow(S, OpPC, SrcValue: Int))
2735 return false;
2736
2737 S.Stk.push<T>(Int);
2738 return true;
2739}
2740
2741static inline bool FnPtrCast(InterpState &S, CodePtr OpPC) {
2742 const SourceInfo &E = S.Current->getSource(PC: OpPC);
2743 S.CCEDiag(SI: E, DiagId: diag::note_constexpr_invalid_cast)
2744 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
2745 << S.getLangOpts().CPlusPlus << S.Current->getRange(PC: OpPC);
2746 return true;
2747}
2748
2749static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {
2750 const auto &Ptr = S.Stk.peek<Pointer>();
2751
2752 if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {
2753 bool HasValidResult = !Ptr.isZero();
2754
2755 if (HasValidResult) {
2756 if (S.getStdAllocatorCaller(Name: "allocate"))
2757 return true;
2758
2759 const auto &E = cast<CastExpr>(Val: S.Current->getExpr(PC: OpPC));
2760 if (S.getLangOpts().CPlusPlus26 &&
2761 S.getASTContext().hasSimilarType(T1: Ptr.getType(),
2762 T2: E->getType()->getPointeeType()))
2763 return true;
2764
2765 S.CCEDiag(E, DiagId: diag::note_constexpr_invalid_void_star_cast)
2766 << E->getSubExpr()->getType() << S.getLangOpts().CPlusPlus26
2767 << Ptr.getType().getCanonicalType() << E->getType()->getPointeeType();
2768 } else if (!S.getLangOpts().CPlusPlus26) {
2769 const SourceInfo &E = S.Current->getSource(PC: OpPC);
2770 S.CCEDiag(SI: E, DiagId: diag::note_constexpr_invalid_cast)
2771 << diag::ConstexprInvalidCastKind::CastFrom << "'void *'"
2772 << S.Current->getRange(PC: OpPC);
2773 }
2774 } else {
2775 const SourceInfo &E = S.Current->getSource(PC: OpPC);
2776 S.CCEDiag(SI: E, DiagId: diag::note_constexpr_invalid_cast)
2777 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
2778 << S.getLangOpts().CPlusPlus << S.Current->getRange(PC: OpPC);
2779 }
2780
2781 return true;
2782}
2783
2784//===----------------------------------------------------------------------===//
2785// Zero, Nullptr
2786//===----------------------------------------------------------------------===//
2787
2788template <PrimType Name, class T = typename PrimConv<Name>::T>
2789bool Zero(InterpState &S, CodePtr OpPC) {
2790 S.Stk.push<T>(T::zero());
2791 return true;
2792}
2793
2794static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2795 auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
2796 if (!Result.singleWord())
2797 std::memset(s: Result.Memory, c: 0, n: Result.numWords() * sizeof(uint64_t));
2798 S.Stk.push<IntegralAP<false>>(Args&: Result);
2799 return true;
2800}
2801
2802static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2803 auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
2804 if (!Result.singleWord())
2805 std::memset(s: Result.Memory, c: 0, n: Result.numWords() * sizeof(uint64_t));
2806 S.Stk.push<IntegralAP<true>>(Args&: Result);
2807 return true;
2808}
2809
2810template <PrimType Name, class T = typename PrimConv<Name>::T>
2811inline bool Null(InterpState &S, CodePtr OpPC, uint64_t Value,
2812 const Descriptor *Desc) {
2813 // FIXME(perf): This is a somewhat often-used function and the value of a
2814 // null pointer is almost always 0.
2815 S.Stk.push<T>(Value, Desc);
2816 return true;
2817}
2818
2819template <PrimType Name, class T = typename PrimConv<Name>::T>
2820inline bool IsNonNull(InterpState &S, CodePtr OpPC) {
2821 const auto &P = S.Stk.pop<T>();
2822 if (P.isWeak())
2823 return false;
2824 S.Stk.push<Boolean>(Boolean::from(!P.isZero()));
2825 return true;
2826}
2827
2828//===----------------------------------------------------------------------===//
2829// This, ImplicitThis
2830//===----------------------------------------------------------------------===//
2831
2832inline bool This(InterpState &S, CodePtr OpPC) {
2833 // Cannot read 'this' in this mode.
2834 if (S.checkingPotentialConstantExpression())
2835 return false;
2836 if (!CheckThis(S, OpPC))
2837 return false;
2838 const Pointer &This = S.Current->getThis();
2839
2840 // Ensure the This pointer has been cast to the correct base.
2841 if (!This.isDummy()) {
2842 assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
2843 if (!This.isTypeidPointer()) {
2844 [[maybe_unused]] const Record *R = This.getRecord();
2845 if (!R)
2846 R = This.narrow().getRecord();
2847 assert(R);
2848 assert(R->getDecl() ==
2849 cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())
2850 ->getParent());
2851 }
2852 }
2853
2854 S.Stk.push<Pointer>(Args: This);
2855 return true;
2856}
2857
2858inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
2859 assert(S.Current->getFunction()->hasRVO());
2860 if (S.checkingPotentialConstantExpression())
2861 return false;
2862 S.Stk.push<Pointer>(Args: S.Current->getRVOPtr());
2863 return true;
2864}
2865
2866//===----------------------------------------------------------------------===//
2867// Shr, Shl
2868//===----------------------------------------------------------------------===//
2869
2870template <class LT, class RT, ShiftDir Dir>
2871inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS,
2872 LT *Result) {
2873 static_assert(!needsAlloc<LT>());
2874 const unsigned Bits = LHS.bitWidth();
2875
2876 // OpenCL 6.3j: shift values are effectively % word size of LHS.
2877 if (S.getLangOpts().OpenCL)
2878 RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
2879 RHS.bitWidth(), &RHS);
2880
2881 if (RHS.isNegative()) {
2882 // During constant-folding, a negative shift is an opposite shift. Such a
2883 // shift is not a constant expression.
2884 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
2885 S.CCEDiag(SI: Loc, DiagId: diag::note_constexpr_negative_shift) << RHS.toAPSInt();
2886 if (!S.noteUndefinedBehavior())
2887 return false;
2888
2889 RHS = RHS.isMin() ? RT(APSInt::getMaxValue(numBits: RHS.bitWidth(), Unsigned: false)) : -RHS;
2890
2891 return DoShift<LT, RT,
2892 Dir == ShiftDir::Left ? ShiftDir::Right : ShiftDir::Left>(
2893 S, OpPC, LHS, RHS, Result);
2894 }
2895
2896 if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits))
2897 return false;
2898
2899 // Limit the shift amount to Bits - 1. If this happened,
2900 // it has already been diagnosed by CheckShift() above,
2901 // but we still need to handle it.
2902 // Note that we have to be extra careful here since we're doing the shift in
2903 // any case, but we need to adjust the shift amount or the way we do the shift
2904 // for the potential error cases.
2905 typename LT::AsUnsigned R;
2906 unsigned MaxShiftAmount = LHS.bitWidth() - 1;
2907 if constexpr (Dir == ShiftDir::Left) {
2908 if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
2909 ComparisonCategoryResult::Greater) {
2910 if (LHS.isNegative())
2911 R = LT::AsUnsigned::zero(LHS.bitWidth());
2912 else {
2913 RHS = RT::from(LHS.countLeadingZeros(), RHS.bitWidth());
2914 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2915 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2916 }
2917 } else if (LHS.isNegative()) {
2918 if (LHS.isMin()) {
2919 R = LT::AsUnsigned::zero(LHS.bitWidth());
2920 } else {
2921 // If the LHS is negative, perform the cast and invert the result.
2922 typename LT::AsUnsigned LHSU = LT::AsUnsigned::from(-LHS);
2923 LT::AsUnsigned::shiftLeft(LHSU, LT::AsUnsigned::from(RHS, Bits), Bits,
2924 &R);
2925 R = -R;
2926 }
2927 } else {
2928 // The good case, a simple left shift.
2929 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2930 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2931 }
2932 S.Stk.push<LT>(LT::from(R));
2933 return true;
2934 }
2935
2936 // Right shift.
2937 if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
2938 ComparisonCategoryResult::Greater) {
2939 R = LT::AsUnsigned::from(-1);
2940 } else {
2941 // Do the shift on potentially signed LT, then convert to unsigned type.
2942 LT A;
2943 LT::shiftRight(LHS, LT::from(RHS, Bits), Bits, &A);
2944 R = LT::AsUnsigned::from(A);
2945 }
2946
2947 S.Stk.push<LT>(LT::from(R));
2948 return true;
2949}
2950
2951/// A version of DoShift that works on IntegralAP.
2952template <class LT, class RT, ShiftDir Dir>
2953inline bool DoShiftAP(InterpState &S, CodePtr OpPC, const APSInt &LHS,
2954 APSInt RHS, LT *Result) {
2955 const unsigned Bits = LHS.getBitWidth();
2956
2957 // OpenCL 6.3j: shift values are effectively % word size of LHS.
2958 if (S.getLangOpts().OpenCL)
2959 RHS &=
2960 APSInt(llvm::APInt(RHS.getBitWidth(), static_cast<uint64_t>(Bits - 1)),
2961 RHS.isUnsigned());
2962
2963 if (RHS.isNegative()) {
2964 // During constant-folding, a negative shift is an opposite shift. Such a
2965 // shift is not a constant expression.
2966 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
2967 S.CCEDiag(SI: Loc, DiagId: diag::note_constexpr_negative_shift) << RHS; //.toAPSInt();
2968 if (!S.noteUndefinedBehavior())
2969 return false;
2970 return DoShiftAP<LT, RT,
2971 Dir == ShiftDir::Left ? ShiftDir::Right : ShiftDir::Left>(
2972 S, OpPC, LHS, -RHS, Result);
2973 }
2974
2975 if (!CheckShift<Dir>(S, OpPC, static_cast<LT>(LHS), static_cast<RT>(RHS),
2976 Bits))
2977 return false;
2978
2979 unsigned SA = (unsigned)RHS.getLimitedValue(Limit: Bits - 1);
2980 if constexpr (Dir == ShiftDir::Left) {
2981 if constexpr (needsAlloc<LT>())
2982 Result->copy(LHS << SA);
2983 else
2984 *Result = LT(LHS << SA);
2985 } else {
2986 if constexpr (needsAlloc<LT>())
2987 Result->copy(LHS >> SA);
2988 else
2989 *Result = LT(LHS >> SA);
2990 }
2991
2992 S.Stk.push<LT>(*Result);
2993 return true;
2994}
2995
2996template <PrimType NameL, PrimType NameR>
2997inline bool Shr(InterpState &S, CodePtr OpPC) {
2998 using LT = typename PrimConv<NameL>::T;
2999 using RT = typename PrimConv<NameR>::T;
3000 auto RHS = S.Stk.pop<RT>();
3001 auto LHS = S.Stk.pop<LT>();
3002
3003 if constexpr (needsAlloc<LT>() || needsAlloc<RT>()) {
3004 LT Result;
3005 if constexpr (needsAlloc<LT>())
3006 Result = S.allocAP<LT>(LHS.bitWidth());
3007 return DoShiftAP<LT, RT, ShiftDir::Right>(S, OpPC, LHS.toAPSInt(),
3008 RHS.toAPSInt(), &Result);
3009 } else {
3010 LT Result;
3011 return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS, &Result);
3012 }
3013}
3014
3015template <PrimType NameL, PrimType NameR>
3016inline bool Shl(InterpState &S, CodePtr OpPC) {
3017 using LT = typename PrimConv<NameL>::T;
3018 using RT = typename PrimConv<NameR>::T;
3019 auto RHS = S.Stk.pop<RT>();
3020 auto LHS = S.Stk.pop<LT>();
3021
3022 if constexpr (needsAlloc<LT>() || needsAlloc<RT>()) {
3023 LT Result;
3024 if constexpr (needsAlloc<LT>())
3025 Result = S.allocAP<LT>(LHS.bitWidth());
3026 return DoShiftAP<LT, RT, ShiftDir::Left>(S, OpPC, LHS.toAPSInt(),
3027 RHS.toAPSInt(), &Result);
3028 } else {
3029 LT Result;
3030 return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS, &Result);
3031 }
3032}
3033
3034static inline bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left) {
3035 const auto &RHS = S.Stk.pop<FixedPoint>();
3036 const auto &LHS = S.Stk.pop<FixedPoint>();
3037 llvm::FixedPointSemantics LHSSema = LHS.getSemantics();
3038
3039 unsigned ShiftBitWidth =
3040 LHSSema.getWidth() - (unsigned)LHSSema.hasUnsignedPadding() - 1;
3041
3042 // Embedded-C 4.1.6.2.2:
3043 // The right operand must be nonnegative and less than the total number
3044 // of (nonpadding) bits of the fixed-point operand ...
3045 if (RHS.isNegative()) {
3046 S.CCEDiag(Loc: S.Current->getLocation(PC: OpPC), DiagId: diag::note_constexpr_negative_shift)
3047 << RHS.toAPSInt();
3048 } else if (static_cast<unsigned>(RHS.toAPSInt().getLimitedValue(
3049 Limit: ShiftBitWidth)) != RHS.toAPSInt()) {
3050 const Expr *E = S.Current->getExpr(PC: OpPC);
3051 S.CCEDiag(E, DiagId: diag::note_constexpr_large_shift)
3052 << RHS.toAPSInt() << E->getType() << ShiftBitWidth;
3053 }
3054
3055 FixedPoint Result;
3056 if (Left) {
3057 if (FixedPoint::shiftLeft(A: LHS, B: RHS, OpBits: ShiftBitWidth, R: &Result) &&
3058 !handleFixedPointOverflow(S, OpPC, FP: Result))
3059 return false;
3060 } else {
3061 if (FixedPoint::shiftRight(A: LHS, B: RHS, OpBits: ShiftBitWidth, R: &Result) &&
3062 !handleFixedPointOverflow(S, OpPC, FP: Result))
3063 return false;
3064 }
3065
3066 S.Stk.push<FixedPoint>(Args&: Result);
3067 return true;
3068}
3069
3070//===----------------------------------------------------------------------===//
3071// NoRet
3072//===----------------------------------------------------------------------===//
3073
3074inline bool NoRet(InterpState &S, CodePtr OpPC) {
3075 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
3076 S.FFDiag(Loc: EndLoc, DiagId: diag::note_constexpr_no_return);
3077 return false;
3078}
3079
3080//===----------------------------------------------------------------------===//
3081// NarrowPtr, ExpandPtr
3082//===----------------------------------------------------------------------===//
3083
3084inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
3085 const Pointer &Ptr = S.Stk.pop<Pointer>();
3086 S.Stk.push<Pointer>(Args: Ptr.narrow());
3087 return true;
3088}
3089
3090inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
3091 const Pointer &Ptr = S.Stk.pop<Pointer>();
3092 if (Ptr.isBlockPointer())
3093 S.Stk.push<Pointer>(Args: Ptr.expand());
3094 else
3095 S.Stk.push<Pointer>(Args: Ptr);
3096 return true;
3097}
3098
3099// 1) Pops an integral value from the stack
3100// 2) Peeks a pointer
3101// 3) Pushes a new pointer that's a narrowed array
3102// element of the peeked pointer with the value
3103// from 1) added as offset.
3104//
3105// This leaves the original pointer on the stack and pushes a new one
3106// with the offset applied and narrowed.
3107template <PrimType Name, class T = typename PrimConv<Name>::T>
3108inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
3109 const T &Offset = S.Stk.pop<T>();
3110 const Pointer &Ptr = S.Stk.peek<Pointer>();
3111
3112 if (!Ptr.isZero() && !Offset.isZero()) {
3113 if (!CheckArray(S, OpPC, Ptr))
3114 return false;
3115 }
3116
3117 if (Offset.isZero()) {
3118 if (const Descriptor *Desc = Ptr.getFieldDesc();
3119 Desc && Desc->isArray() && Ptr.getIndex() == 0) {
3120 S.Stk.push<Pointer>(Args: Ptr.atIndex(Idx: 0).narrow());
3121 return true;
3122 }
3123 S.Stk.push<Pointer>(Args: Ptr.narrow());
3124 return true;
3125 }
3126
3127 assert(!Offset.isZero());
3128
3129 if (std::optional<Pointer> Result =
3130 OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) {
3131 S.Stk.push<Pointer>(Args: Result->narrow());
3132 return true;
3133 }
3134
3135 return false;
3136}
3137
3138template <PrimType Name, class T = typename PrimConv<Name>::T>
3139inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
3140 const T &Offset = S.Stk.pop<T>();
3141 const Pointer &Ptr = S.Stk.pop<Pointer>();
3142
3143 if (!Ptr.isZero() && !Offset.isZero()) {
3144 if (!CheckArray(S, OpPC, Ptr))
3145 return false;
3146 }
3147
3148 if (Offset.isZero()) {
3149 if (const Descriptor *Desc = Ptr.getFieldDesc();
3150 Desc && Desc->isArray() && Ptr.getIndex() == 0) {
3151 S.Stk.push<Pointer>(Args: Ptr.atIndex(Idx: 0).narrow());
3152 return true;
3153 }
3154 S.Stk.push<Pointer>(Args: Ptr.narrow());
3155 return true;
3156 }
3157
3158 assert(!Offset.isZero());
3159
3160 if (std::optional<Pointer> Result =
3161 OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) {
3162 S.Stk.push<Pointer>(Args: Result->narrow());
3163 return true;
3164 }
3165 return false;
3166}
3167
3168template <PrimType Name, class T = typename PrimConv<Name>::T>
3169inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {
3170 const Pointer &Ptr = S.Stk.peek<Pointer>();
3171
3172 if (!CheckLoad(S, OpPC, Ptr))
3173 return false;
3174
3175 assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
3176 S.Stk.push<T>(Ptr.elem<T>(Index));
3177 return true;
3178}
3179
3180template <PrimType Name, class T = typename PrimConv<Name>::T>
3181inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
3182 const Pointer &Ptr = S.Stk.pop<Pointer>();
3183
3184 if (!CheckLoad(S, OpPC, Ptr))
3185 return false;
3186
3187 assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
3188 S.Stk.push<T>(Ptr.elem<T>(Index));
3189 return true;
3190}
3191
3192template <PrimType Name, class T = typename PrimConv<Name>::T>
3193inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex,
3194 uint32_t DestIndex, uint32_t Size) {
3195 const auto &SrcPtr = S.Stk.pop<Pointer>();
3196 const auto &DestPtr = S.Stk.peek<Pointer>();
3197
3198 if (SrcPtr.isDummy() || DestPtr.isDummy())
3199 return false;
3200
3201 if (!SrcPtr.isBlockPointer() || !DestPtr.isBlockPointer())
3202 return false;
3203
3204 for (uint32_t I = 0; I != Size; ++I) {
3205 const Pointer &SP = SrcPtr.atIndex(Idx: SrcIndex + I);
3206
3207 if (!CheckLoad(S, OpPC, Ptr: SP))
3208 return false;
3209
3210 DestPtr.elem<T>(DestIndex + I) = SrcPtr.elem<T>(SrcIndex + I);
3211 DestPtr.initializeElement(Index: DestIndex + I);
3212 }
3213 return true;
3214}
3215
3216/// Just takes a pointer and checks if it's an incomplete
3217/// array type.
3218inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
3219 const Pointer &Ptr = S.Stk.pop<Pointer>();
3220
3221 if (Ptr.isZero()) {
3222 S.Stk.push<Pointer>(Args: Ptr);
3223 return true;
3224 }
3225
3226 if (!Ptr.isZeroSizeArray()) {
3227 if (!CheckRange(S, OpPC, Ptr, CSK: CSK_ArrayToPointer))
3228 return false;
3229 }
3230
3231 if (Ptr.isRoot() || !Ptr.isUnknownSizeArray()) {
3232 S.Stk.push<Pointer>(Args: Ptr.atIndex(Idx: 0).narrow());
3233 return true;
3234 }
3235
3236 const SourceInfo &E = S.Current->getSource(PC: OpPC);
3237 S.FFDiag(SI: E, DiagId: diag::note_constexpr_unsupported_unsized_array);
3238
3239 return false;
3240}
3241
3242inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
3243 assert(Func);
3244 S.Stk.push<Pointer>(Args&: Func);
3245 return true;
3246}
3247
3248template <PrimType Name, class T = typename PrimConv<Name>::T>
3249inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
3250 const T &IntVal = S.Stk.pop<T>();
3251
3252 S.CCEDiag(SI: S.Current->getSource(PC: OpPC), DiagId: diag::note_constexpr_invalid_cast)
3253 << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
3254 << S.getLangOpts().CPlusPlus;
3255
3256 S.Stk.push<Pointer>(Args: static_cast<uint64_t>(IntVal), Args&: Desc);
3257 return true;
3258}
3259
3260inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D) {
3261 S.Stk.push<MemberPointer>(Args&: D);
3262 return true;
3263}
3264
3265inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) {
3266 const auto &MP = S.Stk.pop<MemberPointer>();
3267
3268 if (!MP.isBaseCastPossible())
3269 return false;
3270
3271 S.Stk.push<Pointer>(Args: MP.getBase());
3272 return true;
3273}
3274
3275inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) {
3276 const auto &MP = S.Stk.pop<MemberPointer>();
3277
3278 const auto *FD = cast<FunctionDecl>(Val: MP.getDecl());
3279 const auto *Func = S.getContext().getOrCreateFunction(FuncDecl: FD);
3280
3281 S.Stk.push<Pointer>(Args&: Func);
3282 return true;
3283}
3284
3285/// Just emit a diagnostic. The expression that caused emission of this
3286/// op is not valid in a constant context.
3287
3288inline bool Unsupported(InterpState &S, CodePtr OpPC) {
3289 const SourceLocation &Loc = S.Current->getLocation(PC: OpPC);
3290 S.FFDiag(Loc, DiagId: diag::note_constexpr_stmt_expr_unsupported)
3291 << S.Current->getRange(PC: OpPC);
3292 return false;
3293}
3294
3295inline bool StartSpeculation(InterpState &S, CodePtr OpPC) {
3296 ++S.SpeculationDepth;
3297 if (S.SpeculationDepth != 1)
3298 return true;
3299
3300 assert(S.PrevDiags == nullptr);
3301 S.PrevDiags = S.getEvalStatus().Diag;
3302 S.getEvalStatus().Diag = nullptr;
3303 return true;
3304}
3305
3306inline bool EndSpeculation(InterpState &S, CodePtr OpPC) {
3307 assert(S.SpeculationDepth != 0);
3308 --S.SpeculationDepth;
3309 if (S.SpeculationDepth == 0) {
3310 S.getEvalStatus().Diag = S.PrevDiags;
3311 S.PrevDiags = nullptr;
3312 }
3313 return true;
3314}
3315
3316inline bool PushCC(InterpState &S, CodePtr OpPC, bool Value) {
3317 S.ConstantContextOverride = Value;
3318 return true;
3319}
3320inline bool PopCC(InterpState &S, CodePtr OpPC) {
3321 S.ConstantContextOverride = std::nullopt;
3322 return true;
3323}
3324
3325inline bool PushMSVCCE(InterpState &S, CodePtr OpPC) {
3326 // This is a per-frame property.
3327 ++S.Current->MSVCConstexprAllowed;
3328 return true;
3329}
3330
3331inline bool PopMSVCCE(InterpState &S, CodePtr OpPC) {
3332 assert(S.Current->MSVCConstexprAllowed >= 1);
3333 // This is a per-frame property.
3334 --S.Current->MSVCConstexprAllowed;
3335 return true;
3336}
3337
3338/// Do nothing and just abort execution.
3339inline bool Error(InterpState &S, CodePtr OpPC) { return false; }
3340
3341inline bool SideEffect(InterpState &S, CodePtr OpPC) {
3342 return S.noteSideEffect();
3343}
3344
3345/// Abort without a diagnostic if we're checking for a potential constant
3346/// expression and this is not the bottom frame. This is used in constructors to
3347/// allow evaluating their initializers but abort if we encounter anything in
3348/// their body.
3349inline bool CtorCheck(InterpState &S, CodePtr OpPC) {
3350 if (S.checkingPotentialConstantExpression() && !S.Current->isBottomFrame())
3351 return false;
3352 return true;
3353}
3354
3355inline bool InvalidStore(InterpState &S, CodePtr OpPC, const Type *T) {
3356 if (S.getLangOpts().CPlusPlus) {
3357 QualType VolatileType = QualType(T, 0).withVolatile();
3358 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
3359 DiagId: diag::note_constexpr_access_volatile_type)
3360 << AK_Assign << VolatileType;
3361 } else {
3362 S.FFDiag(SI: S.Current->getSource(PC: OpPC));
3363 }
3364 return false;
3365}
3366
3367inline bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC) {
3368 if (S.inConstantContext()) {
3369 const SourceRange &ArgRange = S.Current->getRange(PC: OpPC);
3370 const Expr *E = S.Current->getExpr(PC: OpPC);
3371 S.CCEDiag(E, DiagId: diag::note_constexpr_non_const_vectorelements) << ArgRange;
3372 }
3373 return false;
3374}
3375
3376inline bool CheckPseudoDtor(InterpState &S, CodePtr OpPC) {
3377 if (!S.getLangOpts().CPlusPlus20)
3378 S.CCEDiag(SI: S.Current->getSource(PC: OpPC),
3379 DiagId: diag::note_constexpr_pseudo_destructor);
3380 return true;
3381}
3382
3383inline bool Assume(InterpState &S, CodePtr OpPC) {
3384 const auto Val = S.Stk.pop<Boolean>();
3385
3386 if (Val)
3387 return true;
3388
3389 // Else, diagnose.
3390 const SourceLocation &Loc = S.Current->getLocation(PC: OpPC);
3391 S.CCEDiag(Loc, DiagId: diag::note_constexpr_assumption_failed);
3392 return false;
3393}
3394
3395template <PrimType Name, class T = typename PrimConv<Name>::T>
3396inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
3397 llvm::SmallVector<int64_t> ArrayIndices;
3398 for (size_t I = 0; I != E->getNumExpressions(); ++I)
3399 ArrayIndices.emplace_back(Args: S.Stk.pop<int64_t>());
3400
3401 int64_t Result;
3402 if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
3403 return false;
3404
3405 S.Stk.push<T>(T::from(Result));
3406
3407 return true;
3408}
3409
3410template <PrimType Name, class T = typename PrimConv<Name>::T>
3411inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
3412 const T &Arg = S.Stk.peek<T>();
3413 if (!Arg.isZero())
3414 return true;
3415
3416 const SourceLocation &Loc = S.Current->getLocation(PC: OpPC);
3417 S.CCEDiag(Loc, DiagId: diag::note_non_null_attribute_failed);
3418
3419 return false;
3420}
3421
3422void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,
3423 const APSInt &Value);
3424
3425template <PrimType Name, class T = typename PrimConv<Name>::T>
3426inline bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED) {
3427 assert(ED);
3428 assert(!ED->isFixed());
3429
3430 if (S.inConstantContext()) {
3431 const APSInt Val = S.Stk.peek<T>().toAPSInt();
3432 diagnoseEnumValue(S, OpPC, ED, Value: Val);
3433 }
3434 return true;
3435}
3436
3437/// OldPtr -> Integer -> NewPtr.
3438template <PrimType TIn, PrimType TOut>
3439inline bool DecayPtr(InterpState &S, CodePtr OpPC) {
3440 static_assert(isPtrType(T: TIn) && isPtrType(T: TOut));
3441 using FromT = typename PrimConv<TIn>::T;
3442 using ToT = typename PrimConv<TOut>::T;
3443
3444 const FromT &OldPtr = S.Stk.pop<FromT>();
3445
3446 if constexpr (std::is_same_v<FromT, FunctionPointer> &&
3447 std::is_same_v<ToT, Pointer>) {
3448 S.Stk.push<Pointer>(OldPtr.getFunction(), OldPtr.getOffset());
3449 return true;
3450 } else if constexpr (std::is_same_v<FromT, Pointer> &&
3451 std::is_same_v<ToT, FunctionPointer>) {
3452 if (OldPtr.isFunctionPointer()) {
3453 S.Stk.push<FunctionPointer>(OldPtr.asFunctionPointer().getFunction(),
3454 OldPtr.getByteOffset());
3455 return true;
3456 }
3457 }
3458
3459 S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
3460 return true;
3461}
3462
3463inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) {
3464 // An expression E is a core constant expression unless the evaluation of E
3465 // would evaluate one of the following: [C++23] - a control flow that passes
3466 // through a declaration of a variable with static or thread storage duration
3467 // unless that variable is usable in constant expressions.
3468 assert(VD->isLocalVarDecl() &&
3469 VD->isStaticLocal()); // Checked before emitting this.
3470
3471 if (VD == S.EvaluatingDecl)
3472 return true;
3473
3474 if (!VD->isUsableInConstantExpressions(C: S.getASTContext())) {
3475 S.CCEDiag(Loc: VD->getLocation(), DiagId: diag::note_constexpr_static_local)
3476 << (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD;
3477 return false;
3478 }
3479 return true;
3480}
3481
3482inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
3483 assert(Desc);
3484
3485 if (!CheckDynamicMemoryAllocation(S, OpPC))
3486 return false;
3487
3488 DynamicAllocator &Allocator = S.getAllocator();
3489 Block *B = Allocator.allocate(D: Desc, EvalID: S.Ctx.getEvalID(),
3490 AllocForm: DynamicAllocator::Form::NonArray);
3491 assert(B);
3492 S.Stk.push<Pointer>(Args&: B);
3493 return true;
3494}
3495
3496template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
3497inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,
3498 bool IsNoThrow) {
3499 if (!CheckDynamicMemoryAllocation(S, OpPC))
3500 return false;
3501
3502 SizeT NumElements = S.Stk.pop<SizeT>();
3503 if (!CheckArraySize(S, OpPC, &NumElements, primSize(Type: T), IsNoThrow)) {
3504 if (!IsNoThrow)
3505 return false;
3506
3507 // If this failed and is nothrow, just return a null ptr.
3508 S.Stk.push<Pointer>(Args: 0, Args: nullptr);
3509 return true;
3510 }
3511 if (NumElements.isNegative()) {
3512 if (!IsNoThrow) {
3513 S.FFDiag(SI: S.Current->getSource(PC: OpPC), DiagId: diag::note_constexpr_new_negative)
3514 << NumElements.toDiagnosticString(S.getASTContext());
3515 return false;
3516 }
3517 S.Stk.push<Pointer>(Args: 0, Args: nullptr);
3518 return true;
3519 }
3520
3521 if (!CheckArraySize(S, OpPC, NumElems: static_cast<uint64_t>(NumElements)))
3522 return false;
3523
3524 DynamicAllocator &Allocator = S.getAllocator();
3525 Block *B =
3526 Allocator.allocate(Source, T, NumElements: static_cast<size_t>(NumElements),
3527 EvalID: S.Ctx.getEvalID(), AllocForm: DynamicAllocator::Form::Array);
3528 assert(B);
3529 if (NumElements.isZero())
3530 S.Stk.push<Pointer>(Args&: B);
3531 else
3532 S.Stk.push<Pointer>(Args: Pointer(B).atIndex(Idx: 0));
3533 return true;
3534}
3535
3536template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
3537inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc,
3538 bool IsNoThrow) {
3539 if (!CheckDynamicMemoryAllocation(S, OpPC))
3540 return false;
3541
3542 if (!ElementDesc)
3543 return false;
3544
3545 SizeT NumElements = S.Stk.pop<SizeT>();
3546 if (!CheckArraySize(S, OpPC, &NumElements, ElementDesc->getSize(),
3547 IsNoThrow)) {
3548 if (!IsNoThrow)
3549 return false;
3550
3551 // If this failed and is nothrow, just return a null ptr.
3552 S.Stk.push<Pointer>(Args: 0, Args&: ElementDesc);
3553 return true;
3554 }
3555 assert(NumElements.isPositive());
3556
3557 if (!CheckArraySize(S, OpPC, NumElems: static_cast<uint64_t>(NumElements)))
3558 return false;
3559
3560 DynamicAllocator &Allocator = S.getAllocator();
3561 Block *B =
3562 Allocator.allocate(D: ElementDesc, NumElements: static_cast<size_t>(NumElements),
3563 EvalID: S.Ctx.getEvalID(), AllocForm: DynamicAllocator::Form::Array);
3564 assert(B);
3565 if (NumElements.isZero())
3566 S.Stk.push<Pointer>(Args&: B);
3567 else
3568 S.Stk.push<Pointer>(Args: Pointer(B).atIndex(Idx: 0));
3569
3570 return true;
3571}
3572
3573bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
3574 bool IsGlobalDelete);
3575
3576static inline bool IsConstantContext(InterpState &S, CodePtr OpPC) {
3577 S.Stk.push<Boolean>(Args: Boolean::from(Value: S.inConstantContext()));
3578 return true;
3579}
3580
3581static inline bool CheckAllocations(InterpState &S, CodePtr OpPC) {
3582 return S.maybeDiagnoseDanglingAllocations();
3583}
3584
3585/// Check if the initializer and storage types of a placement-new expression
3586/// match.
3587bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
3588 std::optional<uint64_t> ArraySize = std::nullopt);
3589
3590template <PrimType Name, class T = typename PrimConv<Name>::T>
3591bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E) {
3592 const auto &Size = S.Stk.pop<T>();
3593 return CheckNewTypeMismatch(S, OpPC, E, ArraySize: static_cast<uint64_t>(Size));
3594}
3595bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E);
3596
3597template <PrimType Name, class T = typename PrimConv<Name>::T>
3598inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
3599 uint32_t ResultBitWidth, const llvm::fltSemantics *Sem,
3600 const Type *TargetType) {
3601 const Pointer &FromPtr = S.Stk.pop<Pointer>();
3602
3603 if (!CheckLoad(S, OpPC, Ptr: FromPtr))
3604 return false;
3605
3606 if constexpr (std::is_same_v<T, Pointer>) {
3607 if (!TargetType->isNullPtrType()) {
3608 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
3609 DiagId: diag::note_constexpr_bit_cast_invalid_type)
3610 << /*IsToType=*/true << /*IsReference=*/false << 1 /*Pointer*/;
3611 return false;
3612 }
3613 // The only pointer type we can validly bitcast to is nullptr_t.
3614 S.Stk.push<Pointer>();
3615 return true;
3616 } else if constexpr (std::is_same_v<T, MemberPointer>) {
3617 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
3618 DiagId: diag::note_constexpr_bit_cast_invalid_type)
3619 << /*IsToType=*/true << /*IsReference=*/false << 2 /*MemberPointer*/;
3620 return false;
3621 } else {
3622
3623 size_t BuffSize = ResultBitWidth / 8;
3624 llvm::SmallVector<std::byte> Buff(BuffSize);
3625 bool HasIndeterminateBits = false;
3626
3627 Bits FullBitWidth(ResultBitWidth);
3628 Bits BitWidth = FullBitWidth;
3629
3630 if constexpr (std::is_same_v<T, Floating>) {
3631 assert(Sem);
3632 BitWidth = Bits(llvm::APFloatBase::getSizeInBits(Sem: *Sem));
3633 }
3634
3635 if (!DoBitCast(S, OpPC, Ptr: FromPtr, Buff: Buff.data(), BitWidth, FullBitWidth,
3636 HasIndeterminateBits))
3637 return false;
3638
3639 if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
3640 return false;
3641
3642 if constexpr (std::is_same_v<T, Floating>) {
3643 assert(Sem);
3644 Floating Result = S.allocFloat(Sem: *Sem);
3645 Floating::bitcastFromMemory(Buff: Buff.data(), Sem: *Sem, Result: &Result);
3646 S.Stk.push<Floating>(Args&: Result);
3647 } else if constexpr (needsAlloc<T>()) {
3648 T Result = S.allocAP<T>(ResultBitWidth);
3649 T::bitcastFromMemory(Buff.data(), ResultBitWidth, &Result);
3650 S.Stk.push<T>(Result);
3651 } else if constexpr (std::is_same_v<T, Boolean>) {
3652 // Only allow to cast single-byte integers to bool if they are either 0
3653 // or 1.
3654 assert(FullBitWidth.getQuantity() == 8);
3655 auto Val = static_cast<unsigned int>(Buff[0]);
3656 if (Val > 1) {
3657 S.FFDiag(SI: S.Current->getSource(PC: OpPC),
3658 DiagId: diag::note_constexpr_bit_cast_unrepresentable_value)
3659 << S.getASTContext().BoolTy << Val;
3660 return false;
3661 }
3662 S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
3663 } else {
3664 assert(!Sem);
3665 S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
3666 }
3667 return true;
3668 }
3669}
3670
3671inline bool BitCast(InterpState &S, CodePtr OpPC) {
3672 const Pointer &FromPtr = S.Stk.pop<Pointer>();
3673 Pointer &ToPtr = S.Stk.peek<Pointer>();
3674
3675 if (!CheckLoad(S, OpPC, Ptr: FromPtr))
3676 return false;
3677
3678 if (!DoBitCastPtr(S, OpPC, FromPtr, ToPtr))
3679 return false;
3680
3681 return true;
3682}
3683
3684/// Typeid support.
3685bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr,
3686 const Type *TypeInfoType);
3687bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType);
3688bool DiagTypeid(InterpState &S, CodePtr OpPC);
3689
3690inline bool CheckDestruction(InterpState &S, CodePtr OpPC) {
3691 const auto &Ptr = S.Stk.peek<Pointer>();
3692 return CheckDestructor(S, OpPC, Ptr);
3693}
3694
3695//===----------------------------------------------------------------------===//
3696// Read opcode arguments
3697//===----------------------------------------------------------------------===//
3698
3699template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
3700 if constexpr (std::is_pointer<T>::value) {
3701 uint32_t ID = OpPC.read<uint32_t>();
3702 return reinterpret_cast<T>(S.P.getNativePointer(Idx: ID));
3703 } else {
3704 return OpPC.read<T>();
3705 }
3706}
3707
3708template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
3709 auto &Semantics =
3710 llvm::APFloatBase::EnumToSemantics(S: Floating::deserializeSemantics(Buff: *OpPC));
3711
3712 auto F = S.allocFloat(Sem: Semantics);
3713 Floating::deserialize(Buff: *OpPC, Result: &F);
3714 OpPC += align(Size: F.bytesToSerialize());
3715 return F;
3716}
3717
3718template <>
3719inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
3720 CodePtr &OpPC) {
3721 uint32_t BitWidth = IntegralAP<false>::deserializeSize(Buff: *OpPC);
3722 auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
3723 assert(Result.bitWidth() == BitWidth);
3724
3725 IntegralAP<false>::deserialize(Buff: *OpPC, Result: &Result);
3726 OpPC += align(Size: Result.bytesToSerialize());
3727 return Result;
3728}
3729
3730template <>
3731inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
3732 CodePtr &OpPC) {
3733 uint32_t BitWidth = IntegralAP<true>::deserializeSize(Buff: *OpPC);
3734 auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
3735 assert(Result.bitWidth() == BitWidth);
3736
3737 IntegralAP<true>::deserialize(Buff: *OpPC, Result: &Result);
3738 OpPC += align(Size: Result.bytesToSerialize());
3739 return Result;
3740}
3741
3742template <>
3743inline FixedPoint ReadArg<FixedPoint>(InterpState &S, CodePtr &OpPC) {
3744 FixedPoint FP = FixedPoint::deserialize(Buff: *OpPC);
3745 OpPC += align(Size: FP.bytesToSerialize());
3746 return FP;
3747}
3748
3749} // namespace interp
3750} // namespace clang
3751
3752#endif
3753