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
toAPValue() const18 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
toRValue() const39 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
DiagnoseUninitializedSubobject(InterpState & S,SourceLocation Loc,const FieldDecl * SubObjDecl)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
CheckArrayInitialized(InterpState & S,SourceLocation Loc,const Pointer & BasePtr,const ConstantArrayType * CAT)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
CheckFieldsInitialized(InterpState & S,SourceLocation Loc,const Pointer & BasePtr,const Record * R)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
checkFullyInitialized(InterpState & S,const Pointer & Ptr) const148 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
collectBlocks(const Pointer & Ptr,llvm::SetVector<const Block * > & Blocks)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
checkReturnValue(InterpState & S,const Context & Ctx,const Pointer & Ptr,const SourceInfo & Info)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