clang 18.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 APInt = llvm::APInt;
41using APSInt = llvm::APSInt;
42
43/// Convert a value to an APValue.
44template <typename T> bool ReturnValue(const T &V, APValue &R) {
45 R = V.toAPValue();
46 return true;
47}
48
49/// Checks if the variable has externally defined storage.
50bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
51
52/// Checks if the array is offsetable.
53bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
54
55/// Checks if a pointer is live and accessible.
56bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
57 AccessKinds AK);
58/// Checks if a pointer is null.
59bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
61
62/// Checks if a pointer is in range.
63bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
64 AccessKinds AK);
65
66/// Checks if a field from which a pointer is going to be derived is valid.
67bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
69
70/// Checks if Ptr is a one-past-the-end pointer.
71bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
73
74/// Checks if a pointer points to const storage.
75bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
76
77/// Checks if a pointer points to a mutable field.
78bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
79
80/// Checks if a value can be loaded from a block.
81bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
82
83bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
84 AccessKinds AK);
85
86/// Checks if a value can be stored in a block.
87bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
88
89/// Checks if a method can be invoked on an object.
90bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
91
92/// Checks if a value can be initialized.
93bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
94
95/// Checks if a method can be called.
96bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
97
98/// Checks if calling the currently active function would exceed
99/// the allowed call depth.
100bool CheckCallDepth(InterpState &S, CodePtr OpPC);
101
102/// Checks the 'this' pointer.
103bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
104
105/// Checks if a method is pure virtual.
106bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
107
108/// Checks that all fields are initialized after a constructor call.
109bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This);
110
111/// Checks if reinterpret casts are legal in the current context.
112bool CheckPotentialReinterpretCast(InterpState &S, CodePtr OpPC,
113 const Pointer &Ptr);
114
115/// Checks if the shift operation is legal.
116template <typename LT, typename RT>
117bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
118 unsigned Bits) {
119 if (RHS.isNegative()) {
120 const SourceInfo &Loc = S.Current->getSource(OpPC);
121 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
122 return false;
123 }
124
125 // C++11 [expr.shift]p1: Shift width must be less than the bit width of
126 // the shifted type.
127 if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
128 const Expr *E = S.Current->getExpr(OpPC);
129 const APSInt Val = RHS.toAPSInt();
130 QualType Ty = E->getType();
131 S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
132 return false;
133 }
134
135 if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
136 const Expr *E = S.Current->getExpr(OpPC);
137 // C++11 [expr.shift]p2: A signed left shift must have a non-negative
138 // operand, and must not overflow the corresponding unsigned type.
139 if (LHS.isNegative())
140 S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
141 else if (LHS.toUnsigned().countLeadingZeros() < static_cast<unsigned>(RHS))
142 S.CCEDiag(E, diag::note_constexpr_lshift_discards);
143 }
144
145 // C++2a [expr.shift]p2: [P0907R4]:
146 // E1 << E2 is the unique value congruent to
147 // E1 x 2^E2 module 2^N.
148 return true;
149}
150
151/// Checks if Div/Rem operation on LHS and RHS is valid.
152template <typename T>
153bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
154 if (RHS.isZero()) {
155 const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
156 S.FFDiag(Op, diag::note_expr_divide_by_zero)
157 << Op->getRHS()->getSourceRange();
158 return false;
159 }
160
161 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
162 APSInt LHSInt = LHS.toAPSInt();
163 SmallString<32> Trunc;
164 (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
165 const SourceInfo &Loc = S.Current->getSource(OpPC);
166 const Expr *E = S.Current->getExpr(OpPC);
167 S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
168 return false;
169 }
170 return true;
171}
172
173/// Checks if the result of a floating-point operation is valid
174/// in the current context.
175bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
176 APFloat::opStatus Status);
177
178/// Checks why the given DeclRefExpr is invalid.
179bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);
180
181/// Interpreter entry point.
182bool Interpret(InterpState &S, APValue &Result);
183
184/// Interpret a builtin function.
185bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
186 const CallExpr *Call);
187
188/// Interpret an offsetof operation.
189bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
190 llvm::ArrayRef<int64_t> ArrayIndices, int64_t &Result);
191
192enum class ArithOp { Add, Sub };
193
194//===----------------------------------------------------------------------===//
195// Returning values
196//===----------------------------------------------------------------------===//
197
198/// Pop arguments of builtins defined as func-name(...).
199bool popBuiltinArgs(InterpState &S, CodePtr OpPC);
200
201template <PrimType Name, class T = typename PrimConv<Name>::T>
203 const T &Ret = S.Stk.pop<T>();
204
205 // Make sure returned pointers are live. We might be trying to return a
206 // pointer or reference to a local variable.
207 // Just return false, since a diagnostic has already been emitted in Sema.
208 if constexpr (std::is_same_v<T, Pointer>) {
209 // FIXME: We could be calling isLive() here, but the emitted diagnostics
210 // seem a little weird, at least if the returned expression is of
211 // pointer type.
212 if (!Ret.isLive())
213 return false;
214 }
215
216 assert(S.Current);
217 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
218 if (!S.checkingPotentialConstantExpression() || S.Current->Caller) {
219 // Certain builtin functions are declared as func-name(...), so the
220 // parameters are checked in Sema and only available through the CallExpr.
221 // The interp::Function we create for them has 0 parameters, so we need to
222 // remove them from the stack by checking the CallExpr.
223 if (S.Current->getFunction()->needsRuntimeArgPop(S.getCtx()))
224 popBuiltinArgs(S, PC);
225 else
226 S.Current->popArgs();
227 }
228
229 if (InterpFrame *Caller = S.Current->Caller) {
230 PC = S.Current->getRetPC();
231 delete S.Current;
232 S.Current = Caller;
233 S.Stk.push<T>(Ret);
234 } else {
235 delete S.Current;
236 S.Current = nullptr;
237 if (!ReturnValue<T>(Ret, Result))
238 return false;
239 }
240 return true;
241}
242
243inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
244 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
245 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
246 S.Current->popArgs();
247
248 if (InterpFrame *Caller = S.Current->Caller) {
249 PC = S.Current->getRetPC();
250 delete S.Current;
251 S.Current = Caller;
252 } else {
253 delete S.Current;
254 S.Current = nullptr;
255 }
256 return true;
257}
258
259//===----------------------------------------------------------------------===//
260// Add, Sub, Mul
261//===----------------------------------------------------------------------===//
262
263template <typename T, bool (*OpFW)(T, T, unsigned, T *),
264 template <typename U> class OpAP>
265bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
266 const T &RHS) {
267 // Fast path - add the numbers with fixed width.
268 T Result;
269 if (!OpFW(LHS, RHS, Bits, &Result)) {
270 S.Stk.push<T>(Result);
271 return true;
272 }
273
274 // If for some reason evaluation continues, use the truncated results.
275 S.Stk.push<T>(Result);
276
277 // Slow path - compute the result using another bit of precision.
278 APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
279
280 // Report undefined behaviour, stopping if required.
281 const Expr *E = S.Current->getExpr(OpPC);
282 QualType Type = E->getType();
283 if (S.checkingForUndefinedBehavior()) {
284 SmallString<32> Trunc;
285 Value.trunc(Result.bitWidth()).toString(Trunc, 10);
286 auto Loc = E->getExprLoc();
287 S.report(Loc, diag::warn_integer_constant_overflow)
288 << Trunc << Type << E->getSourceRange();
289 return true;
290 } else {
291 S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
292 return S.noteUndefinedBehavior();
293 }
294}
295
296template <PrimType Name, class T = typename PrimConv<Name>::T>
297bool Add(InterpState &S, CodePtr OpPC) {
298 const T &RHS = S.Stk.pop<T>();
299 const T &LHS = S.Stk.pop<T>();
300 const unsigned Bits = RHS.bitWidth() + 1;
301 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
302}
303
304inline bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
305 const Floating &RHS = S.Stk.pop<Floating>();
306 const Floating &LHS = S.Stk.pop<Floating>();
307
309 auto Status = Floating::add(LHS, RHS, RM, &Result);
310 S.Stk.push<Floating>(Result);
311 return CheckFloatResult(S, OpPC, Result, Status);
312}
313
314template <PrimType Name, class T = typename PrimConv<Name>::T>
315bool Sub(InterpState &S, CodePtr OpPC) {
316 const T &RHS = S.Stk.pop<T>();
317 const T &LHS = S.Stk.pop<T>();
318 const unsigned Bits = RHS.bitWidth() + 1;
319 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
320}
321
322inline bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
323 const Floating &RHS = S.Stk.pop<Floating>();
324 const Floating &LHS = S.Stk.pop<Floating>();
325
327 auto Status = Floating::sub(LHS, RHS, RM, &Result);
328 S.Stk.push<Floating>(Result);
329 return CheckFloatResult(S, OpPC, Result, Status);
330}
331
332template <PrimType Name, class T = typename PrimConv<Name>::T>
333bool Mul(InterpState &S, CodePtr OpPC) {
334 const T &RHS = S.Stk.pop<T>();
335 const T &LHS = S.Stk.pop<T>();
336 const unsigned Bits = RHS.bitWidth() * 2;
337 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
338}
339
340inline bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
341 const Floating &RHS = S.Stk.pop<Floating>();
342 const Floating &LHS = S.Stk.pop<Floating>();
343
345 auto Status = Floating::mul(LHS, RHS, RM, &Result);
346 S.Stk.push<Floating>(Result);
347 return CheckFloatResult(S, OpPC, Result, Status);
348}
349/// 1) Pops the RHS from the stack.
350/// 2) Pops the LHS from the stack.
351/// 3) Pushes 'LHS & RHS' on the stack
352template <PrimType Name, class T = typename PrimConv<Name>::T>
353bool BitAnd(InterpState &S, CodePtr OpPC) {
354 const T &RHS = S.Stk.pop<T>();
355 const T &LHS = S.Stk.pop<T>();
356
357 unsigned Bits = RHS.bitWidth();
358 T Result;
359 if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
360 S.Stk.push<T>(Result);
361 return true;
362 }
363 return false;
364}
365
366/// 1) Pops the RHS from the stack.
367/// 2) Pops the LHS from the stack.
368/// 3) Pushes 'LHS | RHS' on the stack
369template <PrimType Name, class T = typename PrimConv<Name>::T>
370bool BitOr(InterpState &S, CodePtr OpPC) {
371 const T &RHS = S.Stk.pop<T>();
372 const T &LHS = S.Stk.pop<T>();
373
374 unsigned Bits = RHS.bitWidth();
375 T Result;
376 if (!T::bitOr(LHS, RHS, Bits, &Result)) {
377 S.Stk.push<T>(Result);
378 return true;
379 }
380 return false;
381}
382
383/// 1) Pops the RHS from the stack.
384/// 2) Pops the LHS from the stack.
385/// 3) Pushes 'LHS ^ RHS' on the stack
386template <PrimType Name, class T = typename PrimConv<Name>::T>
387bool BitXor(InterpState &S, CodePtr OpPC) {
388 const T &RHS = S.Stk.pop<T>();
389 const T &LHS = S.Stk.pop<T>();
390
391 unsigned Bits = RHS.bitWidth();
392 T Result;
393 if (!T::bitXor(LHS, RHS, Bits, &Result)) {
394 S.Stk.push<T>(Result);
395 return true;
396 }
397 return false;
398}
399
400/// 1) Pops the RHS from the stack.
401/// 2) Pops the LHS from the stack.
402/// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
403template <PrimType Name, class T = typename PrimConv<Name>::T>
404bool Rem(InterpState &S, CodePtr OpPC) {
405 const T &RHS = S.Stk.pop<T>();
406 const T &LHS = S.Stk.pop<T>();
407
408 if (!CheckDivRem(S, OpPC, LHS, RHS))
409 return false;
410
411 const unsigned Bits = RHS.bitWidth() * 2;
412 T Result;
413 if (!T::rem(LHS, RHS, Bits, &Result)) {
414 S.Stk.push<T>(Result);
415 return true;
416 }
417 return false;
418}
419
420/// 1) Pops the RHS from the stack.
421/// 2) Pops the LHS from the stack.
422/// 3) Pushes 'LHS / RHS' on the stack
423template <PrimType Name, class T = typename PrimConv<Name>::T>
424bool Div(InterpState &S, CodePtr OpPC) {
425 const T &RHS = S.Stk.pop<T>();
426 const T &LHS = S.Stk.pop<T>();
427
428 if (!CheckDivRem(S, OpPC, LHS, RHS))
429 return false;
430
431 const unsigned Bits = RHS.bitWidth() * 2;
432 T Result;
433 if (!T::div(LHS, RHS, Bits, &Result)) {
434 S.Stk.push<T>(Result);
435 return true;
436 }
437 return false;
438}
439
440inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
441 const Floating &RHS = S.Stk.pop<Floating>();
442 const Floating &LHS = S.Stk.pop<Floating>();
443
444 if (!CheckDivRem(S, OpPC, LHS, RHS))
445 return false;
446
448 auto Status = Floating::div(LHS, RHS, RM, &Result);
449 S.Stk.push<Floating>(Result);
450 return CheckFloatResult(S, OpPC, Result, Status);
451}
452
453//===----------------------------------------------------------------------===//
454// Inv
455//===----------------------------------------------------------------------===//
456
457template <PrimType Name, class T = typename PrimConv<Name>::T>
458bool Inv(InterpState &S, CodePtr OpPC) {
459 using BoolT = PrimConv<PT_Bool>::T;
460 const T &Val = S.Stk.pop<T>();
461 const unsigned Bits = Val.bitWidth();
462 Boolean R;
463 Boolean::inv(BoolT::from(Val, Bits), &R);
464
465 S.Stk.push<BoolT>(R);
466 return true;
467}
468
469//===----------------------------------------------------------------------===//
470// Neg
471//===----------------------------------------------------------------------===//
472
473template <PrimType Name, class T = typename PrimConv<Name>::T>
474bool Neg(InterpState &S, CodePtr OpPC) {
475 const T &Value = S.Stk.pop<T>();
476 T Result;
477
478 if (!T::neg(Value, &Result)) {
479 S.Stk.push<T>(Result);
480 return true;
481 }
482
483 assert(isIntegralType(Name) &&
484 "don't expect other types to fail at constexpr negation");
485 S.Stk.push<T>(Result);
486
487 APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
488 const Expr *E = S.Current->getExpr(OpPC);
489 QualType Type = E->getType();
490
491 if (S.checkingForUndefinedBehavior()) {
492 SmallString<32> Trunc;
493 NegatedValue.trunc(Result.bitWidth()).toString(Trunc, 10);
494 auto Loc = E->getExprLoc();
495 S.report(Loc, diag::warn_integer_constant_overflow)
496 << Trunc << Type << E->getSourceRange();
497 return true;
498 }
499
500 S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue << Type;
501 return S.noteUndefinedBehavior();
502}
503
504enum class PushVal : bool {
505 No,
506 Yes,
507};
508enum class IncDecOp {
509 Inc,
510 Dec,
511};
512
513template <typename T, IncDecOp Op, PushVal DoPush>
514bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
515 T Value = Ptr.deref<T>();
516 T Result;
517
518 if constexpr (DoPush == PushVal::Yes)
519 S.Stk.push<T>(Value);
520
521 if constexpr (Op == IncDecOp::Inc) {
522 if (!T::increment(Value, &Result)) {
523 Ptr.deref<T>() = Result;
524 return true;
525 }
526 } else {
527 if (!T::decrement(Value, &Result)) {
528 Ptr.deref<T>() = Result;
529 return true;
530 }
531 }
532
533 // Something went wrong with the previous operation. Compute the
534 // result with another bit of precision.
535 unsigned Bits = Value.bitWidth() + 1;
536 APSInt APResult;
537 if constexpr (Op == IncDecOp::Inc)
538 APResult = ++Value.toAPSInt(Bits);
539 else
540 APResult = --Value.toAPSInt(Bits);
541
542 // Report undefined behaviour, stopping if required.
543 const Expr *E = S.Current->getExpr(OpPC);
544 QualType Type = E->getType();
545 if (S.checkingForUndefinedBehavior()) {
546 SmallString<32> Trunc;
547 APResult.trunc(Result.bitWidth()).toString(Trunc, 10);
548 auto Loc = E->getExprLoc();
549 S.report(Loc, diag::warn_integer_constant_overflow)
550 << Trunc << Type << E->getSourceRange();
551 return true;
552 }
553
554 S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
555 return S.noteUndefinedBehavior();
556}
557
558/// 1) Pops a pointer from the stack
559/// 2) Load the value from the pointer
560/// 3) Writes the value increased by one back to the pointer
561/// 4) Pushes the original (pre-inc) value on the stack.
562template <PrimType Name, class T = typename PrimConv<Name>::T>
563bool Inc(InterpState &S, CodePtr OpPC) {
564 const Pointer &Ptr = S.Stk.pop<Pointer>();
565
566 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
567 return false;
568
569 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
570}
571
572/// 1) Pops a pointer from the stack
573/// 2) Load the value from the pointer
574/// 3) Writes the value increased by one back to the pointer
575template <PrimType Name, class T = typename PrimConv<Name>::T>
576bool IncPop(InterpState &S, CodePtr OpPC) {
577 const Pointer &Ptr = S.Stk.pop<Pointer>();
578
579 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
580 return false;
581
582 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
583}
584
585/// 1) Pops a pointer from the stack
586/// 2) Load the value from the pointer
587/// 3) Writes the value decreased by one back to the pointer
588/// 4) Pushes the original (pre-dec) value on the stack.
589template <PrimType Name, class T = typename PrimConv<Name>::T>
590bool Dec(InterpState &S, CodePtr OpPC) {
591 const Pointer &Ptr = S.Stk.pop<Pointer>();
592
593 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
594 return false;
595
596 return IncDecHelper<T, IncDecOp::Dec, 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 decreased by one back to the pointer
602template <PrimType Name, class T = typename PrimConv<Name>::T>
603bool DecPop(InterpState &S, CodePtr OpPC) {
604 const Pointer &Ptr = S.Stk.pop<Pointer>();
605
606 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
607 return false;
608
609 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
610}
611
612template <IncDecOp Op, PushVal DoPush>
614 llvm::RoundingMode RM) {
615 Floating Value = Ptr.deref<Floating>();
617
618 if constexpr (DoPush == PushVal::Yes)
619 S.Stk.push<Floating>(Value);
620
621 llvm::APFloat::opStatus Status;
622 if constexpr (Op == IncDecOp::Inc)
623 Status = Floating::increment(Value, RM, &Result);
624 else
625 Status = Floating::decrement(Value, RM, &Result);
626
627 Ptr.deref<Floating>() = Result;
628
629 return CheckFloatResult(S, OpPC, Result, Status);
630}
631
632inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
633 const Pointer &Ptr = S.Stk.pop<Pointer>();
634
635 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
636 return false;
637
638 return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM);
639}
640
641inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
642 const Pointer &Ptr = S.Stk.pop<Pointer>();
643
644 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
645 return false;
646
647 return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM);
648}
649
650inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
651 const Pointer &Ptr = S.Stk.pop<Pointer>();
652
653 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
654 return false;
655
656 return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM);
657}
658
659inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
660 const Pointer &Ptr = S.Stk.pop<Pointer>();
661
662 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
663 return false;
664
665 return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM);
666}
667
668/// 1) Pops the value from the stack.
669/// 2) Pushes the bitwise complemented value on the stack (~V).
670template <PrimType Name, class T = typename PrimConv<Name>::T>
671bool Comp(InterpState &S, CodePtr OpPC) {
672 const T &Val = S.Stk.pop<T>();
673 T Result;
674 if (!T::comp(Val, &Result)) {
675 S.Stk.push<T>(Result);
676 return true;
677 }
678
679 return false;
680}
681
682//===----------------------------------------------------------------------===//
683// EQ, NE, GT, GE, LT, LE
684//===----------------------------------------------------------------------===//
685
686using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
687
688template <typename T>
690 using BoolT = PrimConv<PT_Bool>::T;
691 const T &RHS = S.Stk.pop<T>();
692 const T &LHS = S.Stk.pop<T>();
693 S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
694 return true;
695}
696
697template <typename T>
699 return CmpHelper<T>(S, OpPC, Fn);
700}
701
702/// Function pointers cannot be compared in an ordered way.
703template <>
705 CompareFn Fn) {
706 const auto &RHS = S.Stk.pop<FunctionPointer>();
707 const auto &LHS = S.Stk.pop<FunctionPointer>();
708
709 const SourceInfo &Loc = S.Current->getSource(OpPC);
710 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
711 << LHS.toDiagnosticString(S.getCtx())
712 << RHS.toDiagnosticString(S.getCtx());
713 return false;
714}
715
716template <>
718 CompareFn Fn) {
719 const auto &RHS = S.Stk.pop<FunctionPointer>();
720 const auto &LHS = S.Stk.pop<FunctionPointer>();
721 S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
722 return true;
723}
724
725template <>
727 using BoolT = PrimConv<PT_Bool>::T;
728 const Pointer &RHS = S.Stk.pop<Pointer>();
729 const Pointer &LHS = S.Stk.pop<Pointer>();
730
731 if (!Pointer::hasSameBase(LHS, RHS)) {
732 const SourceInfo &Loc = S.Current->getSource(OpPC);
733 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
734 << LHS.toDiagnosticString(S.getCtx())
735 << RHS.toDiagnosticString(S.getCtx());
736 return false;
737 } else {
738 unsigned VL = LHS.getByteOffset();
739 unsigned VR = RHS.getByteOffset();
740 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
741 return true;
742 }
743}
744
745template <>
747 using BoolT = PrimConv<PT_Bool>::T;
748 const Pointer &RHS = S.Stk.pop<Pointer>();
749 const Pointer &LHS = S.Stk.pop<Pointer>();
750
751 if (LHS.isZero() && RHS.isZero()) {
752 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
753 return true;
754 }
755
756 if (!Pointer::hasSameBase(LHS, RHS)) {
757 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
758 return true;
759 } else {
760 unsigned VL = LHS.getByteOffset();
761 unsigned VR = RHS.getByteOffset();
762
763 // In our Pointer class, a pointer to an array and a pointer to the first
764 // element in the same array are NOT equal. They have the same Base value,
765 // but a different Offset. This is a pretty rare case, so we fix this here
766 // by comparing pointers to the first elements.
767 if (LHS.inArray() && LHS.isRoot())
768 VL = LHS.atIndex(0).getByteOffset();
769 if (RHS.inArray() && RHS.isRoot())
770 VR = RHS.atIndex(0).getByteOffset();
771
772 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
773 return true;
774 }
775}
776
777template <PrimType Name, class T = typename PrimConv<Name>::T>
778bool EQ(InterpState &S, CodePtr OpPC) {
779 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
781 });
782}
783
784template <PrimType Name, class T = typename PrimConv<Name>::T>
785bool NE(InterpState &S, CodePtr OpPC) {
786 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
788 });
789}
790
791template <PrimType Name, class T = typename PrimConv<Name>::T>
792bool LT(InterpState &S, CodePtr OpPC) {
793 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
795 });
796}
797
798template <PrimType Name, class T = typename PrimConv<Name>::T>
799bool LE(InterpState &S, CodePtr OpPC) {
800 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
801 return R == ComparisonCategoryResult::Less ||
803 });
804}
805
806template <PrimType Name, class T = typename PrimConv<Name>::T>
807bool GT(InterpState &S, CodePtr OpPC) {
808 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
810 });
811}
812
813template <PrimType Name, class T = typename PrimConv<Name>::T>
814bool GE(InterpState &S, CodePtr OpPC) {
815 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
818 });
819}
820
821//===----------------------------------------------------------------------===//
822// InRange
823//===----------------------------------------------------------------------===//
824
825template <PrimType Name, class T = typename PrimConv<Name>::T>
827 const T RHS = S.Stk.pop<T>();
828 const T LHS = S.Stk.pop<T>();
829 const T Value = S.Stk.pop<T>();
830
831 S.Stk.push<bool>(LHS <= Value && Value <= RHS);
832 return true;
833}
834
835//===----------------------------------------------------------------------===//
836// Dup, Pop, Test
837//===----------------------------------------------------------------------===//
838
839template <PrimType Name, class T = typename PrimConv<Name>::T>
840bool Dup(InterpState &S, CodePtr OpPC) {
841 S.Stk.push<T>(S.Stk.peek<T>());
842 return true;
843}
844
845template <PrimType Name, class T = typename PrimConv<Name>::T>
846bool Pop(InterpState &S, CodePtr OpPC) {
847 S.Stk.pop<T>();
848 return true;
849}
850
851//===----------------------------------------------------------------------===//
852// Const
853//===----------------------------------------------------------------------===//
854
855template <PrimType Name, class T = typename PrimConv<Name>::T>
856bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
857 S.Stk.push<T>(Arg);
858 return true;
859}
860
861//===----------------------------------------------------------------------===//
862// Get/Set Local/Param/Global/This
863//===----------------------------------------------------------------------===//
864
865template <PrimType Name, class T = typename PrimConv<Name>::T>
866bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
867 const Pointer &Ptr = S.Current->getLocalPointer(I);
868 if (!CheckLoad(S, OpPC, Ptr))
869 return false;
870 S.Stk.push<T>(Ptr.deref<T>());
871 return true;
872}
873
874/// 1) Pops the value from the stack.
875/// 2) Writes the value to the local variable with the
876/// given offset.
877template <PrimType Name, class T = typename PrimConv<Name>::T>
878bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
879 S.Current->setLocal<T>(I, S.Stk.pop<T>());
880 return true;
881}
882
883template <PrimType Name, class T = typename PrimConv<Name>::T>
884bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
885 if (S.checkingPotentialConstantExpression()) {
886 return false;
887 }
888 S.Stk.push<T>(S.Current->getParam<T>(I));
889 return true;
890}
891
892template <PrimType Name, class T = typename PrimConv<Name>::T>
893bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
894 S.Current->setParam<T>(I, S.Stk.pop<T>());
895 return true;
896}
897
898/// 1) Peeks a pointer on the stack
899/// 2) Pushes the value of the pointer's field on the stack
900template <PrimType Name, class T = typename PrimConv<Name>::T>
901bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
902 const Pointer &Obj = S.Stk.peek<Pointer>();
903 if (!CheckNull(S, OpPC, Obj, CSK_Field))
904 return false;
905 if (!CheckRange(S, OpPC, Obj, CSK_Field))
906 return false;
907 const Pointer &Field = Obj.atField(I);
908 if (!CheckLoad(S, OpPC, Field))
909 return false;
910 S.Stk.push<T>(Field.deref<T>());
911 return true;
912}
913
914template <PrimType Name, class T = typename PrimConv<Name>::T>
915bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
916 const T &Value = S.Stk.pop<T>();
917 const Pointer &Obj = S.Stk.peek<Pointer>();
918 if (!CheckNull(S, OpPC, Obj, CSK_Field))
919 return false;
920 if (!CheckRange(S, OpPC, Obj, CSK_Field))
921 return false;
922 const Pointer &Field = Obj.atField(I);
923 if (!CheckStore(S, OpPC, Field))
924 return false;
925 Field.initialize();
926 Field.deref<T>() = Value;
927 return true;
928}
929
930/// 1) Pops a pointer from the stack
931/// 2) Pushes the value of the pointer's field on the stack
932template <PrimType Name, class T = typename PrimConv<Name>::T>
933bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
934 const Pointer &Obj = S.Stk.pop<Pointer>();
935 if (!CheckNull(S, OpPC, Obj, CSK_Field))
936 return false;
937 if (!CheckRange(S, OpPC, Obj, CSK_Field))
938 return false;
939 const Pointer &Field = Obj.atField(I);
940 if (!CheckLoad(S, OpPC, Field))
941 return false;
942 S.Stk.push<T>(Field.deref<T>());
943 return true;
944}
945
946template <PrimType Name, class T = typename PrimConv<Name>::T>
947bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
948 if (S.checkingPotentialConstantExpression())
949 return false;
950 const Pointer &This = S.Current->getThis();
951 if (!CheckThis(S, OpPC, This))
952 return false;
953 const Pointer &Field = This.atField(I);
954 if (!CheckLoad(S, OpPC, Field))
955 return false;
956 S.Stk.push<T>(Field.deref<T>());
957 return true;
958}
959
960template <PrimType Name, class T = typename PrimConv<Name>::T>
961bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
962 if (S.checkingPotentialConstantExpression())
963 return false;
964 const T &Value = S.Stk.pop<T>();
965 const Pointer &This = S.Current->getThis();
966 if (!CheckThis(S, OpPC, This))
967 return false;
968 const Pointer &Field = This.atField(I);
969 if (!CheckStore(S, OpPC, Field))
970 return false;
971 Field.deref<T>() = Value;
972 return true;
973}
974
975template <PrimType Name, class T = typename PrimConv<Name>::T>
976bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
977 auto *B = S.P.getGlobal(I);
978 if (B->isExtern())
979 return false;
980 S.Stk.push<T>(B->deref<T>());
981 return true;
982}
983
984template <PrimType Name, class T = typename PrimConv<Name>::T>
985bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
986 // TODO: emit warning.
987 return false;
988}
989
990template <PrimType Name, class T = typename PrimConv<Name>::T>
991bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
992 S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
993 return true;
994}
995
996/// 1) Converts the value on top of the stack to an APValue
997/// 2) Sets that APValue on \Temp
998/// 3) Initialized global with index \I with that
999template <PrimType Name, class T = typename PrimConv<Name>::T>
1000bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
1001 const LifetimeExtendedTemporaryDecl *Temp) {
1002 assert(Temp);
1003 const T Value = S.Stk.peek<T>();
1004 APValue APV = Value.toAPValue();
1005 APValue *Cached = Temp->getOrCreateValue(true);
1006 *Cached = APV;
1007
1008 S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
1009 return true;
1010}
1011
1012/// 1) Converts the value on top of the stack to an APValue
1013/// 2) Sets that APValue on \Temp
1014/// 3) Initialized global with index \I with that
1016 const LifetimeExtendedTemporaryDecl *Temp) {
1017 assert(Temp);
1018 const Pointer &P = S.Stk.peek<Pointer>();
1019 APValue *Cached = Temp->getOrCreateValue(true);
1020
1021 *Cached = P.toRValue(S.getCtx());
1022 return true;
1023}
1024
1025template <PrimType Name, class T = typename PrimConv<Name>::T>
1026bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1027 if (S.checkingPotentialConstantExpression())
1028 return false;
1029 const Pointer &This = S.Current->getThis();
1030 if (!CheckThis(S, OpPC, This))
1031 return false;
1032 const Pointer &Field = This.atField(I);
1033 Field.deref<T>() = S.Stk.pop<T>();
1034 Field.initialize();
1035 return true;
1036}
1037
1038template <PrimType Name, class T = typename PrimConv<Name>::T>
1040 if (S.checkingPotentialConstantExpression())
1041 return false;
1042 const Pointer &This = S.Current->getThis();
1043 if (!CheckThis(S, OpPC, This))
1044 return false;
1045 const Pointer &Field = This.atField(F->Offset);
1046 const auto &Value = S.Stk.pop<T>();
1047 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1048 Field.initialize();
1049 return true;
1050}
1051
1052template <PrimType Name, class T = typename PrimConv<Name>::T>
1053bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1054 if (S.checkingPotentialConstantExpression())
1055 return false;
1056 const Pointer &This = S.Current->getThis();
1057 if (!CheckThis(S, OpPC, This))
1058 return false;
1059 const Pointer &Field = This.atField(I);
1060 Field.deref<T>() = S.Stk.pop<T>();
1061 Field.activate();
1062 Field.initialize();
1063 return true;
1064}
1065
1066/// 1) Pops the value from the stack
1067/// 2) Peeks a pointer from the stack
1068/// 3) Pushes the value to field I of the pointer on the stack
1069template <PrimType Name, class T = typename PrimConv<Name>::T>
1070bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
1071 const T &Value = S.Stk.pop<T>();
1072 const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
1073 Field.deref<T>() = Value;
1074 Field.activate();
1075 Field.initialize();
1076 return true;
1077}
1078
1079template <PrimType Name, class T = typename PrimConv<Name>::T>
1081 const T &Value = S.Stk.pop<T>();
1082 const Pointer &Field = S.Stk.pop<Pointer>().atField(F->Offset);
1083 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1084 Field.activate();
1085 Field.initialize();
1086 return true;
1087}
1088
1089template <PrimType Name, class T = typename PrimConv<Name>::T>
1090bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1091 const T &Value = S.Stk.pop<T>();
1092 const Pointer &Ptr = S.Stk.pop<Pointer>();
1093 const Pointer &Field = Ptr.atField(I);
1094 Field.deref<T>() = Value;
1095 Field.activate();
1096 Field.initialize();
1097 return true;
1098}
1099
1100//===----------------------------------------------------------------------===//
1101// GetPtr Local/Param/Global/Field/This
1102//===----------------------------------------------------------------------===//
1103
1104inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1105 S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
1106 return true;
1107}
1108
1109inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1110 if (S.checkingPotentialConstantExpression()) {
1111 return false;
1112 }
1113 S.Stk.push<Pointer>(S.Current->getParamPointer(I));
1114 return true;
1115}
1116
1117inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1118 S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
1119 return true;
1120}
1121
1122/// 1) Pops a Pointer from the stack
1123/// 2) Pushes Pointer.atField(Off) on the stack
1124inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1125 const Pointer &Ptr = S.Stk.pop<Pointer>();
1126 if (!CheckNull(S, OpPC, Ptr, CSK_Field))
1127 return false;
1128 if (!CheckExtern(S, OpPC, Ptr))
1129 return false;
1130 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1131 return false;
1132 if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1133 return false;
1134
1135 S.Stk.push<Pointer>(Ptr.atField(Off));
1136 return true;
1137}
1138
1139inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1140 if (S.checkingPotentialConstantExpression())
1141 return false;
1142 const Pointer &This = S.Current->getThis();
1143 if (!CheckThis(S, OpPC, This))
1144 return false;
1145 S.Stk.push<Pointer>(This.atField(Off));
1146 return true;
1147}
1148
1149inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1150 const Pointer &Ptr = S.Stk.pop<Pointer>();
1151 if (!CheckNull(S, OpPC, Ptr, CSK_Field))
1152 return false;
1153 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1154 return false;
1155 Pointer Field = Ptr.atField(Off);
1156 Ptr.deactivate();
1157 Field.activate();
1158 S.Stk.push<Pointer>(std::move(Field));
1159 return true;
1160}
1161
1162inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1163 if (S.checkingPotentialConstantExpression())
1164 return false;
1165 const Pointer &This = S.Current->getThis();
1166 if (!CheckThis(S, OpPC, This))
1167 return false;
1168 Pointer Field = This.atField(Off);
1169 This.deactivate();
1170 Field.activate();
1171 S.Stk.push<Pointer>(std::move(Field));
1172 return true;
1173}
1174
1175inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1176 const Pointer &Ptr = S.Stk.pop<Pointer>();
1177 if (!CheckNull(S, OpPC, Ptr, CSK_Derived))
1178 return false;
1179 if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
1180 return false;
1181 S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
1182 return true;
1183}
1184
1185inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1186 const Pointer &Ptr = S.Stk.peek<Pointer>();
1187 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1188 return false;
1189 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1190 return false;
1191 S.Stk.push<Pointer>(Ptr.atField(Off));
1192 return true;
1193}
1194
1195inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1196 const Pointer &Ptr = S.Stk.pop<Pointer>();
1197 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1198 return false;
1199 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1200 return false;
1201 S.Stk.push<Pointer>(Ptr.atField(Off));
1202 return true;
1203}
1204
1205inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1206 if (S.checkingPotentialConstantExpression())
1207 return false;
1208 const Pointer &This = S.Current->getThis();
1209 if (!CheckThis(S, OpPC, This))
1210 return false;
1211 S.Stk.push<Pointer>(This.atField(Off));
1212 return true;
1213}
1214
1215inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1216 const Pointer &Ptr) {
1217 Pointer Base = Ptr;
1218 while (Base.isBaseClass())
1219 Base = Base.getBase();
1220
1221 auto *Field = Base.getRecord()->getVirtualBase(Decl);
1222 S.Stk.push<Pointer>(Base.atField(Field->Offset));
1223 return true;
1224}
1225
1226inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
1227 const Pointer &Ptr = S.Stk.pop<Pointer>();
1228 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1229 return false;
1230 return VirtBaseHelper(S, OpPC, D, Ptr);
1231}
1232
1234 const RecordDecl *D) {
1235 if (S.checkingPotentialConstantExpression())
1236 return false;
1237 const Pointer &This = S.Current->getThis();
1238 if (!CheckThis(S, OpPC, This))
1239 return false;
1240 return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
1241}
1242
1243//===----------------------------------------------------------------------===//
1244// Load, Store, Init
1245//===----------------------------------------------------------------------===//
1246
1247template <PrimType Name, class T = typename PrimConv<Name>::T>
1248bool Load(InterpState &S, CodePtr OpPC) {
1249 const Pointer &Ptr = S.Stk.peek<Pointer>();
1250 if (!CheckLoad(S, OpPC, Ptr))
1251 return false;
1252 S.Stk.push<T>(Ptr.deref<T>());
1253 return true;
1254}
1255
1256template <PrimType Name, class T = typename PrimConv<Name>::T>
1258 const Pointer &Ptr = S.Stk.pop<Pointer>();
1259 if (!CheckLoad(S, OpPC, Ptr))
1260 return false;
1261 S.Stk.push<T>(Ptr.deref<T>());
1262 return true;
1263}
1264
1265template <PrimType Name, class T = typename PrimConv<Name>::T>
1266bool Store(InterpState &S, CodePtr OpPC) {
1267 const T &Value = S.Stk.pop<T>();
1268 const Pointer &Ptr = S.Stk.peek<Pointer>();
1269 if (!CheckStore(S, OpPC, Ptr))
1270 return false;
1271 if (!Ptr.isRoot())
1272 Ptr.initialize();
1273 Ptr.deref<T>() = Value;
1274 return true;
1275}
1276
1277template <PrimType Name, class T = typename PrimConv<Name>::T>
1279 const T &Value = S.Stk.pop<T>();
1280 const Pointer &Ptr = S.Stk.pop<Pointer>();
1281 if (!CheckStore(S, OpPC, Ptr))
1282 return false;
1283 if (!Ptr.isRoot())
1284 Ptr.initialize();
1285 Ptr.deref<T>() = Value;
1286 return true;
1287}
1288
1289template <PrimType Name, class T = typename PrimConv<Name>::T>
1291 const T &Value = S.Stk.pop<T>();
1292 const Pointer &Ptr = S.Stk.peek<Pointer>();
1293 if (!CheckStore(S, OpPC, Ptr))
1294 return false;
1295 if (!Ptr.isRoot())
1296 Ptr.initialize();
1297 if (auto *FD = Ptr.getField()) {
1298 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1299 } else {
1300 Ptr.deref<T>() = Value;
1301 }
1302 return true;
1303}
1304
1305template <PrimType Name, class T = typename PrimConv<Name>::T>
1307 const T &Value = S.Stk.pop<T>();
1308 const Pointer &Ptr = S.Stk.pop<Pointer>();
1309 if (!CheckStore(S, OpPC, Ptr))
1310 return false;
1311 if (!Ptr.isRoot())
1312 Ptr.initialize();
1313 if (auto *FD = Ptr.getField()) {
1314 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1315 } else {
1316 Ptr.deref<T>() = Value;
1317 }
1318 return true;
1319}
1320
1321template <PrimType Name, class T = typename PrimConv<Name>::T>
1323 const T &Value = S.Stk.pop<T>();
1324 const Pointer &Ptr = S.Stk.pop<Pointer>();
1325 if (!CheckInit(S, OpPC, Ptr))
1326 return false;
1327 Ptr.initialize();
1328 new (&Ptr.deref<T>()) T(Value);
1329 return true;
1330}
1331
1332/// 1) Pops the value from the stack
1333/// 2) Peeks a pointer and gets its index \Idx
1334/// 3) Sets the value on the pointer, leaving the pointer on the stack.
1335template <PrimType Name, class T = typename PrimConv<Name>::T>
1336bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1337 const T &Value = S.Stk.pop<T>();
1338 const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
1339 if (!CheckInit(S, OpPC, Ptr))
1340 return false;
1341 Ptr.initialize();
1342 new (&Ptr.deref<T>()) T(Value);
1343 return true;
1344}
1345
1346/// The same as InitElem, but pops the pointer as well.
1347template <PrimType Name, class T = typename PrimConv<Name>::T>
1348bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1349 const T &Value = S.Stk.pop<T>();
1350 const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
1351 if (!CheckInit(S, OpPC, Ptr))
1352 return false;
1353 Ptr.initialize();
1354 new (&Ptr.deref<T>()) T(Value);
1355 return true;
1356}
1357
1358//===----------------------------------------------------------------------===//
1359// AddOffset, SubOffset
1360//===----------------------------------------------------------------------===//
1361
1362template <class T, ArithOp Op>
1363bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
1364 const Pointer &Ptr) {
1365 if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
1366 return false;
1367
1368 // A zero offset does not change the pointer.
1369 if (Offset.isZero()) {
1370 S.Stk.push<Pointer>(Ptr);
1371 return true;
1372 }
1373
1374 if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
1375 return false;
1376
1377 // Arrays of unknown bounds cannot have pointers into them.
1378 if (!CheckArray(S, OpPC, Ptr))
1379 return false;
1380
1381 // Get a version of the index comparable to the type.
1382 T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
1383 // Compute the largest index into the array.
1384 unsigned MaxIndex = Ptr.getNumElems();
1385
1386 // Helper to report an invalid offset, computed as APSInt.
1387 auto InvalidOffset = [&]() {
1388 const unsigned Bits = Offset.bitWidth();
1389 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
1390 APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
1391 APSInt NewIndex =
1392 (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1393 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1394 << NewIndex
1395 << /*array*/ static_cast<int>(!Ptr.inArray())
1396 << static_cast<unsigned>(MaxIndex);
1397 return false;
1398 };
1399
1400 unsigned MaxOffset = MaxIndex - Ptr.getIndex();
1401 if constexpr (Op == ArithOp::Add) {
1402 // If the new offset would be negative, bail out.
1403 if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
1404 return InvalidOffset();
1405
1406 // If the new offset would be out of bounds, bail out.
1407 if (Offset.isPositive() && Offset > MaxOffset)
1408 return InvalidOffset();
1409 } else {
1410 // If the new offset would be negative, bail out.
1411 if (Offset.isPositive() && Index < Offset)
1412 return InvalidOffset();
1413
1414 // If the new offset would be out of bounds, bail out.
1415 if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
1416 return InvalidOffset();
1417 }
1418
1419 // Offset is valid - compute it on unsigned.
1420 int64_t WideIndex = static_cast<int64_t>(Index);
1421 int64_t WideOffset = static_cast<int64_t>(Offset);
1422 int64_t Result;
1423 if constexpr (Op == ArithOp::Add)
1424 Result = WideIndex + WideOffset;
1425 else
1426 Result = WideIndex - WideOffset;
1427
1428 S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
1429 return true;
1430}
1431
1432template <PrimType Name, class T = typename PrimConv<Name>::T>
1434 const T &Offset = S.Stk.pop<T>();
1435 const Pointer &Ptr = S.Stk.pop<Pointer>();
1436 return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
1437}
1438
1439template <PrimType Name, class T = typename PrimConv<Name>::T>
1441 const T &Offset = S.Stk.pop<T>();
1442 const Pointer &Ptr = S.Stk.pop<Pointer>();
1443 return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);
1444}
1445
1446template <ArithOp Op>
1447static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
1448 const Pointer &Ptr) {
1449 using OneT = Integral<8, false>;
1450
1451 // Get the current value on the stack.
1452 S.Stk.push<Pointer>(Ptr.deref<Pointer>());
1453
1454 // Now the current Ptr again and a constant 1.
1455 Pointer P = Ptr.deref<Pointer>();
1456 OneT One = OneT::from(1);
1457 if (!OffsetHelper<OneT, Op>(S, OpPC, One, P))
1458 return false;
1459
1460 // Store the new value.
1461 Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
1462 return true;
1463}
1464
1465static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
1466 const Pointer &Ptr = S.Stk.pop<Pointer>();
1467
1468 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
1469 return false;
1470
1471 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
1472}
1473
1474static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
1475 const Pointer &Ptr = S.Stk.pop<Pointer>();
1476
1477 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
1478 return false;
1479
1480 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
1481}
1482
1483/// 1) Pops a Pointer from the stack.
1484/// 2) Pops another Pointer from the stack.
1485/// 3) Pushes the different of the indices of the two pointers on the stack.
1486template <PrimType Name, class T = typename PrimConv<Name>::T>
1487inline bool SubPtr(InterpState &S, CodePtr OpPC) {
1488 const Pointer &LHS = S.Stk.pop<Pointer>();
1489 const Pointer &RHS = S.Stk.pop<Pointer>();
1490
1491 if (!Pointer::hasSameArray(LHS, RHS)) {
1492 // TODO: Diagnose.
1493 return false;
1494 }
1495
1496 T A = T::from(LHS.getIndex());
1497 T B = T::from(RHS.getIndex());
1498 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
1499}
1500
1501//===----------------------------------------------------------------------===//
1502// Destroy
1503//===----------------------------------------------------------------------===//
1504
1505inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
1506 S.Current->destroy(I);
1507 return true;
1508}
1509
1510//===----------------------------------------------------------------------===//
1511// Cast, CastFP
1512//===----------------------------------------------------------------------===//
1513
1514template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
1515 using T = typename PrimConv<TIn>::T;
1516 using U = typename PrimConv<TOut>::T;
1517 S.Stk.push<U>(U::from(S.Stk.pop<T>()));
1518 return true;
1519}
1520
1521/// 1) Pops a Floating from the stack.
1522/// 2) Pushes a new floating on the stack that uses the given semantics.
1523inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
1524 llvm::RoundingMode RM) {
1525 Floating F = S.Stk.pop<Floating>();
1526 Floating Result = F.toSemantics(Sem, RM);
1527 S.Stk.push<Floating>(Result);
1528 return true;
1529}
1530
1531template <PrimType Name, class T = typename PrimConv<Name>::T>
1533 const llvm::fltSemantics *Sem,
1534 llvm::RoundingMode RM) {
1535 const T &From = S.Stk.pop<T>();
1536 APSInt FromAP = From.toAPSInt();
1538
1539 auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
1540 S.Stk.push<Floating>(Result);
1541
1542 return CheckFloatResult(S, OpPC, Result, Status);
1543}
1544
1545template <PrimType Name, class T = typename PrimConv<Name>::T>
1547 const Floating &F = S.Stk.pop<Floating>();
1548
1549 if constexpr (std::is_same_v<T, Boolean>) {
1550 S.Stk.push<T>(T(F.isNonZero()));
1551 return true;
1552 } else {
1553 APSInt Result(std::max(8u, T::bitWidth() + 1),
1554 /*IsUnsigned=*/!T::isSigned());
1555 auto Status = F.convertToInteger(Result);
1556
1557 // Float-to-Integral overflow check.
1558 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
1559 const Expr *E = S.Current->getExpr(OpPC);
1560 QualType Type = E->getType();
1561
1562 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
1563 return S.noteUndefinedBehavior();
1564 }
1565
1566 S.Stk.push<T>(T(Result));
1567 return CheckFloatResult(S, OpPC, F, Status);
1568 }
1569}
1570
1571template <PrimType Name, class T = typename PrimConv<Name>::T>
1573 const Pointer &Ptr = S.Stk.pop<Pointer>();
1574
1575 if (!CheckPotentialReinterpretCast(S, OpPC, Ptr))
1576 return false;
1577
1578 S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
1579 return true;
1580}
1581
1582//===----------------------------------------------------------------------===//
1583// Zero, Nullptr
1584//===----------------------------------------------------------------------===//
1585
1586template <PrimType Name, class T = typename PrimConv<Name>::T>
1587bool Zero(InterpState &S, CodePtr OpPC) {
1588 S.Stk.push<T>(T::zero());
1589 return true;
1590}
1591
1592template <PrimType Name, class T = typename PrimConv<Name>::T>
1593inline bool Null(InterpState &S, CodePtr OpPC) {
1594 S.Stk.push<T>();
1595 return true;
1596}
1597
1598//===----------------------------------------------------------------------===//
1599// This, ImplicitThis
1600//===----------------------------------------------------------------------===//
1601
1602inline bool This(InterpState &S, CodePtr OpPC) {
1603 // Cannot read 'this' in this mode.
1604 if (S.checkingPotentialConstantExpression()) {
1605 return false;
1606 }
1607
1608 const Pointer &This = S.Current->getThis();
1609 if (!CheckThis(S, OpPC, This))
1610 return false;
1611
1612 S.Stk.push<Pointer>(This);
1613 return true;
1614}
1615
1616inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
1617 assert(S.Current->getFunction()->hasRVO());
1618 if (S.checkingPotentialConstantExpression())
1619 return false;
1620 S.Stk.push<Pointer>(S.Current->getRVOPtr());
1621 return true;
1622}
1623
1624//===----------------------------------------------------------------------===//
1625// Shr, Shl
1626//===----------------------------------------------------------------------===//
1627
1628template <PrimType NameL, PrimType NameR>
1629inline bool Shr(InterpState &S, CodePtr OpPC) {
1630 using LT = typename PrimConv<NameL>::T;
1631 using RT = typename PrimConv<NameR>::T;
1632 const auto &RHS = S.Stk.pop<RT>();
1633 const auto &LHS = S.Stk.pop<LT>();
1634 const unsigned Bits = LHS.bitWidth();
1635
1636 if (!CheckShift(S, OpPC, LHS, RHS, Bits))
1637 return false;
1638
1639 Integral<LT::bitWidth(), false> R;
1640 Integral<LT::bitWidth(), false>::shiftRight(LHS.toUnsigned(), RHS, Bits, &R);
1641 S.Stk.push<LT>(R);
1642 return true;
1643}
1644
1645template <PrimType NameL, PrimType NameR>
1646inline bool Shl(InterpState &S, CodePtr OpPC) {
1647 using LT = typename PrimConv<NameL>::T;
1648 using RT = typename PrimConv<NameR>::T;
1649 const auto &RHS = S.Stk.pop<RT>();
1650 const auto &LHS = S.Stk.pop<LT>();
1651 const unsigned Bits = LHS.bitWidth();
1652
1653 if (!CheckShift(S, OpPC, LHS, RHS, Bits))
1654 return false;
1655
1656 Integral<LT::bitWidth(), false> R;
1657 Integral<LT::bitWidth(), false>::shiftLeft(LHS.toUnsigned(), RHS, Bits, &R);
1658 S.Stk.push<LT>(R);
1659 return true;
1660}
1661
1662//===----------------------------------------------------------------------===//
1663// NoRet
1664//===----------------------------------------------------------------------===//
1665
1666inline bool NoRet(InterpState &S, CodePtr OpPC) {
1667 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
1668 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
1669 return false;
1670}
1671
1672//===----------------------------------------------------------------------===//
1673// NarrowPtr, ExpandPtr
1674//===----------------------------------------------------------------------===//
1675
1676inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
1677 const Pointer &Ptr = S.Stk.pop<Pointer>();
1678 S.Stk.push<Pointer>(Ptr.narrow());
1679 return true;
1680}
1681
1682inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
1683 const Pointer &Ptr = S.Stk.pop<Pointer>();
1684 S.Stk.push<Pointer>(Ptr.expand());
1685 return true;
1686}
1687
1688// 1) Pops an integral value from the stack
1689// 2) Peeks a pointer
1690// 3) Pushes a new pointer that's a narrowed array
1691// element of the peeked pointer with the value
1692// from 1) added as offset.
1693//
1694// This leaves the original pointer on the stack and pushes a new one
1695// with the offset applied and narrowed.
1696template <PrimType Name, class T = typename PrimConv<Name>::T>
1697inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
1698 const T &Offset = S.Stk.pop<T>();
1699 const Pointer &Ptr = S.Stk.peek<Pointer>();
1700
1701 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
1702 return false;
1703
1704 return NarrowPtr(S, OpPC);
1705}
1706
1707template <PrimType Name, class T = typename PrimConv<Name>::T>
1708inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
1709 const T &Offset = S.Stk.pop<T>();
1710 const Pointer &Ptr = S.Stk.pop<Pointer>();
1711
1712 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
1713 return false;
1714
1715 return NarrowPtr(S, OpPC);
1716}
1717
1718inline bool CheckGlobalCtor(InterpState &S, CodePtr OpPC) {
1719 const Pointer &Obj = S.Stk.peek<Pointer>();
1720 return CheckCtorCall(S, OpPC, Obj);
1721}
1722
1723inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func) {
1724 if (Func->hasThisPointer()) {
1725 size_t ThisOffset =
1726 Func->getArgSize() + (Func->hasRVO() ? primSize(PT_Ptr) : 0);
1727
1728 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
1729
1730 // If the current function is a lambda static invoker and
1731 // the function we're about to call is a lambda call operator,
1732 // skip the CheckInvoke, since the ThisPtr is a null pointer
1733 // anyway.
1734 if (!(S.Current->getFunction() &&
1735 S.Current->getFunction()->isLambdaStaticInvoker() &&
1736 Func->isLambdaCallOperator())) {
1737 if (!CheckInvoke(S, OpPC, ThisPtr))
1738 return false;
1739 }
1740
1741 if (S.checkingPotentialConstantExpression())
1742 return false;
1743 }
1744
1745 if (!CheckCallable(S, OpPC, Func))
1746 return false;
1747
1748 if (!CheckCallDepth(S, OpPC))
1749 return false;
1750
1751 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC);
1752 InterpFrame *FrameBefore = S.Current;
1753 S.Current = NewFrame.get();
1754
1755 APValue CallResult;
1756 // Note that we cannot assert(CallResult.hasValue()) here since
1757 // Ret() above only sets the APValue if the curent frame doesn't
1758 // have a caller set.
1759 if (Interpret(S, CallResult)) {
1760 NewFrame.release(); // Frame was delete'd already.
1761 assert(S.Current == FrameBefore);
1762 return true;
1763 }
1764
1765 // Interpreting the function failed somehow. Reset to
1766 // previous state.
1767 S.Current = FrameBefore;
1768 return false;
1769}
1770
1771inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func) {
1772 assert(Func->hasThisPointer());
1773 assert(Func->isVirtual());
1774 size_t ThisOffset =
1775 Func->getArgSize() + (Func->hasRVO() ? primSize(PT_Ptr) : 0);
1776 Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
1777
1778 const CXXRecordDecl *DynamicDecl =
1779 ThisPtr.getDeclDesc()->getType()->getAsCXXRecordDecl();
1780 const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());
1781 const auto *InitialFunction = cast<CXXMethodDecl>(Func->getDecl());
1782 const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
1783 DynamicDecl, StaticDecl, InitialFunction);
1784
1785 if (Overrider != InitialFunction) {
1786 // DR1872: An instantiated virtual constexpr function can't be called in a
1787 // constant expression (prior to C++20). We can still constant-fold such a
1788 // call.
1789 if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {
1790 const Expr *E = S.Current->getExpr(OpPC);
1791 S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();
1792 }
1793
1794 Func = S.getContext().getOrCreateFunction(Overrider);
1795
1796 const CXXRecordDecl *ThisFieldDecl =
1797 ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
1798 if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
1799 // If the function we call is further DOWN the hierarchy than the
1800 // FieldDesc of our pointer, just get the DeclDesc instead, which
1801 // is the furthest we might go up in the hierarchy.
1802 ThisPtr = ThisPtr.getDeclPtr();
1803 }
1804 }
1805
1806 return Call(S, OpPC, Func);
1807}
1808
1809inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
1810 const CallExpr *CE) {
1811 auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
1812
1813 InterpFrame *FrameBefore = S.Current;
1814 S.Current = NewFrame.get();
1815
1816 if (InterpretBuiltin(S, PC, Func, CE)) {
1817 NewFrame.release();
1818 return true;
1819 }
1820 S.Current = FrameBefore;
1821 return false;
1822}
1823
1824inline bool CallPtr(InterpState &S, CodePtr OpPC) {
1825 const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();
1826
1827 const Function *F = FuncPtr.getFunction();
1828 if (!F || !F->isConstexpr())
1829 return false;
1830
1831 if (F->isVirtual())
1832 return CallVirt(S, OpPC, F);
1833
1834 return Call(S, OpPC, F);
1835}
1836
1837inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
1838 assert(Func);
1839 S.Stk.push<FunctionPointer>(Func);
1840 return true;
1841}
1842
1843/// Just emit a diagnostic. The expression that caused emission of this
1844/// op is not valid in a constant context.
1845inline bool Invalid(InterpState &S, CodePtr OpPC) {
1846 const SourceLocation &Loc = S.Current->getLocation(OpPC);
1847 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
1848 << S.Current->getRange(OpPC);
1849 return false;
1850}
1851
1852/// Same here, but only for casts.
1853inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) {
1854 const SourceLocation &Loc = S.Current->getLocation(OpPC);
1855 S.FFDiag(Loc, diag::note_constexpr_invalid_cast)
1856 << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
1857 return false;
1858}
1859
1861 const DeclRefExpr *DR) {
1862 assert(DR);
1863 return CheckDeclRef(S, OpPC, DR);
1864}
1865
1866template <PrimType Name, class T = typename PrimConv<Name>::T>
1867inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
1868 llvm::SmallVector<int64_t> ArrayIndices;
1869 for (size_t I = 0; I != E->getNumExpressions(); ++I)
1870 ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
1871
1872 int64_t Result;
1873 if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
1874 return false;
1875
1876 S.Stk.push<T>(T::from(Result));
1877
1878 return true;
1879}
1880
1881//===----------------------------------------------------------------------===//
1882// Read opcode arguments
1883//===----------------------------------------------------------------------===//
1884
1885template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
1886 if constexpr (std::is_pointer<T>::value) {
1887 uint32_t ID = OpPC.read<uint32_t>();
1888 return reinterpret_cast<T>(S.P.getNativePointer(ID));
1889 } else {
1890 return OpPC.read<T>();
1891 }
1892}
1893
1894template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
1896 OpPC += align(F.bytesToSerialize());
1897 return F;
1898}
1899
1900} // namespace interp
1901} // namespace clang
1902
1903#endif
Defines the clang::ASTContext interface.
#define V(N, I)
Definition: ASTContext.h:3233
ASTImporterLookupTable & LT
StringRef P
static char ID
Definition: Arena.cpp:163
llvm::APSInt APSInt
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
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:2035
bool isVirtual() const
Definition: DeclCXX.h:2079
Represents a C++ struct/union/class.
Definition: DeclCXX.h:254
bool isDerivedFrom(const CXXRecordDecl *Base) const
Determine whether this class is derived from the class Base.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2832
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1242
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:83
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:330
QualType getType() const
Definition: Expr.h:142
unsigned getBitWidthValue(const ASTContext &Ctx) const
Computes the bit width of this field, if this is a bit field.
Definition: Decl.cpp:4472
Implicit declaration of a temporary that was materialized by a MaterializeTemporaryExpr and lifetime-...
Definition: DeclCXX.h:3183
APValue * getOrCreateValue(bool MayCreate) const
Get the storage for the constant value of a materialized temporary of static storage duration.
Definition: DeclCXX.cpp:3012
OffsetOfExpr - [C99 7.17] - This represents an expression of the form offsetof(record-type,...
Definition: Expr.h:2477
unsigned getNumExpressions() const
Definition: Expr.h:2553
A (possibly-)qualified type.
Definition: Type.h:736
Represents a struct/union/class.
Definition: Decl.h:4036
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:325
The base class of the type hierarchy.
Definition: Type.h:1597
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1823
Wrapper around boolean types.
Definition: Boolean.h:25
static bool inv(Boolean A, Boolean *R)
Definition: Boolean.h:138
static Boolean from(T Value)
Definition: Boolean.h:91
Pointer into the code segment.
Definition: Source.h:26
std::enable_if_t<!std::is_pointer< T >::value, T > read()
Reads data and advances the pointer.
Definition: Source.h:51
static APFloat::opStatus div(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:193
static Floating deserialize(const std::byte *Buff)
Definition: Floating.h:146
static APFloat::opStatus sub(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:174
const APFloat & getAPFloat() const
Definition: Floating.h:40
static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:167
static APFloat::opStatus fromIntegral(APSInt Val, const llvm::fltSemantics &Sem, llvm::RoundingMode RM, Floating &Result)
Definition: Floating.h:112
Floating toSemantics(const llvm::fltSemantics *Sem, llvm::RoundingMode RM) const
Definition: Floating.h:55
size_t bytesToSerialize() const
Definition: Floating.h:132
static APFloat::opStatus add(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:161
static APFloat::opStatus mul(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:187
bool isNonZero() const
Definition: Floating.h:86
bool isFinite() const
Definition: Floating.h:91
static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM, Floating *R)
Definition: Floating.h:180
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:75
const CXXRecordDecl * getParentDecl() const
Returns the parent record decl, if any.
Definition: Function.h:142
bool isLambdaCallOperator() const
Returns whether this function is the call operator of a lambda record decl.
Definition: Function.h:158
const FunctionDecl * getDecl() const
Returns the original FunctionDecl.
Definition: Function.h:90
bool hasThisPointer() const
Definition: Function.h:167
bool isVirtual() const
Checks if the function is virtual.
Definition: Function.cpp:46
unsigned getArgSize() const
Returns the size of the argument stack.
Definition: Function.h:82
bool hasRVO() const
Checks if the first argument is a RVO pointer.
Definition: Function.h:108
Wrapper around numeric types.
Definition: Integral.h:48
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:65
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition: Pointer.cpp:218
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition: Pointer.h:121
void deactivate() const
Deactivates an entire strurcutre.
Definition: Pointer.cpp:214
Pointer atFieldSub(unsigned Off) const
Subtract the given offset from the current Base and Offset of the pointer.
Definition: Pointer.h:114
int64_t getIndex() const
Returns the index into an array.
Definition: Pointer.h:326
Pointer atIndex(unsigned Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:95
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:107
T & deref() const
Dereferences the pointer, if it's live.
Definition: Pointer.h:343
unsigned getNumElems() const
Returns the number of elements.
Definition: Pointer.h:321
bool inArray() const
Checks if the innermost field is an array.
Definition: Pointer.h:261
Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition: Pointer.h:216
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
Definition: Pointer.cpp:153
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:185
bool isRoot() const
Pointer points directly to a block.
Definition: Pointer.h:271
Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition: Pointer.h:192
static bool hasSameArray(const Pointer &A, const Pointer &B)
Checks if two pointers can be subtracted.
Definition: Pointer.cpp:222
unsigned getIntegerRepresentation() const
Definition: Pointer.h:87
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
Definition: Pointer.h:157
Pointer getDeclPtr() const
Definition: Pointer.h:229
void initialize() const
Initializes a field.
Definition: Pointer.cpp:180
unsigned getByteOffset() const
Returns the byte offset from the start.
Definition: Pointer.h:316
Describes the statement/declaration an opcode was generated from.
Definition: Source.h:68
bool CheckPotentialReinterpretCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if reinterpret casts are legal in the current context.
Definition: Interp.cpp:487
bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, unsigned Bits)
Checks if the shift operation is legal.
Definition: Interp.h:117
bool popBuiltinArgs(InterpState &S, CodePtr OpPC)
Pop arguments of builtins defined as func-name(...).
Definition: Interp.cpp:125
bool InitPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1322
bool Inv(InterpState &S, CodePtr OpPC)
Definition: Interp.h:458
bool Shr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1629
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) Initialized ...
Definition: Interp.h:1000
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:576
bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1195
bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:322
bool GT(InterpState &S, CodePtr OpPC)
Definition: Interp.h:807
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be initialized.
Definition: Interp.cpp:312
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:603
bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:947
bool NarrowPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1676
llvm::APInt APInt
Definition: Integral.h:29
bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1026
bool Interpret(InterpState &S, APValue &Result)
Interpreter entry point.
Definition: Interp.cpp:577
Floating ReadArg< Floating >(InterpState &S, CodePtr &OpPC)
Definition: Interp.h:1894
bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:632
bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:884
bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx)
The same as InitElem, but pops the pointer as well.
Definition: Interp.h:1348
bool StoreBitField(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1290
bool LoadPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1257
bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:659
static bool IncPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1465
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:547
bool Dup(InterpState &S, CodePtr OpPC)
Definition: Interp.h:840
bool CheckCallDepth(InterpState &S, CodePtr OpPC)
Checks if calling the currently active function would exceed the allowed call depth.
Definition: Interp.cpp:366
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks the 'this' pointer.
Definition: Interp.cpp:377
bool SetField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:915
bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, llvm::ArrayRef< int64_t > ArrayIndices, int64_t &Result)
Interpret an offsetof operation.
bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This)
Checks that all fields are initialized after a constructor call.
Definition: Interp.cpp:478
static bool IncDecPtrHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition: Interp.h:1447
bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1104
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:153
bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, const T &RHS)
Definition: Interp.h:265
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:1124
bool Div(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:424
bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to a mutable field.
Definition: Interp.cpp:245
bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func)
Definition: Interp.h:1837
bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1162
bool SubPtr(InterpState &S, CodePtr OpPC)
1) Pops a Pointer from the stack.
Definition: Interp.h:1487
bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if Ptr is a one-past-the-end pointer.
Definition: Interp.cpp:216
bool ReturnValue(const T &V, APValue &R)
Convert a value to an APValue.
Definition: Interp.h:44
bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1117
bool Call(InterpState &S, CodePtr OpPC, const Function *Func)
Definition: Interp.h:1723
bool ArrayElemPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1697
bool NE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:785
bool NoRet(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1666
bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:304
bool Shl(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1646
bool RVOPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1616
bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition: Interp.cpp:258
bool CastPointerIntegral(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1572
bool SubOffset(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1440
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition: PrimType.h:82
bool BitXor(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:387
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is in range.
Definition: Interp.cpp:198
bool Ret(InterpState &S, CodePtr &PC, APValue &Result)
Definition: Interp.h:202
bool ExpandPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1682
bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1053
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD)
Checks if a method is pure virtual.
Definition: Interp.cpp:395
bool Store(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1266
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:901
bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1708
bool This(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1602
bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:340
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:1070
bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, llvm::RoundingMode RM)
Definition: Interp.h:613
bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:698
llvm::function_ref< bool(ComparisonCategoryResult)> CompareFn
Definition: Interp.h:686
T ReadArg(InterpState &S, CodePtr &OpPC)
Definition: Interp.h:1885
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is live and accessible.
Definition: Interp.cpp:159
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:1015
bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition: Interp.h:514
bool CastFloatingIntegral(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1546
bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:866
bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E)
Definition: Interp.h:1867
bool BitAnd(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:353
bool CastIntegralFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
Definition: Interp.h:1532
bool LE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:799
bool Zero(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1587
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be stored in a block.
Definition: Interp.cpp:288
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK)
Checks if a pointer is null.
Definition: Interp.cpp:189
bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
1) Pops a Floating from the stack.
Definition: Interp.h:1523
bool CallPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1824
ComparisonCategoryResult Compare(const T &X, const T &Y)
Helper to compare two comparable types.
Definition: Primitives.h:25
bool CheckGlobalCtor(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1718
bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:961
bool StoreBitFieldPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1306
static bool DecPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1474
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func)
Definition: Interp.h:1771
bool Null(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1593
bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1090
bool Rem(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:404
bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, const Pointer &Ptr)
Definition: Interp.h:1215
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be loaded from a block.
Definition: Interp.cpp:270
bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:641
bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1139
bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1149
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
Definition: Interp.cpp:151
bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:650
bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1175
bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1185
bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:893
bool CmpHelper< FunctionPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Function pointers cannot be compared in an ordered way.
Definition: Interp.h:704
bool Comp(InterpState &S, CodePtr OpPC)
1) Pops the value from the stack.
Definition: Interp.h:671
bool StorePop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1278
bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F)
Definition: Interp.h:1039
bool CallBI(InterpState &S, CodePtr &PC, const Function *Func, const CallExpr *CE)
Definition: Interp.h:1809
bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
1) Pops the value from the stack.
Definition: Interp.h:878
bool Mul(InterpState &S, CodePtr OpPC)
Definition: Interp.h:333
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:1336
bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1505
bool Pop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:846
bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind)
Same here, but only for casts.
Definition: Interp.h:1853
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
Definition: PrimType.cpp:21
bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F)
Definition: Interp.h:1080
bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)
Definition: Interp.h:1226
bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR)
Definition: Interp.h:1860
bool InRange(InterpState &S, CodePtr OpPC)
Definition: Interp.h:826
bool CmpHelperEQ< FunctionPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:717
bool Neg(InterpState &S, CodePtr OpPC)
Definition: Interp.h:474
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:138
bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:440
bool BitOr(InterpState &S, CodePtr OpPC)
1) Pops the RHS from the stack.
Definition: Interp.h:370
bool Load(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1248
bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:985
bool Cast(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1514
bool EQ(InterpState &S, CodePtr OpPC)
Definition: Interp.h:778
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:933
bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F)
Checks if a method can be called.
Definition: Interp.cpp:320
bool AddOffset(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1433
bool Const(InterpState &S, CodePtr OpPC, const T &Arg)
Definition: Interp.h:856
bool GE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:814
bool CmpHelperEQ< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:746
constexpr bool isIntegralType(PrimType T)
Definition: PrimType.h:59
bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:689
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer points to const storage.
Definition: Interp.cpp:226
bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1109
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:976
bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)
Definition: Interp.h:1233
bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:991
bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result)
Definition: Interp.h:243
bool CmpHelper< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:726
bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a method can be invoked on an object.
Definition: Interp.cpp:302
bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1205
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:498
bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, const Pointer &Ptr)
Definition: Interp.h:1363
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
#define bool
Definition: stdbool.h:20
QualType getType() const
Definition: Descriptor.cpp:278
Mapping from primitive types to their representation.
Definition: PrimType.h:62
Describes a record field.
Definition: Record.h:28
const FieldDecl * Decl
Definition: Record.h:29