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