aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/APValue.h24
-rw-r--r--lib/AST/APValue.cpp121
-rw-r--r--lib/AST/ExprConstant.cpp825
-rw-r--r--lib/CodeGen/CGExprConstant.cpp1
-rw-r--r--test/CodeGen/object-size.c3
-rw-r--r--test/CodeGenCXX/const-base-cast.cpp5
-rw-r--r--test/SemaCXX/constant-expression-cxx11.cpp209
7 files changed, 1008 insertions, 180 deletions
diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h
index 69b1d1b80d..cca00371c2 100644
--- a/include/clang/AST/APValue.h
+++ b/include/clang/AST/APValue.h
@@ -27,6 +27,7 @@ namespace clang {
class FieldDecl;
class Decl;
class ValueDecl;
+ class CXXRecordDecl;
/// APValue - This class implements a discriminated union of [uninitialized]
/// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset],
@@ -45,7 +46,8 @@ public:
Vector,
Array,
Struct,
- Union
+ Union,
+ MemberPointer
};
typedef llvm::PointerUnion<const ValueDecl *, const Expr *> LValueBase;
typedef llvm::PointerIntPair<const Decl *, 1, bool> BaseOrMemberType;
@@ -96,6 +98,7 @@ private:
UnionData();
~UnionData();
};
+ struct MemberPointerData;
enum {
MaxSize = (sizeof(ComplexAPSInt) > sizeof(ComplexAPFloat) ?
@@ -131,9 +134,10 @@ public:
: Kind(Uninitialized) {
MakeLValue(); setLValue(B, O, N);
}
- APValue(LValueBase B, const CharUnits &O, ArrayRef<LValuePathEntry> Path)
+ APValue(LValueBase B, const CharUnits &O, ArrayRef<LValuePathEntry> Path,
+ bool OnePastTheEnd)
: Kind(Uninitialized) {
- MakeLValue(); setLValue(B, O, Path);
+ MakeLValue(); setLValue(B, O, Path, OnePastTheEnd);
}
APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(Uninitialized) {
MakeArray(InitElts, Size);
@@ -145,6 +149,10 @@ public:
: Kind(Uninitialized) {
MakeUnion(); setUnion(D, V);
}
+ APValue(const ValueDecl *Member, bool IsDerivedMember,
+ ArrayRef<const CXXRecordDecl*> Path) : Kind(Uninitialized) {
+ MakeMemberPointer(Member, IsDerivedMember, Path);
+ }
~APValue() {
MakeUninit();
@@ -161,6 +169,7 @@ public:
bool isArray() const { return Kind == Array; }
bool isStruct() const { return Kind == Struct; }
bool isUnion() const { return Kind == Union; }
+ bool isMemberPointer() const { return Kind == MemberPointer; }
void print(raw_ostream &OS) const;
void dump() const;
@@ -218,6 +227,7 @@ public:
const CharUnits &getLValueOffset() const {
return const_cast<APValue*>(this)->getLValueOffset();
}
+ bool isLValueOnePastTheEnd() const;
bool hasLValuePath() const;
ArrayRef<LValuePathEntry> getLValuePath() const;
@@ -297,6 +307,10 @@ public:
return const_cast<APValue*>(this)->getUnionValue();
}
+ const ValueDecl *getMemberPointerDecl() const;
+ bool isMemberPointerToDerivedMember() const;
+ ArrayRef<const CXXRecordDecl*> getMemberPointerPath() const;
+
void setInt(const APSInt &I) {
assert(isInt() && "Invalid accessor");
*(APSInt*)(char*)Data = I;
@@ -328,7 +342,7 @@ public:
}
void setLValue(LValueBase B, const CharUnits &O, NoLValuePath);
void setLValue(LValueBase B, const CharUnits &O,
- ArrayRef<LValuePathEntry> Path);
+ ArrayRef<LValuePathEntry> Path, bool OnePastTheEnd);
void setUnion(const FieldDecl *Field, const APValue &Value) {
assert(isUnion() && "Invalid accessor");
((UnionData*)(char*)Data)->Field = Field;
@@ -376,6 +390,8 @@ private:
new ((void*)(char*)Data) UnionData();
Kind = Union;
}
+ void MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember,
+ ArrayRef<const CXXRecordDecl*> Path);
};
inline raw_ostream &operator<<(raw_ostream &OS, const APValue &V) {
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index 146ebad055..b99a66267c 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -21,7 +21,7 @@ using namespace clang;
namespace {
struct LVBase {
- APValue::LValueBase Base;
+ llvm::PointerIntPair<APValue::LValueBase, 1, bool> BaseAndIsOnePastTheEnd;
CharUnits Offset;
unsigned PathLength;
};
@@ -40,12 +40,17 @@ struct APValue::LV : LVBase {
};
LV() { PathLength = (unsigned)-1; }
- ~LV() { if (hasPathPtr()) delete [] PathPtr; }
+ ~LV() { resizePath(0); }
- void allocPath() {
- if (hasPathPtr()) PathPtr = new LValuePathEntry[PathLength];
+ void resizePath(unsigned Length) {
+ if (Length == PathLength)
+ return;
+ if (hasPathPtr())
+ delete [] PathPtr;
+ PathLength = Length;
+ if (hasPathPtr())
+ PathPtr = new LValuePathEntry[Length];
}
- void freePath() { if (hasPathPtr()) delete [] PathPtr; }
bool hasPath() const { return PathLength != (unsigned)-1; }
bool hasPathPtr() const { return hasPath() && PathLength > InlinePathSpace; }
@@ -56,6 +61,43 @@ struct APValue::LV : LVBase {
}
};
+namespace {
+ struct MemberPointerBase {
+ llvm::PointerIntPair<const ValueDecl*, 1, bool> MemberAndIsDerivedMember;
+ unsigned PathLength;
+ };
+}
+
+struct APValue::MemberPointerData : MemberPointerBase {
+ static const unsigned InlinePathSpace =
+ (MaxSize - 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) :
@@ -78,7 +120,8 @@ APValue::UnionData::~UnionData () {
const APValue &APValue::operator=(const APValue &RHS) {
if (this == &RHS)
return *this;
- if (Kind != RHS.Kind || Kind == Array || Kind == Struct) {
+ if (Kind != RHS.Kind || Kind == Array || Kind == Struct ||
+ Kind == MemberPointer) {
MakeUninit();
if (RHS.isInt())
MakeInt();
@@ -98,6 +141,10 @@ const APValue &APValue::operator=(const APValue &RHS) {
MakeStruct(RHS.getStructNumBases(), RHS.getStructNumFields());
else if (RHS.isUnion())
MakeUnion();
+ else if (RHS.isMemberPointer())
+ MakeMemberPointer(RHS.getMemberPointerDecl(),
+ RHS.isMemberPointerToDerivedMember(),
+ RHS.getMemberPointerPath());
}
if (isInt())
setInt(RHS.getInt());
@@ -112,7 +159,8 @@ const APValue &APValue::operator=(const APValue &RHS) {
setComplexFloat(RHS.getComplexFloatReal(), RHS.getComplexFloatImag());
else if (isLValue()) {
if (RHS.hasLValuePath())
- setLValue(RHS.getLValueBase(), RHS.getLValueOffset(),RHS.getLValuePath());
+ setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), RHS.getLValuePath(),
+ RHS.isLValueOnePastTheEnd());
else
setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath());
} else if (isArray()) {
@@ -149,6 +197,8 @@ void APValue::MakeUninit() {
((StructData*)(char*)Data)->~StructData();
else if (Kind == Union)
((UnionData*)(char*)Data)->~UnionData();
+ else if (Kind == MemberPointer)
+ ((MemberPointerData*)(char*)Data)->~MemberPointerData();
Kind = Uninitialized;
}
@@ -217,6 +267,9 @@ void APValue::print(raw_ostream &OS) const {
case Union:
OS << "Union: " << getUnionValue();
return;
+ case MemberPointer:
+ OS << "MemberPointer: <todo>";
+ return;
}
llvm_unreachable("Unknown APValue kind!");
}
@@ -280,6 +333,9 @@ static void WriteShortAPValueToStream(raw_ostream& Out,
case APValue::Union:
Out << '{' << V.getUnionValue() << '}';
return;
+ case APValue::MemberPointer:
+ Out << "MemberPointer: <todo>";
+ return;
}
llvm_unreachable("Unknown APValue kind!");
}
@@ -294,7 +350,12 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
const APValue::LValueBase APValue::getLValueBase() const {
assert(isLValue() && "Invalid accessor");
- return ((const LV*)(const void*)Data)->Base;
+ return ((const LV*)(const void*)Data)->BaseAndIsOnePastTheEnd.getPointer();
+}
+
+bool APValue::isLValueOnePastTheEnd() const {
+ assert(isLValue() && "Invalid accessor");
+ return ((const LV*)(const void*)Data)->BaseAndIsOnePastTheEnd.getInt();
}
CharUnits &APValue::getLValueOffset() {
@@ -316,24 +377,41 @@ ArrayRef<APValue::LValuePathEntry> APValue::getLValuePath() const {
void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath) {
assert(isLValue() && "Invalid accessor");
LV &LVal = *((LV*)(char*)Data);
- LVal.freePath();
- LVal.Base = B;
+ LVal.BaseAndIsOnePastTheEnd.setPointer(B);
+ LVal.BaseAndIsOnePastTheEnd.setInt(false);
LVal.Offset = O;
- LVal.PathLength = (unsigned)-1;
+ LVal.resizePath((unsigned)-1);
}
void APValue::setLValue(LValueBase B, const CharUnits &O,
- ArrayRef<LValuePathEntry> Path) {
+ ArrayRef<LValuePathEntry> Path, bool IsOnePastTheEnd) {
assert(isLValue() && "Invalid accessor");
LV &LVal = *((LV*)(char*)Data);
- LVal.freePath();
- LVal.Base = B;
+ LVal.BaseAndIsOnePastTheEnd.setPointer(B);
+ LVal.BaseAndIsOnePastTheEnd.setInt(IsOnePastTheEnd);
LVal.Offset = O;
- LVal.PathLength = Path.size();
- LVal.allocPath();
+ LVal.resizePath(Path.size());
memcpy(LVal.getPath(), Path.data(), Path.size() * sizeof(LValuePathEntry));
}
+const ValueDecl *APValue::getMemberPointerDecl() const {
+ assert(isMemberPointer() && "Invalid accessor");
+ const MemberPointerData &MPD = *((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);
+ return MPD.MemberAndIsDerivedMember.getInt();
+}
+
+ArrayRef<const CXXRecordDecl*> APValue::getMemberPointerPath() const {
+ assert(isMemberPointer() && "Invalid accessor");
+ const MemberPointerData &MPD = *((const MemberPointerData*)(const char*)Data);
+ return ArrayRef<const CXXRecordDecl*>(MPD.getPath(), MPD.PathLength);
+}
+
void APValue::MakeLValue() {
assert(isUninit() && "Bad state change");
assert(sizeof(LV) <= MaxSize && "LV too big");
@@ -346,3 +424,14 @@ void APValue::MakeArray(unsigned InitElts, unsigned Size) {
new ((void*)(char*)Data) Arr(InitElts, Size);
Kind = Array;
}
+
+void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember,
+ ArrayRef<const CXXRecordDecl*> Path) {
+ assert(isUninit() && "Bad state change");
+ MemberPointerData *MPD = new ((void*)(char*)Data) 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*));
+}
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index f461ec6429..d602be4581 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -126,6 +126,7 @@ namespace {
V.getLValuePath());
else
assert(V.getLValuePath().empty() &&"Null pointer with nonempty path");
+ OnePastTheEnd = V.isLValueOnePastTheEnd();
}
}
@@ -178,6 +179,10 @@ namespace {
/// A core constant value. This can be the value of any constant expression,
/// or a pointer or reference to a non-static object or function parameter.
+ ///
+ /// For an LValue, the base and offset are stored in the APValue subobject,
+ /// but the other information is stored in the SubobjectDesignator. For all
+ /// other value kinds, the value is stored directly in the APValue subobject.
class CCValue : public APValue {
typedef llvm::APSInt APSInt;
typedef llvm::APFloat APFloat;
@@ -202,6 +207,9 @@ namespace {
APValue(B, O, APValue::NoLValuePath()), CallFrame(F), Designator(D) {}
CCValue(const APValue &V, GlobalValue) :
APValue(V), CallFrame(0), Designator(V) {}
+ CCValue(const ValueDecl *D, bool IsDerivedMember,
+ ArrayRef<const CXXRecordDecl*> Path) :
+ APValue(D, IsDerivedMember, Path) {}
CallStackFrame *getLValueFrame() const {
assert(getKind() == LValue);
@@ -375,6 +383,95 @@ namespace {
Designator = SubobjectDesignator();
}
};
+
+ struct MemberPtr {
+ MemberPtr() {}
+ explicit MemberPtr(const ValueDecl *Decl) :
+ DeclAndIsDerivedMember(Decl, false), Path() {}
+
+ /// The member or (direct or indirect) field referred to by this member
+ /// pointer, or 0 if this is a null member pointer.
+ const ValueDecl *getDecl() const {
+ return DeclAndIsDerivedMember.getPointer();
+ }
+ /// Is this actually a member of some type derived from the relevant class?
+ bool isDerivedMember() const {
+ return DeclAndIsDerivedMember.getInt();
+ }
+ /// Get the class which the declaration actually lives in.
+ const CXXRecordDecl *getContainingRecord() const {
+ return cast<CXXRecordDecl>(
+ DeclAndIsDerivedMember.getPointer()->getDeclContext());
+ }
+
+ void moveInto(CCValue &V) const {
+ V = CCValue(getDecl(), isDerivedMember(), Path);
+ }
+ void setFrom(const CCValue &V) {
+ assert(V.isMemberPointer());
+ DeclAndIsDerivedMember.setPointer(V.getMemberPointerDecl());
+ DeclAndIsDerivedMember.setInt(V.isMemberPointerToDerivedMember());
+ Path.clear();
+ ArrayRef<const CXXRecordDecl*> P = V.getMemberPointerPath();
+ Path.insert(Path.end(), P.begin(), P.end());
+ }
+
+ /// DeclAndIsDerivedMember - The member declaration, and a flag indicating
+ /// whether the member is a member of some class derived from the class type
+ /// of the member pointer.
+ llvm::PointerIntPair<const ValueDecl*, 1, bool> DeclAndIsDerivedMember;
+ /// Path - The path of base/derived classes from the member declaration's
+ /// class (exclusive) to the class type of the member pointer (inclusive).
+ SmallVector<const CXXRecordDecl*, 4> Path;
+
+ /// Perform a cast towards the class of the Decl (either up or down the
+ /// hierarchy).
+ bool castBack(const CXXRecordDecl *Class) {
+ assert(!Path.empty());
+ const CXXRecordDecl *Expected;
+ if (Path.size() >= 2)
+ Expected = Path[Path.size() - 2];
+ else
+ Expected = getContainingRecord();
+ if (Expected->getCanonicalDecl() != Class->getCanonicalDecl()) {
+ // C++11 [expr.static.cast]p12: In a conversion from (D::*) to (B::*),
+ // if B does not contain the original member and is not a base or
+ // derived class of the class containing the original member, the result
+ // of the cast is undefined.
+ // C++11 [conv.mem]p2 does not cover this case for a cast from (B::*) to
+ // (D::*). We consider that to be a language defect.
+ return false;
+ }
+ Path.pop_back();
+ return true;
+ }
+ /// Perform a base-to-derived member pointer cast.
+ bool castToDerived(const CXXRecordDecl *Derived) {
+ if (!getDecl())
+ return true;
+ if (!isDerivedMember()) {
+ Path.push_back(Derived);
+ return true;
+ }
+ if (!castBack(Derived))
+ return false;
+ if (Path.empty())
+ DeclAndIsDerivedMember.setInt(false);
+ return true;
+ }
+ /// Perform a derived-to-base member pointer cast.
+ bool castToBase(const CXXRecordDecl *Base) {
+ if (!getDecl())
+ return true;
+ if (Path.empty())
+ DeclAndIsDerivedMember.setInt(true);
+ if (isDerivedMember()) {
+ Path.push_back(Base);
+ return true;
+ }
+ return castBack(Base);
+ }
+ };
}
static bool Evaluate(CCValue &Result, EvalInfo &Info, const Expr *E);
@@ -382,6 +479,9 @@ static bool EvaluateConstantExpression(APValue &Result, EvalInfo &Info,
const LValue &This, const Expr *E);
static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info);
static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info);
+static bool EvaluateMemberPointer(const Expr *E, MemberPtr &Result,
+ EvalInfo &Info);
+static bool EvaluateTemporary(const Expr *E, LValue &Result, EvalInfo &Info);
static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info);
static bool EvaluateIntegerOrLValue(const Expr *E, CCValue &Result,
EvalInfo &Info);
@@ -448,19 +548,16 @@ static bool CheckLValueConstantExpression(const T &LVal, APValue &Value) {
const SubobjectDesignator &Designator = LVal.getLValueDesignator();
// A constant expression must refer to an object or be a null pointer.
- if (Designator.Invalid || Designator.OnePastTheEnd ||
+ if (Designator.Invalid ||
(!LVal.getLValueBase() && !Designator.Entries.empty())) {
- // FIXME: Check for out-of-bounds array indices.
// FIXME: This is not a constant expression.
Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(),
APValue::NoLValuePath());
return true;
}
- // FIXME: Null references are not constant expressions.
-
Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(),
- Designator.Entries);
+ Designator.Entries, Designator.OnePastTheEnd);
return true;
}
@@ -493,23 +590,23 @@ static bool IsWeakLValue(const LValue &Value) {
return Decl && IsWeakDecl(Decl);
}
-static bool EvalPointerValueAsBool(const LValue &Value, bool &Result) {
+static bool EvalPointerValueAsBool(const CCValue &Value, bool &Result) {
// A null base expression indicates a null pointer. These are always
// evaluatable, and they are false unless the offset is zero.
- if (!Value.Base) {
- Result = !Value.Offset.isZero();
+ if (!Value.getLValueBase()) {
+ Result = !Value.getLValueOffset().isZero();
return true;
}
// Require the base expression to be a global l-value.
// FIXME: C++11 requires such conversions. Remove this check.
- if (!IsGlobalLValue(Value.Base)) return false;
+ if (!IsGlobalLValue(Value.getLValueBase())) return false;
- // We have a non-null base expression. These are generally known to
- // be true, but if it'a decl-ref to a weak symbol it can be null at
- // runtime.
+ // We have a non-null base. These are generally known to be true, but if it's
+ // a weak declaration it can be null at runtime.
Result = true;
- return !IsWeakLValue(Value);
+ const ValueDecl *Decl = Value.getLValueBase().dyn_cast<const ValueDecl*>();
+ return !Decl || !IsWeakDecl(Decl);
}
static bool HandleConversionToBool(const CCValue &Val, bool &Result) {
@@ -530,11 +627,11 @@ static bool HandleConversionToBool(const CCValue &Val, bool &Result) {
Result = !Val.getComplexFloatReal().isZero() ||
!Val.getComplexFloatImag().isZero();
return true;
- case APValue::LValue: {
- LValue PointerResult;
- PointerResult.setFrom(Val);
- return EvalPointerValueAsBool(PointerResult, Result);
- }
+ case APValue::LValue:
+ return EvalPointerValueAsBool(Val, Result);
+ case APValue::MemberPointer:
+ Result = Val.getMemberPointerDecl();
+ return true;
case APValue::Vector:
case APValue::Array:
case APValue::Struct:
@@ -596,21 +693,20 @@ static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType,
return Result;
}
-/// If the given LValue refers to a base subobject of some object, find the most
-/// derived object and the corresponding complete record type. This is necessary
-/// in order to find the offset of a virtual base class.
-static bool ExtractMostDerivedObject(EvalInfo &Info, LValue &Result,
- const CXXRecordDecl *&MostDerivedType) {
- SubobjectDesignator &D = Result.Designator;
- if (D.Invalid || !Result.Base)
+static bool FindMostDerivedObject(EvalInfo &Info, const LValue &LVal,
+ const CXXRecordDecl *&MostDerivedType,
+ unsigned &MostDerivedPathLength,
+ bool &MostDerivedIsArrayElement) {
+ const SubobjectDesignator &D = LVal.Designator;
+ if (D.Invalid || !LVal.Base)
return false;
- const Type *T = getType(Result.Base).getTypePtr();
+ const Type *T = getType(LVal.Base).getTypePtr();
// Find path prefix which leads to the most-derived subobject.
- unsigned MostDerivedPathLength = 0;
MostDerivedType = T->getAsCXXRecordDecl();
- bool MostDerivedIsArrayElement = false;
+ MostDerivedPathLength = 0;
+ MostDerivedIsArrayElement = false;
for (unsigned I = 0, N = D.Entries.size(); I != N; ++I) {
bool IsArray = T && T->isArrayType();
@@ -628,28 +724,46 @@ static bool ExtractMostDerivedObject(EvalInfo &Info, LValue &Result,
}
}
- if (!MostDerivedType)
- return false;
-
// (B*)&d + 1 has no most-derived object.
if (D.OnePastTheEnd && MostDerivedPathLength != D.Entries.size())
return false;
- // Remove the trailing base class path entries and their offsets.
- const RecordDecl *RD = MostDerivedType;
- for (unsigned I = MostDerivedPathLength, N = D.Entries.size(); I != N; ++I) {
+ return MostDerivedType != 0;
+}
+
+static void TruncateLValueBasePath(EvalInfo &Info, LValue &Result,
+ const RecordDecl *TruncatedType,
+ unsigned TruncatedElements,
+ bool IsArrayElement) {
+ SubobjectDesignator &D = Result.Designator;
+ const RecordDecl *RD = TruncatedType;
+ for (unsigned I = TruncatedElements, N = D.Entries.size(); I != N; ++I) {
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
const CXXRecordDecl *Base = getAsBaseClass(D.Entries[I]);
- if (isVirtualBaseClass(D.Entries[I])) {
- assert(I == MostDerivedPathLength &&
- "virtual base class must be immediately after most-derived class");
+ if (isVirtualBaseClass(D.Entries[I]))
Result.Offset -= Layout.getVBaseClassOffset(Base);
- } else
+ else
Result.Offset -= Layout.getBaseClassOffset(Base);
RD = Base;
}
- D.Entries.resize(MostDerivedPathLength);
- D.ArrayElement = MostDerivedIsArrayElement;
+ D.Entries.resize(TruncatedElements);
+ D.ArrayElement = IsArrayElement;
+}
+
+/// If the given LValue refers to a base subobject of some object, find the most
+/// derived object and the corresponding complete record type. This is necessary
+/// in order to find the offset of a virtual base class.
+static bool ExtractMostDerivedObject(EvalInfo &Info, LValue &Result,
+ const CXXRecordDecl *&MostDerivedType) {
+ unsigned MostDerivedPathLength;
+ bool MostDerivedIsArrayElement;
+ if (!FindMostDerivedObject(Info, Result, MostDerivedType,
+ MostDerivedPathLength, MostDerivedIsArrayElement))
+ return false;
+
+ // Remove the trailing base class path entries and their offsets.
+ TruncateLValueBasePath(Info, Result, MostDerivedType, MostDerivedPathLength,
+ MostDerivedIsArrayElement);
return true;
}
@@ -969,10 +1083,141 @@ static bool EvaluateObjectArgument(EvalInfo &Info, const Expr *Object,
if (Object->isGLValue())
return EvaluateLValue(Object, This, Info);
- // Implicitly promote a prvalue *this object to a glvalue.
- This.set(Object, Info.CurrentCall);
- return EvaluateConstantExpression(Info.CurrentCall->Temporaries[Object], Info,
- This, Object);
+ if (Object->getType()->isLiteralType())
+ return EvaluateTemporary(Object, This, Info);
+
+ return false;
+}
+
+/// HandleMemberPointerAccess - Evaluate a member access operation and build an
+/// lvalue referring to the result.
+///
+/// \param Info - Information about the ongoing evaluation.
+/// \param BO - The member pointer access operation.
+/// \param LV - Filled in with a reference to the resulting object.
+/// \param IncludeMember - Specifies whether the member itself is included in
+/// the resulting LValue subobject designator. This is not possible when
+/// creating a bound member function.
+/// \return The field or method declaration to which the member pointer refers,
+/// or 0 if evaluation fails.
+static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
+ const BinaryOperator *BO,
+ LValue &LV,
+ bool IncludeMember = true) {
+ assert(BO->getOpcode() == BO_PtrMemD || BO->getOpcode() == BO_PtrMemI);
+
+ if (!EvaluateObjectArgument(Info, BO->getLHS(), LV))
+ return 0;
+
+ MemberPtr MemPtr;
+ if (!EvaluateMemberPointer(BO->getRHS(), MemPtr, Info))
+ return 0;
+
+ // C++11 [expr.mptr.oper]p6: If the second operand is the null pointer to
+ // member value, the behavior is undefined.
+ if (!MemPtr.getDecl())
+ return 0;
+
+ if (MemPtr.isDerivedMember()) {
+ // This is a member of some derived class. Truncate LV appropriately.
+ const CXXRecordDecl *MostDerivedType;
+ unsigned MostDerivedPathLength;
+ bool MostDerivedIsArrayElement;
+ if (!FindMostDerivedObject(Info, LV, MostDerivedType, MostDerivedPathLength,
+ MostDerivedIsArrayElement))
+ return 0;
+
+ // The end of the derived-to-base path for the base object must match the
+ // derived-to-base path for the member pointer.
+ if (MostDerivedPathLength + MemPtr.Path.size() >
+ LV.Designator.Entries.size())
+ return 0;
+ unsigned PathLengthToMember =
+ LV.Designator.Entries.size() - MemPtr.Path.size();
+ for (unsigned I = 0, N = MemPtr.Path.size(); I != N; ++I) {
+ const CXXRecordDecl *LVDecl = getAsBaseClass(
+ LV.Designator.Entries[PathLengthToMember + I]);
+ const CXXRecordDecl *MPDecl = MemPtr.Path[I];
+ if (LVDecl->getCanonicalDecl() != MPDecl->getCanonicalDecl())
+ return 0;
+ }
+
+ // Truncate the lvalue to the appropriate derived class.
+ bool ResultIsArray = false;
+ if (PathLengthToMember == MostDerivedPathLength)
+ ResultIsArray = MostDerivedIsArrayElement;
+ TruncateLValueBasePath(Info, LV, MemPtr.getContainingRecord(),
+ PathLengthToMember, ResultIsArray);
+ } else if (!MemPtr.Path.empty()) {
+ // Extend the LValue path with the member pointer's path.
+ LV.Designator.Entries.reserve(LV.Designator.Entries.size() +
+ MemPtr.Path.size() + IncludeMember);
+
+ // Walk down to the appropriate base class.
+ QualType LVType = BO->getLHS()->getType();
+ if (const PointerType *PT = LVType->getAs<PointerType>())
+ LVType = PT->getPointeeType();
+ const CXXRecordDecl *RD = LVType->getAsCXXRecordDecl();
+ assert(RD && "member pointer access on non-class-type expression");
+ // The first class in the path is that of the lvalue.
+ for (unsigned I = 1, N = MemPtr.Path.size(); I != N; ++I) {
+ const CXXRecordDecl *Base = MemPtr.Path[N - I - 1];
+ HandleLValueDirectBase(Info, LV, RD, Base);
+ RD = Base;
+ }
+ // Finally cast to the class containing the member.
+ HandleLValueDirectBase(Info, LV, RD, MemPtr.getContainingRecord());
+ }
+
+ // Add the member. Note that we cannot build bound member functions here.
+ if (IncludeMember) {
+ // FIXME: Deal with IndirectFieldDecls.
+ const FieldDecl *FD = dyn_cast<FieldDecl>(MemPtr.getDecl());
+ if (!FD) return 0;
+ HandleLValueMember(Info, LV, FD);
+ }
+
+ return MemPtr.getDecl();
+}
+
+/// HandleBaseToDerivedCast - Apply the given base-to-derived cast operation on
+/// the provided lvalue, which currently refers to the base object.
+static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E,
+ LValue &Result) {
+ const CXXRecordDecl *MostDerivedType;
+ unsigned MostDerivedPathLength;
+ bool MostDerivedIsArrayElement;
+
+ // Check this cast doesn't take us outside the object.
+ if (!FindMostDerivedObject(Info, Result, MostDerivedType,
+ MostDerivedPathLength,
+ MostDerivedIsArrayElement))
+ return false;
+ SubobjectDesignator &D = Result.Designator;
+ if (MostDerivedPathLength + E->path_size() > D.Entries.size())
+ return false;
+
+ // Check the type of the final cast. We don't need to check the path,
+ // since a cast can only be formed if the path is unique.
+ unsigned NewEntriesSize = D.Entries.size() - E->path_size();
+ bool ResultIsArray = false;
+ QualType TargetQT = E->getType();
+ if (const PointerType *PT = TargetQT->getAs<PointerType>())
+ TargetQT = PT->getPointeeType();
+ const CXXRecordDecl *TargetType = TargetQT->getAsCXXRecordDecl();
+ const CXXRecordDecl *FinalType;
+ if (NewEntriesSize == MostDerivedPathLength) {
+ ResultIsArray = MostDerivedIsArrayElement;
+ FinalType = MostDerivedType;
+ } else
+ FinalType = getAsBaseClass(D.Entries[NewEntriesSize - 1]);
+ if (FinalType->getCanonicalDecl() != TargetType->getCanonicalDecl())
+ return false;
+
+ // Truncate the lvalue to the appropriate derived class.
+ TruncateLValueBasePath(Info, Result, TargetType, NewEntriesSize,
+ ResultIsArray);
+ return true;
}
namespace {
@@ -1273,6 +1518,28 @@ public:
RetTy VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E)
{ return StmtVisitorTy::Visit(E->getExpr()); }
+ RetTy VisitBinaryOperator(const BinaryOperator *E) {
+ switch (E->getOpcode()) {
+ default:
+ return DerivedError(E);
+
+ case BO_Comma:
+ VisitIgnoredValue(E->getLHS());
+ return StmtVisitorTy::Visit(E->getRHS());
+
+ case BO_PtrMemD:
+ case BO_PtrMemI: {
+ LValue Obj;
+ if (!HandleMemberPointerAccess(Info, E, Obj))
+ return false;
+ CCValue Result;
+ if (!HandleLValueToRValueConversion(Info, E->getType(), Obj, Result))
+ return false;
+ return DerivedSuccess(Result, E);
+ }
+ }
+ }
+
RetTy VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) {
OpaqueValueEvaluation opaque(Info, E->getOpaqueValue(), E->getCommon());
if (opaque.hasError())
@@ -1303,7 +1570,7 @@ public:
}
RetTy VisitCallExpr(const CallExpr *E) {
- const Expr *Callee = E->getCallee();
+ const Expr *Callee = E->getCallee()->IgnoreParens();
QualType CalleeType = Callee->getType();
const FunctionDecl *FD = 0;
@@ -1312,17 +1579,24 @@ public:
// Extract function decl and 'this' pointer from the callee.
if (CalleeType->isSpecificBuiltinType(BuiltinType::BoundMember)) {
- // Explicit bound member calls, such as x.f() or p->g();
- // FIXME: Handle a BinaryOperator callee ('.*' or '->*').
- const MemberExpr *ME = dyn_cast<MemberExpr>(Callee->IgnoreParens());
- if (!ME)
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(Callee)) {
+ // Explicit bound member calls, such as x.f() or p->g();
+ if (!EvaluateObjectArgument(Info, ME->getBase(), ThisVal))
+ return DerivedError(ME->getBase());
+ This = &ThisVal;
+ FD = dyn_cast<FunctionDecl>(ME->getMemberDecl());
+ if (!FD)
+ return DerivedError(ME);
+ } else if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(Callee)) {
+ // Indirect bound member calls ('.*' or '->*').
+ const ValueDecl *Member = HandleMemberPointerAccess(Info, BE, ThisVal,
+ false);
+ This = &ThisVal;
+ FD = dyn_cast_or_null<FunctionDecl>(Member);
+ if (!FD)
+ return DerivedError(Callee);
+ } else
return DerivedError(Callee);
- if (!EvaluateObjectArgument(Info, ME->getBase(), ThisVal))
- return DerivedError(ME->getBase());
- This = &ThisVal;
- FD = dyn_cast<FunctionDecl>(ME->getMemberDecl());
- if (!FD)
- return DerivedError(ME);
} else if (CalleeType->isFunctionPointerType()) {
CCValue Call;
if (!Evaluate(Call, Info, Callee) || !Call.isLValue() ||
@@ -1381,6 +1655,9 @@ public:
RetTy VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) {
return DerivedValueInitialization(E);
}
+ RetTy VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) {
+ return DerivedValueInitialization(E);
+ }
/// A member expression where the object is a prvalue is itself a prvalue.
RetTy VisitMemberExpr(const MemberExpr *E) {
@@ -1438,6 +1715,118 @@ public:
}
//===----------------------------------------------------------------------===//
+// Common base class for lvalue and temporary evaluation.
+//===----------------------------------------------------------------------===//
+namespace {
+template<class Derived>
+class LValueExprEvaluatorBase
+ : public ExprEvaluatorBase<Derived, bool> {
+protected:
+ LValue &Result;
+ typedef LValueExprEvaluatorBase LValueExprEvaluatorBaseTy;
+ typedef ExprEvaluatorBase<Derived, bool> ExprEvaluatorBaseTy;
+
+ bool Success(APValue::LValueBase B) {
+ Result.set(B);
+ return true;
+ }
+
+public:
+ LValueExprEvaluatorBase(EvalInfo &Info, LValue &Result) :
+ ExprEvaluatorBaseTy(Info), Result(Result) {}
+
+ bool Success(const CCValue &V, const Expr *E) {
+ Result.setFrom(V);
+ return true;
+ }
+ bool Error(const Expr *E) {
+ return false;
+ }
+
+ bool CheckValidLValue() {
+ // C++11 [basic.lval]p1: An lvalue designates a function or an object. Hence
+ // there are no null references, nor once-past-the-end references.
+ // FIXME: Check for one-past-the-end array indices
+ return Result.Base && !Result.Designator.Invalid &&
+ !Result.Designator.OnePastTheEnd;
+ }
+
+ bool VisitMemberExpr(const MemberExpr *E) {
+ // Handle non-static data members.
+ QualType BaseTy;
+ if (E->isArrow()) {
+ if (!EvaluatePointer(E->getBase(), Result, this->Info))
+ return false;
+ BaseTy = E->getBase()->getType()->getAs<PointerType>()->getPointeeType();
+ } else {
+ if (!this->Visit(E->getBase()))
+ return false;
+ BaseTy = E->getBase()->getType();
+ }
+ // FIXME: In C++11, require the result to be a valid lvalue.
+
+ const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
+ // FIXME: Handle IndirectFieldDecls
+ if (!FD) return false;
+ assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() ==
+ FD->getParent()->getCanonicalDecl() && "record / field mismatch");
+ (void)BaseTy;
+
+ HandleLValueMember(this->Info, Result, FD);
+
+ if (FD->getType()->isReferenceType()) {
+ CCValue RefValue;
+ if (!HandleLValueToRValueConversion(this->Info, FD->getType(), Result,
+ RefValue))
+ return false;
+ return Success(RefValue, E);
+ }
+ return true;
+ }
+
+ bool VisitBinaryOperator(const BinaryOperator *E) {
+ switch (E->getOpcode()) {
+ default:
+ return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
+
+ case BO_PtrMemD:
+ case BO_PtrMemI:
+ return HandleMemberPointerAccess(this->Info, E, Result);
+ }
+ }
+
+ bool VisitCastExpr(const CastExpr *E) {
+ switch (E->getCastKind()) {
+ default:
+ return ExprEvaluatorBaseTy::VisitCastExpr(E);
+
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase: {
+ if (!this->Visit(E->getSubExpr()))
+ return false;
+ if (!CheckValidLValue())