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 "Boolean.h"
17#include "Floating.h"
18#include "Function.h"
19#include "FunctionPointer.h"
20#include "InterpFrame.h"
21#include "InterpStack.h"
22#include "InterpState.h"
23#include "Opcode.h"
24#include "PrimType.h"
25#include "Program.h"
26#include "State.h"
27#include "clang/AST/ASTContext.h"
28#include "clang/AST/ASTDiagnostic.h"
29#include "clang/AST/CXXInheritance.h"
30#include "clang/AST/Expr.h"
31#include "llvm/ADT/APFloat.h"
32#include "llvm/ADT/APSInt.h"
33#include "llvm/Support/Endian.h"
34#include <limits>
35#include <type_traits>
36
37namespace clang {
38namespace interp {
39
40using APSInt = llvm::APSInt;
41
42/// Convert a value to an APValue.
43template <typename T> bool ReturnValue(const T &V, APValue &R) {
44 R = V.toAPValue();
45 return true;
46}
47
48/// Checks if the variable has externally defined storage.
49bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
50
51/// Checks if the array is offsetable.
52bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
53
54/// Checks if a pointer is live and accessible.
55bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
56 AccessKinds AK);
57
58/// Checks if a pointer is a dummy pointer.
59bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
60
61/// Checks if a pointer is null.
62bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
63 CheckSubobjectKind CSK);
64
65/// Checks if a pointer is in range.
66bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
67 AccessKinds AK);
68
69/// Checks if a field from which a pointer is going to be derived is valid.
70bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
71 CheckSubobjectKind CSK);
72
73/// Checks if Ptr is a one-past-the-end pointer.
74bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
75 CheckSubobjectKind CSK);
76
77/// Checks if a pointer points to const storage.
78bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
79
80/// Checks if the Descriptor is of a constexpr or const global variable.
81bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc);
82
83/// Checks if a pointer points to a mutable field.
84bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
85
86/// Checks if a value can be loaded from a block.
87bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
88
89bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
90 AccessKinds AK);
91/// Check if a global variable is initialized.
92bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
93
94/// Checks if a value can be stored in a block.
95bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
96
97/// Checks if a method can be invoked on an object.
98bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
99
100/// Checks if a value can be initialized.
101bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
102
103/// Checks if a method can be called.
104bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
105
106/// Checks if calling the currently active function would exceed
107/// the allowed call depth.
108bool CheckCallDepth(InterpState &S, CodePtr OpPC);
109
110/// Checks the 'this' pointer.
111bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
112
113/// Checks if a method is pure virtual.
114bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
115
116/// Checks if all the arguments annotated as 'nonnull' are in fact not null.
117bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,
118 const CallExpr *CE, unsigned ArgSize);
119
120/// Sets the given integral value to the pointer, which is of
121/// a std::{weak,partial,strong}_ordering type.
122bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
123 const Pointer &Ptr, const APSInt &IntValue);
124
125/// Copy the contents of Src into Dest.
126bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest);
127
128/// Checks if the shift operation is legal.
129template <typename LT, typename RT>
130bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
131 unsigned Bits) {
132 if (RHS.isNegative()) {
133 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
134 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
135 return false;
136 }
137
138 // C++11 [expr.shift]p1: Shift width must be less than the bit width of
139 // the shifted type.
140 if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
141 const Expr *E = S.Current->getExpr(PC: OpPC);
142 const APSInt Val = RHS.toAPSInt();
143 QualType Ty = E->getType();
144 S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
145 return true; // We will do the shift anyway but fix up the shift amount.
146 }
147
148 if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
149 const Expr *E = S.Current->getExpr(PC: OpPC);
150 // C++11 [expr.shift]p2: A signed left shift must have a non-negative
151 // operand, and must not overflow the corresponding unsigned type.
152 if (LHS.isNegative())
153 S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
154 else if (LHS.toUnsigned().countLeadingZeros() < static_cast<unsigned>(RHS))
155 S.CCEDiag(E, diag::note_constexpr_lshift_discards);
156 }
157
158 // C++2a [expr.shift]p2: [P0907R4]:
159 // E1 << E2 is the unique value congruent to
160 // E1 x 2^E2 module 2^N.
161 return true;
162}
163
164/// Checks if Div/Rem operation on LHS and RHS is valid.
165template <typename T>
166bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
167 if (RHS.isZero()) {
168 const auto *Op = cast<BinaryOperator>(Val: S.Current->getExpr(PC: OpPC));
169 S.FFDiag(Op, diag::note_expr_divide_by_zero)
170 << Op->getRHS()->getSourceRange();
171 if constexpr (!std::is_same_v<T, Floating>)
172 return false;
173 }
174
175 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
176 APSInt LHSInt = LHS.toAPSInt();
177 SmallString<32> Trunc;
178 (-LHSInt.extend(width: LHSInt.getBitWidth() + 1)).toString(Str&: Trunc, Radix: 10);
179 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
180 const Expr *E = S.Current->getExpr(PC: OpPC);
181 S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
182 return false;
183 }
184 return true;
185}
186
187/// Checks if the result of a floating-point operation is valid
188/// in the current context.
189bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
190 APFloat::opStatus Status);
191
192/// Checks why the given DeclRefExpr is invalid.
193bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);
194
195/// Interpreter entry point.
196bool Interpret(InterpState &S, APValue &Result);
197
198/// Interpret a builtin function.
199bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
200 const CallExpr *Call);
201
202/// Interpret an offsetof operation.
203bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
204 llvm::ArrayRef<int64_t> ArrayIndices, int64_t &Result);
205
206inline bool Invalid(InterpState &S, CodePtr OpPC);
207
208enum class ArithOp { Add, Sub };
209
210//===----------------------------------------------------------------------===//
211// Returning values
212//===----------------------------------------------------------------------===//
213
214void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC);
215
216template <PrimType Name, class T = typename PrimConv<Name>::T>
217bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
218 const T &Ret = S.Stk.pop<T>();
219
220 // Make sure returned pointers are live. We might be trying to return a
221 // pointer or reference to a local variable.
222 // Just return false, since a diagnostic has already been emitted in Sema.
223 if constexpr (std::is_same_v<T, Pointer>) {
224 // FIXME: We could be calling isLive() here, but the emitted diagnostics
225 // seem a little weird, at least if the returned expression is of
226 // pointer type.
227 // Null pointers are considered live here.
228 if (!Ret.isZero() && !Ret.isLive())
229 return false;
230 }
231
232 assert(S.Current);
233 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
234 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
235 cleanupAfterFunctionCall(S, OpPC: PC);
236
237 if (InterpFrame *Caller = S.Current->Caller) {
238 PC = S.Current->getRetPC();
239 delete S.Current;
240 S.Current = Caller;
241 S.Stk.push<T>(Ret);
242 } else {
243 delete S.Current;
244 S.Current = nullptr;
245 if (!ReturnValue<T>(Ret, Result))
246 return false;
247 }
248 return true;
249}
250
251inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
252 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
253
254 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
255 cleanupAfterFunctionCall(S, OpPC: PC);
256
257 if (InterpFrame *Caller = S.Current->Caller) {
258 PC = S.Current->getRetPC();
259 delete S.Current;
260 S.Current = Caller;
261 } else {
262 delete S.Current;
263 S.Current = nullptr;
264 }
265 return true;
266}
267
268//===----------------------------------------------------------------------===//
269// Add, Sub, Mul
270//===----------------------------------------------------------------------===//
271
272template <typename T, bool (*OpFW)(T, T, unsigned, T *),
273 template <typename U> class OpAP>
274bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
275 const T &RHS) {
276 // Fast path - add the numbers with fixed width.
277 T Result;
278 if (!OpFW(LHS, RHS, Bits, &Result)) {
279 S.Stk.push<T>(Result);
280 return true;
281 }
282
283 // If for some reason evaluation continues, use the truncated results.
284 S.Stk.push<T>(Result);
285
286 // Slow path - compute the result using another bit of precision.
287 APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
288
289 // Report undefined behaviour, stopping if required.
290 const Expr *E = S.Current->getExpr(PC: OpPC);
291 QualType Type = E->getType();
292 if (S.checkingForUndefinedBehavior()) {
293 SmallString<32> Trunc;
294 Value.trunc(width: Result.bitWidth())
295 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
296 /*UpperCase=*/true, /*InsertSeparators=*/true);
297 auto Loc = E->getExprLoc();
298 S.report(Loc, diag::warn_integer_constant_overflow)
299 << Trunc << Type << E->getSourceRange();
300 return true;
301 } else {
302 S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
303 if (!S.noteUndefinedBehavior()) {
304 S.Stk.pop<T>();
305 return false;
306 }
307 return true;
308 }
309}
310
311template <PrimType Name, class T = typename PrimConv<Name>::T>
312bool Add(InterpState &S, CodePtr OpPC) {
313 const T &RHS = S.Stk.pop<T>();
314 const T &LHS = S.Stk.pop<T>();
315 const unsigned Bits = RHS.bitWidth() + 1;
316 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
317}
318
319inline bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
320 const Floating &RHS = S.Stk.pop<Floating>();
321 const Floating &LHS = S.Stk.pop<Floating>();
322
323 Floating Result;
324 auto Status = Floating::add(A: LHS, B: RHS, RM, R: &Result);
325 S.Stk.push<Floating>(Args&: Result);
326 return CheckFloatResult(S, OpPC, Result, Status);
327}
328
329template <PrimType Name, class T = typename PrimConv<Name>::T>
330bool Sub(InterpState &S, CodePtr OpPC) {
331 const T &RHS = S.Stk.pop<T>();
332 const T &LHS = S.Stk.pop<T>();
333 const unsigned Bits = RHS.bitWidth() + 1;
334 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
335}
336
337inline bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
338 const Floating &RHS = S.Stk.pop<Floating>();
339 const Floating &LHS = S.Stk.pop<Floating>();
340
341 Floating Result;
342 auto Status = Floating::sub(A: LHS, B: RHS, RM, R: &Result);
343 S.Stk.push<Floating>(Args&: Result);
344 return CheckFloatResult(S, OpPC, Result, Status);
345}
346
347template <PrimType Name, class T = typename PrimConv<Name>::T>
348bool Mul(InterpState &S, CodePtr OpPC) {
349 const T &RHS = S.Stk.pop<T>();
350 const T &LHS = S.Stk.pop<T>();
351 const unsigned Bits = RHS.bitWidth() * 2;
352 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
353}
354
355inline bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
356 const Floating &RHS = S.Stk.pop<Floating>();
357 const Floating &LHS = S.Stk.pop<Floating>();
358
359 Floating Result;
360 auto Status = Floating::mul(A: LHS, B: RHS, RM, R: &Result);
361 S.Stk.push<Floating>(Args&: Result);
362 return CheckFloatResult(S, OpPC, Result, Status);
363}
364/// 1) Pops the RHS from the stack.
365/// 2) Pops the LHS from the stack.
366/// 3) Pushes 'LHS & RHS' on the stack
367template <PrimType Name, class T = typename PrimConv<Name>::T>
368bool BitAnd(InterpState &S, CodePtr OpPC) {
369 const T &RHS = S.Stk.pop<T>();
370 const T &LHS = S.Stk.pop<T>();
371
372 unsigned Bits = RHS.bitWidth();
373 T Result;
374 if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
375 S.Stk.push<T>(Result);
376 return true;
377 }
378 return false;
379}
380
381/// 1) Pops the RHS from the stack.
382/// 2) Pops the LHS from the stack.
383/// 3) Pushes 'LHS | RHS' on the stack
384template <PrimType Name, class T = typename PrimConv<Name>::T>
385bool BitOr(InterpState &S, CodePtr OpPC) {
386 const T &RHS = S.Stk.pop<T>();
387 const T &LHS = S.Stk.pop<T>();
388
389 unsigned Bits = RHS.bitWidth();
390 T Result;
391 if (!T::bitOr(LHS, RHS, Bits, &Result)) {
392 S.Stk.push<T>(Result);
393 return true;
394 }
395 return false;
396}
397
398/// 1) Pops the RHS from the stack.
399/// 2) Pops the LHS from the stack.
400/// 3) Pushes 'LHS ^ RHS' on the stack
401template <PrimType Name, class T = typename PrimConv<Name>::T>
402bool BitXor(InterpState &S, CodePtr OpPC) {
403 const T &RHS = S.Stk.pop<T>();
404 const T &LHS = S.Stk.pop<T>();
405
406 unsigned Bits = RHS.bitWidth();
407 T Result;
408 if (!T::bitXor(LHS, RHS, Bits, &Result)) {
409 S.Stk.push<T>(Result);
410 return true;
411 }
412 return false;
413}
414
415/// 1) Pops the RHS from the stack.
416/// 2) Pops the LHS from the stack.
417/// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
418template <PrimType Name, class T = typename PrimConv<Name>::T>
419bool Rem(InterpState &S, CodePtr OpPC) {
420 const T &RHS = S.Stk.pop<T>();
421 const T &LHS = S.Stk.pop<T>();
422
423 if (!CheckDivRem(S, OpPC, LHS, RHS))
424 return false;
425
426 const unsigned Bits = RHS.bitWidth() * 2;
427 T Result;
428 if (!T::rem(LHS, RHS, Bits, &Result)) {
429 S.Stk.push<T>(Result);
430 return true;
431 }
432 return false;
433}
434
435/// 1) Pops the RHS from the stack.
436/// 2) Pops the LHS from the stack.
437/// 3) Pushes 'LHS / RHS' on the stack
438template <PrimType Name, class T = typename PrimConv<Name>::T>
439bool Div(InterpState &S, CodePtr OpPC) {
440 const T &RHS = S.Stk.pop<T>();
441 const T &LHS = S.Stk.pop<T>();
442
443 if (!CheckDivRem(S, OpPC, LHS, RHS))
444 return false;
445
446 const unsigned Bits = RHS.bitWidth() * 2;
447 T Result;
448 if (!T::div(LHS, RHS, Bits, &Result)) {
449 S.Stk.push<T>(Result);
450 return true;
451 }
452 return false;
453}
454
455inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
456 const Floating &RHS = S.Stk.pop<Floating>();
457 const Floating &LHS = S.Stk.pop<Floating>();
458
459 if (!CheckDivRem(S, OpPC, LHS, RHS))
460 return false;
461
462 Floating Result;
463 auto Status = Floating::div(A: LHS, B: RHS, RM, R: &Result);
464 S.Stk.push<Floating>(Args&: Result);
465 return CheckFloatResult(S, OpPC, Result, Status);
466}
467
468//===----------------------------------------------------------------------===//
469// Inv
470//===----------------------------------------------------------------------===//
471
472template <PrimType Name, class T = typename PrimConv<Name>::T>
473bool Inv(InterpState &S, CodePtr OpPC) {
474 using BoolT = PrimConv<PT_Bool>::T;
475 const T &Val = S.Stk.pop<T>();
476 const unsigned Bits = Val.bitWidth();
477 Boolean R;
478 Boolean::inv(A: BoolT::from(Val, Bits), R: &R);
479
480 S.Stk.push<BoolT>(Args&: R);
481 return true;
482}
483
484//===----------------------------------------------------------------------===//
485// Neg
486//===----------------------------------------------------------------------===//
487
488template <PrimType Name, class T = typename PrimConv<Name>::T>
489bool Neg(InterpState &S, CodePtr OpPC) {
490 const T &Value = S.Stk.pop<T>();
491 T Result;
492
493 if (!T::neg(Value, &Result)) {
494 S.Stk.push<T>(Result);
495 return true;
496 }
497
498 assert(isIntegralType(Name) &&
499 "don't expect other types to fail at constexpr negation");
500 S.Stk.push<T>(Result);
501
502 APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
503 const Expr *E = S.Current->getExpr(PC: OpPC);
504 QualType Type = E->getType();
505
506 if (S.checkingForUndefinedBehavior()) {
507 SmallString<32> Trunc;
508 NegatedValue.trunc(width: Result.bitWidth())
509 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
510 /*UpperCase=*/true, /*InsertSeparators=*/true);
511 auto Loc = E->getExprLoc();
512 S.report(Loc, diag::warn_integer_constant_overflow)
513 << Trunc << Type << E->getSourceRange();
514 return true;
515 }
516
517 S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue << Type;
518 return S.noteUndefinedBehavior();
519}
520
521enum class PushVal : bool {
522 No,
523 Yes,
524};
525enum class IncDecOp {
526 Inc,
527 Dec,
528};
529
530template <typename T, IncDecOp Op, PushVal DoPush>
531bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
532 assert(!Ptr.isDummy());
533
534 if constexpr (std::is_same_v<T, Boolean>) {
535 if (!S.getLangOpts().CPlusPlus14)
536 return Invalid(S, OpPC);
537 }
538
539 const T &Value = Ptr.deref<T>();
540 T Result;
541
542 if constexpr (DoPush == PushVal::Yes)
543 S.Stk.push<T>(Value);
544
545 if constexpr (Op == IncDecOp::Inc) {
546 if (!T::increment(Value, &Result)) {
547 Ptr.deref<T>() = Result;
548 return true;
549 }
550 } else {
551 if (!T::decrement(Value, &Result)) {
552 Ptr.deref<T>() = Result;
553 return true;
554 }
555 }
556
557 // Something went wrong with the previous operation. Compute the
558 // result with another bit of precision.
559 unsigned Bits = Value.bitWidth() + 1;
560 APSInt APResult;
561 if constexpr (Op == IncDecOp::Inc)
562 APResult = ++Value.toAPSInt(Bits);
563 else
564 APResult = --Value.toAPSInt(Bits);
565
566 // Report undefined behaviour, stopping if required.
567 const Expr *E = S.Current->getExpr(PC: OpPC);
568 QualType Type = E->getType();
569 if (S.checkingForUndefinedBehavior()) {
570 SmallString<32> Trunc;
571 APResult.trunc(width: Result.bitWidth())
572 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
573 /*UpperCase=*/true, /*InsertSeparators=*/true);
574 auto Loc = E->getExprLoc();
575 S.report(Loc, diag::warn_integer_constant_overflow)
576 << Trunc << Type << E->getSourceRange();
577 return true;
578 }
579
580 S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
581 return S.noteUndefinedBehavior();
582}
583
584/// 1) Pops a pointer from the stack
585/// 2) Load the value from the pointer
586/// 3) Writes the value increased by one back to the pointer
587/// 4) Pushes the original (pre-inc) value on the stack.
588template <PrimType Name, class T = typename PrimConv<Name>::T>
589bool Inc(InterpState &S, CodePtr OpPC) {
590 const Pointer &Ptr = S.Stk.pop<Pointer>();
591 if (!CheckDummy(S, OpPC, Ptr))
592 return false;
593 if (!CheckInitialized(S, OpPC, Ptr, AK: AK_Increment))
594 return false;
595
596 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
597}
598
599/// 1) Pops a pointer from the stack
600/// 2) Load the value from the pointer
601/// 3) Writes the value increased by one back to the pointer
602template <PrimType Name, class T = typename PrimConv<Name>::T>
603bool IncPop(InterpState &S, CodePtr OpPC) {
604 const Pointer &Ptr = S.Stk.pop<Pointer>();
605 if (!CheckDummy(S, OpPC, Ptr))
606 return false;
607 if (!CheckInitialized(S, OpPC, Ptr, AK: AK_Increment))
608 return false;
609
610 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
611}
612
613/// 1) Pops a pointer from the stack
614/// 2) Load the value from the pointer
615/// 3) Writes the value decreased by one back to the pointer
616/// 4) Pushes the original (pre-dec) value on the stack.
617template <PrimType Name, class T = typename PrimConv<Name>::T>
618bool Dec(InterpState &S, CodePtr OpPC) {
619 const Pointer &Ptr = S.Stk.pop<Pointer>();
620 if (!CheckDummy(S, OpPC, Ptr))
621 return false;
622 if (!CheckInitialized(S, OpPC, Ptr, AK: AK_Decrement))
623 return false;
624
625 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
626}
627
628/// 1) Pops a pointer from the stack
629/// 2) Load the value from the pointer
630/// 3) Writes the value decreased by one back to the pointer
631template <PrimType Name, class T = typename PrimConv<Name>::T>
632bool DecPop(InterpState &S, CodePtr OpPC) {
633 const Pointer &Ptr = S.Stk.pop<Pointer>();
634 if (!CheckDummy(S, OpPC, Ptr))
635 return false;
636 if (!CheckInitialized(S, OpPC, Ptr, AK: AK_Decrement))
637 return false;
638
639 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
640}
641
642template <IncDecOp Op, PushVal DoPush>
643bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
644 llvm::RoundingMode RM) {
645 Floating Value = Ptr.deref<Floating>();
646 Floating Result;
647
648 if constexpr (DoPush == PushVal::Yes)
649 S.Stk.push<Floating>(Args&: Value);
650
651 llvm::APFloat::opStatus Status;
652 if constexpr (Op == IncDecOp::Inc)
653 Status = Floating::increment(A: Value, RM, R: &Result);
654 else
655 Status = Floating::decrement(A: Value, RM, R: &Result);
656
657 Ptr.deref<Floating>() = Result;
658
659 return CheckFloatResult(S, OpPC, Result, Status);
660}
661
662inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
663 const Pointer &Ptr = S.Stk.pop<Pointer>();
664 if (Ptr.isDummy())
665 return false;
666 if (!CheckInitialized(S, OpPC, Ptr, AK: AK_Increment))
667 return false;
668
669 return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM);
670}
671
672inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
673 const Pointer &Ptr = S.Stk.pop<Pointer>();
674 if (Ptr.isDummy())
675 return false;
676 if (!CheckInitialized(S, OpPC, Ptr, AK: AK_Increment))
677 return false;
678
679 return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM);
680}
681
682inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
683 const Pointer &Ptr = S.Stk.pop<Pointer>();
684
685 if (Ptr.isDummy())
686 return false;
687
688 if (!CheckInitialized(S, OpPC, Ptr, AK: AK_Decrement))
689 return false;
690
691 return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM);
692}
693
694inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
695 const Pointer &Ptr = S.Stk.pop<Pointer>();
696
697 if (Ptr.isDummy())
698 return false;
699 if (!CheckInitialized(S, OpPC, Ptr, AK: AK_Decrement))
700 return false;
701
702 return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM);
703}
704
705/// 1) Pops the value from the stack.
706/// 2) Pushes the bitwise complemented value on the stack (~V).
707template <PrimType Name, class T = typename PrimConv<Name>::T>
708bool Comp(InterpState &S, CodePtr OpPC) {
709 const T &Val = S.Stk.pop<T>();
710 T Result;
711 if (!T::comp(Val, &Result)) {
712 S.Stk.push<T>(Result);
713 return true;
714 }
715
716 return false;
717}
718
719//===----------------------------------------------------------------------===//
720// EQ, NE, GT, GE, LT, LE
721//===----------------------------------------------------------------------===//
722
723using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
724
725template <typename T>
726bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
727 using BoolT = PrimConv<PT_Bool>::T;
728 const T &RHS = S.Stk.pop<T>();
729 const T &LHS = S.Stk.pop<T>();
730 S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
731 return true;
732}
733
734template <typename T>
735bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
736 return CmpHelper<T>(S, OpPC, Fn);
737}
738
739/// Function pointers cannot be compared in an ordered way.
740template <>
741inline bool CmpHelper<FunctionPointer>(InterpState &S, CodePtr OpPC,
742 CompareFn Fn) {
743 const auto &RHS = S.Stk.pop<FunctionPointer>();
744 const auto &LHS = S.Stk.pop<FunctionPointer>();
745
746 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
747 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
748 << LHS.toDiagnosticString(S.getCtx())
749 << RHS.toDiagnosticString(S.getCtx());
750 return false;
751}
752
753template <>
754inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC,
755 CompareFn Fn) {
756 const auto &RHS = S.Stk.pop<FunctionPointer>();
757 const auto &LHS = S.Stk.pop<FunctionPointer>();
758
759 // We cannot compare against weak declarations at compile time.
760 for (const auto &FP : {LHS, RHS}) {
761 if (FP.isWeak()) {
762 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
763 S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
764 << FP.toDiagnosticString(S.getCtx());
765 return false;
766 }
767 }
768
769 S.Stk.push<Boolean>(Args: Boolean::from(Value: Fn(LHS.compare(RHS))));
770 return true;
771}
772
773template <>
774inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
775 using BoolT = PrimConv<PT_Bool>::T;
776 const Pointer &RHS = S.Stk.pop<Pointer>();
777 const Pointer &LHS = S.Stk.pop<Pointer>();
778
779 if (!Pointer::hasSameBase(A: LHS, B: RHS)) {
780 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
781 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
782 << LHS.toDiagnosticString(S.getCtx())
783 << RHS.toDiagnosticString(S.getCtx());
784 return false;
785 } else {
786 unsigned VL = LHS.getByteOffset();
787 unsigned VR = RHS.getByteOffset();
788 S.Stk.push<BoolT>(Args: BoolT::from(Value: Fn(Compare(X: VL, Y: VR))));
789 return true;
790 }
791}
792
793template <>
794inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
795 using BoolT = PrimConv<PT_Bool>::T;
796 const Pointer &RHS = S.Stk.pop<Pointer>();
797 const Pointer &LHS = S.Stk.pop<Pointer>();
798
799 if (LHS.isZero() && RHS.isZero()) {
800 S.Stk.push<BoolT>(Args: BoolT::from(Value: Fn(ComparisonCategoryResult::Equal)));
801 return true;
802 }
803
804 for (const auto &P : {LHS, RHS}) {
805 if (P.isZero())
806 continue;
807 if (P.isWeak()) {
808 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
809 S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
810 << P.toDiagnosticString(S.getCtx());
811 return false;
812 }
813 }
814
815 if (!Pointer::hasSameBase(A: LHS, B: RHS)) {
816 S.Stk.push<BoolT>(Args: BoolT::from(Value: Fn(ComparisonCategoryResult::Unordered)));
817 return true;
818 } else {
819 unsigned VL = LHS.getByteOffset();
820 unsigned VR = RHS.getByteOffset();
821
822 // In our Pointer class, a pointer to an array and a pointer to the first
823 // element in the same array are NOT equal. They have the same Base value,
824 // but a different Offset. This is a pretty rare case, so we fix this here
825 // by comparing pointers to the first elements.
826 if (!LHS.isZero() && !LHS.isDummy() && LHS.isArrayRoot())
827 VL = LHS.atIndex(Idx: 0).getByteOffset();
828 if (!RHS.isZero() && !RHS.isDummy() && RHS.isArrayRoot())
829 VR = RHS.atIndex(Idx: 0).getByteOffset();
830
831 S.Stk.push<BoolT>(Args: BoolT::from(Value: Fn(Compare(X: VL, Y: VR))));
832 return true;
833 }
834}
835
836template <PrimType Name, class T = typename PrimConv<Name>::T>
837bool EQ(InterpState &S, CodePtr OpPC) {
838 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
839 return R == ComparisonCategoryResult::Equal;
840 });
841}
842
843template <PrimType Name, class T = typename PrimConv<Name>::T>
844bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
845 const T &RHS = S.Stk.pop<T>();
846 const T &LHS = S.Stk.pop<T>();
847 const Pointer &P = S.Stk.peek<Pointer>();
848
849 ComparisonCategoryResult CmpResult = LHS.compare(RHS);
850 if (CmpResult == ComparisonCategoryResult::Unordered) {
851 // This should only happen with pointers.
852 const SourceInfo &Loc = S.Current->getSource(PC: OpPC);
853 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
854 << LHS.toDiagnosticString(S.getCtx())
855 << RHS.toDiagnosticString(S.getCtx());
856 return false;
857 }
858
859 assert(CmpInfo);
860 const auto *CmpValueInfo =
861 CmpInfo->getValueInfo(ValueKind: CmpInfo->makeWeakResult(Res: CmpResult));
862 assert(CmpValueInfo);
863 assert(CmpValueInfo->hasValidIntValue());
864 return SetThreeWayComparisonField(S, OpPC, Ptr: P, IntValue: CmpValueInfo->getIntValue());
865}
866
867template <PrimType Name, class T = typename PrimConv<Name>::T>
868bool NE(InterpState &S, CodePtr OpPC) {
869 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
870 return R != ComparisonCategoryResult::Equal;
871 });
872}
873
874template <PrimType Name, class T = typename PrimConv<Name>::T>
875bool LT(InterpState &S, CodePtr OpPC) {
876 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
877 return R == ComparisonCategoryResult::Less;
878 });
879}
880
881template <PrimType Name, class T = typename PrimConv<Name>::T>
882bool LE(InterpState &S, CodePtr OpPC) {
883 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
884 return R == ComparisonCategoryResult::Less ||
885 R == ComparisonCategoryResult::Equal;
886 });
887}
888
889template <PrimType Name, class T = typename PrimConv<Name>::T>
890bool GT(InterpState &S, CodePtr OpPC) {
891 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
892 return R == ComparisonCategoryResult::Greater;
893 });
894}
895
896template <PrimType Name, class T = typename PrimConv<Name>::T>
897bool GE(InterpState &S, CodePtr OpPC) {
898 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
899 return R == ComparisonCategoryResult::Greater ||
900 R == ComparisonCategoryResult::Equal;
901 });
902}
903
904//===----------------------------------------------------------------------===//
905// InRange
906//===----------------------------------------------------------------------===//
907
908template <PrimType Name, class T = typename PrimConv<Name>::T>
909bool InRange(InterpState &S, CodePtr OpPC) {
910 const T RHS = S.Stk.pop<T>();
911 const T LHS = S.Stk.pop<T>();
912 const T Value = S.Stk.pop<T>();
913
914 S.Stk.push<bool>(LHS <= Value && Value <= RHS);
915 return true;
916}
917
918//===----------------------------------------------------------------------===//
919// Dup, Pop, Test
920//===----------------------------------------------------------------------===//
921
922template <PrimType Name, class T = typename PrimConv<Name>::T>
923bool Dup(InterpState &S, CodePtr OpPC) {
924 S.Stk.push<T>(S.Stk.peek<T>());
925 return true;
926}
927
928template <PrimType Name, class T = typename PrimConv<Name>::T>
929bool Pop(InterpState &S, CodePtr OpPC) {
930 S.Stk.pop<T>();
931 return true;
932}
933
934//===----------------------------------------------------------------------===//
935// Const
936//===----------------------------------------------------------------------===//
937
938template <PrimType Name, class T = typename PrimConv<Name>::T>
939bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
940 S.Stk.push<T>(Arg);
941 return true;
942}
943
944//===----------------------------------------------------------------------===//
945// Get/Set Local/Param/Global/This
946//===----------------------------------------------------------------------===//
947
948template <PrimType Name, class T = typename PrimConv<Name>::T>
949bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
950 const Pointer &Ptr = S.Current->getLocalPointer(Offset: I);
951 if (!CheckLoad(S, OpPC, Ptr))
952 return false;
953 S.Stk.push<T>(Ptr.deref<T>());
954 return true;
955}
956
957/// 1) Pops the value from the stack.
958/// 2) Writes the value to the local variable with the
959/// given offset.
960template <PrimType Name, class T = typename PrimConv<Name>::T>
961bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
962 S.Current->setLocal<T>(I, S.Stk.pop<T>());
963 return true;
964}
965
966template <PrimType Name, class T = typename PrimConv<Name>::T>
967bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
968 if (S.checkingPotentialConstantExpression()) {
969 return false;
970 }
971 S.Stk.push<T>(S.Current->getParam<T>(I));
972 return true;
973}
974
975template <PrimType Name, class T = typename PrimConv<Name>::T>
976bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
977 S.Current->setParam<T>(I, S.Stk.pop<T>());
978 return true;
979}
980
981/// 1) Peeks a pointer on the stack
982/// 2) Pushes the value of the pointer's field on the stack
983template <PrimType Name, class T = typename PrimConv<Name>::T>
984bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
985 const Pointer &Obj = S.Stk.peek<Pointer>();
986 if (!CheckNull(S, OpPC, Ptr: Obj, CSK: CSK_Field))
987 return false;
988 if (!CheckRange(S, OpPC, Ptr: Obj, CSK: CSK_Field))
989 return false;
990 const Pointer &Field = Obj.atField(Off: I);
991 if (!CheckLoad(S, OpPC, Ptr: Field))
992 return false;
993 S.Stk.push<T>(Field.deref<T>());
994 return true;
995}
996
997template <PrimType Name, class T = typename PrimConv<Name>::T>
998bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
999 const T &Value = S.Stk.pop<T>();
1000 const Pointer &Obj = S.Stk.peek<Pointer>();
1001 if (!CheckNull(S, OpPC, Ptr: Obj, CSK: CSK_Field))
1002 return false;
1003 if (!CheckRange(S, OpPC, Ptr: Obj, CSK: CSK_Field))
1004 return false;
1005 const Pointer &Field = Obj.atField(Off: I);
1006 if (!CheckStore(S, OpPC, Ptr: Field))
1007 return false;
1008 Field.initialize();
1009 Field.deref<T>() = Value;
1010 return true;
1011}
1012
1013/// 1) Pops a pointer from the stack
1014/// 2) Pushes the value of the pointer's field on the stack
1015template <PrimType Name, class T = typename PrimConv<Name>::T>
1016bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
1017 const Pointer &Obj = S.Stk.pop<Pointer>();
1018 if (!CheckNull(S, OpPC, Ptr: Obj, CSK: CSK_Field))
1019 return false;
1020 if (!CheckRange(S, OpPC, Ptr: Obj, CSK: CSK_Field))
1021 return false;
1022 const Pointer &Field = Obj.atField(Off: I);
1023 if (!CheckLoad(S, OpPC, Ptr: Field))
1024 return false;
1025 S.Stk.push<T>(Field.deref<T>());
1026 return true;
1027}
1028
1029template <PrimType Name, class T = typename PrimConv<Name>::T>
1030bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1031 if (S.checkingPotentialConstantExpression())
1032 return false;
1033 const Pointer &This = S.Current->getThis();
1034 if (!CheckThis(S, OpPC, This))
1035 return false;
1036 const Pointer &Field = This.atField(Off: I);
1037 if (!CheckLoad(S, OpPC, Ptr: Field))
1038 return false;
1039 S.Stk.push<T>(Field.deref<T>());
1040 return true;
1041}
1042
1043template <PrimType Name, class T = typename PrimConv<Name>::T>
1044bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1045 if (S.checkingPotentialConstantExpression())
1046 return false;
1047 const T &Value = S.Stk.pop<T>();
1048 const Pointer &This = S.Current->getThis();
1049 if (!CheckThis(S, OpPC, This))
1050 return false;
1051 const Pointer &Field = This.atField(Off: I);
1052 if (!CheckStore(S, OpPC, Ptr: Field))
1053 return false;
1054 Field.deref<T>() = Value;
1055 return true;
1056}
1057
1058template <PrimType Name, class T = typename PrimConv<Name>::T>
1059bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1060 const Pointer &Ptr = S.P.getPtrGlobal(Idx: I);
1061 if (!CheckConstant(S, OpPC, Desc: Ptr.getFieldDesc()))
1062 return false;
1063 if (Ptr.isExtern())
1064 return false;
1065
1066 // If a global variable is uninitialized, that means the initializer we've
1067 // compiled for it wasn't a constant expression. Diagnose that.
1068 if (!CheckGlobalInitialized(S, OpPC, Ptr))
1069 return false;
1070
1071 S.Stk.push<T>(Ptr.deref<T>());
1072 return true;
1073}
1074
1075/// Same as GetGlobal, but without the checks.
1076template <PrimType Name, class T = typename PrimConv<Name>::T>
1077bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {
1078 auto *B = S.P.getGlobal(Idx: I);
1079 S.Stk.push<T>(B->deref<T>());
1080 return true;
1081}
1082
1083template <PrimType Name, class T = typename PrimConv<Name>::T>
1084bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1085 // TODO: emit warning.
1086 return false;
1087}
1088
1089template <PrimType Name, class T = typename PrimConv<Name>::T>
1090bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1091 const Pointer &P = S.P.getGlobal(Idx: I);
1092 P.deref<T>() = S.Stk.pop<T>();
1093 P.initialize();
1094 return true;
1095}
1096
1097/// 1) Converts the value on top of the stack to an APValue
1098/// 2) Sets that APValue on \Temp
1099/// 3) Initializes global with index \I with that
1100template <PrimType Name, class T = typename PrimConv<Name>::T>
1101bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
1102 const LifetimeExtendedTemporaryDecl *Temp) {
1103 assert(Temp);
1104 const T Value = S.Stk.peek<T>();
1105 APValue APV = Value.toAPValue();
1106 APValue *Cached = Temp->getOrCreateValue(MayCreate: true);
1107 *Cached = APV;
1108
1109 const Pointer &P = S.P.getGlobal(Idx: I);
1110 P.deref<T>() = S.Stk.pop<T>();
1111 P.initialize();
1112
1113 return true;
1114}
1115
1116/// 1) Converts the value on top of the stack to an APValue
1117/// 2) Sets that APValue on \Temp
1118/// 3) Initialized global with index \I with that
1119inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC,
1120 const LifetimeExtendedTemporaryDecl *Temp) {
1121 assert(Temp);
1122 const Pointer &P = S.Stk.peek<Pointer>();
1123 APValue *Cached = Temp->getOrCreateValue(MayCreate: true);
1124
1125 if (std::optional<APValue> APV = P.toRValue(S.getCtx())) {
1126 *Cached = *APV;
1127 return true;
1128 }
1129
1130 return false;
1131}
1132
1133template <PrimType Name, class T = typename PrimConv<Name>::T>
1134bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1135 if (S.checkingPotentialConstantExpression())
1136 return false;
1137 const Pointer &This = S.Current->getThis();
1138 if (!CheckThis(S, OpPC, This))
1139 return false;
1140 const Pointer &Field = This.atField(Off: I);
1141 Field.deref<T>() = S.Stk.pop<T>();
1142 Field.initialize();
1143 return true;
1144}
1145
1146// FIXME: The Field pointer here is too much IMO and we could instead just
1147// pass an Offset + BitWidth pair.
1148template <PrimType Name, class T = typename PrimConv<Name>::T>
1149bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,
1150 uint32_t FieldOffset) {
1151 assert(F->isBitField());
1152 if (S.checkingPotentialConstantExpression())
1153 return false;
1154 const Pointer &This = S.Current->getThis();
1155 if (!CheckThis(S, OpPC, This))
1156 return false;
1157 const Pointer &Field = This.atField(Off: FieldOffset);
1158 const auto &Value = S.Stk.pop<T>();
1159 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(Ctx: S.getCtx()));
1160 Field.initialize();
1161 return true;
1162}
1163
1164template <PrimType Name, class T = typename PrimConv<Name>::T>
1165bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1166 if (S.checkingPotentialConstantExpression())
1167 return false;
1168 const Pointer &This = S.Current->getThis();
1169 if (!CheckThis(S, OpPC, This))
1170 return false;
1171 const Pointer &Field = This.atField(Off: I);
1172 Field.deref<T>() = S.Stk.pop<T>();
1173 Field.activate();
1174 Field.initialize();
1175 return true;
1176}
1177
1178/// 1) Pops the value from the stack
1179/// 2) Peeks a pointer from the stack
1180/// 3) Pushes the value to field I of the pointer on the stack
1181template <PrimType Name, class T = typename PrimConv<Name>::T>
1182bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
1183 const T &Value = S.Stk.pop<T>();
1184 const Pointer &Field = S.Stk.peek<Pointer>().atField(Off: I);
1185 Field.deref<T>() = Value;
1186 Field.activate();
1187 Field.initialize();
1188 return true;
1189}
1190
1191template <PrimType Name, class T = typename PrimConv<Name>::T>
1192bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
1193 assert(F->isBitField());
1194 const T &Value = S.Stk.pop<T>();
1195 const Pointer &Field = S.Stk.peek<Pointer>().atField(Off: F->Offset);
1196 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(Ctx: S.getCtx()));
1197 Field.activate();
1198 Field.initialize();
1199 return true;
1200}
1201
1202template <PrimType Name, class T = typename PrimConv<Name>::T>
1203bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1204 const T &Value = S.Stk.pop<T>();
1205 const Pointer &Ptr = S.Stk.pop<Pointer>();
1206 const Pointer &Field = Ptr.atField(Off: I);
1207 Field.deref<T>() = Value;
1208 Field.activate();
1209 Field.initialize();
1210 return true;
1211}
1212
1213//===----------------------------------------------------------------------===//
1214// GetPtr Local/Param/Global/Field/This
1215//===----------------------------------------------------------------------===//
1216
1217inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1218 S.Stk.push<Pointer>(Args: S.Current->getLocalPointer(Offset: I));
1219 return true;
1220}
1221
1222inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1223 if (S.checkingPotentialConstantExpression()) {
1224 return false;
1225 }
1226 S.Stk.push<Pointer>(Args: S.Current->getParamPointer(Offset: I));
1227 return true;
1228}
1229
1230inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1231 S.Stk.push<Pointer>(Args: S.P.getPtrGlobal(Idx: I));
1232 return true;
1233}
1234
1235/// 1) Pops a Pointer from the stack
1236/// 2) Pushes Pointer.atField(Off) on the stack
1237inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1238 const Pointer &Ptr = S.Stk.pop<Pointer>();
1239
1240 if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
1241 !CheckNull(S, OpPC, Ptr, CSK: CSK_Field))
1242 return false;
1243
1244 if (CheckDummy(S, OpPC, Ptr)) {
1245 if (!CheckExtern(S, OpPC, Ptr))
1246 return false;
1247 if (!CheckRange(S, OpPC, Ptr, CSK: CSK_Field))
1248 return false;
1249 if (!CheckSubobject(S, OpPC, Ptr, CSK: CSK_Field))
1250 return false;
1251 }
1252 S.Stk.push<Pointer>(Args: Ptr.atField(Off));
1253 return true;
1254}
1255
1256inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1257 if (S.checkingPotentialConstantExpression())
1258 return false;
1259 const Pointer &This = S.Current->getThis();
1260 if (!CheckThis(S, OpPC, This))
1261 return false;
1262 S.Stk.push<Pointer>(Args: This.atField(Off));
1263 return true;
1264}
1265
1266inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1267 const Pointer &Ptr = S.Stk.pop<Pointer>();
1268 if (!CheckNull(S, OpPC, Ptr, CSK: CSK_Field))
1269 return false;
1270 if (!CheckRange(S, OpPC, Ptr, CSK: CSK_Field))
1271 return false;
1272 Pointer Field = Ptr.atField(Off);
1273 Ptr.deactivate();
1274 Field.activate();
1275 S.Stk.push<Pointer>(Args: std::move(Field));
1276 return true;
1277}
1278
1279inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1280 if (S.checkingPotentialConstantExpression())
1281 return false;
1282 const Pointer &This = S.Current->getThis();
1283 if (!CheckThis(S, OpPC, This))
1284 return false;
1285 Pointer Field = This.atField(Off);
1286 This.deactivate();
1287 Field.activate();
1288 S.Stk.push<Pointer>(Args: std::move(Field));
1289 return true;
1290}
1291
1292inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1293 const Pointer &Ptr = S.Stk.pop<Pointer>();
1294 if (!CheckNull(S, OpPC, Ptr, CSK: CSK_Derived))
1295 return false;
1296 if (!CheckSubobject(S, OpPC, Ptr, CSK: CSK_Derived))
1297 return false;
1298 S.Stk.push<Pointer>(Args: Ptr.atFieldSub(Off));
1299 return true;
1300}
1301
1302inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1303 const Pointer &Ptr = S.Stk.peek<Pointer>();
1304 if (!CheckNull(S, OpPC, Ptr, CSK: CSK_Base))
1305 return false;
1306 if (!CheckSubobject(S, OpPC, Ptr, CSK: CSK_Base))
1307 return false;
1308 S.Stk.push<Pointer>(Args: Ptr.atField(Off));
1309 return true;
1310}
1311
1312inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1313 const Pointer &Ptr = S.Stk.pop<Pointer>();
1314 if (!CheckNull(S, OpPC, Ptr, CSK: CSK_Base))
1315 return false;
1316 if (!CheckSubobject(S, OpPC, Ptr, CSK: CSK_Base))
1317 return false;
1318 S.Stk.push<Pointer>(Args: Ptr.atField(Off));
1319 return true;
1320}
1321
1322inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1323 if (S.checkingPotentialConstantExpression())
1324 return false;
1325 const Pointer &This = S.Current->getThis();
1326 if (!CheckThis(S, OpPC, This))
1327 return false;
1328 S.Stk.push<Pointer>(Args: This.atField(Off));
1329 return true;
1330}
1331
1332inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {
1333 const Pointer &Ptr = S.Stk.pop<Pointer>();
1334 if (Ptr.canBeInitialized())
1335 Ptr.initialize();
1336 return true;
1337}
1338
1339inline bool FinishInit(InterpState &S, CodePtr OpPC) {
1340 const Pointer &Ptr = S.Stk.peek<Pointer>();
1341
1342 if (Ptr.canBeInitialized())
1343 Ptr.initialize();
1344 return true;
1345}
1346
1347inline bool Dump(InterpState &S, CodePtr OpPC) {
1348 S.Stk.dump();
1349 return true;
1350}
1351
1352inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1353 const Pointer &Ptr) {
1354 Pointer Base = Ptr;
1355 while (Base.isBaseClass())
1356 Base = Base.getBase();
1357
1358 auto *Field = Base.getRecord()->getVirtualBase(RD: Decl);
1359 S.Stk.push<Pointer>(Args: Base.atField(Off: Field->Offset));
1360 return true;
1361}
1362
1363inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
1364 const Pointer &Ptr = S.Stk.pop<Pointer>();
1365 if (!CheckNull(S, OpPC, Ptr, CSK: CSK_Base))
1366 return false;
1367 return VirtBaseHelper(S, OpPC, Decl: D, Ptr);
1368}
1369
1370inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
1371 const RecordDecl *D) {
1372 if (S.checkingPotentialConstantExpression())
1373 return false;
1374 const Pointer &This = S.Current->getThis();
1375 if (!CheckThis(S, OpPC, This))
1376 return false;
1377 return VirtBaseHelper(S, OpPC, Decl: D, Ptr: S.Current->getThis());
1378}
1379
1380//===----------------------------------------------------------------------===//
1381// Load, Store, Init
1382//===----------------------------------------------------------------------===//
1383
1384template <PrimType Name, class T = typename PrimConv<Name>::T>
1385bool Load(InterpState &S, CodePtr OpPC) {
1386 const Pointer &Ptr = S.Stk.peek<Pointer>();
1387 if (!CheckLoad(S, OpPC, Ptr))
1388 return false;
1389 if (!Ptr.isBlockPointer())
1390 return false;
1391 S.Stk.push<T>(Ptr.deref<T>());
1392 return true;
1393}
1394
1395template <PrimType Name, class T = typename PrimConv<Name>::T>
1396bool LoadPop(InterpState &S, CodePtr OpPC) {
1397 const Pointer &Ptr = S.Stk.pop<Pointer>();
1398 if (!CheckLoad(S, OpPC, Ptr))
1399 return false;
1400 if (!Ptr.isBlockPointer())
1401 return false;
1402 S.Stk.push<T>(Ptr.deref<T>());
1403 return true;
1404}
1405
1406template <PrimType Name, class T = typename PrimConv<Name>::T>
1407bool Store(InterpState &S, CodePtr OpPC) {
1408 const T &Value = S.Stk.pop<T>();
1409 const Pointer &Ptr = S.Stk.peek<Pointer>();
1410 if (!CheckStore(S, OpPC, Ptr))
1411 return false;
1412 if (Ptr.canBeInitialized())
1413 Ptr.initialize();
1414 Ptr.deref<T>() = Value;
1415 return true;
1416}
1417
1418template <PrimType Name, class T = typename PrimConv<Name>::T>
1419bool StorePop(InterpState &S, CodePtr OpPC) {
1420 const T &Value = S.Stk.pop<T>();
1421 const Pointer &Ptr = S.Stk.pop<Pointer>();
1422 if (!CheckStore(S, OpPC, Ptr))
1423 return false;
1424 if (Ptr.canBeInitialized())
1425 Ptr.initialize();
1426 Ptr.deref<T>() = Value;
1427 return true;
1428}
1429
1430template <PrimType Name, class T = typename PrimConv<Name>::T>
1431bool StoreBitField(InterpState &S, CodePtr OpPC) {
1432 const T &Value = S.Stk.pop<T>();
1433 const Pointer &Ptr = S.Stk.peek<Pointer>();
1434 if (!CheckStore(S, OpPC, Ptr))
1435 return false;
1436 if (Ptr.canBeInitialized())
1437 Ptr.initialize();
1438 if (const auto *FD = Ptr.getField())
1439 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(Ctx: S.getCtx()));
1440 else
1441 Ptr.deref<T>() = Value;
1442 return true;
1443}
1444
1445template <PrimType Name, class T = typename PrimConv<Name>::T>
1446bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
1447 const T &Value = S.Stk.pop<T>();
1448 const Pointer &Ptr = S.Stk.pop<Pointer>();
1449 if (!CheckStore(S, OpPC, Ptr))
1450 return false;
1451 if (Ptr.canBeInitialized())
1452 Ptr.initialize();
1453 if (const auto *FD = Ptr.getField())
1454 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(Ctx: S.getCtx()));
1455 else
1456 Ptr.deref<T>() = Value;
1457 return true;
1458}
1459
1460template <PrimType Name, class T = typename PrimConv<Name>::T>
1461bool Init(InterpState &S, CodePtr OpPC) {
1462 const T &Value = S.Stk.pop<T>();
1463 const Pointer &Ptr = S.Stk.peek<Pointer>();
1464 if (!CheckInit(S, OpPC, Ptr)) {
1465 assert(false);
1466 return false;
1467 }
1468 Ptr.initialize();
1469 new (&Ptr.deref<T>()) T(Value);
1470 return true;
1471}
1472
1473template <PrimType Name, class T = typename PrimConv<Name>::T>
1474bool InitPop(InterpState &S, CodePtr OpPC) {
1475 const T &Value = S.Stk.pop<T>();
1476 const Pointer &Ptr = S.Stk.pop<Pointer>();
1477 if (!CheckInit(S, OpPC, Ptr))
1478 return false;
1479 Ptr.initialize();
1480 new (&Ptr.deref<T>()) T(Value);
1481 return true;
1482}
1483
1484/// 1) Pops the value from the stack
1485/// 2) Peeks a pointer and gets its index \Idx
1486/// 3) Sets the value on the pointer, leaving the pointer on the stack.
1487template <PrimType Name, class T = typename PrimConv<Name>::T>
1488bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1489 const T &Value = S.Stk.pop<T>();
1490 const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
1491 if (Ptr.isUnknownSizeArray())
1492 return false;
1493 if (!CheckInit(S, OpPC, Ptr))
1494 return false;
1495 Ptr.initialize();
1496 new (&Ptr.deref<T>()) T(Value);
1497 return true;
1498}
1499
1500/// The same as InitElem, but pops the pointer as well.
1501template <PrimType Name, class T = typename PrimConv<Name>::T>
1502bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1503 const T &Value = S.Stk.pop<T>();
1504 const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
1505 if (Ptr.isUnknownSizeArray())
1506 return false;
1507 if (!CheckInit(S, OpPC, Ptr))
1508 return false;
1509 Ptr.initialize();
1510 new (&Ptr.deref<T>()) T(Value);
1511 return true;
1512}
1513
1514inline bool Memcpy(InterpState &S, CodePtr OpPC) {
1515 const Pointer &Src = S.Stk.pop<Pointer>();
1516 Pointer &Dest = S.Stk.peek<Pointer>();
1517
1518 if (!CheckLoad(S, OpPC, Ptr: Src))
1519 return false;
1520
1521 return DoMemcpy(S, OpPC, Src, Dest);
1522}
1523
1524//===----------------------------------------------------------------------===//
1525// AddOffset, SubOffset
1526//===----------------------------------------------------------------------===//
1527
1528template <class T, ArithOp Op>
1529bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
1530 const Pointer &Ptr) {
1531 if (!CheckRange(S, OpPC, Ptr, CSK: CSK_ArrayToPointer))
1532 return false;
1533
1534 // A zero offset does not change the pointer.
1535 if (Offset.isZero()) {
1536 S.Stk.push<Pointer>(Args: Ptr);
1537 return true;
1538 }
1539
1540 if (!CheckNull(S, OpPC, Ptr, CSK: CSK_ArrayIndex)) {
1541 // The CheckNull will have emitted a note already, but we only
1542 // abort in C++, since this is fine in C.
1543 if (S.getLangOpts().CPlusPlus)
1544 return false;
1545 }
1546
1547 // Arrays of unknown bounds cannot have pointers into them.
1548 if (!CheckArray(S, OpPC, Ptr))
1549 return false;
1550
1551 uint64_t Index = Ptr.getIndex();
1552 uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());
1553
1554 bool Invalid = false;
1555 // Helper to report an invalid offset, computed as APSInt.
1556 auto DiagInvalidOffset = [&]() -> void {
1557 const unsigned Bits = Offset.bitWidth();
1558 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false);
1559 APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true),
1560 /*IsUnsigned=*/false);
1561 APSInt NewIndex =
1562 (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1563 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1564 << NewIndex
1565 << /*array*/ static_cast<int>(!Ptr.inArray())
1566 << static_cast<unsigned>(MaxIndex);
1567 Invalid = true;
1568 };
1569
1570 if (Ptr.isBlockPointer()) {
1571 uint64_t IOffset = static_cast<uint64_t>(Offset);
1572 uint64_t MaxOffset = MaxIndex - Index;
1573
1574 if constexpr (Op == ArithOp::Add) {
1575 // If the new offset would be negative, bail out.
1576 if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
1577 DiagInvalidOffset();
1578
1579 // If the new offset would be out of bounds, bail out.
1580 if (Offset.isPositive() && IOffset > MaxOffset)
1581 DiagInvalidOffset();
1582 } else {
1583 // If the new offset would be negative, bail out.
1584 if (Offset.isPositive() && Index < IOffset)
1585 DiagInvalidOffset();
1586
1587 // If the new offset would be out of bounds, bail out.
1588 if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
1589 DiagInvalidOffset();
1590 }
1591 }
1592
1593 if (Invalid && !Ptr.isDummy() && S.getLangOpts().CPlusPlus)
1594 return false;
1595
1596 // Offset is valid - compute it on unsigned.
1597 int64_t WideIndex = static_cast<int64_t>(Index);
1598 int64_t WideOffset = static_cast<int64_t>(Offset);
1599 int64_t Result;
1600 if constexpr (Op == ArithOp::Add)
1601 Result = WideIndex + WideOffset;
1602 else
1603 Result = WideIndex - WideOffset;
1604
1605 S.Stk.push<Pointer>(Args: Ptr.atIndex(Idx: static_cast<uint64_t>(Result)));
1606 return true;
1607}
1608
1609template <PrimType Name, class T = typename PrimConv<Name>::T>
1610bool AddOffset(InterpState &S, CodePtr OpPC) {
1611 const T &Offset = S.Stk.pop<T>();
1612 const Pointer &Ptr = S.Stk.pop<Pointer>();
1613 return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
1614}
1615
1616template <PrimType Name, class T = typename PrimConv<Name>::T>
1617bool SubOffset(InterpState &S, CodePtr OpPC) {
1618 const T &Offset = S.Stk.pop<T>();
1619 const Pointer &Ptr = S.Stk.pop<Pointer>();
1620 return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);
1621}
1622
1623template <ArithOp Op>
1624static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
1625 const Pointer &Ptr) {
1626 if (Ptr.isDummy())
1627 return false;
1628
1629 using OneT = Integral<8, false>;
1630
1631 const Pointer &P = Ptr.deref<Pointer>();
1632 if (!CheckNull(S, OpPC, Ptr: P, CSK: CSK_ArrayIndex))
1633 return false;
1634
1635 // Get the current value on the stack.
1636 S.Stk.push<Pointer>(Args: P);
1637
1638 // Now the current Ptr again and a constant 1.
1639 OneT One = OneT::from(Value: 1);
1640 if (!OffsetHelper<OneT, Op>(S, OpPC, One, P))
1641 return false;
1642
1643 // Store the new value.
1644 Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
1645 return true;
1646}
1647
1648static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
1649 const Pointer &Ptr = S.Stk.pop<Pointer>();
1650
1651 if (!CheckInitialized(S, OpPC, Ptr, AK: AK_Increment))
1652 return false;
1653
1654 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
1655}
1656
1657static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
1658 const Pointer &Ptr = S.Stk.pop<Pointer>();
1659
1660 if (!CheckInitialized(S, OpPC, Ptr, AK: AK_Decrement))
1661 return false;
1662
1663 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
1664}
1665
1666/// 1) Pops a Pointer from the stack.
1667/// 2) Pops another Pointer from the stack.
1668/// 3) Pushes the different of the indices of the two pointers on the stack.
1669template <PrimType Name, class T = typename PrimConv<Name>::T>
1670inline bool SubPtr(InterpState &S, CodePtr OpPC) {
1671 const Pointer &LHS = S.Stk.pop<Pointer>();
1672 const Pointer &RHS = S.Stk.pop<Pointer>();
1673
1674 if (RHS.isZero()) {
1675 S.Stk.push<T>(T::from(LHS.getIndex()));
1676 return true;
1677 }
1678
1679 if (!Pointer::hasSameBase(A: LHS, B: RHS) && S.getLangOpts().CPlusPlus) {
1680 // TODO: Diagnose.
1681 return false;
1682 }
1683
1684 if (LHS.isZero() && RHS.isZero()) {
1685 S.Stk.push<T>();
1686 return true;
1687 }
1688
1689 T A = T::from(LHS.getIndex());
1690 T B = T::from(RHS.getIndex());
1691 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
1692}
1693
1694//===----------------------------------------------------------------------===//
1695// Destroy
1696//===----------------------------------------------------------------------===//
1697
1698inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
1699 S.Current->destroy(Idx: I);
1700 return true;
1701}
1702
1703//===----------------------------------------------------------------------===//
1704// Cast, CastFP
1705//===----------------------------------------------------------------------===//
1706
1707template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
1708 using T = typename PrimConv<TIn>::T;
1709 using U = typename PrimConv<TOut>::T;
1710 S.Stk.push<U>(U::from(S.Stk.pop<T>()));
1711 return true;
1712}
1713
1714/// 1) Pops a Floating from the stack.
1715/// 2) Pushes a new floating on the stack that uses the given semantics.
1716inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
1717 llvm::RoundingMode RM) {
1718 Floating F = S.Stk.pop<Floating>();
1719 Floating Result = F.toSemantics(Sem, RM);
1720 S.Stk.push<Floating>(Args&: Result);
1721 return true;
1722}
1723
1724/// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
1725/// to know what bitwidth the result should be.
1726template <PrimType Name, class T = typename PrimConv<Name>::T>
1727bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1728 S.Stk.push<IntegralAP<false>>(
1729 IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth));
1730 return true;
1731}
1732
1733template <PrimType Name, class T = typename PrimConv<Name>::T>
1734bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1735 S.Stk.push<IntegralAP<true>>(
1736 IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth));
1737 return true;
1738}
1739
1740template <PrimType Name, class T = typename PrimConv<Name>::T>
1741bool CastIntegralFloating(InterpState &S, CodePtr OpPC,
1742 const llvm::fltSemantics *Sem,
1743 llvm::RoundingMode RM) {
1744 const T &From = S.Stk.pop<T>();
1745 APSInt FromAP = From.toAPSInt();
1746 Floating Result;
1747
1748 auto Status = Floating::fromIntegral(Val: FromAP, Sem: *Sem, RM, Result);
1749 S.Stk.push<Floating>(Args&: Result);
1750
1751 return CheckFloatResult(S, OpPC, Result, Status);
1752}
1753
1754template <PrimType Name, class T = typename PrimConv<Name>::T>
1755bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) {
1756 const Floating &F = S.Stk.pop<Floating>();
1757
1758 if constexpr (std::is_same_v<T, Boolean>) {
1759 S.Stk.push<T>(T(F.isNonZero()));
1760 return true;
1761 } else {
1762 APSInt Result(std::max(8u, T::bitWidth()),
1763 /*IsUnsigned=*/!T::isSigned());
1764 auto Status = F.convertToInteger(Result);
1765
1766 // Float-to-Integral overflow check.
1767 if ((Status & APFloat::opStatus::opInvalidOp)) {
1768 const Expr *E = S.Current->getExpr(PC: OpPC);
1769 QualType Type = E->getType();
1770
1771 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
1772 if (S.noteUndefinedBehavior()) {
1773 S.Stk.push<T>(T(Result));
1774 return true;
1775 }
1776 return false;
1777 }
1778
1779 S.Stk.push<T>(T(Result));
1780 return CheckFloatResult(S, OpPC, Result: F, Status);
1781 }
1782}
1783
1784static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
1785 uint32_t BitWidth) {
1786 const Floating &F = S.Stk.pop<Floating>();
1787
1788 APSInt Result(BitWidth, /*IsUnsigned=*/true);
1789 auto Status = F.convertToInteger(Result);
1790
1791 // Float-to-Integral overflow check.
1792 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
1793 const Expr *E = S.Current->getExpr(PC: OpPC);
1794 QualType Type = E->getType();
1795
1796 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
1797 return S.noteUndefinedBehavior();
1798 }
1799
1800 S.Stk.push<IntegralAP<true>>(Args: IntegralAP<true>(Result));
1801 return CheckFloatResult(S, OpPC, Result: F, Status);
1802}
1803
1804static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
1805 uint32_t BitWidth) {
1806 const Floating &F = S.Stk.pop<Floating>();
1807
1808 APSInt Result(BitWidth, /*IsUnsigned=*/false);
1809 auto Status = F.convertToInteger(Result);
1810
1811 // Float-to-Integral overflow check.
1812 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
1813 const Expr *E = S.Current->getExpr(PC: OpPC);
1814 QualType Type = E->getType();
1815
1816 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
1817 return S.noteUndefinedBehavior();
1818 }
1819
1820 S.Stk.push<IntegralAP<true>>(Args: IntegralAP<true>(Result));
1821 return CheckFloatResult(S, OpPC, Result: F, Status);
1822}
1823
1824template <PrimType Name, class T = typename PrimConv<Name>::T>
1825bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
1826 const Pointer &Ptr = S.Stk.pop<Pointer>();
1827
1828 const SourceInfo &E = S.Current->getSource(PC: OpPC);
1829 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
1830 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
1831
1832 S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
1833 return true;
1834}
1835
1836static inline bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC,
1837 uint32_t BitWidth) {
1838 const Pointer &Ptr = S.Stk.pop<Pointer>();
1839
1840 const SourceInfo &E = S.Current->getSource(PC: OpPC);
1841 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
1842 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
1843
1844 S.Stk.push<IntegralAP<false>>(
1845 Args: IntegralAP<false>::from(Value: Ptr.getIntegerRepresentation(), NumBits: BitWidth));
1846 return true;
1847}
1848
1849static inline bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC,
1850 uint32_t BitWidth) {
1851 const Pointer &Ptr = S.Stk.pop<Pointer>();
1852
1853 const SourceInfo &E = S.Current->getSource(PC: OpPC);
1854 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
1855 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
1856
1857 S.Stk.push<IntegralAP<true>>(
1858 Args: IntegralAP<true>::from(Value: Ptr.getIntegerRepresentation(), NumBits: BitWidth));
1859 return true;
1860}
1861
1862//===----------------------------------------------------------------------===//
1863// Zero, Nullptr
1864//===----------------------------------------------------------------------===//
1865
1866template <PrimType Name, class T = typename PrimConv<Name>::T>
1867bool Zero(InterpState &S, CodePtr OpPC) {
1868 S.Stk.push<T>(T::zero());
1869 return true;
1870}
1871
1872static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1873 S.Stk.push<IntegralAP<false>>(Args: IntegralAP<false>::zero(BitWidth));
1874 return true;
1875}
1876
1877static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1878 S.Stk.push<IntegralAP<true>>(Args: IntegralAP<true>::zero(BitWidth));
1879 return true;
1880}
1881
1882template <PrimType Name, class T = typename PrimConv<Name>::T>
1883inline bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
1884 // Note: Desc can be null.
1885 S.Stk.push<T>(0, Desc);
1886 return true;
1887}
1888
1889//===----------------------------------------------------------------------===//
1890// This, ImplicitThis
1891//===----------------------------------------------------------------------===//
1892
1893inline bool This(InterpState &S, CodePtr OpPC) {
1894 // Cannot read 'this' in this mode.
1895 if (S.checkingPotentialConstantExpression()) {
1896 return false;
1897 }
1898
1899 const Pointer &This = S.Current->getThis();
1900 if (!CheckThis(S, OpPC, This))
1901 return false;
1902
1903 // Ensure the This pointer has been cast to the correct base.
1904 if (!This.isDummy()) {
1905 assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
1906 assert(This.getRecord());
1907 assert(
1908 This.getRecord()->getDecl() ==
1909 cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent());
1910 }
1911
1912 S.Stk.push<Pointer>(Args: This);
1913 return true;
1914}
1915
1916inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
1917 assert(S.Current->getFunction()->hasRVO());
1918 if (S.checkingPotentialConstantExpression())
1919 return false;
1920 S.Stk.push<Pointer>(Args: S.Current->getRVOPtr());
1921 return true;
1922}
1923
1924//===----------------------------------------------------------------------===//
1925// Shr, Shl
1926//===----------------------------------------------------------------------===//
1927
1928template <PrimType NameL, PrimType NameR>
1929inline bool Shr(InterpState &S, CodePtr OpPC) {
1930 using LT = typename PrimConv<NameL>::T;
1931 using RT = typename PrimConv<NameR>::T;
1932 const auto &RHS = S.Stk.pop<RT>();
1933 const auto &LHS = S.Stk.pop<LT>();
1934 const unsigned Bits = LHS.bitWidth();
1935
1936 if (!CheckShift(S, OpPC, LHS, RHS, Bits))
1937 return false;
1938
1939 // Limit the shift amount to Bits - 1. If this happened,
1940 // it has already been diagnosed by CheckShift() above,
1941 // but we still need to handle it.
1942 typename LT::AsUnsigned R;
1943 if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
1944 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
1945 LT::AsUnsigned::from(Bits - 1), Bits, &R);
1946 else
1947 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
1948 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
1949 S.Stk.push<LT>(LT::from(R));
1950 return true;
1951}
1952
1953template <PrimType NameL, PrimType NameR>
1954inline bool Shl(InterpState &S, CodePtr OpPC) {
1955 using LT = typename PrimConv<NameL>::T;
1956 using RT = typename PrimConv<NameR>::T;
1957 const auto &RHS = S.Stk.pop<RT>();
1958 const auto &LHS = S.Stk.pop<LT>();
1959 const unsigned Bits = LHS.bitWidth();
1960
1961 if (!CheckShift(S, OpPC, LHS, RHS, Bits))
1962 return false;
1963
1964 // Limit the shift amount to Bits - 1. If this happened,
1965 // it has already been diagnosed by CheckShift() above,
1966 // but we still need to handle it.
1967 typename LT::AsUnsigned R;
1968 if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
1969 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
1970 LT::AsUnsigned::from(Bits - 1), Bits, &R);
1971 else
1972 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
1973 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
1974
1975 S.Stk.push<LT>(LT::from(R));
1976 return true;
1977}
1978
1979//===----------------------------------------------------------------------===//
1980// NoRet
1981//===----------------------------------------------------------------------===//
1982
1983inline bool NoRet(InterpState &S, CodePtr OpPC) {
1984 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
1985 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
1986 return false;
1987}
1988
1989//===----------------------------------------------------------------------===//
1990// NarrowPtr, ExpandPtr
1991//===----------------------------------------------------------------------===//
1992
1993inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
1994 const Pointer &Ptr = S.Stk.pop<Pointer>();
1995 S.Stk.push<Pointer>(Args: Ptr.narrow());
1996 return true;
1997}
1998
1999inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
2000 const Pointer &Ptr = S.Stk.pop<Pointer>();
2001 S.Stk.push<Pointer>(Args: Ptr.expand());
2002 return true;
2003}
2004
2005// 1) Pops an integral value from the stack
2006// 2) Peeks a pointer
2007// 3) Pushes a new pointer that's a narrowed array
2008// element of the peeked pointer with the value
2009// from 1) added as offset.
2010//
2011// This leaves the original pointer on the stack and pushes a new one
2012// with the offset applied and narrowed.
2013template <PrimType Name, class T = typename PrimConv<Name>::T>
2014inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
2015 const T &Offset = S.Stk.pop<T>();
2016 const Pointer &Ptr = S.Stk.peek<Pointer>();
2017
2018 if (!Ptr.isZero()) {
2019 if (!CheckArray(S, OpPC, Ptr))
2020 return false;
2021
2022 if (Ptr.isDummy()) {
2023 S.Stk.push<Pointer>(Args: Ptr);
2024 return true;
2025 }
2026 }
2027
2028 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2029 return false;
2030
2031 return NarrowPtr(S, OpPC);
2032}
2033
2034template <PrimType Name, class T = typename PrimConv<Name>::T>
2035inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
2036 const T &Offset = S.Stk.pop<T>();
2037 const Pointer &Ptr = S.Stk.pop<Pointer>();
2038
2039 if (!Ptr.isZero()) {
2040 if (!CheckArray(S, OpPC, Ptr))
2041 return false;
2042
2043 if (Ptr.isDummy()) {
2044 S.Stk.push<Pointer>(Args: Ptr);
2045 return true;
2046 }
2047 }
2048
2049 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2050 return false;
2051
2052 return NarrowPtr(S, OpPC);
2053}
2054
2055template <PrimType Name, class T = typename PrimConv<Name>::T>
2056inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {
2057 const Pointer &Ptr = S.Stk.peek<Pointer>();
2058
2059 if (!CheckLoad(S, OpPC, Ptr))
2060 return false;
2061
2062 S.Stk.push<T>(Ptr.atIndex(Idx: Index).deref<T>());
2063 return true;
2064}
2065
2066template <PrimType Name, class T = typename PrimConv<Name>::T>
2067inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
2068 const Pointer &Ptr = S.Stk.pop<Pointer>();
2069
2070 if (!CheckLoad(S, OpPC, Ptr))
2071 return false;
2072
2073 S.Stk.push<T>(Ptr.atIndex(Idx: Index).deref<T>());
2074 return true;
2075}
2076
2077/// Just takes a pointer and checks if it's an incomplete
2078/// array type.
2079inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
2080 const Pointer &Ptr = S.Stk.pop<Pointer>();
2081
2082 if (Ptr.isZero() || Ptr.isDummy()) {
2083 S.Stk.push<Pointer>(Args: Ptr);
2084 return true;
2085 }
2086
2087 if (!Ptr.isUnknownSizeArray()) {
2088 S.Stk.push<Pointer>(Args: Ptr.atIndex(Idx: 0));
2089 return true;
2090 }
2091
2092 const SourceInfo &E = S.Current->getSource(PC: OpPC);
2093 S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
2094
2095 return false;
2096}
2097
2098inline bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
2099 uint32_t VarArgSize) {
2100 if (Func->hasThisPointer()) {
2101 size_t ArgSize = Func->getArgSize() + VarArgSize;
2102 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(Type: PT_Ptr) : 0);
2103 const Pointer &ThisPtr = S.Stk.peek<Pointer>(Offset: ThisOffset);
2104
2105 // If the current function is a lambda static invoker and
2106 // the function we're about to call is a lambda call operator,
2107 // skip the CheckInvoke, since the ThisPtr is a null pointer
2108 // anyway.
2109 if (!(S.Current->getFunction() &&
2110 S.Current->getFunction()->isLambdaStaticInvoker() &&
2111 Func->isLambdaCallOperator())) {
2112 if (!CheckInvoke(S, OpPC, Ptr: ThisPtr))
2113 return false;
2114 }
2115
2116 if (S.checkingPotentialConstantExpression())
2117 return false;
2118 }
2119
2120 if (!CheckCallable(S, OpPC, F: Func))
2121 return false;
2122
2123 if (!CheckCallDepth(S, OpPC))
2124 return false;
2125
2126 auto NewFrame = std::make_unique<InterpFrame>(args&: S, args&: Func, args&: OpPC, args&: VarArgSize);
2127 InterpFrame *FrameBefore = S.Current;
2128 S.Current = NewFrame.get();
2129
2130 APValue CallResult;
2131 // Note that we cannot assert(CallResult.hasValue()) here since
2132 // Ret() above only sets the APValue if the curent frame doesn't
2133 // have a caller set.
2134 if (Interpret(S, Result&: CallResult)) {
2135 NewFrame.release(); // Frame was delete'd already.
2136 assert(S.Current == FrameBefore);
2137 return true;
2138 }
2139
2140 // Interpreting the function failed somehow. Reset to
2141 // previous state.
2142 S.Current = FrameBefore;
2143 return false;
2144
2145 return false;
2146}
2147
2148inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
2149 uint32_t VarArgSize) {
2150 if (Func->hasThisPointer()) {
2151 size_t ArgSize = Func->getArgSize() + VarArgSize;
2152 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(Type: PT_Ptr) : 0);
2153
2154 const Pointer &ThisPtr = S.Stk.peek<Pointer>(Offset: ThisOffset);
2155
2156 // If the current function is a lambda static invoker and
2157 // the function we're about to call is a lambda call operator,
2158 // skip the CheckInvoke, since the ThisPtr is a null pointer
2159 // anyway.
2160 if (!(S.Current->getFunction() &&
2161 S.Current->getFunction()->isLambdaStaticInvoker() &&
2162 Func->isLambdaCallOperator())) {
2163 if (!CheckInvoke(S, OpPC, Ptr: ThisPtr))
2164 return false;
2165 }
2166
2167 if (S.checkingPotentialConstantExpression())
2168 return false;
2169 }
2170
2171 if (!CheckCallable(S, OpPC, F: Func))
2172 return false;
2173
2174 if (!CheckCallDepth(S, OpPC))
2175 return false;
2176
2177 auto NewFrame = std::make_unique<InterpFrame>(args&: S, args&: Func, args&: OpPC, args&: VarArgSize);
2178 InterpFrame *FrameBefore = S.Current;
2179 S.Current = NewFrame.get();
2180
2181 APValue CallResult;
2182 // Note that we cannot assert(CallResult.hasValue()) here since
2183 // Ret() above only sets the APValue if the curent frame doesn't
2184 // have a caller set.
2185 if (Interpret(S, Result&: CallResult)) {
2186 NewFrame.release(); // Frame was delete'd already.
2187 assert(S.Current == FrameBefore);
2188 return true;
2189 }
2190
2191 // Interpreting the function failed somehow. Reset to
2192 // previous state.
2193 S.Current = FrameBefore;
2194 return false;
2195}
2196
2197inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
2198 uint32_t VarArgSize) {
2199 assert(Func->hasThisPointer());
2200 assert(Func->isVirtual());
2201 size_t ArgSize = Func->getArgSize() + VarArgSize;
2202 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(Type: PT_Ptr) : 0);
2203 Pointer &ThisPtr = S.Stk.peek<Pointer>(Offset: ThisOffset);
2204
2205 QualType DynamicType = ThisPtr.getDeclDesc()->getType();
2206 const CXXRecordDecl *DynamicDecl;
2207 if (DynamicType->isPointerType() || DynamicType->isReferenceType())
2208 DynamicDecl = DynamicType->getPointeeCXXRecordDecl();
2209 else
2210 DynamicDecl = ThisPtr.getDeclDesc()->getType()->getAsCXXRecordDecl();
2211 const auto *StaticDecl = cast<CXXRecordDecl>(Val: Func->getParentDecl());
2212 const auto *InitialFunction = cast<CXXMethodDecl>(Val: Func->getDecl());
2213 const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
2214 DynamicDecl, StaticDecl, InitialFunction);
2215
2216 if (Overrider != InitialFunction) {
2217 // DR1872: An instantiated virtual constexpr function can't be called in a
2218 // constant expression (prior to C++20). We can still constant-fold such a
2219 // call.
2220 if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {
2221 const Expr *E = S.Current->getExpr(PC: OpPC);
2222 S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();
2223 }
2224
2225 Func = S.getContext().getOrCreateFunction(Overrider);
2226
2227 const CXXRecordDecl *ThisFieldDecl =
2228 ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
2229 if (Func->getParentDecl()->isDerivedFrom(Base: ThisFieldDecl)) {
2230 // If the function we call is further DOWN the hierarchy than the
2231 // FieldDesc of our pointer, just get the DeclDesc instead, which
2232 // is the furthest we might go up in the hierarchy.
2233 ThisPtr = ThisPtr.getDeclPtr();
2234 }
2235 }
2236
2237 return Call(S, OpPC, Func, VarArgSize);
2238}
2239
2240inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
2241 const CallExpr *CE) {
2242 auto NewFrame = std::make_unique<InterpFrame>(args&: S, args&: Func, args&: PC);
2243
2244 InterpFrame *FrameBefore = S.Current;
2245 S.Current = NewFrame.get();
2246
2247 if (InterpretBuiltin(S, OpPC: PC, F: Func, Call: CE)) {
2248 NewFrame.release();
2249 return true;
2250 }
2251 S.Current = FrameBefore;
2252 return false;
2253}
2254
2255inline bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
2256 const CallExpr *CE) {
2257 const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();
2258
2259 const Function *F = FuncPtr.getFunction();
2260 if (!F) {
2261 const Expr *E = S.Current->getExpr(PC: OpPC);
2262 S.FFDiag(E, diag::note_constexpr_null_callee)
2263 << const_cast<Expr *>(E) << E->getSourceRange();
2264 return false;
2265 }
2266
2267 if (!FuncPtr.isValid())
2268 return false;
2269
2270 assert(F);
2271
2272 // Check argument nullability state.
2273 if (F->hasNonNullAttr()) {
2274 if (!CheckNonNullArgs(S, OpPC, F, CE, ArgSize))
2275 return false;
2276 }
2277
2278 assert(ArgSize >= F->getWrittenArgSize());
2279 uint32_t VarArgSize = ArgSize - F->getWrittenArgSize();
2280
2281 if (F->isVirtual())
2282 return CallVirt(S, OpPC, Func: F, VarArgSize);
2283
2284 return Call(S, OpPC, Func: F, VarArgSize);
2285}
2286
2287inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
2288 assert(Func);
2289 S.Stk.push<FunctionPointer>(Args&: Func);
2290 return true;
2291}
2292
2293template <PrimType Name, class T = typename PrimConv<Name>::T>
2294inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2295 const T &IntVal = S.Stk.pop<T>();
2296
2297 S.Stk.push<Pointer>(Args: static_cast<uint64_t>(IntVal), Args&: Desc);
2298 return true;
2299}
2300
2301/// Just emit a diagnostic. The expression that caused emission of this
2302/// op is not valid in a constant context.
2303inline bool Invalid(InterpState &S, CodePtr OpPC) {
2304 const SourceLocation &Loc = S.Current->getLocation(PC: OpPC);
2305 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
2306 << S.Current->getRange(OpPC);
2307 return false;
2308}
2309
2310/// Do nothing and just abort execution.
2311inline bool Error(InterpState &S, CodePtr OpPC) { return false; }
2312
2313/// Same here, but only for casts.
2314inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) {
2315 const SourceLocation &Loc = S.Current->getLocation(PC: OpPC);
2316
2317 // FIXME: Support diagnosing other invalid cast kinds.
2318 if (Kind == CastKind::Reinterpret)
2319 S.FFDiag(Loc, diag::note_constexpr_invalid_cast)
2320 << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
2321 return false;
2322}
2323
2324inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC,
2325 const DeclRefExpr *DR) {
2326 assert(DR);
2327 return CheckDeclRef(S, OpPC, DR);
2328}
2329
2330inline bool Assume(InterpState &S, CodePtr OpPC) {
2331 const auto Val = S.Stk.pop<Boolean>();
2332
2333 if (Val)
2334 return true;
2335
2336 // Else, diagnose.
2337 const SourceLocation &Loc = S.Current->getLocation(PC: OpPC);
2338 S.CCEDiag(Loc, diag::note_constexpr_assumption_failed);
2339 return false;
2340}
2341
2342template <PrimType Name, class T = typename PrimConv<Name>::T>
2343inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
2344 llvm::SmallVector<int64_t> ArrayIndices;
2345 for (size_t I = 0; I != E->getNumExpressions(); ++I)
2346 ArrayIndices.emplace_back(Args: S.Stk.pop<int64_t>());
2347
2348 int64_t Result;
2349 if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
2350 return false;
2351
2352 S.Stk.push<T>(T::from(Result));
2353
2354 return true;
2355}
2356
2357template <PrimType Name, class T = typename PrimConv<Name>::T>
2358inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
2359 const T &Arg = S.Stk.peek<T>();
2360 if (!Arg.isZero())
2361 return true;
2362
2363 const SourceLocation &Loc = S.Current->getLocation(PC: OpPC);
2364 S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
2365
2366 return false;
2367}
2368
2369/// OldPtr -> Integer -> NewPtr.
2370template <PrimType TIn, PrimType TOut>
2371inline bool DecayPtr(InterpState &S, CodePtr OpPC) {
2372 static_assert(isPtrType(T: TIn) && isPtrType(T: TOut));
2373 using FromT = typename PrimConv<TIn>::T;
2374 using ToT = typename PrimConv<TOut>::T;
2375
2376 const FromT &OldPtr = S.Stk.pop<FromT>();
2377 S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
2378 return true;
2379}
2380
2381//===----------------------------------------------------------------------===//
2382// Read opcode arguments
2383//===----------------------------------------------------------------------===//
2384
2385template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
2386 if constexpr (std::is_pointer<T>::value) {
2387 uint32_t ID = OpPC.read<uint32_t>();
2388 return reinterpret_cast<T>(S.P.getNativePointer(Idx: ID));
2389 } else {
2390 return OpPC.read<T>();
2391 }
2392}
2393
2394template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
2395 Floating F = Floating::deserialize(Buff: *OpPC);
2396 OpPC += align(Size: F.bytesToSerialize());
2397 return F;
2398}
2399
2400template <>
2401inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
2402 CodePtr &OpPC) {
2403 IntegralAP<false> I = IntegralAP<false>::deserialize(Buff: *OpPC);
2404 OpPC += align(Size: I.bytesToSerialize());
2405 return I;
2406}
2407
2408template <>
2409inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
2410 CodePtr &OpPC) {
2411 IntegralAP<true> I = IntegralAP<true>::deserialize(Buff: *OpPC);
2412 OpPC += align(Size: I.bytesToSerialize());
2413 return I;
2414}
2415
2416} // namespace interp
2417} // namespace clang
2418
2419#endif
2420

source code of clang/lib/AST/Interp/Interp.h