diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-01-06 16:39:00 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-01-06 16:39:00 +0000 |
commit | b4e85ed51905fc94378d7b4ff62b06e0d08042b7 (patch) | |
tree | 341e01d1fbaa36582a5ae93ff542995cf2fe1af1 /lib/AST/ExprConstant.cpp | |
parent | f143ffc4a9af79ac1d822fea6995af4bf45d17dc (diff) |
C++11 generalized constant expressions: implement checking and diagnostics for
pointer-arithmetic-related undefined behavior and unspecified results. We
continue to fold such values, but now notice they aren't constant expressions.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147659 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r-- | lib/AST/ExprConstant.cpp | 546 |
1 files changed, 317 insertions, 229 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 949988db1a..1ad17ea376 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -76,24 +76,38 @@ namespace { return Value.getInt(); } - /// Determine whether the described subobject is an array element. - static bool SubobjectIsArrayElement(QualType Base, - ArrayRef<APValue::LValuePathEntry> Path) { - bool IsArrayElement = false; - const Type *T = Base.getTypePtr(); + /// Find the path length and type of the most-derived subobject in the given + /// path, and find the size of the containing array, if any. + static + unsigned findMostDerivedSubobject(ASTContext &Ctx, QualType Base, + ArrayRef<APValue::LValuePathEntry> Path, + uint64_t &ArraySize, QualType &Type) { + unsigned MostDerivedLength = 0; + Type = Base; for (unsigned I = 0, N = Path.size(); I != N; ++I) { - IsArrayElement = T && T->isArrayType(); - if (IsArrayElement) - T = T->getBaseElementTypeUnsafe(); - else if (const FieldDecl *FD = getAsField(Path[I])) - T = FD->getType().getTypePtr(); - else + if (Type->isArrayType()) { + const ConstantArrayType *CAT = + cast<ConstantArrayType>(Ctx.getAsArrayType(Type)); + Type = CAT->getElementType(); + ArraySize = CAT->getSize().getZExtValue(); + MostDerivedLength = I + 1; + } else if (const FieldDecl *FD = getAsField(Path[I])) { + Type = FD->getType(); + ArraySize = 0; + MostDerivedLength = I + 1; + } else { // Path[I] describes a base class. - T = 0; + ArraySize = 0; + } } - return IsArrayElement; + return MostDerivedLength; } + // The order of this enum is important for diagnostics. + enum CheckSubobjectKind { + CSK_Base, CSK_Derived, CSK_Field, CSK_ArrayToPointer, CSK_ArrayIndex + }; + /// A path from a glvalue to a subobject of that glvalue. struct SubobjectDesignator { /// True if the subobject was named in a manner not supported by C++11. Such @@ -101,32 +115,43 @@ namespace { /// and we cannot perform lvalue-to-rvalue conversions on them. bool Invalid : 1; - /// Whether this designates an array element. - bool ArrayElement : 1; + /// Is this a pointer one past the end of an object? + bool IsOnePastTheEnd : 1; + + /// The length of the path to the most-derived object of which this is a + /// subobject. + unsigned MostDerivedPathLength : 30; + + /// The size of the array of which the most-derived object is an element, or + /// 0 if the most-derived object is not an array element. + uint64_t MostDerivedArraySize; - /// Whether this designates 'one past the end' of the current subobject. - bool OnePastTheEnd : 1; + /// The type of the most derived object referred to by this address. + QualType MostDerivedType; typedef APValue::LValuePathEntry PathEntry; /// The entries on the path from the glvalue to the designated subobject. SmallVector<PathEntry, 8> Entries; - SubobjectDesignator() : - Invalid(false), ArrayElement(false), OnePastTheEnd(false) {} + SubobjectDesignator() : Invalid(true) {} - SubobjectDesignator(const APValue &V) : - Invalid(!V.isLValue() || !V.hasLValuePath()), ArrayElement(false), - OnePastTheEnd(false) { + explicit SubobjectDesignator(QualType T) + : Invalid(false), IsOnePastTheEnd(false), MostDerivedPathLength(0), + MostDerivedArraySize(0), MostDerivedType(T) {} + + SubobjectDesignator(ASTContext &Ctx, const APValue &V) + : Invalid(!V.isLValue() || !V.hasLValuePath()), IsOnePastTheEnd(false), + MostDerivedPathLength(0), MostDerivedArraySize(0) { if (!Invalid) { + IsOnePastTheEnd = V.isLValueOnePastTheEnd(); ArrayRef<PathEntry> VEntries = V.getLValuePath(); Entries.insert(Entries.end(), VEntries.begin(), VEntries.end()); if (V.getLValueBase()) - ArrayElement = SubobjectIsArrayElement(getType(V.getLValueBase()), - V.getLValuePath()); - else - assert(V.getLValuePath().empty() &&"Null pointer with nonempty path"); - OnePastTheEnd = V.isLValueOnePastTheEnd(); + MostDerivedPathLength = + findMostDerivedSubobject(Ctx, getType(V.getLValueBase()), + V.getLValuePath(), MostDerivedArraySize, + MostDerivedType); } } @@ -134,46 +159,76 @@ namespace { Invalid = true; Entries.clear(); } - /// Update this designator to refer to the given element within this array. - void addIndex(uint64_t N) { - if (Invalid) return; - if (OnePastTheEnd) { - setInvalid(); - return; - } + + /// Determine whether this is a one-past-the-end pointer. + bool isOnePastTheEnd() const { + if (IsOnePastTheEnd) + return true; + if (MostDerivedArraySize && + Entries[MostDerivedPathLength - 1].ArrayIndex == MostDerivedArraySize) + return true; + return false; + } + + /// Check that this refers to a valid subobject. + bool isValidSubobject() const { + if (Invalid) + return false; + return !isOnePastTheEnd(); + } + /// Check that this refers to a valid subobject, and if not, produce a + /// relevant diagnostic and set the designator as invalid. + bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK); + + /// Update this designator to refer to the first element within this array. + void addArrayUnchecked(const ConstantArrayType *CAT) { PathEntry Entry; - Entry.ArrayIndex = N; + Entry.ArrayIndex = 0; Entries.push_back(Entry); - ArrayElement = true; + + // This is a most-derived object. + MostDerivedType = CAT->getElementType(); + MostDerivedArraySize = CAT->getSize().getZExtValue(); + MostDerivedPathLength = Entries.size(); } /// Update this designator to refer to the given base or member of this /// object. - void addDecl(const Decl *D, bool Virtual = false) { - if (Invalid) return; - if (OnePastTheEnd) { - setInvalid(); - return; - } + void addDeclUnchecked(const Decl *D, bool Virtual = false) { PathEntry Entry; APValue::BaseOrMemberType Value(D, Virtual); Entry.BaseOrMember = Value.getOpaqueValue(); Entries.push_back(Entry); - ArrayElement = false; + + // If this isn't a base class, it's a new most-derived object. + if (const FieldDecl *FD = dyn_cast<FieldDecl>(D)) { + MostDerivedType = FD->getType(); + MostDerivedArraySize = 0; + MostDerivedPathLength = Entries.size(); + } } + void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, uint64_t N); /// Add N to the address of this subobject. - void adjustIndex(uint64_t N) { + void adjustIndex(EvalInfo &Info, const Expr *E, uint64_t N) { if (Invalid) return; - if (ArrayElement) { - // FIXME: Make sure the index stays within bounds, or one past the end. + if (MostDerivedPathLength == Entries.size() && MostDerivedArraySize) { Entries.back().ArrayIndex += N; + if (Entries.back().ArrayIndex > MostDerivedArraySize) { + diagnosePointerArithmetic(Info, E, Entries.back().ArrayIndex); + setInvalid(); + } return; } - if (OnePastTheEnd && N == (uint64_t)-1) - OnePastTheEnd = false; - else if (!OnePastTheEnd && N == 1) - OnePastTheEnd = true; - else if (N != 0) + // [expr.add]p4: For the purposes of these operators, a pointer to a + // nonarray object behaves the same as a pointer to the first element of + // an array of length one with the type of the object as its element type. + if (IsOnePastTheEnd && N == (uint64_t)-1) + IsOnePastTheEnd = false; + else if (!IsOnePastTheEnd && N == 1) + IsOnePastTheEnd = true; + else if (N != 0) { + diagnosePointerArithmetic(Info, E, uint64_t(IsOnePastTheEnd) + N); setInvalid(); + } } }; @@ -205,8 +260,8 @@ namespace { CCValue(LValueBase B, const CharUnits &O, CallStackFrame *F, const SubobjectDesignator &D) : APValue(B, O, APValue::NoLValuePath()), CallFrame(F), Designator(D) {} - CCValue(const APValue &V, GlobalValue) : - APValue(V), CallFrame(0), Designator(V) {} + CCValue(ASTContext &Ctx, const APValue &V, GlobalValue) : + APValue(V), CallFrame(0), Designator(Ctx, V) {} CCValue(const ValueDecl *D, bool IsDerivedMember, ArrayRef<const CXXRecordDecl*> Path) : APValue(D, IsDerivedMember, Path) {} @@ -397,6 +452,31 @@ namespace { }; } +bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E, + CheckSubobjectKind CSK) { + if (Invalid) + return false; + if (isOnePastTheEnd()) { + Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_past_end_subobject) + << CSK; + setInvalid(); + return false; + } + return true; +} + +void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info, + const Expr *E, uint64_t N) { + if (MostDerivedPathLength == Entries.size() && MostDerivedArraySize) + Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_array_index) + << static_cast<int>(N) << /*array*/ 0 + << static_cast<unsigned>(MostDerivedArraySize); + else + Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_array_index) + << static_cast<int>(N) << /*non-array*/ 1; + setInvalid(); +} + CallStackFrame::CallStackFrame(EvalInfo &Info, SourceLocation CallLoc, const FunctionDecl *Callee, const LValue *This, const CCValue *Arguments) @@ -434,7 +514,7 @@ static void describeCall(CallStackFrame *Frame, llvm::raw_ostream &Out) { // Deliberately slice off the frame to form an APValue we can print. APValue Value(Arg.getLValueBase(), Arg.getLValueOffset(), Arg.getLValueDesignator().Entries, - Arg.getLValueDesignator().OnePastTheEnd); + Arg.getLValueDesignator().IsOnePastTheEnd); Value.printPretty(Out, Frame->Info.Ctx, Param->getType()); } @@ -544,7 +624,44 @@ namespace { Base = B; Offset = CharUnits::Zero(); Frame = F; - Designator = SubobjectDesignator(); + Designator = SubobjectDesignator(getType(B)); + } + + // Check that this LValue is not based on a null pointer. If it is, produce + // a diagnostic and mark the designator as invalid. + bool checkNullPointer(EvalInfo &Info, const Expr *E, + CheckSubobjectKind CSK) { + if (Designator.Invalid) + return false; + if (!Base) { + Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_null_subobject) + << CSK; + Designator.setInvalid(); + return false; + } + return true; + } + + // Check this LValue refers to an object. If not, set the designator to be + // invalid and emit a diagnostic. + bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK) { + return checkNullPointer(Info, E, CSK) && + Designator.checkSubobject(Info, E, CSK); + } + + void addDecl(EvalInfo &Info, const Expr *E, + const Decl *D, bool Virtual = false) { + checkSubobject(Info, E, isa<FieldDecl>(D) ? CSK_Field : CSK_Base); + Designator.addDeclUnchecked(D, Virtual); + } + void addArray(EvalInfo &Info, const Expr *E, const ConstantArrayType *CAT) { + checkSubobject(Info, E, CSK_ArrayToPointer); + Designator.addArrayUnchecked(CAT); + } + void adjustIndex(EvalInfo &Info, const Expr *E, uint64_t N) { + if (!checkNullPointer(Info, E, CSK_ArrayIndex)) + return; + Designator.adjustIndex(Info, E, N); } }; @@ -714,7 +831,8 @@ static bool IsGlobalLValue(APValue::LValueBase B) { } /// Check that this reference or pointer core constant expression is a valid -/// value for a constant expression. Type T should be either LValue or CCValue. +/// value for an address or reference constant expression. Type T should be +/// either LValue or CCValue. template<typename T> static bool CheckLValueConstantExpression(EvalInfo &Info, const Expr *E, const T &LVal, APValue &Value, @@ -739,20 +857,38 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, const Expr *E, return false; } - // A constant expression must refer to an object or be a null pointer. - if (Designator.Invalid || - (!LVal.getLValueBase() && !Designator.Entries.empty())) { - // FIXME: This is not a core constant expression. We should have already - // produced a CCE diagnostic. + bool IsReferenceType = E->isGLValue(); + + if (Designator.Invalid) { + // This is not a core constant expression. A diagnostic will have already + // been produced. + if (IsReferenceType) + return false; + + // Allow this for pointers, so we can fold things like integers cast to + // pointers. Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(), APValue::NoLValuePath()); return true; } + Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(), + Designator.Entries, Designator.IsOnePastTheEnd); + + // Allow address constant expressions to be past-the-end pointers. This is + // an extension: the standard requires them to point to an object. + if (!IsReferenceType) + return true; + + // A reference constant expression must refer to an object. + if (!Base) { + // FIXME: diagnostic + Info.CCEDiag(E->getExprLoc()); + return false; + } + // Does this refer one past the end of some object? - // This is technically not an address constant expression nor a reference - // constant expression, but we allow it for address constant expressions. - if (E->isGLValue() && Base && Designator.OnePastTheEnd) { + if (Designator.isOnePastTheEnd()) { const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>(); Info.Diag(E->getExprLoc(), diag::note_constexpr_past_end, 1) << !Designator.Entries.empty() << !!VD << VD; @@ -764,8 +900,6 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, const Expr *E, return false; } - Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(), - Designator.Entries, Designator.OnePastTheEnd); return true; } @@ -980,49 +1114,22 @@ static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E, return false; } -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(LVal.Base).getTypePtr(); - - // Find path prefix which leads to the most-derived subobject. - MostDerivedType = T->getAsCXXRecordDecl(); - MostDerivedPathLength = 0; - MostDerivedIsArrayElement = false; - - for (unsigned I = 0, N = D.Entries.size(); I != N; ++I) { - bool IsArray = T && T->isArrayType(); - if (IsArray) - T = T->getBaseElementTypeUnsafe(); - else if (const FieldDecl *FD = getAsField(D.Entries[I])) - T = FD->getType().getTypePtr(); - else - T = 0; - - if (T) { - MostDerivedType = T->getAsCXXRecordDecl(); - MostDerivedPathLength = I + 1; - MostDerivedIsArrayElement = IsArray; - } - } +/// Cast an lvalue referring to a base subobject to a derived class, by +/// truncating the lvalue's path to the given length. +static bool CastToDerivedClass(EvalInfo &Info, const Expr *E, LValue &Result, + const RecordDecl *TruncatedType, + unsigned TruncatedElements) { + SubobjectDesignator &D = Result.Designator; - // (B*)&d + 1 has no most-derived object. - if (D.OnePastTheEnd && MostDerivedPathLength != D.Entries.size()) + // Check we actually point to a derived class object. + if (TruncatedElements == D.Entries.size()) + return true; + assert(TruncatedElements >= D.MostDerivedPathLength && + "not casting to a derived class"); + if (!Result.checkSubobject(Info, E, CSK_Derived)) return false; - return MostDerivedType != 0; -} - -static void TruncateLValueBasePath(EvalInfo &Info, LValue &Result, - const RecordDecl *TruncatedType, - unsigned TruncatedElements, - bool IsArrayElement) { - SubobjectDesignator &D = Result.Designator; + // Truncate the path to the subobject, and remove any derived-to-base offsets. const RecordDecl *RD = TruncatedType; for (unsigned I = TruncatedElements, N = D.Entries.size(); I != N; ++I) { const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); @@ -1034,58 +1141,47 @@ static void TruncateLValueBasePath(EvalInfo &Info, LValue &Result, RD = Base; } 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; } -static void HandleLValueDirectBase(EvalInfo &Info, LValue &Obj, +static void HandleLValueDirectBase(EvalInfo &Info, const Expr *E, LValue &Obj, const CXXRecordDecl *Derived, const CXXRecordDecl *Base, const ASTRecordLayout *RL = 0) { if (!RL) RL = &Info.Ctx.getASTRecordLayout(Derived); Obj.getLValueOffset() += RL->getBaseClassOffset(Base); - Obj.Designator.addDecl(Base, /*Virtual*/ false); + Obj.addDecl(Info, E, Base, /*Virtual*/ false); } -static bool HandleLValueBase(EvalInfo &Info, LValue &Obj, +static bool HandleLValueBase(EvalInfo &Info, const Expr *E, LValue &Obj, const CXXRecordDecl *DerivedDecl, const CXXBaseSpecifier *Base) { const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl(); if (!Base->isVirtual()) { - HandleLValueDirectBase(Info, Obj, DerivedDecl, BaseDecl); + HandleLValueDirectBase(Info, E, Obj, DerivedDecl, BaseDecl); return true; } + SubobjectDesignator &D = Obj.Designator; + if (D.Invalid) + return false; + // Extract most-derived object and corresponding type. - if (!ExtractMostDerivedObject(Info, Obj, DerivedDecl)) + DerivedDecl = D.MostDerivedType->getAsCXXRecordDecl(); + if (!CastToDerivedClass(Info, E, Obj, DerivedDecl, D.MostDerivedPathLength)) return false; + // Find the virtual base class. const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl); Obj.getLValueOffset() += Layout.getVBaseClassOffset(BaseDecl); - Obj.Designator.addDecl(BaseDecl, /*Virtual*/ true); + Obj.addDecl(Info, E, BaseDecl, /*Virtual*/ true); return true; } /// Update LVal to refer to the given field, which must be a member of the type /// currently described by LVal. -static void HandleLValueMember(EvalInfo &Info, LValue &LVal, +static void HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal, const FieldDecl *FD, const ASTRecordLayout *RL = 0) { if (!RL) @@ -1093,7 +1189,7 @@ static void HandleLValueMember(EvalInfo &Info, LValue &LVal, unsigned I = FD->getFieldIndex(); LVal.Offset += Info.Ctx.toCharUnitsFromBits(RL->getFieldOffset(I)); - LVal.Designator.addDecl(FD); + LVal.addDecl(Info, E, FD); } /// Get the size of the given type in char units. @@ -1107,6 +1203,7 @@ static bool HandleSizeof(EvalInfo &Info, QualType Type, CharUnits &Size) { if (!Type->isConstantSizeType()) { // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2. + // FIXME: Diagnostic. return false; } @@ -1116,18 +1213,20 @@ static bool HandleSizeof(EvalInfo &Info, QualType Type, CharUnits &Size) { /// Update a pointer value to model pointer arithmetic. /// \param Info - Information about the ongoing evaluation. +/// \param E - The expression being evaluated, for diagnostic purposes. /// \param LVal - The pointer value to be updated. /// \param EltTy - The pointee type represented by LVal. /// \param Adjustment - The adjustment, in objects of type EltTy, to add. -static bool HandleLValueArrayAdjustment(EvalInfo &Info, LValue &LVal, - QualType EltTy, int64_t Adjustment) { +static bool HandleLValueArrayAdjustment(EvalInfo &Info, const Expr *E, + LValue &LVal, QualType EltTy, + int64_t Adjustment) { CharUnits SizeOfPointee; if (!HandleSizeof(Info, EltTy, SizeOfPointee)) return false; // Compute the new offset in the appropriate width. LVal.Offset += Adjustment * SizeOfPointee; - LVal.Designator.adjustIndex(Adjustment); + LVal.adjustIndex(Info, E, Adjustment); return true; } @@ -1156,7 +1255,8 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E, // If we're currently evaluating the initializer of this declaration, use that // in-flight value. if (Info.EvaluatingDecl == VD) { - Result = CCValue(*Info.EvaluatingDeclValue, CCValue::GlobalValue()); + Result = CCValue(Info.Ctx, *Info.EvaluatingDeclValue, + CCValue::GlobalValue()); return !Result.isUninit(); } @@ -1183,7 +1283,7 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E, Info.addNotes(Notes); } - Result = CCValue(*VD->getEvaluatedValue(), CCValue::GlobalValue()); + Result = CCValue(Info.Ctx, *VD->getEvaluatedValue(), CCValue::GlobalValue()); return true; } @@ -1211,11 +1311,10 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived, static bool ExtractSubobject(EvalInfo &Info, const Expr *E, CCValue &Obj, QualType ObjType, const SubobjectDesignator &Sub, QualType SubType) { - if (Sub.Invalid) { - Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); + if (Sub.Invalid) + // A diagnostic will have already been produced. return false; - } - if (Sub.OnePastTheEnd) { + if (Sub.isOnePastTheEnd()) { Info.Diag(E->getExprLoc(), Info.getLangOpts().CPlusPlus0x ? (unsigned)diag::note_constexpr_read_past_end : (unsigned)diag::note_invalid_subexpr_in_const_expr); @@ -1288,7 +1387,7 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E, } } - Obj = CCValue(*O, CCValue::GlobalValue()); + Obj = CCValue(Info.Ctx, *O, CCValue::GlobalValue()); return true; } @@ -1309,6 +1408,10 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, if (!Info.getLangOpts().CPlusPlus) Info.CCEDiag(Conv->getExprLoc(), diag::note_invalid_subexpr_in_const_expr); + if (LVal.Designator.Invalid) + // A diagnostic will have already been produced. + return false; + const Expr *Base = LVal.Base.dyn_cast<const Expr*>(); CallStackFrame *Frame = LVal.Frame; SourceLocation Loc = Conv->getExprLoc(); @@ -1513,16 +1616,9 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info, 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() > + if (LV.Designator.MostDerivedPathLength + MemPtr.Path.size() > LV.Designator.Entries.size()) return 0; unsigned PathLengthToMember = @@ -1536,11 +1632,9 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info, } // Truncate the lvalue to the appropriate derived class. - bool ResultIsArray = false; - if (PathLengthToMember == MostDerivedPathLength) - ResultIsArray = MostDerivedIsArrayElement; - TruncateLValueBasePath(Info, LV, MemPtr.getContainingRecord(), - PathLengthToMember, ResultIsArray); + if (!CastToDerivedClass(Info, BO, LV, MemPtr.getContainingRecord(), + PathLengthToMember)) + return 0; } else if (!MemPtr.Path.empty()) { // Extend the LValue path with the member pointer's path. LV.Designator.Entries.reserve(LV.Designator.Entries.size() + @@ -1555,11 +1649,11 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info, // 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); + HandleLValueDirectBase(Info, BO, LV, RD, Base); RD = Base; } // Finally cast to the class containing the member. - HandleLValueDirectBase(Info, LV, RD, MemPtr.getContainingRecord()); + HandleLValueDirectBase(Info, BO, LV, RD, MemPtr.getContainingRecord()); } // Add the member. Note that we cannot build bound member functions here. @@ -1567,7 +1661,7 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info, // FIXME: Deal with IndirectFieldDecls. const FieldDecl *FD = dyn_cast<FieldDecl>(MemPtr.getDecl()); if (!FD) return 0; - HandleLValueMember(Info, LV, FD); + HandleLValueMember(Info, BO, LV, FD); } return MemPtr.getDecl(); @@ -1577,40 +1671,38 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info, /// 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()) + if (D.Invalid || !Result.checkNullPointer(Info, E, CSK_Derived)) 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(); + + // Check this cast lands within the final derived-to-base subobject path. + if (D.MostDerivedPathLength + E->path_size() > D.Entries.size()) { + Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_invalid_downcast) + << D.MostDerivedType << TargetQT; + 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(); const CXXRecordDecl *TargetType = TargetQT->getAsCXXRecordDecl(); const CXXRecordDecl *FinalType; - if (NewEntriesSize == MostDerivedPathLength) { - ResultIsArray = MostDerivedIsArrayElement; - FinalType = MostDerivedType; - } else + if (NewEntriesSize == D.MostDerivedPathLength) + FinalType = D.MostDerivedType->getAsCXXRecordDecl(); + else FinalType = getAsBaseClass(D.Entries[NewEntriesSize - 1]); - if (FinalType->getCanonicalDecl() != TargetType->getCanonicalDecl()) + if (FinalType->getCanonicalDecl() != TargetType->getCanonicalDecl()) { + Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_invalid_downcast) + << D.MostDerivedType << TargetQT; return false; + } // Truncate the lvalue to the appropriate derived class. - TruncateLValueBasePath(Info, Result, TargetType, NewEntriesSize, - ResultIsArray); - return true; + return CastToDerivedClass(Info, E, Result, TargetType, NewEntriesSize); } namespace { @@ -1787,14 +1879,14 @@ static bool HandleConstructorCall(const Expr *CallExpr, const LValue &This, ++BaseIt; #endif LValue Subobject = This; - HandleLValueDirectBase(Info, Subobject, RD, + HandleLValueDirectBase(Info, (*I)->getInit(), Subobject, RD, BaseType->getAsCXXRecordDecl(), &Layout); if (!EvaluateConstantExpression(Result.getStructBase(BasesSeen++), Info, Subobject, (*I)->getInit())) return false; } else if (FieldDecl *FD = (*I)->getMember()) { LValue Subobject = This; - HandleLValueMember(Info, Subobject, FD, &Layout); + HandleLValueMember(Info, (*I)->getInit(), Subobject, FD, &Layout); if (RD->isUnion()) { Result = APValue(FD); if (!EvaluateConstantExpression(Result.getUnionValue(), Info, Subobject, @@ -2083,11 +2175,11 @@ public: if (!FD) return Error(Callee); } else if (CalleeType->isFunctionPointerType()) { - CCValue Call; - if (!Evaluate(Call, Info, Callee)) + LValue Call; + if (!EvaluatePointer(Callee, Call, Info)) return false; - if (!Call.isLValue() || !Call.getLValueOffset().isZero()) + if (!Call.getLValueOffset().isZero()) return Error(Callee); FD = dyn_cast_or_null<FunctionDecl>( Call.getLValueBase().dyn_cast<const ValueDecl*>()); @@ -2124,7 +2216,7 @@ public: !HandleFunctionCall(E, Definition, This, Args, Body, Info, Result)) return false; - return DerivedSuccess(CCValue(Result, CCValue::GlobalValue()), E); + return DerivedSuccess(CCValue(Info.Ctx, Result, CCValue::GlobalValue()), E); } RetTy VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { @@ -2163,8 +2255,8 @@ public: assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() == FD->getParent()->getCanonicalDecl() && "record / field mismatch"); - SubobjectDesignator Designator; - Designator.addDecl(FD); + SubobjectDesignator Designator(BaseTy); + Designator.addDeclUnchecked(FD); return ExtractSubobject(Info, E, Val, BaseTy, Designator, E->getType()) && DerivedSuccess(Val, E); @@ -2228,14 +2320,6 @@ public: return true; } - 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; @@ -2253,7 +2337,6 @@ public: 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 @@ -2262,7 +2345,7 @@ public: FD->getParent()->getCanonicalDecl() && "record / field mismatch"); (void)BaseTy; - HandleLValueMember(this->Info, Result, FD); + HandleLValueMember(this->Info, E, Result, FD); if (FD->getType()->isReferenceType()) { CCValue RefValue; @@ -2294,8 +2377,6 @@ public: 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. @@ -2303,7 +2384,7 @@ public: for (CastExpr::path_const_iterator PathI = E->path_begin(), PathE = E->path_end(); PathI != PathE; ++PathI) { - if (!HandleLValueBase(this->Info, Result, Type->getAsCXXRecordDecl(), + if (!HandleLValueBase(this->Info, E, Result, Type->getAsCXXRecordDecl(), *PathI)) return false; Type = (*PathI)->getType(); @@ -2378,8 +2459,6 @@ public: case CK_BaseToDerived: if (!Visit(E->getSubExpr())) return false; - if (!CheckValidLValue()) - return false; return HandleBaseToDerivedCast(Info, E, Result); } } @@ -2502,12 +2581,10 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { = 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); + return HandleLValueArrayAdjustment(Info, E, 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); } @@ -2589,8 +2666,8 @@ bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { 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); + return HandleLValueArrayAdjustment(Info, E, Result, Pointee, + AdditionalOffset); } bool PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) { @@ -2637,7 +2714,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { for (CastExpr::path_const_iterator PathI = E->path_begin(), PathE = E->path_end(); PathI != PathE; ++PathI) { - if (!HandleLValueBase(Info, Result, Type->getAsCXXRecordDecl(), *PathI)) + if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(), + *PathI)) return false; Type = (*PathI)->getType(); } @@ -2687,7 +2765,11 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { return false; } // The result is a pointer to the first element of the array. - Result.Designator.addIndex(0); + if (const ConstantArrayType *CAT + = Info.Ctx.getAsConstantArrayType(SubExpr->getType())) + Result.addArray(Info, E, CAT); + else + Result.Designator.setInvalid(); return true; case CK_FunctionToPointerDecay: @@ -2823,7 +2905,8 @@ namespace { /// -- if T is a (possibly cv-qualified) non-union class type, /// each non-static data member and each base-class subobject is /// zero-initialized -static bool HandleClassZeroInitialization(EvalInfo &Info, const RecordDecl *RD, +static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E, + const RecordDecl *RD, const LValue &This, APValue &Result) { assert(!RD->isUnion() && "Expected non-union class type"); const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD); @@ -2835,24 +2918,24 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const RecordDecl *RD, if (CD) { unsigned Index = 0; for (CXXRecordDecl::base_class_const_iterator I = CD->bases_begin(), - E = CD->bases_end(); I ! |