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