brintos

brintos / llvm-project-archived public Read only

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