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