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