[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / clang / lib / AST / Interp / Interp.h
blob7dd415d6e4605365d826576b399407f764208bca
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.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_CLANG_AST_INTERP_INTERP_H
14 #define LLVM_CLANG_AST_INTERP_INTERP_H
16 #include "Boolean.h"
17 #include "Floating.h"
18 #include "Function.h"
19 #include "FunctionPointer.h"
20 #include "InterpFrame.h"
21 #include "InterpStack.h"
22 #include "InterpState.h"
23 #include "Opcode.h"
24 #include "PrimType.h"
25 #include "Program.h"
26 #include "State.h"
27 #include "clang/AST/ASTContext.h"
28 #include "clang/AST/ASTDiagnostic.h"
29 #include "clang/AST/CXXInheritance.h"
30 #include "clang/AST/Expr.h"
31 #include "llvm/ADT/APFloat.h"
32 #include "llvm/ADT/APSInt.h"
33 #include "llvm/Support/Endian.h"
34 #include <limits>
35 #include <type_traits>
37 namespace clang {
38 namespace interp {
40 using APInt = llvm::APInt;
41 using APSInt = llvm::APSInt;
43 /// Convert a value to an APValue.
44 template <typename T> bool ReturnValue(const T &V, APValue &R) {
45 R = V.toAPValue();
46 return true;
49 /// Checks if the variable has externally defined storage.
50 bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
52 /// Checks if the array is offsetable.
53 bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
55 /// Checks if a pointer is live and accessible.
56 bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
57 AccessKinds AK);
59 /// Checks if a pointer is a dummy pointer.
60 bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
62 /// Checks if a pointer is null.
63 bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
64 CheckSubobjectKind CSK);
66 /// Checks if a pointer is in range.
67 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
68 AccessKinds AK);
70 /// Checks if a field from which a pointer is going to be derived is valid.
71 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
72 CheckSubobjectKind CSK);
74 /// Checks if Ptr is a one-past-the-end pointer.
75 bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
76 CheckSubobjectKind CSK);
78 /// Checks if a pointer points to const storage.
79 bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
81 /// Checks if a pointer points to a mutable field.
82 bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
84 /// Checks if a value can be loaded from a block.
85 bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
87 bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
88 AccessKinds AK);
90 /// Checks if a value can be stored in a block.
91 bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
93 /// Checks if a method can be invoked on an object.
94 bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
96 /// Checks if a value can be initialized.
97 bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
99 /// Checks if a method can be called.
100 bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
102 /// Checks if calling the currently active function would exceed
103 /// the allowed call depth.
104 bool CheckCallDepth(InterpState &S, CodePtr OpPC);
106 /// Checks the 'this' pointer.
107 bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
109 /// Checks if a method is pure virtual.
110 bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
112 /// Checks that all fields are initialized after a constructor call.
113 bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This);
115 /// Checks if reinterpret casts are legal in the current context.
116 bool CheckPotentialReinterpretCast(InterpState &S, CodePtr OpPC,
117 const Pointer &Ptr);
119 /// Sets the given integral value to the pointer, which is of
120 /// a std::{weak,partial,strong}_ordering type.
121 bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
122 const Pointer &Ptr, const APSInt &IntValue);
124 /// Checks if the shift operation is legal.
125 template <typename LT, typename RT>
126 bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
127 unsigned Bits) {
128 if (RHS.isNegative()) {
129 const SourceInfo &Loc = S.Current->getSource(OpPC);
130 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
131 return false;
134 // C++11 [expr.shift]p1: Shift width must be less than the bit width of
135 // the shifted type.
136 if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
137 const Expr *E = S.Current->getExpr(OpPC);
138 const APSInt Val = RHS.toAPSInt();
139 QualType Ty = E->getType();
140 S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
141 return false;
144 if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
145 const Expr *E = S.Current->getExpr(OpPC);
146 // C++11 [expr.shift]p2: A signed left shift must have a non-negative
147 // operand, and must not overflow the corresponding unsigned type.
148 if (LHS.isNegative())
149 S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
150 else if (LHS.toUnsigned().countLeadingZeros() < static_cast<unsigned>(RHS))
151 S.CCEDiag(E, diag::note_constexpr_lshift_discards);
154 // C++2a [expr.shift]p2: [P0907R4]:
155 // E1 << E2 is the unique value congruent to
156 // E1 x 2^E2 module 2^N.
157 return true;
160 /// Checks if Div/Rem operation on LHS and RHS is valid.
161 template <typename T>
162 bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
163 if (RHS.isZero()) {
164 const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
165 S.FFDiag(Op, diag::note_expr_divide_by_zero)
166 << Op->getRHS()->getSourceRange();
167 return false;
170 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
171 APSInt LHSInt = LHS.toAPSInt();
172 SmallString<32> Trunc;
173 (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
174 const SourceInfo &Loc = S.Current->getSource(OpPC);
175 const Expr *E = S.Current->getExpr(OpPC);
176 S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
177 return false;
179 return true;
182 /// Checks if the result of a floating-point operation is valid
183 /// in the current context.
184 bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
185 APFloat::opStatus Status);
187 /// Checks why the given DeclRefExpr is invalid.
188 bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);
190 /// Interpreter entry point.
191 bool Interpret(InterpState &S, APValue &Result);
193 /// Interpret a builtin function.
194 bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
195 const CallExpr *Call);
197 /// Interpret an offsetof operation.
198 bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
199 llvm::ArrayRef<int64_t> ArrayIndices, int64_t &Result);
201 enum class ArithOp { Add, Sub };
203 //===----------------------------------------------------------------------===//
204 // Returning values
205 //===----------------------------------------------------------------------===//
207 void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC);
209 template <PrimType Name, class T = typename PrimConv<Name>::T>
210 bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
211 const T &Ret = S.Stk.pop<T>();
213 // Make sure returned pointers are live. We might be trying to return a
214 // pointer or reference to a local variable.
215 // Just return false, since a diagnostic has already been emitted in Sema.
216 if constexpr (std::is_same_v<T, Pointer>) {
217 // FIXME: We could be calling isLive() here, but the emitted diagnostics
218 // seem a little weird, at least if the returned expression is of
219 // pointer type.
220 // Null pointers are considered live here.
221 if (!Ret.isZero() && !Ret.isLive())
222 return false;
225 assert(S.Current);
226 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
227 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
228 cleanupAfterFunctionCall(S, PC);
230 if (InterpFrame *Caller = S.Current->Caller) {
231 PC = S.Current->getRetPC();
232 delete S.Current;
233 S.Current = Caller;
234 S.Stk.push<T>(Ret);
235 } else {
236 delete S.Current;
237 S.Current = nullptr;
238 if (!ReturnValue<T>(Ret, Result))
239 return false;
241 return true;
244 inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
245 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
247 if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
248 cleanupAfterFunctionCall(S, PC);
250 if (InterpFrame *Caller = S.Current->Caller) {
251 PC = S.Current->getRetPC();
252 delete S.Current;
253 S.Current = Caller;
254 } else {
255 delete S.Current;
256 S.Current = nullptr;
258 return true;
261 //===----------------------------------------------------------------------===//
262 // Add, Sub, Mul
263 //===----------------------------------------------------------------------===//
265 template <typename T, bool (*OpFW)(T, T, unsigned, T *),
266 template <typename U> class OpAP>
267 bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
268 const T &RHS) {
269 // Fast path - add the numbers with fixed width.
270 T Result;
271 if (!OpFW(LHS, RHS, Bits, &Result)) {
272 S.Stk.push<T>(Result);
273 return true;
276 // If for some reason evaluation continues, use the truncated results.
277 S.Stk.push<T>(Result);
279 // Slow path - compute the result using another bit of precision.
280 APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
282 // Report undefined behaviour, stopping if required.
283 const Expr *E = S.Current->getExpr(OpPC);
284 QualType Type = E->getType();
285 if (S.checkingForUndefinedBehavior()) {
286 SmallString<32> Trunc;
287 Value.trunc(Result.bitWidth()).toString(Trunc, 10);
288 auto Loc = E->getExprLoc();
289 S.report(Loc, diag::warn_integer_constant_overflow)
290 << Trunc << Type << E->getSourceRange();
291 return true;
292 } else {
293 S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
294 if (!S.noteUndefinedBehavior()) {
295 S.Stk.pop<T>();
296 return false;
298 return true;
302 template <PrimType Name, class T = typename PrimConv<Name>::T>
303 bool Add(InterpState &S, CodePtr OpPC) {
304 const T &RHS = S.Stk.pop<T>();
305 const T &LHS = S.Stk.pop<T>();
306 const unsigned Bits = RHS.bitWidth() + 1;
307 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
310 inline bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
311 const Floating &RHS = S.Stk.pop<Floating>();
312 const Floating &LHS = S.Stk.pop<Floating>();
314 Floating Result;
315 auto Status = Floating::add(LHS, RHS, RM, &Result);
316 S.Stk.push<Floating>(Result);
317 return CheckFloatResult(S, OpPC, Result, Status);
320 template <PrimType Name, class T = typename PrimConv<Name>::T>
321 bool Sub(InterpState &S, CodePtr OpPC) {
322 const T &RHS = S.Stk.pop<T>();
323 const T &LHS = S.Stk.pop<T>();
324 const unsigned Bits = RHS.bitWidth() + 1;
325 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
328 inline bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
329 const Floating &RHS = S.Stk.pop<Floating>();
330 const Floating &LHS = S.Stk.pop<Floating>();
332 Floating Result;
333 auto Status = Floating::sub(LHS, RHS, RM, &Result);
334 S.Stk.push<Floating>(Result);
335 return CheckFloatResult(S, OpPC, Result, Status);
338 template <PrimType Name, class T = typename PrimConv<Name>::T>
339 bool Mul(InterpState &S, CodePtr OpPC) {
340 const T &RHS = S.Stk.pop<T>();
341 const T &LHS = S.Stk.pop<T>();
342 const unsigned Bits = RHS.bitWidth() * 2;
343 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
346 inline bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
347 const Floating &RHS = S.Stk.pop<Floating>();
348 const Floating &LHS = S.Stk.pop<Floating>();
350 Floating Result;
351 auto Status = Floating::mul(LHS, RHS, RM, &Result);
352 S.Stk.push<Floating>(Result);
353 return CheckFloatResult(S, OpPC, Result, Status);
355 /// 1) Pops the RHS from the stack.
356 /// 2) Pops the LHS from the stack.
357 /// 3) Pushes 'LHS & RHS' on the stack
358 template <PrimType Name, class T = typename PrimConv<Name>::T>
359 bool BitAnd(InterpState &S, CodePtr OpPC) {
360 const T &RHS = S.Stk.pop<T>();
361 const T &LHS = S.Stk.pop<T>();
363 unsigned Bits = RHS.bitWidth();
364 T Result;
365 if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
366 S.Stk.push<T>(Result);
367 return true;
369 return false;
372 /// 1) Pops the RHS from the stack.
373 /// 2) Pops the LHS from the stack.
374 /// 3) Pushes 'LHS | RHS' on the stack
375 template <PrimType Name, class T = typename PrimConv<Name>::T>
376 bool BitOr(InterpState &S, CodePtr OpPC) {
377 const T &RHS = S.Stk.pop<T>();
378 const T &LHS = S.Stk.pop<T>();
380 unsigned Bits = RHS.bitWidth();
381 T Result;
382 if (!T::bitOr(LHS, RHS, Bits, &Result)) {
383 S.Stk.push<T>(Result);
384 return true;
386 return false;
389 /// 1) Pops the RHS from the stack.
390 /// 2) Pops the LHS from the stack.
391 /// 3) Pushes 'LHS ^ RHS' on the stack
392 template <PrimType Name, class T = typename PrimConv<Name>::T>
393 bool BitXor(InterpState &S, CodePtr OpPC) {
394 const T &RHS = S.Stk.pop<T>();
395 const T &LHS = S.Stk.pop<T>();
397 unsigned Bits = RHS.bitWidth();
398 T Result;
399 if (!T::bitXor(LHS, RHS, Bits, &Result)) {
400 S.Stk.push<T>(Result);
401 return true;
403 return false;
406 /// 1) Pops the RHS from the stack.
407 /// 2) Pops the LHS from the stack.
408 /// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
409 template <PrimType Name, class T = typename PrimConv<Name>::T>
410 bool Rem(InterpState &S, CodePtr OpPC) {
411 const T &RHS = S.Stk.pop<T>();
412 const T &LHS = S.Stk.pop<T>();
414 if (!CheckDivRem(S, OpPC, LHS, RHS))
415 return false;
417 const unsigned Bits = RHS.bitWidth() * 2;
418 T Result;
419 if (!T::rem(LHS, RHS, Bits, &Result)) {
420 S.Stk.push<T>(Result);
421 return true;
423 return false;
426 /// 1) Pops the RHS from the stack.
427 /// 2) Pops the LHS from the stack.
428 /// 3) Pushes 'LHS / RHS' on the stack
429 template <PrimType Name, class T = typename PrimConv<Name>::T>
430 bool Div(InterpState &S, CodePtr OpPC) {
431 const T &RHS = S.Stk.pop<T>();
432 const T &LHS = S.Stk.pop<T>();
434 if (!CheckDivRem(S, OpPC, LHS, RHS))
435 return false;
437 const unsigned Bits = RHS.bitWidth() * 2;
438 T Result;
439 if (!T::div(LHS, RHS, Bits, &Result)) {
440 S.Stk.push<T>(Result);
441 return true;
443 return false;
446 inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
447 const Floating &RHS = S.Stk.pop<Floating>();
448 const Floating &LHS = S.Stk.pop<Floating>();
450 if (!CheckDivRem(S, OpPC, LHS, RHS))
451 return false;
453 Floating Result;
454 auto Status = Floating::div(LHS, RHS, RM, &Result);
455 S.Stk.push<Floating>(Result);
456 return CheckFloatResult(S, OpPC, Result, Status);
459 //===----------------------------------------------------------------------===//
460 // Inv
461 //===----------------------------------------------------------------------===//
463 template <PrimType Name, class T = typename PrimConv<Name>::T>
464 bool Inv(InterpState &S, CodePtr OpPC) {
465 using BoolT = PrimConv<PT_Bool>::T;
466 const T &Val = S.Stk.pop<T>();
467 const unsigned Bits = Val.bitWidth();
468 Boolean R;
469 Boolean::inv(BoolT::from(Val, Bits), &R);
471 S.Stk.push<BoolT>(R);
472 return true;
475 //===----------------------------------------------------------------------===//
476 // Neg
477 //===----------------------------------------------------------------------===//
479 template <PrimType Name, class T = typename PrimConv<Name>::T>
480 bool Neg(InterpState &S, CodePtr OpPC) {
481 const T &Value = S.Stk.pop<T>();
482 T Result;
484 if (!T::neg(Value, &Result)) {
485 S.Stk.push<T>(Result);
486 return true;
489 assert(isIntegralType(Name) &&
490 "don't expect other types to fail at constexpr negation");
491 S.Stk.push<T>(Result);
493 APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
494 const Expr *E = S.Current->getExpr(OpPC);
495 QualType Type = E->getType();
497 if (S.checkingForUndefinedBehavior()) {
498 SmallString<32> Trunc;
499 NegatedValue.trunc(Result.bitWidth()).toString(Trunc, 10);
500 auto Loc = E->getExprLoc();
501 S.report(Loc, diag::warn_integer_constant_overflow)
502 << Trunc << Type << E->getSourceRange();
503 return true;
506 S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue << Type;
507 return S.noteUndefinedBehavior();
510 enum class PushVal : bool {
512 Yes,
514 enum class IncDecOp {
515 Inc,
516 Dec,
519 template <typename T, IncDecOp Op, PushVal DoPush>
520 bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
521 const T &Value = Ptr.deref<T>();
522 T Result;
524 if constexpr (DoPush == PushVal::Yes)
525 S.Stk.push<T>(Value);
527 if constexpr (Op == IncDecOp::Inc) {
528 if (!T::increment(Value, &Result)) {
529 Ptr.deref<T>() = Result;
530 return true;
532 } else {
533 if (!T::decrement(Value, &Result)) {
534 Ptr.deref<T>() = Result;
535 return true;
539 // Something went wrong with the previous operation. Compute the
540 // result with another bit of precision.
541 unsigned Bits = Value.bitWidth() + 1;
542 APSInt APResult;
543 if constexpr (Op == IncDecOp::Inc)
544 APResult = ++Value.toAPSInt(Bits);
545 else
546 APResult = --Value.toAPSInt(Bits);
548 // Report undefined behaviour, stopping if required.
549 const Expr *E = S.Current->getExpr(OpPC);
550 QualType Type = E->getType();
551 if (S.checkingForUndefinedBehavior()) {
552 SmallString<32> Trunc;
553 APResult.trunc(Result.bitWidth()).toString(Trunc, 10);
554 auto Loc = E->getExprLoc();
555 S.report(Loc, diag::warn_integer_constant_overflow)
556 << Trunc << Type << E->getSourceRange();
557 return true;
560 S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
561 return S.noteUndefinedBehavior();
564 /// 1) Pops a pointer from the stack
565 /// 2) Load the value from the pointer
566 /// 3) Writes the value increased by one back to the pointer
567 /// 4) Pushes the original (pre-inc) value on the stack.
568 template <PrimType Name, class T = typename PrimConv<Name>::T>
569 bool Inc(InterpState &S, CodePtr OpPC) {
570 const Pointer &Ptr = S.Stk.pop<Pointer>();
572 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
573 return false;
575 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
578 /// 1) Pops a pointer from the stack
579 /// 2) Load the value from the pointer
580 /// 3) Writes the value increased by one back to the pointer
581 template <PrimType Name, class T = typename PrimConv<Name>::T>
582 bool IncPop(InterpState &S, CodePtr OpPC) {
583 const Pointer &Ptr = S.Stk.pop<Pointer>();
585 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
586 return false;
588 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
591 /// 1) Pops a pointer from the stack
592 /// 2) Load the value from the pointer
593 /// 3) Writes the value decreased by one back to the pointer
594 /// 4) Pushes the original (pre-dec) value on the stack.
595 template <PrimType Name, class T = typename PrimConv<Name>::T>
596 bool Dec(InterpState &S, CodePtr OpPC) {
597 const Pointer &Ptr = S.Stk.pop<Pointer>();
599 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
600 return false;
602 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
605 /// 1) Pops a pointer from the stack
606 /// 2) Load the value from the pointer
607 /// 3) Writes the value decreased by one back to the pointer
608 template <PrimType Name, class T = typename PrimConv<Name>::T>
609 bool DecPop(InterpState &S, CodePtr OpPC) {
610 const Pointer &Ptr = S.Stk.pop<Pointer>();
612 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
613 return false;
615 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
618 template <IncDecOp Op, PushVal DoPush>
619 bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
620 llvm::RoundingMode RM) {
621 Floating Value = Ptr.deref<Floating>();
622 Floating Result;
624 if constexpr (DoPush == PushVal::Yes)
625 S.Stk.push<Floating>(Value);
627 llvm::APFloat::opStatus Status;
628 if constexpr (Op == IncDecOp::Inc)
629 Status = Floating::increment(Value, RM, &Result);
630 else
631 Status = Floating::decrement(Value, RM, &Result);
633 Ptr.deref<Floating>() = Result;
635 return CheckFloatResult(S, OpPC, Result, Status);
638 inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
639 const Pointer &Ptr = S.Stk.pop<Pointer>();
641 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
642 return false;
644 return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM);
647 inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
648 const Pointer &Ptr = S.Stk.pop<Pointer>();
650 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
651 return false;
653 return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM);
656 inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
657 const Pointer &Ptr = S.Stk.pop<Pointer>();
659 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
660 return false;
662 return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM);
665 inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
666 const Pointer &Ptr = S.Stk.pop<Pointer>();
668 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
669 return false;
671 return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM);
674 /// 1) Pops the value from the stack.
675 /// 2) Pushes the bitwise complemented value on the stack (~V).
676 template <PrimType Name, class T = typename PrimConv<Name>::T>
677 bool Comp(InterpState &S, CodePtr OpPC) {
678 const T &Val = S.Stk.pop<T>();
679 T Result;
680 if (!T::comp(Val, &Result)) {
681 S.Stk.push<T>(Result);
682 return true;
685 return false;
688 //===----------------------------------------------------------------------===//
689 // EQ, NE, GT, GE, LT, LE
690 //===----------------------------------------------------------------------===//
692 using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
694 template <typename T>
695 bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
696 using BoolT = PrimConv<PT_Bool>::T;
697 const T &RHS = S.Stk.pop<T>();
698 const T &LHS = S.Stk.pop<T>();
699 S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
700 return true;
703 template <typename T>
704 bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
705 return CmpHelper<T>(S, OpPC, Fn);
708 /// Function pointers cannot be compared in an ordered way.
709 template <>
710 inline bool CmpHelper<FunctionPointer>(InterpState &S, CodePtr OpPC,
711 CompareFn Fn) {
712 const auto &RHS = S.Stk.pop<FunctionPointer>();
713 const auto &LHS = S.Stk.pop<FunctionPointer>();
715 const SourceInfo &Loc = S.Current->getSource(OpPC);
716 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
717 << LHS.toDiagnosticString(S.getCtx())
718 << RHS.toDiagnosticString(S.getCtx());
719 return false;
722 template <>
723 inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC,
724 CompareFn Fn) {
725 const auto &RHS = S.Stk.pop<FunctionPointer>();
726 const auto &LHS = S.Stk.pop<FunctionPointer>();
727 S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
728 return true;
731 template <>
732 inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
733 using BoolT = PrimConv<PT_Bool>::T;
734 const Pointer &RHS = S.Stk.pop<Pointer>();
735 const Pointer &LHS = S.Stk.pop<Pointer>();
737 if (!Pointer::hasSameBase(LHS, RHS)) {
738 const SourceInfo &Loc = S.Current->getSource(OpPC);
739 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
740 << LHS.toDiagnosticString(S.getCtx())
741 << RHS.toDiagnosticString(S.getCtx());
742 return false;
743 } else {
744 unsigned VL = LHS.getByteOffset();
745 unsigned VR = RHS.getByteOffset();
746 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
747 return true;
751 template <>
752 inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
753 using BoolT = PrimConv<PT_Bool>::T;
754 const Pointer &RHS = S.Stk.pop<Pointer>();
755 const Pointer &LHS = S.Stk.pop<Pointer>();
757 if (LHS.isZero() && RHS.isZero()) {
758 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
759 return true;
762 if (!Pointer::hasSameBase(LHS, RHS)) {
763 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
764 return true;
765 } else {
766 unsigned VL = LHS.getByteOffset();
767 unsigned VR = RHS.getByteOffset();
769 // In our Pointer class, a pointer to an array and a pointer to the first
770 // element in the same array are NOT equal. They have the same Base value,
771 // but a different Offset. This is a pretty rare case, so we fix this here
772 // by comparing pointers to the first elements.
773 if (LHS.inArray() && LHS.isRoot())
774 VL = LHS.atIndex(0).getByteOffset();
775 if (RHS.inArray() && RHS.isRoot())
776 VR = RHS.atIndex(0).getByteOffset();
778 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
779 return true;
783 template <PrimType Name, class T = typename PrimConv<Name>::T>
784 bool EQ(InterpState &S, CodePtr OpPC) {
785 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
786 return R == ComparisonCategoryResult::Equal;
790 template <PrimType Name, class T = typename PrimConv<Name>::T>
791 bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
792 const T &RHS = S.Stk.pop<T>();
793 const T &LHS = S.Stk.pop<T>();
794 const Pointer &P = S.Stk.peek<Pointer>();
796 ComparisonCategoryResult CmpResult = LHS.compare(RHS);
797 if (CmpResult == ComparisonCategoryResult::Unordered) {
798 // This should only happen with pointers.
799 const SourceInfo &Loc = S.Current->getSource(OpPC);
800 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
801 << LHS.toDiagnosticString(S.getCtx())
802 << RHS.toDiagnosticString(S.getCtx());
803 return false;
806 assert(CmpInfo);
807 const auto *CmpValueInfo = CmpInfo->getValueInfo(CmpResult);
808 assert(CmpValueInfo);
809 assert(CmpValueInfo->hasValidIntValue());
810 APSInt IntValue = CmpValueInfo->getIntValue();
811 return SetThreeWayComparisonField(S, OpPC, P, IntValue);
814 template <PrimType Name, class T = typename PrimConv<Name>::T>
815 bool NE(InterpState &S, CodePtr OpPC) {
816 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
817 return R != ComparisonCategoryResult::Equal;
821 template <PrimType Name, class T = typename PrimConv<Name>::T>
822 bool LT(InterpState &S, CodePtr OpPC) {
823 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
824 return R == ComparisonCategoryResult::Less;
828 template <PrimType Name, class T = typename PrimConv<Name>::T>
829 bool LE(InterpState &S, CodePtr OpPC) {
830 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
831 return R == ComparisonCategoryResult::Less ||
832 R == ComparisonCategoryResult::Equal;
836 template <PrimType Name, class T = typename PrimConv<Name>::T>
837 bool GT(InterpState &S, CodePtr OpPC) {
838 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
839 return R == ComparisonCategoryResult::Greater;
843 template <PrimType Name, class T = typename PrimConv<Name>::T>
844 bool GE(InterpState &S, CodePtr OpPC) {
845 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
846 return R == ComparisonCategoryResult::Greater ||
847 R == ComparisonCategoryResult::Equal;
851 //===----------------------------------------------------------------------===//
852 // InRange
853 //===----------------------------------------------------------------------===//
855 template <PrimType Name, class T = typename PrimConv<Name>::T>
856 bool InRange(InterpState &S, CodePtr OpPC) {
857 const T RHS = S.Stk.pop<T>();
858 const T LHS = S.Stk.pop<T>();
859 const T Value = S.Stk.pop<T>();
861 S.Stk.push<bool>(LHS <= Value && Value <= RHS);
862 return true;
865 //===----------------------------------------------------------------------===//
866 // Dup, Pop, Test
867 //===----------------------------------------------------------------------===//
869 template <PrimType Name, class T = typename PrimConv<Name>::T>
870 bool Dup(InterpState &S, CodePtr OpPC) {
871 S.Stk.push<T>(S.Stk.peek<T>());
872 return true;
875 template <PrimType Name, class T = typename PrimConv<Name>::T>
876 bool Pop(InterpState &S, CodePtr OpPC) {
877 S.Stk.pop<T>();
878 return true;
881 //===----------------------------------------------------------------------===//
882 // Const
883 //===----------------------------------------------------------------------===//
885 template <PrimType Name, class T = typename PrimConv<Name>::T>
886 bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
887 S.Stk.push<T>(Arg);
888 return true;
891 //===----------------------------------------------------------------------===//
892 // Get/Set Local/Param/Global/This
893 //===----------------------------------------------------------------------===//
895 template <PrimType Name, class T = typename PrimConv<Name>::T>
896 bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
897 const Pointer &Ptr = S.Current->getLocalPointer(I);
898 if (!CheckLoad(S, OpPC, Ptr))
899 return false;
900 S.Stk.push<T>(Ptr.deref<T>());
901 return true;
904 /// 1) Pops the value from the stack.
905 /// 2) Writes the value to the local variable with the
906 /// given offset.
907 template <PrimType Name, class T = typename PrimConv<Name>::T>
908 bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
909 S.Current->setLocal<T>(I, S.Stk.pop<T>());
910 return true;
913 template <PrimType Name, class T = typename PrimConv<Name>::T>
914 bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
915 if (S.checkingPotentialConstantExpression()) {
916 return false;
918 S.Stk.push<T>(S.Current->getParam<T>(I));
919 return true;
922 template <PrimType Name, class T = typename PrimConv<Name>::T>
923 bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
924 S.Current->setParam<T>(I, S.Stk.pop<T>());
925 return true;
928 /// 1) Peeks a pointer on the stack
929 /// 2) Pushes the value of the pointer's field on the stack
930 template <PrimType Name, class T = typename PrimConv<Name>::T>
931 bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
932 const Pointer &Obj = S.Stk.peek<Pointer>();
933 if (!CheckNull(S, OpPC, Obj, CSK_Field))
934 return false;
935 if (!CheckRange(S, OpPC, Obj, CSK_Field))
936 return false;
937 const Pointer &Field = Obj.atField(I);
938 if (!CheckLoad(S, OpPC, Field))
939 return false;
940 S.Stk.push<T>(Field.deref<T>());
941 return true;
944 template <PrimType Name, class T = typename PrimConv<Name>::T>
945 bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
946 const T &Value = S.Stk.pop<T>();
947 const Pointer &Obj = S.Stk.peek<Pointer>();
948 if (!CheckNull(S, OpPC, Obj, CSK_Field))
949 return false;
950 if (!CheckRange(S, OpPC, Obj, CSK_Field))
951 return false;
952 const Pointer &Field = Obj.atField(I);
953 if (!CheckStore(S, OpPC, Field))
954 return false;
955 Field.initialize();
956 Field.deref<T>() = Value;
957 return true;
960 /// 1) Pops a pointer from the stack
961 /// 2) Pushes the value of the pointer's field on the stack
962 template <PrimType Name, class T = typename PrimConv<Name>::T>
963 bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
964 const Pointer &Obj = S.Stk.pop<Pointer>();
965 if (!CheckNull(S, OpPC, Obj, CSK_Field))
966 return false;
967 if (!CheckRange(S, OpPC, Obj, CSK_Field))
968 return false;
969 const Pointer &Field = Obj.atField(I);
970 if (!CheckLoad(S, OpPC, Field))
971 return false;
972 S.Stk.push<T>(Field.deref<T>());
973 return true;
976 template <PrimType Name, class T = typename PrimConv<Name>::T>
977 bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
978 if (S.checkingPotentialConstantExpression())
979 return false;
980 const Pointer &This = S.Current->getThis();
981 if (!CheckThis(S, OpPC, This))
982 return false;
983 const Pointer &Field = This.atField(I);
984 if (!CheckLoad(S, OpPC, Field))
985 return false;
986 S.Stk.push<T>(Field.deref<T>());
987 return true;
990 template <PrimType Name, class T = typename PrimConv<Name>::T>
991 bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
992 if (S.checkingPotentialConstantExpression())
993 return false;
994 const T &Value = S.Stk.pop<T>();
995 const Pointer &This = S.Current->getThis();
996 if (!CheckThis(S, OpPC, This))
997 return false;
998 const Pointer &Field = This.atField(I);
999 if (!CheckStore(S, OpPC, Field))
1000 return false;
1001 Field.deref<T>() = Value;
1002 return true;
1005 template <PrimType Name, class T = typename PrimConv<Name>::T>
1006 bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1007 auto *B = S.P.getGlobal(I);
1008 if (B->isExtern())
1009 return false;
1010 S.Stk.push<T>(B->deref<T>());
1011 return true;
1014 template <PrimType Name, class T = typename PrimConv<Name>::T>
1015 bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1016 // TODO: emit warning.
1017 return false;
1020 template <PrimType Name, class T = typename PrimConv<Name>::T>
1021 bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1022 S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
1023 return true;
1026 /// 1) Converts the value on top of the stack to an APValue
1027 /// 2) Sets that APValue on \Temp
1028 /// 3) Initialized global with index \I with that
1029 template <PrimType Name, class T = typename PrimConv<Name>::T>
1030 bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
1031 const LifetimeExtendedTemporaryDecl *Temp) {
1032 assert(Temp);
1033 const T Value = S.Stk.peek<T>();
1034 APValue APV = Value.toAPValue();
1035 APValue *Cached = Temp->getOrCreateValue(true);
1036 *Cached = APV;
1038 S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
1039 return true;
1042 /// 1) Converts the value on top of the stack to an APValue
1043 /// 2) Sets that APValue on \Temp
1044 /// 3) Initialized global with index \I with that
1045 inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC,
1046 const LifetimeExtendedTemporaryDecl *Temp) {
1047 assert(Temp);
1048 const Pointer &P = S.Stk.peek<Pointer>();
1049 APValue *Cached = Temp->getOrCreateValue(true);
1051 *Cached = P.toRValue(S.getCtx());
1052 return true;
1055 template <PrimType Name, class T = typename PrimConv<Name>::T>
1056 bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1057 if (S.checkingPotentialConstantExpression())
1058 return false;
1059 const Pointer &This = S.Current->getThis();
1060 if (!CheckThis(S, OpPC, This))
1061 return false;
1062 const Pointer &Field = This.atField(I);
1063 Field.deref<T>() = S.Stk.pop<T>();
1064 Field.initialize();
1065 return true;
1068 template <PrimType Name, class T = typename PrimConv<Name>::T>
1069 bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
1070 assert(F->isBitField());
1071 if (S.checkingPotentialConstantExpression())
1072 return false;
1073 const Pointer &This = S.Current->getThis();
1074 if (!CheckThis(S, OpPC, This))
1075 return false;
1076 const Pointer &Field = This.atField(F->Offset);
1077 const auto &Value = S.Stk.pop<T>();
1078 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1079 Field.initialize();
1080 return true;
1083 template <PrimType Name, class T = typename PrimConv<Name>::T>
1084 bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1085 if (S.checkingPotentialConstantExpression())
1086 return false;
1087 const Pointer &This = S.Current->getThis();
1088 if (!CheckThis(S, OpPC, This))
1089 return false;
1090 const Pointer &Field = This.atField(I);
1091 Field.deref<T>() = S.Stk.pop<T>();
1092 Field.activate();
1093 Field.initialize();
1094 return true;
1097 /// 1) Pops the value from the stack
1098 /// 2) Peeks a pointer from the stack
1099 /// 3) Pushes the value to field I of the pointer on the stack
1100 template <PrimType Name, class T = typename PrimConv<Name>::T>
1101 bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
1102 const T &Value = S.Stk.pop<T>();
1103 const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
1104 Field.deref<T>() = Value;
1105 Field.activate();
1106 Field.initialize();
1107 return true;
1110 template <PrimType Name, class T = typename PrimConv<Name>::T>
1111 bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
1112 assert(F->isBitField());
1113 const T &Value = S.Stk.pop<T>();
1114 const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
1115 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1116 Field.activate();
1117 Field.initialize();
1118 return true;
1121 template <PrimType Name, class T = typename PrimConv<Name>::T>
1122 bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1123 const T &Value = S.Stk.pop<T>();
1124 const Pointer &Ptr = S.Stk.pop<Pointer>();
1125 const Pointer &Field = Ptr.atField(I);
1126 Field.deref<T>() = Value;
1127 Field.activate();
1128 Field.initialize();
1129 return true;
1132 //===----------------------------------------------------------------------===//
1133 // GetPtr Local/Param/Global/Field/This
1134 //===----------------------------------------------------------------------===//
1136 inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1137 S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
1138 return true;
1141 inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1142 if (S.checkingPotentialConstantExpression()) {
1143 return false;
1145 S.Stk.push<Pointer>(S.Current->getParamPointer(I));
1146 return true;
1149 inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1150 S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
1151 return true;
1154 /// 1) Pops a Pointer from the stack
1155 /// 2) Pushes Pointer.atField(Off) on the stack
1156 inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1157 const Pointer &Ptr = S.Stk.pop<Pointer>();
1158 if (S.inConstantContext() && !CheckNull(S, OpPC, Ptr, CSK_Field))
1159 return false;
1160 if (!CheckExtern(S, OpPC, Ptr))
1161 return false;
1162 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1163 return false;
1164 if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1165 return false;
1167 S.Stk.push<Pointer>(Ptr.atField(Off));
1168 return true;
1171 inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1172 if (S.checkingPotentialConstantExpression())
1173 return false;
1174 const Pointer &This = S.Current->getThis();
1175 if (!CheckThis(S, OpPC, This))
1176 return false;
1177 S.Stk.push<Pointer>(This.atField(Off));
1178 return true;
1181 inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1182 const Pointer &Ptr = S.Stk.pop<Pointer>();
1183 if (!CheckNull(S, OpPC, Ptr, CSK_Field))
1184 return false;
1185 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1186 return false;
1187 Pointer Field = Ptr.atField(Off);
1188 Ptr.deactivate();
1189 Field.activate();
1190 S.Stk.push<Pointer>(std::move(Field));
1191 return true;
1194 inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1195 if (S.checkingPotentialConstantExpression())
1196 return false;
1197 const Pointer &This = S.Current->getThis();
1198 if (!CheckThis(S, OpPC, This))
1199 return false;
1200 Pointer Field = This.atField(Off);
1201 This.deactivate();
1202 Field.activate();
1203 S.Stk.push<Pointer>(std::move(Field));
1204 return true;
1207 inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1208 const Pointer &Ptr = S.Stk.pop<Pointer>();
1209 if (!CheckNull(S, OpPC, Ptr, CSK_Derived))
1210 return false;
1211 if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
1212 return false;
1213 S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
1214 return true;
1217 inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1218 const Pointer &Ptr = S.Stk.peek<Pointer>();
1219 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1220 return false;
1221 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1222 return false;
1223 S.Stk.push<Pointer>(Ptr.atField(Off));
1224 return true;
1227 inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1228 const Pointer &Ptr = S.Stk.pop<Pointer>();
1229 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1230 return false;
1231 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1232 return false;
1233 S.Stk.push<Pointer>(Ptr.atField(Off));
1234 return true;
1237 inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1238 if (S.checkingPotentialConstantExpression())
1239 return false;
1240 const Pointer &This = S.Current->getThis();
1241 if (!CheckThis(S, OpPC, This))
1242 return false;
1243 S.Stk.push<Pointer>(This.atField(Off));
1244 return true;
1247 inline bool InitPtrPop(InterpState &S, CodePtr OpPC) {
1248 const Pointer &Ptr = S.Stk.pop<Pointer>();
1249 Ptr.initialize();
1250 return true;
1253 inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1254 const Pointer &Ptr) {
1255 Pointer Base = Ptr;
1256 while (Base.isBaseClass())
1257 Base = Base.getBase();
1259 auto *Field = Base.getRecord()->getVirtualBase(Decl);
1260 S.Stk.push<Pointer>(Base.atField(Field->Offset));
1261 return true;
1264 inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
1265 const Pointer &Ptr = S.Stk.pop<Pointer>();
1266 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1267 return false;
1268 return VirtBaseHelper(S, OpPC, D, Ptr);
1271 inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
1272 const RecordDecl *D) {
1273 if (S.checkingPotentialConstantExpression())
1274 return false;
1275 const Pointer &This = S.Current->getThis();
1276 if (!CheckThis(S, OpPC, This))
1277 return false;
1278 return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
1281 //===----------------------------------------------------------------------===//
1282 // Load, Store, Init
1283 //===----------------------------------------------------------------------===//
1285 template <PrimType Name, class T = typename PrimConv<Name>::T>
1286 bool Load(InterpState &S, CodePtr OpPC) {
1287 const Pointer &Ptr = S.Stk.peek<Pointer>();
1288 if (!CheckLoad(S, OpPC, Ptr))
1289 return false;
1290 S.Stk.push<T>(Ptr.deref<T>());
1291 return true;
1294 template <PrimType Name, class T = typename PrimConv<Name>::T>
1295 bool LoadPop(InterpState &S, CodePtr OpPC) {
1296 const Pointer &Ptr = S.Stk.pop<Pointer>();
1297 if (!CheckLoad(S, OpPC, Ptr))
1298 return false;
1299 S.Stk.push<T>(Ptr.deref<T>());
1300 return true;
1303 template <PrimType Name, class T = typename PrimConv<Name>::T>
1304 bool Store(InterpState &S, CodePtr OpPC) {
1305 const T &Value = S.Stk.pop<T>();
1306 const Pointer &Ptr = S.Stk.peek<Pointer>();
1307 if (!CheckStore(S, OpPC, Ptr))
1308 return false;
1309 if (!Ptr.isRoot())
1310 Ptr.initialize();
1311 Ptr.deref<T>() = Value;
1312 return true;
1315 template <PrimType Name, class T = typename PrimConv<Name>::T>
1316 bool StorePop(InterpState &S, CodePtr OpPC) {
1317 const T &Value = S.Stk.pop<T>();
1318 const Pointer &Ptr = S.Stk.pop<Pointer>();
1319 if (!CheckStore(S, OpPC, Ptr))
1320 return false;
1321 if (!Ptr.isRoot())
1322 Ptr.initialize();
1323 Ptr.deref<T>() = Value;
1324 return true;
1327 template <PrimType Name, class T = typename PrimConv<Name>::T>
1328 bool StoreBitField(InterpState &S, CodePtr OpPC) {
1329 const T &Value = S.Stk.pop<T>();
1330 const Pointer &Ptr = S.Stk.peek<Pointer>();
1331 if (!CheckStore(S, OpPC, Ptr))
1332 return false;
1333 if (!Ptr.isRoot())
1334 Ptr.initialize();
1335 if (const auto *FD = Ptr.getField())
1336 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1337 else
1338 Ptr.deref<T>() = Value;
1339 return true;
1342 template <PrimType Name, class T = typename PrimConv<Name>::T>
1343 bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
1344 const T &Value = S.Stk.pop<T>();
1345 const Pointer &Ptr = S.Stk.pop<Pointer>();
1346 if (!CheckStore(S, OpPC, Ptr))
1347 return false;
1348 if (!Ptr.isRoot())
1349 Ptr.initialize();
1350 if (const auto *FD = Ptr.getField())
1351 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1352 else
1353 Ptr.deref<T>() = Value;
1354 return true;
1357 template <PrimType Name, class T = typename PrimConv<Name>::T>
1358 bool InitPop(InterpState &S, CodePtr OpPC) {
1359 const T &Value = S.Stk.pop<T>();
1360 const Pointer &Ptr = S.Stk.pop<Pointer>();
1361 if (!CheckInit(S, OpPC, Ptr))
1362 return false;
1363 Ptr.initialize();
1364 new (&Ptr.deref<T>()) T(Value);
1365 return true;
1368 /// 1) Pops the value from the stack
1369 /// 2) Peeks a pointer and gets its index \Idx
1370 /// 3) Sets the value on the pointer, leaving the pointer on the stack.
1371 template <PrimType Name, class T = typename PrimConv<Name>::T>
1372 bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1373 const T &Value = S.Stk.pop<T>();
1374 const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
1375 if (!CheckInit(S, OpPC, Ptr))
1376 return false;
1377 Ptr.initialize();
1378 new (&Ptr.deref<T>()) T(Value);
1379 return true;
1382 /// The same as InitElem, but pops the pointer as well.
1383 template <PrimType Name, class T = typename PrimConv<Name>::T>
1384 bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1385 const T &Value = S.Stk.pop<T>();
1386 const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
1387 if (!CheckInit(S, OpPC, Ptr))
1388 return false;
1389 Ptr.initialize();
1390 new (&Ptr.deref<T>()) T(Value);
1391 return true;
1394 //===----------------------------------------------------------------------===//
1395 // AddOffset, SubOffset
1396 //===----------------------------------------------------------------------===//
1398 template <class T, ArithOp Op>
1399 bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
1400 const Pointer &Ptr) {
1401 if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
1402 return false;
1404 // A zero offset does not change the pointer.
1405 if (Offset.isZero()) {
1406 S.Stk.push<Pointer>(Ptr);
1407 return true;
1410 if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
1411 return false;
1413 // Arrays of unknown bounds cannot have pointers into them.
1414 if (!CheckArray(S, OpPC, Ptr))
1415 return false;
1417 // Get a version of the index comparable to the type.
1418 T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
1419 // Compute the largest index into the array.
1420 T MaxIndex = T::from(Ptr.getNumElems(), Offset.bitWidth());
1422 bool Invalid = false;
1423 // Helper to report an invalid offset, computed as APSInt.
1424 auto DiagInvalidOffset = [&]() -> void {
1425 const unsigned Bits = Offset.bitWidth();
1426 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
1427 APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
1428 APSInt NewIndex =
1429 (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1430 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1431 << NewIndex
1432 << /*array*/ static_cast<int>(!Ptr.inArray())
1433 << static_cast<unsigned>(MaxIndex);
1434 Invalid = true;
1437 T MaxOffset = T::from(MaxIndex - Index, Offset.bitWidth());
1438 if constexpr (Op == ArithOp::Add) {
1439 // If the new offset would be negative, bail out.
1440 if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
1441 DiagInvalidOffset();
1443 // If the new offset would be out of bounds, bail out.
1444 if (Offset.isPositive() && Offset > MaxOffset)
1445 DiagInvalidOffset();
1446 } else {
1447 // If the new offset would be negative, bail out.
1448 if (Offset.isPositive() && Index < Offset)
1449 DiagInvalidOffset();
1451 // If the new offset would be out of bounds, bail out.
1452 if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
1453 DiagInvalidOffset();
1456 if (Invalid && !Ptr.isDummy())
1457 return false;
1459 // Offset is valid - compute it on unsigned.
1460 int64_t WideIndex = static_cast<int64_t>(Index);
1461 int64_t WideOffset = static_cast<int64_t>(Offset);
1462 int64_t Result;
1463 if constexpr (Op == ArithOp::Add)
1464 Result = WideIndex + WideOffset;
1465 else
1466 Result = WideIndex - WideOffset;
1468 S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
1469 return true;
1472 template <PrimType Name, class T = typename PrimConv<Name>::T>
1473 bool AddOffset(InterpState &S, CodePtr OpPC) {
1474 const T &Offset = S.Stk.pop<T>();
1475 const Pointer &Ptr = S.Stk.pop<Pointer>();
1476 return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
1479 template <PrimType Name, class T = typename PrimConv<Name>::T>
1480 bool SubOffset(InterpState &S, CodePtr OpPC) {
1481 const T &Offset = S.Stk.pop<T>();
1482 const Pointer &Ptr = S.Stk.pop<Pointer>();
1483 return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);
1486 template <ArithOp Op>
1487 static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
1488 const Pointer &Ptr) {
1489 using OneT = Integral<8, false>;
1491 const Pointer &P = Ptr.deref<Pointer>();
1492 if (!CheckNull(S, OpPC, P, CSK_ArrayIndex))
1493 return false;
1495 // Get the current value on the stack.
1496 S.Stk.push<Pointer>(P);
1498 // Now the current Ptr again and a constant 1.
1499 OneT One = OneT::from(1);
1500 if (!OffsetHelper<OneT, Op>(S, OpPC, One, P))
1501 return false;
1503 // Store the new value.
1504 Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
1505 return true;
1508 static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
1509 const Pointer &Ptr = S.Stk.pop<Pointer>();
1511 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
1512 return false;
1514 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
1517 static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
1518 const Pointer &Ptr = S.Stk.pop<Pointer>();
1520 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
1521 return false;
1523 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
1526 /// 1) Pops a Pointer from the stack.
1527 /// 2) Pops another Pointer from the stack.
1528 /// 3) Pushes the different of the indices of the two pointers on the stack.
1529 template <PrimType Name, class T = typename PrimConv<Name>::T>
1530 inline bool SubPtr(InterpState &S, CodePtr OpPC) {
1531 const Pointer &LHS = S.Stk.pop<Pointer>();
1532 const Pointer &RHS = S.Stk.pop<Pointer>();
1534 if (!Pointer::hasSameArray(LHS, RHS)) {
1535 // TODO: Diagnose.
1536 return false;
1539 T A = T::from(LHS.getIndex());
1540 T B = T::from(RHS.getIndex());
1541 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
1544 //===----------------------------------------------------------------------===//
1545 // Destroy
1546 //===----------------------------------------------------------------------===//
1548 inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
1549 S.Current->destroy(I);
1550 return true;
1553 //===----------------------------------------------------------------------===//
1554 // Cast, CastFP
1555 //===----------------------------------------------------------------------===//
1557 template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
1558 using T = typename PrimConv<TIn>::T;
1559 using U = typename PrimConv<TOut>::T;
1560 S.Stk.push<U>(U::from(S.Stk.pop<T>()));
1561 return true;
1564 /// 1) Pops a Floating from the stack.
1565 /// 2) Pushes a new floating on the stack that uses the given semantics.
1566 inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
1567 llvm::RoundingMode RM) {
1568 Floating F = S.Stk.pop<Floating>();
1569 Floating Result = F.toSemantics(Sem, RM);
1570 S.Stk.push<Floating>(Result);
1571 return true;
1574 /// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
1575 /// to know what bitwidth the result should be.
1576 template <PrimType Name, class T = typename PrimConv<Name>::T>
1577 bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1578 S.Stk.push<IntegralAP<false>>(
1579 IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth));
1580 return true;
1583 template <PrimType Name, class T = typename PrimConv<Name>::T>
1584 bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1585 S.Stk.push<IntegralAP<true>>(
1586 IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth));
1587 return true;
1590 template <PrimType Name, class T = typename PrimConv<Name>::T>
1591 bool CastIntegralFloating(InterpState &S, CodePtr OpPC,
1592 const llvm::fltSemantics *Sem,
1593 llvm::RoundingMode RM) {
1594 const T &From = S.Stk.pop<T>();
1595 APSInt FromAP = From.toAPSInt();
1596 Floating Result;
1598 auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
1599 S.Stk.push<Floating>(Result);
1601 return CheckFloatResult(S, OpPC, Result, Status);
1604 template <PrimType Name, class T = typename PrimConv<Name>::T>
1605 bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) {
1606 const Floating &F = S.Stk.pop<Floating>();
1608 if constexpr (std::is_same_v<T, Boolean>) {
1609 S.Stk.push<T>(T(F.isNonZero()));
1610 return true;
1611 } else {
1612 APSInt Result(std::max(8u, T::bitWidth()),
1613 /*IsUnsigned=*/!T::isSigned());
1614 auto Status = F.convertToInteger(Result);
1616 // Float-to-Integral overflow check.
1617 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
1618 const Expr *E = S.Current->getExpr(OpPC);
1619 QualType Type = E->getType();
1621 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
1622 return S.noteUndefinedBehavior();
1625 S.Stk.push<T>(T(Result));
1626 return CheckFloatResult(S, OpPC, F, Status);
1630 static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
1631 uint32_t BitWidth) {
1632 const Floating &F = S.Stk.pop<Floating>();
1634 APSInt Result(BitWidth, /*IsUnsigned=*/true);
1635 auto Status = F.convertToInteger(Result);
1637 // Float-to-Integral overflow check.
1638 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
1639 const Expr *E = S.Current->getExpr(OpPC);
1640 QualType Type = E->getType();
1642 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
1643 return S.noteUndefinedBehavior();
1646 S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
1647 return CheckFloatResult(S, OpPC, F, Status);
1650 static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
1651 uint32_t BitWidth) {
1652 const Floating &F = S.Stk.pop<Floating>();
1654 APSInt Result(BitWidth, /*IsUnsigned=*/false);
1655 auto Status = F.convertToInteger(Result);
1657 // Float-to-Integral overflow check.
1658 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
1659 const Expr *E = S.Current->getExpr(OpPC);
1660 QualType Type = E->getType();
1662 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
1663 return S.noteUndefinedBehavior();
1666 S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
1667 return CheckFloatResult(S, OpPC, F, Status);
1670 template <PrimType Name, class T = typename PrimConv<Name>::T>
1671 bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
1672 const Pointer &Ptr = S.Stk.pop<Pointer>();
1674 if (!CheckPotentialReinterpretCast(S, OpPC, Ptr))
1675 return false;
1677 S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
1678 return true;
1681 //===----------------------------------------------------------------------===//
1682 // Zero, Nullptr
1683 //===----------------------------------------------------------------------===//
1685 template <PrimType Name, class T = typename PrimConv<Name>::T>
1686 bool Zero(InterpState &S, CodePtr OpPC) {
1687 S.Stk.push<T>(T::zero());
1688 return true;
1691 static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1692 S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth));
1693 return true;
1696 static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1697 S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth));
1698 return true;
1701 template <PrimType Name, class T = typename PrimConv<Name>::T>
1702 inline bool Null(InterpState &S, CodePtr OpPC) {
1703 S.Stk.push<T>();
1704 return true;
1707 //===----------------------------------------------------------------------===//
1708 // This, ImplicitThis
1709 //===----------------------------------------------------------------------===//
1711 inline bool This(InterpState &S, CodePtr OpPC) {
1712 // Cannot read 'this' in this mode.
1713 if (S.checkingPotentialConstantExpression()) {
1714 return false;
1717 const Pointer &This = S.Current->getThis();
1718 if (!CheckThis(S, OpPC, This))
1719 return false;
1721 S.Stk.push<Pointer>(This);
1722 return true;
1725 inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
1726 assert(S.Current->getFunction()->hasRVO());
1727 if (S.checkingPotentialConstantExpression())
1728 return false;
1729 S.Stk.push<Pointer>(S.Current->getRVOPtr());
1730 return true;
1733 //===----------------------------------------------------------------------===//
1734 // Shr, Shl
1735 //===----------------------------------------------------------------------===//
1737 template <PrimType NameL, PrimType NameR>
1738 inline bool Shr(InterpState &S, CodePtr OpPC) {
1739 using LT = typename PrimConv<NameL>::T;
1740 using RT = typename PrimConv<NameR>::T;
1741 const auto &RHS = S.Stk.pop<RT>();
1742 const auto &LHS = S.Stk.pop<LT>();
1743 const unsigned Bits = LHS.bitWidth();
1745 if (!CheckShift(S, OpPC, LHS, RHS, Bits))
1746 return false;
1748 typename LT::AsUnsigned R;
1749 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
1750 LT::AsUnsigned::from(RHS), Bits, &R);
1751 S.Stk.push<LT>(LT::from(R));
1753 return true;
1756 template <PrimType NameL, PrimType NameR>
1757 inline bool Shl(InterpState &S, CodePtr OpPC) {
1758 using LT = typename PrimConv<NameL>::T;
1759 using RT = typename PrimConv<NameR>::T;
1760 const auto &RHS = S.Stk.pop<RT>();
1761 const auto &LHS = S.Stk.pop<LT>();
1762 const unsigned Bits = LHS.bitWidth();
1764 if (!CheckShift(S, OpPC, LHS, RHS, Bits))
1765 return false;
1767 typename LT::AsUnsigned R;
1768 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
1769 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
1770 S.Stk.push<LT>(LT::from(R));
1771 return true;
1774 //===----------------------------------------------------------------------===//
1775 // NoRet
1776 //===----------------------------------------------------------------------===//
1778 inline bool NoRet(InterpState &S, CodePtr OpPC) {
1779 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
1780 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
1781 return false;
1784 //===----------------------------------------------------------------------===//
1785 // NarrowPtr, ExpandPtr
1786 //===----------------------------------------------------------------------===//
1788 inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
1789 const Pointer &Ptr = S.Stk.pop<Pointer>();
1790 S.Stk.push<Pointer>(Ptr.narrow());
1791 return true;
1794 inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
1795 const Pointer &Ptr = S.Stk.pop<Pointer>();
1796 S.Stk.push<Pointer>(Ptr.expand());
1797 return true;
1800 // 1) Pops an integral value from the stack
1801 // 2) Peeks a pointer
1802 // 3) Pushes a new pointer that's a narrowed array
1803 // element of the peeked pointer with the value
1804 // from 1) added as offset.
1806 // This leaves the original pointer on the stack and pushes a new one
1807 // with the offset applied and narrowed.
1808 template <PrimType Name, class T = typename PrimConv<Name>::T>
1809 inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
1810 const T &Offset = S.Stk.pop<T>();
1811 const Pointer &Ptr = S.Stk.peek<Pointer>();
1813 if (!CheckArray(S, OpPC, Ptr))
1814 return false;
1816 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
1817 return false;
1819 return NarrowPtr(S, OpPC);
1822 /// Just takes a pointer and checks if its' an incomplete
1823 /// array type.
1824 inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
1825 const Pointer &Ptr = S.Stk.peek<Pointer>();
1827 if (!Ptr.isUnknownSizeArray())
1828 return true;
1830 const SourceInfo &E = S.Current->getSource(OpPC);
1831 S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
1833 return false;
1836 template <PrimType Name, class T = typename PrimConv<Name>::T>
1837 inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
1838 const T &Offset = S.Stk.pop<T>();
1839 const Pointer &Ptr = S.Stk.pop<Pointer>();
1841 if (!CheckArray(S, OpPC, Ptr))
1842 return false;
1844 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
1845 return false;
1847 return NarrowPtr(S, OpPC);
1850 inline bool CheckGlobalCtor(InterpState &S, CodePtr OpPC) {
1851 const Pointer &Obj = S.Stk.peek<Pointer>();
1852 return CheckCtorCall(S, OpPC, Obj);
1855 inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func) {
1856 if (Func->hasThisPointer()) {
1857 size_t ThisOffset =
1858 Func->getArgSize() + (Func->hasRVO() ? primSize(PT_Ptr) : 0);
1860 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
1862 // If the current function is a lambda static invoker and
1863 // the function we're about to call is a lambda call operator,
1864 // skip the CheckInvoke, since the ThisPtr is a null pointer
1865 // anyway.
1866 if (!(S.Current->getFunction() &&
1867 S.Current->getFunction()->isLambdaStaticInvoker() &&
1868 Func->isLambdaCallOperator())) {
1869 if (!CheckInvoke(S, OpPC, ThisPtr))
1870 return false;
1873 if (S.checkingPotentialConstantExpression())
1874 return false;
1877 if (!CheckCallable(S, OpPC, Func))
1878 return false;
1880 if (!CheckCallDepth(S, OpPC))
1881 return false;
1883 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC);
1884 InterpFrame *FrameBefore = S.Current;
1885 S.Current = NewFrame.get();
1887 APValue CallResult;
1888 // Note that we cannot assert(CallResult.hasValue()) here since
1889 // Ret() above only sets the APValue if the curent frame doesn't
1890 // have a caller set.
1891 if (Interpret(S, CallResult)) {
1892 NewFrame.release(); // Frame was delete'd already.
1893 assert(S.Current == FrameBefore);
1894 return true;
1897 // Interpreting the function failed somehow. Reset to
1898 // previous state.
1899 S.Current = FrameBefore;
1900 return false;
1903 inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func) {
1904 assert(Func->hasThisPointer());
1905 assert(Func->isVirtual());
1906 size_t ThisOffset =
1907 Func->getArgSize() + (Func->hasRVO() ? primSize(PT_Ptr) : 0);
1908 Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
1910 const CXXRecordDecl *DynamicDecl =
1911 ThisPtr.getDeclDesc()->getType()->getAsCXXRecordDecl();
1912 const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());
1913 const auto *InitialFunction = cast<CXXMethodDecl>(Func->getDecl());
1914 const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
1915 DynamicDecl, StaticDecl, InitialFunction);
1917 if (Overrider != InitialFunction) {
1918 // DR1872: An instantiated virtual constexpr function can't be called in a
1919 // constant expression (prior to C++20). We can still constant-fold such a
1920 // call.
1921 if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {
1922 const Expr *E = S.Current->getExpr(OpPC);
1923 S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();
1926 Func = S.getContext().getOrCreateFunction(Overrider);
1928 const CXXRecordDecl *ThisFieldDecl =
1929 ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
1930 if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
1931 // If the function we call is further DOWN the hierarchy than the
1932 // FieldDesc of our pointer, just get the DeclDesc instead, which
1933 // is the furthest we might go up in the hierarchy.
1934 ThisPtr = ThisPtr.getDeclPtr();
1938 return Call(S, OpPC, Func);
1941 inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
1942 const CallExpr *CE) {
1943 auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
1945 InterpFrame *FrameBefore = S.Current;
1946 S.Current = NewFrame.get();
1948 if (InterpretBuiltin(S, PC, Func, CE)) {
1949 NewFrame.release();
1950 return true;
1952 S.Current = FrameBefore;
1953 return false;
1956 inline bool CallPtr(InterpState &S, CodePtr OpPC) {
1957 const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();
1959 const Function *F = FuncPtr.getFunction();
1960 if (!F || !F->isConstexpr())
1961 return false;
1963 if (F->isVirtual())
1964 return CallVirt(S, OpPC, F);
1966 return Call(S, OpPC, F);
1969 inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
1970 assert(Func);
1971 S.Stk.push<FunctionPointer>(Func);
1972 return true;
1975 /// Just emit a diagnostic. The expression that caused emission of this
1976 /// op is not valid in a constant context.
1977 inline bool Invalid(InterpState &S, CodePtr OpPC) {
1978 const SourceLocation &Loc = S.Current->getLocation(OpPC);
1979 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
1980 << S.Current->getRange(OpPC);
1981 return false;
1984 /// Same here, but only for casts.
1985 inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) {
1986 const SourceLocation &Loc = S.Current->getLocation(OpPC);
1987 S.FFDiag(Loc, diag::note_constexpr_invalid_cast)
1988 << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
1989 return false;
1992 inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC,
1993 const DeclRefExpr *DR) {
1994 assert(DR);
1995 return CheckDeclRef(S, OpPC, DR);
1998 template <PrimType Name, class T = typename PrimConv<Name>::T>
1999 inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
2000 llvm::SmallVector<int64_t> ArrayIndices;
2001 for (size_t I = 0; I != E->getNumExpressions(); ++I)
2002 ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
2004 int64_t Result;
2005 if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
2006 return false;
2008 S.Stk.push<T>(T::from(Result));
2010 return true;
2013 //===----------------------------------------------------------------------===//
2014 // Read opcode arguments
2015 //===----------------------------------------------------------------------===//
2017 template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
2018 if constexpr (std::is_pointer<T>::value) {
2019 uint32_t ID = OpPC.read<uint32_t>();
2020 return reinterpret_cast<T>(S.P.getNativePointer(ID));
2021 } else {
2022 return OpPC.read<T>();
2026 template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
2027 Floating F = Floating::deserialize(*OpPC);
2028 OpPC += align(F.bytesToSerialize());
2029 return F;
2032 } // namespace interp
2033 } // namespace clang
2035 #endif