diff options
Diffstat (limited to 'clang/lib/AST/APValue.cpp')
| -rw-r--r-- | clang/lib/AST/APValue.cpp | 841 | 
1 files changed, 841 insertions, 0 deletions
| diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp new file mode 100644 index 000000000000..50f8d05dacb4 --- /dev/null +++ b/clang/lib/AST/APValue.cpp @@ -0,0 +1,841 @@ +//===--- APValue.cpp - Union class for APFloat/APSInt/Complex -------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +//  This file implements the APValue class. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/APValue.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/CharUnits.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +/// The identity of a type_info object depends on the canonical unqualified +/// type only. +TypeInfoLValue::TypeInfoLValue(const Type *T) +    : T(T->getCanonicalTypeUnqualified().getTypePtr()) {} + +void TypeInfoLValue::print(llvm::raw_ostream &Out, +                           const PrintingPolicy &Policy) const { +  Out << "typeid("; +  QualType(getType(), 0).print(Out, Policy); +  Out << ")"; +} + +static_assert( +    1 << llvm::PointerLikeTypeTraits<TypeInfoLValue>::NumLowBitsAvailable <= +        alignof(Type), +    "Type is insufficiently aligned"); + +APValue::LValueBase::LValueBase(const ValueDecl *P, unsigned I, unsigned V) +    : Ptr(P), Local{I, V} {} +APValue::LValueBase::LValueBase(const Expr *P, unsigned I, unsigned V) +    : Ptr(P), Local{I, V} {} + +APValue::LValueBase APValue::LValueBase::getDynamicAlloc(DynamicAllocLValue LV, +                                                         QualType Type) { +  LValueBase Base; +  Base.Ptr = LV; +  Base.DynamicAllocType = Type.getAsOpaquePtr(); +  return Base; +} + +APValue::LValueBase APValue::LValueBase::getTypeInfo(TypeInfoLValue LV, +                                                     QualType TypeInfo) { +  LValueBase Base; +  Base.Ptr = LV; +  Base.TypeInfoType = TypeInfo.getAsOpaquePtr(); +  return Base; +} + +unsigned APValue::LValueBase::getCallIndex() const { +  return (is<TypeInfoLValue>() || is<DynamicAllocLValue>()) ? 0 +                                                            : Local.CallIndex; +} + +unsigned APValue::LValueBase::getVersion() const { +  return (is<TypeInfoLValue>() || is<DynamicAllocLValue>()) ? 0 : Local.Version; +} + +QualType APValue::LValueBase::getTypeInfoType() const { +  assert(is<TypeInfoLValue>() && "not a type_info lvalue"); +  return QualType::getFromOpaquePtr(TypeInfoType); +} + +QualType APValue::LValueBase::getDynamicAllocType() const { +  assert(is<DynamicAllocLValue>() && "not a dynamic allocation lvalue"); +  return QualType::getFromOpaquePtr(DynamicAllocType); +} + +namespace clang { +bool operator==(const APValue::LValueBase &LHS, +                const APValue::LValueBase &RHS) { +  if (LHS.Ptr != RHS.Ptr) +    return false; +  if (LHS.is<TypeInfoLValue>()) +    return true; +  return LHS.Local.CallIndex == RHS.Local.CallIndex && +         LHS.Local.Version == RHS.Local.Version; +} +} + +namespace { +  struct LVBase { +    APValue::LValueBase Base; +    CharUnits Offset; +    unsigned PathLength; +    bool IsNullPtr : 1; +    bool IsOnePastTheEnd : 1; +  }; +} + +void *APValue::LValueBase::getOpaqueValue() const { +  return Ptr.getOpaqueValue(); +} + +bool APValue::LValueBase::isNull() const { +  return Ptr.isNull(); +} + +APValue::LValueBase::operator bool () const { +  return static_cast<bool>(Ptr); +} + +clang::APValue::LValueBase +llvm::DenseMapInfo<clang::APValue::LValueBase>::getEmptyKey() { +  return clang::APValue::LValueBase( +      DenseMapInfo<const ValueDecl*>::getEmptyKey()); +} + +clang::APValue::LValueBase +llvm::DenseMapInfo<clang::APValue::LValueBase>::getTombstoneKey() { +  return clang::APValue::LValueBase( +      DenseMapInfo<const ValueDecl*>::getTombstoneKey()); +} + +namespace clang { +llvm::hash_code hash_value(const APValue::LValueBase &Base) { +  if (Base.is<TypeInfoLValue>() || Base.is<DynamicAllocLValue>()) +    return llvm::hash_value(Base.getOpaqueValue()); +  return llvm::hash_combine(Base.getOpaqueValue(), Base.getCallIndex(), +                            Base.getVersion()); +} +} + +unsigned llvm::DenseMapInfo<clang::APValue::LValueBase>::getHashValue( +    const clang::APValue::LValueBase &Base) { +  return hash_value(Base); +} + +bool llvm::DenseMapInfo<clang::APValue::LValueBase>::isEqual( +    const clang::APValue::LValueBase &LHS, +    const clang::APValue::LValueBase &RHS) { +  return LHS == RHS; +} + +struct APValue::LV : LVBase { +  static const unsigned InlinePathSpace = +      (DataSize - sizeof(LVBase)) / sizeof(LValuePathEntry); + +  /// Path - The sequence of base classes, fields and array indices to follow to +  /// walk from Base to the subobject. When performing GCC-style folding, there +  /// may not be such a path. +  union { +    LValuePathEntry Path[InlinePathSpace]; +    LValuePathEntry *PathPtr; +  }; + +  LV() { PathLength = (unsigned)-1; } +  ~LV() { resizePath(0); } + +  void resizePath(unsigned Length) { +    if (Length == PathLength) +      return; +    if (hasPathPtr()) +      delete [] PathPtr; +    PathLength = Length; +    if (hasPathPtr()) +      PathPtr = new LValuePathEntry[Length]; +  } + +  bool hasPath() const { return PathLength != (unsigned)-1; } +  bool hasPathPtr() const { return hasPath() && PathLength > InlinePathSpace; } + +  LValuePathEntry *getPath() { return hasPathPtr() ? PathPtr : Path; } +  const LValuePathEntry *getPath() const { +    return hasPathPtr() ? PathPtr : Path; +  } +}; + +namespace { +  struct MemberPointerBase { +    llvm::PointerIntPair<const ValueDecl*, 1, bool> MemberAndIsDerivedMember; +    unsigned PathLength; +  }; +} + +struct APValue::MemberPointerData : MemberPointerBase { +  static const unsigned InlinePathSpace = +      (DataSize - sizeof(MemberPointerBase)) / sizeof(const CXXRecordDecl*); +  typedef const CXXRecordDecl *PathElem; +  union { +    PathElem Path[InlinePathSpace]; +    PathElem *PathPtr; +  }; + +  MemberPointerData() { PathLength = 0; } +  ~MemberPointerData() { resizePath(0); } + +  void resizePath(unsigned Length) { +    if (Length == PathLength) +      return; +    if (hasPathPtr()) +      delete [] PathPtr; +    PathLength = Length; +    if (hasPathPtr()) +      PathPtr = new PathElem[Length]; +  } + +  bool hasPathPtr() const { return PathLength > InlinePathSpace; } + +  PathElem *getPath() { return hasPathPtr() ? PathPtr : Path; } +  const PathElem *getPath() const { +    return hasPathPtr() ? PathPtr : Path; +  } +}; + +// FIXME: Reduce the malloc traffic here. + +APValue::Arr::Arr(unsigned NumElts, unsigned Size) : +  Elts(new APValue[NumElts + (NumElts != Size ? 1 : 0)]), +  NumElts(NumElts), ArrSize(Size) {} +APValue::Arr::~Arr() { delete [] Elts; } + +APValue::StructData::StructData(unsigned NumBases, unsigned NumFields) : +  Elts(new APValue[NumBases+NumFields]), +  NumBases(NumBases), NumFields(NumFields) {} +APValue::StructData::~StructData() { +  delete [] Elts; +} + +APValue::UnionData::UnionData() : Field(nullptr), Value(new APValue) {} +APValue::UnionData::~UnionData () { +  delete Value; +} + +APValue::APValue(const APValue &RHS) : Kind(None) { +  switch (RHS.getKind()) { +  case None: +  case Indeterminate: +    Kind = RHS.getKind(); +    break; +  case Int: +    MakeInt(); +    setInt(RHS.getInt()); +    break; +  case Float: +    MakeFloat(); +    setFloat(RHS.getFloat()); +    break; +  case FixedPoint: { +    APFixedPoint FXCopy = RHS.getFixedPoint(); +    MakeFixedPoint(std::move(FXCopy)); +    break; +  } +  case Vector: +    MakeVector(); +    setVector(((const Vec *)(const char *)RHS.Data.buffer)->Elts, +              RHS.getVectorLength()); +    break; +  case ComplexInt: +    MakeComplexInt(); +    setComplexInt(RHS.getComplexIntReal(), RHS.getComplexIntImag()); +    break; +  case ComplexFloat: +    MakeComplexFloat(); +    setComplexFloat(RHS.getComplexFloatReal(), RHS.getComplexFloatImag()); +    break; +  case LValue: +    MakeLValue(); +    if (RHS.hasLValuePath()) +      setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), RHS.getLValuePath(), +                RHS.isLValueOnePastTheEnd(), RHS.isNullPointer()); +    else +      setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath(), +                RHS.isNullPointer()); +    break; +  case Array: +    MakeArray(RHS.getArrayInitializedElts(), RHS.getArraySize()); +    for (unsigned I = 0, N = RHS.getArrayInitializedElts(); I != N; ++I) +      getArrayInitializedElt(I) = RHS.getArrayInitializedElt(I); +    if (RHS.hasArrayFiller()) +      getArrayFiller() = RHS.getArrayFiller(); +    break; +  case Struct: +    MakeStruct(RHS.getStructNumBases(), RHS.getStructNumFields()); +    for (unsigned I = 0, N = RHS.getStructNumBases(); I != N; ++I) +      getStructBase(I) = RHS.getStructBase(I); +    for (unsigned I = 0, N = RHS.getStructNumFields(); I != N; ++I) +      getStructField(I) = RHS.getStructField(I); +    break; +  case Union: +    MakeUnion(); +    setUnion(RHS.getUnionField(), RHS.getUnionValue()); +    break; +  case MemberPointer: +    MakeMemberPointer(RHS.getMemberPointerDecl(), +                      RHS.isMemberPointerToDerivedMember(), +                      RHS.getMemberPointerPath()); +    break; +  case AddrLabelDiff: +    MakeAddrLabelDiff(); +    setAddrLabelDiff(RHS.getAddrLabelDiffLHS(), RHS.getAddrLabelDiffRHS()); +    break; +  } +} + +void APValue::DestroyDataAndMakeUninit() { +  if (Kind == Int) +    ((APSInt*)(char*)Data.buffer)->~APSInt(); +  else if (Kind == Float) +    ((APFloat*)(char*)Data.buffer)->~APFloat(); +  else if (Kind == FixedPoint) +    ((APFixedPoint *)(char *)Data.buffer)->~APFixedPoint(); +  else if (Kind == Vector) +    ((Vec*)(char*)Data.buffer)->~Vec(); +  else if (Kind == ComplexInt) +    ((ComplexAPSInt*)(char*)Data.buffer)->~ComplexAPSInt(); +  else if (Kind == ComplexFloat) +    ((ComplexAPFloat*)(char*)Data.buffer)->~ComplexAPFloat(); +  else if (Kind == LValue) +    ((LV*)(char*)Data.buffer)->~LV(); +  else if (Kind == Array) +    ((Arr*)(char*)Data.buffer)->~Arr(); +  else if (Kind == Struct) +    ((StructData*)(char*)Data.buffer)->~StructData(); +  else if (Kind == Union) +    ((UnionData*)(char*)Data.buffer)->~UnionData(); +  else if (Kind == MemberPointer) +    ((MemberPointerData*)(char*)Data.buffer)->~MemberPointerData(); +  else if (Kind == AddrLabelDiff) +    ((AddrLabelDiffData*)(char*)Data.buffer)->~AddrLabelDiffData(); +  Kind = None; +} + +bool APValue::needsCleanup() const { +  switch (getKind()) { +  case None: +  case Indeterminate: +  case AddrLabelDiff: +    return false; +  case Struct: +  case Union: +  case Array: +  case Vector: +    return true; +  case Int: +    return getInt().needsCleanup(); +  case Float: +    return getFloat().needsCleanup(); +  case FixedPoint: +    return getFixedPoint().getValue().needsCleanup(); +  case ComplexFloat: +    assert(getComplexFloatImag().needsCleanup() == +               getComplexFloatReal().needsCleanup() && +           "In _Complex float types, real and imaginary values always have the " +           "same size."); +    return getComplexFloatReal().needsCleanup(); +  case ComplexInt: +    assert(getComplexIntImag().needsCleanup() == +               getComplexIntReal().needsCleanup() && +           "In _Complex int types, real and imaginary values must have the " +           "same size."); +    return getComplexIntReal().needsCleanup(); +  case LValue: +    return reinterpret_cast<const LV *>(Data.buffer)->hasPathPtr(); +  case MemberPointer: +    return reinterpret_cast<const MemberPointerData *>(Data.buffer) +        ->hasPathPtr(); +  } +  llvm_unreachable("Unknown APValue kind!"); +} + +void APValue::swap(APValue &RHS) { +  std::swap(Kind, RHS.Kind); +  char TmpData[DataSize]; +  memcpy(TmpData, Data.buffer, DataSize); +  memcpy(Data.buffer, RHS.Data.buffer, DataSize); +  memcpy(RHS.Data.buffer, TmpData, DataSize); +} + +LLVM_DUMP_METHOD void APValue::dump() const { +  dump(llvm::errs()); +  llvm::errs() << '\n'; +} + +static double GetApproxValue(const llvm::APFloat &F) { +  llvm::APFloat V = F; +  bool ignored; +  V.convert(llvm::APFloat::IEEEdouble(), llvm::APFloat::rmNearestTiesToEven, +            &ignored); +  return V.convertToDouble(); +} + +void APValue::dump(raw_ostream &OS) const { +  switch (getKind()) { +  case None: +    OS << "None"; +    return; +  case Indeterminate: +    OS << "Indeterminate"; +    return; +  case Int: +    OS << "Int: " << getInt(); +    return; +  case Float: +    OS << "Float: " << GetApproxValue(getFloat()); +    return; +  case FixedPoint: +    OS << "FixedPoint : " << getFixedPoint(); +    return; +  case Vector: +    OS << "Vector: "; +    getVectorElt(0).dump(OS); +    for (unsigned i = 1; i != getVectorLength(); ++i) { +      OS << ", "; +      getVectorElt(i).dump(OS); +    } +    return; +  case ComplexInt: +    OS << "ComplexInt: " << getComplexIntReal() << ", " << getComplexIntImag(); +    return; +  case ComplexFloat: +    OS << "ComplexFloat: " << GetApproxValue(getComplexFloatReal()) +       << ", " << GetApproxValue(getComplexFloatImag()); +    return; +  case LValue: +    OS << "LValue: <todo>"; +    return; +  case Array: +    OS << "Array: "; +    for (unsigned I = 0, N = getArrayInitializedElts(); I != N; ++I) { +      getArrayInitializedElt(I).dump(OS); +      if (I != getArraySize() - 1) OS << ", "; +    } +    if (hasArrayFiller()) { +      OS << getArraySize() - getArrayInitializedElts() << " x "; +      getArrayFiller().dump(OS); +    } +    return; +  case Struct: +    OS << "Struct "; +    if (unsigned N = getStructNumBases()) { +      OS << " bases: "; +      getStructBase(0).dump(OS); +      for (unsigned I = 1; I != N; ++I) { +        OS << ", "; +        getStructBase(I).dump(OS); +      } +    } +    if (unsigned N = getStructNumFields()) { +      OS << " fields: "; +      getStructField(0).dump(OS); +      for (unsigned I = 1; I != N; ++I) { +        OS << ", "; +        getStructField(I).dump(OS); +      } +    } +    return; +  case Union: +    OS << "Union: "; +    getUnionValue().dump(OS); +    return; +  case MemberPointer: +    OS << "MemberPointer: <todo>"; +    return; +  case AddrLabelDiff: +    OS << "AddrLabelDiff: <todo>"; +    return; +  } +  llvm_unreachable("Unknown APValue kind!"); +} + +void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx, +                          QualType Ty) const { +  switch (getKind()) { +  case APValue::None: +    Out << "<out of lifetime>"; +    return; +  case APValue::Indeterminate: +    Out << "<uninitialized>"; +    return; +  case APValue::Int: +    if (Ty->isBooleanType()) +      Out << (getInt().getBoolValue() ? "true" : "false"); +    else +      Out << getInt(); +    return; +  case APValue::Float: +    Out << GetApproxValue(getFloat()); +    return; +  case APValue::FixedPoint: +    Out << getFixedPoint(); +    return; +  case APValue::Vector: { +    Out << '{'; +    QualType ElemTy = Ty->castAs<VectorType>()->getElementType(); +    getVectorElt(0).printPretty(Out, Ctx, ElemTy); +    for (unsigned i = 1; i != getVectorLength(); ++i) { +      Out << ", "; +      getVectorElt(i).printPretty(Out, Ctx, ElemTy); +    } +    Out << '}'; +    return; +  } +  case APValue::ComplexInt: +    Out << getComplexIntReal() << "+" << getComplexIntImag() << "i"; +    return; +  case APValue::ComplexFloat: +    Out << GetApproxValue(getComplexFloatReal()) << "+" +        << GetApproxValue(getComplexFloatImag()) << "i"; +    return; +  case APValue::LValue: { +    bool IsReference = Ty->isReferenceType(); +    QualType InnerTy +      = IsReference ? Ty.getNonReferenceType() : Ty->getPointeeType(); +    if (InnerTy.isNull()) +      InnerTy = Ty; + +    LValueBase Base = getLValueBase(); +    if (!Base) { +      if (isNullPointer()) { +        Out << (Ctx.getLangOpts().CPlusPlus11 ? "nullptr" : "0"); +      } else if (IsReference) { +        Out << "*(" << InnerTy.stream(Ctx.getPrintingPolicy()) << "*)" +            << getLValueOffset().getQuantity(); +      } else { +        Out << "(" << Ty.stream(Ctx.getPrintingPolicy()) << ")" +            << getLValueOffset().getQuantity(); +      } +      return; +    } + +    if (!hasLValuePath()) { +      // No lvalue path: just print the offset. +      CharUnits O = getLValueOffset(); +      CharUnits S = Ctx.getTypeSizeInChars(InnerTy); +      if (!O.isZero()) { +        if (IsReference) +          Out << "*("; +        if (O % S) { +          Out << "(char*)"; +          S = CharUnits::One(); +        } +        Out << '&'; +      } else if (!IsReference) { +        Out << '&'; +      } + +      if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) +        Out << *VD; +      else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) { +        TI.print(Out, Ctx.getPrintingPolicy()); +      } else if (DynamicAllocLValue DA = Base.dyn_cast<DynamicAllocLValue>()) { +        Out << "{*new " +            << Base.getDynamicAllocType().stream(Ctx.getPrintingPolicy()) << "#" +            << DA.getIndex() << "}"; +      } else { +        assert(Base.get<const Expr *>() != nullptr && +               "Expecting non-null Expr"); +        Base.get<const Expr*>()->printPretty(Out, nullptr, +                                             Ctx.getPrintingPolicy()); +      } + +      if (!O.isZero()) { +        Out << " + " << (O / S); +        if (IsReference) +          Out << ')'; +      } +      return; +    } + +    // We have an lvalue path. Print it out nicely. +    if (!IsReference) +      Out << '&'; +    else if (isLValueOnePastTheEnd()) +      Out << "*(&"; + +    QualType ElemTy; +    if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) { +      Out << *VD; +      ElemTy = VD->getType(); +    } else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) { +      TI.print(Out, Ctx.getPrintingPolicy()); +      ElemTy = Base.getTypeInfoType(); +    } else if (DynamicAllocLValue DA = Base.dyn_cast<DynamicAllocLValue>()) { +      Out << "{*new " +          << Base.getDynamicAllocType().stream(Ctx.getPrintingPolicy()) << "#" +          << DA.getIndex() << "}"; +      ElemTy = Base.getDynamicAllocType(); +    } else { +      const Expr *E = Base.get<const Expr*>(); +      assert(E != nullptr && "Expecting non-null Expr"); +      E->printPretty(Out, nullptr, Ctx.getPrintingPolicy()); +      // FIXME: This is wrong if E is a MaterializeTemporaryExpr with an lvalue +      // adjustment. +      ElemTy = E->getType(); +    } + +    ArrayRef<LValuePathEntry> Path = getLValuePath(); +    const CXXRecordDecl *CastToBase = nullptr; +    for (unsigned I = 0, N = Path.size(); I != N; ++I) { +      if (ElemTy->getAs<RecordType>()) { +        // The lvalue refers to a class type, so the next path entry is a base +        // or member. +        const Decl *BaseOrMember = Path[I].getAsBaseOrMember().getPointer(); +        if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) { +          CastToBase = RD; +          ElemTy = Ctx.getRecordType(RD); +        } else { +          const ValueDecl *VD = cast<ValueDecl>(BaseOrMember); +          Out << "."; +          if (CastToBase) +            Out << *CastToBase << "::"; +          Out << *VD; +          ElemTy = VD->getType(); +        } +      } else { +        // The lvalue must refer to an array. +        Out << '[' << Path[I].getAsArrayIndex() << ']'; +        ElemTy = Ctx.getAsArrayType(ElemTy)->getElementType(); +      } +    } + +    // Handle formatting of one-past-the-end lvalues. +    if (isLValueOnePastTheEnd()) { +      // FIXME: If CastToBase is non-0, we should prefix the output with +      // "(CastToBase*)". +      Out << " + 1"; +      if (IsReference) +        Out << ')'; +    } +    return; +  } +  case APValue::Array: { +    const ArrayType *AT = Ctx.getAsArrayType(Ty); +    QualType ElemTy = AT->getElementType(); +    Out << '{'; +    if (unsigned N = getArrayInitializedElts()) { +      getArrayInitializedElt(0).printPretty(Out, Ctx, ElemTy); +      for (unsigned I = 1; I != N; ++I) { +        Out << ", "; +        if (I == 10) { +          // Avoid printing out the entire contents of large arrays. +          Out << "..."; +          break; +        } +        getArrayInitializedElt(I).printPretty(Out, Ctx, ElemTy); +      } +    } +    Out << '}'; +    return; +  } +  case APValue::Struct: { +    Out << '{'; +    const RecordDecl *RD = Ty->castAs<RecordType>()->getDecl(); +    bool First = true; +    if (unsigned N = getStructNumBases()) { +      const CXXRecordDecl *CD = cast<CXXRecordDecl>(RD); +      CXXRecordDecl::base_class_const_iterator BI = CD->bases_begin(); +      for (unsigned I = 0; I != N; ++I, ++BI) { +        assert(BI != CD->bases_end()); +        if (!First) +          Out << ", "; +        getStructBase(I).printPretty(Out, Ctx, BI->getType()); +        First = false; +      } +    } +    for (const auto *FI : RD->fields()) { +      if (!First) +        Out << ", "; +      if (FI->isUnnamedBitfield()) continue; +      getStructField(FI->getFieldIndex()). +        printPretty(Out, Ctx, FI->getType()); +      First = false; +    } +    Out << '}'; +    return; +  } +  case APValue::Union: +    Out << '{'; +    if (const FieldDecl *FD = getUnionField()) { +      Out << "." << *FD << " = "; +      getUnionValue().printPretty(Out, Ctx, FD->getType()); +    } +    Out << '}'; +    return; +  case APValue::MemberPointer: +    // FIXME: This is not enough to unambiguously identify the member in a +    // multiple-inheritance scenario. +    if (const ValueDecl *VD = getMemberPointerDecl()) { +      Out << '&' << *cast<CXXRecordDecl>(VD->getDeclContext()) << "::" << *VD; +      return; +    } +    Out << "0"; +    return; +  case APValue::AddrLabelDiff: +    Out << "&&" << getAddrLabelDiffLHS()->getLabel()->getName(); +    Out << " - "; +    Out << "&&" << getAddrLabelDiffRHS()->getLabel()->getName(); +    return; +  } +  llvm_unreachable("Unknown APValue kind!"); +} + +std::string APValue::getAsString(const ASTContext &Ctx, QualType Ty) const { +  std::string Result; +  llvm::raw_string_ostream Out(Result); +  printPretty(Out, Ctx, Ty); +  Out.flush(); +  return Result; +} + +bool APValue::toIntegralConstant(APSInt &Result, QualType SrcTy, +                                 const ASTContext &Ctx) const { +  if (isInt()) { +    Result = getInt(); +    return true; +  } + +  if (isLValue() && isNullPointer()) { +    Result = Ctx.MakeIntValue(Ctx.getTargetNullPointerValue(SrcTy), SrcTy); +    return true; +  } + +  if (isLValue() && !getLValueBase()) { +    Result = Ctx.MakeIntValue(getLValueOffset().getQuantity(), SrcTy); +    return true; +  } + +  return false; +} + +const APValue::LValueBase APValue::getLValueBase() const { +  assert(isLValue() && "Invalid accessor"); +  return ((const LV*)(const void*)Data.buffer)->Base; +} + +bool APValue::isLValueOnePastTheEnd() const { +  assert(isLValue() && "Invalid accessor"); +  return ((const LV*)(const void*)Data.buffer)->IsOnePastTheEnd; +} + +CharUnits &APValue::getLValueOffset() { +  assert(isLValue() && "Invalid accessor"); +  return ((LV*)(void*)Data.buffer)->Offset; +} + +bool APValue::hasLValuePath() const { +  assert(isLValue() && "Invalid accessor"); +  return ((const LV*)(const char*)Data.buffer)->hasPath(); +} + +ArrayRef<APValue::LValuePathEntry> APValue::getLValuePath() const { +  assert(isLValue() && hasLValuePath() && "Invalid accessor"); +  const LV &LVal = *((const LV*)(const char*)Data.buffer); +  return llvm::makeArrayRef(LVal.getPath(), LVal.PathLength); +} + +unsigned APValue::getLValueCallIndex() const { +  assert(isLValue() && "Invalid accessor"); +  return ((const LV*)(const char*)Data.buffer)->Base.getCallIndex(); +} + +unsigned APValue::getLValueVersion() const { +  assert(isLValue() && "Invalid accessor"); +  return ((const LV*)(const char*)Data.buffer)->Base.getVersion(); +} + +bool APValue::isNullPointer() const { +  assert(isLValue() && "Invalid usage"); +  return ((const LV*)(const char*)Data.buffer)->IsNullPtr; +} + +void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath, +                        bool IsNullPtr) { +  assert(isLValue() && "Invalid accessor"); +  LV &LVal = *((LV*)(char*)Data.buffer); +  LVal.Base = B; +  LVal.IsOnePastTheEnd = false; +  LVal.Offset = O; +  LVal.resizePath((unsigned)-1); +  LVal.IsNullPtr = IsNullPtr; +} + +void APValue::setLValue(LValueBase B, const CharUnits &O, +                        ArrayRef<LValuePathEntry> Path, bool IsOnePastTheEnd, +                        bool IsNullPtr) { +  assert(isLValue() && "Invalid accessor"); +  LV &LVal = *((LV*)(char*)Data.buffer); +  LVal.Base = B; +  LVal.IsOnePastTheEnd = IsOnePastTheEnd; +  LVal.Offset = O; +  LVal.resizePath(Path.size()); +  memcpy(LVal.getPath(), Path.data(), Path.size() * sizeof(LValuePathEntry)); +  LVal.IsNullPtr = IsNullPtr; +} + +const ValueDecl *APValue::getMemberPointerDecl() const { +  assert(isMemberPointer() && "Invalid accessor"); +  const MemberPointerData &MPD = +      *((const MemberPointerData *)(const char *)Data.buffer); +  return MPD.MemberAndIsDerivedMember.getPointer(); +} + +bool APValue::isMemberPointerToDerivedMember() const { +  assert(isMemberPointer() && "Invalid accessor"); +  const MemberPointerData &MPD = +      *((const MemberPointerData *)(const char *)Data.buffer); +  return MPD.MemberAndIsDerivedMember.getInt(); +} + +ArrayRef<const CXXRecordDecl*> APValue::getMemberPointerPath() const { +  assert(isMemberPointer() && "Invalid accessor"); +  const MemberPointerData &MPD = +      *((const MemberPointerData *)(const char *)Data.buffer); +  return llvm::makeArrayRef(MPD.getPath(), MPD.PathLength); +} + +void APValue::MakeLValue() { +  assert(isAbsent() && "Bad state change"); +  static_assert(sizeof(LV) <= DataSize, "LV too big"); +  new ((void*)(char*)Data.buffer) LV(); +  Kind = LValue; +} + +void APValue::MakeArray(unsigned InitElts, unsigned Size) { +  assert(isAbsent() && "Bad state change"); +  new ((void*)(char*)Data.buffer) Arr(InitElts, Size); +  Kind = Array; +} + +void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember, +                                ArrayRef<const CXXRecordDecl*> Path) { +  assert(isAbsent() && "Bad state change"); +  MemberPointerData *MPD = new ((void*)(char*)Data.buffer) MemberPointerData; +  Kind = MemberPointer; +  MPD->MemberAndIsDerivedMember.setPointer(Member); +  MPD->MemberAndIsDerivedMember.setInt(IsDerivedMember); +  MPD->resizePath(Path.size()); +  memcpy(MPD->getPath(), Path.data(), Path.size()*sizeof(const CXXRecordDecl*)); +} | 
