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