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