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
16namespace clang {
17namespace interp {
18
19APValue 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>(ptr: &Value))
25 return P->toAPValue(ASTCtx: Ctx->getASTContext());
26 else if (const auto *FP = std::get_if<FunctionPointer>(ptr: &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>(v: Value);
33 case Valid:
34 return APValue();
35 default:
36 llvm_unreachable("Unhandled result kind?");
37 }
38}
39
40std::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>(ptr: &Value))
48 return P->toRValue(Ctx: *Ctx, ResultType: getSourceType());
49 else if (const auto *FP = std::get_if<FunctionPointer>(ptr: &Value)) // Nope
50 return FP->toAPValue(Ctx->getASTContext());
51 llvm_unreachable("Unhandled lvalue kind");
52}
53
54static 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
63static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
64 const Pointer &BasePtr, const Record *R);
65
66static 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(Idx: I).narrow();
77 Result &= CheckFieldsInitialized(S, Loc, BasePtr: 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(Idx: 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(Idx: I).isInitialized()) {
87 DiagnoseUninitializedSubobject(S, Loc, SubObjDecl: BasePtr.getField());
88 Result = false;
89 }
90 }
91 }
92
93 return Result;
94}
95
96static 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(Off: 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, BasePtr: FieldPtr, R: 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, SubObjDecl: F.Decl);
121 Result = false;
122 }
123 }
124
125 // Check Fields in all bases
126 for (auto [I, B] : llvm::enumerate(First: R->bases())) {
127 Pointer P = BasePtr.atField(Off: B.Offset);
128 if (!P.isInitialized()) {
129 const Descriptor *Desc = BasePtr.getDeclDesc();
130 if (const auto *CD = dyn_cast_if_present<CXXRecordDecl>(Val: R->getDecl())) {
131 const auto &BS = *std::next(x: CD->bases_begin(), n: 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, BasePtr: P, R: B.R);
142 }
143
144 // TODO: Virtual bases
145
146 return Result;
147}
148
149bool 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 *>(Val: Source))
164 InitLoc = cast<VarDecl>(Val: D)->getAnyInitializer()->getExprLoc();
165 else if (const auto *E = dyn_cast<const Expr *>(Val: Source))
166 InitLoc = E->getExprLoc();
167
168 if (const Record *R = Ptr.getRecord())
169 return CheckFieldsInitialized(S, Loc: InitLoc, BasePtr: 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
178static 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(X: 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(Off: F.Offset);
197 assert(FieldPtr.block() == Ptr.block());
198 collectBlocks(Ptr: 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(key: Pointee.block()))
203 collectBlocks(Ptr: 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(Idx: I).deref<Pointer>();
208 if (isUsefulPtr(ElemPointee) && !Blocks.contains(key: ElemPointee.block()))
209 collectBlocks(Ptr: ElemPointee, Blocks);
210 }
211 } else if (Desc->isCompositeArray()) {
212 for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
213 const Pointer &ElemPtr = Ptr.atIndex(Idx: I).narrow();
214 collectBlocks(Ptr: ElemPtr, Blocks);
215 }
216 }
217}
218
219bool 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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of clang/lib/AST/ByteCode/EvaluationResult.cpp