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
659inline bool Inv(InterpState &S, CodePtr OpPC) {
660 const auto &Val = S.Stk.pop<Boolean>();
661 S.Stk.push<Boolean>(!Val);
662 return true;
663}
664
665//===----------------------------------------------------------------------===//
666// Neg
667//===----------------------------------------------------------------------===//
668
669template <PrimType Name, class T = typename PrimConv<Name>::T>
670bool Neg(InterpState &S, CodePtr OpPC) {
671 const T &Value = S.Stk.pop<T>();
672 T Result;
673
674 if (!T::neg(Value, &Result)) {
675 S.Stk.push<T>(Result);
676 return true;
677 }
678
679 assert(isIntegralType(Name) &&
680 "don't expect other types to fail at constexpr negation");
681 S.Stk.push<T>(Result);
682
683 APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
684 const Expr *E = S.Current->getExpr(OpPC);
685 QualType Type = E->getType();
686
687 if (S.checkingForUndefinedBehavior()) {
688 SmallString<32> Trunc;
689 NegatedValue.trunc(Result.bitWidth())
690 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
691 /*UpperCase=*/true, /*InsertSeparators=*/true);
692 auto Loc = E->getExprLoc();
693 S.report(Loc, diag::warn_integer_constant_overflow)
694 << Trunc << Type << E->getSourceRange();
695 return true;
696 }
697
698 S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue << Type;
699 return S.noteUndefinedBehavior();
700}
701
702enum class PushVal : bool {
703 No,
704 Yes,
705};
706enum class IncDecOp {
707 Inc,
708 Dec,
709};
710
711template <typename T, IncDecOp Op, PushVal DoPush>
712bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
713 assert(!Ptr.isDummy());
714
715 if constexpr (std::is_same_v<T, Boolean>) {
716 if (!S.getLangOpts().CPlusPlus14)
717 return Invalid(S, OpPC);
718 }
719
720 const T &Value = Ptr.deref<T>();
721 T Result;
722
723 if constexpr (DoPush == PushVal::Yes)
724 S.Stk.push<T>(Value);
725
726 if constexpr (Op == IncDecOp::Inc) {
727 if (!T::increment(Value, &Result)) {
728 Ptr.deref<T>() = Result;
729 return true;
730 }
731 } else {
732 if (!T::decrement(Value, &Result)) {
733 Ptr.deref<T>() = Result;
734 return true;
735 }
736 }
737
738 // Something went wrong with the previous operation. Compute the
739 // result with another bit of precision.
740 unsigned Bits = Value.bitWidth() + 1;
741 APSInt APResult;
742 if constexpr (Op == IncDecOp::Inc)
743 APResult = ++Value.toAPSInt(Bits);
744 else
745 APResult = --Value.toAPSInt(Bits);
746
747 // Report undefined behaviour, stopping if required.
748 const Expr *E = S.Current->getExpr(OpPC);
749 QualType Type = E->getType();
750 if (S.checkingForUndefinedBehavior()) {
751 SmallString<32> Trunc;
752 APResult.trunc(Result.bitWidth())
753 .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
754 /*UpperCase=*/true, /*InsertSeparators=*/true);
755 auto Loc = E->getExprLoc();
756 S.report(Loc, diag::warn_integer_constant_overflow)
757 << Trunc << Type << E->getSourceRange();
758 return true;
759 }
760
761 S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
762 return S.noteUndefinedBehavior();
763}
764
765/// 1) Pops a pointer from the stack
766/// 2) Load the value from the pointer
767/// 3) Writes the value increased by one back to the pointer
768/// 4) Pushes the original (pre-inc) value on the stack.
769template <PrimType Name, class T = typename PrimConv<Name>::T>
770bool Inc(InterpState &S, CodePtr OpPC) {
771 const Pointer &Ptr = S.Stk.pop<Pointer>();
772 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
773 return false;
774
775 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
776}
777
778/// 1) Pops a pointer from the stack
779/// 2) Load the value from the pointer
780/// 3) Writes the value increased by one back to the pointer
781template <PrimType Name, class T = typename PrimConv<Name>::T>
782bool IncPop(InterpState &S, CodePtr OpPC) {
783 const Pointer &Ptr = S.Stk.pop<Pointer>();
784 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
785 return false;
786
787 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
788}
789
790/// 1) Pops a pointer from the stack
791/// 2) Load the value from the pointer
792/// 3) Writes the value decreased by one back to the pointer
793/// 4) Pushes the original (pre-dec) value on the stack.
794template <PrimType Name, class T = typename PrimConv<Name>::T>
795bool Dec(InterpState &S, CodePtr OpPC) {
796 const Pointer &Ptr = S.Stk.pop<Pointer>();
797 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
798 return false;
799
800 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
801}
802
803/// 1) Pops a pointer from the stack
804/// 2) Load the value from the pointer
805/// 3) Writes the value decreased by one back to the pointer
806template <PrimType Name, class T = typename PrimConv<Name>::T>
807bool DecPop(InterpState &S, CodePtr OpPC) {
808 const Pointer &Ptr = S.Stk.pop<Pointer>();
809 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
810 return false;
811
812 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
813}
814
815template <IncDecOp Op, PushVal DoPush>
817 llvm::RoundingMode RM) {
818 Floating Value = Ptr.deref<Floating>();
820
821 if constexpr (DoPush == PushVal::Yes)
822 S.Stk.push<Floating>(Value);
823
824 llvm::APFloat::opStatus Status;
825 if constexpr (Op == IncDecOp::Inc)
826 Status = Floating::increment(Value, RM, &Result);
827 else
828 Status = Floating::decrement(Value, RM, &Result);
829
830 Ptr.deref<Floating>() = Result;
831
832 return CheckFloatResult(S, OpPC, Result, Status);
833}
834
835inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
836 const Pointer &Ptr = S.Stk.pop<Pointer>();
837 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
838 return false;
839
840 return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM);
841}
842
843inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
844 const Pointer &Ptr = S.Stk.pop<Pointer>();
845 if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
846 return false;
847
848 return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM);
849}
850
851inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
852 const Pointer &Ptr = S.Stk.pop<Pointer>();
853 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
854 return false;
855
856 return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM);
857}
858
859inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
860 const Pointer &Ptr = S.Stk.pop<Pointer>();
861 if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
862 return false;
863
864 return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM);
865}
866
867/// 1) Pops the value from the stack.
868/// 2) Pushes the bitwise complemented value on the stack (~V).
869template <PrimType Name, class T = typename PrimConv<Name>::T>
870bool Comp(InterpState &S, CodePtr OpPC) {
871 const T &Val = S.Stk.pop<T>();
872 T Result;
873 if (!T::comp(Val, &Result)) {
874 S.Stk.push<T>(Result);
875 return true;
876 }
877
878 return false;
879}
880
881//===----------------------------------------------------------------------===//
882// EQ, NE, GT, GE, LT, LE
883//===----------------------------------------------------------------------===//
884
885using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
886
887template <typename T>
889 assert((!std::is_same_v<T, MemberPointer>) &&
890 "Non-equality comparisons on member pointer types should already be "
891 "rejected in Sema.");
892 using BoolT = PrimConv<PT_Bool>::T;
893 const T &RHS = S.Stk.pop<T>();
894 const T &LHS = S.Stk.pop<T>();
895 S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
896 return true;
897}
898
899template <typename T>
901 return CmpHelper<T>(S, OpPC, Fn);
902}
903
904/// Function pointers cannot be compared in an ordered way.
905template <>
907 CompareFn Fn) {
908 const auto &RHS = S.Stk.pop<FunctionPointer>();
909 const auto &LHS = S.Stk.pop<FunctionPointer>();
910
911 const SourceInfo &Loc = S.Current->getSource(OpPC);
912 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
913 << LHS.toDiagnosticString(S.getCtx())
914 << RHS.toDiagnosticString(S.getCtx());
915 return false;
916}
917
918template <>
920 CompareFn Fn) {
921 const auto &RHS = S.Stk.pop<FunctionPointer>();
922 const auto &LHS = S.Stk.pop<FunctionPointer>();
923
924 // We cannot compare against weak declarations at compile time.
925 for (const auto &FP : {LHS, RHS}) {
926 if (FP.isWeak()) {
927 const SourceInfo &Loc = S.Current->getSource(OpPC);
928 S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
929 << FP.toDiagnosticString(S.getCtx());
930 return false;
931 }
932 }
933
934 S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
935 return true;
936}
937
938template <>
940 using BoolT = PrimConv<PT_Bool>::T;
941 const Pointer &RHS = S.Stk.pop<Pointer>();
942 const Pointer &LHS = S.Stk.pop<Pointer>();
943
944 if (!Pointer::hasSameBase(LHS, RHS)) {
945 const SourceInfo &Loc = S.Current->getSource(OpPC);
946 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
947 << LHS.toDiagnosticString(S.getCtx())
948 << RHS.toDiagnosticString(S.getCtx());
949 return false;
950 } else {
951 unsigned VL = LHS.getByteOffset();
952 unsigned VR = RHS.getByteOffset();
953 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
954 return true;
955 }
956}
957
958template <>
960 using BoolT = PrimConv<PT_Bool>::T;
961 const Pointer &RHS = S.Stk.pop<Pointer>();
962 const Pointer &LHS = S.Stk.pop<Pointer>();
963
964 if (LHS.isZero() && RHS.isZero()) {
965 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
966 return true;
967 }
968
969 // Reject comparisons to weak pointers.
970 for (const auto &P : {LHS, RHS}) {
971 if (P.isZero())
972 continue;
973 if (P.isWeak()) {
974 const SourceInfo &Loc = S.Current->getSource(OpPC);
975 S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
976 << P.toDiagnosticString(S.getCtx());
977 return false;
978 }
979 }
980
981 if (!Pointer::hasSameBase(LHS, RHS)) {
982 if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() &&
983 RHS.getOffset() == 0) {
984 const SourceInfo &Loc = S.Current->getSource(OpPC);
985 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
986 << LHS.toDiagnosticString(S.getCtx());
987 return false;
988 } else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
989 LHS.getOffset() == 0) {
990 const SourceInfo &Loc = S.Current->getSource(OpPC);
991 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
992 << RHS.toDiagnosticString(S.getCtx());
993 return false;
994 }
995
996 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
997 return true;
998 } else {
999 unsigned VL = LHS.getByteOffset();
1000 unsigned VR = RHS.getByteOffset();
1001
1002 // In our Pointer class, a pointer to an array and a pointer to the first
1003 // element in the same array are NOT equal. They have the same Base value,
1004 // but a different Offset. This is a pretty rare case, so we fix this here
1005 // by comparing pointers to the first elements.
1006 if (!LHS.isZero() && LHS.isArrayRoot())
1007 VL = LHS.atIndex(0).getByteOffset();
1008 if (!RHS.isZero() && RHS.isArrayRoot())
1009 VR = RHS.atIndex(0).getByteOffset();
1010
1011 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
1012 return true;
1013 }
1014}
1015
1016template <>
1018 CompareFn Fn) {
1019 const auto &RHS = S.Stk.pop<MemberPointer>();
1020 const auto &LHS = S.Stk.pop<MemberPointer>();
1021
1022 // If either operand is a pointer to a weak function, the comparison is not
1023 // constant.
1024 for (const auto &MP : {LHS, RHS}) {
1025 if (const CXXMethodDecl *MD = MP.getMemberFunction(); MD && MD->isWeak()) {
1026 const SourceInfo &Loc = S.Current->getSource(OpPC);
1027 S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison) << MD;
1028 return false;
1029 }
1030 }
1031
1032 // C++11 [expr.eq]p2:
1033 // If both operands are null, they compare equal. Otherwise if only one is
1034 // null, they compare unequal.
1035 if (LHS.isZero() && RHS.isZero()) {
1037 return true;
1038 }
1039 if (LHS.isZero() || RHS.isZero()) {
1041 return true;
1042 }
1043
1044 // We cannot compare against virtual declarations at compile time.
1045 for (const auto &MP : {LHS, RHS}) {
1046 if (const CXXMethodDecl *MD = MP.getMemberFunction();
1047 MD && MD->isVirtual()) {
1048 const SourceInfo &Loc = S.Current->getSource(OpPC);
1049 S.CCEDiag(Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD;
1050 }
1051 }
1052
1053 S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
1054 return true;
1055}
1056
1057template <PrimType Name, class T = typename PrimConv<Name>::T>
1058bool EQ(InterpState &S, CodePtr OpPC) {
1059 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1061 });
1062}
1063
1064template <PrimType Name, class T = typename PrimConv<Name>::T>
1065bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
1066 const T &RHS = S.Stk.pop<T>();
1067 const T &LHS = S.Stk.pop<T>();
1068 const Pointer &P = S.Stk.peek<Pointer>();
1069
1070 ComparisonCategoryResult CmpResult = LHS.compare(RHS);
1071 if (CmpResult == ComparisonCategoryResult::Unordered) {
1072 // This should only happen with pointers.
1073 const SourceInfo &Loc = S.Current->getSource(OpPC);
1074 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1075 << LHS.toDiagnosticString(S.getCtx())
1076 << RHS.toDiagnosticString(S.getCtx());
1077 return false;
1078 }
1079
1080 assert(CmpInfo);
1081 const auto *CmpValueInfo =
1082 CmpInfo->getValueInfo(CmpInfo->makeWeakResult(CmpResult));
1083 assert(CmpValueInfo);
1084 assert(CmpValueInfo->hasValidIntValue());
1085 return SetThreeWayComparisonField(S, OpPC, P, CmpValueInfo->getIntValue());
1086}
1087
1088template <PrimType Name, class T = typename PrimConv<Name>::T>
1089bool NE(InterpState &S, CodePtr OpPC) {
1090 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1092 });
1093}
1094
1095template <PrimType Name, class T = typename PrimConv<Name>::T>
1096bool LT(InterpState &S, CodePtr OpPC) {
1097 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1099 });
1100}
1101
1102template <PrimType Name, class T = typename PrimConv<Name>::T>
1103bool LE(InterpState &S, CodePtr OpPC) {
1104 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1105 return R == ComparisonCategoryResult::Less ||
1107 });
1108}
1109
1110template <PrimType Name, class T = typename PrimConv<Name>::T>
1111bool GT(InterpState &S, CodePtr OpPC) {
1112 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1114 });
1115}
1116
1117template <PrimType Name, class T = typename PrimConv<Name>::T>
1118bool GE(InterpState &S, CodePtr OpPC) {
1119 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1122 });
1123}
1124
1125//===----------------------------------------------------------------------===//
1126// InRange
1127//===----------------------------------------------------------------------===//
1128
1129template <PrimType Name, class T = typename PrimConv<Name>::T>
1131 const T RHS = S.Stk.pop<T>();
1132 const T LHS = S.Stk.pop<T>();
1133 const T Value = S.Stk.pop<T>();
1134
1135 S.Stk.push<bool>(LHS <= Value && Value <= RHS);
1136 return true;
1137}
1138
1139//===----------------------------------------------------------------------===//
1140// Dup, Pop, Test
1141//===----------------------------------------------------------------------===//
1142
1143template <PrimType Name, class T = typename PrimConv<Name>::T>
1144bool Dup(InterpState &S, CodePtr OpPC) {
1145 S.Stk.push<T>(S.Stk.peek<T>());
1146 return true;
1147}
1148
1149template <PrimType Name, class T = typename PrimConv<Name>::T>
1150bool Pop(InterpState &S, CodePtr OpPC) {
1151 S.Stk.pop<T>();
1152 return true;
1153}
1154
1155/// [Value1, Value2] -> [Value2, Value1]
1156template <PrimType TopName, PrimType BottomName>
1157bool Flip(InterpState &S, CodePtr OpPC) {
1158 using TopT = typename PrimConv<TopName>::T;
1159 using BottomT = typename PrimConv<BottomName>::T;
1160
1161 const auto &Top = S.Stk.pop<TopT>();
1162 const auto &Bottom = S.Stk.pop<BottomT>();
1163
1164 S.Stk.push<TopT>(Top);
1165 S.Stk.push<BottomT>(Bottom);
1166
1167 return true;
1168}
1169
1170//===----------------------------------------------------------------------===//
1171// Const
1172//===----------------------------------------------------------------------===//
1173
1174template <PrimType Name, class T = typename PrimConv<Name>::T>
1175bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
1176 S.Stk.push<T>(Arg);
1177 return true;
1178}
1179
1180//===----------------------------------------------------------------------===//
1181// Get/Set Local/Param/Global/This
1182//===----------------------------------------------------------------------===//
1183
1184template <PrimType Name, class T = typename PrimConv<Name>::T>
1185bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1186 const Pointer &Ptr = S.Current->getLocalPointer(I);
1187 if (!CheckLoad(S, OpPC, Ptr))
1188 return false;
1189 S.Stk.push<T>(Ptr.deref<T>());
1190 return true;
1191}
1192
1193/// 1) Pops the value from the stack.
1194/// 2) Writes the value to the local variable with the
1195/// given offset.
1196template <PrimType Name, class T = typename PrimConv<Name>::T>
1197bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1198 S.Current->setLocal<T>(I, S.Stk.pop<T>());
1199 return true;
1200}
1201
1202template <PrimType Name, class T = typename PrimConv<Name>::T>
1203bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1204 if (S.checkingPotentialConstantExpression()) {
1205 return false;
1206 }
1207 S.Stk.push<T>(S.Current->getParam<T>(I));
1208 return true;
1209}
1210
1211template <PrimType Name, class T = typename PrimConv<Name>::T>
1212bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1213 S.Current->setParam<T>(I, S.Stk.pop<T>());
1214 return true;
1215}
1216
1217/// 1) Peeks a pointer on the stack
1218/// 2) Pushes the value of the pointer's field on the stack
1219template <PrimType Name, class T = typename PrimConv<Name>::T>
1220bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1221 const Pointer &Obj = S.Stk.peek<Pointer>();
1222 if (!CheckNull(S, OpPC, Obj, CSK_Field))
1223 return false;
1224 if (!CheckRange(S, OpPC, Obj, CSK_Field))
1225 return false;
1226 const Pointer &Field = Obj.atField(I);
1227 if (!CheckLoad(S, OpPC, Field))
1228 return false;
1229 S.Stk.push<T>(Field.deref<T>());
1230 return true;
1231}
1232
1233template <PrimType Name, class T = typename PrimConv<Name>::T>
1234bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1235 const T &Value = S.Stk.pop<T>();
1236 const Pointer &Obj = S.Stk.peek<Pointer>();
1237 if (!CheckNull(S, OpPC, Obj, CSK_Field))
1238 return false;
1239 if (!CheckRange(S, OpPC, Obj, CSK_Field))
1240 return false;
1241 const Pointer &Field = Obj.atField(I);
1242 if (!CheckStore(S, OpPC, Field))
1243 return false;
1244 Field.initialize();
1245 Field.deref<T>() = Value;
1246 return true;
1247}
1248
1249/// 1) Pops a pointer from the stack
1250/// 2) Pushes the value of the pointer's field on the stack
1251template <PrimType Name, class T = typename PrimConv<Name>::T>
1252bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
1253 const Pointer &Obj = S.Stk.pop<Pointer>();
1254 if (!CheckNull(S, OpPC, Obj, CSK_Field))
1255 return false;
1256 if (!CheckRange(S, OpPC, Obj, CSK_Field))
1257 return false;
1258 const Pointer &Field = Obj.atField(I);
1259 if (!CheckLoad(S, OpPC, Field))
1260 return false;
1261 S.Stk.push<T>(Field.deref<T>());
1262 return true;
1263}
1264
1265template <PrimType Name, class T = typename PrimConv<Name>::T>
1266bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1267 if (S.checkingPotentialConstantExpression())
1268 return false;
1269 const Pointer &This = S.Current->getThis();
1270 if (!CheckThis(S, OpPC, This))
1271 return false;
1272 const Pointer &Field = This.atField(I);
1273 if (!CheckLoad(S, OpPC, Field))
1274 return false;
1275 S.Stk.push<T>(Field.deref<T>());
1276 return true;
1277}
1278
1279template <PrimType Name, class T = typename PrimConv<Name>::T>
1280bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1281 if (S.checkingPotentialConstantExpression())
1282 return false;
1283 const T &Value = S.Stk.pop<T>();
1284 const Pointer &This = S.Current->getThis();
1285 if (!CheckThis(S, OpPC, This))
1286 return false;
1287 const Pointer &Field = This.atField(I);
1288 if (!CheckStore(S, OpPC, Field))
1289 return false;
1290 Field.deref<T>() = Value;
1291 return true;
1292}
1293
1294template <PrimType Name, class T = typename PrimConv<Name>::T>
1295bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1296 const Pointer &Ptr = S.P.getPtrGlobal(I);
1297 if (!CheckConstant(S, OpPC, Ptr.getFieldDesc()))
1298 return false;
1299 if (Ptr.isExtern())
1300 return false;
1301
1302 // If a global variable is uninitialized, that means the initializer we've
1303 // compiled for it wasn't a constant expression. Diagnose that.
1304 if (!CheckGlobalInitialized(S, OpPC, Ptr))
1305 return false;
1306
1307 S.Stk.push<T>(Ptr.deref<T>());
1308 return true;
1309}
1310
1311/// Same as GetGlobal, but without the checks.
1312template <PrimType Name, class T = typename PrimConv<Name>::T>
1313bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {
1314 const Pointer &Ptr = S.P.getPtrGlobal(I);
1315 if (!Ptr.isInitialized())
1316 return false;
1317 S.Stk.push<T>(Ptr.deref<T>());
1318 return true;
1319}
1320
1321template <PrimType Name, class T = typename PrimConv<Name>::T>
1322bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1323 // TODO: emit warning.
1324 return false;
1325}
1326
1327template <PrimType Name, class T = typename PrimConv<Name>::T>
1328bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1329 const Pointer &P = S.P.getGlobal(I);
1330 P.deref<T>() = S.Stk.pop<T>();
1331 P.initialize();
1332 return true;
1333}
1334
1335/// 1) Converts the value on top of the stack to an APValue
1336/// 2) Sets that APValue on \Temp
1337/// 3) Initializes global with index \I with that
1338template <PrimType Name, class T = typename PrimConv<Name>::T>
1339bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
1340 const LifetimeExtendedTemporaryDecl *Temp) {
1341 const Pointer &Ptr = S.P.getGlobal(I);
1342
1343 const T Value = S.Stk.peek<T>();
1344 APValue APV = Value.toAPValue(S.getCtx());
1345 APValue *Cached = Temp->getOrCreateValue(true);
1346 *Cached = APV;
1347
1348 assert(Ptr.getDeclDesc()->asExpr());
1349
1350 S.SeenGlobalTemporaries.push_back(
1351 std::make_pair(Ptr.getDeclDesc()->asExpr(), Temp));
1352
1353 Ptr.deref<T>() = S.Stk.pop<T>();
1354 Ptr.initialize();
1355 return true;
1356}
1357
1358/// 1) Converts the value on top of the stack to an APValue
1359/// 2) Sets that APValue on \Temp
1360/// 3) Initialized global with index \I with that
1362 const LifetimeExtendedTemporaryDecl *Temp) {
1363 assert(Temp);
1364 const Pointer &P = S.Stk.peek<Pointer>();
1365 APValue *Cached = Temp->getOrCreateValue(true);
1366
1367 S.SeenGlobalTemporaries.push_back(
1368 std::make_pair(P.getDeclDesc()->asExpr(), Temp));
1369
1370 if (std::optional<APValue> APV =
1371 P.toRValue(S.getCtx(), Temp->getTemporaryExpr()->getType())) {
1372 *Cached = *APV;
1373 return true;
1374 }
1375
1376 return false;
1377}
1378
1379template <PrimType Name, class T = typename PrimConv<Name>::T>
1380bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1381 if (S.checkingPotentialConstantExpression())
1382 return false;
1383 const Pointer &This = S.Current->getThis();
1384 if (!CheckThis(S, OpPC, This))
1385 return false;
1386 const Pointer &Field = This.atField(I);
1387 Field.deref<T>() = S.Stk.pop<T>();
1388 Field.activate();
1389 Field.initialize();
1390 return true;
1391}
1392
1393// FIXME: The Field pointer here is too much IMO and we could instead just
1394// pass an Offset + BitWidth pair.
1395template <PrimType Name, class T = typename PrimConv<Name>::T>
1396bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,
1397 uint32_t FieldOffset) {
1398 assert(F->isBitField());
1399 if (S.checkingPotentialConstantExpression())
1400 return false;
1401 const Pointer &This = S.Current->getThis();
1402 if (!CheckThis(S, OpPC, This))
1403 return false;
1404 const Pointer &Field = This.atField(FieldOffset);
1405 const auto &Value = S.Stk.pop<T>();
1406 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1407 Field.initialize();
1408 return true;
1409}
1410
1411/// 1) Pops the value from the stack
1412/// 2) Peeks a pointer from the stack
1413/// 3) Pushes the value to field I of the pointer on the stack
1414template <PrimType Name, class T = typename PrimConv<Name>::T>
1415bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
1416 const T &Value = S.Stk.pop<T>();
1417 const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
1418 Field.deref<T>() = Value;
1419 Field.activate();
1420 Field.initialize();
1421 return true;
1422}
1423
1424template <PrimType Name, class T = typename PrimConv<Name>::T>
1425bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
1426 assert(F->isBitField());
1427 const T &Value = S.Stk.pop<T>();
1428 const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
1429 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1430 Field.activate();
1431 Field.initialize();
1432 return true;
1433}
1434
1435//===----------------------------------------------------------------------===//
1436// GetPtr Local/Param/Global/Field/This
1437//===----------------------------------------------------------------------===//
1438
1439inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1440 S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
1441 return true;
1442}
1443
1444inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1445 if (S.checkingPotentialConstantExpression()) {
1446 return false;
1447 }
1448 S.Stk.push<Pointer>(S.Current->getParamPointer(I));
1449 return true;
1450}
1451
1452inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1453 S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
1454 return true;
1455}
1456
1457/// 1) Peeks a Pointer
1458/// 2) Pushes Pointer.atField(Off) on the stack
1459inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1460 const Pointer &Ptr = S.Stk.peek<Pointer>();
1461
1462 if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
1463 !CheckNull(S, OpPC, Ptr, CSK_Field))
1464 return false;
1465
1466 if (!CheckExtern(S, OpPC, Ptr))
1467 return false;
1468 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1469 return false;
1470 if (!CheckArray(S, OpPC, Ptr))
1471 return false;
1472 if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1473 return false;
1474
1475 if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
1476 return false;
1477
1478 if (Ptr.isIntegralPointer()) {
1479 S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getCtx(), Off));
1480 return true;
1481 }
1482
1483 S.Stk.push<Pointer>(Ptr.atField(Off));
1484 return true;
1485}
1486
1487inline bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1488 const Pointer &Ptr = S.Stk.pop<Pointer>();
1489
1490 if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
1491 !CheckNull(S, OpPC, Ptr, CSK_Field))
1492 return false;
1493
1494 if (!CheckExtern(S, OpPC, Ptr))
1495 return false;
1496 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1497 return false;
1498 if (!CheckArray(S, OpPC, Ptr))
1499 return false;
1500 if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1501 return false;
1502
1503 if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())
1504 return false;
1505
1506 if (Ptr.isIntegralPointer()) {
1507 S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getCtx(), Off));
1508 return true;
1509 }
1510
1511 S.Stk.push<Pointer>(Ptr.atField(Off));
1512 return true;
1513}
1514
1515inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1516 if (S.checkingPotentialConstantExpression())
1517 return false;
1518 const Pointer &This = S.Current->getThis();
1519 if (!CheckThis(S, OpPC, This))
1520 return false;
1521 S.Stk.push<Pointer>(This.atField(Off));
1522 return true;
1523}
1524
1525inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1526 const Pointer &Ptr = S.Stk.pop<Pointer>();
1527 if (!CheckNull(S, OpPC, Ptr, CSK_Field))
1528 return false;
1529 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1530 return false;
1531 Pointer Field = Ptr.atField(Off);
1532 Ptr.deactivate();
1533 Field.activate();
1534 S.Stk.push<Pointer>(std::move(Field));
1535 return true;
1536}
1537
1538inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1539 if (S.checkingPotentialConstantExpression())
1540 return false;
1541 const Pointer &This = S.Current->getThis();
1542 if (!CheckThis(S, OpPC, This))
1543 return false;
1544 Pointer Field = This.atField(Off);
1545 This.deactivate();
1546 Field.activate();
1547 S.Stk.push<Pointer>(std::move(Field));
1548 return true;
1549}
1550
1551inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1552 const Pointer &Ptr = S.Stk.pop<Pointer>();
1553 if (!CheckNull(S, OpPC, Ptr, CSK_Derived))
1554 return false;
1555 if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
1556 return false;
1557 if (!CheckDowncast(S, OpPC, Ptr, Off))
1558 return false;
1559
1560 S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
1561 return true;
1562}
1563
1564inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1565 const Pointer &Ptr = S.Stk.peek<Pointer>();
1566 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1567 return false;
1568 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1569 return false;
1570 const Pointer &Result = Ptr.atField(Off);
1571 if (Result.isPastEnd() || !Result.isBaseClass())
1572 return false;
1573 S.Stk.push<Pointer>(Result);
1574 return true;
1575}
1576
1577inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1578 const Pointer &Ptr = S.Stk.pop<Pointer>();
1579 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1580 return false;
1581 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1582 return false;
1583 const Pointer &Result = Ptr.atField(Off);
1584 if (Result.isPastEnd() || !Result.isBaseClass())
1585 return false;
1586 S.Stk.push<Pointer>(Result);
1587 return true;
1588}
1589
1590inline bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off) {
1591 const auto &Ptr = S.Stk.pop<MemberPointer>();
1592 S.Stk.push<MemberPointer>(Ptr.atInstanceBase(Off));
1593 return true;
1594}
1595
1596inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1597 if (S.checkingPotentialConstantExpression())
1598 return false;
1599 const Pointer &This = S.Current->getThis();
1600 if (!CheckThis(S, OpPC, This))
1601 return false;
1602 S.Stk.push<Pointer>(This.atField(Off));
1603 return true;
1604}
1605
1606inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {
1607 const Pointer &Ptr = S.Stk.pop<Pointer>();
1608 if (Ptr.canBeInitialized()) {
1609 Ptr.initialize();
1610 Ptr.activate();
1611 }
1612 return true;
1613}
1614
1615inline bool FinishInit(InterpState &S, CodePtr OpPC) {
1616 const Pointer &Ptr = S.Stk.peek<Pointer>();
1617 if (Ptr.canBeInitialized()) {
1618 Ptr.initialize();
1619 Ptr.activate();
1620 }
1621 return true;
1622}
1623
1624inline bool Dump(InterpState &S, CodePtr OpPC) {
1625 S.Stk.dump();
1626 return true;
1627}
1628
1629inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1630 const Pointer &Ptr) {
1631 Pointer Base = Ptr;
1632 while (Base.isBaseClass())
1633 Base = Base.getBase();
1634
1635 const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(Decl);
1636 S.Stk.push<Pointer>(Base.atField(VirtBase->Offset));
1637 return true;
1638}
1639
1641 const RecordDecl *D) {
1642 assert(D);
1643 const Pointer &Ptr = S.Stk.pop<Pointer>();
1644 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1645 return false;
1646 return VirtBaseHelper(S, OpPC, D, Ptr);
1647}
1648
1650 const RecordDecl *D) {
1651 assert(D);
1652 if (S.checkingPotentialConstantExpression())
1653 return false;
1654 const Pointer &This = S.Current->getThis();
1655 if (!CheckThis(S, OpPC, This))
1656 return false;
1657 return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
1658}
1659
1660//===----------------------------------------------------------------------===//
1661// Load, Store, Init
1662//===----------------------------------------------------------------------===//
1663
1664template <PrimType Name, class T = typename PrimConv<Name>::T>
1665bool Load(InterpState &S, CodePtr OpPC) {
1666 const Pointer &Ptr = S.Stk.peek<Pointer>();
1667 if (!CheckLoad(S, OpPC, Ptr))
1668 return false;
1669 if (!Ptr.isBlockPointer())
1670 return false;
1671 S.Stk.push<T>(Ptr.deref<T>());
1672 return true;
1673}
1674
1675template <PrimType Name, class T = typename PrimConv<Name>::T>
1677 const Pointer &Ptr = S.Stk.pop<Pointer>();
1678 if (!CheckLoad(S, OpPC, Ptr))
1679 return false;
1680 if (!Ptr.isBlockPointer())
1681 return false;
1682 S.Stk.push<T>(Ptr.deref<T>());
1683 return true;
1684}
1685
1686template <PrimType Name, class T = typename PrimConv<Name>::T>
1687bool Store(InterpState &S, CodePtr OpPC) {
1688 const T &Value = S.Stk.pop<T>();
1689 const Pointer &Ptr = S.Stk.peek<Pointer>();
1690 if (!CheckStore(S, OpPC, Ptr))
1691 return false;
1692 if (Ptr.canBeInitialized()) {
1693 Ptr.initialize();
1694 Ptr.activate();
1695 }
1696 Ptr.deref<T>() = Value;
1697 return true;
1698}
1699
1700template <PrimType Name, class T = typename PrimConv<Name>::T>
1702 const T &Value = S.Stk.pop<T>();
1703 const Pointer &Ptr = S.Stk.pop<Pointer>();
1704 if (!CheckStore(S, OpPC, Ptr))
1705 return false;
1706 if (Ptr.canBeInitialized()) {
1707 Ptr.initialize();
1708 Ptr.activate();
1709 }
1710 Ptr.deref<T>() = Value;
1711 return true;
1712}
1713
1714template <PrimType Name, class T = typename PrimConv<Name>::T>
1716 const T &Value = S.Stk.pop<T>();
1717 const Pointer &Ptr = S.Stk.peek<Pointer>();
1718 if (!CheckStore(S, OpPC, Ptr))
1719 return false;
1720 if (Ptr.canBeInitialized())
1721 Ptr.initialize();
1722 if (const auto *FD = Ptr.getField())
1723 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1724 else
1725 Ptr.deref<T>() = Value;
1726 return true;
1727}
1728
1729template <PrimType Name, class T = typename PrimConv<Name>::T>
1731 const T &Value = S.Stk.pop<T>();
1732 const Pointer &Ptr = S.Stk.pop<Pointer>();
1733 if (!CheckStore(S, OpPC, Ptr))
1734 return false;
1735 if (Ptr.canBeInitialized())
1736 Ptr.initialize();
1737 if (const auto *FD = Ptr.getField())
1738 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1739 else
1740 Ptr.deref<T>() = Value;
1741 return true;
1742}
1743
1744template <PrimType Name, class T = typename PrimConv<Name>::T>
1745bool Init(InterpState &S, CodePtr OpPC) {
1746 const T &Value = S.Stk.pop<T>();
1747 const Pointer &Ptr = S.Stk.peek<Pointer>();
1748 if (!CheckInit(S, OpPC, Ptr)) {
1749 assert(false);
1750 return false;
1751 }
1752 Ptr.initialize();
1753 new (&Ptr.deref<T>()) T(Value);
1754 return true;
1755}
1756
1757template <PrimType Name, class T = typename PrimConv<Name>::T>
1759 const T &Value = S.Stk.pop<T>();
1760 const Pointer &Ptr = S.Stk.pop<Pointer>();
1761 if (!CheckInit(S, OpPC, Ptr))
1762 return false;
1763 Ptr.initialize();
1764 new (&Ptr.deref<T>()) T(Value);
1765 return true;
1766}
1767
1768/// 1) Pops the value from the stack
1769/// 2) Peeks a pointer and gets its index \Idx
1770/// 3) Sets the value on the pointer, leaving the pointer on the stack.
1771template <PrimType Name, class T = typename PrimConv<Name>::T>
1772bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1773 const T &Value = S.Stk.pop<T>();
1774 const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
1775 if (Ptr.isUnknownSizeArray())
1776 return false;
1777 if (!CheckInit(S, OpPC, Ptr))
1778 return false;
1779 Ptr.initialize();
1780 new (&Ptr.deref<T>()) T(Value);
1781 return true;
1782}
1783
1784/// The same as InitElem, but pops the pointer as well.
1785template <PrimType Name, class T = typename PrimConv<Name>::T>
1786bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1787 const T &Value = S.Stk.pop<T>();
1788 const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
1789 if (Ptr.isUnknownSizeArray())
1790 return false;
1791 if (!CheckInit(S, OpPC, Ptr))
1792 return false;
1793 Ptr.initialize();
1794 new (&Ptr.deref<T>()) T(Value);
1795 return true;
1796}
1797
1798inline bool Memcpy(InterpState &S, CodePtr OpPC) {
1799 const Pointer &Src = S.Stk.pop<Pointer>();
1800 Pointer &Dest = S.Stk.peek<Pointer>();
1801
1802 if (!CheckLoad(S, OpPC, Src))
1803 return false;
1804
1805 return DoMemcpy(S, OpPC, Src, Dest);
1806}
1807
1808inline bool ToMemberPtr(InterpState &S, CodePtr OpPC) {
1809 const auto &Member = S.Stk.pop<MemberPointer>();
1810 const auto &Base = S.Stk.pop<Pointer>();
1811
1812 S.Stk.push<MemberPointer>(Member.takeInstance(Base));
1813 return true;
1814}
1815
1816inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) {
1817 const auto &MP = S.Stk.pop<MemberPointer>();
1818
1819 if (std::optional<Pointer> Ptr = MP.toPointer(S.Ctx)) {
1820 S.Stk.push<Pointer>(*Ptr);
1821 return true;
1822 }
1823 return false;
1824}
1825
1826//===----------------------------------------------------------------------===//
1827// AddOffset, SubOffset
1828//===----------------------------------------------------------------------===//
1829
1830template <class T, ArithOp Op>
1831bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
1832 const Pointer &Ptr) {
1833 // A zero offset does not change the pointer.
1834 if (Offset.isZero()) {
1835 S.Stk.push<Pointer>(Ptr);
1836 return true;
1837 }
1838
1839 if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) {
1840 // The CheckNull will have emitted a note already, but we only
1841 // abort in C++, since this is fine in C.
1842 if (S.getLangOpts().CPlusPlus)
1843 return false;
1844 }
1845
1846 // Arrays of unknown bounds cannot have pointers into them.
1847 if (!CheckArray(S, OpPC, Ptr))
1848 return false;
1849
1850 // This is much simpler for integral pointers, so handle them first.
1851 if (Ptr.isIntegralPointer()) {
1852 uint64_t V = Ptr.getIntegerRepresentation();
1853 uint64_t O = static_cast<uint64_t>(Offset) * Ptr.elemSize();
1854 if constexpr (Op == ArithOp::Add)
1855 S.Stk.push<Pointer>(V + O, Ptr.asIntPointer().Desc);
1856 else
1857 S.Stk.push<Pointer>(V - O, Ptr.asIntPointer().Desc);
1858 return true;
1859 }
1860
1861 uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());
1862 uint64_t Index;
1863 if (Ptr.isOnePastEnd())
1864 Index = MaxIndex;
1865 else
1866 Index = Ptr.getIndex();
1867
1868 bool Invalid = false;
1869 // Helper to report an invalid offset, computed as APSInt.
1870 auto DiagInvalidOffset = [&]() -> void {
1871 const unsigned Bits = Offset.bitWidth();
1872 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false);
1873 APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true),
1874 /*IsUnsigned=*/false);
1875 APSInt NewIndex =
1876 (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1877 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1878 << NewIndex << /*array*/ static_cast<int>(!Ptr.inArray()) << MaxIndex;
1879 Invalid = true;
1880 };
1881
1882 if (Ptr.isBlockPointer()) {
1883 uint64_t IOffset = static_cast<uint64_t>(Offset);
1884 uint64_t MaxOffset = MaxIndex - Index;
1885
1886 if constexpr (Op == ArithOp::Add) {
1887 // If the new offset would be negative, bail out.
1888 if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
1889 DiagInvalidOffset();
1890
1891 // If the new offset would be out of bounds, bail out.
1892 if (Offset.isPositive() && IOffset > MaxOffset)
1893 DiagInvalidOffset();
1894 } else {
1895 // If the new offset would be negative, bail out.
1896 if (Offset.isPositive() && Index < IOffset)
1897 DiagInvalidOffset();
1898
1899 // If the new offset would be out of bounds, bail out.
1900 if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
1901 DiagInvalidOffset();
1902 }
1903 }
1904
1905 if (Invalid && S.getLangOpts().CPlusPlus)
1906 return false;
1907
1908 // Offset is valid - compute it on unsigned.
1909 int64_t WideIndex = static_cast<int64_t>(Index);
1910 int64_t WideOffset = static_cast<int64_t>(Offset);
1911 int64_t Result;
1912 if constexpr (Op == ArithOp::Add)
1913 Result = WideIndex + WideOffset;
1914 else
1915 Result = WideIndex - WideOffset;
1916
1917 // When the pointer is one-past-end, going back to index 0 is the only
1918 // useful thing we can do. Any other index has been diagnosed before and
1919 // we don't get here.
1920 if (Result == 0 && Ptr.isOnePastEnd()) {
1921 S.Stk.push<Pointer>(Ptr.asBlockPointer().Pointee,
1922 Ptr.asBlockPointer().Base);
1923 return true;
1924 }
1925
1926 S.Stk.push<Pointer>(Ptr.atIndex(static_cast<uint64_t>(Result)));
1927 return true;
1928}
1929
1930template <PrimType Name, class T = typename PrimConv<Name>::T>
1932 const T &Offset = S.Stk.pop<T>();
1933 const Pointer &Ptr = S.Stk.pop<Pointer>();
1934 return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
1935}
1936
1937template <PrimType Name, class T = typename PrimConv<Name>::T>
1939 const T &Offset = S.Stk.pop<T>();
1940 const Pointer &Ptr = S.Stk.pop<Pointer>();
1941 return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);
1942}
1943
1944template <ArithOp Op>
1945static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
1946 const Pointer &Ptr) {
1947 if (Ptr.isDummy())
1948 return false;
1949
1950 using OneT = Integral<8, false>;
1951
1952 const Pointer &P = Ptr.deref<Pointer>();
1953 if (!CheckNull(S, OpPC, P, CSK_ArrayIndex))
1954 return false;
1955
1956 // Get the current value on the stack.
1957 S.Stk.push<Pointer>(P);
1958
1959 // Now the current Ptr again and a constant 1.
1960 OneT One = OneT::from(1);
1961 if (!OffsetHelper<OneT, Op>(S, OpPC, One, P))
1962 return false;
1963
1964 // Store the new value.
1965 Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
1966 return true;
1967}
1968
1969static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
1970 const Pointer &Ptr = S.Stk.pop<Pointer>();
1971
1972 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
1973 return false;
1974
1975 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
1976}
1977
1978static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
1979 const Pointer &Ptr = S.Stk.pop<Pointer>();
1980
1981 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
1982 return false;
1983
1984 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
1985}
1986
1987/// 1) Pops a Pointer from the stack.
1988/// 2) Pops another Pointer from the stack.
1989/// 3) Pushes the different of the indices of the two pointers on the stack.
1990template <PrimType Name, class T = typename PrimConv<Name>::T>
1991inline bool SubPtr(InterpState &S, CodePtr OpPC) {
1992 const Pointer &LHS = S.Stk.pop<Pointer>();
1993 const Pointer &RHS = S.Stk.pop<Pointer>();
1994
1995 for (const Pointer &P : {LHS, RHS}) {
1996 if (P.isZeroSizeArray()) {
1997 QualType PtrT = P.getType();
1998 while (auto *AT = dyn_cast<ArrayType>(PtrT))
1999 PtrT = AT->getElementType();
2000
2001 QualType ArrayTy = S.getCtx().getConstantArrayType(
2002 PtrT, APInt::getZero(1), nullptr, ArraySizeModifier::Normal, 0);
2003 S.FFDiag(S.Current->getSource(OpPC),
2004 diag::note_constexpr_pointer_subtraction_zero_size)
2005 << ArrayTy;
2006
2007 return false;
2008 }
2009 }
2010
2011 if (RHS.isZero()) {
2012 S.Stk.push<T>(T::from(LHS.getIndex()));
2013 return true;
2014 }
2015
2016 if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
2017 // TODO: Diagnose.
2018 return false;
2019 }
2020
2021 if (LHS.isZero() && RHS.isZero()) {
2022 S.Stk.push<T>();
2023 return true;
2024 }
2025
2026 T A = LHS.isElementPastEnd() ? T::from(LHS.getNumElems())
2027 : T::from(LHS.getIndex());
2028 T B = RHS.isElementPastEnd() ? T::from(RHS.getNumElems())
2029 : T::from(RHS.getIndex());
2030 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
2031}
2032
2033//===----------------------------------------------------------------------===//
2034// Destroy
2035//===----------------------------------------------------------------------===//
2036
2037inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
2038 S.Current->destroy(I);
2039 return true;
2040}
2041
2042inline bool InitScope(InterpState &S, CodePtr OpPC, uint32_t I) {
2043 S.Current->initScope(I);
2044 return true;
2045}
2046
2047//===----------------------------------------------------------------------===//
2048// Cast, CastFP
2049//===----------------------------------------------------------------------===//
2050
2051template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
2052 using T = typename PrimConv<TIn>::T;
2053 using U = typename PrimConv<TOut>::T;
2054 S.Stk.push<U>(U::from(S.Stk.pop<T>()));
2055 return true;
2056}
2057
2058/// 1) Pops a Floating from the stack.
2059/// 2) Pushes a new floating on the stack that uses the given semantics.
2060inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
2061 llvm::RoundingMode RM) {
2062 Floating F = S.Stk.pop<Floating>();
2063 Floating Result = F.toSemantics(Sem, RM);
2064 S.Stk.push<Floating>(Result);
2065 return true;
2066}
2067
2068/// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
2069/// to know what bitwidth the result should be.
2070template <PrimType Name, class T = typename PrimConv<Name>::T>
2071bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2072 S.Stk.push<IntegralAP<false>>(
2073 IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth));
2074 return true;
2075}
2076
2077template <PrimType Name, class T = typename PrimConv<Name>::T>
2078bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2079 S.Stk.push<IntegralAP<true>>(
2080 IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth));
2081 return true;
2082}
2083
2084template <PrimType Name, class T = typename PrimConv<Name>::T>
2086 const llvm::fltSemantics *Sem,
2087 llvm::RoundingMode RM) {
2088 const T &From = S.Stk.pop<T>();
2089 APSInt FromAP = From.toAPSInt();
2091
2092 auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
2093 S.Stk.push<Floating>(Result);
2094
2095 return CheckFloatResult(S, OpPC, Result, Status);
2096}
2097
2098template <PrimType Name, class T = typename PrimConv<Name>::T>
2100 const Floating &F = S.Stk.pop<Floating>();
2101
2102 if constexpr (std::is_same_v<T, Boolean>) {
2103 S.Stk.push<T>(T(F.isNonZero()));
2104 return true;
2105 } else {
2106 APSInt Result(std::max(8u, T::bitWidth()),
2107 /*IsUnsigned=*/!T::isSigned());
2108 auto Status = F.convertToInteger(Result);
2109
2110 // Float-to-Integral overflow check.
2111 if ((Status & APFloat::opStatus::opInvalidOp)) {
2112 const Expr *E = S.Current->getExpr(OpPC);
2113 QualType Type = E->getType();
2114
2115 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2116 if (S.noteUndefinedBehavior()) {
2117 S.Stk.push<T>(T(Result));
2118 return true;
2119 }
2120 return false;
2121 }
2122
2123 S.Stk.push<T>(T(Result));
2124 return CheckFloatResult(S, OpPC, F, Status);
2125 }
2126}
2127
2128static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
2129 uint32_t BitWidth) {
2130 const Floating &F = S.Stk.pop<Floating>();
2131
2132 APSInt Result(BitWidth, /*IsUnsigned=*/true);
2133 auto Status = F.convertToInteger(Result);
2134
2135 // Float-to-Integral overflow check.
2136 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
2137 const Expr *E = S.Current->getExpr(OpPC);
2138 QualType Type = E->getType();
2139
2140 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2141 return S.noteUndefinedBehavior();
2142 }
2143
2145 return CheckFloatResult(S, OpPC, F, Status);
2146}
2147
2148static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
2149 uint32_t BitWidth) {
2150 const Floating &F = S.Stk.pop<Floating>();
2151
2152 APSInt Result(BitWidth, /*IsUnsigned=*/false);
2153 auto Status = F.convertToInteger(Result);
2154
2155 // Float-to-Integral overflow check.
2156 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
2157 const Expr *E = S.Current->getExpr(OpPC);
2158 QualType Type = E->getType();
2159
2160 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2161 return S.noteUndefinedBehavior();
2162 }
2163
2165 return CheckFloatResult(S, OpPC, F, Status);
2166}
2167
2168template <PrimType Name, class T = typename PrimConv<Name>::T>
2170 const Pointer &Ptr = S.Stk.pop<Pointer>();
2171
2172 if (Ptr.isDummy())
2173 return false;
2174
2175 const SourceInfo &E = S.Current->getSource(OpPC);
2176 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2177 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2178
2179 S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
2180 return true;
2181}
2182
2183static inline bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC,
2184 uint32_t BitWidth) {
2185 const Pointer &Ptr = S.Stk.pop<Pointer>();
2186
2187 if (Ptr.isDummy())
2188 return false;
2189
2190 const SourceInfo &E = S.Current->getSource(OpPC);
2191 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2192 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2193
2194 S.Stk.push<IntegralAP<false>>(
2196 return true;
2197}
2198
2199static inline bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC,
2200 uint32_t BitWidth) {
2201 const Pointer &Ptr = S.Stk.pop<Pointer>();
2202
2203 if (Ptr.isDummy())
2204 return false;
2205
2206 const SourceInfo &E = S.Current->getSource(OpPC);
2207 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2208 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2209
2210 S.Stk.push<IntegralAP<true>>(
2212 return true;
2213}
2214
2215static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {
2216 const auto &Ptr = S.Stk.peek<Pointer>();
2217
2218 if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {
2219 bool HasValidResult = !Ptr.isZero();
2220
2221 if (HasValidResult) {
2222 // FIXME: note_constexpr_invalid_void_star_cast
2223 } else if (!S.getLangOpts().CPlusPlus26) {
2224 const SourceInfo &E = S.Current->getSource(OpPC);
2225 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2226 << 3 << "'void *'" << S.Current->getRange(OpPC);
2227 }
2228 } else {
2229 const SourceInfo &E = S.Current->getSource(OpPC);
2230 S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2231 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2232 }
2233
2234 return true;
2235}
2236
2237//===----------------------------------------------------------------------===//
2238// Zero, Nullptr
2239//===----------------------------------------------------------------------===//
2240
2241template <PrimType Name, class T = typename PrimConv<Name>::T>
2242bool Zero(InterpState &S, CodePtr OpPC) {
2243 S.Stk.push<T>(T::zero());
2244 return true;
2245}
2246
2247static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2248 S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth));
2249 return true;
2250}
2251
2252static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2253 S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth));
2254 return true;
2255}
2256
2257template <PrimType Name, class T = typename PrimConv<Name>::T>
2258inline bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2259 // Note: Desc can be null.
2260 S.Stk.push<T>(0, Desc);
2261 return true;
2262}
2263
2264//===----------------------------------------------------------------------===//
2265// This, ImplicitThis
2266//===----------------------------------------------------------------------===//
2267
2268inline bool This(InterpState &S, CodePtr OpPC) {
2269 // Cannot read 'this' in this mode.
2270 if (S.checkingPotentialConstantExpression()) {
2271 return false;
2272 }
2273
2274 const Pointer &This = S.Current->getThis();
2275 if (!CheckThis(S, OpPC, This))
2276 return false;
2277
2278 // Ensure the This pointer has been cast to the correct base.
2279 if (!This.isDummy()) {
2280 assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
2281 assert(This.getRecord());
2282 assert(
2283 This.getRecord()->getDecl() ==
2284 cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent());
2285 }
2286
2287 S.Stk.push<Pointer>(This);
2288 return true;
2289}
2290
2291inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
2292 assert(S.Current->getFunction()->hasRVO());
2293 if (S.checkingPotentialConstantExpression())
2294 return false;
2295 S.Stk.push<Pointer>(S.Current->getRVOPtr());
2296 return true;
2297}
2298
2299//===----------------------------------------------------------------------===//
2300// Shr, Shl
2301//===----------------------------------------------------------------------===//
2302enum class ShiftDir { Left, Right };
2303
2304template <class LT, class RT, ShiftDir Dir>
2305inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
2306 const unsigned Bits = LHS.bitWidth();
2307
2308 // OpenCL 6.3j: shift values are effectively % word size of LHS.
2309 if (S.getLangOpts().OpenCL)
2310 RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
2311 RHS.bitWidth(), &RHS);
2312
2313 if (RHS.isNegative()) {
2314 // During constant-folding, a negative shift is an opposite shift. Such a
2315 // shift is not a constant expression.
2316 const SourceInfo &Loc = S.Current->getSource(OpPC);
2317 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
2318 if (!S.noteUndefinedBehavior())
2319 return false;
2320 RHS = -RHS;
2321 return DoShift<LT, RT,
2323 S, OpPC, LHS, RHS);
2324 }
2325
2326 if constexpr (Dir == ShiftDir::Left) {
2327 if (LHS.isNegative() && !S.getLangOpts().CPlusPlus20) {
2328 // C++11 [expr.shift]p2: A signed left shift must have a non-negative
2329 // operand, and must not overflow the corresponding unsigned type.
2330 // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to
2331 // E1 x 2^E2 module 2^N.
2332 const SourceInfo &Loc = S.Current->getSource(OpPC);
2333 S.CCEDiag(Loc, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
2334 if (!S.noteUndefinedBehavior())
2335 return false;
2336 }
2337 }
2338
2339 if (!CheckShift(S, OpPC, LHS, RHS, Bits))
2340 return false;
2341
2342 // Limit the shift amount to Bits - 1. If this happened,
2343 // it has already been diagnosed by CheckShift() above,
2344 // but we still need to handle it.
2345 typename LT::AsUnsigned R;
2346 if constexpr (Dir == ShiftDir::Left) {
2347 if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
2348 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2349 LT::AsUnsigned::from(Bits - 1), Bits, &R);
2350 else
2351 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2352 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2353 } else {
2354 if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
2355 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
2356 LT::AsUnsigned::from(Bits - 1), Bits, &R);
2357 else
2358 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
2359 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2360 }
2361
2362 // We did the shift above as unsigned. Restore the sign bit if we need to.
2363 if constexpr (Dir == ShiftDir::Right) {
2364 if (LHS.isSigned() && LHS.isNegative()) {
2365 typename LT::AsUnsigned SignBit;
2366 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(1, Bits),
2367 LT::AsUnsigned::from(Bits - 1, Bits), Bits,
2368 &SignBit);
2369 LT::AsUnsigned::bitOr(R, SignBit, Bits, &R);
2370 }
2371 }
2372
2373 S.Stk.push<LT>(LT::from(R));
2374 return true;
2375}
2376
2377template <PrimType NameL, PrimType NameR>
2378inline bool Shr(InterpState &S, CodePtr OpPC) {
2379 using LT = typename PrimConv<NameL>::T;
2380 using RT = typename PrimConv<NameR>::T;
2381 auto RHS = S.Stk.pop<RT>();
2382 auto LHS = S.Stk.pop<LT>();
2383
2384 return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS);
2385}
2386
2387template <PrimType NameL, PrimType NameR>
2388inline bool Shl(InterpState &S, CodePtr OpPC) {
2389 using LT = typename PrimConv<NameL>::T;
2390 using RT = typename PrimConv<NameR>::T;
2391 auto RHS = S.Stk.pop<RT>();
2392 auto LHS = S.Stk.pop<LT>();
2393
2394 return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS);
2395}
2396
2397//===----------------------------------------------------------------------===//
2398// NoRet
2399//===----------------------------------------------------------------------===//
2400
2401inline bool NoRet(InterpState &S, CodePtr OpPC) {
2402 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
2403 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
2404 return false;
2405}
2406
2407//===----------------------------------------------------------------------===//
2408// NarrowPtr, ExpandPtr
2409//===----------------------------------------------------------------------===//
2410
2411inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
2412 const Pointer &Ptr = S.Stk.pop<Pointer>();
2413 S.Stk.push<Pointer>(Ptr.narrow());
2414 return true;
2415}
2416
2417inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
2418 const Pointer &Ptr = S.Stk.pop<Pointer>();
2419 S.Stk.push<Pointer>(Ptr.expand());
2420 return true;
2421}
2422
2423// 1) Pops an integral value from the stack
2424// 2) Peeks a pointer
2425// 3) Pushes a new pointer that's a narrowed array
2426// element of the peeked pointer with the value
2427// from 1) added as offset.
2428//
2429// This leaves the original pointer on the stack and pushes a new one
2430// with the offset applied and narrowed.
2431template <PrimType Name, class T = typename PrimConv<Name>::T>
2432inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
2433 const T &Offset = S.Stk.pop<T>();
2434 const Pointer &Ptr = S.Stk.peek<Pointer>();
2435
2436 if (!Ptr.isZero() && !Offset.isZero()) {
2437 if (!CheckArray(S, OpPC, Ptr))
2438 return false;
2439 }
2440
2441 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2442 return false;
2443
2444 return NarrowPtr(S, OpPC);
2445}
2446
2447template <PrimType Name, class T = typename PrimConv<Name>::T>
2448inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
2449 const T &Offset = S.Stk.pop<T>();
2450 const Pointer &Ptr = S.Stk.pop<Pointer>();
2451
2452 if (!Ptr.isZero() && !Offset.isZero()) {
2453 if (!CheckArray(S, OpPC, Ptr))
2454 return false;
2455 }
2456
2457 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
2458 return false;
2459
2460 return NarrowPtr(S, OpPC);
2461}
2462
2463template <PrimType Name, class T = typename PrimConv<Name>::T>
2464inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {
2465 const Pointer &Ptr = S.Stk.peek<Pointer>();
2466
2467 if (!CheckLoad(S, OpPC, Ptr))
2468 return false;
2469
2470 S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
2471 return true;
2472}
2473
2474template <PrimType Name, class T = typename PrimConv<Name>::T>
2475inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
2476 const Pointer &Ptr = S.Stk.pop<Pointer>();
2477
2478 if (!CheckLoad(S, OpPC, Ptr))
2479 return false;
2480
2481 S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
2482 return true;
2483}
2484
2485template <PrimType Name, class T = typename PrimConv<Name>::T>
2486inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex,
2487 uint32_t DestIndex, uint32_t Size) {
2488 const auto &SrcPtr = S.Stk.pop<Pointer>();
2489 const auto &DestPtr = S.Stk.peek<Pointer>();
2490
2491 for (uint32_t I = 0; I != Size; ++I) {
2492 const Pointer &SP = SrcPtr.atIndex(SrcIndex + I);
2493
2494 if (!CheckLoad(S, OpPC, SP))
2495 return false;
2496
2497 const Pointer &DP = DestPtr.atIndex(DestIndex + I);
2498 DP.deref<T>() = SP.deref<T>();
2499 DP.initialize();
2500 }
2501 return true;
2502}
2503
2504/// Just takes a pointer and checks if it's an incomplete
2505/// array type.
2506inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
2507 const Pointer &Ptr = S.Stk.pop<Pointer>();
2508
2509 if (Ptr.isZero()) {
2510 S.Stk.push<Pointer>(Ptr);
2511 return true;
2512 }
2513
2514 if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
2515 return false;
2516
2517 if (Ptr.isRoot() || !Ptr.isUnknownSizeArray() || Ptr.isDummy()) {
2518 S.Stk.push<Pointer>(Ptr.atIndex(0));
2519 return true;
2520 }
2521
2522 const SourceInfo &E = S.Current->getSource(OpPC);
2523 S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
2524
2525 return false;
2526}
2527
2528inline bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
2529 uint32_t VarArgSize) {
2530 if (Func->hasThisPointer()) {
2531 size_t ArgSize = Func->getArgSize() + VarArgSize;
2532 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
2533 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
2534
2535 // If the current function is a lambda static invoker and
2536 // the function we're about to call is a lambda call operator,
2537 // skip the CheckInvoke, since the ThisPtr is a null pointer
2538 // anyway.
2539 if (!(S.Current->getFunction() &&
2540 S.Current->getFunction()->isLambdaStaticInvoker() &&
2541 Func->isLambdaCallOperator())) {
2542 if (!CheckInvoke(S, OpPC, ThisPtr))
2543 return false;
2544 }
2545
2546 if (S.checkingPotentialConstantExpression())
2547 return false;
2548 }
2549
2550 if (!CheckCallable(S, OpPC, Func))
2551 return false;
2552
2553 if (!CheckCallDepth(S, OpPC))
2554 return false;
2555
2556 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
2557 InterpFrame *FrameBefore = S.Current;
2558 S.Current = NewFrame.get();
2559
2560 APValue CallResult;
2561 // Note that we cannot assert(CallResult.hasValue()) here since
2562 // Ret() above only sets the APValue if the curent frame doesn't
2563 // have a caller set.
2564 if (Interpret(S, CallResult)) {
2565 NewFrame.release(); // Frame was delete'd already.
2566 assert(S.Current == FrameBefore);
2567 return true;
2568 }
2569
2570 // Interpreting the function failed somehow. Reset to
2571 // previous state.
2572 S.Current = FrameBefore;
2573 return false;
2574
2575 return false;
2576}
2577
2578inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
2579 uint32_t VarArgSize) {
2580 if (Func->hasThisPointer()) {
2581 size_t ArgSize = Func->getArgSize() + VarArgSize;
2582 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
2583
2584 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
2585
2586 // If the current function is a lambda static invoker and
2587 // the function we're about to call is a lambda call operator,
2588 // skip the CheckInvoke, since the ThisPtr is a null pointer
2589 // anyway.
2590 if (!(S.Current->getFunction() &&
2591 S.Current->getFunction()->isLambdaStaticInvoker() &&
2592 Func->isLambdaCallOperator())) {
2593 if (!CheckInvoke(S, OpPC, ThisPtr))
2594 return false;
2595 }
2596 }
2597
2598 if (!CheckCallable(S, OpPC, Func))
2599 return false;
2600
2601 if (Func->hasThisPointer() && S.checkingPotentialConstantExpression())
2602 return false;
2603
2604 if (!CheckCallDepth(S, OpPC))
2605 return false;
2606
2607 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
2608 InterpFrame *FrameBefore = S.Current;
2609 S.Current = NewFrame.get();
2610
2611 APValue CallResult;
2612 // Note that we cannot assert(CallResult.hasValue()) here since
2613 // Ret() above only sets the APValue if the curent frame doesn't
2614 // have a caller set.
2615 if (Interpret(S, CallResult)) {
2616 NewFrame.release(); // Frame was delete'd already.
2617 assert(S.Current == FrameBefore);
2618 return true;
2619 }
2620
2621 // Interpreting the function failed somehow. Reset to
2622 // previous state.
2623 S.Current = FrameBefore;
2624 return false;
2625}
2626
2627inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
2628 uint32_t VarArgSize) {
2629 assert(Func->hasThisPointer());
2630 assert(Func->isVirtual());
2631 size_t ArgSize = Func->getArgSize() + VarArgSize;
2632 size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
2633 Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
2634
2635 const CXXRecordDecl *DynamicDecl = nullptr;
2636 {
2637 Pointer TypePtr = ThisPtr;
2638 while (TypePtr.isBaseClass())
2639 TypePtr = TypePtr.getBase();
2640
2641 QualType DynamicType = TypePtr.getType();
2642 if (DynamicType->isPointerType() || DynamicType->isReferenceType())
2643 DynamicDecl = DynamicType->getPointeeCXXRecordDecl();
2644 else
2645 DynamicDecl = DynamicType->getAsCXXRecordDecl();
2646 }
2647 assert(DynamicDecl);
2648
2649 const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());
2650 const auto *InitialFunction = cast<CXXMethodDecl>(Func->getDecl());
2651 const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
2652 DynamicDecl, StaticDecl, InitialFunction);
2653
2654 if (Overrider != InitialFunction) {
2655 // DR1872: An instantiated virtual constexpr function can't be called in a
2656 // constant expression (prior to C++20). We can still constant-fold such a
2657 // call.
2658 if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {
2659 const Expr *E = S.Current->getExpr(OpPC);
2660 S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();
2661 }
2662
2663 Func = S.getContext().getOrCreateFunction(Overrider);
2664
2665 const CXXRecordDecl *ThisFieldDecl =
2666 ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
2667 if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
2668 // If the function we call is further DOWN the hierarchy than the
2669 // FieldDesc of our pointer, just go up the hierarchy of this field
2670 // the furthest we can go.
2671 while (ThisPtr.isBaseClass())
2672 ThisPtr = ThisPtr.getBase();
2673 }
2674 }
2675
2676 if (!Call(S, OpPC, Func, VarArgSize))
2677 return false;
2678
2679 // Covariant return types. The return type of Overrider is a pointer
2680 // or reference to a class type.
2681 if (Overrider != InitialFunction &&
2682 Overrider->getReturnType()->isPointerOrReferenceType() &&
2683 InitialFunction->getReturnType()->isPointerOrReferenceType()) {
2684 QualType OverriderPointeeType =
2685 Overrider->getReturnType()->getPointeeType();
2686 QualType InitialPointeeType =
2687 InitialFunction->getReturnType()->getPointeeType();
2688 // We've called Overrider above, but calling code expects us to return what
2689 // InitialFunction returned. According to the rules for covariant return
2690 // types, what InitialFunction returns needs to be a base class of what
2691 // Overrider returns. So, we need to do an upcast here.
2692 unsigned Offset = S.getContext().collectBaseOffset(
2693 InitialPointeeType->getAsRecordDecl(),
2694 OverriderPointeeType->getAsRecordDecl());
2695 return GetPtrBasePop(S, OpPC, Offset);
2696 }
2697
2698 return true;
2699}
2700
2701inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
2702 const CallExpr *CE) {
2703 auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
2704
2705 InterpFrame *FrameBefore = S.Current;
2706 S.Current = NewFrame.get();
2707
2708 if (InterpretBuiltin(S, PC, Func, CE)) {
2709 NewFrame.release();
2710 return true;
2711 }
2712 S.Current = FrameBefore;
2713 return false;
2714}
2715
2716inline bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
2717 const CallExpr *CE) {
2718 const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();
2719
2720 const Function *F = FuncPtr.getFunction();
2721 if (!F) {
2722 const auto *E = cast<CallExpr>(S.Current->getExpr(OpPC));
2723 S.FFDiag(E, diag::note_constexpr_null_callee)
2724 << const_cast<Expr *>(E->getCallee()) << E->getSourceRange();
2725 return false;
2726 }
2727
2728 if (!FuncPtr.isValid() || !F->getDecl())
2729 return Invalid(S, OpPC);
2730
2731 assert(F);
2732
2733 // This happens when the call expression has been cast to
2734 // something else, but we don't support that.
2735 if (S.Ctx.classify(F->getDecl()->getReturnType()) !=
2736 S.Ctx.classify(CE->getType()))
2737 return false;
2738
2739 // Check argument nullability state.
2740 if (F->hasNonNullAttr()) {
2741 if (!CheckNonNullArgs(S, OpPC, F, CE, ArgSize))
2742 return false;
2743 }
2744
2745 assert(ArgSize >= F->getWrittenArgSize());
2746 uint32_t VarArgSize = ArgSize - F->getWrittenArgSize();
2747
2748 // We need to do this explicitly here since we don't have the necessary
2749 // information to do it automatically.
2750 if (F->isThisPointerExplicit())
2751 VarArgSize -= align(primSize(PT_Ptr));
2752
2753 if (F->isVirtual())
2754 return CallVirt(S, OpPC, F, VarArgSize);
2755
2756 return Call(S, OpPC, F, VarArgSize);
2757}
2758
2759inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
2760 assert(Func);
2761 S.Stk.push<FunctionPointer>(Func);
2762 return true;
2763}
2764
2765template <PrimType Name, class T = typename PrimConv<Name>::T>
2766inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2767 const T &IntVal = S.Stk.pop<T>();
2768
2769 S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
2770 return true;
2771}
2772
2773inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const Decl *D) {
2774 S.Stk.push<MemberPointer>(D);
2775 return true;
2776}
2777
2778inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) {
2779 const auto &MP = S.Stk.pop<MemberPointer>();
2780
2781 S.Stk.push<Pointer>(MP.getBase());
2782 return true;
2783}
2784
2785inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) {
2786 const auto &MP = S.Stk.pop<MemberPointer>();
2787
2788 const auto *FD = cast<FunctionDecl>(MP.getDecl());
2789 const auto *Func = S.getContext().getOrCreateFunction(FD);
2790
2791 S.Stk.push<FunctionPointer>(Func);
2792 return true;
2793}
2794
2795/// Just emit a diagnostic. The expression that caused emission of this
2796/// op is not valid in a constant context.
2797inline bool Invalid(InterpState &S, CodePtr OpPC) {
2798 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2799 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
2800 << S.Current->getRange(OpPC);
2801 return false;
2802}
2803
2804inline bool Unsupported(InterpState &S, CodePtr OpPC) {
2805 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2806 S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)
2807 << S.Current->getRange(OpPC);
2808 return false;
2809}
2810
2811/// Do nothing and just abort execution.
2812inline bool Error(InterpState &S, CodePtr OpPC) { return false; }
2813
2814/// Same here, but only for casts.
2815inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind,
2816 bool Fatal) {
2817 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2818
2819 // FIXME: Support diagnosing other invalid cast kinds.
2820 if (Kind == CastKind::Reinterpret) {
2821 S.CCEDiag(Loc, diag::note_constexpr_invalid_cast)
2822 << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
2823 return !Fatal;
2824 }
2825 return false;
2826}
2827
2829 const DeclRefExpr *DR) {
2830 assert(DR);
2831 return CheckDeclRef(S, OpPC, DR);
2832}
2833
2835 if (S.inConstantContext()) {
2836 const SourceRange &ArgRange = S.Current->getRange(OpPC);
2837 const Expr *E = S.Current->getExpr(OpPC);
2838 S.CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange;
2839 }
2840 return false;
2841}
2842
2843inline bool Assume(InterpState &S, CodePtr OpPC) {
2844 const auto Val = S.Stk.pop<Boolean>();
2845
2846 if (Val)
2847 return true;
2848
2849 // Else, diagnose.
2850 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2851 S.CCEDiag(Loc, diag::note_constexpr_assumption_failed);
2852 return false;
2853}
2854
2855template <PrimType Name, class T = typename PrimConv<Name>::T>
2856inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
2857 llvm::SmallVector<int64_t> ArrayIndices;
2858 for (size_t I = 0; I != E->getNumExpressions(); ++I)
2859 ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
2860
2861 int64_t Result;
2862 if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
2863 return false;
2864
2865 S.Stk.push<T>(T::from(Result));
2866
2867 return true;
2868}
2869
2870template <PrimType Name, class T = typename PrimConv<Name>::T>
2871inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
2872 const T &Arg = S.Stk.peek<T>();
2873 if (!Arg.isZero())
2874 return true;
2875
2876 const SourceLocation &Loc = S.Current->getLocation(OpPC);
2877 S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
2878
2879 return false;
2880}
2881
2882void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,
2883 const APSInt &Value);
2884
2885template <PrimType Name, class T = typename PrimConv<Name>::T>
2886inline bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED) {
2887 assert(ED);
2888 assert(!ED->isFixed());
2889 const APSInt Val = S.Stk.peek<T>().toAPSInt();
2890
2891 if (S.inConstantContext())
2892 diagnoseEnumValue(S, OpPC, ED, Val);
2893 return true;
2894}
2895
2896/// OldPtr -> Integer -> NewPtr.
2897template <PrimType TIn, PrimType TOut>
2898inline bool DecayPtr(InterpState &S, CodePtr OpPC) {
2899 static_assert(isPtrType(TIn) && isPtrType(TOut));
2900 using FromT = typename PrimConv<TIn>::T;
2901 using ToT = typename PrimConv<TOut>::T;
2902
2903 const FromT &OldPtr = S.Stk.pop<FromT>();
2904
2905 if constexpr (std::is_same_v<FromT, FunctionPointer> &&
2906 std::is_same_v<ToT, Pointer>) {
2907 S.Stk.push<Pointer>(OldPtr.getFunction());
2908 return true;
2909 }
2910
2911 S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
2912 return true;
2913}
2914
2915inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) {
2916 // An expression E is a core constant expression unless the evaluation of E
2917 // would evaluate one of the following: [C++23] - a control flow that passes
2918 // through a declaration of a variable with static or thread storage duration
2919 // unless that variable is usable in constant expressions.
2920 assert(VD->isLocalVarDecl() &&
2921 VD->isStaticLocal()); // Checked before emitting this.
2922
2923 if (VD == S.EvaluatingDecl)
2924 return true;
2925
2926 if (!VD->isUsableInConstantExpressions(S.getCtx())) {
2927 S.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local)
2928 << (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD;
2929 return false;
2930 }
2931 return true;
2932}
2933
2934inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
2935 assert(Desc);
2936
2937 if (!CheckDynamicMemoryAllocation(S, OpPC))
2938 return false;
2939
2940 DynamicAllocator &Allocator = S.getAllocator();
2941 Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID());
2942 assert(B);
2943
2944 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
2945
2946 return true;
2947}
2948
2949template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
2950inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,
2951 bool IsNoThrow) {
2952 if (!CheckDynamicMemoryAllocation(S, OpPC))
2953 return false;
2954
2955 SizeT NumElements = S.Stk.pop<SizeT>();
2956 if (!CheckArraySize(S, OpPC, &NumElements, primSize(T), IsNoThrow)) {
2957 if (!IsNoThrow)
2958 return false;
2959
2960 // If this failed and is nothrow, just return a null ptr.
2961 S.Stk.push<Pointer>(0, nullptr);
2962 return true;
2963 }
2964
2965 DynamicAllocator &Allocator = S.getAllocator();
2966 Block *B = Allocator.allocate(Source, T, static_cast<size_t>(NumElements),
2967 S.Ctx.getEvalID());
2968 assert(B);
2969 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
2970
2971 return true;
2972}
2973
2974template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
2975inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc,
2976 bool IsNoThrow) {
2977 if (!CheckDynamicMemoryAllocation(S, OpPC))
2978 return false;
2979
2980 SizeT NumElements = S.Stk.pop<SizeT>();
2981 if (!CheckArraySize(S, OpPC, &NumElements, ElementDesc->getSize(),
2982 IsNoThrow)) {
2983 if (!IsNoThrow)
2984 return false;
2985
2986 // If this failed and is nothrow, just return a null ptr.
2987 S.Stk.push<Pointer>(0, ElementDesc);
2988 return true;
2989 }
2990
2991 DynamicAllocator &Allocator = S.getAllocator();
2992 Block *B = Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements),
2993 S.Ctx.getEvalID());
2994 assert(B);
2995
2996 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
2997
2998 return true;
2999}
3000
3001bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B);
3002static inline bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm) {
3003 if (!CheckDynamicMemoryAllocation(S, OpPC))
3004 return false;
3005
3006 const Expr *Source = nullptr;
3007 const Block *BlockToDelete = nullptr;
3008 {
3009 // Extra scope for this so the block doesn't have this pointer
3010 // pointing to it when we destroy it.
3011 const Pointer &Ptr = S.Stk.pop<Pointer>();
3012
3013 // Deleteing nullptr is always fine.
3014 if (Ptr.isZero())
3015 return true;
3016
3017 if (!Ptr.isRoot() || Ptr.isOnePastEnd() || Ptr.isArrayElement()) {
3018 const SourceInfo &Loc = S.Current->getSource(OpPC);
3019 S.FFDiag(Loc, diag::note_constexpr_delete_subobject)
3020 << Ptr.toDiagnosticString(S.getCtx()) << Ptr.isOnePastEnd();
3021 return false;
3022 }
3023
3024 Source = Ptr.getDeclDesc()->asExpr();
3025 BlockToDelete = Ptr.block();
3026
3027 if (!CheckDeleteSource(S, OpPC, Source, Ptr))
3028 return false;
3029 }
3030 assert(Source);
3031 assert(BlockToDelete);
3032
3033 // Invoke destructors before deallocating the memory.
3034 if (!RunDestructors(S, OpPC, BlockToDelete))
3035 return false;
3036
3037 DynamicAllocator &Allocator = S.getAllocator();
3038 bool WasArrayAlloc = Allocator.isArrayAllocation(Source);
3039 const Descriptor *BlockDesc = BlockToDelete->getDescriptor();
3040
3041 if (!Allocator.deallocate(Source, BlockToDelete, S)) {
3042 // Nothing has been deallocated, this must be a double-delete.
3043 const SourceInfo &Loc = S.Current->getSource(OpPC);
3044 S.FFDiag(Loc, diag::note_constexpr_double_delete);
3045 return false;
3046 }
3047 return CheckNewDeleteForms(S, OpPC, WasArrayAlloc, DeleteIsArrayForm,
3048 BlockDesc, Source);
3049}
3050
3051inline bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T) {
3052 assert(T);
3053 assert(!S.getLangOpts().CPlusPlus23);
3054
3055 // C++1y: A constant initializer for an object o [...] may also invoke
3056 // constexpr constructors for o and its subobjects even if those objects
3057 // are of non-literal class types.
3058 //
3059 // C++11 missed this detail for aggregates, so classes like this:
3060 // struct foo_t { union { int i; volatile int j; } u; };
3061 // are not (obviously) initializable like so:
3062 // __attribute__((__require_constant_initialization__))
3063 // static const foo_t x = {{0}};
3064 // because "i" is a subobject with non-literal initialization (due to the
3065 // volatile member of the union). See:
3066 // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1677
3067 // Therefore, we use the C++1y behavior.
3068
3069 if (S.EvaluatingDecl)
3070 return true;
3071
3072 if (S.Current->getFunction() && S.Current->getFunction()->isConstructor() &&
3073 S.Current->getThis().getDeclDesc()->asDecl() == S.EvaluatingDecl)
3074 return true;
3075
3076 const Expr *E = S.Current->getExpr(OpPC);
3077 if (S.getLangOpts().CPlusPlus11)
3078 S.FFDiag(E, diag::note_constexpr_nonliteral) << E->getType();
3079 else
3080 S.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
3081 return false;
3082}
3083
3084//===----------------------------------------------------------------------===//
3085// Read opcode arguments
3086//===----------------------------------------------------------------------===//
3087
3088template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
3089 if constexpr (std::is_pointer<T>::value) {
3090 uint32_t ID = OpPC.read<uint32_t>();
3091 return reinterpret_cast<T>(S.P.getNativePointer(ID));
3092 } else {
3093 return OpPC.read<T>();
3094 }
3095}
3096
3097template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
3099 OpPC += align(F.bytesToSerialize());
3100 return F;
3101}
3102
3103template <>
3104inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
3105 CodePtr &OpPC) {
3106 IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);
3107 OpPC += align(I.bytesToSerialize());
3108 return I;
3109}
3110
3111template <>
3112inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
3113 CodePtr &OpPC) {
3114 IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);
3115 OpPC += align(I.bytesToSerialize());
3116 return I;
3117}
3118
3119} // namespace interp
3120} // namespace clang
3121
3122#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:759
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:2064
bool isVirtual() const
Definition: DeclCXX.h:2119
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:446
Represents an enum.
Definition: Decl.h:3844
bool isFixed() const
Returns true if this is an Objective-C, C++11, or Microsoft-style enumeration with a fixed underlying...
Definition: Decl.h:4058
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:3233
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:3279
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:4145
const LangOptions & getLangOpts() const
Definition: Sema.h:553
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:5364
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 Boolean from(T Value)
Definition: Boolean.h:94
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:81
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:66
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:435
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:431
bool isInitialized() const
Checks if an object was initialized.
Definition: Pointer.cpp:311
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:623
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:395
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:301
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:666
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
size_t elemSize() const
Returns the element size of the innermost field.
Definition: Pointer.h:357
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:347
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:1487
bool InitPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1758
bool Shr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2378
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:1339
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:782
bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index)
Definition: Interp.h:2475
bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1577
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:2464
bool GT(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1111
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:2778
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:807
bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1266
bool NarrowPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2411
bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B)
Definition: Interp.cpp:888
llvm::APInt APInt
Definition: Integral.h:29
bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off)
Definition: Interp.h:1590
bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1380
bool Interpret(InterpState &S, APValue &Result)
Interpreter entry point.
Definition: Interp.cpp:938
Floating ReadArg< Floating >(InterpState &S, CodePtr &OpPC)
Definition: Interp.h:3097
static bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:2252
bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:835
bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1203
bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx)
The same as InitElem, but pops the pointer as well.
Definition: Interp.h:1786
bool StoreBitField(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1715
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:1676
bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:859
static bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:2148
static bool IncPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1969
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:1144
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:1234
bool CheckNonNullArg(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2871
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:1945
bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1439
static bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:2128
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:2915
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:1459
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:2759
bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I)
Same as GetGlobal, but without the checks.
Definition: Interp.h:1313
bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1538
bool SubPtr(InterpState &S, CodePtr OpPC)
1) Pops a Pointer from the stack.
Definition: Interp.h:1991
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:2199
bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1452
bool Mulc(InterpState &S, CodePtr OpPC)
Definition: Interp.h:425
bool ArrayElemPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2432
bool NE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1089
bool NoRet(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2401
bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Definition: Interp.h:2766
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:2247
bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:378
bool Shl(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2388
bool RVOPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2291
bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Definition: Interp.cpp:493
bool CastPointerIntegral(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2169
constexpr bool isPtrType(PrimType T)
Definition: PrimType.h:51
bool SubOffset(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1938
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition: PrimType.h:126
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:2078
bool ExpandPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2417
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:1687
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:1220
bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2448
bool This(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2268
bool InitScope(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:2042
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:1415
bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, llvm::RoundingMode RM)
Definition: Interp.h:816
bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex, uint32_t DestIndex, uint32_t Size)
Definition: Interp.h:2486
bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:900
llvm::function_ref< bool(ComparisonCategoryResult)> CompareFn
Definition: Interp.h:885
T ReadArg(InterpState &S, CodePtr &OpPC)
Definition: Interp.h:3088
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:2506
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:1361
bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Definition: Interp.h:712
bool CastFloatingIntegral(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2099
bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1185
bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E)
Definition: Interp.h:2856
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:913
bool CastIntegralFloating(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, llvm::RoundingMode RM)
Definition: Interp.h:2085
bool LE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1103
PrimType
Enumeration of the primitive types of the VM.
Definition: PrimType.h:33
bool Zero(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2242
bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F, uint32_t FieldOffset)
Definition: Interp.h:1396
bool Unsupported(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2804
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:2060
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:1280
bool StoreBitFieldPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1730
bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition: Interp.h:2528
static bool DecPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1978
bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Definition: Interp.h:2934
bool ToMemberPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1808
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:1629
bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM)
Definition: Interp.h:843
bool Dump(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1624
bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2834
bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Definition: Interp.h:2258
static bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth)
Definition: Interp.h:2183
static bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr)
Definition: Interp.h:2215
bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T)
Definition: Interp.h:3051
bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1515
bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off)
Definition: Interp.h:1525
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:851
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:1551
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:1564
bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1212
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:2785
bool CmpHelper< FunctionPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Function pointers cannot be compared in an ordered way.
Definition: Interp.h:906
bool Comp(InterpState &S, CodePtr OpPC)
1) Pops the value from the stack.
Definition: Interp.h:870
bool DecayPtr(InterpState &S, CodePtr OpPC)
OldPtr -> Integer -> NewPtr.
Definition: Interp.h:2898
bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC, const RecordDecl *D)
Definition: Interp.h:1640
bool StorePop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1701
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:2701
bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I)
1) Pops the value from the stack.
Definition: Interp.h:1197
bool FinishInit(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1615
bool Mul(InterpState &S, CodePtr OpPC)
Definition: Interp.h:407
bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS)
Definition: Interp.h:2305
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:1772
bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:2037
bool Pop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1150
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:1425
bool GetMemberPtr(InterpState &S, CodePtr OpPC, const Decl *D)
Definition: Interp.h:2773
bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR)
Definition: Interp.h:2828
bool FinishInitPop(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1606
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:1130
bool CmpHelperEQ< FunctionPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:919
bool Neg(InterpState &S, CodePtr OpPC)
Definition: Interp.h:670
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 Inv(InterpState &S, CodePtr OpPC)
Definition: Interp.h:659
bool Load(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1665
bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1322
bool Cast(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2051
bool EQ(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1058
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:1252
bool CmpHelperEQ< MemberPointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:1017
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:1931
bool Const(InterpState &S, CodePtr OpPC, const T &Arg)
Definition: Interp.h:1175
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:1798
bool GE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1118
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:2716
bool CmpHelperEQ< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:959
constexpr bool isIntegralType(PrimType T)
Definition: PrimType.h:72
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition: Interp.h:2627
bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:888
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:1444
bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc, bool IsNoThrow)
Definition: Interp.h:2975
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1295
bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D)
Definition: Interp.h:1649
bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I)
Definition: Interp.h:1328
bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind, bool Fatal)
Same here, but only for casts.
Definition: Interp.h:2815
bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1816
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:1157
bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo)
Definition: Interp.h:1065
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:2071
bool CmpHelper< Pointer >(InterpState &S, CodePtr OpPC, CompareFn Fn)
Definition: Interp.h:939
bool Assume(InterpState &S, CodePtr OpPC)
Definition: Interp.h:2843
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:1596
static bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm)
Definition: Interp.h:3002
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:1831
bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source, bool IsNoThrow)
Definition: Interp.h:2950
bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED)
Definition: Interp.h:2886
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:633
const Descriptor * Desc
Definition: Pointer.h:45
Mapping from primitive types to their representation.
Definition: PrimType.h:75