summaryrefslogtreecommitdiff
path: root/lib/AST/APValue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST/APValue.cpp')
-rw-r--r--lib/AST/APValue.cpp166
1 files changed, 135 insertions, 31 deletions
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index c05b160b8e3d..1993bba9bd1a 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -1,9 +1,8 @@
//===--- APValue.cpp - Union class for APFloat/APSInt/Complex -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -21,6 +20,61 @@
#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::getTypeInfo(TypeInfoLValue LV,
+ QualType TypeInfo) {
+ LValueBase Base;
+ Base.Ptr = LV;
+ Base.TypeInfoType = TypeInfo.getAsOpaquePtr();
+ return Base;
+}
+
+unsigned APValue::LValueBase::getCallIndex() const {
+ return is<TypeInfoLValue>() ? 0 : Local.CallIndex;
+}
+
+unsigned APValue::LValueBase::getVersion() const {
+ return is<TypeInfoLValue>() ? 0 : Local.Version;
+}
+
+QualType APValue::LValueBase::getTypeInfoType() const {
+ assert(is<TypeInfoLValue>() && "not a type_info lvalue");
+ return QualType::getFromOpaquePtr(TypeInfoType);
+}
+
+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;
@@ -46,26 +100,27 @@ APValue::LValueBase::operator bool () const {
clang::APValue::LValueBase
llvm::DenseMapInfo<clang::APValue::LValueBase>::getEmptyKey() {
return clang::APValue::LValueBase(
- DenseMapInfo<clang::APValue::LValueBase::PtrTy>::getEmptyKey(),
- DenseMapInfo<unsigned>::getEmptyKey(),
- DenseMapInfo<unsigned>::getEmptyKey());
+ DenseMapInfo<const ValueDecl*>::getEmptyKey());
}
clang::APValue::LValueBase
llvm::DenseMapInfo<clang::APValue::LValueBase>::getTombstoneKey() {
return clang::APValue::LValueBase(
- DenseMapInfo<clang::APValue::LValueBase::PtrTy>::getTombstoneKey(),
- DenseMapInfo<unsigned>::getTombstoneKey(),
- DenseMapInfo<unsigned>::getTombstoneKey());
+ DenseMapInfo<const ValueDecl*>::getTombstoneKey());
+}
+
+namespace clang {
+llvm::hash_code hash_value(const APValue::LValueBase &Base) {
+ if (Base.is<TypeInfoLValue>())
+ 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) {
- llvm::FoldingSetNodeID ID;
- ID.AddPointer(Base.getOpaqueValue());
- ID.AddInteger(Base.getCallIndex());
- ID.AddInteger(Base.getVersion());
- return ID.ComputeHash();
+ return hash_value(Base);
}
bool llvm::DenseMapInfo<clang::APValue::LValueBase>::isEqual(
@@ -164,9 +219,11 @@ APValue::UnionData::~UnionData () {
delete Value;
}
-APValue::APValue(const APValue &RHS) : Kind(Uninitialized) {
+APValue::APValue(const APValue &RHS) : Kind(None) {
switch (RHS.getKind()) {
- case Uninitialized:
+ case None:
+ case Indeterminate:
+ Kind = RHS.getKind();
break;
case Int:
MakeInt();
@@ -176,6 +233,11 @@ APValue::APValue(const APValue &RHS) : Kind(Uninitialized) {
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,
@@ -233,6 +295,8 @@ void APValue::DestroyDataAndMakeUninit() {
((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)
@@ -251,12 +315,13 @@ void APValue::DestroyDataAndMakeUninit() {
((MemberPointerData*)(char*)Data.buffer)->~MemberPointerData();
else if (Kind == AddrLabelDiff)
((AddrLabelDiffData*)(char*)Data.buffer)->~AddrLabelDiffData();
- Kind = Uninitialized;
+ Kind = None;
}
bool APValue::needsCleanup() const {
switch (getKind()) {
- case Uninitialized:
+ case None:
+ case Indeterminate:
case AddrLabelDiff:
return false;
case Struct:
@@ -268,6 +333,8 @@ bool APValue::needsCleanup() const {
return getInt().needsCleanup();
case Float:
return getFloat().needsCleanup();
+ case FixedPoint:
+ return getFixedPoint().getValue().needsCleanup();
case ComplexFloat:
assert(getComplexFloatImag().needsCleanup() ==
getComplexFloatReal().needsCleanup() &&
@@ -312,8 +379,11 @@ static double GetApproxValue(const llvm::APFloat &F) {
void APValue::dump(raw_ostream &OS) const {
switch (getKind()) {
- case Uninitialized:
- OS << "Uninitialized";
+ case None:
+ OS << "None";
+ return;
+ case Indeterminate:
+ OS << "Indeterminate";
return;
case Int:
OS << "Int: " << getInt();
@@ -321,6 +391,9 @@ void APValue::dump(raw_ostream &OS) const {
case Float:
OS << "Float: " << GetApproxValue(getFloat());
return;
+ case FixedPoint:
+ OS << "FixedPoint : " << getFixedPoint();
+ return;
case Vector:
OS << "Vector: ";
getVectorElt(0).dump(OS);
@@ -383,9 +456,13 @@ void APValue::dump(raw_ostream &OS) const {
llvm_unreachable("Unknown APValue kind!");
}
-void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
+void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx,
+ QualType Ty) const {
switch (getKind()) {
- case APValue::Uninitialized:
+ case APValue::None:
+ Out << "<out of lifetime>";
+ return;
+ case APValue::Indeterminate:
Out << "<uninitialized>";
return;
case APValue::Int:
@@ -397,6 +474,9 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
case APValue::Float:
Out << GetApproxValue(getFloat());
return;
+ case APValue::FixedPoint:
+ Out << getFixedPoint();
+ return;
case APValue::Vector: {
Out << '{';
QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
@@ -453,7 +533,9 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>())
Out << *VD;
- else {
+ else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) {
+ TI.print(Out, Ctx.getPrintingPolicy());
+ } else {
assert(Base.get<const Expr *>() != nullptr &&
"Expecting non-null Expr");
Base.get<const Expr*>()->printPretty(Out, nullptr,
@@ -478,6 +560,9 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
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 {
const Expr *E = Base.get<const Expr*>();
assert(E != nullptr && "Expecting non-null Expr");
@@ -491,8 +576,7 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
if (ElemTy->getAs<RecordType>()) {
// The lvalue refers to a class type, so the next path entry is a base
// or member.
- const Decl *BaseOrMember =
- BaseOrMemberType::getFromOpaqueValue(Path[I].BaseOrMember).getPointer();
+ const Decl *BaseOrMember = Path[I].getAsBaseOrMember().getPointer();
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
CastToBase = RD;
ElemTy = Ctx.getRecordType(RD);
@@ -506,7 +590,7 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
}
} else {
// The lvalue must refer to an array.
- Out << '[' << Path[I].ArrayIndex << ']';
+ Out << '[' << Path[I].getAsArrayIndex() << ']';
ElemTy = Ctx.getAsArrayType(ElemTy)->getElementType();
}
}
@@ -592,7 +676,7 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
llvm_unreachable("Unknown APValue kind!");
}
-std::string APValue::getAsString(ASTContext &Ctx, QualType Ty) const {
+std::string APValue::getAsString(const ASTContext &Ctx, QualType Ty) const {
std::string Result;
llvm::raw_string_ostream Out(Result);
printPretty(Out, Ctx, Ty);
@@ -600,6 +684,26 @@ std::string APValue::getAsString(ASTContext &Ctx, QualType Ty) const {
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;
@@ -687,21 +791,21 @@ ArrayRef<const CXXRecordDecl*> APValue::getMemberPointerPath() const {
}
void APValue::MakeLValue() {
- assert(isUninit() && "Bad state change");
+ 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(isUninit() && "Bad state change");
+ 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(isUninit() && "Bad state change");
+ assert(isAbsent() && "Bad state change");
MemberPointerData *MPD = new ((void*)(char*)Data.buffer) MemberPointerData;
Kind = MemberPointer;
MPD->MemberAndIsDerivedMember.setPointer(Member);