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