1*700637cbSDimitry Andric //===--- InterpState.cpp - Interpreter for the constexpr VM -----*- C++ -*-===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric
9*700637cbSDimitry Andric #include "InterpState.h"
10*700637cbSDimitry Andric #include "InterpFrame.h"
11*700637cbSDimitry Andric #include "InterpStack.h"
12*700637cbSDimitry Andric #include "Program.h"
13*700637cbSDimitry Andric #include "State.h"
14*700637cbSDimitry Andric
15*700637cbSDimitry Andric using namespace clang;
16*700637cbSDimitry Andric using namespace clang::interp;
17*700637cbSDimitry Andric
InterpState(State & Parent,Program & P,InterpStack & Stk,Context & Ctx,SourceMapper * M)18*700637cbSDimitry Andric InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
19*700637cbSDimitry Andric Context &Ctx, SourceMapper *M)
20*700637cbSDimitry Andric : Parent(Parent), M(M), P(P), Stk(Stk), Ctx(Ctx), BottomFrame(*this),
21*700637cbSDimitry Andric Current(&BottomFrame) {}
22*700637cbSDimitry Andric
InterpState(State & Parent,Program & P,InterpStack & Stk,Context & Ctx,const Function * Func)23*700637cbSDimitry Andric InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
24*700637cbSDimitry Andric Context &Ctx, const Function *Func)
25*700637cbSDimitry Andric : Parent(Parent), M(nullptr), P(P), Stk(Stk), Ctx(Ctx),
26*700637cbSDimitry Andric BottomFrame(*this, Func, nullptr, CodePtr(), Func->getArgSize()),
27*700637cbSDimitry Andric Current(&BottomFrame) {}
28*700637cbSDimitry Andric
inConstantContext() const29*700637cbSDimitry Andric bool InterpState::inConstantContext() const {
30*700637cbSDimitry Andric if (ConstantContextOverride)
31*700637cbSDimitry Andric return *ConstantContextOverride;
32*700637cbSDimitry Andric
33*700637cbSDimitry Andric return Parent.InConstantContext;
34*700637cbSDimitry Andric }
35*700637cbSDimitry Andric
~InterpState()36*700637cbSDimitry Andric InterpState::~InterpState() {
37*700637cbSDimitry Andric while (Current && !Current->isBottomFrame()) {
38*700637cbSDimitry Andric InterpFrame *Next = Current->Caller;
39*700637cbSDimitry Andric delete Current;
40*700637cbSDimitry Andric Current = Next;
41*700637cbSDimitry Andric }
42*700637cbSDimitry Andric BottomFrame.destroyScopes();
43*700637cbSDimitry Andric
44*700637cbSDimitry Andric while (DeadBlocks) {
45*700637cbSDimitry Andric DeadBlock *Next = DeadBlocks->Next;
46*700637cbSDimitry Andric std::free(DeadBlocks);
47*700637cbSDimitry Andric DeadBlocks = Next;
48*700637cbSDimitry Andric }
49*700637cbSDimitry Andric }
50*700637cbSDimitry Andric
cleanup()51*700637cbSDimitry Andric void InterpState::cleanup() {
52*700637cbSDimitry Andric // As a last resort, make sure all pointers still pointing to a dead block
53*700637cbSDimitry Andric // don't point to it anymore.
54*700637cbSDimitry Andric for (DeadBlock *DB = DeadBlocks; DB; DB = DB->Next) {
55*700637cbSDimitry Andric for (Pointer *P = DB->B.Pointers; P; P = P->Next) {
56*700637cbSDimitry Andric P->PointeeStorage.BS.Pointee = nullptr;
57*700637cbSDimitry Andric }
58*700637cbSDimitry Andric }
59*700637cbSDimitry Andric
60*700637cbSDimitry Andric Alloc.cleanup();
61*700637cbSDimitry Andric }
62*700637cbSDimitry Andric
getCurrentFrame()63*700637cbSDimitry Andric Frame *InterpState::getCurrentFrame() {
64*700637cbSDimitry Andric if (Current && Current->Caller)
65*700637cbSDimitry Andric return Current;
66*700637cbSDimitry Andric return Parent.getCurrentFrame();
67*700637cbSDimitry Andric }
68*700637cbSDimitry Andric
reportOverflow(const Expr * E,const llvm::APSInt & Value)69*700637cbSDimitry Andric bool InterpState::reportOverflow(const Expr *E, const llvm::APSInt &Value) {
70*700637cbSDimitry Andric QualType Type = E->getType();
71*700637cbSDimitry Andric CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
72*700637cbSDimitry Andric return noteUndefinedBehavior();
73*700637cbSDimitry Andric }
74*700637cbSDimitry Andric
deallocate(Block * B)75*700637cbSDimitry Andric void InterpState::deallocate(Block *B) {
76*700637cbSDimitry Andric assert(B);
77*700637cbSDimitry Andric const Descriptor *Desc = B->getDescriptor();
78*700637cbSDimitry Andric assert(Desc);
79*700637cbSDimitry Andric
80*700637cbSDimitry Andric if (B->hasPointers()) {
81*700637cbSDimitry Andric size_t Size = B->getSize();
82*700637cbSDimitry Andric
83*700637cbSDimitry Andric // Allocate a new block, transferring over pointers.
84*700637cbSDimitry Andric char *Memory =
85*700637cbSDimitry Andric reinterpret_cast<char *>(std::malloc(sizeof(DeadBlock) + Size));
86*700637cbSDimitry Andric auto *D = new (Memory) DeadBlock(DeadBlocks, B);
87*700637cbSDimitry Andric std::memset(D->B.rawData(), 0, D->B.getSize());
88*700637cbSDimitry Andric
89*700637cbSDimitry Andric // Move data and metadata from the old block to the new (dead)block.
90*700637cbSDimitry Andric if (B->IsInitialized && Desc->MoveFn) {
91*700637cbSDimitry Andric Desc->MoveFn(B, B->data(), D->data(), Desc);
92*700637cbSDimitry Andric if (Desc->getMetadataSize() > 0)
93*700637cbSDimitry Andric std::memcpy(D->rawData(), B->rawData(), Desc->getMetadataSize());
94*700637cbSDimitry Andric }
95*700637cbSDimitry Andric D->B.IsInitialized = B->IsInitialized;
96*700637cbSDimitry Andric
97*700637cbSDimitry Andric // We moved the contents over to the DeadBlock.
98*700637cbSDimitry Andric B->IsInitialized = false;
99*700637cbSDimitry Andric } else if (B->IsInitialized) {
100*700637cbSDimitry Andric B->invokeDtor();
101*700637cbSDimitry Andric }
102*700637cbSDimitry Andric }
103*700637cbSDimitry Andric
maybeDiagnoseDanglingAllocations()104*700637cbSDimitry Andric bool InterpState::maybeDiagnoseDanglingAllocations() {
105*700637cbSDimitry Andric bool NoAllocationsLeft = (Alloc.getNumAllocations() == 0);
106*700637cbSDimitry Andric
107*700637cbSDimitry Andric if (!checkingPotentialConstantExpression()) {
108*700637cbSDimitry Andric for (const auto &It : Alloc.allocation_sites()) {
109*700637cbSDimitry Andric assert(It.second.size() > 0);
110*700637cbSDimitry Andric
111*700637cbSDimitry Andric const Expr *Source = It.first;
112*700637cbSDimitry Andric CCEDiag(Source->getExprLoc(), diag::note_constexpr_memory_leak)
113*700637cbSDimitry Andric << (It.second.size() - 1) << Source->getSourceRange();
114*700637cbSDimitry Andric }
115*700637cbSDimitry Andric }
116*700637cbSDimitry Andric // Keep evaluating before C++20, since the CXXNewExpr wasn't valid there
117*700637cbSDimitry Andric // in the first place.
118*700637cbSDimitry Andric return NoAllocationsLeft || !getLangOpts().CPlusPlus20;
119*700637cbSDimitry Andric }
120*700637cbSDimitry Andric
getStdAllocatorCaller(StringRef Name) const121*700637cbSDimitry Andric StdAllocatorCaller InterpState::getStdAllocatorCaller(StringRef Name) const {
122*700637cbSDimitry Andric for (const InterpFrame *F = Current; F; F = F->Caller) {
123*700637cbSDimitry Andric const Function *Func = F->getFunction();
124*700637cbSDimitry Andric if (!Func)
125*700637cbSDimitry Andric continue;
126*700637cbSDimitry Andric const auto *MD = dyn_cast_if_present<CXXMethodDecl>(Func->getDecl());
127*700637cbSDimitry Andric if (!MD)
128*700637cbSDimitry Andric continue;
129*700637cbSDimitry Andric const IdentifierInfo *FnII = MD->getIdentifier();
130*700637cbSDimitry Andric if (!FnII || !FnII->isStr(Name))
131*700637cbSDimitry Andric continue;
132*700637cbSDimitry Andric
133*700637cbSDimitry Andric const auto *CTSD =
134*700637cbSDimitry Andric dyn_cast<ClassTemplateSpecializationDecl>(MD->getParent());
135*700637cbSDimitry Andric if (!CTSD)
136*700637cbSDimitry Andric continue;
137*700637cbSDimitry Andric
138*700637cbSDimitry Andric const IdentifierInfo *ClassII = CTSD->getIdentifier();
139*700637cbSDimitry Andric const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
140*700637cbSDimitry Andric if (CTSD->isInStdNamespace() && ClassII && ClassII->isStr("allocator") &&
141*700637cbSDimitry Andric TAL.size() >= 1 && TAL[0].getKind() == TemplateArgument::Type) {
142*700637cbSDimitry Andric QualType ElemType = TAL[0].getAsType();
143*700637cbSDimitry Andric const auto *NewCall = cast<CallExpr>(F->Caller->getExpr(F->getRetPC()));
144*700637cbSDimitry Andric return {NewCall, ElemType};
145*700637cbSDimitry Andric }
146*700637cbSDimitry Andric }
147*700637cbSDimitry Andric
148*700637cbSDimitry Andric return {};
149*700637cbSDimitry Andric }
150