xref: /llvm-project/clang/lib/AST/ByteCode/InterpState.cpp (revision a024a0ceedae886c254b496c9321f9ef253cd7f8)
1a07aba5dSTimm Baeder //===--- InterpState.cpp - Interpreter for the constexpr VM -----*- C++ -*-===//
2a07aba5dSTimm Baeder //
3a07aba5dSTimm Baeder // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a07aba5dSTimm Baeder // See https://llvm.org/LICENSE.txt for license information.
5a07aba5dSTimm Baeder // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a07aba5dSTimm Baeder //
7a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
8a07aba5dSTimm Baeder 
9a07aba5dSTimm Baeder #include "InterpState.h"
10a07aba5dSTimm Baeder #include "InterpFrame.h"
11a07aba5dSTimm Baeder #include "InterpStack.h"
12a07aba5dSTimm Baeder #include "Program.h"
13a07aba5dSTimm Baeder #include "State.h"
14a07aba5dSTimm Baeder 
15a07aba5dSTimm Baeder using namespace clang;
16a07aba5dSTimm Baeder using namespace clang::interp;
17a07aba5dSTimm Baeder 
18a07aba5dSTimm Baeder InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
19a07aba5dSTimm Baeder                          Context &Ctx, SourceMapper *M)
20a07aba5dSTimm Baeder     : Parent(Parent), M(M), P(P), Stk(Stk), Ctx(Ctx), Current(nullptr) {}
21a07aba5dSTimm Baeder 
22*a024a0ceSTimm Baeder bool InterpState::inConstantContext() const {
23*a024a0ceSTimm Baeder   if (ConstantContextOverride)
24*a024a0ceSTimm Baeder     return *ConstantContextOverride;
25*a024a0ceSTimm Baeder 
26*a024a0ceSTimm Baeder   return Parent.InConstantContext;
27*a024a0ceSTimm Baeder }
28*a024a0ceSTimm Baeder 
29a07aba5dSTimm Baeder InterpState::~InterpState() {
30a07aba5dSTimm Baeder   while (Current) {
31a07aba5dSTimm Baeder     InterpFrame *Next = Current->Caller;
32a07aba5dSTimm Baeder     delete Current;
33a07aba5dSTimm Baeder     Current = Next;
34a07aba5dSTimm Baeder   }
35a07aba5dSTimm Baeder 
36a07aba5dSTimm Baeder   while (DeadBlocks) {
37a07aba5dSTimm Baeder     DeadBlock *Next = DeadBlocks->Next;
38a07aba5dSTimm Baeder     std::free(DeadBlocks);
39a07aba5dSTimm Baeder     DeadBlocks = Next;
40a07aba5dSTimm Baeder   }
41a07aba5dSTimm Baeder }
42a07aba5dSTimm Baeder 
43a07aba5dSTimm Baeder void InterpState::cleanup() {
44a07aba5dSTimm Baeder   // As a last resort, make sure all pointers still pointing to a dead block
45a07aba5dSTimm Baeder   // don't point to it anymore.
46a07aba5dSTimm Baeder   for (DeadBlock *DB = DeadBlocks; DB; DB = DB->Next) {
47a07aba5dSTimm Baeder     for (Pointer *P = DB->B.Pointers; P; P = P->Next) {
48a07aba5dSTimm Baeder       P->PointeeStorage.BS.Pointee = nullptr;
49a07aba5dSTimm Baeder     }
50a07aba5dSTimm Baeder   }
51a07aba5dSTimm Baeder 
52a07aba5dSTimm Baeder   Alloc.cleanup();
53a07aba5dSTimm Baeder }
54a07aba5dSTimm Baeder 
55a07aba5dSTimm Baeder Frame *InterpState::getCurrentFrame() {
56a07aba5dSTimm Baeder   if (Current && Current->Caller)
57a07aba5dSTimm Baeder     return Current;
58a07aba5dSTimm Baeder   return Parent.getCurrentFrame();
59a07aba5dSTimm Baeder }
60a07aba5dSTimm Baeder 
61a07aba5dSTimm Baeder bool InterpState::reportOverflow(const Expr *E, const llvm::APSInt &Value) {
62a07aba5dSTimm Baeder   QualType Type = E->getType();
63a07aba5dSTimm Baeder   CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
64a07aba5dSTimm Baeder   return noteUndefinedBehavior();
65a07aba5dSTimm Baeder }
66a07aba5dSTimm Baeder 
67a07aba5dSTimm Baeder void InterpState::deallocate(Block *B) {
68a07aba5dSTimm Baeder   assert(B);
69a07aba5dSTimm Baeder   const Descriptor *Desc = B->getDescriptor();
70a07aba5dSTimm Baeder   assert(Desc);
71a07aba5dSTimm Baeder 
72a07aba5dSTimm Baeder   if (B->hasPointers()) {
73a07aba5dSTimm Baeder     size_t Size = B->getSize();
74a07aba5dSTimm Baeder 
75a07aba5dSTimm Baeder     // Allocate a new block, transferring over pointers.
76a07aba5dSTimm Baeder     char *Memory =
77a07aba5dSTimm Baeder         reinterpret_cast<char *>(std::malloc(sizeof(DeadBlock) + Size));
78a07aba5dSTimm Baeder     auto *D = new (Memory) DeadBlock(DeadBlocks, B);
79a07aba5dSTimm Baeder     std::memset(D->B.rawData(), 0, D->B.getSize());
80a07aba5dSTimm Baeder 
81a07aba5dSTimm Baeder     // Move data and metadata from the old block to the new (dead)block.
82a07aba5dSTimm Baeder     if (B->IsInitialized && Desc->MoveFn) {
83a07aba5dSTimm Baeder       Desc->MoveFn(B, B->data(), D->data(), Desc);
84a07aba5dSTimm Baeder       if (Desc->getMetadataSize() > 0)
85a07aba5dSTimm Baeder         std::memcpy(D->rawData(), B->rawData(), Desc->getMetadataSize());
86a07aba5dSTimm Baeder     }
87a07aba5dSTimm Baeder     D->B.IsInitialized = B->IsInitialized;
88a07aba5dSTimm Baeder 
89a07aba5dSTimm Baeder     // We moved the contents over to the DeadBlock.
90a07aba5dSTimm Baeder     B->IsInitialized = false;
91a07aba5dSTimm Baeder   } else if (B->IsInitialized) {
92a07aba5dSTimm Baeder     B->invokeDtor();
93a07aba5dSTimm Baeder   }
94a07aba5dSTimm Baeder }
95a07aba5dSTimm Baeder 
96a07aba5dSTimm Baeder bool InterpState::maybeDiagnoseDanglingAllocations() {
97a07aba5dSTimm Baeder   bool NoAllocationsLeft = (Alloc.getNumAllocations() == 0);
98a07aba5dSTimm Baeder 
99a07aba5dSTimm Baeder   if (!checkingPotentialConstantExpression()) {
100a07aba5dSTimm Baeder     for (const auto &It : Alloc.allocation_sites()) {
101a07aba5dSTimm Baeder       assert(It.second.size() > 0);
102a07aba5dSTimm Baeder 
103a07aba5dSTimm Baeder       const Expr *Source = It.first;
104a07aba5dSTimm Baeder       CCEDiag(Source->getExprLoc(), diag::note_constexpr_memory_leak)
105a07aba5dSTimm Baeder           << (It.second.size() - 1) << Source->getSourceRange();
106a07aba5dSTimm Baeder     }
107a07aba5dSTimm Baeder   }
108a07aba5dSTimm Baeder   return NoAllocationsLeft;
109a07aba5dSTimm Baeder }
110