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