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/EvaluationResult.cpp
213799 views
1
//===----- EvaluationResult.cpp - Result class for the 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 "EvaluationResult.h"
10
#include "InterpState.h"
11
#include "Record.h"
12
#include "llvm/ADT/STLExtras.h"
13
#include "llvm/ADT/SetVector.h"
14
#include <iterator>
15
16
namespace clang {
17
namespace interp {
18
19
APValue EvaluationResult::toAPValue() const {
20
assert(!empty());
21
switch (Kind) {
22
case LValue:
23
// Either a pointer or a function pointer.
24
if (const auto *P = std::get_if<Pointer>(&Value))
25
return P->toAPValue(Ctx->getASTContext());
26
else if (const auto *FP = std::get_if<FunctionPointer>(&Value))
27
return FP->toAPValue(Ctx->getASTContext());
28
else
29
llvm_unreachable("Unhandled LValue type");
30
break;
31
case RValue:
32
return std::get<APValue>(Value);
33
case Valid:
34
return APValue();
35
default:
36
llvm_unreachable("Unhandled result kind?");
37
}
38
}
39
40
std::optional<APValue> EvaluationResult::toRValue() const {
41
if (Kind == RValue)
42
return toAPValue();
43
44
assert(Kind == LValue);
45
46
// We have a pointer and want an RValue.
47
if (const auto *P = std::get_if<Pointer>(&Value))
48
return P->toRValue(*Ctx, getSourceType());
49
else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
50
return FP->toAPValue(Ctx->getASTContext());
51
llvm_unreachable("Unhandled lvalue kind");
52
}
53
54
static void DiagnoseUninitializedSubobject(InterpState &S, SourceLocation Loc,
55
const FieldDecl *SubObjDecl) {
56
assert(SubObjDecl && "Subobject declaration does not exist");
57
S.FFDiag(Loc, diag::note_constexpr_uninitialized)
58
<< /*(name)*/ 1 << SubObjDecl;
59
S.Note(SubObjDecl->getLocation(),
60
diag::note_constexpr_subobject_declared_here);
61
}
62
63
static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
64
const Pointer &BasePtr, const Record *R);
65
66
static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc,
67
const Pointer &BasePtr,
68
const ConstantArrayType *CAT) {
69
bool Result = true;
70
size_t NumElems = CAT->getZExtSize();
71
QualType ElemType = CAT->getElementType();
72
73
if (ElemType->isRecordType()) {
74
const Record *R = BasePtr.getElemRecord();
75
for (size_t I = 0; I != NumElems; ++I) {
76
Pointer ElemPtr = BasePtr.atIndex(I).narrow();
77
Result &= CheckFieldsInitialized(S, Loc, ElemPtr, R);
78
}
79
} else if (const auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) {
80
for (size_t I = 0; I != NumElems; ++I) {
81
Pointer ElemPtr = BasePtr.atIndex(I).narrow();
82
Result &= CheckArrayInitialized(S, Loc, ElemPtr, ElemCAT);
83
}
84
} else {
85
for (size_t I = 0; I != NumElems; ++I) {
86
if (!BasePtr.atIndex(I).isInitialized()) {
87
DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField());
88
Result = false;
89
}
90
}
91
}
92
93
return Result;
94
}
95
96
static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
97
const Pointer &BasePtr, const Record *R) {
98
assert(R);
99
bool Result = true;
100
// Check all fields of this record are initialized.
101
for (const Record::Field &F : R->fields()) {
102
Pointer FieldPtr = BasePtr.atField(F.Offset);
103
QualType FieldType = F.Decl->getType();
104
105
// Don't check inactive union members.
106
if (R->isUnion() && !FieldPtr.isActive())
107
continue;
108
109
if (FieldType->isRecordType()) {
110
Result &= CheckFieldsInitialized(S, Loc, FieldPtr, FieldPtr.getRecord());
111
} else if (FieldType->isIncompleteArrayType()) {
112
// Nothing to do here.
113
} else if (F.Decl->isUnnamedBitField()) {
114
// Nothing do do here.
115
} else if (FieldType->isArrayType()) {
116
const auto *CAT =
117
cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe());
118
Result &= CheckArrayInitialized(S, Loc, FieldPtr, CAT);
119
} else if (!FieldPtr.isInitialized()) {
120
DiagnoseUninitializedSubobject(S, Loc, F.Decl);
121
Result = false;
122
}
123
}
124
125
// Check Fields in all bases
126
for (auto [I, B] : llvm::enumerate(R->bases())) {
127
Pointer P = BasePtr.atField(B.Offset);
128
if (!P.isInitialized()) {
129
const Descriptor *Desc = BasePtr.getDeclDesc();
130
if (const auto *CD = dyn_cast_if_present<CXXRecordDecl>(R->getDecl())) {
131
const auto &BS = *std::next(CD->bases_begin(), I);
132
SourceLocation TypeBeginLoc = BS.getBaseTypeLoc();
133
S.FFDiag(TypeBeginLoc, diag::note_constexpr_uninitialized_base)
134
<< B.Desc->getType() << SourceRange(TypeBeginLoc, BS.getEndLoc());
135
} else {
136
S.FFDiag(Desc->getLocation(), diag::note_constexpr_uninitialized_base)
137
<< B.Desc->getType();
138
}
139
return false;
140
}
141
Result &= CheckFieldsInitialized(S, Loc, P, B.R);
142
}
143
144
// TODO: Virtual bases
145
146
return Result;
147
}
148
149
bool EvaluationResult::checkFullyInitialized(InterpState &S,
150
const Pointer &Ptr) const {
151
assert(Source);
152
assert(empty());
153
154
if (Ptr.isZero())
155
return true;
156
157
// We can't inspect dead pointers at all. Return true here so we can
158
// diagnose them later.
159
if (!Ptr.isLive())
160
return true;
161
162
SourceLocation InitLoc;
163
if (const auto *D = dyn_cast<const Decl *>(Source))
164
InitLoc = cast<VarDecl>(D)->getAnyInitializer()->getExprLoc();
165
else if (const auto *E = dyn_cast<const Expr *>(Source))
166
InitLoc = E->getExprLoc();
167
168
if (const Record *R = Ptr.getRecord())
169
return CheckFieldsInitialized(S, InitLoc, Ptr, R);
170
171
if (const auto *CAT = dyn_cast_if_present<ConstantArrayType>(
172
Ptr.getType()->getAsArrayTypeUnsafe()))
173
return CheckArrayInitialized(S, InitLoc, Ptr, CAT);
174
175
return true;
176
}
177
178
static void collectBlocks(const Pointer &Ptr,
179
llvm::SetVector<const Block *> &Blocks) {
180
auto isUsefulPtr = [](const Pointer &P) -> bool {
181
return P.isLive() && !P.isZero() && !P.isDummy() && P.isDereferencable() &&
182
!P.isUnknownSizeArray() && !P.isOnePastEnd();
183
};
184
185
if (!isUsefulPtr(Ptr))
186
return;
187
188
Blocks.insert(Ptr.block());
189
190
const Descriptor *Desc = Ptr.getFieldDesc();
191
if (!Desc)
192
return;
193
194
if (const Record *R = Desc->ElemRecord) {
195
for (const Record::Field &F : R->fields()) {
196
const Pointer &FieldPtr = Ptr.atField(F.Offset);
197
assert(FieldPtr.block() == Ptr.block());
198
collectBlocks(FieldPtr, Blocks);
199
}
200
} else if (Desc->isPrimitive() && Desc->getPrimType() == PT_Ptr) {
201
const Pointer &Pointee = Ptr.deref<Pointer>();
202
if (isUsefulPtr(Pointee) && !Blocks.contains(Pointee.block()))
203
collectBlocks(Pointee, Blocks);
204
205
} else if (Desc->isPrimitiveArray() && Desc->getPrimType() == PT_Ptr) {
206
for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
207
const Pointer &ElemPointee = Ptr.atIndex(I).deref<Pointer>();
208
if (isUsefulPtr(ElemPointee) && !Blocks.contains(ElemPointee.block()))
209
collectBlocks(ElemPointee, Blocks);
210
}
211
} else if (Desc->isCompositeArray()) {
212
for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
213
const Pointer &ElemPtr = Ptr.atIndex(I).narrow();
214
collectBlocks(ElemPtr, Blocks);
215
}
216
}
217
}
218
219
bool EvaluationResult::checkReturnValue(InterpState &S, const Context &Ctx,
220
const Pointer &Ptr,
221
const SourceInfo &Info) {
222
// Collect all blocks that this pointer (transitively) points to and
223
// return false if any of them is a dynamic block.
224
llvm::SetVector<const Block *> Blocks;
225
226
collectBlocks(Ptr, Blocks);
227
228
for (const Block *B : Blocks) {
229
if (B->isDynamic()) {
230
assert(B->getDescriptor());
231
assert(B->getDescriptor()->asExpr());
232
233
bool IsSubobj = !Ptr.isRoot() || Ptr.isArrayElement();
234
S.FFDiag(Info, diag::note_constexpr_dynamic_alloc)
235
<< Ptr.getType()->isReferenceType() << IsSubobj;
236
S.Note(B->getDescriptor()->asExpr()->getExprLoc(),
237
diag::note_constexpr_dynamic_alloc_here);
238
return false;
239
}
240
}
241
242
return true;
243
}
244
245
} // namespace interp
246
} // namespace clang
247
248