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