diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/AST/APValue.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/AST/APValue.cpp | 538 |
1 files changed, 455 insertions, 83 deletions
diff --git a/contrib/llvm-project/clang/lib/AST/APValue.cpp b/contrib/llvm-project/clang/lib/AST/APValue.cpp index f3828bb54c1d..9a9233bc1ea7 100644 --- a/contrib/llvm-project/clang/lib/AST/APValue.cpp +++ b/contrib/llvm-project/clang/lib/AST/APValue.cpp @@ -11,10 +11,12 @@ //===----------------------------------------------------------------------===// #include "clang/AST/APValue.h" +#include "Linkage.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/Type.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" @@ -38,7 +40,7 @@ static_assert( "Type is insufficiently aligned"); APValue::LValueBase::LValueBase(const ValueDecl *P, unsigned I, unsigned V) - : Ptr(P), Local{I, V} {} + : Ptr(P ? cast<ValueDecl>(P->getCanonicalDecl()) : nullptr), Local{I, V} {} APValue::LValueBase::LValueBase(const Expr *P, unsigned I, unsigned V) : Ptr(P), Local{I, V} {} @@ -58,6 +60,51 @@ APValue::LValueBase APValue::LValueBase::getTypeInfo(TypeInfoLValue LV, return Base; } +QualType APValue::LValueBase::getType() const { + if (!*this) return QualType(); + if (const ValueDecl *D = dyn_cast<const ValueDecl*>()) { + // FIXME: It's unclear where we're supposed to take the type from, and + // this actually matters for arrays of unknown bound. Eg: + // + // extern int arr[]; void f() { extern int arr[3]; }; + // constexpr int *p = &arr[1]; // valid? + // + // For now, we take the most complete type we can find. + for (auto *Redecl = cast<ValueDecl>(D->getMostRecentDecl()); Redecl; + Redecl = cast_or_null<ValueDecl>(Redecl->getPreviousDecl())) { + QualType T = Redecl->getType(); + if (!T->isIncompleteArrayType()) + return T; + } + return D->getType(); + } + + if (is<TypeInfoLValue>()) + return getTypeInfoType(); + + if (is<DynamicAllocLValue>()) + return getDynamicAllocType(); + + const Expr *Base = get<const Expr*>(); + + // For a materialized temporary, the type of the temporary we materialized + // may not be the type of the expression. + if (const MaterializeTemporaryExpr *MTE = + clang::dyn_cast<MaterializeTemporaryExpr>(Base)) { + SmallVector<const Expr *, 2> CommaLHSs; + SmallVector<SubobjectAdjustment, 2> Adjustments; + const Expr *Temp = MTE->getSubExpr(); + const Expr *Inner = Temp->skipRValueSubobjectAdjustments(CommaLHSs, + Adjustments); + // Keep any cv-qualifiers from the reference if we generated a temporary + // for it directly. Otherwise use the type after adjustment. + if (!Adjustments.empty()) + return Inner->getType(); + } + + return Base->getType(); +} + unsigned APValue::LValueBase::getCallIndex() const { return (is<TypeInfoLValue>() || is<DynamicAllocLValue>()) ? 0 : Local.CallIndex; @@ -77,18 +124,44 @@ QualType APValue::LValueBase::getDynamicAllocType() const { return QualType::getFromOpaquePtr(DynamicAllocType); } +void APValue::LValueBase::Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddPointer(Ptr.getOpaqueValue()); + if (is<TypeInfoLValue>() || is<DynamicAllocLValue>()) + return; + ID.AddInteger(Local.CallIndex); + ID.AddInteger(Local.Version); +} + namespace clang { bool operator==(const APValue::LValueBase &LHS, const APValue::LValueBase &RHS) { if (LHS.Ptr != RHS.Ptr) return false; - if (LHS.is<TypeInfoLValue>()) + if (LHS.is<TypeInfoLValue>() || LHS.is<DynamicAllocLValue>()) return true; return LHS.Local.CallIndex == RHS.Local.CallIndex && LHS.Local.Version == RHS.Local.Version; } } +APValue::LValuePathEntry::LValuePathEntry(BaseOrMemberType BaseOrMember) { + if (const Decl *D = BaseOrMember.getPointer()) + BaseOrMember.setPointer(D->getCanonicalDecl()); + Value = reinterpret_cast<uintptr_t>(BaseOrMember.getOpaqueValue()); +} + +void APValue::LValuePathEntry::Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(Value); +} + +APValue::LValuePathSerializationHelper::LValuePathSerializationHelper( + ArrayRef<LValuePathEntry> Path, QualType ElemTy) + : ElemTy((const void *)ElemTy.getTypePtrOrNull()), Path(Path) {} + +QualType APValue::LValuePathSerializationHelper::getType() { + return QualType::getFromOpaquePtr(ElemTy); +} + namespace { struct LVBase { APValue::LValueBase Base; @@ -113,14 +186,16 @@ APValue::LValueBase::operator bool () const { clang::APValue::LValueBase llvm::DenseMapInfo<clang::APValue::LValueBase>::getEmptyKey() { - return clang::APValue::LValueBase( - DenseMapInfo<const ValueDecl*>::getEmptyKey()); + clang::APValue::LValueBase B; + B.Ptr = DenseMapInfo<const ValueDecl*>::getEmptyKey(); + return B; } clang::APValue::LValueBase llvm::DenseMapInfo<clang::APValue::LValueBase>::getTombstoneKey() { - return clang::APValue::LValueBase( - DenseMapInfo<const ValueDecl*>::getTombstoneKey()); + clang::APValue::LValueBase B; + B.Ptr = DenseMapInfo<const ValueDecl*>::getTombstoneKey(); + return B; } namespace clang { @@ -254,7 +329,7 @@ APValue::APValue(const APValue &RHS) : Kind(None) { } case Vector: MakeVector(); - setVector(((const Vec *)(const char *)RHS.Data.buffer)->Elts, + setVector(((const Vec *)(const char *)&RHS.Data)->Elts, RHS.getVectorLength()); break; case ComplexInt: @@ -304,31 +379,50 @@ APValue::APValue(const APValue &RHS) : Kind(None) { } } +APValue::APValue(APValue &&RHS) : Kind(RHS.Kind), Data(RHS.Data) { + RHS.Kind = None; +} + +APValue &APValue::operator=(const APValue &RHS) { + if (this != &RHS) + *this = APValue(RHS); + return *this; +} + +APValue &APValue::operator=(APValue &&RHS) { + if (Kind != None && Kind != Indeterminate) + DestroyDataAndMakeUninit(); + Kind = RHS.Kind; + Data = RHS.Data; + RHS.Kind = None; + return *this; +} + void APValue::DestroyDataAndMakeUninit() { if (Kind == Int) - ((APSInt*)(char*)Data.buffer)->~APSInt(); + ((APSInt *)(char *)&Data)->~APSInt(); else if (Kind == Float) - ((APFloat*)(char*)Data.buffer)->~APFloat(); + ((APFloat *)(char *)&Data)->~APFloat(); else if (Kind == FixedPoint) - ((APFixedPoint *)(char *)Data.buffer)->~APFixedPoint(); + ((APFixedPoint *)(char *)&Data)->~APFixedPoint(); else if (Kind == Vector) - ((Vec*)(char*)Data.buffer)->~Vec(); + ((Vec *)(char *)&Data)->~Vec(); else if (Kind == ComplexInt) - ((ComplexAPSInt*)(char*)Data.buffer)->~ComplexAPSInt(); + ((ComplexAPSInt *)(char *)&Data)->~ComplexAPSInt(); else if (Kind == ComplexFloat) - ((ComplexAPFloat*)(char*)Data.buffer)->~ComplexAPFloat(); + ((ComplexAPFloat *)(char *)&Data)->~ComplexAPFloat(); else if (Kind == LValue) - ((LV*)(char*)Data.buffer)->~LV(); + ((LV *)(char *)&Data)->~LV(); else if (Kind == Array) - ((Arr*)(char*)Data.buffer)->~Arr(); + ((Arr *)(char *)&Data)->~Arr(); else if (Kind == Struct) - ((StructData*)(char*)Data.buffer)->~StructData(); + ((StructData *)(char *)&Data)->~StructData(); else if (Kind == Union) - ((UnionData*)(char*)Data.buffer)->~UnionData(); + ((UnionData *)(char *)&Data)->~UnionData(); else if (Kind == MemberPointer) - ((MemberPointerData*)(char*)Data.buffer)->~MemberPointerData(); + ((MemberPointerData *)(char *)&Data)->~MemberPointerData(); else if (Kind == AddrLabelDiff) - ((AddrLabelDiffData*)(char*)Data.buffer)->~AddrLabelDiffData(); + ((AddrLabelDiffData *)(char *)&Data)->~AddrLabelDiffData(); Kind = None; } @@ -362,20 +456,165 @@ bool APValue::needsCleanup() const { "same size."); return getComplexIntReal().needsCleanup(); case LValue: - return reinterpret_cast<const LV *>(Data.buffer)->hasPathPtr(); + return reinterpret_cast<const LV *>(&Data)->hasPathPtr(); case MemberPointer: - return reinterpret_cast<const MemberPointerData *>(Data.buffer) - ->hasPathPtr(); + return reinterpret_cast<const MemberPointerData *>(&Data)->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); + std::swap(Data, RHS.Data); +} + +/// Profile the value of an APInt, excluding its bit-width. +static void profileIntValue(llvm::FoldingSetNodeID &ID, const llvm::APInt &V) { + for (unsigned I = 0, N = V.getBitWidth(); I < N; I += 32) + ID.AddInteger((uint32_t)V.extractBitsAsZExtValue(std::min(32u, N - I), I)); +} + +void APValue::Profile(llvm::FoldingSetNodeID &ID) const { + // Note that our profiling assumes that only APValues of the same type are + // ever compared. As a result, we don't consider collisions that could only + // happen if the types are different. (For example, structs with different + // numbers of members could profile the same.) + + ID.AddInteger(Kind); + + switch (Kind) { + case None: + case Indeterminate: + return; + + case AddrLabelDiff: + ID.AddPointer(getAddrLabelDiffLHS()->getLabel()->getCanonicalDecl()); + ID.AddPointer(getAddrLabelDiffRHS()->getLabel()->getCanonicalDecl()); + return; + + case Struct: + for (unsigned I = 0, N = getStructNumBases(); I != N; ++I) + getStructBase(I).Profile(ID); + for (unsigned I = 0, N = getStructNumFields(); I != N; ++I) + getStructField(I).Profile(ID); + return; + + case Union: + if (!getUnionField()) { + ID.AddInteger(0); + return; + } + ID.AddInteger(getUnionField()->getFieldIndex() + 1); + getUnionValue().Profile(ID); + return; + + case Array: { + if (getArraySize() == 0) + return; + + // The profile should not depend on whether the array is expanded or + // not, but we don't want to profile the array filler many times for + // a large array. So treat all equal trailing elements as the filler. + // Elements are profiled in reverse order to support this, and the + // first profiled element is followed by a count. For example: + // + // ['a', 'c', 'x', 'x', 'x'] is profiled as + // [5, 'x', 3, 'c', 'a'] + llvm::FoldingSetNodeID FillerID; + (hasArrayFiller() ? getArrayFiller() + : getArrayInitializedElt(getArrayInitializedElts() - 1)) + .Profile(FillerID); + ID.AddNodeID(FillerID); + unsigned NumFillers = getArraySize() - getArrayInitializedElts(); + unsigned N = getArrayInitializedElts(); + + // Count the number of elements equal to the last one. This loop ends + // by adding an integer indicating the number of such elements, with + // N set to the number of elements left to profile. + while (true) { + if (N == 0) { + // All elements are fillers. + assert(NumFillers == getArraySize()); + ID.AddInteger(NumFillers); + break; + } + + // No need to check if the last element is equal to the last + // element. + if (N != getArraySize()) { + llvm::FoldingSetNodeID ElemID; + getArrayInitializedElt(N - 1).Profile(ElemID); + if (ElemID != FillerID) { + ID.AddInteger(NumFillers); + ID.AddNodeID(ElemID); + --N; + break; + } + } + + // This is a filler. + ++NumFillers; + --N; + } + + // Emit the remaining elements. + for (; N != 0; --N) + getArrayInitializedElt(N - 1).Profile(ID); + return; + } + + case Vector: + for (unsigned I = 0, N = getVectorLength(); I != N; ++I) + getVectorElt(I).Profile(ID); + return; + + case Int: + profileIntValue(ID, getInt()); + return; + + case Float: + profileIntValue(ID, getFloat().bitcastToAPInt()); + return; + + case FixedPoint: + profileIntValue(ID, getFixedPoint().getValue()); + return; + + case ComplexFloat: + profileIntValue(ID, getComplexFloatReal().bitcastToAPInt()); + profileIntValue(ID, getComplexFloatImag().bitcastToAPInt()); + return; + + case ComplexInt: + profileIntValue(ID, getComplexIntReal()); + profileIntValue(ID, getComplexIntImag()); + return; + + case LValue: + getLValueBase().Profile(ID); + ID.AddInteger(getLValueOffset().getQuantity()); + ID.AddInteger((isNullPointer() ? 1 : 0) | + (isLValueOnePastTheEnd() ? 2 : 0) | + (hasLValuePath() ? 4 : 0)); + if (hasLValuePath()) { + ID.AddInteger(getLValuePath().size()); + // For uniqueness, we only need to profile the entries corresponding + // to union members, but we don't have the type here so we don't know + // how to interpret the entries. + for (LValuePathEntry E : getLValuePath()) + E.Profile(ID); + } + return; + + case MemberPointer: + ID.AddPointer(getMemberPointerDecl()); + ID.AddInteger(isMemberPointerToDerivedMember()); + for (const CXXRecordDecl *D : getMemberPointerPath()) + ID.AddPointer(D); + return; + } + + llvm_unreachable("Unknown APValue kind!"); } static double GetApproxValue(const llvm::APFloat &F) { @@ -388,6 +627,18 @@ static double GetApproxValue(const llvm::APFloat &F) { void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx, QualType Ty) const { + printPretty(Out, Ctx.getPrintingPolicy(), Ty, &Ctx); +} + +void APValue::printPretty(raw_ostream &Out, const PrintingPolicy &Policy, + QualType Ty, const ASTContext *Ctx) const { + // There are no objects of type 'void', but values of this type can be + // returned from functions. + if (Ty->isVoidType()) { + Out << "void()"; + return; + } + switch (getKind()) { case APValue::None: Out << "<out of lifetime>"; @@ -410,10 +661,10 @@ void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx, case APValue::Vector: { Out << '{'; QualType ElemTy = Ty->castAs<VectorType>()->getElementType(); - getVectorElt(0).printPretty(Out, Ctx, ElemTy); + getVectorElt(0).printPretty(Out, Policy, ElemTy, Ctx); for (unsigned i = 1; i != getVectorLength(); ++i) { Out << ", "; - getVectorElt(i).printPretty(Out, Ctx, ElemTy); + getVectorElt(i).printPretty(Out, Policy, ElemTy, Ctx); } Out << '}'; return; @@ -435,12 +686,12 @@ void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx, LValueBase Base = getLValueBase(); if (!Base) { if (isNullPointer()) { - Out << (Ctx.getLangOpts().CPlusPlus11 ? "nullptr" : "0"); + Out << (Policy.Nullptr ? "nullptr" : "0"); } else if (IsReference) { - Out << "*(" << InnerTy.stream(Ctx.getPrintingPolicy()) << "*)" + Out << "*(" << InnerTy.stream(Policy) << "*)" << getLValueOffset().getQuantity(); } else { - Out << "(" << Ty.stream(Ctx.getPrintingPolicy()) << ")" + Out << "(" << Ty.stream(Policy) << ")" << getLValueOffset().getQuantity(); } return; @@ -449,11 +700,11 @@ void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx, if (!hasLValuePath()) { // No lvalue path: just print the offset. CharUnits O = getLValueOffset(); - CharUnits S = Ctx.getTypeSizeInChars(InnerTy); + CharUnits S = Ctx ? Ctx->getTypeSizeInChars(InnerTy) : CharUnits::Zero(); if (!O.isZero()) { if (IsReference) Out << "*("; - if (O % S) { + if (S.isZero() || O % S) { Out << "(char*)"; S = CharUnits::One(); } @@ -465,16 +716,15 @@ void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx, if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) Out << *VD; else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) { - TI.print(Out, Ctx.getPrintingPolicy()); + TI.print(Out, Policy); } else if (DynamicAllocLValue DA = Base.dyn_cast<DynamicAllocLValue>()) { Out << "{*new " - << Base.getDynamicAllocType().stream(Ctx.getPrintingPolicy()) << "#" + << Base.getDynamicAllocType().stream(Policy) << "#" << DA.getIndex() << "}"; } else { assert(Base.get<const Expr *>() != nullptr && "Expecting non-null Expr"); - Base.get<const Expr*>()->printPretty(Out, nullptr, - Ctx.getPrintingPolicy()); + Base.get<const Expr*>()->printPretty(Out, nullptr, Policy); } if (!O.isZero()) { @@ -491,37 +741,31 @@ void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx, else if (isLValueOnePastTheEnd()) Out << "*(&"; - QualType ElemTy; + QualType ElemTy = Base.getType(); 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(); + TI.print(Out, Policy); } else if (DynamicAllocLValue DA = Base.dyn_cast<DynamicAllocLValue>()) { - Out << "{*new " - << Base.getDynamicAllocType().stream(Ctx.getPrintingPolicy()) << "#" + Out << "{*new " << Base.getDynamicAllocType().stream(Policy) << "#" << 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(); + E->printPretty(Out, nullptr, Policy); } ArrayRef<LValuePathEntry> Path = getLValuePath(); const CXXRecordDecl *CastToBase = nullptr; for (unsigned I = 0, N = Path.size(); I != N; ++I) { - if (ElemTy->getAs<RecordType>()) { + if (ElemTy->isRecordType()) { // 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); + // Leave ElemTy referring to the most-derived class. The actual type + // doesn't matter except for array types. } else { const ValueDecl *VD = cast<ValueDecl>(BaseOrMember); Out << "."; @@ -533,7 +777,7 @@ void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx, } else { // The lvalue must refer to an array. Out << '[' << Path[I].getAsArrayIndex() << ']'; - ElemTy = Ctx.getAsArrayType(ElemTy)->getElementType(); + ElemTy = ElemTy->castAsArrayTypeUnsafe()->getElementType(); } } @@ -548,11 +792,11 @@ void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx, return; } case APValue::Array: { - const ArrayType *AT = Ctx.getAsArrayType(Ty); + const ArrayType *AT = Ty->castAsArrayTypeUnsafe(); QualType ElemTy = AT->getElementType(); Out << '{'; if (unsigned N = getArrayInitializedElts()) { - getArrayInitializedElt(0).printPretty(Out, Ctx, ElemTy); + getArrayInitializedElt(0).printPretty(Out, Policy, ElemTy, Ctx); for (unsigned I = 1; I != N; ++I) { Out << ", "; if (I == 10) { @@ -560,7 +804,7 @@ void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx, Out << "..."; break; } - getArrayInitializedElt(I).printPretty(Out, Ctx, ElemTy); + getArrayInitializedElt(I).printPretty(Out, Policy, ElemTy, Ctx); } } Out << '}'; @@ -577,7 +821,7 @@ void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx, assert(BI != CD->bases_end()); if (!First) Out << ", "; - getStructBase(I).printPretty(Out, Ctx, BI->getType()); + getStructBase(I).printPretty(Out, Policy, BI->getType(), Ctx); First = false; } } @@ -586,7 +830,7 @@ void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx, Out << ", "; if (FI->isUnnamedBitfield()) continue; getStructField(FI->getFieldIndex()). - printPretty(Out, Ctx, FI->getType()); + printPretty(Out, Policy, FI->getType(), Ctx); First = false; } Out << '}'; @@ -596,7 +840,7 @@ void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx, Out << '{'; if (const FieldDecl *FD = getUnionField()) { Out << "." << *FD << " = "; - getUnionValue().printPretty(Out, Ctx, FD->getType()); + getUnionValue().printPretty(Out, Policy, FD->getType(), Ctx); } Out << '}'; return; @@ -648,49 +892,49 @@ bool APValue::toIntegralConstant(APSInt &Result, QualType SrcTy, const APValue::LValueBase APValue::getLValueBase() const { assert(isLValue() && "Invalid accessor"); - return ((const LV*)(const void*)Data.buffer)->Base; + return ((const LV *)(const void *)&Data)->Base; } bool APValue::isLValueOnePastTheEnd() const { assert(isLValue() && "Invalid accessor"); - return ((const LV*)(const void*)Data.buffer)->IsOnePastTheEnd; + return ((const LV *)(const void *)&Data)->IsOnePastTheEnd; } CharUnits &APValue::getLValueOffset() { assert(isLValue() && "Invalid accessor"); - return ((LV*)(void*)Data.buffer)->Offset; + return ((LV *)(void *)&Data)->Offset; } bool APValue::hasLValuePath() const { assert(isLValue() && "Invalid accessor"); - return ((const LV*)(const char*)Data.buffer)->hasPath(); + return ((const LV *)(const char *)&Data)->hasPath(); } ArrayRef<APValue::LValuePathEntry> APValue::getLValuePath() const { assert(isLValue() && hasLValuePath() && "Invalid accessor"); - const LV &LVal = *((const LV*)(const char*)Data.buffer); + const LV &LVal = *((const LV *)(const char *)&Data); return llvm::makeArrayRef(LVal.getPath(), LVal.PathLength); } unsigned APValue::getLValueCallIndex() const { assert(isLValue() && "Invalid accessor"); - return ((const LV*)(const char*)Data.buffer)->Base.getCallIndex(); + return ((const LV *)(const char *)&Data)->Base.getCallIndex(); } unsigned APValue::getLValueVersion() const { assert(isLValue() && "Invalid accessor"); - return ((const LV*)(const char*)Data.buffer)->Base.getVersion(); + return ((const LV *)(const char *)&Data)->Base.getVersion(); } bool APValue::isNullPointer() const { assert(isLValue() && "Invalid usage"); - return ((const LV*)(const char*)Data.buffer)->IsNullPtr; + return ((const LV *)(const char *)&Data)->IsNullPtr; } void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath, bool IsNullPtr) { assert(isLValue() && "Invalid accessor"); - LV &LVal = *((LV*)(char*)Data.buffer); + LV &LVal = *((LV *)(char *)&Data); LVal.Base = B; LVal.IsOnePastTheEnd = false; LVal.Offset = O; @@ -698,60 +942,188 @@ void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath, LVal.IsNullPtr = IsNullPtr; } -void APValue::setLValue(LValueBase B, const CharUnits &O, - ArrayRef<LValuePathEntry> Path, bool IsOnePastTheEnd, - bool IsNullPtr) { +MutableArrayRef<APValue::LValuePathEntry> +APValue::setLValueUninit(LValueBase B, const CharUnits &O, unsigned Size, + bool IsOnePastTheEnd, bool IsNullPtr) { assert(isLValue() && "Invalid accessor"); - LV &LVal = *((LV*)(char*)Data.buffer); + LV &LVal = *((LV *)(char *)&Data); 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; + LVal.resizePath(Size); + return {LVal.getPath(), Size}; +} + +void APValue::setLValue(LValueBase B, const CharUnits &O, + ArrayRef<LValuePathEntry> Path, bool IsOnePastTheEnd, + bool IsNullPtr) { + MutableArrayRef<APValue::LValuePathEntry> InternalPath = + setLValueUninit(B, O, Path.size(), IsOnePastTheEnd, IsNullPtr); + if (Path.size()) { + memcpy(InternalPath.data(), Path.data(), + Path.size() * sizeof(LValuePathEntry)); + } +} + +void APValue::setUnion(const FieldDecl *Field, const APValue &Value) { + assert(isUnion() && "Invalid accessor"); + ((UnionData *)(char *)&Data)->Field = + Field ? Field->getCanonicalDecl() : nullptr; + *((UnionData *)(char *)&Data)->Value = Value; } const ValueDecl *APValue::getMemberPointerDecl() const { assert(isMemberPointer() && "Invalid accessor"); const MemberPointerData &MPD = - *((const MemberPointerData *)(const char *)Data.buffer); + *((const MemberPointerData *)(const char *)&Data); return MPD.MemberAndIsDerivedMember.getPointer(); } bool APValue::isMemberPointerToDerivedMember() const { assert(isMemberPointer() && "Invalid accessor"); const MemberPointerData &MPD = - *((const MemberPointerData *)(const char *)Data.buffer); + *((const MemberPointerData *)(const char *)&Data); return MPD.MemberAndIsDerivedMember.getInt(); } ArrayRef<const CXXRecordDecl*> APValue::getMemberPointerPath() const { assert(isMemberPointer() && "Invalid accessor"); const MemberPointerData &MPD = - *((const MemberPointerData *)(const char *)Data.buffer); + *((const MemberPointerData *)(const char *)&Data); 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(); + new ((void *)(char *)&Data) LV(); Kind = LValue; } void APValue::MakeArray(unsigned InitElts, unsigned Size) { assert(isAbsent() && "Bad state change"); - new ((void*)(char*)Data.buffer) Arr(InitElts, Size); + new ((void *)(char *)&Data) Arr(InitElts, Size); Kind = Array; } -void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember, - ArrayRef<const CXXRecordDecl*> Path) { +MutableArrayRef<APValue::LValuePathEntry> +setLValueUninit(APValue::LValueBase B, const CharUnits &O, unsigned Size, + bool OnePastTheEnd, bool IsNullPtr); + +MutableArrayRef<const CXXRecordDecl *> +APValue::setMemberPointerUninit(const ValueDecl *Member, bool IsDerivedMember, + unsigned Size) { assert(isAbsent() && "Bad state change"); - MemberPointerData *MPD = new ((void*)(char*)Data.buffer) MemberPointerData; + MemberPointerData *MPD = new ((void *)(char *)&Data) MemberPointerData; Kind = MemberPointer; - MPD->MemberAndIsDerivedMember.setPointer(Member); + MPD->MemberAndIsDerivedMember.setPointer( + Member ? cast<ValueDecl>(Member->getCanonicalDecl()) : nullptr); MPD->MemberAndIsDerivedMember.setInt(IsDerivedMember); - MPD->resizePath(Path.size()); - memcpy(MPD->getPath(), Path.data(), Path.size()*sizeof(const CXXRecordDecl*)); + MPD->resizePath(Size); + return {MPD->getPath(), MPD->PathLength}; +} + +void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember, + ArrayRef<const CXXRecordDecl *> Path) { + MutableArrayRef<const CXXRecordDecl *> InternalPath = + setMemberPointerUninit(Member, IsDerivedMember, Path.size()); + for (unsigned I = 0; I != Path.size(); ++I) + InternalPath[I] = Path[I]->getCanonicalDecl(); +} + +LinkageInfo LinkageComputer::getLVForValue(const APValue &V, + LVComputationKind computation) { + LinkageInfo LV = LinkageInfo::external(); + + auto MergeLV = [&](LinkageInfo MergeLV) { + LV.merge(MergeLV); + return LV.getLinkage() == InternalLinkage; + }; + auto Merge = [&](const APValue &V) { + return MergeLV(getLVForValue(V, computation)); + }; + + switch (V.getKind()) { + case APValue::None: + case APValue::Indeterminate: + case APValue::Int: + case APValue::Float: + case APValue::FixedPoint: + case APValue::ComplexInt: + case APValue::ComplexFloat: + case APValue::Vector: + break; + + case APValue::AddrLabelDiff: + // Even for an inline function, it's not reasonable to treat a difference + // between the addresses of labels as an external value. + return LinkageInfo::internal(); + + case APValue::Struct: { + for (unsigned I = 0, N = V.getStructNumBases(); I != N; ++I) + if (Merge(V.getStructBase(I))) + break; + for (unsigned I = 0, N = V.getStructNumFields(); I != N; ++I) + if (Merge(V.getStructField(I))) + break; + break; + } + + case APValue::Union: + if (V.getUnionField()) + Merge(V.getUnionValue()); + break; + + case APValue::Array: { + for (unsigned I = 0, N = V.getArrayInitializedElts(); I != N; ++I) + if (Merge(V.getArrayInitializedElt(I))) + break; + if (V.hasArrayFiller()) + Merge(V.getArrayFiller()); + break; + } + + case APValue::LValue: { + if (!V.getLValueBase()) { + // Null or absolute address: this is external. + } else if (const auto *VD = + V.getLValueBase().dyn_cast<const ValueDecl *>()) { + if (VD && MergeLV(getLVForDecl(VD, computation))) + break; + } else if (const auto TI = V.getLValueBase().dyn_cast<TypeInfoLValue>()) { + if (MergeLV(getLVForType(*TI.getType(), computation))) + break; + } else if (const Expr *E = V.getLValueBase().dyn_cast<const Expr *>()) { + // Almost all expression bases are internal. The exception is + // lifetime-extended temporaries. + // FIXME: These should be modeled as having the + // LifetimeExtendedTemporaryDecl itself as the base. + // FIXME: If we permit Objective-C object literals in template arguments, + // they should not imply internal linkage. + auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E); + if (!MTE || MTE->getStorageDuration() == SD_FullExpression) + return LinkageInfo::internal(); + if (MergeLV(getLVForDecl(MTE->getExtendingDecl(), computation))) + break; + } else { + assert(V.getLValueBase().is<DynamicAllocLValue>() && + "unexpected LValueBase kind"); + return LinkageInfo::internal(); + } + // The lvalue path doesn't matter: pointers to all subobjects always have + // the same visibility as pointers to the complete object. + break; + } + + case APValue::MemberPointer: + if (const NamedDecl *D = V.getMemberPointerDecl()) + MergeLV(getLVForDecl(D, computation)); + // Note that we could have a base-to-derived conversion here to a member of + // a derived class with less linkage/visibility. That's covered by the + // linkage and visibility of the value's type. + break; + } + + return LV; } |