1 //===--- Interp.h - Interpreter for the constexpr VM ------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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
19 #include "FunctionPointer.h"
20 #include "InterpFrame.h"
21 #include "InterpStack.h"
22 #include "InterpState.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"
35 #include <type_traits>
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
) {
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
,
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
,
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
,
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
,
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
,
128 if (RHS
.isNegative()) {
129 const SourceInfo
&Loc
= S
.Current
->getSource(OpPC
);
130 S
.CCEDiag(Loc
, diag::note_constexpr_negative_shift
) << RHS
.toAPSInt();
134 // C++11 [expr.shift]p1: Shift width must be less than the bit width of
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
;
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.
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
) {
164 const auto *Op
= cast
<BinaryOperator
>(S
.Current
->getExpr(OpPC
));
165 S
.FFDiag(Op
, diag::note_expr_divide_by_zero
)
166 << Op
->getRHS()->getSourceRange();
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();
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 //===----------------------------------------------------------------------===//
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
220 // Null pointers are considered live here.
221 if (!Ret
.isZero() && !Ret
.isLive())
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();
238 if (!ReturnValue
<T
>(Ret
, Result
))
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();
261 //===----------------------------------------------------------------------===//
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
,
269 // Fast path - add the numbers with fixed width.
271 if (!OpFW(LHS
, RHS
, Bits
, &Result
)) {
272 S
.Stk
.push
<T
>(Result
);
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();
293 S
.CCEDiag(E
, diag::note_constexpr_overflow
) << Value
<< Type
;
294 if (!S
.noteUndefinedBehavior()) {
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
>();
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
>();
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
>();
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();
365 if (!T::bitAnd(LHS
, RHS
, Bits
, &Result
)) {
366 S
.Stk
.push
<T
>(Result
);
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();
382 if (!T::bitOr(LHS
, RHS
, Bits
, &Result
)) {
383 S
.Stk
.push
<T
>(Result
);
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();
399 if (!T::bitXor(LHS
, RHS
, Bits
, &Result
)) {
400 S
.Stk
.push
<T
>(Result
);
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
))
417 const unsigned Bits
= RHS
.bitWidth() * 2;
419 if (!T::rem(LHS
, RHS
, Bits
, &Result
)) {
420 S
.Stk
.push
<T
>(Result
);
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
))
437 const unsigned Bits
= RHS
.bitWidth() * 2;
439 if (!T::div(LHS
, RHS
, Bits
, &Result
)) {
440 S
.Stk
.push
<T
>(Result
);
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
))
454 auto Status
= Floating::div(LHS
, RHS
, RM
, &Result
);
455 S
.Stk
.push
<Floating
>(Result
);
456 return CheckFloatResult(S
, OpPC
, Result
, Status
);
459 //===----------------------------------------------------------------------===//
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();
469 Boolean::inv(BoolT::from(Val
, Bits
), &R
);
471 S
.Stk
.push
<BoolT
>(R
);
475 //===----------------------------------------------------------------------===//
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
>();
484 if (!T::neg(Value
, &Result
)) {
485 S
.Stk
.push
<T
>(Result
);
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();
506 S
.CCEDiag(E
, diag::note_constexpr_overflow
) << NegatedValue
<< Type
;
507 return S
.noteUndefinedBehavior();
510 enum class PushVal
: bool {
514 enum class IncDecOp
{
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
>();
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
;
533 if (!T::decrement(Value
, &Result
)) {
534 Ptr
.deref
<T
>() = Result
;
539 // Something went wrong with the previous operation. Compute the
540 // result with another bit of precision.
541 unsigned Bits
= Value
.bitWidth() + 1;
543 if constexpr (Op
== IncDecOp::Inc
)
544 APResult
= ++Value
.toAPSInt(Bits
);
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();
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
))
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
))
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
))
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
))
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
>();
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
);
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
))
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
))
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
))
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
))
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
>();
680 if (!T::comp(Val
, &Result
)) {
681 S
.Stk
.push
<T
>(Result
);
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
))));
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.
710 inline bool CmpHelper
<FunctionPointer
>(InterpState
&S
, CodePtr OpPC
,
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());
723 inline bool CmpHelperEQ
<FunctionPointer
>(InterpState
&S
, CodePtr OpPC
,
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
))));
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());
744 unsigned VL
= LHS
.getByteOffset();
745 unsigned VR
= RHS
.getByteOffset();
746 S
.Stk
.push
<BoolT
>(BoolT::from(Fn(Compare(VL
, VR
))));
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
)));
762 if (!Pointer::hasSameBase(LHS
, RHS
)) {
763 S
.Stk
.push
<BoolT
>(BoolT::from(Fn(ComparisonCategoryResult::Unordered
)));
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
))));
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());
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 //===----------------------------------------------------------------------===//
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
);
865 //===----------------------------------------------------------------------===//
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
>());
875 template <PrimType Name
, class T
= typename PrimConv
<Name
>::T
>
876 bool Pop(InterpState
&S
, CodePtr OpPC
) {
881 //===----------------------------------------------------------------------===//
883 //===----------------------------------------------------------------------===//
885 template <PrimType Name
, class T
= typename PrimConv
<Name
>::T
>
886 bool Const(InterpState
&S
, CodePtr OpPC
, const T
&Arg
) {
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
))
900 S
.Stk
.push
<T
>(Ptr
.deref
<T
>());
904 /// 1) Pops the value from the stack.
905 /// 2) Writes the value to the local variable with the
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
>());
913 template <PrimType Name
, class T
= typename PrimConv
<Name
>::T
>
914 bool GetParam(InterpState
&S
, CodePtr OpPC
, uint32_t I
) {
915 if (S
.checkingPotentialConstantExpression()) {
918 S
.Stk
.push
<T
>(S
.Current
->getParam
<T
>(I
));
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
>());
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
))
935 if (!CheckRange(S
, OpPC
, Obj
, CSK_Field
))
937 const Pointer
&Field
= Obj
.atField(I
);
938 if (!CheckLoad(S
, OpPC
, Field
))
940 S
.Stk
.push
<T
>(Field
.deref
<T
>());
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
))
950 if (!CheckRange(S
, OpPC
, Obj
, CSK_Field
))
952 const Pointer
&Field
= Obj
.atField(I
);
953 if (!CheckStore(S
, OpPC
, Field
))
956 Field
.deref
<T
>() = Value
;
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
))
967 if (!CheckRange(S
, OpPC
, Obj
, CSK_Field
))
969 const Pointer
&Field
= Obj
.atField(I
);
970 if (!CheckLoad(S
, OpPC
, Field
))
972 S
.Stk
.push
<T
>(Field
.deref
<T
>());
976 template <PrimType Name
, class T
= typename PrimConv
<Name
>::T
>
977 bool GetThisField(InterpState
&S
, CodePtr OpPC
, uint32_t I
) {
978 if (S
.checkingPotentialConstantExpression())
980 const Pointer
&This
= S
.Current
->getThis();
981 if (!CheckThis(S
, OpPC
, This
))
983 const Pointer
&Field
= This
.atField(I
);
984 if (!CheckLoad(S
, OpPC
, Field
))
986 S
.Stk
.push
<T
>(Field
.deref
<T
>());
990 template <PrimType Name
, class T
= typename PrimConv
<Name
>::T
>
991 bool SetThisField(InterpState
&S
, CodePtr OpPC
, uint32_t I
) {
992 if (S
.checkingPotentialConstantExpression())
994 const T
&Value
= S
.Stk
.pop
<T
>();
995 const Pointer
&This
= S
.Current
->getThis();
996 if (!CheckThis(S
, OpPC
, This
))
998 const Pointer
&Field
= This
.atField(I
);
999 if (!CheckStore(S
, OpPC
, Field
))
1001 Field
.deref
<T
>() = Value
;
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
);
1010 S
.Stk
.push
<T
>(B
->deref
<T
>());
1014 template <PrimType Name
, class T
= typename PrimConv
<Name
>::T
>
1015 bool SetGlobal(InterpState
&S
, CodePtr OpPC
, uint32_t I
) {
1016 // TODO: emit warning.
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
>();
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
) {
1033 const T Value
= S
.Stk
.peek
<T
>();
1034 APValue APV
= Value
.toAPValue();
1035 APValue
*Cached
= Temp
->getOrCreateValue(true);
1038 S
.P
.getGlobal(I
)->deref
<T
>() = S
.Stk
.pop
<T
>();
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
) {
1048 const Pointer
&P
= S
.Stk
.peek
<Pointer
>();
1049 APValue
*Cached
= Temp
->getOrCreateValue(true);
1051 *Cached
= P
.toRValue(S
.getCtx());
1055 template <PrimType Name
, class T
= typename PrimConv
<Name
>::T
>
1056 bool InitThisField(InterpState
&S
, CodePtr OpPC
, uint32_t I
) {
1057 if (S
.checkingPotentialConstantExpression())
1059 const Pointer
&This
= S
.Current
->getThis();
1060 if (!CheckThis(S
, OpPC
, This
))
1062 const Pointer
&Field
= This
.atField(I
);
1063 Field
.deref
<T
>() = S
.Stk
.pop
<T
>();
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())
1073 const Pointer
&This
= S
.Current
->getThis();
1074 if (!CheckThis(S
, OpPC
, This
))
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()));
1083 template <PrimType Name
, class T
= typename PrimConv
<Name
>::T
>
1084 bool InitThisFieldActive(InterpState
&S
, CodePtr OpPC
, uint32_t I
) {
1085 if (S
.checkingPotentialConstantExpression())
1087 const Pointer
&This
= S
.Current
->getThis();
1088 if (!CheckThis(S
, OpPC
, This
))
1090 const Pointer
&Field
= This
.atField(I
);
1091 Field
.deref
<T
>() = S
.Stk
.pop
<T
>();
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
;
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()));
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
;
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
));
1141 inline bool GetPtrParam(InterpState
&S
, CodePtr OpPC
, uint32_t I
) {
1142 if (S
.checkingPotentialConstantExpression()) {
1145 S
.Stk
.push
<Pointer
>(S
.Current
->getParamPointer(I
));
1149 inline bool GetPtrGlobal(InterpState
&S
, CodePtr OpPC
, uint32_t I
) {
1150 S
.Stk
.push
<Pointer
>(S
.P
.getPtrGlobal(I
));
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
))
1160 if (!CheckExtern(S
, OpPC
, Ptr
))
1162 if (!CheckRange(S
, OpPC
, Ptr
, CSK_Field
))
1164 if (!CheckSubobject(S
, OpPC
, Ptr
, CSK_Field
))
1167 S
.Stk
.push
<Pointer
>(Ptr
.atField(Off
));
1171 inline bool GetPtrThisField(InterpState
&S
, CodePtr OpPC
, uint32_t Off
) {
1172 if (S
.checkingPotentialConstantExpression())
1174 const Pointer
&This
= S
.Current
->getThis();
1175 if (!CheckThis(S
, OpPC
, This
))
1177 S
.Stk
.push
<Pointer
>(This
.atField(Off
));
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
))
1185 if (!CheckRange(S
, OpPC
, Ptr
, CSK_Field
))
1187 Pointer Field
= Ptr
.atField(Off
);
1190 S
.Stk
.push
<Pointer
>(std::move(Field
));
1194 inline bool GetPtrActiveThisField(InterpState
&S
, CodePtr OpPC
, uint32_t Off
) {
1195 if (S
.checkingPotentialConstantExpression())
1197 const Pointer
&This
= S
.Current
->getThis();
1198 if (!CheckThis(S
, OpPC
, This
))
1200 Pointer Field
= This
.atField(Off
);
1203 S
.Stk
.push
<Pointer
>(std::move(Field
));
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
))
1211 if (!CheckSubobject(S
, OpPC
, Ptr
, CSK_Derived
))
1213 S
.Stk
.push
<Pointer
>(Ptr
.atFieldSub(Off
));
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
))
1221 if (!CheckSubobject(S
, OpPC
, Ptr
, CSK_Base
))
1223 S
.Stk
.push
<Pointer
>(Ptr
.atField(Off
));
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
))
1231 if (!CheckSubobject(S
, OpPC
, Ptr
, CSK_Base
))
1233 S
.Stk
.push
<Pointer
>(Ptr
.atField(Off
));
1237 inline bool GetPtrThisBase(InterpState
&S
, CodePtr OpPC
, uint32_t Off
) {
1238 if (S
.checkingPotentialConstantExpression())
1240 const Pointer
&This
= S
.Current
->getThis();
1241 if (!CheckThis(S
, OpPC
, This
))
1243 S
.Stk
.push
<Pointer
>(This
.atField(Off
));
1247 inline bool InitPtrPop(InterpState
&S
, CodePtr OpPC
) {
1248 const Pointer
&Ptr
= S
.Stk
.pop
<Pointer
>();
1253 inline bool VirtBaseHelper(InterpState
&S
, CodePtr OpPC
, const RecordDecl
*Decl
,
1254 const Pointer
&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
));
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
))
1268 return VirtBaseHelper(S
, OpPC
, D
, Ptr
);
1271 inline bool GetPtrThisVirtBase(InterpState
&S
, CodePtr OpPC
,
1272 const RecordDecl
*D
) {
1273 if (S
.checkingPotentialConstantExpression())
1275 const Pointer
&This
= S
.Current
->getThis();
1276 if (!CheckThis(S
, OpPC
, This
))
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
))
1290 S
.Stk
.push
<T
>(Ptr
.deref
<T
>());
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
))
1299 S
.Stk
.push
<T
>(Ptr
.deref
<T
>());
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
))
1311 Ptr
.deref
<T
>() = Value
;
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
))
1323 Ptr
.deref
<T
>() = Value
;
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
))
1335 if (const auto *FD
= Ptr
.getField())
1336 Ptr
.deref
<T
>() = Value
.truncate(FD
->getBitWidthValue(S
.getCtx()));
1338 Ptr
.deref
<T
>() = Value
;
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
))
1350 if (const auto *FD
= Ptr
.getField())
1351 Ptr
.deref
<T
>() = Value
.truncate(FD
->getBitWidthValue(S
.getCtx()));
1353 Ptr
.deref
<T
>() = Value
;
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
))
1364 new (&Ptr
.deref
<T
>()) T(Value
);
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
))
1378 new (&Ptr
.deref
<T
>()) T(Value
);
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
))
1390 new (&Ptr
.deref
<T
>()) T(Value
);
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
))
1404 // A zero offset does not change the pointer.
1405 if (Offset
.isZero()) {
1406 S
.Stk
.push
<Pointer
>(Ptr
);
1410 if (!CheckNull(S
, OpPC
, Ptr
, CSK_ArrayIndex
))
1413 // Arrays of unknown bounds cannot have pointers into them.
1414 if (!CheckArray(S
, OpPC
, Ptr
))
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);
1429 (Op
== ArithOp::Add
) ? (APIndex
+ APOffset
) : (APIndex
- APOffset
);
1430 S
.CCEDiag(S
.Current
->getSource(OpPC
), diag::note_constexpr_array_index
)
1432 << /*array*/ static_cast<int>(!Ptr
.inArray())
1433 << static_cast<unsigned>(MaxIndex
);
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();
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())
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
);
1463 if constexpr (Op
== ArithOp::Add
)
1464 Result
= WideIndex
+ WideOffset
;
1466 Result
= WideIndex
- WideOffset
;
1468 S
.Stk
.push
<Pointer
>(Ptr
.atIndex(static_cast<unsigned>(Result
)));
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
))
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
))
1503 // Store the new value.
1504 Ptr
.deref
<Pointer
>() = S
.Stk
.pop
<Pointer
>();
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
))
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
))
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
)) {
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 //===----------------------------------------------------------------------===//
1546 //===----------------------------------------------------------------------===//
1548 inline bool Destroy(InterpState
&S
, CodePtr OpPC
, uint32_t I
) {
1549 S
.Current
->destroy(I
);
1553 //===----------------------------------------------------------------------===//
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
>()));
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
);
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
));
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
));
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();
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()));
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
))
1677 S
.Stk
.push
<T
>(T::from(Ptr
.getIntegerRepresentation()));
1681 //===----------------------------------------------------------------------===//
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());
1691 static inline bool ZeroIntAP(InterpState
&S
, CodePtr OpPC
, uint32_t BitWidth
) {
1692 S
.Stk
.push
<IntegralAP
<false>>(IntegralAP
<false>::zero(BitWidth
));
1696 static inline bool ZeroIntAPS(InterpState
&S
, CodePtr OpPC
, uint32_t BitWidth
) {
1697 S
.Stk
.push
<IntegralAP
<true>>(IntegralAP
<true>::zero(BitWidth
));
1701 template <PrimType Name
, class T
= typename PrimConv
<Name
>::T
>
1702 inline bool Null(InterpState
&S
, CodePtr OpPC
) {
1707 //===----------------------------------------------------------------------===//
1708 // This, ImplicitThis
1709 //===----------------------------------------------------------------------===//
1711 inline bool This(InterpState
&S
, CodePtr OpPC
) {
1712 // Cannot read 'this' in this mode.
1713 if (S
.checkingPotentialConstantExpression()) {
1717 const Pointer
&This
= S
.Current
->getThis();
1718 if (!CheckThis(S
, OpPC
, This
))
1721 S
.Stk
.push
<Pointer
>(This
);
1725 inline bool RVOPtr(InterpState
&S
, CodePtr OpPC
) {
1726 assert(S
.Current
->getFunction()->hasRVO());
1727 if (S
.checkingPotentialConstantExpression())
1729 S
.Stk
.push
<Pointer
>(S
.Current
->getRVOPtr());
1733 //===----------------------------------------------------------------------===//
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
))
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
));
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
))
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
));
1774 //===----------------------------------------------------------------------===//
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
);
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());
1794 inline bool ExpandPtr(InterpState
&S
, CodePtr OpPC
) {
1795 const Pointer
&Ptr
= S
.Stk
.pop
<Pointer
>();
1796 S
.Stk
.push
<Pointer
>(Ptr
.expand());
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
))
1816 if (!OffsetHelper
<T
, ArithOp::Add
>(S
, OpPC
, Offset
, Ptr
))
1819 return NarrowPtr(S
, OpPC
);
1822 /// Just takes a pointer and checks if its' an incomplete
1824 inline bool ArrayDecay(InterpState
&S
, CodePtr OpPC
) {
1825 const Pointer
&Ptr
= S
.Stk
.peek
<Pointer
>();
1827 if (!Ptr
.isUnknownSizeArray())
1830 const SourceInfo
&E
= S
.Current
->getSource(OpPC
);
1831 S
.FFDiag(E
, diag::note_constexpr_unsupported_unsized_array
);
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
))
1844 if (!OffsetHelper
<T
, ArithOp::Add
>(S
, OpPC
, Offset
, Ptr
))
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()) {
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
1866 if (!(S
.Current
->getFunction() &&
1867 S
.Current
->getFunction()->isLambdaStaticInvoker() &&
1868 Func
->isLambdaCallOperator())) {
1869 if (!CheckInvoke(S
, OpPC
, ThisPtr
))
1873 if (S
.checkingPotentialConstantExpression())
1877 if (!CheckCallable(S
, OpPC
, Func
))
1880 if (!CheckCallDepth(S
, OpPC
))
1883 auto NewFrame
= std::make_unique
<InterpFrame
>(S
, Func
, OpPC
);
1884 InterpFrame
*FrameBefore
= S
.Current
;
1885 S
.Current
= NewFrame
.get();
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
);
1897 // Interpreting the function failed somehow. Reset to
1899 S
.Current
= FrameBefore
;
1903 inline bool CallVirt(InterpState
&S
, CodePtr OpPC
, const Function
*Func
) {
1904 assert(Func
->hasThisPointer());
1905 assert(Func
->isVirtual());
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
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
)) {
1952 S
.Current
= FrameBefore
;
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())
1964 return CallVirt(S
, OpPC
, F
);
1966 return Call(S
, OpPC
, F
);
1969 inline bool GetFnPtr(InterpState
&S
, CodePtr OpPC
, const Function
*Func
) {
1971 S
.Stk
.push
<FunctionPointer
>(Func
);
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
);
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
);
1992 inline bool InvalidDeclRef(InterpState
&S
, CodePtr OpPC
,
1993 const DeclRefExpr
*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>());
2005 if (!InterpretOffsetOf(S
, OpPC
, E
, ArrayIndices
, Result
))
2008 S
.Stk
.push
<T
>(T::from(Result
));
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
));
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());
2032 } // namespace interp
2033 } // namespace clang