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 "Function.h"
18 #include "InterpFrame.h"
19 #include "InterpStack.h"
20 #include "InterpState.h"
21 #include "Opcode.h"
22 #include "PrimType.h"
23 #include "Program.h"
24 #include "State.h"
25 #include "clang/AST/ASTContext.h"
26 #include "clang/AST/ASTDiagnostic.h"
27 #include "clang/AST/CXXInheritance.h"
28 #include "clang/AST/Expr.h"
29 #include "llvm/ADT/APFloat.h"
30 #include "llvm/ADT/APSInt.h"
31 #include "llvm/Support/Endian.h"
32 #include <limits>
33 #include <type_traits>
34
35 namespace clang {
36 namespace interp {
37
38 using APInt = llvm::APInt;
39 using APSInt = llvm::APSInt;
40
41 /// Convert a value to an APValue.
ReturnValue(const T & V,APValue & R)42 template <typename T> bool ReturnValue(const T &V, APValue &R) {
43 R = V.toAPValue();
44 return true;
45 }
46
47 /// Checks if the variable has externally defined storage.
48 bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
49
50 /// Checks if the array is offsetable.
51 bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
52
53 /// Checks if a pointer is live and accessible.
54 bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
55 AccessKinds AK);
56 /// Checks if a pointer is null.
57 bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
58 CheckSubobjectKind CSK);
59
60 /// Checks if a pointer is in range.
61 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
62 AccessKinds AK);
63
64 /// Checks if a field from which a pointer is going to be derived is valid.
65 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
66 CheckSubobjectKind CSK);
67
68 /// Checks if a pointer points to const storage.
69 bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
70
71 /// Checks if a pointer points to a mutable field.
72 bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
73
74 /// Checks if a value can be loaded from a block.
75 bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
76
77 /// Checks if a value can be stored in a block.
78 bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
79
80 /// Checks if a method can be invoked on an object.
81 bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
82
83 /// Checks if a value can be initialized.
84 bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
85
86 /// Checks if a method can be called.
87 bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
88
89 /// Checks the 'this' pointer.
90 bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
91
92 /// Checks if a method is pure virtual.
93 bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
94
95 /// Checks that all fields are initialized after a constructor call.
96 bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This);
97
98 /// Checks if the shift operation is legal.
99 template <typename RT>
CheckShift(InterpState & S,CodePtr OpPC,const RT & RHS,unsigned Bits)100 bool CheckShift(InterpState &S, CodePtr OpPC, const RT &RHS, unsigned Bits) {
101 if (RHS.isNegative()) {
102 const SourceInfo &Loc = S.Current->getSource(OpPC);
103 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
104 return false;
105 }
106
107 // C++11 [expr.shift]p1: Shift width must be less than the bit width of
108 // the shifted type.
109 if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
110 const Expr *E = S.Current->getExpr(OpPC);
111 const APSInt Val = RHS.toAPSInt();
112 QualType Ty = E->getType();
113 S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
114 return false;
115 }
116 return true;
117 }
118
119 /// Checks if Div/Rem operation on LHS and RHS is valid.
120 template <typename T>
CheckDivRem(InterpState & S,CodePtr OpPC,const T & LHS,const T & RHS)121 bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
122 if (RHS.isZero()) {
123 const SourceInfo &Loc = S.Current->getSource(OpPC);
124 S.FFDiag(Loc, diag::note_expr_divide_by_zero);
125 return false;
126 }
127
128 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
129 APSInt LHSInt = LHS.toAPSInt();
130 SmallString<32> Trunc;
131 (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
132 const SourceInfo &Loc = S.Current->getSource(OpPC);
133 const Expr *E = S.Current->getExpr(OpPC);
134 S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
135 return false;
136 }
137 return true;
138 }
139
140 /// Interpreter entry point.
141 bool Interpret(InterpState &S, APValue &Result);
142
143 //===----------------------------------------------------------------------===//
144 // Add, Sub, Mul
145 //===----------------------------------------------------------------------===//
146
147 template <typename T, bool (*OpFW)(T, T, unsigned, T *),
148 template <typename U> class OpAP>
AddSubMulHelper(InterpState & S,CodePtr OpPC,unsigned Bits,const T & LHS,const T & RHS)149 bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
150 const T &RHS) {
151 // Fast path - add the numbers with fixed width.
152 T Result;
153 if (!OpFW(LHS, RHS, Bits, &Result)) {
154 S.Stk.push<T>(Result);
155 return true;
156 }
157
158 // If for some reason evaluation continues, use the truncated results.
159 S.Stk.push<T>(Result);
160
161 // Slow path - compute the result using another bit of precision.
162 APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
163
164 // Report undefined behaviour, stopping if required.
165 const Expr *E = S.Current->getExpr(OpPC);
166 QualType Type = E->getType();
167 if (S.checkingForUndefinedBehavior()) {
168 SmallString<32> Trunc;
169 Value.trunc(Result.bitWidth()).toString(Trunc, 10);
170 auto Loc = E->getExprLoc();
171 S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
172 return true;
173 } else {
174 S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
175 return S.noteUndefinedBehavior();
176 }
177 }
178
179 template <PrimType Name, class T = typename PrimConv<Name>::T>
Add(InterpState & S,CodePtr OpPC)180 bool Add(InterpState &S, CodePtr OpPC) {
181 const T &RHS = S.Stk.pop<T>();
182 const T &LHS = S.Stk.pop<T>();
183 const unsigned Bits = RHS.bitWidth() + 1;
184 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
185 }
186
187 template <PrimType Name, class T = typename PrimConv<Name>::T>
Sub(InterpState & S,CodePtr OpPC)188 bool Sub(InterpState &S, CodePtr OpPC) {
189 const T &RHS = S.Stk.pop<T>();
190 const T &LHS = S.Stk.pop<T>();
191 const unsigned Bits = RHS.bitWidth() + 1;
192 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
193 }
194
195 template <PrimType Name, class T = typename PrimConv<Name>::T>
Mul(InterpState & S,CodePtr OpPC)196 bool Mul(InterpState &S, CodePtr OpPC) {
197 const T &RHS = S.Stk.pop<T>();
198 const T &LHS = S.Stk.pop<T>();
199 const unsigned Bits = RHS.bitWidth() * 2;
200 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
201 }
202
203 /// 1) Pops the RHS from the stack.
204 /// 2) Pops the LHS from the stack.
205 /// 3) Pushes 'LHS & RHS' on the stack
206 template <PrimType Name, class T = typename PrimConv<Name>::T>
BitAnd(InterpState & S,CodePtr OpPC)207 bool BitAnd(InterpState &S, CodePtr OpPC) {
208 const T &RHS = S.Stk.pop<T>();
209 const T &LHS = S.Stk.pop<T>();
210
211 unsigned Bits = RHS.bitWidth();
212 T Result;
213 if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
214 S.Stk.push<T>(Result);
215 return true;
216 }
217 return false;
218 }
219
220 /// 1) Pops the RHS from the stack.
221 /// 2) Pops the LHS from the stack.
222 /// 3) Pushes 'LHS | RHS' on the stack
223 template <PrimType Name, class T = typename PrimConv<Name>::T>
BitOr(InterpState & S,CodePtr OpPC)224 bool BitOr(InterpState &S, CodePtr OpPC) {
225 const T &RHS = S.Stk.pop<T>();
226 const T &LHS = S.Stk.pop<T>();
227
228 unsigned Bits = RHS.bitWidth();
229 T Result;
230 if (!T::bitOr(LHS, RHS, Bits, &Result)) {
231 S.Stk.push<T>(Result);
232 return true;
233 }
234 return false;
235 }
236
237 /// 1) Pops the RHS from the stack.
238 /// 2) Pops the LHS from the stack.
239 /// 3) Pushes 'LHS ^ RHS' on the stack
240 template <PrimType Name, class T = typename PrimConv<Name>::T>
BitXor(InterpState & S,CodePtr OpPC)241 bool BitXor(InterpState &S, CodePtr OpPC) {
242 const T &RHS = S.Stk.pop<T>();
243 const T &LHS = S.Stk.pop<T>();
244
245 unsigned Bits = RHS.bitWidth();
246 T Result;
247 if (!T::bitXor(LHS, RHS, Bits, &Result)) {
248 S.Stk.push<T>(Result);
249 return true;
250 }
251 return false;
252 }
253
254 /// 1) Pops the RHS from the stack.
255 /// 2) Pops the LHS from the stack.
256 /// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
257 template <PrimType Name, class T = typename PrimConv<Name>::T>
Rem(InterpState & S,CodePtr OpPC)258 bool Rem(InterpState &S, CodePtr OpPC) {
259 const T &RHS = S.Stk.pop<T>();
260 const T &LHS = S.Stk.pop<T>();
261
262 if (!CheckDivRem(S, OpPC, LHS, RHS))
263 return false;
264
265 const unsigned Bits = RHS.bitWidth() * 2;
266 T Result;
267 if (!T::rem(LHS, RHS, Bits, &Result)) {
268 S.Stk.push<T>(Result);
269 return true;
270 }
271 return false;
272 }
273
274 /// 1) Pops the RHS from the stack.
275 /// 2) Pops the LHS from the stack.
276 /// 3) Pushes 'LHS / RHS' on the stack
277 template <PrimType Name, class T = typename PrimConv<Name>::T>
Div(InterpState & S,CodePtr OpPC)278 bool Div(InterpState &S, CodePtr OpPC) {
279 const T &RHS = S.Stk.pop<T>();
280 const T &LHS = S.Stk.pop<T>();
281
282 if (!CheckDivRem(S, OpPC, LHS, RHS))
283 return false;
284
285 const unsigned Bits = RHS.bitWidth() * 2;
286 T Result;
287 if (!T::div(LHS, RHS, Bits, &Result)) {
288 S.Stk.push<T>(Result);
289 return true;
290 }
291 return false;
292 }
293
294 //===----------------------------------------------------------------------===//
295 // Inv
296 //===----------------------------------------------------------------------===//
297
298 template <PrimType Name, class T = typename PrimConv<Name>::T>
Inv(InterpState & S,CodePtr OpPC)299 bool Inv(InterpState &S, CodePtr OpPC) {
300 using BoolT = PrimConv<PT_Bool>::T;
301 const T &Val = S.Stk.pop<T>();
302 const unsigned Bits = Val.bitWidth();
303 Boolean R;
304 Boolean::inv(BoolT::from(Val, Bits), &R);
305
306 S.Stk.push<BoolT>(R);
307 return true;
308 }
309
310 //===----------------------------------------------------------------------===//
311 // Neg
312 //===----------------------------------------------------------------------===//
313
314 template <PrimType Name, class T = typename PrimConv<Name>::T>
Neg(InterpState & S,CodePtr OpPC)315 bool Neg(InterpState &S, CodePtr OpPC) {
316 const T &Val = S.Stk.pop<T>();
317 T Result;
318 T::neg(Val, &Result);
319
320 S.Stk.push<T>(Result);
321 return true;
322 }
323
324 enum class PushVal : bool {
325 No,
326 Yes,
327 };
328 enum class IncDecOp {
329 Inc,
330 Dec,
331 };
332
333 template <typename T, IncDecOp Op, PushVal DoPush>
IncDecHelper(InterpState & S,CodePtr OpPC,const Pointer & Ptr)334 bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
335 T Value = Ptr.deref<T>();
336 T Result;
337
338 if constexpr (DoPush == PushVal::Yes)
339 S.Stk.push<T>(Result);
340
341 if constexpr (Op == IncDecOp::Inc) {
342 if (!T::increment(Value, &Result)) {
343 Ptr.deref<T>() = Result;
344 return true;
345 }
346 } else {
347 if (!T::decrement(Value, &Result)) {
348 Ptr.deref<T>() = Result;
349 return true;
350 }
351 }
352
353 // Something went wrong with the previous operation. Compute the
354 // result with another bit of precision.
355 unsigned Bits = Value.bitWidth() + 1;
356 APSInt APResult;
357 if constexpr (Op == IncDecOp::Inc)
358 APResult = ++Value.toAPSInt(Bits);
359 else
360 APResult = --Value.toAPSInt(Bits);
361
362 // Report undefined behaviour, stopping if required.
363 const Expr *E = S.Current->getExpr(OpPC);
364 QualType Type = E->getType();
365 if (S.checkingForUndefinedBehavior()) {
366 SmallString<32> Trunc;
367 APResult.trunc(Result.bitWidth()).toString(Trunc, 10);
368 auto Loc = E->getExprLoc();
369 S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
370 return true;
371 }
372
373 S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
374 return S.noteUndefinedBehavior();
375 }
376
377 /// 1) Pops a pointer from the stack
378 /// 2) Load the value from the pointer
379 /// 3) Writes the value increased by one back to the pointer
380 /// 4) Pushes the original (pre-inc) value on the stack.
381 template <PrimType Name, class T = typename PrimConv<Name>::T>
Inc(InterpState & S,CodePtr OpPC)382 bool Inc(InterpState &S, CodePtr OpPC) {
383 // FIXME: Check initialization of Ptr
384 const Pointer &Ptr = S.Stk.pop<Pointer>();
385
386 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
387 }
388
389 /// 1) Pops a pointer from the stack
390 /// 2) Load the value from the pointer
391 /// 3) Writes the value increased by one back to the pointer
392 template <PrimType Name, class T = typename PrimConv<Name>::T>
IncPop(InterpState & S,CodePtr OpPC)393 bool IncPop(InterpState &S, CodePtr OpPC) {
394 // FIXME: Check initialization of Ptr
395 const Pointer &Ptr = S.Stk.pop<Pointer>();
396
397 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
398 }
399
400 /// 1) Pops a pointer from the stack
401 /// 2) Load the value from the pointer
402 /// 3) Writes the value decreased by one back to the pointer
403 /// 4) Pushes the original (pre-dec) value on the stack.
404 template <PrimType Name, class T = typename PrimConv<Name>::T>
Dec(InterpState & S,CodePtr OpPC)405 bool Dec(InterpState &S, CodePtr OpPC) {
406 // FIXME: Check initialization of Ptr
407 const Pointer &Ptr = S.Stk.pop<Pointer>();
408
409 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
410 }
411
412 /// 1) Pops a pointer from the stack
413 /// 2) Load the value from the pointer
414 /// 3) Writes the value decreased by one back to the pointer
415 template <PrimType Name, class T = typename PrimConv<Name>::T>
DecPop(InterpState & S,CodePtr OpPC)416 bool DecPop(InterpState &S, CodePtr OpPC) {
417 // FIXME: Check initialization of Ptr
418 const Pointer &Ptr = S.Stk.pop<Pointer>();
419
420 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
421 }
422
423 /// 1) Pops the value from the stack.
424 /// 2) Pushes the bitwise complemented value on the stack (~V).
425 template <PrimType Name, class T = typename PrimConv<Name>::T>
Comp(InterpState & S,CodePtr OpPC)426 bool Comp(InterpState &S, CodePtr OpPC) {
427 const T &Val = S.Stk.pop<T>();
428 T Result;
429 if (!T::comp(Val, &Result)) {
430 S.Stk.push<T>(Result);
431 return true;
432 }
433
434 return false;
435 }
436
437 //===----------------------------------------------------------------------===//
438 // EQ, NE, GT, GE, LT, LE
439 //===----------------------------------------------------------------------===//
440
441 using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
442
443 template <typename T>
CmpHelper(InterpState & S,CodePtr OpPC,CompareFn Fn)444 bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
445 using BoolT = PrimConv<PT_Bool>::T;
446 const T &RHS = S.Stk.pop<T>();
447 const T &LHS = S.Stk.pop<T>();
448 S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
449 return true;
450 }
451
452 template <typename T>
CmpHelperEQ(InterpState & S,CodePtr OpPC,CompareFn Fn)453 bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
454 return CmpHelper<T>(S, OpPC, Fn);
455 }
456
457 template <>
458 inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
459 using BoolT = PrimConv<PT_Bool>::T;
460 const Pointer &RHS = S.Stk.pop<Pointer>();
461 const Pointer &LHS = S.Stk.pop<Pointer>();
462
463 if (!Pointer::hasSameBase(LHS, RHS)) {
464 const SourceInfo &Loc = S.Current->getSource(OpPC);
465 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
466 return false;
467 } else {
468 unsigned VL = LHS.getByteOffset();
469 unsigned VR = RHS.getByteOffset();
470 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
471 return true;
472 }
473 }
474
475 template <>
476 inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
477 using BoolT = PrimConv<PT_Bool>::T;
478 const Pointer &RHS = S.Stk.pop<Pointer>();
479 const Pointer &LHS = S.Stk.pop<Pointer>();
480
481 if (LHS.isZero() && RHS.isZero()) {
482 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
483 return true;
484 }
485
486 if (!Pointer::hasSameBase(LHS, RHS)) {
487 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
488 return true;
489 } else {
490 unsigned VL = LHS.getByteOffset();
491 unsigned VR = RHS.getByteOffset();
492
493 // In our Pointer class, a pointer to an array and a pointer to the first
494 // element in the same array are NOT equal. They have the same Base value,
495 // but a different Offset. This is a pretty rare case, so we fix this here
496 // by comparing pointers to the first elements.
497 if (LHS.inArray() && LHS.isRoot())
498 VL = LHS.atIndex(0).getByteOffset();
499 if (RHS.inArray() && RHS.isRoot())
500 VR = RHS.atIndex(0).getByteOffset();
501
502 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
503 return true;
504 }
505 }
506
507 template <PrimType Name, class T = typename PrimConv<Name>::T>
EQ(InterpState & S,CodePtr OpPC)508 bool EQ(InterpState &S, CodePtr OpPC) {
509 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
510 return R == ComparisonCategoryResult::Equal;
511 });
512 }
513
514 template <PrimType Name, class T = typename PrimConv<Name>::T>
NE(InterpState & S,CodePtr OpPC)515 bool NE(InterpState &S, CodePtr OpPC) {
516 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
517 return R != ComparisonCategoryResult::Equal;
518 });
519 }
520
521 template <PrimType Name, class T = typename PrimConv<Name>::T>
LT(InterpState & S,CodePtr OpPC)522 bool LT(InterpState &S, CodePtr OpPC) {
523 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
524 return R == ComparisonCategoryResult::Less;
525 });
526 }
527
528 template <PrimType Name, class T = typename PrimConv<Name>::T>
LE(InterpState & S,CodePtr OpPC)529 bool LE(InterpState &S, CodePtr OpPC) {
530 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
531 return R == ComparisonCategoryResult::Less ||
532 R == ComparisonCategoryResult::Equal;
533 });
534 }
535
536 template <PrimType Name, class T = typename PrimConv<Name>::T>
GT(InterpState & S,CodePtr OpPC)537 bool GT(InterpState &S, CodePtr OpPC) {
538 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
539 return R == ComparisonCategoryResult::Greater;
540 });
541 }
542
543 template <PrimType Name, class T = typename PrimConv<Name>::T>
GE(InterpState & S,CodePtr OpPC)544 bool GE(InterpState &S, CodePtr OpPC) {
545 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
546 return R == ComparisonCategoryResult::Greater ||
547 R == ComparisonCategoryResult::Equal;
548 });
549 }
550
551 //===----------------------------------------------------------------------===//
552 // InRange
553 //===----------------------------------------------------------------------===//
554
555 template <PrimType Name, class T = typename PrimConv<Name>::T>
InRange(InterpState & S,CodePtr OpPC)556 bool InRange(InterpState &S, CodePtr OpPC) {
557 const T RHS = S.Stk.pop<T>();
558 const T LHS = S.Stk.pop<T>();
559 const T Value = S.Stk.pop<T>();
560
561 S.Stk.push<bool>(LHS <= Value && Value <= RHS);
562 return true;
563 }
564
565 //===----------------------------------------------------------------------===//
566 // Dup, Pop, Test
567 //===----------------------------------------------------------------------===//
568
569 template <PrimType Name, class T = typename PrimConv<Name>::T>
Dup(InterpState & S,CodePtr OpPC)570 bool Dup(InterpState &S, CodePtr OpPC) {
571 S.Stk.push<T>(S.Stk.peek<T>());
572 return true;
573 }
574
575 template <PrimType Name, class T = typename PrimConv<Name>::T>
Pop(InterpState & S,CodePtr OpPC)576 bool Pop(InterpState &S, CodePtr OpPC) {
577 S.Stk.pop<T>();
578 return true;
579 }
580
581 //===----------------------------------------------------------------------===//
582 // Const
583 //===----------------------------------------------------------------------===//
584
585 template <PrimType Name, class T = typename PrimConv<Name>::T>
Const(InterpState & S,CodePtr OpPC,const T & Arg)586 bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
587 S.Stk.push<T>(Arg);
588 return true;
589 }
590
591 //===----------------------------------------------------------------------===//
592 // Get/Set Local/Param/Global/This
593 //===----------------------------------------------------------------------===//
594
595 template <PrimType Name, class T = typename PrimConv<Name>::T>
GetLocal(InterpState & S,CodePtr OpPC,uint32_t I)596 bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
597 const Pointer &Ptr = S.Current->getLocalPointer(I);
598 if (!CheckLoad(S, OpPC, Ptr))
599 return false;
600 S.Stk.push<T>(Ptr.deref<T>());
601 return true;
602 }
603
604 template <PrimType Name, class T = typename PrimConv<Name>::T>
SetLocal(InterpState & S,CodePtr OpPC,uint32_t I)605 bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
606 S.Current->setLocal<T>(I, S.Stk.pop<T>());
607 return true;
608 }
609
610 template <PrimType Name, class T = typename PrimConv<Name>::T>
GetParam(InterpState & S,CodePtr OpPC,uint32_t I)611 bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
612 if (S.checkingPotentialConstantExpression()) {
613 return false;
614 }
615 S.Stk.push<T>(S.Current->getParam<T>(I));
616 return true;
617 }
618
619 template <PrimType Name, class T = typename PrimConv<Name>::T>
SetParam(InterpState & S,CodePtr OpPC,uint32_t I)620 bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
621 S.Current->setParam<T>(I, S.Stk.pop<T>());
622 return true;
623 }
624
625 /// 1) Peeks a pointer on the stack
626 /// 2) Pushes the value of the pointer's field on the stack
627 template <PrimType Name, class T = typename PrimConv<Name>::T>
GetField(InterpState & S,CodePtr OpPC,uint32_t I)628 bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
629 const Pointer &Obj = S.Stk.peek<Pointer>();
630 if (!CheckNull(S, OpPC, Obj, CSK_Field))
631 return false;
632 if (!CheckRange(S, OpPC, Obj, CSK_Field))
633 return false;
634 const Pointer &Field = Obj.atField(I);
635 if (!CheckLoad(S, OpPC, Field))
636 return false;
637 S.Stk.push<T>(Field.deref<T>());
638 return true;
639 }
640
641 template <PrimType Name, class T = typename PrimConv<Name>::T>
SetField(InterpState & S,CodePtr OpPC,uint32_t I)642 bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
643 const T &Value = S.Stk.pop<T>();
644 const Pointer &Obj = S.Stk.peek<Pointer>();
645 if (!CheckNull(S, OpPC, Obj, CSK_Field))
646 return false;
647 if (!CheckRange(S, OpPC, Obj, CSK_Field))
648 return false;
649 const Pointer &Field = Obj.atField(I);
650 if (!CheckStore(S, OpPC, Field))
651 return false;
652 Field.deref<T>() = Value;
653 return true;
654 }
655
656 /// 1) Pops a pointer from the stack
657 /// 2) Pushes the value of the pointer's field on the stack
658 template <PrimType Name, class T = typename PrimConv<Name>::T>
GetFieldPop(InterpState & S,CodePtr OpPC,uint32_t I)659 bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
660 const Pointer &Obj = S.Stk.pop<Pointer>();
661 if (!CheckNull(S, OpPC, Obj, CSK_Field))
662 return false;
663 if (!CheckRange(S, OpPC, Obj, CSK_Field))
664 return false;
665 const Pointer &Field = Obj.atField(I);
666 if (!CheckLoad(S, OpPC, Field))
667 return false;
668 S.Stk.push<T>(Field.deref<T>());
669 return true;
670 }
671
672 template <PrimType Name, class T = typename PrimConv<Name>::T>
GetThisField(InterpState & S,CodePtr OpPC,uint32_t I)673 bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
674 if (S.checkingPotentialConstantExpression())
675 return false;
676 const Pointer &This = S.Current->getThis();
677 if (!CheckThis(S, OpPC, This))
678 return false;
679 const Pointer &Field = This.atField(I);
680 if (!CheckLoad(S, OpPC, Field))
681 return false;
682 S.Stk.push<T>(Field.deref<T>());
683 return true;
684 }
685
686 template <PrimType Name, class T = typename PrimConv<Name>::T>
SetThisField(InterpState & S,CodePtr OpPC,uint32_t I)687 bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
688 if (S.checkingPotentialConstantExpression())
689 return false;
690 const T &Value = S.Stk.pop<T>();
691 const Pointer &This = S.Current->getThis();
692 if (!CheckThis(S, OpPC, This))
693 return false;
694 const Pointer &Field = This.atField(I);
695 if (!CheckStore(S, OpPC, Field))
696 return false;
697 Field.deref<T>() = Value;
698 return true;
699 }
700
701 template <PrimType Name, class T = typename PrimConv<Name>::T>
GetGlobal(InterpState & S,CodePtr OpPC,uint32_t I)702 bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
703 auto *B = S.P.getGlobal(I);
704 if (B->isExtern())
705 return false;
706 S.Stk.push<T>(B->deref<T>());
707 return true;
708 }
709
710 template <PrimType Name, class T = typename PrimConv<Name>::T>
SetGlobal(InterpState & S,CodePtr OpPC,uint32_t I)711 bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
712 // TODO: emit warning.
713 return false;
714 }
715
716 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitGlobal(InterpState & S,CodePtr OpPC,uint32_t I)717 bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
718 S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
719 return true;
720 }
721
722 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisField(InterpState & S,CodePtr OpPC,uint32_t I)723 bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
724 if (S.checkingPotentialConstantExpression())
725 return false;
726 const Pointer &This = S.Current->getThis();
727 if (!CheckThis(S, OpPC, This))
728 return false;
729 const Pointer &Field = This.atField(I);
730 Field.deref<T>() = S.Stk.pop<T>();
731 Field.initialize();
732 return true;
733 }
734
735 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisBitField(InterpState & S,CodePtr OpPC,const Record::Field * F)736 bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
737 if (S.checkingPotentialConstantExpression())
738 return false;
739 const Pointer &This = S.Current->getThis();
740 if (!CheckThis(S, OpPC, This))
741 return false;
742 const Pointer &Field = This.atField(F->Offset);
743 const auto &Value = S.Stk.pop<T>();
744 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
745 Field.initialize();
746 return true;
747 }
748
749 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisFieldActive(InterpState & S,CodePtr OpPC,uint32_t I)750 bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
751 if (S.checkingPotentialConstantExpression())
752 return false;
753 const Pointer &This = S.Current->getThis();
754 if (!CheckThis(S, OpPC, This))
755 return false;
756 const Pointer &Field = This.atField(I);
757 Field.deref<T>() = S.Stk.pop<T>();
758 Field.activate();
759 Field.initialize();
760 return true;
761 }
762
763 /// 1) Pops the value from the stack
764 /// 2) Peeks a pointer from the stack
765 /// 3) Pushes the value to field I of the pointer on the stack
766 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitField(InterpState & S,CodePtr OpPC,uint32_t I)767 bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
768 const T &Value = S.Stk.pop<T>();
769 const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
770 Field.deref<T>() = Value;
771 Field.activate();
772 Field.initialize();
773 return true;
774 }
775
776 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitBitField(InterpState & S,CodePtr OpPC,const Record::Field * F)777 bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
778 const T &Value = S.Stk.pop<T>();
779 const Pointer &Field = S.Stk.pop<Pointer>().atField(F->Offset);
780 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
781 Field.activate();
782 Field.initialize();
783 return true;
784 }
785
786 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitFieldActive(InterpState & S,CodePtr OpPC,uint32_t I)787 bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
788 const T &Value = S.Stk.pop<T>();
789 const Pointer &Ptr = S.Stk.pop<Pointer>();
790 const Pointer &Field = Ptr.atField(I);
791 Field.deref<T>() = Value;
792 Field.activate();
793 Field.initialize();
794 return true;
795 }
796
797 //===----------------------------------------------------------------------===//
798 // GetPtr Local/Param/Global/Field/This
799 //===----------------------------------------------------------------------===//
800
GetPtrLocal(InterpState & S,CodePtr OpPC,uint32_t I)801 inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
802 S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
803 return true;
804 }
805
GetPtrParam(InterpState & S,CodePtr OpPC,uint32_t I)806 inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
807 if (S.checkingPotentialConstantExpression()) {
808 return false;
809 }
810 S.Stk.push<Pointer>(S.Current->getParamPointer(I));
811 return true;
812 }
813
GetPtrGlobal(InterpState & S,CodePtr OpPC,uint32_t I)814 inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
815 S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
816 return true;
817 }
818
819 /// 1) Pops a Pointer from the stack
820 /// 2) Pushes Pointer.atField(Off) on the stack
GetPtrField(InterpState & S,CodePtr OpPC,uint32_t Off)821 inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
822 const Pointer &Ptr = S.Stk.pop<Pointer>();
823 if (!CheckNull(S, OpPC, Ptr, CSK_Field))
824 return false;
825 if (!CheckExtern(S, OpPC, Ptr))
826 return false;
827 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
828 return false;
829 S.Stk.push<Pointer>(Ptr.atField(Off));
830 return true;
831 }
832
GetPtrThisField(InterpState & S,CodePtr OpPC,uint32_t Off)833 inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
834 if (S.checkingPotentialConstantExpression())
835 return false;
836 const Pointer &This = S.Current->getThis();
837 if (!CheckThis(S, OpPC, This))
838 return false;
839 S.Stk.push<Pointer>(This.atField(Off));
840 return true;
841 }
842
GetPtrActiveField(InterpState & S,CodePtr OpPC,uint32_t Off)843 inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
844 const Pointer &Ptr = S.Stk.pop<Pointer>();
845 if (!CheckNull(S, OpPC, Ptr, CSK_Field))
846 return false;
847 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
848 return false;
849 Pointer Field = Ptr.atField(Off);
850 Ptr.deactivate();
851 Field.activate();
852 S.Stk.push<Pointer>(std::move(Field));
853 return true;
854 }
855
GetPtrActiveThisField(InterpState & S,CodePtr OpPC,uint32_t Off)856 inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
857 if (S.checkingPotentialConstantExpression())
858 return false;
859 const Pointer &This = S.Current->getThis();
860 if (!CheckThis(S, OpPC, This))
861 return false;
862 Pointer Field = This.atField(Off);
863 This.deactivate();
864 Field.activate();
865 S.Stk.push<Pointer>(std::move(Field));
866 return true;
867 }
868
GetPtrBase(InterpState & S,CodePtr OpPC,uint32_t Off)869 inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
870 const Pointer &Ptr = S.Stk.pop<Pointer>();
871 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
872 return false;
873 S.Stk.push<Pointer>(Ptr.atField(Off));
874 return true;
875 }
876
GetPtrThisBase(InterpState & S,CodePtr OpPC,uint32_t Off)877 inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
878 if (S.checkingPotentialConstantExpression())
879 return false;
880 const Pointer &This = S.Current->getThis();
881 if (!CheckThis(S, OpPC, This))
882 return false;
883 S.Stk.push<Pointer>(This.atField(Off));
884 return true;
885 }
886
VirtBaseHelper(InterpState & S,CodePtr OpPC,const RecordDecl * Decl,const Pointer & Ptr)887 inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
888 const Pointer &Ptr) {
889 Pointer Base = Ptr;
890 while (Base.isBaseClass())
891 Base = Base.getBase();
892
893 auto *Field = Base.getRecord()->getVirtualBase(Decl);
894 S.Stk.push<Pointer>(Base.atField(Field->Offset));
895 return true;
896 }
897
GetPtrVirtBase(InterpState & S,CodePtr OpPC,const RecordDecl * D)898 inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
899 const Pointer &Ptr = S.Stk.pop<Pointer>();
900 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
901 return false;
902 return VirtBaseHelper(S, OpPC, D, Ptr);
903 }
904
GetPtrThisVirtBase(InterpState & S,CodePtr OpPC,const RecordDecl * D)905 inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
906 const RecordDecl *D) {
907 if (S.checkingPotentialConstantExpression())
908 return false;
909 const Pointer &This = S.Current->getThis();
910 if (!CheckThis(S, OpPC, This))
911 return false;
912 return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
913 }
914
915 //===----------------------------------------------------------------------===//
916 // Load, Store, Init
917 //===----------------------------------------------------------------------===//
918
919 template <PrimType Name, class T = typename PrimConv<Name>::T>
Load(InterpState & S,CodePtr OpPC)920 bool Load(InterpState &S, CodePtr OpPC) {
921 const Pointer &Ptr = S.Stk.peek<Pointer>();
922 if (!CheckLoad(S, OpPC, Ptr))
923 return false;
924 S.Stk.push<T>(Ptr.deref<T>());
925 return true;
926 }
927
928 template <PrimType Name, class T = typename PrimConv<Name>::T>
LoadPop(InterpState & S,CodePtr OpPC)929 bool LoadPop(InterpState &S, CodePtr OpPC) {
930 const Pointer &Ptr = S.Stk.pop<Pointer>();
931 if (!CheckLoad(S, OpPC, Ptr))
932 return false;
933 S.Stk.push<T>(Ptr.deref<T>());
934 return true;
935 }
936
937 template <PrimType Name, class T = typename PrimConv<Name>::T>
Store(InterpState & S,CodePtr OpPC)938 bool Store(InterpState &S, CodePtr OpPC) {
939 const T &Value = S.Stk.pop<T>();
940 const Pointer &Ptr = S.Stk.peek<Pointer>();
941 if (!CheckStore(S, OpPC, Ptr))
942 return false;
943 if (!Ptr.isRoot())
944 Ptr.initialize();
945 Ptr.deref<T>() = Value;
946 return true;
947 }
948
949 template <PrimType Name, class T = typename PrimConv<Name>::T>
StorePop(InterpState & S,CodePtr OpPC)950 bool StorePop(InterpState &S, CodePtr OpPC) {
951 const T &Value = S.Stk.pop<T>();
952 const Pointer &Ptr = S.Stk.pop<Pointer>();
953 if (!CheckStore(S, OpPC, Ptr))
954 return false;
955 if (!Ptr.isRoot())
956 Ptr.initialize();
957 Ptr.deref<T>() = Value;
958 return true;
959 }
960
961 template <PrimType Name, class T = typename PrimConv<Name>::T>
StoreBitField(InterpState & S,CodePtr OpPC)962 bool StoreBitField(InterpState &S, CodePtr OpPC) {
963 const T &Value = S.Stk.pop<T>();
964 const Pointer &Ptr = S.Stk.peek<Pointer>();
965 if (!CheckStore(S, OpPC, Ptr))
966 return false;
967 if (!Ptr.isRoot())
968 Ptr.initialize();
969 if (auto *FD = Ptr.getField()) {
970 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
971 } else {
972 Ptr.deref<T>() = Value;
973 }
974 return true;
975 }
976
977 template <PrimType Name, class T = typename PrimConv<Name>::T>
StoreBitFieldPop(InterpState & S,CodePtr OpPC)978 bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
979 const T &Value = S.Stk.pop<T>();
980 const Pointer &Ptr = S.Stk.pop<Pointer>();
981 if (!CheckStore(S, OpPC, Ptr))
982 return false;
983 if (!Ptr.isRoot())
984 Ptr.initialize();
985 if (auto *FD = Ptr.getField()) {
986 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
987 } else {
988 Ptr.deref<T>() = Value;
989 }
990 return true;
991 }
992
993 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitPop(InterpState & S,CodePtr OpPC)994 bool InitPop(InterpState &S, CodePtr OpPC) {
995 const T &Value = S.Stk.pop<T>();
996 const Pointer &Ptr = S.Stk.pop<Pointer>();
997 if (!CheckInit(S, OpPC, Ptr))
998 return false;
999 Ptr.initialize();
1000 new (&Ptr.deref<T>()) T(Value);
1001 return true;
1002 }
1003
1004 /// 1) Pops the value from the stack
1005 /// 2) Peeks a pointer and gets its index \Idx
1006 /// 3) Sets the value on the pointer, leaving the pointer on the stack.
1007 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitElem(InterpState & S,CodePtr OpPC,uint32_t Idx)1008 bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1009 const T &Value = S.Stk.pop<T>();
1010 const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
1011 if (!CheckInit(S, OpPC, Ptr))
1012 return false;
1013 Ptr.initialize();
1014 new (&Ptr.deref<T>()) T(Value);
1015 return true;
1016 }
1017
1018 /// The same as InitElem, but pops the pointer as well.
1019 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitElemPop(InterpState & S,CodePtr OpPC,uint32_t Idx)1020 bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1021 const T &Value = S.Stk.pop<T>();
1022 const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
1023 if (!CheckInit(S, OpPC, Ptr))
1024 return false;
1025 Ptr.initialize();
1026 new (&Ptr.deref<T>()) T(Value);
1027 return true;
1028 }
1029
1030 //===----------------------------------------------------------------------===//
1031 // AddOffset, SubOffset
1032 //===----------------------------------------------------------------------===//
1033
OffsetHelper(InterpState & S,CodePtr OpPC)1034 template <class T, bool Add> bool OffsetHelper(InterpState &S, CodePtr OpPC) {
1035 // Fetch the pointer and the offset.
1036 const T &Offset = S.Stk.pop<T>();
1037 const Pointer &Ptr = S.Stk.pop<Pointer>();
1038
1039 if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
1040 return false;
1041
1042 // A zero offset does not change the pointer.
1043 if (Offset.isZero()) {
1044 S.Stk.push<Pointer>(Ptr);
1045 return true;
1046 }
1047
1048 if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
1049 return false;
1050
1051 // Arrays of unknown bounds cannot have pointers into them.
1052 if (!CheckArray(S, OpPC, Ptr))
1053 return false;
1054
1055 // Get a version of the index comparable to the type.
1056 T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
1057 // Compute the largest index into the array.
1058 unsigned MaxIndex = Ptr.getNumElems();
1059
1060 // Helper to report an invalid offset, computed as APSInt.
1061 auto InvalidOffset = [&]() {
1062 const unsigned Bits = Offset.bitWidth();
1063 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
1064 APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
1065 APSInt NewIndex = Add ? (APIndex + APOffset) : (APIndex - APOffset);
1066 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1067 << NewIndex
1068 << /*array*/ static_cast<int>(!Ptr.inArray())
1069 << static_cast<unsigned>(MaxIndex);
1070 return false;
1071 };
1072
1073 unsigned MaxOffset = MaxIndex - Ptr.getIndex();
1074 if constexpr (Add) {
1075 // If the new offset would be negative, bail out.
1076 if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
1077 return InvalidOffset();
1078
1079 // If the new offset would be out of bounds, bail out.
1080 if (Offset.isPositive() && Offset > MaxOffset)
1081 return InvalidOffset();
1082 } else {
1083 // If the new offset would be negative, bail out.
1084 if (Offset.isPositive() && Index < Offset)
1085 return InvalidOffset();
1086
1087 // If the new offset would be out of bounds, bail out.
1088 if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
1089 return InvalidOffset();
1090 }
1091
1092 // Offset is valid - compute it on unsigned.
1093 int64_t WideIndex = static_cast<int64_t>(Index);
1094 int64_t WideOffset = static_cast<int64_t>(Offset);
1095 int64_t Result;
1096 if constexpr (Add)
1097 Result = WideIndex + WideOffset;
1098 else
1099 Result = WideIndex - WideOffset;
1100
1101 S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
1102 return true;
1103 }
1104
1105 template <PrimType Name, class T = typename PrimConv<Name>::T>
AddOffset(InterpState & S,CodePtr OpPC)1106 bool AddOffset(InterpState &S, CodePtr OpPC) {
1107 return OffsetHelper<T, true>(S, OpPC);
1108 }
1109
1110 template <PrimType Name, class T = typename PrimConv<Name>::T>
SubOffset(InterpState & S,CodePtr OpPC)1111 bool SubOffset(InterpState &S, CodePtr OpPC) {
1112 return OffsetHelper<T, false>(S, OpPC);
1113 }
1114
1115 /// 1) Pops a Pointer from the stack.
1116 /// 2) Pops another Pointer from the stack.
1117 /// 3) Pushes the different of the indices of the two pointers on the stack.
1118 template <PrimType Name, class T = typename PrimConv<Name>::T>
SubPtr(InterpState & S,CodePtr OpPC)1119 inline bool SubPtr(InterpState &S, CodePtr OpPC) {
1120 const Pointer &LHS = S.Stk.pop<Pointer>();
1121 const Pointer &RHS = S.Stk.pop<Pointer>();
1122
1123 if (!Pointer::hasSameArray(LHS, RHS)) {
1124 // TODO: Diagnose.
1125 return false;
1126 }
1127
1128 T A = T::from(LHS.getIndex());
1129 T B = T::from(RHS.getIndex());
1130 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
1131 }
1132
1133 //===----------------------------------------------------------------------===//
1134 // Destroy
1135 //===----------------------------------------------------------------------===//
1136
Destroy(InterpState & S,CodePtr OpPC,uint32_t I)1137 inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
1138 S.Current->destroy(I);
1139 return true;
1140 }
1141
1142 //===----------------------------------------------------------------------===//
1143 // Cast, CastFP
1144 //===----------------------------------------------------------------------===//
1145
Cast(InterpState & S,CodePtr OpPC)1146 template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
1147 using T = typename PrimConv<TIn>::T;
1148 using U = typename PrimConv<TOut>::T;
1149 S.Stk.push<U>(U::from(S.Stk.pop<T>()));
1150 return true;
1151 }
1152
1153 //===----------------------------------------------------------------------===//
1154 // Zero, Nullptr
1155 //===----------------------------------------------------------------------===//
1156
1157 template <PrimType Name, class T = typename PrimConv<Name>::T>
Zero(InterpState & S,CodePtr OpPC)1158 bool Zero(InterpState &S, CodePtr OpPC) {
1159 S.Stk.push<T>(T::zero());
1160 return true;
1161 }
1162
1163 template <PrimType Name, class T = typename PrimConv<Name>::T>
Null(InterpState & S,CodePtr OpPC)1164 inline bool Null(InterpState &S, CodePtr OpPC) {
1165 S.Stk.push<T>();
1166 return true;
1167 }
1168
1169 //===----------------------------------------------------------------------===//
1170 // This, ImplicitThis
1171 //===----------------------------------------------------------------------===//
1172
This(InterpState & S,CodePtr OpPC)1173 inline bool This(InterpState &S, CodePtr OpPC) {
1174 // Cannot read 'this' in this mode.
1175 if (S.checkingPotentialConstantExpression()) {
1176 return false;
1177 }
1178
1179 const Pointer &This = S.Current->getThis();
1180 if (!CheckThis(S, OpPC, This))
1181 return false;
1182
1183 S.Stk.push<Pointer>(This);
1184 return true;
1185 }
1186
RVOPtr(InterpState & S,CodePtr OpPC)1187 inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
1188 assert(S.Current->getFunction()->hasRVO());
1189 S.Stk.push<Pointer>(S.Current->getRVOPtr());
1190 return true;
1191 }
1192
1193 //===----------------------------------------------------------------------===//
1194 // Shr, Shl
1195 //===----------------------------------------------------------------------===//
1196
1197 template <PrimType NameL, PrimType NameR>
Shr(InterpState & S,CodePtr OpPC)1198 inline bool Shr(InterpState &S, CodePtr OpPC) {
1199 using LT = typename PrimConv<NameL>::T;
1200 using RT = typename PrimConv<NameR>::T;
1201 const auto &RHS = S.Stk.pop<RT>();
1202 const auto &LHS = S.Stk.pop<LT>();
1203 const unsigned Bits = LHS.bitWidth();
1204
1205 if (!CheckShift<RT>(S, OpPC, RHS, Bits))
1206 return false;
1207
1208 unsigned URHS = static_cast<unsigned>(RHS);
1209 S.Stk.push<LT>(LT::from(static_cast<unsigned>(LHS) >> URHS, LHS.bitWidth()));
1210 return true;
1211 }
1212
1213 template <PrimType NameL, PrimType NameR>
Shl(InterpState & S,CodePtr OpPC)1214 inline bool Shl(InterpState &S, CodePtr OpPC) {
1215 using LT = typename PrimConv<NameL>::T;
1216 using RT = typename PrimConv<NameR>::T;
1217 const auto &RHS = S.Stk.pop<RT>();
1218 const auto &LHS = S.Stk.pop<LT>();
1219 const unsigned Bits = LHS.bitWidth();
1220
1221 if (!CheckShift<RT>(S, OpPC, RHS, Bits))
1222 return false;
1223
1224 unsigned URHS = static_cast<unsigned>(RHS);
1225 S.Stk.push<LT>(LT::from(static_cast<unsigned>(LHS) << URHS, LHS.bitWidth()));
1226
1227 return true;
1228 }
1229
1230 //===----------------------------------------------------------------------===//
1231 // NoRet
1232 //===----------------------------------------------------------------------===//
1233
NoRet(InterpState & S,CodePtr OpPC)1234 inline bool NoRet(InterpState &S, CodePtr OpPC) {
1235 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
1236 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
1237 return false;
1238 }
1239
1240 //===----------------------------------------------------------------------===//
1241 // NarrowPtr, ExpandPtr
1242 //===----------------------------------------------------------------------===//
1243
NarrowPtr(InterpState & S,CodePtr OpPC)1244 inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
1245 const Pointer &Ptr = S.Stk.pop<Pointer>();
1246 S.Stk.push<Pointer>(Ptr.narrow());
1247 return true;
1248 }
1249
ExpandPtr(InterpState & S,CodePtr OpPC)1250 inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
1251 const Pointer &Ptr = S.Stk.pop<Pointer>();
1252 S.Stk.push<Pointer>(Ptr.expand());
1253 return true;
1254 }
1255
Call(InterpState & S,CodePtr & PC,const Function * Func)1256 inline bool Call(InterpState &S, CodePtr &PC, const Function *Func) {
1257 auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
1258 Pointer ThisPtr;
1259 if (Func->hasThisPointer()) {
1260 ThisPtr = NewFrame->getThis();
1261 if (!CheckInvoke(S, PC, ThisPtr)) {
1262 return false;
1263 }
1264 }
1265
1266 if (!CheckCallable(S, PC, Func))
1267 return false;
1268
1269 InterpFrame *FrameBefore = S.Current;
1270 S.Current = NewFrame.get();
1271
1272 APValue CallResult;
1273 // Note that we cannot assert(CallResult.hasValue()) here since
1274 // Ret() above only sets the APValue if the curent frame doesn't
1275 // have a caller set.
1276 if (Interpret(S, CallResult)) {
1277 NewFrame.release(); // Frame was delete'd already.
1278 assert(S.Current == FrameBefore);
1279
1280 // For constructors, check that all fields have been initialized.
1281 if (Func->isConstructor() && !CheckCtorCall(S, PC, ThisPtr))
1282 return false;
1283
1284 return true;
1285 }
1286
1287 // Interpreting the function failed somehow. Reset to
1288 // previous state.
1289 S.Current = FrameBefore;
1290 return false;
1291 }
1292
1293 //===----------------------------------------------------------------------===//
1294 // Read opcode arguments
1295 //===----------------------------------------------------------------------===//
1296
ReadArg(InterpState & S,CodePtr & OpPC)1297 template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
1298 if constexpr (std::is_pointer<T>::value) {
1299 uint32_t ID = OpPC.read<uint32_t>();
1300 return reinterpret_cast<T>(S.P.getNativePointer(ID));
1301 } else {
1302 return OpPC.read<T>();
1303 }
1304 }
1305
1306 } // namespace interp
1307 } // namespace clang
1308
1309 #endif
1310