Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/EvaluationResult.cpp
213799 views
//===----- EvaluationResult.cpp - Result class for the VM ------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "EvaluationResult.h"9#include "InterpState.h"10#include "Record.h"11#include "llvm/ADT/STLExtras.h"12#include "llvm/ADT/SetVector.h"13#include <iterator>1415namespace clang {16namespace interp {1718APValue EvaluationResult::toAPValue() const {19assert(!empty());20switch (Kind) {21case LValue:22// Either a pointer or a function pointer.23if (const auto *P = std::get_if<Pointer>(&Value))24return P->toAPValue(Ctx->getASTContext());25else if (const auto *FP = std::get_if<FunctionPointer>(&Value))26return FP->toAPValue(Ctx->getASTContext());27else28llvm_unreachable("Unhandled LValue type");29break;30case RValue:31return std::get<APValue>(Value);32case Valid:33return APValue();34default:35llvm_unreachable("Unhandled result kind?");36}37}3839std::optional<APValue> EvaluationResult::toRValue() const {40if (Kind == RValue)41return toAPValue();4243assert(Kind == LValue);4445// We have a pointer and want an RValue.46if (const auto *P = std::get_if<Pointer>(&Value))47return P->toRValue(*Ctx, getSourceType());48else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope49return FP->toAPValue(Ctx->getASTContext());50llvm_unreachable("Unhandled lvalue kind");51}5253static void DiagnoseUninitializedSubobject(InterpState &S, SourceLocation Loc,54const FieldDecl *SubObjDecl) {55assert(SubObjDecl && "Subobject declaration does not exist");56S.FFDiag(Loc, diag::note_constexpr_uninitialized)57<< /*(name)*/ 1 << SubObjDecl;58S.Note(SubObjDecl->getLocation(),59diag::note_constexpr_subobject_declared_here);60}6162static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,63const Pointer &BasePtr, const Record *R);6465static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc,66const Pointer &BasePtr,67const ConstantArrayType *CAT) {68bool Result = true;69size_t NumElems = CAT->getZExtSize();70QualType ElemType = CAT->getElementType();7172if (ElemType->isRecordType()) {73const Record *R = BasePtr.getElemRecord();74for (size_t I = 0; I != NumElems; ++I) {75Pointer ElemPtr = BasePtr.atIndex(I).narrow();76Result &= CheckFieldsInitialized(S, Loc, ElemPtr, R);77}78} else if (const auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) {79for (size_t I = 0; I != NumElems; ++I) {80Pointer ElemPtr = BasePtr.atIndex(I).narrow();81Result &= CheckArrayInitialized(S, Loc, ElemPtr, ElemCAT);82}83} else {84for (size_t I = 0; I != NumElems; ++I) {85if (!BasePtr.atIndex(I).isInitialized()) {86DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField());87Result = false;88}89}90}9192return Result;93}9495static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,96const Pointer &BasePtr, const Record *R) {97assert(R);98bool Result = true;99// Check all fields of this record are initialized.100for (const Record::Field &F : R->fields()) {101Pointer FieldPtr = BasePtr.atField(F.Offset);102QualType FieldType = F.Decl->getType();103104// Don't check inactive union members.105if (R->isUnion() && !FieldPtr.isActive())106continue;107108if (FieldType->isRecordType()) {109Result &= CheckFieldsInitialized(S, Loc, FieldPtr, FieldPtr.getRecord());110} else if (FieldType->isIncompleteArrayType()) {111// Nothing to do here.112} else if (F.Decl->isUnnamedBitField()) {113// Nothing do do here.114} else if (FieldType->isArrayType()) {115const auto *CAT =116cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe());117Result &= CheckArrayInitialized(S, Loc, FieldPtr, CAT);118} else if (!FieldPtr.isInitialized()) {119DiagnoseUninitializedSubobject(S, Loc, F.Decl);120Result = false;121}122}123124// Check Fields in all bases125for (auto [I, B] : llvm::enumerate(R->bases())) {126Pointer P = BasePtr.atField(B.Offset);127if (!P.isInitialized()) {128const Descriptor *Desc = BasePtr.getDeclDesc();129if (const auto *CD = dyn_cast_if_present<CXXRecordDecl>(R->getDecl())) {130const auto &BS = *std::next(CD->bases_begin(), I);131SourceLocation TypeBeginLoc = BS.getBaseTypeLoc();132S.FFDiag(TypeBeginLoc, diag::note_constexpr_uninitialized_base)133<< B.Desc->getType() << SourceRange(TypeBeginLoc, BS.getEndLoc());134} else {135S.FFDiag(Desc->getLocation(), diag::note_constexpr_uninitialized_base)136<< B.Desc->getType();137}138return false;139}140Result &= CheckFieldsInitialized(S, Loc, P, B.R);141}142143// TODO: Virtual bases144145return Result;146}147148bool EvaluationResult::checkFullyInitialized(InterpState &S,149const Pointer &Ptr) const {150assert(Source);151assert(empty());152153if (Ptr.isZero())154return true;155156// We can't inspect dead pointers at all. Return true here so we can157// diagnose them later.158if (!Ptr.isLive())159return true;160161SourceLocation InitLoc;162if (const auto *D = dyn_cast<const Decl *>(Source))163InitLoc = cast<VarDecl>(D)->getAnyInitializer()->getExprLoc();164else if (const auto *E = dyn_cast<const Expr *>(Source))165InitLoc = E->getExprLoc();166167if (const Record *R = Ptr.getRecord())168return CheckFieldsInitialized(S, InitLoc, Ptr, R);169170if (const auto *CAT = dyn_cast_if_present<ConstantArrayType>(171Ptr.getType()->getAsArrayTypeUnsafe()))172return CheckArrayInitialized(S, InitLoc, Ptr, CAT);173174return true;175}176177static void collectBlocks(const Pointer &Ptr,178llvm::SetVector<const Block *> &Blocks) {179auto isUsefulPtr = [](const Pointer &P) -> bool {180return P.isLive() && !P.isZero() && !P.isDummy() && P.isDereferencable() &&181!P.isUnknownSizeArray() && !P.isOnePastEnd();182};183184if (!isUsefulPtr(Ptr))185return;186187Blocks.insert(Ptr.block());188189const Descriptor *Desc = Ptr.getFieldDesc();190if (!Desc)191return;192193if (const Record *R = Desc->ElemRecord) {194for (const Record::Field &F : R->fields()) {195const Pointer &FieldPtr = Ptr.atField(F.Offset);196assert(FieldPtr.block() == Ptr.block());197collectBlocks(FieldPtr, Blocks);198}199} else if (Desc->isPrimitive() && Desc->getPrimType() == PT_Ptr) {200const Pointer &Pointee = Ptr.deref<Pointer>();201if (isUsefulPtr(Pointee) && !Blocks.contains(Pointee.block()))202collectBlocks(Pointee, Blocks);203204} else if (Desc->isPrimitiveArray() && Desc->getPrimType() == PT_Ptr) {205for (unsigned I = 0; I != Desc->getNumElems(); ++I) {206const Pointer &ElemPointee = Ptr.atIndex(I).deref<Pointer>();207if (isUsefulPtr(ElemPointee) && !Blocks.contains(ElemPointee.block()))208collectBlocks(ElemPointee, Blocks);209}210} else if (Desc->isCompositeArray()) {211for (unsigned I = 0; I != Desc->getNumElems(); ++I) {212const Pointer &ElemPtr = Ptr.atIndex(I).narrow();213collectBlocks(ElemPtr, Blocks);214}215}216}217218bool EvaluationResult::checkReturnValue(InterpState &S, const Context &Ctx,219const Pointer &Ptr,220const SourceInfo &Info) {221// Collect all blocks that this pointer (transitively) points to and222// return false if any of them is a dynamic block.223llvm::SetVector<const Block *> Blocks;224225collectBlocks(Ptr, Blocks);226227for (const Block *B : Blocks) {228if (B->isDynamic()) {229assert(B->getDescriptor());230assert(B->getDescriptor()->asExpr());231232bool IsSubobj = !Ptr.isRoot() || Ptr.isArrayElement();233S.FFDiag(Info, diag::note_constexpr_dynamic_alloc)234<< Ptr.getType()->isReferenceType() << IsSubobj;235S.Note(B->getDescriptor()->asExpr()->getExprLoc(),236diag::note_constexpr_dynamic_alloc_here);237return false;238}239}240241return true;242}243244} // namespace interp245} // namespace clang246247248