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