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 "Function.h"
17 #include "InterpFrame.h"
18 #include "InterpStack.h"
19 #include "InterpState.h"
20 #include "Opcode.h"
21 #include "PrimType.h"
22 #include "Program.h"
23 #include "State.h"
24 #include "clang/AST/ASTContext.h"
25 #include "clang/AST/ASTDiagnostic.h"
26 #include "clang/AST/CXXInheritance.h"
27 #include "clang/AST/Expr.h"
28 #include "llvm/ADT/APFloat.h"
29 #include "llvm/ADT/APSInt.h"
30 #include "llvm/Support/Endian.h"
31 #include <limits>
32 #include <type_traits>
33 #include <vector>
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, 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
IsTrue(const T & V)95 template <typename T> inline bool IsTrue(const T &V) { return !V.isZero(); }
96
97 //===----------------------------------------------------------------------===//
98 // Add, Sub, Mul
99 //===----------------------------------------------------------------------===//
100
101 template <typename T, bool (*OpFW)(T, T, unsigned, T *),
102 template <typename U> class OpAP>
AddSubMulHelper(InterpState & S,CodePtr OpPC,unsigned Bits,const T & LHS,const T & RHS)103 bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
104 const T &RHS) {
105 // Fast path - add the numbers with fixed width.
106 T Result;
107 if (!OpFW(LHS, RHS, Bits, &Result)) {
108 S.Stk.push<T>(Result);
109 return true;
110 }
111
112 // If for some reason evaluation continues, use the truncated results.
113 S.Stk.push<T>(Result);
114
115 // Slow path - compute the result using another bit of precision.
116 APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
117
118 // Report undefined behaviour, stopping if required.
119 const Expr *E = S.Current->getExpr(OpPC);
120 QualType Type = E->getType();
121 if (S.checkingForUndefinedBehavior()) {
122 SmallString<32> Trunc;
123 Value.trunc(Result.bitWidth()).toString(Trunc, 10);
124 auto Loc = E->getExprLoc();
125 S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
126 return true;
127 } else {
128 S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
129 return S.noteUndefinedBehavior();
130 }
131 }
132
133 template <PrimType Name, class T = typename PrimConv<Name>::T>
Add(InterpState & S,CodePtr OpPC)134 bool Add(InterpState &S, CodePtr OpPC) {
135 const T &RHS = S.Stk.pop<T>();
136 const T &LHS = S.Stk.pop<T>();
137 const unsigned Bits = RHS.bitWidth() + 1;
138 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
139 }
140
141 template <PrimType Name, class T = typename PrimConv<Name>::T>
Sub(InterpState & S,CodePtr OpPC)142 bool Sub(InterpState &S, CodePtr OpPC) {
143 const T &RHS = S.Stk.pop<T>();
144 const T &LHS = S.Stk.pop<T>();
145 const unsigned Bits = RHS.bitWidth() + 1;
146 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
147 }
148
149 template <PrimType Name, class T = typename PrimConv<Name>::T>
Mul(InterpState & S,CodePtr OpPC)150 bool Mul(InterpState &S, CodePtr OpPC) {
151 const T &RHS = S.Stk.pop<T>();
152 const T &LHS = S.Stk.pop<T>();
153 const unsigned Bits = RHS.bitWidth() * 2;
154 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
155 }
156
157 //===----------------------------------------------------------------------===//
158 // EQ, NE, GT, GE, LT, LE
159 //===----------------------------------------------------------------------===//
160
161 using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
162
163 template <typename T>
CmpHelper(InterpState & S,CodePtr OpPC,CompareFn Fn)164 bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
165 using BoolT = PrimConv<PT_Bool>::T;
166 const T &RHS = S.Stk.pop<T>();
167 const T &LHS = S.Stk.pop<T>();
168 S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
169 return true;
170 }
171
172 template <typename T>
CmpHelperEQ(InterpState & S,CodePtr OpPC,CompareFn Fn)173 bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
174 return CmpHelper<T>(S, OpPC, Fn);
175 }
176
177 template <>
178 inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
179 using BoolT = PrimConv<PT_Bool>::T;
180 const Pointer &RHS = S.Stk.pop<Pointer>();
181 const Pointer &LHS = S.Stk.pop<Pointer>();
182
183 if (!Pointer::hasSameBase(LHS, RHS)) {
184 const SourceInfo &Loc = S.Current->getSource(OpPC);
185 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
186 return false;
187 } else {
188 unsigned VL = LHS.getByteOffset();
189 unsigned VR = RHS.getByteOffset();
190 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
191 return true;
192 }
193 }
194
195 template <>
196 inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
197 using BoolT = PrimConv<PT_Bool>::T;
198 const Pointer &RHS = S.Stk.pop<Pointer>();
199 const Pointer &LHS = S.Stk.pop<Pointer>();
200
201 if (LHS.isZero() && RHS.isZero()) {
202 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
203 return true;
204 }
205
206 if (!Pointer::hasSameBase(LHS, RHS)) {
207 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
208 return true;
209 } else {
210 unsigned VL = LHS.getByteOffset();
211 unsigned VR = RHS.getByteOffset();
212 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
213 return true;
214 }
215 }
216
217 template <PrimType Name, class T = typename PrimConv<Name>::T>
EQ(InterpState & S,CodePtr OpPC)218 bool EQ(InterpState &S, CodePtr OpPC) {
219 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
220 return R == ComparisonCategoryResult::Equal;
221 });
222 }
223
224 template <PrimType Name, class T = typename PrimConv<Name>::T>
NE(InterpState & S,CodePtr OpPC)225 bool NE(InterpState &S, CodePtr OpPC) {
226 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
227 return R != ComparisonCategoryResult::Equal;
228 });
229 }
230
231 template <PrimType Name, class T = typename PrimConv<Name>::T>
LT(InterpState & S,CodePtr OpPC)232 bool LT(InterpState &S, CodePtr OpPC) {
233 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
234 return R == ComparisonCategoryResult::Less;
235 });
236 }
237
238 template <PrimType Name, class T = typename PrimConv<Name>::T>
LE(InterpState & S,CodePtr OpPC)239 bool LE(InterpState &S, CodePtr OpPC) {
240 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
241 return R == ComparisonCategoryResult::Less ||
242 R == ComparisonCategoryResult::Equal;
243 });
244 }
245
246 template <PrimType Name, class T = typename PrimConv<Name>::T>
GT(InterpState & S,CodePtr OpPC)247 bool GT(InterpState &S, CodePtr OpPC) {
248 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
249 return R == ComparisonCategoryResult::Greater;
250 });
251 }
252
253 template <PrimType Name, class T = typename PrimConv<Name>::T>
GE(InterpState & S,CodePtr OpPC)254 bool GE(InterpState &S, CodePtr OpPC) {
255 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
256 return R == ComparisonCategoryResult::Greater ||
257 R == ComparisonCategoryResult::Equal;
258 });
259 }
260
261 //===----------------------------------------------------------------------===//
262 // InRange
263 //===----------------------------------------------------------------------===//
264
265 template <PrimType Name, class T = typename PrimConv<Name>::T>
InRange(InterpState & S,CodePtr OpPC)266 bool InRange(InterpState &S, CodePtr OpPC) {
267 const T RHS = S.Stk.pop<T>();
268 const T LHS = S.Stk.pop<T>();
269 const T Value = S.Stk.pop<T>();
270
271 S.Stk.push<bool>(LHS <= Value && Value <= RHS);
272 return true;
273 }
274
275 //===----------------------------------------------------------------------===//
276 // Dup, Pop, Test
277 //===----------------------------------------------------------------------===//
278
279 template <PrimType Name, class T = typename PrimConv<Name>::T>
Dup(InterpState & S,CodePtr OpPC)280 bool Dup(InterpState &S, CodePtr OpPC) {
281 S.Stk.push<T>(S.Stk.peek<T>());
282 return true;
283 }
284
285 template <PrimType Name, class T = typename PrimConv<Name>::T>
Pop(InterpState & S,CodePtr OpPC)286 bool Pop(InterpState &S, CodePtr OpPC) {
287 S.Stk.pop<T>();
288 return true;
289 }
290
291 //===----------------------------------------------------------------------===//
292 // Const
293 //===----------------------------------------------------------------------===//
294
295 template <PrimType Name, class T = typename PrimConv<Name>::T>
Const(InterpState & S,CodePtr OpPC,const T & Arg)296 bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
297 S.Stk.push<T>(Arg);
298 return true;
299 }
300
301 //===----------------------------------------------------------------------===//
302 // Get/Set Local/Param/Global/This
303 //===----------------------------------------------------------------------===//
304
305 template <PrimType Name, class T = typename PrimConv<Name>::T>
GetLocal(InterpState & S,CodePtr OpPC,uint32_t I)306 bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
307 S.Stk.push<T>(S.Current->getLocal<T>(I));
308 return true;
309 }
310
311 template <PrimType Name, class T = typename PrimConv<Name>::T>
SetLocal(InterpState & S,CodePtr OpPC,uint32_t I)312 bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
313 S.Current->setLocal<T>(I, S.Stk.pop<T>());
314 return true;
315 }
316
317 template <PrimType Name, class T = typename PrimConv<Name>::T>
GetParam(InterpState & S,CodePtr OpPC,uint32_t I)318 bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
319 if (S.checkingPotentialConstantExpression()) {
320 return false;
321 }
322 S.Stk.push<T>(S.Current->getParam<T>(I));
323 return true;
324 }
325
326 template <PrimType Name, class T = typename PrimConv<Name>::T>
SetParam(InterpState & S,CodePtr OpPC,uint32_t I)327 bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
328 S.Current->setParam<T>(I, S.Stk.pop<T>());
329 return true;
330 }
331
332 template <PrimType Name, class T = typename PrimConv<Name>::T>
GetField(InterpState & S,CodePtr OpPC,uint32_t I)333 bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
334 const Pointer &Obj = S.Stk.peek<Pointer>();
335 if (!CheckNull(S, OpPC, Obj, CSK_Field))
336 return false;
337 if (!CheckRange(S, OpPC, Obj, CSK_Field))
338 return false;
339 const Pointer &Field = Obj.atField(I);
340 if (!CheckLoad(S, OpPC, Field))
341 return false;
342 S.Stk.push<T>(Field.deref<T>());
343 return true;
344 }
345
346 template <PrimType Name, class T = typename PrimConv<Name>::T>
SetField(InterpState & S,CodePtr OpPC,uint32_t I)347 bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
348 const T &Value = S.Stk.pop<T>();
349 const Pointer &Obj = S.Stk.peek<Pointer>();
350 if (!CheckNull(S, OpPC, Obj, CSK_Field))
351 return false;
352 if (!CheckRange(S, OpPC, Obj, CSK_Field))
353 return false;
354 const Pointer &Field = Obj.atField(I);
355 if (!CheckStore(S, OpPC, Field))
356 return false;
357 Field.deref<T>() = Value;
358 return true;
359 }
360
361 template <PrimType Name, class T = typename PrimConv<Name>::T>
GetFieldPop(InterpState & S,CodePtr OpPC,uint32_t I)362 bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
363 const Pointer &Obj = S.Stk.pop<Pointer>();
364 if (!CheckNull(S, OpPC, Obj, CSK_Field))
365 return false;
366 if (!CheckRange(S, OpPC, Obj, CSK_Field))
367 return false;
368 const Pointer &Field = Obj.atField(I);
369 if (!CheckLoad(S, OpPC, Field))
370 return false;
371 S.Stk.push<T>(Field.deref<T>());
372 return true;
373 }
374
375 template <PrimType Name, class T = typename PrimConv<Name>::T>
GetThisField(InterpState & S,CodePtr OpPC,uint32_t I)376 bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
377 if (S.checkingPotentialConstantExpression())
378 return false;
379 const Pointer &This = S.Current->getThis();
380 if (!CheckThis(S, OpPC, This))
381 return false;
382 const Pointer &Field = This.atField(I);
383 if (!CheckLoad(S, OpPC, Field))
384 return false;
385 S.Stk.push<T>(Field.deref<T>());
386 return true;
387 }
388
389 template <PrimType Name, class T = typename PrimConv<Name>::T>
SetThisField(InterpState & S,CodePtr OpPC,uint32_t I)390 bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
391 if (S.checkingPotentialConstantExpression())
392 return false;
393 const T &Value = S.Stk.pop<T>();
394 const Pointer &This = S.Current->getThis();
395 if (!CheckThis(S, OpPC, This))
396 return false;
397 const Pointer &Field = This.atField(I);
398 if (!CheckStore(S, OpPC, Field))
399 return false;
400 Field.deref<T>() = Value;
401 return true;
402 }
403
404 template <PrimType Name, class T = typename PrimConv<Name>::T>
GetGlobal(InterpState & S,CodePtr OpPC,uint32_t I)405 bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
406 auto *B = S.P.getGlobal(I);
407 if (B->isExtern())
408 return false;
409 S.Stk.push<T>(B->deref<T>());
410 return true;
411 }
412
413 template <PrimType Name, class T = typename PrimConv<Name>::T>
SetGlobal(InterpState & S,CodePtr OpPC,uint32_t I)414 bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
415 // TODO: emit warning.
416 return false;
417 }
418
419 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitGlobal(InterpState & S,CodePtr OpPC,uint32_t I)420 bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
421 S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
422 return true;
423 }
424
425 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisField(InterpState & S,CodePtr OpPC,uint32_t I)426 bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
427 if (S.checkingPotentialConstantExpression())
428 return false;
429 const Pointer &This = S.Current->getThis();
430 if (!CheckThis(S, OpPC, This))
431 return false;
432 const Pointer &Field = This.atField(I);
433 Field.deref<T>() = S.Stk.pop<T>();
434 Field.initialize();
435 return true;
436 }
437
438 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisBitField(InterpState & S,CodePtr OpPC,const Record::Field * F)439 bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
440 if (S.checkingPotentialConstantExpression())
441 return false;
442 const Pointer &This = S.Current->getThis();
443 if (!CheckThis(S, OpPC, This))
444 return false;
445 const Pointer &Field = This.atField(F->Offset);
446 const auto &Value = S.Stk.pop<T>();
447 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
448 Field.initialize();
449 return true;
450 }
451
452 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisFieldActive(InterpState & S,CodePtr OpPC,uint32_t I)453 bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
454 if (S.checkingPotentialConstantExpression())
455 return false;
456 const Pointer &This = S.Current->getThis();
457 if (!CheckThis(S, OpPC, This))
458 return false;
459 const Pointer &Field = This.atField(I);
460 Field.deref<T>() = S.Stk.pop<T>();
461 Field.activate();
462 Field.initialize();
463 return true;
464 }
465
466 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitField(InterpState & S,CodePtr OpPC,uint32_t I)467 bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
468 const T &Value = S.Stk.pop<T>();
469 const Pointer &Field = S.Stk.pop<Pointer>().atField(I);
470 Field.deref<T>() = Value;
471 Field.activate();
472 Field.initialize();
473 return true;
474 }
475
476 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitBitField(InterpState & S,CodePtr OpPC,const Record::Field * F)477 bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
478 const T &Value = S.Stk.pop<T>();
479 const Pointer &Field = S.Stk.pop<Pointer>().atField(F->Offset);
480 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
481 Field.activate();
482 Field.initialize();
483 return true;
484 }
485
486 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitFieldActive(InterpState & S,CodePtr OpPC,uint32_t I)487 bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
488 const T &Value = S.Stk.pop<T>();
489 const Pointer &Ptr = S.Stk.pop<Pointer>();
490 const Pointer &Field = Ptr.atField(I);
491 Field.deref<T>() = Value;
492 Field.activate();
493 Field.initialize();
494 return true;
495 }
496
497 //===----------------------------------------------------------------------===//
498 // GetPtr Local/Param/Global/Field/This
499 //===----------------------------------------------------------------------===//
500
GetPtrLocal(InterpState & S,CodePtr OpPC,uint32_t I)501 inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
502 S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
503 return true;
504 }
505
GetPtrParam(InterpState & S,CodePtr OpPC,uint32_t I)506 inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
507 if (S.checkingPotentialConstantExpression()) {
508 return false;
509 }
510 S.Stk.push<Pointer>(S.Current->getParamPointer(I));
511 return true;
512 }
513
GetPtrGlobal(InterpState & S,CodePtr OpPC,uint32_t I)514 inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
515 S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
516 return true;
517 }
518
GetPtrField(InterpState & S,CodePtr OpPC,uint32_t Off)519 inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
520 const Pointer &Ptr = S.Stk.pop<Pointer>();
521 if (!CheckNull(S, OpPC, Ptr, CSK_Field))
522 return false;
523 if (!CheckExtern(S, OpPC, Ptr))
524 return false;
525 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
526 return false;
527 S.Stk.push<Pointer>(Ptr.atField(Off));
528 return true;
529 }
530
GetPtrThisField(InterpState & S,CodePtr OpPC,uint32_t Off)531 inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
532 if (S.checkingPotentialConstantExpression())
533 return false;
534 const Pointer &This = S.Current->getThis();
535 if (!CheckThis(S, OpPC, This))
536 return false;
537 S.Stk.push<Pointer>(This.atField(Off));
538 return true;
539 }
540
GetPtrActiveField(InterpState & S,CodePtr OpPC,uint32_t Off)541 inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
542 const Pointer &Ptr = S.Stk.pop<Pointer>();
543 if (!CheckNull(S, OpPC, Ptr, CSK_Field))
544 return false;
545 if (!CheckRange(S, OpPC, Ptr, CSK_Field))
546 return false;
547 Pointer Field = Ptr.atField(Off);
548 Ptr.deactivate();
549 Field.activate();
550 S.Stk.push<Pointer>(std::move(Field));
551 return true;
552 }
553
GetPtrActiveThisField(InterpState & S,CodePtr OpPC,uint32_t Off)554 inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
555 if (S.checkingPotentialConstantExpression())
556 return false;
557 const Pointer &This = S.Current->getThis();
558 if (!CheckThis(S, OpPC, This))
559 return false;
560 Pointer Field = This.atField(Off);
561 This.deactivate();
562 Field.activate();
563 S.Stk.push<Pointer>(std::move(Field));
564 return true;
565 }
566
GetPtrBase(InterpState & S,CodePtr OpPC,uint32_t Off)567 inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
568 const Pointer &Ptr = S.Stk.pop<Pointer>();
569 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
570 return false;
571 S.Stk.push<Pointer>(Ptr.atField(Off));
572 return true;
573 }
574
GetPtrThisBase(InterpState & S,CodePtr OpPC,uint32_t Off)575 inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
576 if (S.checkingPotentialConstantExpression())
577 return false;
578 const Pointer &This = S.Current->getThis();
579 if (!CheckThis(S, OpPC, This))
580 return false;
581 S.Stk.push<Pointer>(This.atField(Off));
582 return true;
583 }
584
VirtBaseHelper(InterpState & S,CodePtr OpPC,const RecordDecl * Decl,const Pointer & Ptr)585 inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
586 const Pointer &Ptr) {
587 Pointer Base = Ptr;
588 while (Base.isBaseClass())
589 Base = Base.getBase();
590
591 auto *Field = Base.getRecord()->getVirtualBase(Decl);
592 S.Stk.push<Pointer>(Base.atField(Field->Offset));
593 return true;
594 }
595
GetPtrVirtBase(InterpState & S,CodePtr OpPC,const RecordDecl * D)596 inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
597 const Pointer &Ptr = S.Stk.pop<Pointer>();
598 if (!CheckNull(S, OpPC, Ptr, CSK_Base))
599 return false;
600 return VirtBaseHelper(S, OpPC, D, Ptr);
601 }
602
GetPtrThisVirtBase(InterpState & S,CodePtr OpPC,const RecordDecl * D)603 inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
604 const RecordDecl *D) {
605 if (S.checkingPotentialConstantExpression())
606 return false;
607 const Pointer &This = S.Current->getThis();
608 if (!CheckThis(S, OpPC, This))
609 return false;
610 return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
611 }
612
613 //===----------------------------------------------------------------------===//
614 // Load, Store, Init
615 //===----------------------------------------------------------------------===//
616
617 template <PrimType Name, class T = typename PrimConv<Name>::T>
Load(InterpState & S,CodePtr OpPC)618 bool Load(InterpState &S, CodePtr OpPC) {
619 const Pointer &Ptr = S.Stk.peek<Pointer>();
620 if (!CheckLoad(S, OpPC, Ptr))
621 return false;
622 S.Stk.push<T>(Ptr.deref<T>());
623 return true;
624 }
625
626 template <PrimType Name, class T = typename PrimConv<Name>::T>
LoadPop(InterpState & S,CodePtr OpPC)627 bool LoadPop(InterpState &S, CodePtr OpPC) {
628 const Pointer &Ptr = S.Stk.pop<Pointer>();
629 if (!CheckLoad(S, OpPC, Ptr))
630 return false;
631 S.Stk.push<T>(Ptr.deref<T>());
632 return true;
633 }
634
635 template <PrimType Name, class T = typename PrimConv<Name>::T>
Store(InterpState & S,CodePtr OpPC)636 bool Store(InterpState &S, CodePtr OpPC) {
637 const T &Value = S.Stk.pop<T>();
638 const Pointer &Ptr = S.Stk.peek<Pointer>();
639 if (!CheckStore(S, OpPC, Ptr))
640 return false;
641 Ptr.deref<T>() = Value;
642 return true;
643 }
644
645 template <PrimType Name, class T = typename PrimConv<Name>::T>
StorePop(InterpState & S,CodePtr OpPC)646 bool StorePop(InterpState &S, CodePtr OpPC) {
647 const T &Value = S.Stk.pop<T>();
648 const Pointer &Ptr = S.Stk.pop<Pointer>();
649 if (!CheckStore(S, OpPC, Ptr))
650 return false;
651 Ptr.deref<T>() = Value;
652 return true;
653 }
654
655 template <PrimType Name, class T = typename PrimConv<Name>::T>
StoreBitField(InterpState & S,CodePtr OpPC)656 bool StoreBitField(InterpState &S, CodePtr OpPC) {
657 const T &Value = S.Stk.pop<T>();
658 const Pointer &Ptr = S.Stk.peek<Pointer>();
659 if (!CheckStore(S, OpPC, Ptr))
660 return false;
661 if (auto *FD = Ptr.getField()) {
662 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
663 } else {
664 Ptr.deref<T>() = Value;
665 }
666 return true;
667 }
668
669 template <PrimType Name, class T = typename PrimConv<Name>::T>
StoreBitFieldPop(InterpState & S,CodePtr OpPC)670 bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
671 const T &Value = S.Stk.pop<T>();
672 const Pointer &Ptr = S.Stk.pop<Pointer>();
673 if (!CheckStore(S, OpPC, Ptr))
674 return false;
675 if (auto *FD = Ptr.getField()) {
676 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
677 } else {
678 Ptr.deref<T>() = Value;
679 }
680 return true;
681 }
682
683 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitPop(InterpState & S,CodePtr OpPC)684 bool InitPop(InterpState &S, CodePtr OpPC) {
685 const T &Value = S.Stk.pop<T>();
686 const Pointer &Ptr = S.Stk.pop<Pointer>();
687 if (!CheckInit(S, OpPC, Ptr))
688 return false;
689 Ptr.initialize();
690 new (&Ptr.deref<T>()) T(Value);
691 return true;
692 }
693
694 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitElem(InterpState & S,CodePtr OpPC,uint32_t Idx)695 bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
696 const T &Value = S.Stk.pop<T>();
697 const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
698 if (!CheckInit(S, OpPC, Ptr))
699 return false;
700 Ptr.initialize();
701 new (&Ptr.deref<T>()) T(Value);
702 return true;
703 }
704
705 template <PrimType Name, class T = typename PrimConv<Name>::T>
InitElemPop(InterpState & S,CodePtr OpPC,uint32_t Idx)706 bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
707 const T &Value = S.Stk.pop<T>();
708 const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
709 if (!CheckInit(S, OpPC, Ptr))
710 return false;
711 Ptr.initialize();
712 new (&Ptr.deref<T>()) T(Value);
713 return true;
714 }
715
716 //===----------------------------------------------------------------------===//
717 // AddOffset, SubOffset
718 //===----------------------------------------------------------------------===//
719
OffsetHelper(InterpState & S,CodePtr OpPC)720 template <class T, bool Add> bool OffsetHelper(InterpState &S, CodePtr OpPC) {
721 // Fetch the pointer and the offset.
722 const T &Offset = S.Stk.pop<T>();
723 const Pointer &Ptr = S.Stk.pop<Pointer>();
724 if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
725 return false;
726 if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
727 return false;
728
729 // Get a version of the index comparable to the type.
730 T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
731 // A zero offset does not change the pointer, but in the case of an array
732 // it has to be adjusted to point to the first element instead of the array.
733 if (Offset.isZero()) {
734 S.Stk.push<Pointer>(Index.isZero() ? Ptr.atIndex(0) : Ptr);
735 return true;
736 }
737 // Arrays of unknown bounds cannot have pointers into them.
738 if (!CheckArray(S, OpPC, Ptr))
739 return false;
740
741 // Compute the largest index into the array.
742 unsigned MaxIndex = Ptr.getNumElems();
743
744 // Helper to report an invalid offset, computed as APSInt.
745 auto InvalidOffset = [&]() {
746 const unsigned Bits = Offset.bitWidth();
747 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
748 APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
749 APSInt NewIndex = Add ? (APIndex + APOffset) : (APIndex - APOffset);
750 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
751 << NewIndex
752 << /*array*/ static_cast<int>(!Ptr.inArray())
753 << static_cast<unsigned>(MaxIndex);
754 return false;
755 };
756
757 // If the new offset would be negative, bail out.
758 if (Add && Offset.isNegative() && (Offset.isMin() || -Offset > Index))
759 return InvalidOffset();
760 if (!Add && Offset.isPositive() && Index < Offset)
761 return InvalidOffset();
762
763 // If the new offset would be out of bounds, bail out.
764 unsigned MaxOffset = MaxIndex - Ptr.getIndex();
765 if (Add && Offset.isPositive() && Offset > MaxOffset)
766 return InvalidOffset();
767 if (!Add && Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
768 return InvalidOffset();
769
770 // Offset is valid - compute it on unsigned.
771 int64_t WideIndex = static_cast<int64_t>(Index);
772 int64_t WideOffset = static_cast<int64_t>(Offset);
773 int64_t Result = Add ? (WideIndex + WideOffset) : (WideIndex - WideOffset);
774 S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
775 return true;
776 }
777
778 template <PrimType Name, class T = typename PrimConv<Name>::T>
AddOffset(InterpState & S,CodePtr OpPC)779 bool AddOffset(InterpState &S, CodePtr OpPC) {
780 return OffsetHelper<T, true>(S, OpPC);
781 }
782
783 template <PrimType Name, class T = typename PrimConv<Name>::T>
SubOffset(InterpState & S,CodePtr OpPC)784 bool SubOffset(InterpState &S, CodePtr OpPC) {
785 return OffsetHelper<T, false>(S, OpPC);
786 }
787
788
789 //===----------------------------------------------------------------------===//
790 // Destroy
791 //===----------------------------------------------------------------------===//
792
Destroy(InterpState & S,CodePtr OpPC,uint32_t I)793 inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
794 S.Current->destroy(I);
795 return true;
796 }
797
798 //===----------------------------------------------------------------------===//
799 // Cast, CastFP
800 //===----------------------------------------------------------------------===//
801
Cast(InterpState & S,CodePtr OpPC)802 template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
803 using T = typename PrimConv<TIn>::T;
804 using U = typename PrimConv<TOut>::T;
805 S.Stk.push<U>(U::from(S.Stk.pop<T>()));
806 return true;
807 }
808
809 //===----------------------------------------------------------------------===//
810 // Zero, Nullptr
811 //===----------------------------------------------------------------------===//
812
813 template <PrimType Name, class T = typename PrimConv<Name>::T>
Zero(InterpState & S,CodePtr OpPC)814 bool Zero(InterpState &S, CodePtr OpPC) {
815 S.Stk.push<T>(T::zero());
816 return true;
817 }
818
819 template <PrimType Name, class T = typename PrimConv<Name>::T>
Null(InterpState & S,CodePtr OpPC)820 inline bool Null(InterpState &S, CodePtr OpPC) {
821 S.Stk.push<T>();
822 return true;
823 }
824
825 //===----------------------------------------------------------------------===//
826 // This, ImplicitThis
827 //===----------------------------------------------------------------------===//
828
This(InterpState & S,CodePtr OpPC)829 inline bool This(InterpState &S, CodePtr OpPC) {
830 // Cannot read 'this' in this mode.
831 if (S.checkingPotentialConstantExpression()) {
832 return false;
833 }
834
835 const Pointer &This = S.Current->getThis();
836 if (!CheckThis(S, OpPC, This))
837 return false;
838
839 S.Stk.push<Pointer>(This);
840 return true;
841 }
842
843 //===----------------------------------------------------------------------===//
844 // Shr, Shl
845 //===----------------------------------------------------------------------===//
846
847 template <PrimType TR, PrimType TL, class T = typename PrimConv<TR>::T>
Trunc(InterpState & S,CodePtr OpPC,unsigned Bits,const T & V)848 unsigned Trunc(InterpState &S, CodePtr OpPC, unsigned Bits, const T &V) {
849 // C++11 [expr.shift]p1: Shift width must be less than the bit width of
850 // the shifted type.
851 if (Bits > 1 && V >= T::from(Bits, V.bitWidth())) {
852 const Expr *E = S.Current->getExpr(OpPC);
853 const APSInt Val = V.toAPSInt();
854 QualType Ty = E->getType();
855 S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
856 return Bits;
857 } else {
858 return static_cast<unsigned>(V);
859 }
860 }
861
862 template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T>
ShiftRight(InterpState & S,CodePtr OpPC,const T & V,unsigned RHS)863 inline bool ShiftRight(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS) {
864 if (RHS >= V.bitWidth()) {
865 S.Stk.push<T>(T::from(0, V.bitWidth()));
866 } else {
867 S.Stk.push<T>(T::from(V >> RHS, V.bitWidth()));
868 }
869 return true;
870 }
871
872 template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T>
ShiftLeft(InterpState & S,CodePtr OpPC,const T & V,unsigned RHS)873 inline bool ShiftLeft(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS) {
874 if (V.isSigned() && !S.getLangOpts().CPlusPlus20) {
875 // C++11 [expr.shift]p2: A signed left shift must have a non-negative
876 // operand, and must not overflow the corresponding unsigned type.
877 // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to
878 // E1 x 2^E2 module 2^N.
879 if (V.isNegative()) {
880 const Expr *E = S.Current->getExpr(OpPC);
881 S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << V.toAPSInt();
882 } else if (V.countLeadingZeros() < RHS) {
883 S.CCEDiag(S.Current->getExpr(OpPC), diag::note_constexpr_lshift_discards);
884 }
885 }
886
887 if (V.bitWidth() == 1) {
888 S.Stk.push<T>(V);
889 } else if (RHS >= V.bitWidth()) {
890 S.Stk.push<T>(T::from(0, V.bitWidth()));
891 } else {
892 S.Stk.push<T>(T::from(V.toUnsigned() << RHS, V.bitWidth()));
893 }
894 return true;
895 }
896
897 template <PrimType TL, PrimType TR>
Shr(InterpState & S,CodePtr OpPC)898 inline bool Shr(InterpState &S, CodePtr OpPC) {
899 const auto &RHS = S.Stk.pop<typename PrimConv<TR>::T>();
900 const auto &LHS = S.Stk.pop<typename PrimConv<TL>::T>();
901 const unsigned Bits = LHS.bitWidth();
902
903 if (RHS.isSigned() && RHS.isNegative()) {
904 const SourceInfo &Loc = S.Current->getSource(OpPC);
905 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
906 return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS));
907 } else {
908 return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS));
909 }
910 }
911
912 template <PrimType TL, PrimType TR>
Shl(InterpState & S,CodePtr OpPC)913 inline bool Shl(InterpState &S, CodePtr OpPC) {
914 const auto &RHS = S.Stk.pop<typename PrimConv<TR>::T>();
915 const auto &LHS = S.Stk.pop<typename PrimConv<TL>::T>();
916 const unsigned Bits = LHS.bitWidth();
917
918 if (RHS.isSigned() && RHS.isNegative()) {
919 const SourceInfo &Loc = S.Current->getSource(OpPC);
920 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
921 return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS));
922 } else {
923 return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS));
924 }
925 }
926
927 //===----------------------------------------------------------------------===//
928 // NoRet
929 //===----------------------------------------------------------------------===//
930
NoRet(InterpState & S,CodePtr OpPC)931 inline bool NoRet(InterpState &S, CodePtr OpPC) {
932 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
933 S.FFDiag(EndLoc, diag::note_constexpr_no_return);
934 return false;
935 }
936
937 //===----------------------------------------------------------------------===//
938 // NarrowPtr, ExpandPtr
939 //===----------------------------------------------------------------------===//
940
NarrowPtr(InterpState & S,CodePtr OpPC)941 inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
942 const Pointer &Ptr = S.Stk.pop<Pointer>();
943 S.Stk.push<Pointer>(Ptr.narrow());
944 return true;
945 }
946
ExpandPtr(InterpState & S,CodePtr OpPC)947 inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
948 const Pointer &Ptr = S.Stk.pop<Pointer>();
949 S.Stk.push<Pointer>(Ptr.expand());
950 return true;
951 }
952
953 //===----------------------------------------------------------------------===//
954 // Read opcode arguments
955 //===----------------------------------------------------------------------===//
956
957 template <typename T>
ReadArg(InterpState & S,CodePtr OpPC)958 inline std::enable_if_t<!std::is_pointer<T>::value, T> ReadArg(InterpState &S,
959 CodePtr OpPC) {
960 return OpPC.read<T>();
961 }
962
963 template <typename T>
ReadArg(InterpState & S,CodePtr OpPC)964 inline std::enable_if_t<std::is_pointer<T>::value, T> ReadArg(InterpState &S,
965 CodePtr OpPC) {
966 uint32_t ID = OpPC.read<uint32_t>();
967 return reinterpret_cast<T>(S.P.getNativePointer(ID));
968 }
969
970 /// Interpreter entry point.
971 bool Interpret(InterpState &S, APValue &Result);
972
973 } // namespace interp
974 } // namespace clang
975
976 #endif
977