diff options
-rw-r--r-- | include/clang/AST/APValue.h | 24 | ||||
-rw-r--r-- | lib/AST/APValue.cpp | 121 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 825 | ||||
-rw-r--r-- | lib/CodeGen/CGExprConstant.cpp | 1 | ||||
-rw-r--r-- | test/CodeGen/object-size.c | 3 | ||||
-rw-r--r-- | test/CodeGenCXX/const-base-cast.cpp | 5 | ||||
-rw-r--r-- | test/SemaCXX/constant-expression-cxx11.cpp | 209 |
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()) |