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