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 LValueBase; typedef llvm::PointerIntPair 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 Path) + APValue(LValueBase B, const CharUnits &O, ArrayRef 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 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(this)->getLValueOffset(); } + bool isLValueOnePastTheEnd() const; bool hasLValuePath() const; ArrayRef getLValuePath() const; @@ -297,6 +307,10 @@ public: return const_cast(this)->getUnionValue(); } + const ValueDecl *getMemberPointerDecl() const; + bool isMemberPointerToDerivedMember() const; + ArrayRef 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 Path); + ArrayRef 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 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 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 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: "; + 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: "; + 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::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 Path) { + ArrayRef 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 APValue::getMemberPointerPath() const { + assert(isMemberPointer() && "Invalid accessor"); + const MemberPointerData &MPD = *((const MemberPointerData*)(const char*)Data); + return ArrayRef(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 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 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( + 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 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 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 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(); + 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()) + 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(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()) + 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(Callee->IgnoreParens()); - if (!ME) + if (const MemberExpr *ME = dyn_cast(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(ME->getMemberDecl()); + if (!FD) + return DerivedError(ME); + } else if (const BinaryOperator *BE = dyn_cast(Callee)) { + // Indirect bound member calls ('.*' or '->*'). + const ValueDecl *Member = HandleMemberPointerAccess(Info, BE, ThisVal, + false); + This = &ThisVal; + FD = dyn_cast_or_null(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(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) { @@ -1437,6 +1714,118 @@ public: } +//===----------------------------------------------------------------------===// +// Common base class for lvalue and temporary evaluation. +//===----------------------------------------------------------------------===// +namespace { +template +class LValueExprEvaluatorBase + : public ExprEvaluatorBase { +protected: + LValue &Result; + typedef LValueExprEvaluatorBase LValueExprEvaluatorBaseTy; + typedef ExprEvaluatorBase 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()->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(E->getMemberDecl()); + // FIXME: Handle IndirectFieldDecls + if (!FD) return false; + assert(BaseTy->getAs()->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 // @@ -1465,27 +1854,11 @@ public: //===----------------------------------------------------------------------===// namespace { class LValueExprEvaluator - : public ExprEvaluatorBase { - LValue &Result; - const Decl *PrevDecl; - - bool Success(APValue::LValueBase B) { - Result.set(B); - return true; - } + : public LValueExprEvaluatorBase { 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 @@ public: 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 @@ public: 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::VisitVarDecl(const Expr *E, const VarDecl *VD) { 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 @@ bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) { } // Handle non-static data members. - QualType BaseTy; - if (E->isArrow()) { - if (!EvaluatePointer(E->getBase(), Result, Info)) - return false; - BaseTy = E->getBase()->getType()->getAs()->getPointeeType(); - } else { - if (!Visit(E->getBase())) - return false; - BaseTy = E->getBase()->getType(); - } - - const FieldDecl *FD = dyn_cast(E->getMemberDecl()); - if (!FD) return false; - assert(BaseTy->getAs()->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 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { = Index.isSigned() ? Index.getSExtValue() : static_cast(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 @@ public: 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 @@ static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info) { 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 @@ bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { AdditionalOffset = -AdditionalOffset; QualType Pointee = PExp->getType()->getAs()->getPointeeType(); + // FIXME: In C++11, require the result to be a valid lvalue. return HandleLValueArrayAdjustment(Info, Result, Pointee, AdditionalOffset); } @@ -1762,6 +2115,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { 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 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { 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 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { } } 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; @@ -1824,6 +2190,96 @@ bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) { return ExprEvaluatorBaseTy::VisitCallExpr(E); } +//===----------------------------------------------------------------------===// +// Member Pointer Evaluation +//===----------------------------------------------------------------------===// + +namespace { +class MemberPointerExprEvaluator + : public ExprEvaluatorBase { + 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 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()->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(E->getSubExpr())->getDecl()); +} + //===----------------------------------------------------------------------===// // Record Evaluation //===----------------------------------------------------------------------===// @@ -1956,6 +2412,55 @@ static bool EvaluateRecord(const Expr *E, const LValue &This, return RecordExprEvaluator(Info, This, Result).Visit(E); } +//===----------------------------------------------------------------------===// +// 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 { +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 @@ namespace { 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 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { 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 Args(E->getArgs(), E->getNumArgs()); + return HandleConstructorCall(Subobject, Args, + cast(Definition), + Info, Result.getArrayFiller()); +} + //===----------------------------------------------------------------------===// // Integer Evaluation // @@ -2832,9 +3364,8 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { } 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::VisitUnaryOperator(const UnaryOperator *E) { } bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { - if (E->getOpcode() == BO_Comma) { - VisitIgnoredValue(E->getLHS()); - return Visit(E->getRHS()); - } + if (E->isPtrMemOp() || E->isAssignmentOp() || E->getOpcode() == BO_Comma) + return ExprEvaluatorBaseTy::VisitBinaryOperator(E); - // We can't evaluate pointer-to-member operations or assignments. - if (E->isPtrMemOp() || E->isAssignmentOp()) - return false; - - // 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::VisitCastExpr(const CastExpr *E) { } 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 @@ static bool Evaluate(CCValue &Result, EvalInfo &Info, const Expr *E) { 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 @@ bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const { // 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); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 819fc3fa08..7485c71d7d 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -1074,6 +1074,7 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, case APValue::Array: case APValue::Struct: case APValue::Union: + case APValue::MemberPointer: break; } } diff --git a/test/CodeGen/object-size.c b/test/CodeGen/object-size.c index 287d742b87..1f16d02d7d 100644 --- a/test/CodeGen/object-size.c +++ b/test/CodeGen/object-size.c @@ -55,8 +55,7 @@ void test6() { // 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"); } diff --git a/test/CodeGenCXX/const-base-cast.cpp b/test/CodeGenCXX/const-base-cast.cpp index ed47069d24..320c790c5e 100644 --- a/test/CodeGenCXX/const-base-cast.cpp +++ b/test/CodeGenCXX/const-base-cast.cpp @@ -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 {}; diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index d208362cbc..021fe4facc 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -94,7 +94,7 @@ namespace TemplateArgumentConversion { template 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; // expected-error {{not an integral constant expression}} using IntParam0 = IntParam; // expected-error {{did you mean to call it with no arguments?}} expected-error {{not an integral constant expression}} } @@ -104,7 +104,7 @@ namespace CaseStatements { 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 @@ constexpr int CountZero(const int *p, const int *q) { 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 @@ static_assert_fold(d.a == 3, ""); } -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.r == &derived.a, ""); // expected-error {{}} 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(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(s).n; +} +constexpr int n = f(T(5)); +static_assert_fold(f(T(5)) == 5, ""); + } namespace Union { @@ -626,6 +695,138 @@ static_assert_fold((&(u[1]) + 1 + 1)->b == 3, ""); } +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 struct T : T {}; + 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(&a[3]); + constexpr Base *pb3 = const_cast(&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(&Derived::f); + static_assert_fold((pb9->*pfb)() == &a[9].n, ""); +} + namespace Complex { class complex {