clang 19.0.0git
Interp.h
Go to the documentation of this file.
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"
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,
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,
72
73/// Checks if Ptr is a one-past-the-end pointer.
74bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
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(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(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(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>(S.Current->getExpr(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(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
179 const SourceInfo &Loc = S.Current->getSource(OpPC);
180 const Expr *E = S.Current->getExpr(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>
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)
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)
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(OpPC);
291 QualType Type = E->getType();
292 if (S.checkingForUndefinedBehavior()) {
293 SmallString<32> Trunc;
294 Value.trunc(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
324 auto Status = Floating::add(LHS, RHS, RM, &Result);
325 S.Stk.push<Floating>(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
342 auto Status = Floating::sub(LHS, RHS, RM, &Result);
343 S.Stk.push<Floating>(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
360 auto Status = Floating::mul(LHS, RHS, RM, &Result);
361 S.Stk.push<Floating>(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
463 auto Status = Floating::div(LHS, RHS, RM, &Result);
464 S.Stk.push<Floating>(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(BoolT::from(Val, Bits), &R);
479
480 S.Stk.push<BoolT>(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(OpPC);
504 QualType Type = E->getType();
505
506 if (S.checkingForUndefinedBehavior()) {
507 SmallString<32> Trunc;
508 NegatedValue.trunc(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(OpPC);
568 QualType Type = E->getType();
569 if (S.checkingForUndefinedBehavior()) {
570 SmallString<32> Trunc;
571 APResult.trunc(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_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_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_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_Decrement))
637 return false;
638
639 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
640}
641
642template <IncDecOp Op, PushVal DoPush>
644 llvm::RoundingMode RM) {
645 Floating Value = Ptr.deref<Floating>();
647
648 if constexpr (DoPush == PushVal::Yes)
649 S.Stk.push<Floating>(Value);
650
651 llvm::APFloat::opStatus Status;
652 if constexpr (Op == IncDecOp::Inc)
653 Status = Floating::increment(Value, RM, &Result);
654 else
655 Status = Floating::decrement(Value, RM, &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_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_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_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_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>
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>
736 return CmpHelper<T>(S, OpPC, Fn);
737}
738
739/// Function pointers cannot be compared in an ordered way.
740template <>
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(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 <>
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(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>(Boolean::from(Fn(LHS.compare(RHS))));
770 return true;
771}
772
773template <>
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(LHS, RHS)) {
780 const SourceInfo &Loc = S.Current->getSource(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>(BoolT::from(Fn(Compare(VL, VR))));
789 return true;
790 }
791}
792
793template <>
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>(BoolT::from(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(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(LHS, RHS)) {
816 S.Stk.push<BoolT>(BoolT::from(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.isArrayRoot())
827 VL = LHS.atIndex(0).getByteOffset();
828 if (!RHS.isZero() && RHS.isArrayRoot())
829 VR = RHS.atIndex(0).getByteOffset();
830
831 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, 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) {
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(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(CmpInfo->makeWeakResult(CmpResult));
862 assert(CmpValueInfo);
863 assert(CmpValueInfo->hasValidIntValue());
864 return SetThreeWayComparisonField(S, OpPC, P, 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) {
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) {
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 ||
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) {
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) {
901 });
902}
903
904//===----------------------------------------------------------------------===//
905// InRange
906//===----------------------------------------------------------------------===//
907
908template <PrimType Name, class T = typename PrimConv<Name>::T>
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(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, Obj, CSK_Field))
987 return false;
988 if (!CheckRange(S, OpPC, Obj, CSK_Field))
989 return false;
990 const Pointer &Field = Obj.atField(I);
991 if (!CheckLoad(S, OpPC, 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, Obj, CSK_Field))
1002 return false;
1003 if (!CheckRange(S, OpPC, Obj, CSK_Field))
1004 return false;
1005 const Pointer &Field = Obj.atField(I);
1006 if (!CheckStore(S, OpPC, 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, Obj, CSK_Field))
1019 return false;
1020 if (!CheckRange(S, OpPC, Obj, CSK_Field))
1021 return false;
1022 const Pointer &Field = Obj.atField(I);
1023 if (!CheckLoad(S, OpPC, 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(I);
1037 if (!CheckLoad(S, OpPC, 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(I);
1052 if (!CheckStore(S, OpPC, 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(I);
1061 if (!CheckConstant(S, OpPC, 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(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(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(true);
1107 *Cached = APV;
1108
1109 const Pointer &P = S.P.getGlobal(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
1120 const LifetimeExtendedTemporaryDecl *Temp) {
1121 assert(Temp);
1122 const Pointer &P = S.Stk.peek<Pointer>();
1123 APValue *Cached = Temp->getOrCreateValue(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(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(FieldOffset);
1158 const auto &Value = S.Stk.pop<T>();
1159 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(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(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(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(F->Offset);
1196 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(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(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>(S.Current->getLocalPointer(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>(S.Current->getParamPointer(I));
1227 return true;
1228}
1229
1230inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1231 S.Stk.push<Pointer>(S.P.getPtrGlobal(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_Field))
1242 return false;
1243
1244 if (!CheckExtern(S, OpPC, Ptr))
1245 return false;
1246 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1247 return false;
1248 if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1249 return false;
1250
1251 if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
1252 return false;
1253
1254 S.Stk.push<Pointer>(Ptr.atField(Off));
1255 return true;
1256}
1257
1258inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1259 if (S.checkingPotentialConstantExpression())
1260 return false;
1261 const Pointer &This = S.Current->getThis();
1262 if (!CheckThis(S, OpPC, This))
1263 return false;
1264 S.Stk.push<Pointer>(This.atField(Off));
1265 return true;
1266}
1267
1268inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1269 const Pointer &Ptr = S.Stk.pop<Pointer>();
1270 if (!CheckNull(S, OpPC, Ptr, CSK_Field))
1271 return false;
1272 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1273 return false;
1274 Pointer Field = Ptr.atField(Off);
1275 Ptr.deactivate();
1276 Field.activate();
1277 S.Stk.push<Pointer>(std::move(Field));
1278 return true;
1279}
1280
1281inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1282 if (S.checkingPotentialConstantExpression())
1283 return false;
1284 const Pointer &This = S.Current->getThis();
1285 if (!CheckThis(S, OpPC, This))
1286 return false;
1287 Pointer Field = This.atField(Off);
1288 This.deactivate();
1289 Field.activate();
1290 S.Stk.push<Pointer>(std::move(Field));
1291 return true;
1292}
1293
1294inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1295 const Pointer &Ptr = S.Stk.pop<Pointer>();
1296 if (!CheckNull(S, OpPC, Ptr, CSK_Derived))
1297 return false;
1298 if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
1299 return false;
1300 S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
1301 return true;
1302}
1303
1304inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1305 const Pointer &Ptr = S.Stk.peek<Pointer>();
1306 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1307 return false;
1308 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1309 return false;
1310 S.Stk.push<Pointer>(Ptr.atField(Off));
1311 return true;
1312}
1313
1314inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1315 const Pointer &Ptr = S.Stk.pop<Pointer>();
1316 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1317 return false;
1318 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1319 return false;
1320 S.Stk.push<Pointer>(Ptr.atField(Off));
1321 return true;
1322}
1323
1324inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1325 if (S.checkingPotentialConstantExpression())
1326 return false;
1327 const Pointer &This = S.Current->getThis();
1328 if (!CheckThis(S, OpPC, This))
1329 return false;
1330 S.Stk.push<Pointer>(This.atField(Off));
1331 return true;
1332}
1333
1334inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {
1335 const Pointer &Ptr = S.Stk.pop<Pointer>();
1336 if (Ptr.canBeInitialized())
1337 Ptr.initialize();
1338 return true;
1339}
1340
1341inline bool FinishInit(InterpState &S, CodePtr OpPC) {
1342 const Pointer &Ptr = S.Stk.peek<Pointer>();
1343
1344 if (Ptr.canBeInitialized())
1345 Ptr.initialize();
1346 return true;
1347}
1348
1349inline bool Dump(InterpState &S, CodePtr OpPC) {
1350 S.Stk.dump();
1351 return true;
1352}
1353
1354inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1355 const Pointer &Ptr) {
1356 Pointer Base = Ptr;
1357 while (Base.isBaseClass())
1358 Base = Base.getBase();
1359
1360 const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(Decl);
1361 S.Stk.push<Pointer>(Base.atField(VirtBase->Offset));
1362 return true;
1363}
1364
1366 const RecordDecl *D) {
1367 assert(D);
1368 const Pointer &Ptr = S.Stk.pop<Pointer>();
1369 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1370 return false;
1371 if (Ptr.isDummy()) // FIXME: Once we have type info for dummy pointers, this
1372 // needs to go.
1373 return false;
1374 return VirtBaseHelper(S, OpPC, D, Ptr);
1375}
1376
1378 const RecordDecl *D) {
1379 assert(D);
1380 if (S.checkingPotentialConstantExpression())
1381 return false;
1382 const Pointer &This = S.Current->getThis();
1383 if (!CheckThis(S, OpPC, This))
1384 return false;
1385 return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
1386}
1387
1388//===----------------------------------------------------------------------===//
1389// Load, Store, Init
1390//===----------------------------------------------------------------------===//
1391
1392template <PrimType Name, class T = typename PrimConv<Name>::T>
1393bool Load(InterpState &S, CodePtr OpPC) {
1394 const Pointer &Ptr = S.Stk.peek<Pointer>();
1395 if (!CheckLoad(S, OpPC, Ptr))
1396 return false;
1397 if (!Ptr.isBlockPointer())
1398 return false;
1399 S.Stk.push<T>(Ptr.deref<T>());
1400 return true;
1401}
1402
1403template <PrimType Name, class T = typename PrimConv<Name>::T>
1405 const Pointer &Ptr = S.Stk.pop<Pointer>();
1406 if (!CheckLoad(S, OpPC, Ptr))
1407 return false;
1408 if (!Ptr.isBlockPointer())
1409 return false;
1410 S.Stk.push<T>(Ptr.deref<T>());
1411 return true;
1412}
1413
1414template <PrimType Name, class T = typename PrimConv<Name>::T>
1415bool Store(InterpState &S, CodePtr OpPC) {
1416 const T &Value = S.Stk.pop<T>();
1417 const Pointer &Ptr = S.Stk.peek<Pointer>();
1418 if (!CheckStore(S, OpPC, Ptr))
1419 return false;
1420 if (Ptr.canBeInitialized())
1421 Ptr.initialize();
1422 Ptr.deref<T>() = Value;
1423 return true;
1424}
1425
1426template <PrimType Name, class T = typename PrimConv<Name>::T>
1428 const T &Value = S.Stk.pop<T>();
1429 const Pointer &Ptr = S.Stk.pop<Pointer>();
1430 if (!CheckStore(S, OpPC, Ptr))
1431 return false;
1432 if (Ptr.canBeInitialized())
1433 Ptr.initialize();
1434 Ptr.deref<T>() = Value;
1435 return true;
1436}
1437
1438template <PrimType Name, class T = typename PrimConv<Name>::T>
1440 const T &Value = S.Stk.pop<T>();
1441 const Pointer &Ptr = S.Stk.peek<Pointer>();
1442 if (!CheckStore(S, OpPC, Ptr))
1443 return false;
1444 if (Ptr.canBeInitialized())
1445 Ptr.initialize();
1446 if (const auto *FD = Ptr.getField())
1447 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1448 else
1449 Ptr.deref<T>() = Value;
1450 return true;
1451}
1452
1453template <PrimType Name, class T = typename PrimConv<Name>::T>
1455 const T &Value = S.Stk.pop<T>();
1456 const Pointer &Ptr = S.Stk.pop<Pointer>();
1457 if (!CheckStore(S, OpPC, Ptr))
1458 return false;
1459 if (Ptr.canBeInitialized())
1460 Ptr.initialize();
1461 if (const auto *FD = Ptr.getField())
1462 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1463 else
1464 Ptr.deref<T>() = Value;
1465 return true;
1466}
1467
1468template <PrimType Name, class T = typename PrimConv<Name>::T>
1469bool Init(InterpState &S, CodePtr OpPC) {
1470 const T &Value = S.Stk.pop<T>();
1471 const Pointer &Ptr = S.Stk.peek<Pointer>();
1472 if (!CheckInit(S, OpPC, Ptr)) {
1473 assert(false);
1474 return false;
1475 }
1476 Ptr.initialize();
1477 new (&Ptr.deref<T>()) T(Value);
1478 return true;
1479}
1480
1481template <PrimType Name, class T = typename PrimConv<Name>::T>
1483 const T &Value = S.Stk.pop<T>();
1484 const Pointer &Ptr = S.Stk.pop<Pointer>();
1485 if (!CheckInit(S, OpPC, Ptr))
1486 return false;
1487 Ptr.initialize();
1488 new (&Ptr.deref<T>()) T(Value);
1489 return true;
1490}
1491
1492/// 1) Pops the value from the stack
1493/// 2) Peeks a pointer and gets its index \Idx
1494/// 3) Sets the value on the pointer, leaving the pointer on the stack.
1495template <PrimType Name, class T = typename PrimConv<Name>::T>
1496bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1497 const T &Value = S.Stk.pop<T>();
1498 const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
1499 if (Ptr.isUnknownSizeArray())
1500 return false;
1501 if (!CheckInit(S, OpPC, Ptr))
1502 return false;
1503 Ptr.initialize();
1504 new (&Ptr.deref<T>()) T(Value);
1505 return true;
1506}
1507
1508/// The same as InitElem, but pops the pointer as well.
1509template <PrimType Name, class T = typename PrimConv<Name>::T>
1510bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1511 const T &Value = S.Stk.pop<T>();
1512 const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
1513 if (Ptr.isUnknownSizeArray())
1514 return false;
1515 if (!CheckInit(S, OpPC, Ptr))
1516 return false;
1517 Ptr.initialize();
1518 new (&Ptr.deref<T>()) T(Value);
1519 return true;
1520}
1521
1522inline bool Memcpy(InterpState &S, CodePtr OpPC) {
1523 const Pointer &Src = S.Stk.pop<Pointer>();
1524 Pointer &Dest = S.Stk.peek<Pointer>();
1525
1526 if (!CheckLoad(S, OpPC, Src))
1527 return false;
1528
1529 return DoMemcpy(S, OpPC, Src, Dest);
1530}
1531
1532//===----------------------------------------------------------------------===//
1533// AddOffset, SubOffset
1534//===----------------------------------------------------------------------===//
1535
1536template <class T, ArithOp Op>
1537bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
1538 const Pointer &Ptr) {
1539 if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
1540 return false;
1541
1542 // A zero offset does not change the pointer.
1543 if (Offset.isZero()) {
1544 S.Stk.push<Pointer>(Ptr);
1545 return true;
1546 }
1547
1548 if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) {
1549 // The CheckNull will have emitted a note already, but we only
1550 // abort in C++, since this is fine in C.
1551 if (S.getLangOpts().CPlusPlus)
1552 return false;
1553 }
1554
1555 // Arrays of unknown bounds cannot have pointers into them.
1556 if (!CheckArray(S, OpPC, Ptr))
1557 return false;
1558
1559 uint64_t Index = Ptr.getIndex();
1560 uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());
1561
1562 bool Invalid = false;
1563 // Helper to report an invalid offset, computed as APSInt.
1564 auto DiagInvalidOffset = [&]() -> void {
1565 const unsigned Bits = Offset.bitWidth();
1566 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false);
1567 APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true),
1568 /*IsUnsigned=*/false);
1569 APSInt NewIndex =
1570 (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1571 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1572 << NewIndex << /*array*/ static_cast<int>(!Ptr.inArray()) << MaxIndex;
1573 Invalid = true;
1574 };
1575
1576 if (Ptr.isBlockPointer()) {
1577 uint64_t IOffset = static_cast<uint64_t>(Offset);
1578 uint64_t MaxOffset = MaxIndex - Index;
1579
1580 if constexpr (Op == ArithOp::Add) {
1581 // If the new offset would be negative, bail out.
1582 if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
1583 DiagInvalidOffset();
1584
1585 // If the new offset would be out of bounds, bail out.
1586 if (Offset.isPositive() && IOffset > MaxOffset)
1587 DiagInvalidOffset();
1588 } else {
1589 // If the new offset would be negative, bail out.
1590 if (Offset.isPositive() && Index < IOffset)
1591 DiagInvalidOffset();
1592
1593 // If the new offset would be out of bounds, bail out.
1594 if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
1595 DiagInvalidOffset();
1596 }
1597 }
1598
1599 if (Invalid && S.getLangOpts().CPlusPlus)
1600 return false;
1601
1602 // Offset is valid - compute it on unsigned.
1603 int64_t WideIndex = static_cast<int64_t>(Index);
1604 int64_t WideOffset = static_cast<int64_t>(Offset);
1605 int64_t Result;
1606 if constexpr (Op == ArithOp::Add)
1607 Result = WideIndex + WideOffset;
1608 else
1609 Result = WideIndex - WideOffset;
1610
1611 S.Stk.push<Pointer>(Ptr.atIndex(static_cast<uint64_t>(Result)));
1612 return true;
1613}
1614
1615template <PrimType Name, class T = typename PrimConv<Name>::T>
1617 const T &Offset = S.Stk.pop<T>();
1618 const Pointer &Ptr = S.Stk.pop<Pointer>();
1619 return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
1620}
1621
1622template <PrimType Name, class T = typename PrimConv<Name>::T>
1624 const T &Offset = S.Stk.pop<T>();
1625 const Pointer &Ptr = S.Stk.pop<Pointer>();
1626 return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);
1627}
1628
1629template <ArithOp Op>
1630static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
1631 const Pointer &Ptr) {
1632 if (Ptr.isDummy())
1633 return false;
1634
1635 using OneT = Integral<8, false>;
1636
1637 const Pointer &P = Ptr.deref<Pointer>();
1638 if (!CheckNull(S, OpPC, P, CSK_ArrayIndex))
1639 return false;
1640
1641 // Get the current value on the stack.
1642 S.Stk.push<Pointer>(P);
1643
1644 // Now the current Ptr again and a constant 1.
1645 OneT One = OneT::from(1);
1646 if (!OffsetHelper<OneT, Op>(S, OpPC, One, P))
1647 return false;
1648
1649 // Store the new value.
1650 Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
1651 return true;
1652}
1653
1654static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
1655 const Pointer &Ptr = S.Stk.pop<Pointer>();
1656
1657 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
1658 return false;
1659
1660 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
1661}
1662
1663static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
1664 const Pointer &Ptr = S.Stk.pop<Pointer>();
1665
1666 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
1667 return false;
1668
1669 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
1670}
1671
1672/// 1) Pops a Pointer from the stack.
1673/// 2) Pops another Pointer from the stack.
1674/// 3) Pushes the different of the indices of the two pointers on the stack.
1675template <PrimType Name, class T = typename PrimConv<Name>::T>
1676inline bool SubPtr(InterpState &S, CodePtr OpPC) {
1677 const Pointer &LHS = S.Stk.pop<Pointer>();
1678 const Pointer &RHS = S.Stk.pop<Pointer>();
1679
1680 if (RHS.isZero()) {
1681 S.Stk.push<T>(T::from(LHS.getIndex()));
1682 return true;
1683 }
1684
1685 if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
1686 // TODO: Diagnose.
1687 return false;
1688 }
1689
1690 if (LHS.isZero() && RHS.isZero()) {
1691 S.Stk.push<T>();
1692 return true;
1693 }
1694
1695 T A = T::from(LHS.getIndex());
1696 T B = T::from(RHS.getIndex());
1697 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
1698}
1699
1700//===----------------------------------------------------------------------===//
1701// Destroy
1702//===----------------------------------------------------------------------===//
1703
1704inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
1705 S.Current->destroy(I);
1706 return true;
1707}
1708
1709//===----------------------------------------------------------------------===//
1710// Cast, CastFP
1711//===----------------------------------------------------------------------===//
1712
1713template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
1714 using T = typename PrimConv<TIn>::T;
1715 using U = typename PrimConv<TOut>::T;
1716 S.Stk.push<U>(U::from(S.Stk.pop<T>()));
1717 return true;
1718}
1719
1720/// 1) Pops a Floating from the stack.
1721/// 2) Pushes a new floating on the stack that uses the given semantics.
1722inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
1723 llvm::RoundingMode RM) {
1724 Floating F = S.Stk.pop<Floating>();
1725 Floating Result = F.toSemantics(Sem, RM);
1726 S.Stk.push<Floating>(Result);
1727 return true;
1728}
1729
1730/// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
1731/// to know what bitwidth the result should be.
1732template <PrimType Name, class T = typename PrimConv<Name>::T>
1733bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1734 S.Stk.push<IntegralAP<false>>(
1735 IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth));
1736 return true;
1737}
1738
1739template <PrimType Name, class T = typename PrimConv<Name>::T>
1740bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1741 S.Stk.push<IntegralAP<true>>(
1742 IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth));
1743 return true;
1744}
1745
1746template <PrimType Name, class T = typename PrimConv<Name>::T>
1748 const llvm::fltSemantics *Sem,
1749 llvm::RoundingMode RM) {
1750 const T &From = S.Stk.pop<T>();
1751 APSInt FromAP = From.toAPSInt();
1753
1754 auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
1755 S.Stk.push<Floating>(Result);
1756
1757 return CheckFloatResult(S, OpPC, Result, Status);
1758}
1759
1760template <PrimType Name, class T = typename PrimConv<Name>::T>
1762 const Floating &F = S.Stk.pop<Floating>();
1763
1764 if constexpr (std::is_same_v<T, Boolean>) {
1765 S.Stk.push<T>(T(F.isNonZero()));
1766 return true;
1767 } else {
1768 APSInt Result(std::max(8u, T::bitWidth()),
1769 /*IsUnsigned=*/!T::isSigned());
1770 auto Status = F.convertToInteger(Result);
1771
1772 // Float-to-Integral overflow check.
1773 if ((Status & APFloat::opStatus::opInvalidOp)) {
1774 const Expr *E = S.Current->getExpr(OpPC);
1775 QualType Type = E->getType();
1776
1777 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
1778 if (S.noteUndefinedBehavior()) {
1779 S.Stk.push<T>(T(Result));
1780 return true;
1781 }
1782 return false;
1783 }
1784
1785 S.Stk.push<T>(T(Result));
1786 return CheckFloatResult(S, OpPC, F, Status);
1787 }
1788}
1789
1790static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
1791 uint32_t BitWidth) {
1792 const Floating &F = S.Stk.pop<Floating>();
1793
1794 APSInt Result(BitWidth, /*IsUnsigned=*/true);
1795 auto Status = F.convertToInteger(Result);
1796
1797 // Float-to-Integral overflow check.
1798 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
1799 const Expr *E = S.Current->getExpr(OpPC);
1800 QualType Type = E->getType();
1801
1802 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
1803 return S.noteUndefinedBehavior();
1804 }
1805
1807 return CheckFloatResult(S, OpPC, F, Status);
1808}
1809
1810static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
1811 uint32_t BitWidth) {
1812 const Floating &F = S.Stk.pop<Floating>();
1813
1814 APSInt Result(BitWidth, /*IsUnsigned=*/false);
1815 auto Status = F.convertToInteger(Result);
1816
1817 // Float-to-Integral overflow check.
1818 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
1819 const Expr *E = S.Current->getExpr(OpPC);
1820 QualType Type = E->getType();
1821
1822 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
1823 return S.noteUndefinedBehavior();
1824 }
1825
1827 return CheckFloatResult(S, OpPC, F, Status);
1828}
1829
1830template <PrimType Name, class T = typename PrimConv<Name>::T>
1832 const Pointer &Ptr = S.Stk.pop<Pointer>();
1833
1834 const SourceInfo &E = S.Current->getSource(OpPC);
1835 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
1836 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
1837
1838 S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
1839 return true;
1840}
1841
1842static inline bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC,
1843 uint32_t BitWidth) {
1844 const Pointer &Ptr = S.Stk.pop<Pointer>();
1845
1846 const SourceInfo &E = S.Current->getSource(OpPC);
1847 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
1848 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
1849
1850 S.Stk.push<IntegralAP<false>>(
1852 return true;
1853}
1854
1855static inline bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC,
1856 uint32_t BitWidth) {
1857 const Pointer &Ptr = S.Stk.pop<Pointer>();
1858
1859 const SourceInfo &E = S.Current->getSource(OpPC);
1860 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
1861 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
1862
1863 S.Stk.push<IntegralAP<true>>(
1865 return true;
1866}
1867
1868//===----------------------------------------------------------------------===//
1869// Zero, Nullptr
1870//===----------------------------------------------------------------------===//
1871
1872template <PrimType Name, class T = typename PrimConv<Name>::T>
1873bool Zero(InterpState &S, CodePtr OpPC) {
1874 S.Stk.push<T>(T::zero());
1875 return true;
1876}
1877
1878static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1879 S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth));
1880 return true;
1881}
1882
1883static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1884 S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth));
1885 return true;
1886}
1887
1888template <PrimType Name, class T = typename PrimConv<Name>::T>
1889inline bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
1890 // Note: Desc can be null.
1891 S.Stk.push<T>(0, Desc);
1892 return true;
1893}
1894
1895//===----------------------------------------------------------------------===//
1896// This, ImplicitThis
1897//===----------------------------------------------------------------------===//
1898
1899inline bool This(InterpState &S, CodePtr OpPC) {
1900 // Cannot read 'this' in this mode.
1901 if (S.checkingPotentialConstantExpression()) {
1902 return false;
1903 }
1904
1905 const Pointer &This = S.Current->getThis();
1906 if (!CheckThis(S, OpPC, This))
1907 return false;
1908
1909 // Ensure the This pointer has been cast to the correct base.
1910 if (!This.isDummy()) {
1911 assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
1912 assert(This.getRecord());
1913 assert(
1914 This.getRecord()->getDecl() ==
1915 cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent());
1916 }
1917
1918 S.Stk.push<Pointer>(This);
1919 return true;
1920}
1921
1922inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
1923 assert(S.Current->getFunction()->hasRVO());
1924 if (S.checkingPotentialConstantExpression())
1925 return false;
1926 S.Stk.push<Pointer>(S.Current->getRVOPtr());
1927 return true;
1928}
1929
1930//===----------------------------------------------------------------------===//
1931// Shr, Shl
1932//===----------------------------------------------------------------------===//
1933
1934template <PrimType NameL, PrimType NameR>
1935inline bool Shr(InterpState &S, CodePtr OpPC) {
1936 using LT = typename PrimConv<NameL>::T;
1937 using RT = typename PrimConv<NameR>::T;
1938 auto RHS = S.Stk.pop<RT>();
1939 const auto &LHS = S.Stk.pop<LT>();
1940 const unsigned Bits = LHS.bitWidth();
1941
1942 // OpenCL 6.3j: shift values are effectively % word size of LHS.
1943 if (S.getLangOpts().OpenCL)
1944 RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
1945 RHS.bitWidth(), &RHS);
1946
1947 if (!CheckShift(S, OpPC, LHS, RHS, Bits))
1948 return false;
1949
1950 // Limit the shift amount to Bits - 1. If this happened,
1951 // it has already been diagnosed by CheckShift() above,
1952 // but we still need to handle it.
1953 typename LT::AsUnsigned R;
1954 if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
1955 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
1956 LT::AsUnsigned::from(Bits - 1), Bits, &R);
1957 else
1958 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
1959 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
1960 S.Stk.push<LT>(LT::from(R));
1961 return true;
1962}
1963
1964template <PrimType NameL, PrimType NameR>
1965inline bool Shl(InterpState &S, CodePtr OpPC) {
1966 using LT = typename PrimConv<NameL>::T;
1967 using RT = typename PrimConv<NameR>::T;
1968 auto RHS = S.Stk.pop<RT>();
1969 const auto &LHS = S.Stk.pop<LT>();
1970 const unsigned Bits = LHS.bitWidth();
1971
1972 // OpenCL 6.3j: shift values are effectively % word size of LHS.
1973 if (S.getLangOpts().OpenCL)
1974 RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
1975 RHS.bitWidth(), &RHS);
1976
1977 if (!CheckShift(S, OpPC, LHS, RHS, Bits))
1978 return false;
1979
1980 // Limit the shift amount to Bits - 1. If this happened,
1981 // it has already been diagnosed by CheckShift() above,
1982 // but we still need to handle it.
1983 typename LT::AsUnsigned R;
1984 if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
1985 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
1986 LT::AsUnsigned::from(Bits - 1), Bits, &R);
1987 else
1988 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
1989 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
1990
1991 S.Stk.push<LT>(LT::from(R));
1992 return true;
1993}
1994
1995//===----------------------------------------------------------------------===//
1996// NoRet
1997//===----------------------------------------------------------------------===//
1998
1999inline bool NoRet(InterpState &S, CodePtr OpPC) {
2000 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
2001 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
2002 return false;
2003}
2004
2005//===----------------------------------------------------------------------===//
2006// NarrowPtr, ExpandPtr
2007//===----------------------------------------------------------------------===//
2008
2009inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
2010 const Pointer &Ptr = S.Stk.pop<Pointer>();
2011 S.Stk.push<Pointer>(Ptr.narrow());
2012 return true;
2013}
2014
2015inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
2016 const Pointer &Ptr = S.Stk.pop<Pointer>();
2017 S.Stk.push<Pointer>(Ptr.expand());
2018 return true;
2019}
2020
2021// 1) Pops an integral value from the stack
2022// 2) Peeks a pointer
2023// 3) Pushes a new pointer that's a narrowed array
2024// element of the peeked pointer with the value
2025// from 1) added as offset.
2026//
2027// This leaves the original pointer on the stack and pushes a new one
2028// with the offset applied and narrowed.
2029template <PrimType Name, class T = typename PrimConv<Name>::T>
2030inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
2031 const T &Offset = S.Stk.pop<T>();
2032 const Pointer &Ptr = S.Stk.peek<Pointer>();
2033
2034 if (!Ptr.isZero()) {
2035 if (!CheckArray(S, OpPC, Ptr))
2036 return false;
2037 }
2038
2039 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2040 return false;
2041
2042 return NarrowPtr(S, OpPC);
2043}
2044
2045template <PrimType Name, class T = typename PrimConv<Name>::T>
2046inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
2047 const T &Offset = S.Stk.pop<T>();
2048 const Pointer &Ptr = S.Stk.pop<Pointer>();
2049
2050 if (!Ptr.isZero()) {
2051 if (!CheckArray(S, OpPC, Ptr))
2052 return false;
2053 }
2054
2055 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2056 return false;
2057
2058 return NarrowPtr(S, OpPC);
2059}
2060
2061template <PrimType Name, class T = typename PrimConv<Name>::T>
2062inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {
2063 const Pointer &Ptr = S.Stk.peek<Pointer>();
2064
2065 if (!CheckLoad(S, OpPC, Ptr))
2066 return false;
2067
2068 S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
2069 return true;
2070}
2071
2072template <PrimType Name, class T = typename PrimConv<Name>::T>
2073inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
2074 const Pointer &Ptr = S.Stk.pop<Pointer>();
2075
2076 if (!CheckLoad(S, OpPC, Ptr))
2077 return false;
2078
2079 S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
2080 return true;
2081}
2082
2083template <PrimType Name, class T = typename PrimConv<Name>::T>
2084inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex, uint32_t DestIndex, uint32_t Size) {
2085 const auto &SrcPtr = S.Stk.pop<Pointer>();
2086 const auto &DestPtr = S.Stk.peek<Pointer>();
2087
2088 for (uint32_t I = 0; I != Size; ++I) {
2089 const Pointer &SP = SrcPtr.atIndex(SrcIndex + I);
2090
2091 if (!CheckLoad(S, OpPC, SP))
2092 return false;
2093
2094 const Pointer &DP = DestPtr.atIndex(DestIndex + I);
2095 DP.deref<T>() = SP.deref<T>();
2096 DP.initialize();
2097 }
2098 return true;
2099}
2100
2101/// Just takes a pointer and checks if it's an incomplete
2102/// array type.
2103inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
2104 const Pointer &Ptr = S.Stk.pop<Pointer>();
2105
2106 if (Ptr.isZero()) {
2107 S.Stk.push<Pointer>(Ptr);
2108 return true;
2109 }
2110
2111 if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
2112 return false;
2113
2114 if (!Ptr.isUnknownSizeArray() || Ptr.isDummy()) {
2115 S.Stk.push<Pointer>(Ptr.atIndex(0));
2116 return true;
2117 }
2118
2119 const SourceInfo &E = S.Current->getSource(OpPC);
2120 S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
2121
2122 return false;
2123}
2124
2125inline bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
2126 uint32_t VarArgSize) {
2127 if (Func->hasThisPointer()) {
2128 size_t ArgSize = Func->getArgSize() + VarArgSize;
2129 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
2130 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
2131
2132 // If the current function is a lambda static invoker and
2133 // the function we're about to call is a lambda call operator,
2134 // skip the CheckInvoke, since the ThisPtr is a null pointer
2135 // anyway.
2136 if (!(S.Current->getFunction() &&
2137 S.Current->getFunction()->isLambdaStaticInvoker() &&
2138 Func->isLambdaCallOperator())) {
2139 if (!CheckInvoke(S, OpPC, ThisPtr))
2140 return false;
2141 }
2142
2143 if (S.checkingPotentialConstantExpression())
2144 return false;
2145 }
2146
2147 if (!CheckCallable(S, OpPC, Func))
2148 return false;
2149
2150 if (!CheckCallDepth(S, OpPC))
2151 return false;
2152
2153 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
2154 InterpFrame *FrameBefore = S.Current;
2155 S.Current = NewFrame.get();
2156
2157 APValue CallResult;
2158 // Note that we cannot assert(CallResult.hasValue()) here since
2159 // Ret() above only sets the APValue if the curent frame doesn't
2160 // have a caller set.
2161 if (Interpret(S, CallResult)) {
2162 NewFrame.release(); // Frame was delete'd already.
2163 assert(S.Current == FrameBefore);
2164 return true;
2165 }
2166
2167 // Interpreting the function failed somehow. Reset to
2168 // previous state.
2169 S.Current = FrameBefore;
2170 return false;
2171
2172 return false;
2173}
2174
2175inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
2176 uint32_t VarArgSize) {
2177 if (Func->hasThisPointer()) {
2178 size_t ArgSize = Func->getArgSize() + VarArgSize;
2179 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
2180
2181 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
2182
2183 // If the current function is a lambda static invoker and
2184 // the function we're about to call is a lambda call operator,
2185 // skip the CheckInvoke, since the ThisPtr is a null pointer
2186 // anyway.
2187 if (!(S.Current->getFunction() &&
2188 S.Current->getFunction()->isLambdaStaticInvoker() &&
2189 Func->isLambdaCallOperator())) {
2190 if (!CheckInvoke(S, OpPC, ThisPtr))
2191 return false;
2192 }
2193
2194 if (S.checkingPotentialConstantExpression())
2195 return false;
2196 }
2197
2198 if (!CheckCallable(S, OpPC, Func))
2199 return false;
2200
2201 if (!CheckCallDepth(S, OpPC))
2202 return false;
2203
2204 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
2205 InterpFrame *FrameBefore = S.Current;
2206 S.Current = NewFrame.get();
2207
2208 APValue CallResult;
2209 // Note that we cannot assert(CallResult.hasValue()) here since
2210 // Ret() above only sets the APValue if the curent frame doesn't
2211 // have a caller set.
2212 if (Interpret(S, CallResult)) {
2213 NewFrame.release(); // Frame was delete'd already.
2214 assert(S.Current == FrameBefore);
2215 return true;
2216 }
2217
2218 // Interpreting the function failed somehow. Reset to
2219 // previous state.
2220 S.Current = FrameBefore;
2221 return false;
2222}
2223
2224inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
2225 uint32_t VarArgSize) {
2226 assert(Func->hasThisPointer());
2227 assert(Func->isVirtual());
2228 size_t ArgSize = Func->getArgSize() + VarArgSize;
2229 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
2230 Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
2231
2232 QualType DynamicType = ThisPtr.getDeclDesc()->getType();
2233 const CXXRecordDecl *DynamicDecl;
2234 if (DynamicType->isPointerType() || DynamicType->isReferenceType())
2235 DynamicDecl = DynamicType->getPointeeCXXRecordDecl();
2236 else
2237 DynamicDecl = ThisPtr.getDeclDesc()->getType()->getAsCXXRecordDecl();
2238 const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());
2239 const auto *InitialFunction = cast<CXXMethodDecl>(Func->getDecl());
2240 const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
2241 DynamicDecl, StaticDecl, InitialFunction);
2242
2243 if (Overrider != InitialFunction) {
2244 // DR1872: An instantiated virtual constexpr function can't be called in a
2245 // constant expression (prior to C++20). We can still constant-fold such a
2246 // call.
2247 if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {
2248 const Expr *E = S.Current->getExpr(OpPC);
2249 S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();
2250 }
2251
2252 Func = S.getContext().getOrCreateFunction(Overrider);
2253
2254 const CXXRecordDecl *ThisFieldDecl =
2255 ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
2256 if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
2257 // If the function we call is further DOWN the hierarchy than the
2258 // FieldDesc of our pointer, just get the DeclDesc instead, which
2259 // is the furthest we might go up in the hierarchy.
2260 ThisPtr = ThisPtr.getDeclPtr();
2261 }
2262 }
2263
2264 return Call(S, OpPC, Func, VarArgSize);
2265}
2266
2267inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
2268 const CallExpr *CE) {
2269 auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
2270
2271 InterpFrame *FrameBefore = S.Current;
2272 S.Current = NewFrame.get();
2273
2274 if (InterpretBuiltin(S, PC, Func, CE)) {
2275 NewFrame.release();
2276 return true;
2277 }
2278 S.Current = FrameBefore;
2279 return false;
2280}
2281
2282inline bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
2283 const CallExpr *CE) {
2284 const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();
2285
2286 const Function *F = FuncPtr.getFunction();
2287 if (!F) {
2288 const Expr *E = S.Current->getExpr(OpPC);
2289 S.FFDiag(E, diag::note_constexpr_null_callee)
2290 << const_cast<Expr *>(E) << E->getSourceRange();
2291 return false;
2292 }
2293
2294 if (!FuncPtr.isValid())
2295 return false;
2296
2297 assert(F);
2298
2299 // Check argument nullability state.
2300 if (F->hasNonNullAttr()) {
2301 if (!CheckNonNullArgs(S, OpPC, F, CE, ArgSize))
2302 return false;
2303 }
2304
2305 assert(ArgSize >= F->getWrittenArgSize());
2306 uint32_t VarArgSize = ArgSize - F->getWrittenArgSize();
2307
2308 if (F->isVirtual())
2309 return CallVirt(S, OpPC, F, VarArgSize);
2310
2311 return Call(S, OpPC, F, VarArgSize);
2312}
2313
2314inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
2315 assert(Func);
2316 S.Stk.push<FunctionPointer>(Func);
2317 return true;
2318}
2319
2320template <PrimType Name, class T = typename PrimConv<Name>::T>
2321inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2322 const T &IntVal = S.Stk.pop<T>();
2323
2324 S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
2325 return true;
2326}
2327
2328/// Just emit a diagnostic. The expression that caused emission of this
2329/// op is not valid in a constant context.
2330inline bool Invalid(InterpState &S, CodePtr OpPC) {
2331 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2332 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
2333 << S.Current->getRange(OpPC);
2334 return false;
2335}
2336
2337/// Do nothing and just abort execution.
2338inline bool Error(InterpState &S, CodePtr OpPC) { return false; }
2339
2340/// Same here, but only for casts.
2341inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) {
2342 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2343
2344 // FIXME: Support diagnosing other invalid cast kinds.
2345 if (Kind == CastKind::Reinterpret)
2346 S.FFDiag(Loc, diag::note_constexpr_invalid_cast)
2347 << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
2348 return false;
2349}
2350
2352 const DeclRefExpr *DR) {
2353 assert(DR);
2354 return CheckDeclRef(S, OpPC, DR);
2355}
2356
2357inline bool Assume(InterpState &S, CodePtr OpPC) {
2358 const auto Val = S.Stk.pop<Boolean>();
2359
2360 if (Val)
2361 return true;
2362
2363 // Else, diagnose.
2364 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2365 S.CCEDiag(Loc, diag::note_constexpr_assumption_failed);
2366 return false;
2367}
2368
2369template <PrimType Name, class T = typename PrimConv<Name>::T>
2370inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
2371 llvm::SmallVector<int64_t> ArrayIndices;
2372 for (size_t I = 0; I != E->getNumExpressions(); ++I)
2373 ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
2374
2375 int64_t Result;
2376 if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
2377 return false;
2378
2379 S.Stk.push<T>(T::from(Result));
2380
2381 return true;
2382}
2383
2384template <PrimType Name, class T = typename PrimConv<Name>::T>
2385inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
2386 const T &Arg = S.Stk.peek<T>();
2387 if (!Arg.isZero())
2388 return true;
2389
2390 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2391 S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
2392
2393 return false;
2394}
2395
2396/// OldPtr -> Integer -> NewPtr.
2397template <PrimType TIn, PrimType TOut>
2398inline bool DecayPtr(InterpState &S, CodePtr OpPC) {
2399 static_assert(isPtrType(TIn) && isPtrType(TOut));
2400 using FromT = typename PrimConv<TIn>::T;
2401 using ToT = typename PrimConv<TOut>::T;
2402
2403 const FromT &OldPtr = S.Stk.pop<FromT>();
2404 S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
2405 return true;
2406}
2407
2408//===----------------------------------------------------------------------===//
2409// Read opcode arguments
2410//===----------------------------------------------------------------------===//
2411
2412template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
2413 if constexpr (std::is_pointer<T>::value) {
2414 uint32_t ID = OpPC.read<uint32_t>();
2415 return reinterpret_cast<T>(S.P.getNativePointer(ID));
2416 } else {
2417 return OpPC.read<T>();
2418 }
2419}
2420
2421template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
2423 OpPC += align(F.bytesToSerialize());
2424 return F;
2425}
2426
2427template <>
2428inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
2429 CodePtr &OpPC) {
2430 IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);
2431 OpPC += align(I.bytesToSerialize());
2432 return I;
2433}
2434
2435template <>
2436inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
2437 CodePtr &OpPC) {
2438 IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);
2439 OpPC += align(I.bytesToSerialize());
2440 return I;
2441}
2442
2443} // namespace interp
2444} // namespace clang
2445
2446#endif
Defines the clang::ASTContext interface.
#define V(N, I)
Definition: ASTContext.h:3285
ASTImporterLookupTable & LT
StringRef P
static char ID
Definition: Arena.cpp:183
llvm::APSInt APSInt
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
SourceLocation Loc
Definition: SemaObjC.cpp:755
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition: APValue.h:122
Represents a static or instance method of a struct/union/class.
Definition: DeclCXX.h:2060
bool isVirtual() const
Definition: DeclCXX.h:2115
Represents a C++ struct/union/class.
Definition: DeclCXX.h:258
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2820
const ValueInfo * getValueInfo(ComparisonCategoryResult ValueKind) const
ComparisonCategoryResult makeWeakResult(ComparisonCategoryResult Res) const
Converts the specified result kind into the correct result kind for this category.
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1260
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
This represents one expression.
Definition: Expr.h:110
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition: Expr.cpp:277
QualType getType() const
Definition: Expr.h:142
Implicit declaration of a temporary that was materialized by a MaterializeTemporaryExpr and lifetime-...
Definition: DeclCXX.h:3229
APValue * getOrCreateValue(bool MayCreate) const
Get the storage for the constant value of a materialized temporary of static storage duration.
Definition: DeclCXX.cpp:3079
OffsetOfExpr - [C99 7.17] - This represents an expression of the form offsetof(record-type,...
Definition: Expr.h:2465
unsigned getNumExpressions() const
Definition: Expr.h:2541
A (possibly-)qualified type.
Definition: Type.h:940
Represents a struct/union/class.
Definition: Decl.h:4168
Encodes a location in the source.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:326
The base class of the type hierarchy.
Definition: Type.h:1813
unsigned getSize() const
Returns the size of the block.
Definition: InterpBlock.h:75
Wrapper around boolean types.
Definition: Boolean.h:25
static bool inv(Boolean A, Boolean *R)
Definition: Boolean.h:145
static Boolean from(T Value)
Definition: Boolean.h:98
Pointer into the code segment.
Definition: Source.h:30
std::enable_if_t<!std::is_pointer< T >::value, T > read()
Reads data and advances the pointer.
Definition: Source.h:55
static APFloat::opStatus div(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:200
static Floating deserialize(const std::byte *Buff)
Definition: Floating.h:153
static APFloat::opStatus sub(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:181
const APFloat & getAPFloat() const
Definition: Floating.h:40
static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:174
static APFloat::opStatus fromIntegral(APSInt Val, const llvm::fltSemantics &Sem, llvm::RoundingMode RM, Floating &Result)
Definition: Floating.h:119
Floating toSemantics(const llvm::fltSemantics *Sem, llvm::RoundingMode RM) const
Definition: Floating.h:55
size_t bytesToSerialize() const
Definition: Floating.h:139
static APFloat::opStatus add(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:168
static APFloat::opStatus mul(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:194
bool isNonZero() const
Definition: Floating.h:92
bool isFinite() const
Definition: Floating.h:98
static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:187
APFloat::opStatus convertToInteger(APSInt &Result) const
Definition: Floating.h:50
const Function * getFunction() const
ComparisonCategoryResult compare(const FunctionPointer &RHS) const
std::string toDiagnosticString(const ASTContext &Ctx) const
Bytecode function.
Definition: Function.h:77
static IntegralAP< Signed > deserialize(const std::byte *Buff)
Definition: IntegralAP.h:284
static IntegralAP zero(int32_t BitWidth)
Definition: IntegralAP.h:120
static IntegralAP from(T Value, unsigned NumBits=0)
Definition: IntegralAP.h:96
Wrapper around numeric types.
Definition: Integral.h:50
Frame storing local variables.
Definition: InterpFrame.h:28
Interpreter context.
Definition: InterpState.h:35
A pointer to a memory block, live or dead.
Definition: Pointer.h:80
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition: Pointer.cpp:294
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition: Pointer.h:170
void deactivate() const
Deactivates an entire strurcutre.
Definition: Pointer.cpp:290
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:137
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition: Pointer.h:488
Pointer atFieldSub(unsigned Off) const
Subtract the given offset from the current Base and Offset of the pointer.
Definition: Pointer.h:163
bool isExtern() const
Checks if the storage is extern.
Definition: Pointer.h:436
int64_t getIndex() const
Returns the index into an array.
Definition: Pointer.h:531
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:154
T & deref() const
Dereferences the pointer, if it's live.
Definition: Pointer.h:566
unsigned getNumElems() const
Returns the number of elements.
Definition: Pointer.h:522
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition: Pointer.h:384
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
Definition: Pointer.h:367
bool inArray() const
Checks if the innermost field is an array.
Definition: Pointer.h:372
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
Definition: Pointer.cpp:205
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:242
ComparisonCategoryResult compare(const Pointer &Other) const
Compare two pointers.
Definition: Pointer.h:597
uint64_t getIntegerRepresentation() const
Definition: Pointer.h:127
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
Definition: Pointer.h:212
bool isBlockPointer() const
Definition: Pointer.h:419
const Block * block() const
Definition: Pointer.h:528
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition: Pointer.h:305
bool canBeInitialized() const
If this pointer has an InlineDescriptor we can use to initialize.
Definition: Pointer.h:404
void initialize() const
Initializes a field.
Definition: Pointer.cpp:242
unsigned getByteOffset() const
Returns the byte offset from the start.
Definition: Pointer.h:515
Describes the statement/declaration an opcode was generated from.
Definition: Source.h:72
bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, unsigned Bits)
Checks if the shift operation is legal.
Definition: Interp.h:130
bool InitPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1482
bool Inv(InterpState &S, CodePtr OpPC)
Definition: Interp.h:473
bool Shr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1935
bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I, const LifetimeExtendedTemporaryDecl *Temp)
1) Converts the value on top of the stack to an APValue 2) Sets that APValue on \Temp 3) Initializes ...
Definition: Interp.h:1101
bool IncPop(InterpState &S, CodePtr OpPC)
1) Pops a pointer from the stack 2) Load the value from the pointer 3) Writes the value increased by ...
Definition: Interp.h:603
bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition: Interp.h:2073
bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1314
bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:337
bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition: Interp.h:2062
bool GT(InterpState &S, CodePtr OpPC)
Definition: Interp.h:890
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
Definition: Interp.cpp:500
bool DecPop(InterpState &S, CodePtr OpPC)
1) Pops a pointer from the stack 2) Load the value from the pointer 3) Writes the value decreased by ...
Definition: Interp.h:632
bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1030
bool NarrowPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2009
llvm::APInt APInt
Definition: Integral.h:29
bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1134
bool Interpret(InterpState &S, APValue &Result)
Interpreter entry point.
Definition: Interp.cpp:694
Floating ReadArg< Floating >(InterpState &S, CodePtr &OpPC)
Definition: Interp.h:2421
static bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:1883
bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:662
bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:967
bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx)
The same as InitElem, but pops the pointer as well.
Definition: Interp.h:1510
bool StoreBitField(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1439
bool LoadPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1404
bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:694
static bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:1810
static bool IncPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1654
bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR)
We aleady know the given DeclRefExpr is invalid for some reason, now figure out why and print appropr...
Definition: Interp.cpp:655
bool Dup(InterpState &S, CodePtr OpPC)
Definition: Interp.h:923
bool CheckCallDepth(InterpState &S, CodePtr OpPC)
Checks if calling the currently active function would exceed the allowed call depth.
Definition: Interp.cpp:568
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks the 'this' pointer.
Definition: Interp.cpp:579
bool SetField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:998
bool CheckNonNullArg(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2385
bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, llvm::ArrayRef< int64_t > ArrayIndices, int64_t &Result)
Interpret an offsetof operation.
bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC, const Pointer &Ptr, const APSInt &IntValue)
Sets the given integral value to the pointer, which is of a std::{weak,partial,strong}_ordering type.
static bool IncDecPtrHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition: Interp.h:1630
bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1217
static bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:1790
bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS)
Checks if Div/Rem operation on LHS and RHS is valid.
Definition: Interp.h:166
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Checks if the Descriptor is of a constexpr or const global variable.
Definition: Interp.cpp:296
bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, const T &RHS)
Definition: Interp.h:274
bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off)
1) Pops a Pointer from the stack 2) Pushes Pointer.atField(Off) on the stack
Definition: Interp.h:1237
bool Div(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:439
bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to a mutable field.
Definition: Interp.cpp:395
bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func)
Definition: Interp.h:2314
bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I)
Same as GetGlobal, but without the checks.
Definition: Interp.h:1077
bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1281
bool SubPtr(InterpState &S, CodePtr OpPC)
1) Pops a Pointer from the stack.
Definition: Interp.h:1676
bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if Ptr is a one-past-the-end pointer.
Definition: Interp.cpp:363
static bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:1855
bool ReturnValue(const T &V, APValue &R)
Convert a value to an APValue.
Definition: Interp.h:43
bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1230
bool ArrayElemPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2030
bool NE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:868
bool NoRet(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1999
bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Definition: Interp.h:2321
static bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:1878
bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:319
bool Shl(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1965
bool RVOPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1922
bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition: Interp.cpp:408
bool CastPointerIntegral(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1831
constexpr bool isPtrType(PrimType T)
Definition: PrimType.h:49
bool SubOffset(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1623
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition: PrimType.h:99
bool BitXor(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:402
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is in range.
Definition: Interp.cpp:345
bool Ret(InterpState &S, CodePtr &PC, APValue &Result)
Definition: Interp.h:217
bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:1740
bool ExpandPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2015
bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1165
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD)
Checks if a method is pure virtual.
Definition: Interp.cpp:597
bool Store(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1415
bool GetField(InterpState &S, CodePtr OpPC, uint32_t I)
1) Peeks a pointer on the stack 2) Pushes the value of the pointer's field on the stack
Definition: Interp.h:984
bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2046
bool This(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1899
bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:355
bool InitField(InterpState &S, CodePtr OpPC, uint32_t I)
1) Pops the value from the stack 2) Peeks a pointer from the stack 3) Pushes the value to field I of ...
Definition: Interp.h:1182
bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, llvm::RoundingMode RM)
Definition: Interp.h:643
bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex, uint32_t DestIndex, uint32_t Size)
Definition: Interp.h:2084
bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:735
llvm::function_ref< bool(ComparisonCategoryResult)> CompareFn
Definition: Interp.h:723
T ReadArg(InterpState &S, CodePtr &OpPC)
Definition: Interp.h:2412
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is live and accessible.
Definition: Interp.cpp:266
bool ArrayDecay(InterpState &S, CodePtr OpPC)
Just takes a pointer and checks if it's an incomplete array type.
Definition: Interp.h:2103
bool InitGlobalTempComp(InterpState &S, CodePtr OpPC, const LifetimeExtendedTemporaryDecl *Temp)
1) Converts the value on top of the stack to an APValue 2) Sets that APValue on \Temp 3) Initialized ...
Definition: Interp.h:1119
bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition: Interp.h:531
bool CastFloatingIntegral(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1761
bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:949
bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E)
Definition: Interp.h:2370
bool BitAnd(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:368
bool CastIntegralFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
Definition: Interp.h:1747
bool LE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:882
bool Zero(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1873
bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F, uint32_t FieldOffset)
Definition: Interp.h:1149
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be stored in a block.
Definition: Interp.cpp:474
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if a pointer is null.
Definition: Interp.cpp:336
bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
1) Pops a Floating from the stack.
Definition: Interp.h:1722
ComparisonCategoryResult Compare(const T &X, const T &Y)
Helper to compare two comparable types.
Definition: Primitives.h:25
bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1044
bool StoreBitFieldPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1454
bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition: Interp.h:2125
static bool DecPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1663
bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1203
bool Rem(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:419
bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, const Pointer &Ptr)
Definition: Interp.h:1354
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be loaded from a block.
Definition: Interp.cpp:451
bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:672
bool Dump(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1349
bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Definition: Interp.h:1889
static bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:1842
bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1258
bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1268
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
Definition: Interp.cpp:258
bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:682
bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Check if a global variable is initialized.
Definition: Interp.cpp:434
bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1294
bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *CE, unsigned ArgSize)
Checks if all the arguments annotated as 'nonnull' are in fact not null.
Definition: Interp.cpp:672
bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1304
bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:976
bool CmpHelper< FunctionPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Function pointers cannot be compared in an ordered way.
Definition: Interp.h:741
bool Comp(InterpState &S, CodePtr OpPC)
1) Pops the value from the stack.
Definition: Interp.h:708
bool DecayPtr(InterpState &S, CodePtr OpPC)
OldPtr -> Integer -> NewPtr.
Definition: Interp.h:2398
bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC, const RecordDecl *D)
Definition: Interp.h:1365
bool StorePop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1427
void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC)
Definition: Interp.cpp:194
bool CallBI(InterpState &S, CodePtr &PC, const Function *Func, const CallExpr *CE)
Definition: Interp.h:2267
bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
1) Pops the value from the stack.
Definition: Interp.h:961
bool FinishInit(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1341
bool Mul(InterpState &S, CodePtr OpPC)
Definition: Interp.h:348
bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx)
1) Pops the value from the stack 2) Peeks a pointer and gets its index \Idx 3) Sets the value on the ...
Definition: Interp.h:1496
bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1704
bool Pop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:929
bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind)
Same here, but only for casts.
Definition: Interp.h:2341
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
Definition: PrimType.cpp:22
bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F)
Definition: Interp.h:1192
bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR)
Definition: Interp.h:2351
bool FinishInitPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1334
bool InRange(InterpState &S, CodePtr OpPC)
Definition: Interp.h:909
bool CmpHelperEQ< FunctionPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:754
bool Neg(InterpState &S, CodePtr OpPC)
Definition: Interp.h:489
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call)
Interpret a builtin function.
llvm::APSInt APSInt
Definition: Floating.h:24
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the variable has externally defined storage.
Definition: Interp.cpp:244
bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:455
bool BitOr(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:385
bool Load(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1393
bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1084
bool Cast(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1713
bool EQ(InterpState &S, CodePtr OpPC)
Definition: Interp.h:837
bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I)
1) Pops a pointer from the stack 2) Pushes the value of the pointer's field on the stack
Definition: Interp.h:1016
bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F)
Checks if a method can be called.
Definition: Interp.cpp:508
bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer is a dummy pointer.
Definition: Interp.cpp:660
bool AddOffset(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1616
bool Const(InterpState &S, CodePtr OpPC, const T &Arg)
Definition: Interp.h:939
bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest)
Copy the contents of Src into Dest.
bool Memcpy(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1522
bool GE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:897
bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize, const CallExpr *CE)
Definition: Interp.h:2282
bool CmpHelperEQ< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:794
constexpr bool isIntegralType(PrimType T)
Definition: PrimType.h:70
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition: Interp.h:2224
bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:726
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to const storage.
Definition: Interp.cpp:373
bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1222
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1059
bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)
Definition: Interp.h:1377
bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1090
bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result)
Definition: Interp.h:251
bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo)
Definition: Interp.h:844
bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need to know what bitwidth the resu...
Definition: Interp.h:1733
bool CmpHelper< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:774
bool Assume(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2357
bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a method can be invoked on an object.
Definition: Interp.cpp:490
bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1324
bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, APFloat::opStatus Status)
Checks if the result of a floating-point operation is valid in the current context.
Definition: Interp.cpp:606
bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, const Pointer &Ptr)
Definition: Interp.h:1537
The JSON file list parser is used to communicate input to InstallAPI.
ComparisonCategoryResult
An enumeration representing the possible results of a three-way comparison.
CheckSubobjectKind
The order of this enum is important for diagnostics.
Definition: State.h:40
@ CSK_ArrayToPointer
Definition: State.h:44
@ CSK_Derived
Definition: State.h:42
@ CSK_Base
Definition: State.h:41
@ CSK_ArrayIndex
Definition: State.h:45
@ CSK_Field
Definition: State.h:43
@ Result
The result type of a method or function.
AccessKinds
Kinds of access we can perform on an object, for diagnostics.
Definition: State.h:26
@ AK_Increment
Definition: State.h:30
@ AK_Decrement
Definition: State.h:31
const FunctionProtoType * T
#define bool
Definition: stdbool.h:24
Describes a memory block created by an allocation site.
Definition: Descriptor.h:91
Mapping from primitive types to their representation.
Definition: PrimType.h:73