17a6dacacSDimitry Andric //===----- EvaluationResult.cpp - Result class for the VM ------*- C++ -*-===//
27a6dacacSDimitry Andric //
37a6dacacSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47a6dacacSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
57a6dacacSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67a6dacacSDimitry Andric //
77a6dacacSDimitry Andric //===----------------------------------------------------------------------===//
87a6dacacSDimitry Andric
97a6dacacSDimitry Andric #include "EvaluationResult.h"
107a6dacacSDimitry Andric #include "InterpState.h"
117a6dacacSDimitry Andric #include "Record.h"
127a6dacacSDimitry Andric #include "clang/AST/ExprCXX.h"
13*0fca6ea1SDimitry Andric #include "llvm/ADT/SetVector.h"
147a6dacacSDimitry Andric
157a6dacacSDimitry Andric namespace clang {
167a6dacacSDimitry Andric namespace interp {
177a6dacacSDimitry Andric
toAPValue() const187a6dacacSDimitry Andric APValue EvaluationResult::toAPValue() const {
197a6dacacSDimitry Andric assert(!empty());
207a6dacacSDimitry Andric switch (Kind) {
217a6dacacSDimitry Andric case LValue:
227a6dacacSDimitry Andric // Either a pointer or a function pointer.
237a6dacacSDimitry Andric if (const auto *P = std::get_if<Pointer>(&Value))
24*0fca6ea1SDimitry Andric return P->toAPValue(Ctx->getASTContext());
257a6dacacSDimitry Andric else if (const auto *FP = std::get_if<FunctionPointer>(&Value))
26*0fca6ea1SDimitry Andric return FP->toAPValue(Ctx->getASTContext());
277a6dacacSDimitry Andric else
287a6dacacSDimitry Andric llvm_unreachable("Unhandled LValue type");
297a6dacacSDimitry Andric break;
307a6dacacSDimitry Andric case RValue:
317a6dacacSDimitry Andric return std::get<APValue>(Value);
327a6dacacSDimitry Andric case Valid:
337a6dacacSDimitry Andric return APValue();
347a6dacacSDimitry Andric default:
357a6dacacSDimitry Andric llvm_unreachable("Unhandled result kind?");
367a6dacacSDimitry Andric }
377a6dacacSDimitry Andric }
387a6dacacSDimitry Andric
toRValue() const397a6dacacSDimitry Andric std::optional<APValue> EvaluationResult::toRValue() const {
407a6dacacSDimitry Andric if (Kind == RValue)
417a6dacacSDimitry Andric return toAPValue();
427a6dacacSDimitry Andric
437a6dacacSDimitry Andric assert(Kind == LValue);
447a6dacacSDimitry Andric
457a6dacacSDimitry Andric // We have a pointer and want an RValue.
467a6dacacSDimitry Andric if (const auto *P = std::get_if<Pointer>(&Value))
47*0fca6ea1SDimitry Andric return P->toRValue(*Ctx, getSourceType());
487a6dacacSDimitry Andric else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
49*0fca6ea1SDimitry Andric return FP->toAPValue(Ctx->getASTContext());
507a6dacacSDimitry Andric llvm_unreachable("Unhandled lvalue kind");
517a6dacacSDimitry Andric }
527a6dacacSDimitry Andric
DiagnoseUninitializedSubobject(InterpState & S,SourceLocation Loc,const FieldDecl * SubObjDecl)537a6dacacSDimitry Andric static void DiagnoseUninitializedSubobject(InterpState &S, SourceLocation Loc,
547a6dacacSDimitry Andric const FieldDecl *SubObjDecl) {
557a6dacacSDimitry Andric assert(SubObjDecl && "Subobject declaration does not exist");
567a6dacacSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_uninitialized)
577a6dacacSDimitry Andric << /*(name)*/ 1 << SubObjDecl;
587a6dacacSDimitry Andric S.Note(SubObjDecl->getLocation(),
597a6dacacSDimitry Andric diag::note_constexpr_subobject_declared_here);
607a6dacacSDimitry Andric }
617a6dacacSDimitry Andric
627a6dacacSDimitry Andric static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
637a6dacacSDimitry Andric const Pointer &BasePtr, const Record *R);
647a6dacacSDimitry Andric
CheckArrayInitialized(InterpState & S,SourceLocation Loc,const Pointer & BasePtr,const ConstantArrayType * CAT)657a6dacacSDimitry Andric static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc,
667a6dacacSDimitry Andric const Pointer &BasePtr,
677a6dacacSDimitry Andric const ConstantArrayType *CAT) {
687a6dacacSDimitry Andric bool Result = true;
69*0fca6ea1SDimitry Andric size_t NumElems = CAT->getZExtSize();
707a6dacacSDimitry Andric QualType ElemType = CAT->getElementType();
717a6dacacSDimitry Andric
727a6dacacSDimitry Andric if (ElemType->isRecordType()) {
737a6dacacSDimitry Andric const Record *R = BasePtr.getElemRecord();
747a6dacacSDimitry Andric for (size_t I = 0; I != NumElems; ++I) {
757a6dacacSDimitry Andric Pointer ElemPtr = BasePtr.atIndex(I).narrow();
767a6dacacSDimitry Andric Result &= CheckFieldsInitialized(S, Loc, ElemPtr, R);
777a6dacacSDimitry Andric }
787a6dacacSDimitry Andric } else if (const auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) {
797a6dacacSDimitry Andric for (size_t I = 0; I != NumElems; ++I) {
807a6dacacSDimitry Andric Pointer ElemPtr = BasePtr.atIndex(I).narrow();
817a6dacacSDimitry Andric Result &= CheckArrayInitialized(S, Loc, ElemPtr, ElemCAT);
827a6dacacSDimitry Andric }
837a6dacacSDimitry Andric } else {
847a6dacacSDimitry Andric for (size_t I = 0; I != NumElems; ++I) {
857a6dacacSDimitry Andric if (!BasePtr.atIndex(I).isInitialized()) {
867a6dacacSDimitry Andric DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField());
877a6dacacSDimitry Andric Result = false;
887a6dacacSDimitry Andric }
897a6dacacSDimitry Andric }
907a6dacacSDimitry Andric }
917a6dacacSDimitry Andric
927a6dacacSDimitry Andric return Result;
937a6dacacSDimitry Andric }
947a6dacacSDimitry Andric
CheckFieldsInitialized(InterpState & S,SourceLocation Loc,const Pointer & BasePtr,const Record * R)957a6dacacSDimitry Andric static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
967a6dacacSDimitry Andric const Pointer &BasePtr, const Record *R) {
977a6dacacSDimitry Andric assert(R);
987a6dacacSDimitry Andric bool Result = true;
997a6dacacSDimitry Andric // Check all fields of this record are initialized.
1007a6dacacSDimitry Andric for (const Record::Field &F : R->fields()) {
1017a6dacacSDimitry Andric Pointer FieldPtr = BasePtr.atField(F.Offset);
1027a6dacacSDimitry Andric QualType FieldType = F.Decl->getType();
1037a6dacacSDimitry Andric
104*0fca6ea1SDimitry Andric // Don't check inactive union members.
105*0fca6ea1SDimitry Andric if (R->isUnion() && !FieldPtr.isActive())
106*0fca6ea1SDimitry Andric continue;
107*0fca6ea1SDimitry Andric
1087a6dacacSDimitry Andric if (FieldType->isRecordType()) {
1097a6dacacSDimitry Andric Result &= CheckFieldsInitialized(S, Loc, FieldPtr, FieldPtr.getRecord());
1107a6dacacSDimitry Andric } else if (FieldType->isIncompleteArrayType()) {
1117a6dacacSDimitry Andric // Nothing to do here.
112*0fca6ea1SDimitry Andric } else if (F.Decl->isUnnamedBitField()) {
113*0fca6ea1SDimitry Andric // Nothing do do here.
1147a6dacacSDimitry Andric } else if (FieldType->isArrayType()) {
1157a6dacacSDimitry Andric const auto *CAT =
1167a6dacacSDimitry Andric cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe());
1177a6dacacSDimitry Andric Result &= CheckArrayInitialized(S, Loc, FieldPtr, CAT);
1187a6dacacSDimitry Andric } else if (!FieldPtr.isInitialized()) {
1197a6dacacSDimitry Andric DiagnoseUninitializedSubobject(S, Loc, F.Decl);
1207a6dacacSDimitry Andric Result = false;
1217a6dacacSDimitry Andric }
1227a6dacacSDimitry Andric }
1237a6dacacSDimitry Andric
1247a6dacacSDimitry Andric // Check Fields in all bases
1257a6dacacSDimitry Andric for (const Record::Base &B : R->bases()) {
1267a6dacacSDimitry Andric Pointer P = BasePtr.atField(B.Offset);
1277a6dacacSDimitry Andric if (!P.isInitialized()) {
128*0fca6ea1SDimitry Andric const Descriptor *Desc = BasePtr.getDeclDesc();
129*0fca6ea1SDimitry Andric if (Desc->asDecl())
1307a6dacacSDimitry Andric S.FFDiag(BasePtr.getDeclDesc()->asDecl()->getLocation(),
1317a6dacacSDimitry Andric diag::note_constexpr_uninitialized_base)
1327a6dacacSDimitry Andric << B.Desc->getType();
133*0fca6ea1SDimitry Andric else
134*0fca6ea1SDimitry Andric S.FFDiag(BasePtr.getDeclDesc()->asExpr()->getExprLoc(),
135*0fca6ea1SDimitry Andric diag::note_constexpr_uninitialized_base)
136*0fca6ea1SDimitry Andric << B.Desc->getType();
137*0fca6ea1SDimitry Andric
1387a6dacacSDimitry Andric return false;
1397a6dacacSDimitry Andric }
1407a6dacacSDimitry Andric Result &= CheckFieldsInitialized(S, Loc, P, B.R);
1417a6dacacSDimitry Andric }
1427a6dacacSDimitry Andric
1437a6dacacSDimitry Andric // TODO: Virtual bases
1447a6dacacSDimitry Andric
1457a6dacacSDimitry Andric return Result;
1467a6dacacSDimitry Andric }
1477a6dacacSDimitry Andric
checkFullyInitialized(InterpState & S,const Pointer & Ptr) const148*0fca6ea1SDimitry Andric bool EvaluationResult::checkFullyInitialized(InterpState &S,
149*0fca6ea1SDimitry Andric const Pointer &Ptr) const {
1507a6dacacSDimitry Andric assert(Source);
151*0fca6ea1SDimitry Andric assert(empty());
1527a6dacacSDimitry Andric
153*0fca6ea1SDimitry Andric if (Ptr.isZero())
154*0fca6ea1SDimitry Andric return true;
1557a6dacacSDimitry Andric
156*0fca6ea1SDimitry Andric // We can't inspect dead pointers at all. Return true here so we can
157*0fca6ea1SDimitry Andric // diagnose them later.
158*0fca6ea1SDimitry Andric if (!Ptr.isLive())
159*0fca6ea1SDimitry Andric return true;
160*0fca6ea1SDimitry Andric
161*0fca6ea1SDimitry Andric SourceLocation InitLoc;
162*0fca6ea1SDimitry Andric if (const auto *D = Source.dyn_cast<const Decl *>())
163*0fca6ea1SDimitry Andric InitLoc = cast<VarDecl>(D)->getAnyInitializer()->getExprLoc();
164*0fca6ea1SDimitry Andric else if (const auto *E = Source.dyn_cast<const Expr *>())
165*0fca6ea1SDimitry Andric InitLoc = E->getExprLoc();
1667a6dacacSDimitry Andric
1677a6dacacSDimitry Andric if (const Record *R = Ptr.getRecord())
1687a6dacacSDimitry Andric return CheckFieldsInitialized(S, InitLoc, Ptr, R);
169*0fca6ea1SDimitry Andric
170*0fca6ea1SDimitry Andric if (const auto *CAT = dyn_cast_if_present<ConstantArrayType>(
171*0fca6ea1SDimitry Andric Ptr.getType()->getAsArrayTypeUnsafe()))
1727a6dacacSDimitry Andric return CheckArrayInitialized(S, InitLoc, Ptr, CAT);
1737a6dacacSDimitry Andric
1747a6dacacSDimitry Andric return true;
1757a6dacacSDimitry Andric }
1767a6dacacSDimitry Andric
collectBlocks(const Pointer & Ptr,llvm::SetVector<const Block * > & Blocks)177*0fca6ea1SDimitry Andric static void collectBlocks(const Pointer &Ptr,
178*0fca6ea1SDimitry Andric llvm::SetVector<const Block *> &Blocks) {
179*0fca6ea1SDimitry Andric auto isUsefulPtr = [](const Pointer &P) -> bool {
180*0fca6ea1SDimitry Andric return P.isLive() && !P.isZero() && !P.isDummy() &&
181*0fca6ea1SDimitry Andric !P.isUnknownSizeArray() && !P.isOnePastEnd() && P.isBlockPointer();
182*0fca6ea1SDimitry Andric };
1837a6dacacSDimitry Andric
184*0fca6ea1SDimitry Andric if (!isUsefulPtr(Ptr))
185*0fca6ea1SDimitry Andric return;
186*0fca6ea1SDimitry Andric
187*0fca6ea1SDimitry Andric Blocks.insert(Ptr.block());
188*0fca6ea1SDimitry Andric
189*0fca6ea1SDimitry Andric const Descriptor *Desc = Ptr.getFieldDesc();
190*0fca6ea1SDimitry Andric if (!Desc)
191*0fca6ea1SDimitry Andric return;
192*0fca6ea1SDimitry Andric
193*0fca6ea1SDimitry Andric if (const Record *R = Desc->ElemRecord) {
194*0fca6ea1SDimitry Andric for (const Record::Field &F : R->fields()) {
195*0fca6ea1SDimitry Andric const Pointer &FieldPtr = Ptr.atField(F.Offset);
196*0fca6ea1SDimitry Andric assert(FieldPtr.block() == Ptr.block());
197*0fca6ea1SDimitry Andric collectBlocks(FieldPtr, Blocks);
198*0fca6ea1SDimitry Andric }
199*0fca6ea1SDimitry Andric } else if (Desc->isPrimitive() && Desc->getPrimType() == PT_Ptr) {
200*0fca6ea1SDimitry Andric const Pointer &Pointee = Ptr.deref<Pointer>();
201*0fca6ea1SDimitry Andric if (isUsefulPtr(Pointee) && !Blocks.contains(Pointee.block()))
202*0fca6ea1SDimitry Andric collectBlocks(Pointee, Blocks);
203*0fca6ea1SDimitry Andric
204*0fca6ea1SDimitry Andric } else if (Desc->isPrimitiveArray() && Desc->getPrimType() == PT_Ptr) {
205*0fca6ea1SDimitry Andric for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
206*0fca6ea1SDimitry Andric const Pointer &ElemPointee = Ptr.atIndex(I).deref<Pointer>();
207*0fca6ea1SDimitry Andric if (isUsefulPtr(ElemPointee) && !Blocks.contains(ElemPointee.block()))
208*0fca6ea1SDimitry Andric collectBlocks(ElemPointee, Blocks);
209*0fca6ea1SDimitry Andric }
210*0fca6ea1SDimitry Andric } else if (Desc->isCompositeArray()) {
211*0fca6ea1SDimitry Andric for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
212*0fca6ea1SDimitry Andric const Pointer &ElemPtr = Ptr.atIndex(I).narrow();
213*0fca6ea1SDimitry Andric collectBlocks(ElemPtr, Blocks);
214*0fca6ea1SDimitry Andric }
215*0fca6ea1SDimitry Andric }
2167a6dacacSDimitry Andric }
2177a6dacacSDimitry Andric
checkReturnValue(InterpState & S,const Context & Ctx,const Pointer & Ptr,const SourceInfo & Info)218*0fca6ea1SDimitry Andric bool EvaluationResult::checkReturnValue(InterpState &S, const Context &Ctx,
219*0fca6ea1SDimitry Andric const Pointer &Ptr,
220*0fca6ea1SDimitry Andric const SourceInfo &Info) {
221*0fca6ea1SDimitry Andric // Collect all blocks that this pointer (transitively) points to and
222*0fca6ea1SDimitry Andric // return false if any of them is a dynamic block.
223*0fca6ea1SDimitry Andric llvm::SetVector<const Block *> Blocks;
224*0fca6ea1SDimitry Andric
225*0fca6ea1SDimitry Andric collectBlocks(Ptr, Blocks);
226*0fca6ea1SDimitry Andric
227*0fca6ea1SDimitry Andric for (const Block *B : Blocks) {
228*0fca6ea1SDimitry Andric if (B->isDynamic()) {
229*0fca6ea1SDimitry Andric assert(B->getDescriptor());
230*0fca6ea1SDimitry Andric assert(B->getDescriptor()->asExpr());
231*0fca6ea1SDimitry Andric
232*0fca6ea1SDimitry Andric S.FFDiag(Info, diag::note_constexpr_dynamic_alloc)
233*0fca6ea1SDimitry Andric << Ptr.getType()->isReferenceType() << !Ptr.isRoot();
234*0fca6ea1SDimitry Andric S.Note(B->getDescriptor()->asExpr()->getExprLoc(),
235*0fca6ea1SDimitry Andric diag::note_constexpr_dynamic_alloc_here);
236*0fca6ea1SDimitry Andric return false;
237*0fca6ea1SDimitry Andric }
2387a6dacacSDimitry Andric }
2397a6dacacSDimitry Andric
240*0fca6ea1SDimitry Andric return true;
2417a6dacacSDimitry Andric }
2427a6dacacSDimitry Andric
2437a6dacacSDimitry Andric } // namespace interp
2447a6dacacSDimitry Andric } // namespace clang
245