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