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