Path: blob/main/contrib/llvm-project/clang/lib/AST/Interp/EvaluationResult.cpp
35292 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 "clang/AST/ExprCXX.h"12#include "llvm/ADT/SetVector.h"1314namespace clang {15namespace interp {1617APValue EvaluationResult::toAPValue() const {18assert(!empty());19switch (Kind) {20case LValue:21// Either a pointer or a function pointer.22if (const auto *P = std::get_if<Pointer>(&Value))23return P->toAPValue(Ctx->getASTContext());24else if (const auto *FP = std::get_if<FunctionPointer>(&Value))25return FP->toAPValue(Ctx->getASTContext());26else27llvm_unreachable("Unhandled LValue type");28break;29case RValue:30return std::get<APValue>(Value);31case Valid:32return APValue();33default:34llvm_unreachable("Unhandled result kind?");35}36}3738std::optional<APValue> EvaluationResult::toRValue() const {39if (Kind == RValue)40return toAPValue();4142assert(Kind == LValue);4344// We have a pointer and want an RValue.45if (const auto *P = std::get_if<Pointer>(&Value))46return P->toRValue(*Ctx, getSourceType());47else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope48return FP->toAPValue(Ctx->getASTContext());49llvm_unreachable("Unhandled lvalue kind");50}5152static void DiagnoseUninitializedSubobject(InterpState &S, SourceLocation Loc,53const FieldDecl *SubObjDecl) {54assert(SubObjDecl && "Subobject declaration does not exist");55S.FFDiag(Loc, diag::note_constexpr_uninitialized)56<< /*(name)*/ 1 << SubObjDecl;57S.Note(SubObjDecl->getLocation(),58diag::note_constexpr_subobject_declared_here);59}6061static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,62const Pointer &BasePtr, const Record *R);6364static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc,65const Pointer &BasePtr,66const ConstantArrayType *CAT) {67bool Result = true;68size_t NumElems = CAT->getZExtSize();69QualType ElemType = CAT->getElementType();7071if (ElemType->isRecordType()) {72const Record *R = BasePtr.getElemRecord();73for (size_t I = 0; I != NumElems; ++I) {74Pointer ElemPtr = BasePtr.atIndex(I).narrow();75Result &= CheckFieldsInitialized(S, Loc, ElemPtr, R);76}77} else if (const auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) {78for (size_t I = 0; I != NumElems; ++I) {79Pointer ElemPtr = BasePtr.atIndex(I).narrow();80Result &= CheckArrayInitialized(S, Loc, ElemPtr, ElemCAT);81}82} else {83for (size_t I = 0; I != NumElems; ++I) {84if (!BasePtr.atIndex(I).isInitialized()) {85DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField());86Result = false;87}88}89}9091return Result;92}9394static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,95const Pointer &BasePtr, const Record *R) {96assert(R);97bool Result = true;98// Check all fields of this record are initialized.99for (const Record::Field &F : R->fields()) {100Pointer FieldPtr = BasePtr.atField(F.Offset);101QualType FieldType = F.Decl->getType();102103// Don't check inactive union members.104if (R->isUnion() && !FieldPtr.isActive())105continue;106107if (FieldType->isRecordType()) {108Result &= CheckFieldsInitialized(S, Loc, FieldPtr, FieldPtr.getRecord());109} else if (FieldType->isIncompleteArrayType()) {110// Nothing to do here.111} else if (F.Decl->isUnnamedBitField()) {112// Nothing do do here.113} else if (FieldType->isArrayType()) {114const auto *CAT =115cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe());116Result &= CheckArrayInitialized(S, Loc, FieldPtr, CAT);117} else if (!FieldPtr.isInitialized()) {118DiagnoseUninitializedSubobject(S, Loc, F.Decl);119Result = false;120}121}122123// Check Fields in all bases124for (const Record::Base &B : R->bases()) {125Pointer P = BasePtr.atField(B.Offset);126if (!P.isInitialized()) {127const Descriptor *Desc = BasePtr.getDeclDesc();128if (Desc->asDecl())129S.FFDiag(BasePtr.getDeclDesc()->asDecl()->getLocation(),130diag::note_constexpr_uninitialized_base)131<< B.Desc->getType();132else133S.FFDiag(BasePtr.getDeclDesc()->asExpr()->getExprLoc(),134diag::note_constexpr_uninitialized_base)135<< B.Desc->getType();136137return false;138}139Result &= CheckFieldsInitialized(S, Loc, P, B.R);140}141142// TODO: Virtual bases143144return Result;145}146147bool EvaluationResult::checkFullyInitialized(InterpState &S,148const Pointer &Ptr) const {149assert(Source);150assert(empty());151152if (Ptr.isZero())153return true;154155// We can't inspect dead pointers at all. Return true here so we can156// diagnose them later.157if (!Ptr.isLive())158return true;159160SourceLocation InitLoc;161if (const auto *D = Source.dyn_cast<const Decl *>())162InitLoc = cast<VarDecl>(D)->getAnyInitializer()->getExprLoc();163else if (const auto *E = Source.dyn_cast<const Expr *>())164InitLoc = E->getExprLoc();165166if (const Record *R = Ptr.getRecord())167return CheckFieldsInitialized(S, InitLoc, Ptr, R);168169if (const auto *CAT = dyn_cast_if_present<ConstantArrayType>(170Ptr.getType()->getAsArrayTypeUnsafe()))171return CheckArrayInitialized(S, InitLoc, Ptr, CAT);172173return true;174}175176static void collectBlocks(const Pointer &Ptr,177llvm::SetVector<const Block *> &Blocks) {178auto isUsefulPtr = [](const Pointer &P) -> bool {179return P.isLive() && !P.isZero() && !P.isDummy() &&180!P.isUnknownSizeArray() && !P.isOnePastEnd() && P.isBlockPointer();181};182183if (!isUsefulPtr(Ptr))184return;185186Blocks.insert(Ptr.block());187188const Descriptor *Desc = Ptr.getFieldDesc();189if (!Desc)190return;191192if (const Record *R = Desc->ElemRecord) {193for (const Record::Field &F : R->fields()) {194const Pointer &FieldPtr = Ptr.atField(F.Offset);195assert(FieldPtr.block() == Ptr.block());196collectBlocks(FieldPtr, Blocks);197}198} else if (Desc->isPrimitive() && Desc->getPrimType() == PT_Ptr) {199const Pointer &Pointee = Ptr.deref<Pointer>();200if (isUsefulPtr(Pointee) && !Blocks.contains(Pointee.block()))201collectBlocks(Pointee, Blocks);202203} else if (Desc->isPrimitiveArray() && Desc->getPrimType() == PT_Ptr) {204for (unsigned I = 0; I != Desc->getNumElems(); ++I) {205const Pointer &ElemPointee = Ptr.atIndex(I).deref<Pointer>();206if (isUsefulPtr(ElemPointee) && !Blocks.contains(ElemPointee.block()))207collectBlocks(ElemPointee, Blocks);208}209} else if (Desc->isCompositeArray()) {210for (unsigned I = 0; I != Desc->getNumElems(); ++I) {211const Pointer &ElemPtr = Ptr.atIndex(I).narrow();212collectBlocks(ElemPtr, Blocks);213}214}215}216217bool EvaluationResult::checkReturnValue(InterpState &S, const Context &Ctx,218const Pointer &Ptr,219const SourceInfo &Info) {220// Collect all blocks that this pointer (transitively) points to and221// return false if any of them is a dynamic block.222llvm::SetVector<const Block *> Blocks;223224collectBlocks(Ptr, Blocks);225226for (const Block *B : Blocks) {227if (B->isDynamic()) {228assert(B->getDescriptor());229assert(B->getDescriptor()->asExpr());230231S.FFDiag(Info, diag::note_constexpr_dynamic_alloc)232<< Ptr.getType()->isReferenceType() << !Ptr.isRoot();233S.Note(B->getDescriptor()->asExpr()->getExprLoc(),234diag::note_constexpr_dynamic_alloc_here);235return false;236}237}238239return true;240}241242} // namespace interp243} // namespace clang244245246