[cfe-commits] r144926 - in /cfe/trunk: include/clang/AST/APValue.h lib/AST/APValue.cpp lib/AST/ExprConstant.cpp lib/CodeGen/CGExprConstant.cpp test/CodeGen/object-size.c test/CodeGenCXX/const-base-cast.cpp test/SemaCXX/constant-expression-cxx11.cpp
Richard Smith
richard-llvm at metafoo.co.uk
Thu Nov 17 14:56:20 PST 2011
Author: rsmith
Date: Thu Nov 17 16:56:20 2011
New Revision: 144926
URL: http://llvm.org/viewvc/llvm-project?rev=144926&view=rev
Log:
Constant expression evaluation: add support for evaluation of member pointers
and base-to-derived casts, and add proper handling of temporaries.
Modified:
cfe/trunk/include/clang/AST/APValue.h
cfe/trunk/lib/AST/APValue.cpp
cfe/trunk/lib/AST/ExprConstant.cpp
cfe/trunk/lib/CodeGen/CGExprConstant.cpp
cfe/trunk/test/CodeGen/object-size.c
cfe/trunk/test/CodeGenCXX/const-base-cast.cpp
cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
Modified: cfe/trunk/include/clang/AST/APValue.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/APValue.h?rev=144926&r1=144925&r2=144926&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/APValue.h (original)
+++ cfe/trunk/include/clang/AST/APValue.h Thu Nov 17 16:56:20 2011
@@ -27,6 +27,7 @@
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 @@
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 @@
UnionData();
~UnionData();
};
+ struct MemberPointerData;
enum {
MaxSize = (sizeof(ComplexAPSInt) > sizeof(ComplexAPFloat) ?
@@ -131,9 +134,10 @@
: 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 @@
: 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 @@
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 @@
const CharUnits &getLValueOffset() const {
return const_cast<APValue*>(this)->getLValueOffset();
}
+ bool isLValueOnePastTheEnd() const;
bool hasLValuePath() const;
ArrayRef<LValuePathEntry> getLValuePath() const;
@@ -297,6 +307,10 @@
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 @@
}
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 @@
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) {
Modified: cfe/trunk/lib/AST/APValue.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/APValue.cpp?rev=144926&r1=144925&r2=144926&view=diff
==============================================================================
--- cfe/trunk/lib/AST/APValue.cpp (original)
+++ cfe/trunk/lib/AST/APValue.cpp Thu Nov 17 16:56:20 2011
@@ -21,7 +21,7 @@
namespace {
struct LVBase {
- APValue::LValueBase Base;
+ llvm::PointerIntPair<APValue::LValueBase, 1, bool> BaseAndIsOnePastTheEnd;
CharUnits Offset;
unsigned PathLength;
};
@@ -40,12 +40,17 @@
};
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 @@
}
};
+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 @@
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 @@
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 @@
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 @@
((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 @@
case Union:
OS << "Union: " << getUnionValue();
return;
+ case MemberPointer:
+ OS << "MemberPointer: <todo>";
+ return;
}
llvm_unreachable("Unknown APValue kind!");
}
@@ -280,6 +333,9 @@
case APValue::Union:
Out << '{' << V.getUnionValue() << '}';
return;
+ case APValue::MemberPointer:
+ Out << "MemberPointer: <todo>";
+ return;
}
llvm_unreachable("Unknown APValue kind!");
}
@@ -294,7 +350,12 @@
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 @@
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 @@
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*));
+}
Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=144926&r1=144925&r2=144926&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Thu Nov 17 16:56:20 2011
@@ -126,6 +126,7 @@
V.getLValuePath());
else
assert(V.getLValuePath().empty() &&"Null pointer with nonempty path");
+ OnePastTheEnd = V.isLValueOnePastTheEnd();
}
}
@@ -178,6 +179,10 @@
/// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
- 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 @@
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 @@
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 @@
}
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 @@
// 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 @@
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 @@
}
//===----------------------------------------------------------------------===//
+// 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())
+ return false;
+
+ // Now figure out the necessary offset to add to the base LV to get from
+ // the derived class to the base class.
+ QualType Type = E->getSubExpr()->getType();
+
+ for (CastExpr::path_const_iterator PathI = E->path_begin(),
+ PathE = E->path_end(); PathI != PathE; ++PathI) {
+ if (!HandleLValueBase(this->Info, Result, Type->getAsCXXRecordDecl(),
+ *PathI))
+ return false;
+ Type = (*PathI)->getType();
+ }
+
+ return true;
+ }
+ }
+ }
+};
+}
+
+//===----------------------------------------------------------------------===//
// LValue Evaluation
//
// This is used for evaluating lvalues (in C and C++), xvalues (in C++11),
@@ -1465,27 +1854,11 @@
//===----------------------------------------------------------------------===//
namespace {
class LValueExprEvaluator
- : public ExprEvaluatorBase<LValueExprEvaluator, bool> {
- LValue &Result;
- const Decl *PrevDecl;
-
- bool Success(APValue::LValueBase B) {
- Result.set(B);
- return true;
- }
+ : public LValueExprEvaluatorBase<LValueExprEvaluator> {
public:
+ LValueExprEvaluator(EvalInfo &Info, LValue &Result) :
+ LValueExprEvaluatorBaseTy(Info, Result) {}
- LValueExprEvaluator(EvalInfo &info, LValue &Result) :
- ExprEvaluatorBaseTy(info), Result(Result), PrevDecl(0) {}
-
- bool Success(const CCValue &V, const Expr *E) {
- Result.setFrom(V);
- return true;
- }
- bool Error(const Expr *E) {
- return false;
- }
-
bool VisitVarDecl(const Expr *E, const VarDecl *VD);
bool VisitDeclRefExpr(const DeclRefExpr *E);
@@ -1501,7 +1874,7 @@
bool VisitCastExpr(const CastExpr *E) {
switch (E->getCastKind()) {
default:
- return ExprEvaluatorBaseTy::VisitCastExpr(E);
+ return LValueExprEvaluatorBaseTy::VisitCastExpr(E);
case CK_LValueBitCast:
if (!Visit(E->getSubExpr()))
@@ -1509,24 +1882,12 @@
Result.Designator.setInvalid();
return true;
- case CK_DerivedToBase:
- case CK_UncheckedDerivedToBase: {
+ case CK_BaseToDerived:
if (!Visit(E->getSubExpr()))
return false;
-
- // Now figure out the necessary offset to add to the base LV to get from
- // the derived class to the base class.
- QualType Type = E->getSubExpr()->getType();
-
- for (CastExpr::path_const_iterator PathI = E->path_begin(),
- PathE = E->path_end(); PathI != PathE; ++PathI) {
- if (!HandleLValueBase(Info, Result, Type->getAsCXXRecordDecl(), *PathI))
- return false;
- Type = (*PathI)->getType();
- }
-
- return true;
- }
+ if (!CheckValidLValue())
+ return false;
+ return HandleBaseToDerivedCast(Info, E, Result);
}
}
@@ -1573,9 +1934,25 @@
bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
const MaterializeTemporaryExpr *E) {
+ if (E->GetTemporaryExpr()->isRValue()) {
+ if (E->getType()->isRecordType() && E->getType()->isLiteralType())
+ return EvaluateTemporary(E->GetTemporaryExpr(), Result, Info);
+
+ Result.set(E, Info.CurrentCall);
+ return EvaluateConstantExpression(Info.CurrentCall->Temporaries[E], Info,
+ Result, E->GetTemporaryExpr());
+ }
+
+ // Materialization of an lvalue temporary occurs when we need to force a copy
+ // (for instance, if it's a bitfield).
+ // FIXME: The AST should contain an lvalue-to-rvalue node for such cases.
+ if (!Visit(E->GetTemporaryExpr()))
+ return false;
+ if (!HandleLValueToRValueConversion(Info, E->getType(), Result,
+ Info.CurrentCall->Temporaries[E]))
+ return false;
Result.set(E, Info.CurrentCall);
- return EvaluateConstantExpression(Info.CurrentCall->Temporaries[E], Info,
- Result, E->GetTemporaryExpr());
+ return true;
}
bool
@@ -1602,32 +1979,7 @@
}
// Handle non-static data members.
- QualType BaseTy;
- if (E->isArrow()) {
- if (!EvaluatePointer(E->getBase(), Result, Info))
- return false;
- BaseTy = E->getBase()->getType()->getAs<PointerType>()->getPointeeType();
- } else {
- if (!Visit(E->getBase()))
- return false;
- BaseTy = E->getBase()->getType();
- }
-
- const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
- if (!FD) return false;
- assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() ==
- FD->getParent()->getCanonicalDecl() && "record / field mismatch");
- (void)BaseTy;
-
- HandleLValueMember(Info, Result, FD);
-
- if (FD->getType()->isReferenceType()) {
- CCValue RefValue;
- if (!HandleLValueToRValueConversion(Info, FD->getType(), Result, RefValue))
- return false;
- return Success(RefValue, E);
- }
- return true;
+ return LValueExprEvaluatorBaseTy::VisitMemberExpr(E);
}
bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
@@ -1645,10 +1997,12 @@
= Index.isSigned() ? Index.getSExtValue()
: static_cast<int64_t>(Index.getZExtValue());
+ // FIXME: In C++11, require the result to be a valid lvalue.
return HandleLValueArrayAdjustment(Info, Result, E->getType(), IndexValue);
}
bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
+ // FIXME: In C++11, require the result to be a valid lvalue.
return EvaluatePointer(E->getSubExpr(), Result, Info);
}
@@ -1694,8 +2048,6 @@
return Success(E);
return false;
}
- bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E)
- { return ValueInitialization(E); }
bool VisitCXXThisExpr(const CXXThisExpr *E) {
if (!Info.CurrentCall->This)
return false;
@@ -1715,7 +2067,7 @@
bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (E->getOpcode() != BO_Add &&
E->getOpcode() != BO_Sub)
- return false;
+ return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
const Expr *PExp = E->getLHS();
const Expr *IExp = E->getRHS();
@@ -1735,6 +2087,7 @@
AdditionalOffset = -AdditionalOffset;
QualType Pointee = PExp->getType()->getAs<PointerType>()->getPointeeType();
+ // FIXME: In C++11, require the result to be a valid lvalue.
return HandleLValueArrayAdjustment(Info, Result, Pointee, AdditionalOffset);
}
@@ -1762,6 +2115,8 @@
case CK_UncheckedDerivedToBase: {
if (!EvaluatePointer(E->getSubExpr(), Result, Info))
return false;
+ if (!Result.Base && Result.Offset.isZero())
+ return true;
// Now figure out the necessary offset to add to the base LV to get from
// the derived class to the base class.
@@ -1778,6 +2133,13 @@
return true;
}
+ case CK_BaseToDerived:
+ if (!Visit(E->getSubExpr()))
+ return false;
+ if (!Result.Base && Result.Offset.isZero())
+ return true;
+ return HandleBaseToDerivedCast(Info, E, Result);
+
case CK_NullToPointer:
return ValueInitialization(E);
@@ -1801,11 +2163,15 @@
}
}
case CK_ArrayToPointerDecay:
- // FIXME: Support array-to-pointer decay on array rvalues.
- if (!SubExpr->isGLValue())
- return Error(E);
- if (!EvaluateLValue(SubExpr, Result, Info))
- return false;
+ if (SubExpr->isGLValue()) {
+ if (!EvaluateLValue(SubExpr, Result, Info))
+ return false;
+ } else {
+ Result.set(SubExpr, Info.CurrentCall);
+ if (!EvaluateConstantExpression(Info.CurrentCall->Temporaries[SubExpr],
+ Info, Result, SubExpr))
+ return false;
+ }
// The result is a pointer to the first element of the array.
Result.Designator.addIndex(0);
return true;
@@ -1825,6 +2191,96 @@
}
//===----------------------------------------------------------------------===//
+// Member Pointer Evaluation
+//===----------------------------------------------------------------------===//
+
+namespace {
+class MemberPointerExprEvaluator
+ : public ExprEvaluatorBase<MemberPointerExprEvaluator, bool> {
+ MemberPtr &Result;
+
+ bool Success(const ValueDecl *D) {
+ Result = MemberPtr(D);
+ return true;
+ }
+public:
+
+ MemberPointerExprEvaluator(EvalInfo &Info, MemberPtr &Result)
+ : ExprEvaluatorBaseTy(Info), Result(Result) {}
+
+ bool Success(const CCValue &V, const Expr *E) {
+ Result.setFrom(V);
+ return true;
+ }
+ bool Error(const Stmt *S) {
+ return false;
+ }
+ bool ValueInitialization(const Expr *E) {
+ return Success((const ValueDecl*)0);
+ }
+
+ bool VisitCastExpr(const CastExpr *E);
+ bool VisitUnaryAddrOf(const UnaryOperator *E);
+};
+} // end anonymous namespace
+
+static bool EvaluateMemberPointer(const Expr *E, MemberPtr &Result,
+ EvalInfo &Info) {
+ assert(E->isRValue() && E->getType()->isMemberPointerType());
+ return MemberPointerExprEvaluator(Info, Result).Visit(E);
+}
+
+bool MemberPointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
+ switch (E->getCastKind()) {
+ default:
+ return ExprEvaluatorBaseTy::VisitCastExpr(E);
+
+ case CK_NullToMemberPointer:
+ return ValueInitialization(E);
+
+ case CK_BaseToDerivedMemberPointer: {
+ if (!Visit(E->getSubExpr()))
+ return false;
+ if (E->path_empty())
+ return true;
+ // Base-to-derived member pointer casts store the path in derived-to-base
+ // order, so iterate backwards. The CXXBaseSpecifier also provides us with
+ // the wrong end of the derived->base arc, so stagger the path by one class.
+ typedef std::reverse_iterator<CastExpr::path_const_iterator> ReverseIter;
+ for (ReverseIter PathI(E->path_end() - 1), PathE(E->path_begin());
+ PathI != PathE; ++PathI) {
+ assert(!(*PathI)->isVirtual() && "memptr cast through vbase");
+ const CXXRecordDecl *Derived = (*PathI)->getType()->getAsCXXRecordDecl();
+ if (!Result.castToDerived(Derived))
+ return false;
+ }
+ const Type *FinalTy = E->getType()->castAs<MemberPointerType>()->getClass();
+ if (!Result.castToDerived(FinalTy->getAsCXXRecordDecl()))
+ return false;
+ return true;
+ }
+
+ case CK_DerivedToBaseMemberPointer:
+ if (!Visit(E->getSubExpr()))
+ return false;
+ for (CastExpr::path_const_iterator PathI = E->path_begin(),
+ PathE = E->path_end(); PathI != PathE; ++PathI) {
+ assert(!(*PathI)->isVirtual() && "memptr cast through vbase");
+ const CXXRecordDecl *Base = (*PathI)->getType()->getAsCXXRecordDecl();
+ if (!Result.castToBase(Base))
+ return false;
+ }
+ return true;
+ }
+}
+
+bool MemberPointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
+ // C++11 [expr.unary.op]p3 has very strict rules on how the address of a
+ // member can be formed.
+ return Success(cast<DeclRefExpr>(E->getSubExpr())->getDecl());
+}
+
+//===----------------------------------------------------------------------===//
// Record Evaluation
//===----------------------------------------------------------------------===//
@@ -1957,6 +2413,55 @@
}
//===----------------------------------------------------------------------===//
+// Temporary Evaluation
+//
+// Temporaries are represented in the AST as rvalues, but generally behave like
+// lvalues. The full-object of which the temporary is a subobject is implicitly
+// materialized so that a reference can bind to it.
+//===----------------------------------------------------------------------===//
+namespace {
+class TemporaryExprEvaluator
+ : public LValueExprEvaluatorBase<TemporaryExprEvaluator> {
+public:
+ TemporaryExprEvaluator(EvalInfo &Info, LValue &Result) :
+ LValueExprEvaluatorBaseTy(Info, Result) {}
+
+ /// Visit an expression which constructs the value of this temporary.
+ bool VisitConstructExpr(const Expr *E) {
+ Result.set(E, Info.CurrentCall);
+ return EvaluateConstantExpression(Info.CurrentCall->Temporaries[E], Info,
+ Result, E);
+ }
+
+ bool VisitCastExpr(const CastExpr *E) {
+ switch (E->getCastKind()) {
+ default:
+ return LValueExprEvaluatorBaseTy::VisitCastExpr(E);
+
+ case CK_ConstructorConversion:
+ return VisitConstructExpr(E->getSubExpr());
+ }
+ }
+ bool VisitInitListExpr(const InitListExpr *E) {
+ return VisitConstructExpr(E);
+ }
+ bool VisitCXXConstructExpr(const CXXConstructExpr *E) {
+ return VisitConstructExpr(E);
+ }
+ bool VisitCallExpr(const CallExpr *E) {
+ return VisitConstructExpr(E);
+ }
+};
+} // end anonymous namespace
+
+/// Evaluate an expression of record type as a temporary.
+static bool EvaluateTemporary(const Expr *E, LValue &Result, EvalInfo &Info) {
+ assert(E->isRValue() && E->getType()->isRecordType() &&
+ E->getType()->isLiteralType());
+ return TemporaryExprEvaluator(Info, Result).Visit(E);
+}
+
+//===----------------------------------------------------------------------===//
// Vector Evaluation
//===----------------------------------------------------------------------===//
@@ -2183,9 +2688,8 @@
Subobject, &VIE);
}
- // FIXME: We also get CXXConstructExpr, in cases like:
- // struct S { constexpr S(); }; constexpr S s[10];
bool VisitInitListExpr(const InitListExpr *E);
+ bool VisitCXXConstructExpr(const CXXConstructExpr *E);
};
} // end anonymous namespace
@@ -2225,6 +2729,34 @@
Subobject, E->getArrayFiller());
}
+bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
+ const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(E->getType());
+ if (!CAT)
+ return false;
+
+ Result = APValue(APValue::UninitArray(), 0, CAT->getSize().getZExtValue());
+ if (!Result.hasArrayFiller())
+ return true;
+
+ const CXXConstructorDecl *FD = E->getConstructor();
+ const FunctionDecl *Definition = 0;
+ FD->getBody(Definition);
+
+ if (!Definition || !Definition->isConstexpr() || Definition->isInvalidDecl())
+ return false;
+
+ // FIXME: The Subobject here isn't necessarily right. This rarely matters,
+ // but sometimes does:
+ // struct S { constexpr S() : p(&p) {} void *p; };
+ // S s[10];
+ LValue Subobject = This;
+ Subobject.Designator.addIndex(0);
+ llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
+ return HandleConstructorCall(Subobject, Args,
+ cast<CXXConstructorDecl>(Definition),
+ Info, Result.getArrayFiller());
+}
+
//===----------------------------------------------------------------------===//
// Integer Evaluation
//
@@ -2832,9 +3364,8 @@
}
if (!LHSTy->isIntegralOrEnumerationType() ||
!RHSTy->isIntegralOrEnumerationType()) {
- // We can't continue from here for non-integral types, and they
- // could potentially confuse the following operations.
- return false;
+ // We can't continue from here for non-integral types.
+ return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
}
// The LHS of a constant expr is always evaluated and needed.
@@ -3423,17 +3954,9 @@
}
bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
- if (E->getOpcode() == BO_Comma) {
- VisitIgnoredValue(E->getLHS());
- return Visit(E->getRHS());
- }
-
- // We can't evaluate pointer-to-member operations or assignments.
- if (E->isPtrMemOp() || E->isAssignmentOp())
- return false;
+ if (E->isPtrMemOp() || E->isAssignmentOp() || E->getOpcode() == BO_Comma)
+ return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
- // FIXME: Diagnostics? I really don't understand how the warnings
- // and errors are supposed to work.
APFloat RHS(0.0);
if (!EvaluateFloat(E->getLHS(), Result, Info))
return false;
@@ -3695,14 +4218,9 @@
}
bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
- if (E->isPtrMemOp() || E->isAssignmentOp())
+ if (E->isPtrMemOp() || E->isAssignmentOp() || E->getOpcode() == BO_Comma)
return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
- if (E->getOpcode() == BO_Comma) {
- VisitIgnoredValue(E->getLHS());
- return Visit(E->getRHS());
- }
-
if (!Visit(E->getLHS()))
return false;
@@ -3884,8 +4402,11 @@
return false;
C.moveInto(Result);
} else if (E->getType()->isMemberPointerType()) {
- // FIXME: Implement evaluation of pointer-to-member types.
- return false;
+ MemberPtr P;
+ if (!EvaluateMemberPointer(E, P, Info))
+ return false;
+ P.moveInto(Result);
+ return true;
} else if (E->getType()->isArrayType() && E->getType()->isLiteralType()) {
LValue LV;
LV.set(E, Info.CurrentCall);
@@ -3935,7 +4456,9 @@
// FIXME: Evaluating initializers for large arrays can cause performance
// problems, and we don't use such values yet. Once we have a more efficient
// array representation, this should be reinstated, and used by CodeGen.
- if (isRValue() && getType()->isArrayType())
+ // The same problem affects large records.
+ if (isRValue() && (getType()->isArrayType() || getType()->isRecordType()) &&
+ !Ctx.getLangOptions().CPlusPlus0x)
return false;
EvalInfo Info(Ctx, Result);
Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=144926&r1=144925&r2=144926&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Thu Nov 17 16:56:20 2011
@@ -1074,6 +1074,7 @@
case APValue::Array:
case APValue::Struct:
case APValue::Union:
+ case APValue::MemberPointer:
break;
}
}
Modified: cfe/trunk/test/CodeGen/object-size.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/object-size.c?rev=144926&r1=144925&r2=144926&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/object-size.c (original)
+++ cfe/trunk/test/CodeGen/object-size.c Thu Nov 17 16:56:20 2011
@@ -55,8 +55,7 @@
// CHECK: define void @test7
void test7() {
int i;
- // CHECK-NOT: __strcpy_chk
- // CHECK: = call i8* @__inline_strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
+ // CHECK: = call i64 @llvm.objectsize.i64(i8* {{.*}}@gbuf{{.*}}, i1 false)
strcpy((++i, gbuf), "Hi there");
}
Modified: cfe/trunk/test/CodeGenCXX/const-base-cast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/const-base-cast.cpp?rev=144926&r1=144925&r2=144926&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/const-base-cast.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/const-base-cast.cpp Thu Nov 17 16:56:20 2011
@@ -1,8 +1,7 @@
-// RUN: %clang_cc1 -O1 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
// Check that the following construct, which is similar to one which occurs
-// in Firefox, is not misfolded (folding it correctly would be a bonus, but
-// that doesn't work at the moment, hence the -O1 in the runline).
+// in Firefox, is folded correctly.
struct A { char x; };
struct B { char y; };
struct C : A,B {};
Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=144926&r1=144925&r2=144926&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Thu Nov 17 16:56:20 2011
@@ -94,7 +94,7 @@
template<int n> struct IntParam {};
using IntParam0 = IntParam<0>;
- // FIXME: This should be accepted once we do constexpr function invocation.
+ // FIXME: This should be accepted once we implement the new ICE rules.
using IntParam0 = IntParam<id(0)>; // expected-error {{not an integral constant expression}}
using IntParam0 = IntParam<MemberZero().zero>; // expected-error {{did you mean to call it with no arguments?}} expected-error {{not an integral constant expression}}
}
@@ -104,7 +104,7 @@
switch (n) {
// FIXME: Produce the 'add ()' fixit for this.
case MemberZero().zero: // desired-error {{did you mean to call it with no arguments?}} expected-error {{not an integer constant expression}}
- // FIXME: This should be accepted once we do constexpr function invocation.
+ // FIXME: This should be accepted once we implement the new ICE rules.
case id(1): // expected-error {{not an integer constant expression}}
return;
}
@@ -432,6 +432,17 @@
static_assert_fold(SumNonzero(arr) == 6, "");
static_assert_fold(CountZero(arr, arr + 40) == 36, "");
+struct ArrayElem {
+ constexpr ArrayElem() : n(0) {}
+ int n;
+ constexpr int f() { return n; }
+};
+struct ArrayRVal {
+ constexpr ArrayRVal() {}
+ ArrayElem elems[10];
+};
+static_assert_fold(ArrayRVal().elems[3].f() == 0, "");
+
}
namespace DependentValues {
@@ -572,12 +583,13 @@
}
-struct Base {
+struct Bottom { constexpr Bottom() {} };
+struct Base : Bottom {
constexpr Base(int a = 42, const char *b = "test") : a(a), b(b) {}
int a;
const char *b;
};
-struct Base2 {
+struct Base2 : Bottom {
constexpr Base2(const int &r) : r(r) {}
int q = 123;
// FIXME: When we track the global for which we are computing the initializer,
@@ -607,6 +619,63 @@
static_assert_fold(!(derived == base), "");
static_assert_fold(derived == base2, "");
+constexpr Bottom &bot1 = (Base&)derived;
+constexpr Bottom &bot2 = (Base2&)derived;
+static_assert_fold(&bot1 != &bot2, "");
+
+constexpr Bottom *pb1 = (Base*)&derived;
+constexpr Bottom *pb2 = (Base2*)&derived;
+static_assert_fold(pb1 != pb2, "");
+static_assert_fold(pb1 == &bot1, "");
+static_assert_fold(pb2 == &bot2, "");
+
+constexpr Base2 &fail = (Base2&)bot1; // expected-error {{constant expression}}
+constexpr Base &fail2 = (Base&)*pb2; // expected-error {{constant expression}}
+constexpr Base2 &ok2 = (Base2&)bot2;
+static_assert_fold(&ok2 == &derived, "");
+
+constexpr Base2 *pfail = (Base2*)pb1; // expected-error {{constant expression}}
+constexpr Base *pfail2 = (Base*)&bot2; // expected-error {{constant expression}}
+constexpr Base2 *pok2 = (Base2*)pb2;
+static_assert_fold(pok2 == &derived, "");
+static_assert_fold(&ok2 == pok2, "");
+static_assert_fold((Base2*)(Derived*)(Base*)pb1 == pok2, "");
+static_assert_fold((Derived*)(Base*)pb1 == (Derived*)pok2, "");
+
+constexpr Base *nullB = 42 - 6 * 7;
+static_assert_fold((Bottom*)nullB == 0, "");
+static_assert_fold((Derived*)nullB == 0, "");
+static_assert_fold((void*)(Bottom*)nullB == (void*)(Derived*)nullB, "");
+
+}
+
+namespace Temporaries {
+
+struct S {
+ constexpr S() {}
+ constexpr int f();
+};
+struct T : S {
+ constexpr T(int n) : S(), n(n) {}
+ int n;
+};
+constexpr int S::f() {
+ // 'this' must be the postfix-expression in a class member access expression,
+ // so we can't just use
+ // return static_cast<T*>(this)->n;
+ return this->*(int(S::*))&T::n;
+}
+// The T temporary is implicitly cast to an S subobject, but we can recover the
+// T full-object via a base-to-derived cast, or a derived-to-base-casted member
+// pointer.
+static_assert_fold(T(3).f() == 3, "");
+
+constexpr int f(const S &s) {
+ return static_cast<const T&>(s).n;
+}
+constexpr int n = f(T(5));
+static_assert_fold(f(T(5)) == 5, "");
+
}
namespace Union {
@@ -626,6 +695,138 @@
}
+namespace MemberPointer {
+ struct A {
+ constexpr A(int n) : n(n) {}
+ int n;
+ constexpr int f() { return n + 3; }
+ };
+ constexpr A a(7);
+ static_assert_fold(A(5).*&A::n == 5, "");
+ static_assert_fold((&a)->*&A::n == 7, "");
+ static_assert_fold((A(8).*&A::f)() == 11, "");
+ static_assert_fold(((&a)->*&A::f)() == 10, "");
+
+ struct B : A {
+ constexpr B(int n, int m) : A(n), m(m) {}
+ int m;
+ constexpr int g() { return n + m + 1; }
+ };
+ constexpr B b(9, 13);
+ static_assert_fold(B(4, 11).*&A::n == 4, "");
+ static_assert_fold(B(4, 11).*&B::m == 11, "");
+ static_assert_fold(B(4, 11).*(int(A::*))&B::m == 11, "");
+ static_assert_fold((&b)->*&A::n == 9, "");
+ static_assert_fold((&b)->*&B::m == 13, "");
+ static_assert_fold((&b)->*(int(A::*))&B::m == 13, "");
+ static_assert_fold((B(4, 11).*&A::f)() == 7, "");
+ static_assert_fold((B(4, 11).*&B::g)() == 16, "");
+ static_assert_fold((B(4, 11).*(int(A::*)()const)&B::g)() == 16, "");
+ static_assert_fold(((&b)->*&A::f)() == 12, "");
+ static_assert_fold(((&b)->*&B::g)() == 23, "");
+ static_assert_fold(((&b)->*(int(A::*)()const)&B::g)() == 23, "");
+
+ struct S {
+ constexpr S(int m, int n, int (S::*pf)() const, int S::*pn) :
+ m(m), n(n), pf(pf), pn(pn) {}
+ constexpr S() : m(), n(), pf(&S::f), pn(&S::n) {}
+
+ constexpr int f() { return this->*pn; }
+ virtual int g() const;
+
+ int m, n;
+ int (S::*pf)() const;
+ int S::*pn;
+ };
+
+ constexpr int S::*pm = &S::m;
+ constexpr int S::*pn = &S::n;
+ constexpr int (S::*pf)() const = &S::f;
+ constexpr int (S::*pg)() const = &S::g;
+
+ constexpr S s(2, 5, &S::f, &S::m);
+
+ static_assert_fold((s.*&S::f)() == 2, "");
+ static_assert_fold((s.*s.pf)() == 2, "");
+
+ template<int n> struct T : T<n-1> {};
+ template<> struct T<0> { int n; };
+ template<> struct T<30> : T<29> { int m; };
+
+ T<17> t17;
+ T<30> t30;
+
+ constexpr int (T<10>::*deepn) = &T<0>::n;
+ static_assert_fold(&(t17.*deepn) == &t17.n, "");
+
+ constexpr int (T<15>::*deepm) = (int(T<10>::*))&T<30>::m;
+ constexpr int *pbad = &(t17.*deepm); // expected-error {{constant expression}}
+ static_assert_fold(&(t30.*deepm) == &t30.m, "");
+
+ constexpr T<5> *p17_5 = &t17;
+ constexpr T<13> *p17_13 = (T<13>*)p17_5;
+ constexpr T<23> *p17_23 = (T<23>*)p17_13; // expected-error {{constant expression}}
+ static_assert_fold(&(p17_5->*(int(T<3>::*))deepn) == &t17.n, "");
+ static_assert_fold(&(p17_13->*deepn) == &t17.n, "");
+ constexpr int *pbad2 = &(p17_13->*(int(T<9>::*))deepm); // expected-error {{constant expression}}
+
+ constexpr T<5> *p30_5 = &t30;
+ constexpr T<23> *p30_23 = (T<23>*)p30_5;
+ constexpr T<13> *p30_13 = p30_23;
+ static_assert_fold(&(p30_5->*(int(T<3>::*))deepn) == &t30.n, "");
+ static_assert_fold(&(p30_13->*deepn) == &t30.n, "");
+ static_assert_fold(&(p30_23->*deepn) == &t30.n, "");
+ static_assert_fold(&(p30_5->*(int(T<2>::*))deepm) == &t30.m, "");
+ static_assert_fold(&(((T<17>*)p30_13)->*deepm) == &t30.m, "");
+ static_assert_fold(&(p30_23->*deepm) == &t30.m, "");
+}
+
+namespace ArrayBaseDerived {
+
+ struct Base {
+ constexpr Base() {}
+ int n = 0;
+ };
+ struct Derived : Base {
+ constexpr Derived() {}
+ constexpr const int *f() { return &n; }
+ };
+
+ constexpr Derived a[10];
+ constexpr Derived *pd3 = const_cast<Derived*>(&a[3]);
+ constexpr Base *pb3 = const_cast<Derived*>(&a[3]);
+ static_assert_fold(pb3 == pd3, "");
+
+ // pb3 does not point to an array element.
+ constexpr Base *pb4 = pb3 + 1; // ok, one-past-the-end pointer.
+ constexpr int pb4n = pb4->n; // expected-error {{constant expression}}
+ constexpr Base *err_pb5 = pb3 + 2; // FIXME: reject this.
+ constexpr int err_pb5n = err_pb5->n; // expected-error {{constant expression}}
+ constexpr Base *err_pb2 = pb3 - 1; // FIXME: reject this.
+ constexpr int err_pb2n = err_pb2->n; // expected-error {{constant expression}}
+ constexpr Base *pb3a = pb4 - 1;
+
+ // pb4 does not point to a Derived.
+ constexpr Derived *err_pd4 = (Derived*)pb4; // expected-error {{constant expression}}
+ constexpr Derived *pd3a = (Derived*)pb3a;
+ constexpr int pd3n = pd3a->n;
+
+ // pd3a still points to the Derived array.
+ constexpr Derived *pd6 = pd3a + 3;
+ static_assert_fold(pd6 == &a[6], "");
+ constexpr Derived *pd9 = pd6 + 3;
+ constexpr Derived *pd10 = pd6 + 4;
+ constexpr int pd9n = pd9->n; // ok
+ constexpr int err_pd10n = pd10->n; // expected-error {{constant expression}}
+ constexpr int pd0n = pd10[-10].n;
+ constexpr int err_pdminus1n = pd10[-11].n; // expected-error {{constant expression}}
+
+ constexpr Base *pb9 = pd9;
+ constexpr const int *(Base::*pfb)() const =
+ static_cast<const int *(Base::*)() const>(&Derived::f);
+ static_assert_fold((pb9->*pfb)() == &a[9].n, "");
+}
+
namespace Complex {
class complex {
More information about the cfe-commits
mailing list