xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/EvaluationResult.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
187a6dacacSDimitry 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 
397a6dacacSDimitry 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 
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 
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 
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 
148*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 
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 
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