Constant expression evaluation: support for evaluation of structs and unions of
literal types, as well as derived-to-base casts for lvalues and
derived-to-virtual-base casts.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@144265 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index af34642..e64bf7c 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -45,6 +45,7 @@
void allocPath() {
if (hasPathPtr()) PathPtr = new LValuePathEntry[PathLength];
}
+ void freePath() { if (hasPathPtr()) delete [] PathPtr; }
bool hasPath() const { return PathLength != (unsigned)-1; }
bool hasPathPtr() const { return hasPath() && PathLength > InlinePathSpace; }
@@ -62,13 +63,27 @@
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(0), Value(new APValue) {}
+APValue::UnionData::~UnionData () {
+ delete Value;
+}
+
APValue::APValue(const Expr* B) : Kind(Uninitialized) {
MakeLValue();
setLValue(B, CharUnits::Zero(), ArrayRef<LValuePathEntry>());
}
const APValue &APValue::operator=(const APValue &RHS) {
- if (Kind != RHS.Kind) {
+ if (this == &RHS)
+ return *this;
+ if (Kind != RHS.Kind || Kind == Array || Kind == Struct) {
MakeUninit();
if (RHS.isInt())
MakeInt();
@@ -84,6 +99,10 @@
MakeLValue();
else if (RHS.isArray())
MakeArray(RHS.getArrayInitializedElts(), RHS.getArraySize());
+ else if (RHS.isStruct())
+ MakeStruct(RHS.getStructNumBases(), RHS.getStructNumFields());
+ else if (RHS.isUnion())
+ MakeUnion();
}
if (isInt())
setInt(RHS.getInt());
@@ -106,7 +125,13 @@
getArrayInitializedElt(I) = RHS.getArrayInitializedElt(I);
if (RHS.hasArrayFiller())
getArrayFiller() = RHS.getArrayFiller();
- }
+ } else if (isStruct()) {
+ 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);
+ } else if (isUnion())
+ setUnion(RHS.getUnionField(), RHS.getUnionValue());
return *this;
}
@@ -125,6 +150,10 @@
((LV*)(char*)Data)->~LV();
else if (Kind == Array)
((Arr*)(char*)Data)->~Arr();
+ else if (Kind == Struct)
+ ((StructData*)(char*)Data)->~StructData();
+ else if (Kind == Union)
+ ((UnionData*)(char*)Data)->~UnionData();
Kind = Uninitialized;
}
@@ -143,7 +172,6 @@
void APValue::print(raw_ostream &OS) const {
switch (getKind()) {
- default: llvm_unreachable("Unknown APValue kind!");
case Uninitialized:
OS << "Uninitialized";
return;
@@ -178,22 +206,38 @@
OS << getArraySize() - getArrayInitializedElts() << " x "
<< getArrayFiller();
return;
+ case Struct:
+ OS << "Struct ";
+ if (unsigned N = getStructNumBases()) {
+ OS << " bases: " << getStructBase(0);
+ for (unsigned I = 1; I != N; ++I)
+ OS << ", " << getStructBase(I);
+ }
+ if (unsigned N = getStructNumFields()) {
+ OS << " fields: " << getStructField(0);
+ for (unsigned I = 1; I != N; ++I)
+ OS << ", " << getStructField(I);
+ }
+ return;
+ case Union:
+ OS << "Union: " << getUnionValue();
+ return;
}
+ llvm_unreachable("Unknown APValue kind!");
}
static void WriteShortAPValueToStream(raw_ostream& Out,
const APValue& V) {
switch (V.getKind()) {
- default: llvm_unreachable("Unknown APValue kind!");
case APValue::Uninitialized:
Out << "Uninitialized";
- break;
+ return;
case APValue::Int:
Out << V.getInt();
- break;
+ return;
case APValue::Float:
Out << GetApproxValue(V.getFloat());
- break;
+ return;
case APValue::Vector:
Out << '[';
WriteShortAPValueToStream(Out, V.getVectorElt(0));
@@ -202,17 +246,17 @@
WriteShortAPValueToStream(Out, V.getVectorElt(i));
}
Out << ']';
- break;
+ return;
case APValue::ComplexInt:
Out << V.getComplexIntReal() << "+" << V.getComplexIntImag() << "i";
- break;
+ return;
case APValue::ComplexFloat:
Out << GetApproxValue(V.getComplexFloatReal()) << "+"
<< GetApproxValue(V.getComplexFloatImag()) << "i";
- break;
+ return;
case APValue::LValue:
Out << "LValue: <todo>";
- break;
+ return;
case APValue::Array:
Out << '{';
if (unsigned N = V.getArrayInitializedElts()) {
@@ -221,8 +265,28 @@
Out << ", " << V.getArrayInitializedElt(I);
}
Out << '}';
- break;
+ return;
+ case APValue::Struct:
+ Out << '{';
+ if (unsigned N = V.getStructNumBases()) {
+ Out << V.getStructBase(0);
+ for (unsigned I = 1; I != N; ++I)
+ Out << ", " << V.getStructBase(I);
+ if (V.getStructNumFields())
+ Out << ", ";
+ }
+ if (unsigned N = V.getStructNumFields()) {
+ Out << V.getStructField(0);
+ for (unsigned I = 1; I != N; ++I)
+ Out << ", " << V.getStructField(I);
+ }
+ Out << '}';
+ return;
+ case APValue::Union:
+ Out << '{' << V.getUnionValue() << '}';
+ return;
}
+ llvm_unreachable("Unknown APValue kind!");
}
const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
@@ -257,6 +321,7 @@
void APValue::setLValue(const Expr *B, const CharUnits &O, NoLValuePath) {
assert(isLValue() && "Invalid accessor");
LV &LVal = *((LV*)(char*)Data);
+ LVal.freePath();
LVal.Base = B;
LVal.Offset = O;
LVal.PathLength = (unsigned)-1;
@@ -266,6 +331,7 @@
ArrayRef<LValuePathEntry> Path) {
assert(isLValue() && "Invalid accessor");
LV &LVal = *((LV*)(char*)Data);
+ LVal.freePath();
LVal.Base = B;
LVal.Offset = O;
LVal.PathLength = Path.size();