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