diff options
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r-- | lib/AST/ExprConstant.cpp | 1251 |
1 files changed, 996 insertions, 255 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index ae86150ee2..8c650290b5 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -286,21 +286,37 @@ namespace { /// ParmBindings - Parameter bindings for this function call, indexed by /// parameters' function scope indices. - const APValue *Arguments; + APValue *Arguments; // Note that we intentionally use std::map here so that references to // values are stable. - typedef std::map<const Expr*, APValue> MapTy; + typedef std::map<const void*, APValue> MapTy; typedef MapTy::const_iterator temp_iterator; /// Temporaries - Temporary lvalues materialized within this stack frame. MapTy Temporaries; CallStackFrame(EvalInfo &Info, SourceLocation CallLoc, const FunctionDecl *Callee, const LValue *This, - const APValue *Arguments); + APValue *Arguments); ~CallStackFrame(); }; + /// Temporarily override 'this'. + class ThisOverrideRAII { + public: + ThisOverrideRAII(CallStackFrame &Frame, const LValue *NewThis, bool Enable) + : Frame(Frame), OldThis(Frame.This) { + if (Enable) + Frame.This = NewThis; + } + ~ThisOverrideRAII() { + Frame.This = OldThis; + } + private: + CallStackFrame &Frame; + const LValue *OldThis; + }; + /// A partial diagnostic which we might know in advance that we are not going /// to emit. class OptionalDiagnostic { @@ -581,7 +597,7 @@ void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info, CallStackFrame::CallStackFrame(EvalInfo &Info, SourceLocation CallLoc, const FunctionDecl *Callee, const LValue *This, - const APValue *Arguments) + APValue *Arguments) : Info(Info), Caller(Info.CurrentCall), CallLoc(CallLoc), Callee(Callee), Index(Info.NextCallIndex++), This(This), Arguments(Arguments) { Info.CurrentCall = this; @@ -897,6 +913,18 @@ static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info); // Misc utilities //===----------------------------------------------------------------------===// +/// Evaluate an expression to see if it had side-effects, and discard its +/// result. +/// \return \c true if the caller should keep evaluating. +static bool EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) { + APValue Scratch; + if (!Evaluate(Scratch, Info, E)) { + Info.EvalStatus.HasSideEffects = true; + return Info.keepEvaluatingAfterFailure(); + } + return true; +} + /// Should this call expression be treated as a string literal? static bool IsStringLiteralCall(const CallExpr *E) { unsigned Builtin = E->isBuiltinCall(); @@ -999,7 +1027,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, // Check if this is a thread-local variable. if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) { if (const VarDecl *Var = dyn_cast<const VarDecl>(VD)) { - if (Var->isThreadSpecified()) + if (Var->getTLSKind()) return false; } } @@ -1030,7 +1058,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, /// Check that this core constant expression is of literal type, and if not, /// produce an appropriate diagnostic. static bool CheckLiteralType(EvalInfo &Info, const Expr *E) { - if (!E->isRValue() || E->getType()->isLiteralType()) + if (!E->isRValue() || E->getType()->isLiteralType(Info.Ctx)) return true; // Prvalue constant expressions must be of literal types. @@ -1427,9 +1455,16 @@ static bool HandleLValueComplexElement(EvalInfo &Info, const Expr *E, } /// Try to evaluate the initializer for a variable declaration. -static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E, - const VarDecl *VD, - CallStackFrame *Frame, APValue &Result) { +/// +/// \param Info Information about the ongoing evaluation. +/// \param E An expression to be used when printing diagnostics. +/// \param VD The variable whose initializer should be obtained. +/// \param Frame The frame in which the variable was created. Must be null +/// if this variable is not local to the evaluation. +/// \param Result Filled in with a pointer to the value of the variable. +static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, + const VarDecl *VD, CallStackFrame *Frame, + APValue *&Result) { // If this is a parameter to an active constexpr function call, perform // argument substitution. if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) { @@ -1441,10 +1476,19 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E, Info.Diag(E, diag::note_invalid_subexpr_in_const_expr); return false; } - Result = Frame->Arguments[PVD->getFunctionScopeIndex()]; + Result = &Frame->Arguments[PVD->getFunctionScopeIndex()]; return true; } + // If this is a local variable, dig out its value. + if (Frame) { + Result = &Frame->Temporaries[VD]; + // If we've carried on past an unevaluatable local variable initializer, + // we can't go any further. This can happen during potential constant + // expression checking. + return !Result->isUninit(); + } + // Dig out the initializer, and use the declaration which it's attached to. const Expr *Init = VD->getAnyInitializer(VD); if (!Init || Init->isValueDependent()) { @@ -1458,8 +1502,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 = *Info.EvaluatingDeclValue; - return !Result.isUninit(); + Result = Info.EvaluatingDeclValue; + return !Result->isUninit(); } // Never evaluate the initializer of a weak variable. We can't be sure that @@ -1485,7 +1529,7 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E, Info.addNotes(Notes); } - Result = *VD->getEvaluatedValue(); + Result = VD->getEvaluatedValue(); return true; } @@ -1509,15 +1553,15 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived, llvm_unreachable("base class missing from derived class's bases list"); } -/// Extract the value of a character from a string literal. CharType is used to -/// determine the expected signedness of the result -- a string literal used to -/// initialize an array of 'signed char' or 'unsigned char' might contain chars -/// of the wrong signedness. -static APSInt ExtractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit, - uint64_t Index, QualType CharType) { +/// Extract the value of a character from a string literal. +static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit, + uint64_t Index) { // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant - const StringLiteral *S = dyn_cast<StringLiteral>(Lit); - assert(S && "unexpected string literal expression kind"); + const StringLiteral *S = cast<StringLiteral>(Lit); + const ConstantArrayType *CAT = + Info.Ctx.getAsConstantArrayType(S->getType()); + assert(CAT && "string literal isn't an array"); + QualType CharType = CAT->getElementType(); assert(CharType->isIntegerType() && "unexpected character type"); APSInt Value(S->getCharByteWidth() * Info.Ctx.getCharWidth(), @@ -1527,26 +1571,99 @@ static APSInt ExtractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit, return Value; } -/// Extract the designated sub-object of an rvalue. -static bool ExtractSubobject(EvalInfo &Info, const Expr *E, - APValue &Obj, QualType ObjType, - const SubobjectDesignator &Sub, QualType SubType) { +// Expand a string literal into an array of characters. +static void expandStringLiteral(EvalInfo &Info, const Expr *Lit, + APValue &Result) { + const StringLiteral *S = cast<StringLiteral>(Lit); + const ConstantArrayType *CAT = + Info.Ctx.getAsConstantArrayType(S->getType()); + assert(CAT && "string literal isn't an array"); + QualType CharType = CAT->getElementType(); + assert(CharType->isIntegerType() && "unexpected character type"); + + unsigned Elts = CAT->getSize().getZExtValue(); + Result = APValue(APValue::UninitArray(), + std::min(S->getLength(), Elts), Elts); + APSInt Value(S->getCharByteWidth() * Info.Ctx.getCharWidth(), + CharType->isUnsignedIntegerType()); + if (Result.hasArrayFiller()) + Result.getArrayFiller() = APValue(Value); + for (unsigned I = 0, N = Result.getArrayInitializedElts(); I != N; ++I) { + Value = S->getCodeUnit(I); + Result.getArrayInitializedElt(I) = APValue(Value); + } +} + +// Expand an array so that it has more than Index filled elements. +static void expandArray(APValue &Array, unsigned Index) { + unsigned Size = Array.getArraySize(); + assert(Index < Size); + + // Always at least double the number of elements for which we store a value. + unsigned OldElts = Array.getArrayInitializedElts(); + unsigned NewElts = std::max(Index+1, OldElts * 2); + NewElts = std::min(Size, std::max(NewElts, 8u)); + + // Copy the data across. + APValue NewValue(APValue::UninitArray(), NewElts, Size); + for (unsigned I = 0; I != OldElts; ++I) + NewValue.getArrayInitializedElt(I).swap(Array.getArrayInitializedElt(I)); + for (unsigned I = OldElts; I != NewElts; ++I) + NewValue.getArrayInitializedElt(I) = Array.getArrayFiller(); + if (NewValue.hasArrayFiller()) + NewValue.getArrayFiller() = Array.getArrayFiller(); + Array.swap(NewValue); +} + +/// Kinds of access we can perform on an object. +enum AccessKinds { + AK_Read, + AK_Assign, + AK_Increment, + AK_Decrement +}; + +/// A handle to a complete object (an object that is not a subobject of +/// another object). +struct CompleteObject { + /// The value of the complete object. + APValue *Value; + /// The type of the complete object. + QualType Type; + + CompleteObject() : Value(0) {} + CompleteObject(APValue *Value, QualType Type) + : Value(Value), Type(Type) { + assert(Value && "missing value for complete object"); + } + + operator bool() const { return Value; } +}; + +/// Find the designated sub-object of an rvalue. +template<typename SubobjectHandler> +typename SubobjectHandler::result_type +findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, + const SubobjectDesignator &Sub, SubobjectHandler &handler) { if (Sub.Invalid) // A diagnostic will have already been produced. - return false; + return handler.failed(); if (Sub.isOnePastTheEnd()) { - Info.Diag(E, Info.getLangOpts().CPlusPlus11 ? - (unsigned)diag::note_constexpr_read_past_end : - (unsigned)diag::note_invalid_subexpr_in_const_expr); - return false; + if (Info.getLangOpts().CPlusPlus11) + Info.Diag(E, diag::note_constexpr_access_past_end) + << handler.AccessKind; + else + Info.Diag(E); + return handler.failed(); } if (Sub.Entries.empty()) - return true; - if (Info.CheckingPotentialConstantExpression && Obj.isUninit()) + return handler.found(*Obj.Value, Obj.Type); + if (Info.CheckingPotentialConstantExpression && Obj.Value->isUninit()) // This object might be initialized later. - return false; + return handler.failed(); - APValue *O = &Obj; + APValue *O = Obj.Value; + QualType ObjType = Obj.Type; // Walk the designator's path to find the subobject. for (unsigned I = 0, N = Sub.Entries.size(); I != N; ++I) { if (ObjType->isArrayType()) { @@ -1557,49 +1674,67 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E, if (CAT->getSize().ule(Index)) { // Note, it should not be possible to form a pointer with a valid // designator which points more than one past the end of the array. - Info.Diag(E, Info.getLangOpts().CPlusPlus11 ? - (unsigned)diag::note_constexpr_read_past_end : - (unsigned)diag::note_invalid_subexpr_in_const_expr); - return false; + if (Info.getLangOpts().CPlusPlus11) + Info.Diag(E, diag::note_constexpr_access_past_end) + << handler.AccessKind; + else + Info.Diag(E); + return handler.failed(); } + + ObjType = CAT->getElementType(); + // An array object is represented as either an Array APValue or as an // LValue which refers to a string literal. if (O->isLValue()) { assert(I == N - 1 && "extracting subobject of character?"); assert(!O->hasLValuePath() || O->getLValuePath().empty()); - Obj = APValue(ExtractStringLiteralCharacter( - Info, O->getLValueBase().get<const Expr*>(), Index, SubType)); - return true; - } else if (O->getArrayInitializedElts() > Index) + if (handler.AccessKind != AK_Read) + expandStringLiteral(Info, O->getLValueBase().get<const Expr *>(), + *O); + else + return handler.foundString(*O, ObjType, Index); + } + + if (O->getArrayInitializedElts() > Index) O = &O->getArrayInitializedElt(Index); - else + else if (handler.AccessKind != AK_Read) { + expandArray(*O, Index); + O = &O->getArrayInitializedElt(Index); + } else O = &O->getArrayFiller(); - ObjType = CAT->getElementType(); } else if (ObjType->isAnyComplexType()) { // Next subobject is a complex number. uint64_t Index = Sub.Entries[I].ArrayIndex; if (Index > 1) { - Info.Diag(E, Info.getLangOpts().CPlusPlus11 ? - (unsigned)diag::note_constexpr_read_past_end : - (unsigned)diag::note_invalid_subexpr_in_const_expr); - return false; + if (Info.getLangOpts().CPlusPlus11) + Info.Diag(E, diag::note_constexpr_access_past_end) + << handler.AccessKind; + else + Info.Diag(E); + return handler.failed(); } + + bool WasConstQualified = ObjType.isConstQualified(); + ObjType = ObjType->castAs<ComplexType>()->getElementType(); + if (WasConstQualified) + ObjType.addConst(); + assert(I == N - 1 && "extracting subobject of scalar?"); if (O->isComplexInt()) { - Obj = APValue(Index ? O->getComplexIntImag() - : O->getComplexIntReal()); + return handler.found(Index ? O->getComplexIntImag() + : O->getComplexIntReal(), ObjType); } else { assert(O->isComplexFloat()); - Obj = APValue(Index ? O->getComplexFloatImag() - : O->getComplexFloatReal()); + return handler.found(Index ? O->getComplexFloatImag() + : O->getComplexFloatReal(), ObjType); } - return true; } else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) { - if (Field->isMutable()) { + if (Field->isMutable() && handler.AccessKind == AK_Read) { Info.Diag(E, diag::note_constexpr_ltor_mutable, 1) << Field; Info.Note(Field->getLocation(), diag::note_declared_at); - return false; + return handler.failed(); } // Next subobject is a class, struct or union field. @@ -1608,49 +1743,150 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E, const FieldDecl *UnionField = O->getUnionField(); if (!UnionField || UnionField->getCanonicalDecl() != Field->getCanonicalDecl()) { - Info.Diag(E, diag::note_constexpr_read_inactive_union_member) - << Field << !UnionField << UnionField; - return false; + Info.Diag(E, diag::note_constexpr_access_inactive_union_member) + << handler.AccessKind << Field << !UnionField << UnionField; + return handler.failed(); } O = &O->getUnionValue(); } else O = &O->getStructField(Field->getFieldIndex()); + + bool WasConstQualified = ObjType.isConstQualified(); ObjType = Field->getType(); + if (WasConstQualified && !Field->isMutable()) + ObjType.addConst(); if (ObjType.isVolatileQualified()) { if (Info.getLangOpts().CPlusPlus) { // FIXME: Include a description of the path to the volatile subobject. - Info.Diag(E, diag::note_constexpr_ltor_volatile_obj, 1) - << 2 << Field; + Info.Diag(E, diag::note_constexpr_access_volatile_obj, 1) + << handler.AccessKind << 2 << Field; Info.Note(Field->getLocation(), diag::note_declared_at); } else { Info.Diag(E, diag::note_invalid_subexpr_in_const_expr); } - return false; + return handler.failed(); } } else { // Next subobject is a base class. const CXXRecordDecl *Derived = ObjType->getAsCXXRecordDecl(); const CXXRecordDecl *Base = getAsBaseClass(Sub.Entries[I]); O = &O->getStructBase(getBaseIndex(Derived, Base)); + + bool WasConstQualified = ObjType.isConstQualified(); ObjType = Info.Ctx.getRecordType(Base); + if (WasConstQualified) + ObjType.addConst(); } if (O->isUninit()) { if (!Info.CheckingPotentialConstantExpression) - Info.Diag(E, diag::note_constexpr_read_uninit); + Info.Diag(E, diag::note_constexpr_access_uninit) << handler.AccessKind; + return handler.failed(); + } + } + + return handler.found(*O, ObjType); +} + +namespace { +struct ExtractSubobjectHandler { + EvalInfo &Info; + APValue &Result; + + static const AccessKinds AccessKind = AK_Read; + + typedef bool result_type; + bool failed() { return false; } + bool found(APValue &Subobj, QualType SubobjType) { + Result = Subobj; + return true; + } + bool found(APSInt &Value, QualType SubobjType) { + Result = APValue(Value); + return true; + } + bool found(APFloat &Value, QualType SubobjType) { + Result = APValue(Value); + return true; + } + bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) { + Result = APValue(extractStringLiteralCharacter( + Info, Subobj.getLValueBase().get<const Expr *>(), Character)); + return true; + } +}; +} // end anonymous namespace + +const AccessKinds ExtractSubobjectHandler::AccessKind; + +/// Extract the designated sub-object of an rvalue. +static bool extractSubobject(EvalInfo &Info, const Expr *E, + const CompleteObject &Obj, + const SubobjectDesignator &Sub, + APValue &Result) { + ExtractSubobjectHandler Handler = { Info, Result }; + return findSubobject(Info, E, Obj, Sub, Handler); +} + +namespace { +struct ModifySubobjectHandler { + EvalInfo &Info; + APValue &NewVal; + const Expr *E; + + typedef bool result_type; + static const AccessKinds AccessKind = AK_Assign; + + bool checkConst(QualType QT) { + // Assigning to a const object has undefined behavior. + if (QT.isConstQualified()) { + Info.Diag(E, diag::note_constexpr_modify_const_type) << QT; return false; } + return true; } - // This may look super-stupid, but it serves an important purpose: if we just - // swapped Obj and *O, we'd create an object which had itself as a subobject. - // To avoid the leak, we ensure that Tmp ends up owning the original complete - // object, which is destroyed by Tmp's destructor. - APValue Tmp; - O->swap(Tmp); - Obj.swap(Tmp); - return true; + bool failed() { return false; } + bool found(APValue &Subobj, QualType SubobjType) { + if (!checkConst(SubobjType)) + return false; + // We've been given ownership of NewVal, so just swap it in. + Subobj.swap(NewVal); + return true; + } + bool found(APSInt &Value, QualType SubobjType) { + if (!checkConst(SubobjType)) + return false; + if (!NewVal.isInt()) { + // Maybe trying to write a cast pointer value into a complex? + Info.Diag(E); + return false; + } + Value = NewVal.getInt(); + return true; + } + bool found(APFloat &Value, QualType SubobjType) { + if (!checkConst(SubobjType)) + return false; + Value = NewVal.getFloat(); + return true; + } + bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) { + llvm_unreachable("shouldn't encounter string elements with ExpandArrays"); + } +}; +} // end anonymous namespace + +const AccessKinds ModifySubobjectHandler::AccessKind; + +/// Update the designated sub-object of an rvalue to the given value. +static bool modifySubobject(EvalInfo &Info, const Expr *E, + const CompleteObject &Obj, + const SubobjectDesignator &Sub, + APValue &NewVal) { + ModifySubobjectHandler Handler = { Info, NewVal, E }; + return findSubobject(Info, E, Obj, Sub, Handler); } /// Find the position where two subobject designators diverge, or equivalently @@ -1710,59 +1946,52 @@ static bool AreElementsOfSameArray(QualType ObjType, return CommonLength >= A.Entries.size() - IsArray; } -/// HandleLValueToRValueConversion - Perform an lvalue-to-rvalue conversion on -/// the given lvalue. This can also be used for 'lvalue-to-lvalue' conversions -/// for looking up the glvalue referred to by an entity of reference type. -/// -/// \param Info - Information about the ongoing evaluation. -/// \param Conv - The expression for which we are performing the conversion. -/// Used for diagnostics. -/// \param Type - The type we expect this conversion to produce, before -/// stripping cv-qualifiers in the case of a non-clas type. -/// \param LVal - The glvalue on which we are attempting to perform this action. -/// \param RVal - The produced value will be placed here. -static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, - QualType Type, - const LValue &LVal, APValue &RVal) { - if (LVal.Designator.Invalid) - // A diagnostic will have already been produced. - return false; - - const Expr *Base = LVal.Base.dyn_cast<const Expr*>(); - +/// Find the complete object to which an LValue refers. +CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, + const LValue &LVal, QualType LValType) { if (!LVal.Base) { - // FIXME: Indirection through a null pointer deserves a specific diagnostic. - Info.Diag(Conv, diag::note_invalid_subexpr_in_const_expr); - return false; + Info.Diag(E, diag::note_constexpr_access_null) << AK; + return CompleteObject(); } CallStackFrame *Frame = 0; if (LVal.CallIndex) { Frame = Info.getCallFrame(LVal.CallIndex); if (!Frame) { - Info.Diag(Conv, diag::note_constexpr_lifetime_ended, 1) << !Base; + Info.Diag(E, diag::note_constexpr_lifetime_ended, 1) + << AK << LVal.Base.is<const ValueDecl*>(); NoteLValueLocation(Info, LVal.Base); - return false; + return CompleteObject(); } + } else if (AK != AK_Read) { + Info.Diag(E, diag::note_constexpr_modify_global); + return CompleteObject(); } // C++11 DR1311: An lvalue-to-rvalue conversion on a volatile-qualified type // is not a constant expression (even if the object is non-volatile). We also // apply this rule to C++98, in order to conform to the expected 'volatile' // semantics. - if (Type.isVolatileQualified()) { + if (LValType.isVolatileQualified()) { if (Info.getLangOpts().CPlusPlus) - Info.Diag(Conv, diag::note_constexpr_ltor_volatile_type) << Type; + Info.Diag(E, diag::note_constexpr_access_volatile_type) + << AK << LValType; else - Info.Diag(Conv); - return false; + Info.Diag(E); + return CompleteObject(); } + // Compute value storage location and type of base object. + APValue *BaseVal = 0; + QualType BaseType; + if (const ValueDecl *D = LVal.Base.dyn_cast<const ValueDecl*>()) { // In C++98, const, non-volatile integers initialized with ICEs are ICEs. // In C++11, constexpr, non-volatile variables initialized with constant // expressions are constant expressions too. Inside constexpr functions, // parameters are constant expressions even if they're non-const. + // In C++1y, objects local to a constant expression (those with a Frame) are + // both readable and writable inside constant expressions. // In C, such things can also be folded, although they are not ICEs. const VarDecl *VD = dyn_cast<VarDecl>(D); if (VD) { @@ -1770,120 +1999,312 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, VD = VDef; } if (!VD || VD->isInvalidDecl()) { - Info.Diag(Conv); - return false; + Info.Diag(E); + return CompleteObject(); } - // DR1313: If the object is volatile-qualified but the glvalue was not, - // behavior is undefined so the result is not a constant expression. - QualType VT = VD->getType(); - if (VT.isVolatileQualified()) { + // Accesses of volatile-qualified objects are not allowed. + BaseType = VD->getType(); + if (BaseType.isVolatileQualified()) { if (Info.getLangOpts().CPlusPlus) { - Info.Diag(Conv, diag::note_constexpr_ltor_volatile_obj, 1) << 1 << VD; + Info.Diag(E, diag::note_constexpr_access_volatile_obj, 1) + << AK << 1 << VD; Info.Note(VD->getLocation(), diag::note_declared_at); } else { - Info.Diag(Conv); + Info.Diag(E); } - return false; + return CompleteObject(); } - if (!isa<ParmVarDecl>(VD)) { + // Unless we're looking at a local variable or argument in a constexpr call, + // the variable we're reading must be const. + if (!Frame) { + assert(AK == AK_Read && "can't modify non-local"); if (VD->isConstexpr()) { // OK, we can read this variable. - } else if (VT->isIntegralOrEnumerationType()) { - if (!VT.isConstQualified()) { + } else if (BaseType->isIntegralOrEnumerationType()) { + if (!BaseType.isConstQualified()) { if (Info.getLangOpts().CPlusPlus) { - Info.Diag(Conv, diag::note_constexpr_ltor_non_const_int, 1) << VD; + Info.Diag(E, diag::note_constexpr_ltor_non_const_int, 1) << VD; Info.Note(VD->getLocation(), diag::note_declared_at); } else { - Info.Diag(Conv); + Info.Diag(E); } - return false; + return CompleteObject(); } - } else if (VT->isFloatingType() && VT.isConstQualified()) { + } else if (BaseType->isFloatingType() && BaseType.isConstQualified()) { // We support folding of const floating-point types, in order to make // static const data members of such types (supported as an extension) // more useful. if (Info.getLangOpts().CPlusPlus11) { - Info.CCEDiag(Conv, diag::note_constexpr_ltor_non_constexpr, 1) << VD; + Info.CCEDiag(E, diag::note_constexpr_ltor_non_constexpr, 1) << VD; Info.Note(VD->getLocation(), diag::note_declared_at); } else { - Info.CCEDiag(Conv); + Info.CCEDiag(E); } } else { // FIXME: Allow folding of values of any literal type in all languages. if (Info.getLangOpts().CPlusPlus11) { - Info.Diag(Conv, diag::note_constexpr_ltor_non_constexpr, 1) << VD; + Info.Diag(E, diag::note_constexpr_ltor_non_constexpr, 1) << VD; Info.Note(VD->getLocation(), diag::note_declared_at); } else { - Info.Diag(Conv); + Info.Diag(E); } - return false; + return CompleteObject(); } } - if (!EvaluateVarDeclInit(Info, Conv, VD, Frame, RVal)) - return false; + if (!evaluateVarDeclInit(Info, E, VD, Frame, BaseVal)) + return CompleteObject(); + } else { + const Expr *Base = LVal.Base.dyn_cast<const Expr*>(); + + if (!Frame) { + Info.Diag(E); + return CompleteObject(); + } - if (isa<ParmVarDecl>(VD) || !VD->getAnyInitializer()->isLValue()) - return ExtractSubobject(Info, Conv, RVal, VT, LVal.Designator, Type); - - // The declaration was initialized by an lvalue, with no lvalue-to-rvalue - // conversion. This happens when the declaration and the lvalue should be - // considered synonymous, for instance when initializing an array of char - // from a string literal. Continue as if the initializer lvalue was the - // value we were originally given. - assert(RVal.getLValueOffset().isZero() && - "offset for lvalue init of non-reference"); - Base = RVal.getLValueBase().get<const Expr*>(); - - if (unsigned CallIndex = RVal.getLValueCallIndex()) { - Frame = Info.getCallFrame(CallIndex); - if (!Frame) { - Info.Diag(Conv, diag::note_constexpr_lifetime_ended, 1) << !Base; - NoteLValueLocation(Info, RVal.getLValueBase()); + BaseType = Base->getType(); + BaseVal = &Frame->Temporaries[Base]; + + // Volatile temporary objects cannot be accessed in constant expressions. + if (BaseType.isVolatileQualified()) { + if (Info.getLangOpts().CPlusPlus) { + Info.Diag(E, diag::note_constexpr_access_volatile_obj, 1) + << AK << 0; + Info.Note(Base->getExprLoc(), diag::note_constexpr_temporary_here); + } else { + Info.Diag(E); + } + return CompleteObject(); + } + } + + // In C++1y, we can't safely access any mutable state when checking a + // potential constant expression. + if (Frame && Info.getLangOpts().CPlusPlus1y && + Info.CheckingPotentialConstantExpression) + return CompleteObject(); + + return CompleteObject(BaseVal, BaseType); +} + +/// \brief Perform an lvalue-to-rvalue conversion on the given glvalue. This +/// can also be used for 'lvalue-to-lvalue' conversions for looking up the +/// glvalue referred to by an entity of reference type. +/// +/// \param Info - Information about the ongoing evaluation. +/// \param Conv - The expression for which we are performing the conversion. +/// Used for diagnostics. +/// \param Type - The type of the glvalue (before stripping cv-qualifiers in the +/// case of a non-class type). +/// \param LVal - The glvalue on which we are attempting to perform this action. +/// \param RVal - The produced value will be placed here. +static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, + QualType Type, + const LValue &LVal, APValue &RVal) { + if (LVal.Designator.Invalid) + return false; + + // Check for special cases where there is no existing APValue to look at. + const Expr *Base = LVal.Base.dyn_cast<const Expr*>(); + if (!LVal.Designator.Invalid && Base && !LVal.CallIndex && + !Type.isVolatileQualified()) { + if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(Base)) { + // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the + // initializer until now for such expressions. Such an expression can't be + // an ICE in C, so this only matters for fold. + assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?"); + if (Type.isVolatileQualified()) { + Info.Diag(Conv); return false; } - } else { - Frame = 0; + APValue Lit; + if (!Evaluate(Lit, Info, CLE->getInitializer())) + return false; + CompleteObject LitObj(&Lit, Base->getType()); + return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal); + } else if (isa<StringLiteral>(Base)) { + // We represent a string literal array as an lvalue pointing at the + // corresponding expression, rather than building an array of chars. + // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant + APValue Str(Base, CharUnits::Zero(), APValue::NoLValuePath(), 0); + CompleteObject StrObj(&Str, Base->getType()); + return extractSubobject(Info, Conv, StrObj, LVal.Designator, RVal); } } - // Volatile temporary objects cannot be read in constant expressions. - if (Base->getType().isVolatileQualified()) { - if (Info.getLangOpts().CPlusPlus) { - Info.Diag(Conv, diag::note_constexpr_ltor_volatile_obj, 1) << 0; - Info.Note(Base->getExprLoc(), diag::note_constexpr_temporary_here); + CompleteObject Obj = findCompleteObject(Info, Conv, AK_Read, LVal, Type); + return Obj && extractSubobject(Info, Conv, Obj, LVal.Designator, RVal); +} + +/// Perform an assignment of Val to LVal. Takes ownership of Val. +static bool handleAssignment(EvalInfo &Info, const Expr *E, const LValue &LVal, + QualType LValType, APValue &Val) { + if (LVal.Designator.Invalid) + return false; + + if (!Info.getLangOpts().CPlusPlus1y) { + Info.Diag(E); + return false; + } + + CompleteObject Obj = findCompleteObject(Info, E, AK_Assign, LVal, LValType); + return Obj && modifySubobject(Info, E, Obj, LVal.Designator, Val); +} + +static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) { + return T->isSignedIntegerType() && + Ctx.getIntWidth(T) >= Ctx.getIntWidth(Ctx.IntTy); +} + +namespace { +struct IncDecSubobjectHandler { + EvalInfo &Info; + const Expr *E; + AccessKinds AccessKind; + APValue *Old; + + typedef bool result_type; + + bool checkConst(QualType QT) { + // Assigning to a const object has undefined behavior. + if (QT.isConstQualified()) { + Info.Diag(E, diag::note_constexpr_modify_const_type) << QT; + return false; + } + return true; + } + + bool failed() { return false; } + bool found(APValue &Subobj, QualType SubobjType) { + // Stash the old value. Also clear Old, so we don't clobber it later + // if we're post-incrementing a complex. + if (Old) { + *Old = Subobj; + Old = 0; + } + + switch (Subobj.getKind()) { + case APValue::Int: + return found(Subobj.getInt(), SubobjType); + case APValue::Float: + return found(Subobj.getFloat(), SubobjType); + case APValue::ComplexInt: + return found(Subobj.getComplexIntReal(), + SubobjType->castAs<ComplexType>()->getElementType() + .withCVRQualifiers(SubobjType.getCVRQualifiers())); + case APValue::ComplexFloat: + return found(Subobj.getComplexFloatReal(), + SubobjType->castAs<ComplexType>()->getElementType() + .withCVRQualifiers(SubobjType.getCVRQualifiers())); + case APValue::LValue: + return foundPointer(Subobj, SubobjType); + default: + // FIXME: can this happen? + Info.Diag(E); + return false; + } + } + bool found(APSInt &Value, QualType SubobjType) { + if (!checkConst(SubobjType)) + return false; + + if (!SubobjType->isIntegerType()) { + // We don't support increment / decrement on integer-cast-to-pointer + // values. + Info.Diag(E); + return false; + } + + if (Old) *Old = APValue(Value); + + // bool arithmetic promotes to int, and the conversion back to bool + // doesn't reduce mod 2^n, so special-case it. + if (SubobjType->isBooleanType()) { + if (AccessKind == AK_Increment) + Value = 1; + else + Value = !Value; + return true; + } + + bool WasNegative = Value.isNegative(); + if (AccessKind == AK_Increment) { + ++Value; + + if (!WasNegative && Value.isNegative() && + isOverflowingIntegerType(Info.Ctx, SubobjType)) { + APSInt ActualValue(Value, /*IsUnsigned*/true); + HandleOverflow(Info, E, ActualValue, SubobjType); + } } else { - Info.Diag(Conv); + --Value; + + if (WasNegative && !Value.isNegative() && + isOverflowingIntegerType(Info.Ctx, SubobjType)) { + unsigned BitWidth = Value.getBitWidth(); + APSInt ActualValue(Value.sext(BitWidth + 1), /*IsUnsigned*/false); + ActualValue.setBit(BitWidth); + HandleOverflow(Info, E, ActualValue, SubobjType); + } } - return false; + return true; } + bool found(APFloat &Value, QualType SubobjType) { + if (!checkConst(SubobjType)) + return false; - if (Frame) { - // If this is a temporary expression with a nontrivial initializer, grab the - // value from the relevant stack frame. - RVal = Frame->Temporaries[Base]; - } else if (const CompoundLiteralExpr *CLE - = dyn_cast<CompoundLiteralExpr>(Base)) { - // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the - // initializer until now for such expressions. Such an expression can't be - // an ICE in C, so this only matters for fold. - assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?"); - if (!Evaluate(RVal, Info, CLE->getInitializer())) + if (Old) *Old = APValue(Value); + + APFloat One(Value.getSemantics(), 1); + if (AccessKind == AK_Increment) + Value.add(One, APFloat::rmNearestTiesToEven); + else + Value.subtract(One, APFloat::rmNearestTiesToEven); + return true; + } + bool foundPointer(APValue &Subobj, QualType SubobjType) { + if (!checkConst(SubobjType)) return false; - } else if (isa<StringLiteral>(Base)) { - // We represent a string literal array as an lvalue pointing at the - // corresponding expression, rather than building an array of chars. - // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant - RVal = APValue(Base, CharUnits::Zero(), APValue::NoLValuePath(), 0); - } else { - Info.Diag(Conv, diag::note_invalid_subexpr_in_const_expr); + + QualType PointeeType; + if (const PointerType *PT = SubobjType->getAs<PointerType>()) + PointeeType = PT->getPointeeType(); + else { + Info.Diag(E); + return false; + } + + LValue LVal; + LVal.setFrom(Info.Ctx, Subobj); + if (!HandleLValueArrayAdjustment(Info, E, LVal, PointeeType, + AccessKind == AK_Increment ? 1 : -1)) + return false; + LVal.moveInto(Subobj); + return true; + } + bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) { + llvm_unreachable("shouldn't encounter string elements here"); + } +}; +} // end anonymous namespace + +/// Perform an increment or decrement on LVal. +static bool handleIncDec(EvalInfo &Info, const Expr *E, const LValue &LVal, + QualType LValType, bool IsIncrement, APValue *Old) { + if (LVal.Designator.Invalid) + return false; + + if (!Info.getLangOpts().CPlusPlus1y) { + Info.Diag(E); return false; } - return ExtractSubobject(Info, Conv, RVal, Base->getType(), LVal.Designator, - Type); + AccessKinds AK = IsIncrement ? AK_Increment : AK_Decrement; + CompleteObject Obj = findCompleteObject(Info, E, AK, LVal, LValType); + IncDecSubobjectHandler Handler = { Info, E, AK, Old }; + return Obj && findSubobject(Info, E, Obj, LVal.Designator, Handler); } /// Build an lvalue for the object argument of a member function call. @@ -1895,7 +2316,7 @@ static bool EvaluateObjectArgument(EvalInfo &Info, const Expr *Object, if (Object->isGLValue()) return EvaluateLValue(Object, This, Info); - if (Object->getType()->isLiteralType()) + if (Object->getType()->isLiteralType(Info.Ctx)) return EvaluateTemporary(Object, This, Info); return false; @@ -2040,24 +2461,95 @@ enum EvalStmtResult { /// Hit a 'return' statement. ESR_Returned, /// Evaluation succeeded. - ESR_Succeeded + ESR_Succeeded, + /// Hit a 'continue' statement. + ESR_Continue, + /// Hit a 'break' statement. + ESR_Break }; } +static bool EvaluateDecl(EvalInfo &Info, const Decl *D) { + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + // We don't need to evaluate the initializer for a static local. + if (!VD->hasLocalStorage()) + return true; + + LValue Result; + Result.set(VD, Info.CurrentCall->Index); + APValue &Val = Info.CurrentCall->Temporaries[VD]; + + if (!EvaluateInPlace(Val, Info, Result, VD->getInit())) { + // Wipe out any partially-computed value, to allow tracking that this + // evaluation failed. + Val = APValue(); + return false; + } + } + + return true; +} + +/// Evaluate a condition (either a variable declaration or an expression). +static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl, + const Expr *Cond, bool &Result) { + if (CondDecl && !EvaluateDecl(Info, CondDecl)) + return false; + return EvaluateAsBooleanCondition(Cond, Result, Info); +} + +static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, + const Stmt *S); + +/// Evaluate the body of a loop, and translate the result as appropriate. +static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info, + const Stmt *Body) { + switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body)) { + case ESR_Break: + return ESR_Succeeded; + case ESR_Succeeded: + case ESR_Continue: + return ESR_Continue; + case ESR_Failed: + case ESR_Returned: + return ESR; + } + llvm_unreachable("Invalid EvalStmtResult!"); +} + // Evaluate a statement. static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, const Stmt *S) { + // FIXME: Mark all temporaries in the current frame as destroyed at + // the end of each full-expression. switch (S->getStmtClass()) { default: + if (const Expr *E = dyn_cast<Expr>(S)) { + // Don't bother evaluating beyond an expression-statement which couldn't + // be evaluated. + if (!EvaluateIgnoredValue(Info, E)) + return ESR_Failed; + return ESR_Succeeded; + } + + Info.Diag(S->getLocStart()); return ESR_Failed; case Stmt::NullStmtClass: - case Stmt::DeclStmtClass: return ESR_Succeeded; + case Stmt::DeclStmtClass: { + const DeclStmt *DS = cast<DeclStmt>(S); + for (DeclStmt::const_decl_iterator DclIt = DS->decl_begin(), + DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt) + if (!EvaluateDecl(Info, *DclIt) && !Info.keepEvaluatingAfterFailure()) + return ESR_Failed; + return ESR_Succeeded; + } + case Stmt::ReturnStmtClass: { const Expr *RetExpr = cast<ReturnStmt>(S)->getRetValue(); - if (!Evaluate(Result, Info, RetExpr)) + if (RetExpr && !Evaluate(Result, Info, RetExpr)) return ESR_Failed; return ESR_Returned; } @@ -2072,6 +2564,123 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, } return ESR_Succeeded; } + + case Stmt::IfStmtClass: { + const IfStmt *IS = cast<IfStmt>(S); + + // Evaluate the condition, as either a var decl or as an expression. + bool Cond; + if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(), Cond)) + return ESR_Failed; + + if (const Stmt *SubStmt = Cond ? IS->getThen() : IS->getElse()) { + EvalStmtResult ESR = EvaluateStmt(Result, Info, SubStmt); + if (ESR != ESR_Succeeded) + return ESR; + } + return ESR_Succeeded; + } + + case Stmt::WhileStmtClass: { + const WhileStmt *WS = cast<WhileStmt>(S); + while (true) { + bool Continue; + if (!EvaluateCond(Info, WS->getConditionVariable(), WS->getCond(), + Continue)) + return ESR_Failed; + if (!Continue) + break; + + EvalStmtResult ESR = EvaluateLoopBody(Result, Info, WS->getBody()); + if (ESR != ESR_Continue) + return ESR; + } + return ESR_Succeeded; + } + + case Stmt::DoStmtClass: { + const DoStmt *DS = cast<DoStmt>(S); + bool Continue; + do { + EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody()); + if (ESR != ESR_Continue) + return ESR; + + if (!EvaluateAsBooleanCondition(DS->getCond(), Continue, Info)) + return ESR_Failed; + } while (Continue); + return ESR_Succeeded; + } + + case Stmt::ForStmtClass: { + const ForStmt *FS = cast<ForStmt>(S); + if (FS->getInit()) { + EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getInit()); + if (ESR != ESR_Succeeded) + return ESR; + } + while (true) { + bool Continue = true; + if (FS->getCond() && !EvaluateCond(Info, FS->getConditionVariable(), + FS->getCond(), Continue)) + return ESR_Failed; + if (!Continue) + break; + + EvalStmtResult ESR = EvaluateLoopBody(Result, Info, FS->getBody()); + if (ESR != ESR_Continue) + return ESR; + + if (FS->getInc() && !EvaluateIgnoredValue(Info, FS->getInc())) + return ESR_Failed; + } + return ESR_Succeeded; + } + + case Stmt::CXXForRangeStmtClass: { + const CXXForRangeStmt *FS = cast<CXXForRangeStmt>(S); + + // Initialize the __range variable. + EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getRangeStmt()); + if (ESR != ESR_Succeeded) + return ESR; + + // Create the __begin and __end iterators. + ESR = EvaluateStmt(Result, Info, FS->getBeginEndStmt()); + if (ESR != ESR_Succeeded) + return ESR; + + while (true) { + // Condition: __begin != __end. + bool Continue = true; + if (!EvaluateAsBooleanCondition(FS->getCond(), Continue, Info)) + return ESR_Failed; + if (!Continue) + break; + + // User's variable declaration, initialized by *__begin. + ESR = EvaluateStmt(Result, Info, FS->getLoopVarStmt()); + if (ESR != ESR_Succeeded) + return ESR; + + // Loop body. + ESR = EvaluateLoopBody(Result, Info, FS->getBody()); + if (ESR != ESR_Continue) + return ESR; + + // Increment: ++__begin + if (!EvaluateIgnoredValue(Info, FS->getInc())) + return ESR_Failed; + } + + return ESR_Succeeded; + } + + case Stmt::ContinueStmtClass: + return ESR_Continue; + + case Stmt::BreakStmtClass: + return ESR_Break; } } @@ -2165,7 +2774,13 @@ static bool HandleFunctionCall(SourceLocation CallLoc, return false; CallStackFrame Frame(Info, CallLoc, Callee, This, ArgValues.data()); - return EvaluateStmt(Result, Info, Body) == ESR_Returned; + EvalStmtResult ESR = EvaluateStmt(Result, Info, Body); + if (ESR == ESR_Succeeded) { + if (Callee->getResultType()->isVoidType()) + return true; + Info.Diag(Callee->getLocEnd(), diag::note_constexpr_no_return); + } + return ESR == ESR_Returned; } /// Evaluate a constructor call. @@ -2191,7 +2806,9 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, // If it's a delegating constructor, just delegate. if (Definition->isDelegatingConstructor()) { CXXConstructorDecl::init_const_iterator I = Definition->init_begin(); - return EvaluateInPlace(Result, Info, This, (*I)->getInit()); + if (!EvaluateInPlace(Result, Info, This, (*I)->getInit())) + return false; + return EvaluateStmt(Result, Info, Definition->getBody()) != ESR_Failed; } // For a trivial copy or move constructor, perform an APValue copy. This is @@ -2202,7 +2819,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, (Definition->isMoveConstructor() && Definition->isTrivial()))) { LValue RHS; RHS.setFrom(Info.Ctx, ArgValues[0]); - return HandleLValueToRValueConversion(Info, Args[0], Args[0]->getType(), + return handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(), RHS, Result); } @@ -2291,7 +2908,8 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, } } - return Success; + return Success && + EvaluateStmt(Result, Info, Definition->getBody()) != ESR_Failed; } //===----------------------------------------------------------------------===// @@ -2397,6 +3015,8 @@ public: { return StmtVisitorTy::Visit(E->getReplacement()); } RetTy VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) { return StmtVisitorTy::Visit(E->getExpr()); } + RetTy VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) + { return StmtVisitorTy::Visit(E->getExpr()); } // We cannot create any objects for which cleanups are required, so there is // nothing to do here; all cleanups must come from unevaluated subexpressions. RetTy VisitExprWithCleanups(const ExprWithCleanups *E) @@ -2426,7 +3046,7 @@ public: if (!HandleMemberPointerAccess(Info, E, Obj)) return false; APValue Result; - if (!HandleLValueToRValueConversion(Info, E, E->getType(), Obj, Result)) + if (!handleLValueToRValueConversion(Info, E, E->getType(), Obj, Result)) return false; return DerivedSuccess(Result, E); } @@ -2606,11 +3226,13 @@ public: assert(BaseTy->castAs<RecordType>()->getDecl()->getCanonicalDecl() == FD->getParent()->getCanonicalDecl() && "record / field mismatch"); + CompleteObject Obj(&Val, BaseTy); SubobjectDesignator Designator(BaseTy); Designator.addDeclUnchecked(FD); - return ExtractSubobject(Info, E, Val, BaseTy, Designator, E->getType()) && - DerivedSuccess(Val, E); + APValue Result; + return extractSubobject(Info, E, Obj, Designator, Result) && + DerivedSuccess(Result, E); } RetTy VisitCastExpr(const CastExpr *E) { @@ -2630,7 +3252,7 @@ public: return false; APValue RVal; // Note, we use the subexpression's type in order to retain cv-qualifiers. - if (!HandleLValueToRValueConversion(Info, E, E->getSubExpr()->getType(), + if (!handleLValueToRValueConversion(Info, E, E->getSubExpr()->getType(), LVal, RVal)) return false; return DerivedSuccess(RVal, E); @@ -2640,11 +3262,29 @@ public: return Error(E); } + RetTy VisitUnaryPostInc(const UnaryOperator *UO) { + return VisitUnaryPostIncDec(UO); + } + RetTy VisitUnaryPostDec(const UnaryOperator *UO) { + return VisitUnaryPostIncDec(UO); + } + RetTy VisitUnaryPostIncDec(const UnaryOperator *UO) { + if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure()) + return Error(UO); + + LValue LVal; + if (!EvaluateLValue(UO->getSubExpr(), LVal, Info)) + return false; + APValue RVal; + if (!handleIncDec(this->Info, UO, LVal, UO->getSubExpr()->getType(), + UO->isIncrementOp(), &RVal)) + return false; + return DerivedSuccess(RVal, UO); + } + /// Visit a value which is evaluated, but whose value is ignored. void VisitIgnoredValue(const Expr *E) { - APValue Scratch; - if (!Evaluate(Scratch, Info, E)) - Info.EvalStatus.HasSideEffects = true; + EvaluateIgnoredValue(Info, E); } }; @@ -2709,7 +3349,7 @@ public: if (MD->getType()->isReferenceType()) { APValue RefValue; - if (!HandleLValueToRValueConversion(this->Info, E, MD->getType(), Result, + if (!handleLValueToRValueConversion(this->Info, E, MD->getType(), Result, RefValue)) return false; return Success(RefValue, E); @@ -2792,6 +3432,7 @@ public: LValueExprEvaluatorBaseTy(Info, Result) {} bool VisitVarDecl(const Expr *E, const VarDecl *VD); + bool VisitUnaryPreIncDec(const UnaryOperator *UO); bool VisitDeclRefExpr(const DeclRefExpr *E); bool VisitPredefinedExpr(const PredefinedExpr *E) { return Success(E); } @@ -2806,6 +3447,14 @@ public: bool VisitUnaryDeref(const UnaryOperator *E); bool VisitUnaryReal(const UnaryOperator *E); bool VisitUnaryImag(const UnaryOperator *E); + bool VisitUnaryPreInc(const UnaryOperator *UO) { + return VisitUnaryPreIncDec(UO); + } + bool VisitUnaryPreDec(const UnaryOperator *UO) { + return VisitUnaryPreIncDec(UO); + } + bool VisitBinAssign(const BinaryOperator *BO); + bool VisitCompoundAssignOperator(const CompoundAssignOperator *CAO); bool VisitCastExpr(const CastExpr *E) { switch (E->getCastKind()) { @@ -2829,14 +3478,12 @@ public: } // end anonymous namespace /// Evaluate an expression as an lvalue. This can be legitimately called on -/// expressions which are not glvalues, in a few cases: -/// * function designators in C, -/// * "extern void" objects, -/// * temporaries, if building with -Wno-address-of-temporary. -static bool EvaluateLValue(const Expr* E, LValue& Result, EvalInfo &Info) { - assert((E->isGLValue() || E->getType()->isFunctionType() || - E->getType()->isVoidType() || isa<CXXTemporaryObjectExpr>(E)) && - "can't evaluate expression as an lvalue"); +/// expressions which are not glvalues, in two cases: +/// * function designators in C, and +/// * "extern void" objects +static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info) { + assert(E->isGLValue() || E->getType()->isFunctionType() || + E->getType()->isVoidType()); return LValueExprEvaluator(Info, Result).Visit(E); } @@ -2849,41 +3496,32 @@ bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { } bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { + CallStackFrame *Frame = 0; + if (VD->hasLocalStorage() && Info.CurrentCall->Index > 1) + Frame = Info.CurrentCall; + if (!VD->getType()->isReferenceType()) { - if (isa<ParmVarDecl>(VD)) { - Result.set(VD, Info.CurrentCall->Index); + if (Frame) { + Result.set(VD, Frame->Index); return true; } return Success(VD); } - APValue V; - if (!EvaluateVarDeclInit(Info, E, VD, Info.CurrentCall, V)) + APValue *V; + if (!evaluateVarDeclInit(Info, E, VD, Frame, V)) return false; - return Success(V, E); + return Success(*V, E); } bool LValueExprEvaluator::VisitMaterializeTemporaryExpr( const MaterializeTemporaryExpr *E) { - if (E->GetTemporaryExpr()->isRValue()) { - if (E->getType()->isRecordType()) - return EvaluateTemporary(E->GetTemporaryExpr(), Result, Info); + if (E->getType()->isRecordType()) + return EvaluateTemporary(E->GetTemporaryExpr(), Result, Info); - Result.set(E, Info.CurrentCall->Index); - return EvaluateInPlace(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, E->getType(), Result, - Info.CurrentCall->Temporaries[E])) - return false; Result.set(E, Info.CurrentCall->Index); - return true; + return EvaluateInPlace(Info.CurrentCall->Temporaries[E], Info, + Result, E->GetTemporaryExpr()); } bool @@ -2906,7 +3544,7 @@ bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) { bool LValueExprEvaluator::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { return Success(E); -} +} bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) { // Handle static data members. @@ -2967,6 +3605,64 @@ bool LValueExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { return true; } +bool LValueExprEvaluator::VisitUnaryPreIncDec(const UnaryOperator *UO) { + if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure()) + return Error(UO); + + if (!this->Visit(UO->getSubExpr())) + return false; + + return handleIncDec( + this->Info, UO, Result, UO->getSubExpr()->getType(), + UO->isIncrementOp(), 0); +} + +bool LValueExprEvaluator::VisitCompoundAssignOperator( + const CompoundAssignOperator *CAO) { + if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure()) + return Error(CAO); + + APValue RHS; + + // The overall lvalue result is the result of evaluating the LHS. + if (!this->Visit(CAO->getLHS())) { + if (Info.keepEvaluatingAfterFailure()) + Evaluate(RHS, this->Info, CAO->getRHS()); + return false; + } + + if (!Evaluate(RHS, this->Info, CAO->getRHS())) + return false; + + // FIXME: + //return handleCompoundAssignment( + // this->Info, CAO, + // Result, CAO->getLHS()->getType(), CAO->getComputationLHSType(), + // RHS, CAO->getRHS()->getType(), + // CAO->getOpForCompoundAssignment(CAO->getOpcode()), + // CAO->getComputationResultType()); + return Error(CAO); +} + +bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) { + if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure()) + return Error(E); + + APValue NewVal; + + if (!this->Visit(E->getLHS())) { + if (Info.keepEvaluatingAfterFailure()) + Evaluate(NewVal, this->Info, E->getRHS()); + return false; + } + + if (!Evaluate(NewVal, this->Info, E->getRHS())) + return false; + + return handleAssignment(this->Info, E, Result, E->getLHS()->getType(), + NewVal); +} + //===----------------------------------------------------------------------===// // Pointer Evaluation //===----------------------------------------------------------------------===// @@ -3411,12 +4107,20 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // If the initializer list for a union does not contain any elements, the // first element of the union is value-initialized. + // FIXME: The element should be initialized from an initializer list. + // Is this difference ever observable for initializer lists which + // we don't build? ImplicitValueInitExpr VIE(Field->getType()); const Expr *InitExpr = E->getNumInits() ? E->getInit(0) : &VIE; LValue Subobject = This; if (!HandleLValueMember(Info, InitExpr, Subobject, Field, &Layout)) return false; + + // Temporarily override This, in case there's a CXXDefaultInitExpr in here. + ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This, + isa<CXXDefaultInitExpr>(InitExpr)); + return EvaluateInPlace(Result.getUnionValue(), Info, Subobject, InitExpr); } @@ -3446,10 +4150,14 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // Perform an implicit value-initialization for members beyond the end of // the initializer list. ImplicitValueInitExpr VIE(HaveInit ? Info.Ctx.IntTy : Field->getType()); + const Expr *Init = HaveInit ? E->getInit(ElementNo++) : &VIE; - if (!EvaluateInPlace( - Result.getStructField(Field->getFieldIndex()), - Info, Subobject, HaveInit ? E->getInit(ElementNo++) : &VIE)) { + // Temporarily override This, in case there's a CXXDefaultInitExpr in here. + ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This, + isa<CXXDefaultInitExpr>(Init)); + + if (!EvaluateInPlace(Result.getStructField(Field->getFieldIndex()), Info, + Subobject, Init)) { if (!Info.keepEvaluatingAfterFailure()) return false; Success = false; @@ -3777,6 +4485,9 @@ namespace { bool VisitInitListExpr(const InitListExpr *E); bool VisitCXXConstructExpr(const CXXConstructExpr *E); + bool VisitCXXConstructExpr(const CXXConstructExpr *E, + const LValue &Subobject, + APValue *Value, QualType Type); }; } // end anonymous namespace @@ -3810,8 +4521,16 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { if (Result.isArray() && Result.hasArrayFiller()) Filler = Result.getArrayFiller(); - Result = APValue(APValue::UninitArray(), E->getNumInits(), - CAT->getSize().getZExtValue()); + unsigned NumEltsToInit = E->getNumInits(); + unsigned NumElts = CAT->getSize().getZExtValue(); + const Expr *FillerExpr = E->hasArrayFiller() ? E->getArrayFiller() : 0; + + // If the initializer might depend on the array index, run it for each + // array element. For now, just whitelist non-class value-initialization. + if (NumEltsToInit != NumElts && !isa<ImplicitValueInitExpr>(FillerExpr)) + NumEltsToInit = NumElts; + + Result = APValue(APValue::UninitArray(), NumEltsToInit, NumElts); // If the array was previously zero-initialized, preserve the // zero-initialized values. @@ -3824,12 +4543,12 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { LValue Subobject = This; Subobject.addArray(Info, E, CAT); - unsigned Index = 0; - for (InitListExpr::const_iterator I = E->begin(), End = E->end(); - I != End; ++I, ++Index) { + for (unsigned Index = 0; Index != NumEltsToInit; ++Index) { + const Expr *Init = + Index < E->getNumInits() ? E->getInit(Index) : FillerExpr; if (!EvaluateInPlace(Result.getArrayInitializedElt(Index), - Info, Subobject, cast<Expr>(*I)) || - !HandleLValueArrayAdjustment(Info, cast<Expr>(*I), Subobject, + Info, Subobject, Init) || + !HandleLValueArrayAdjustment(Info, Init, Subobject, CAT->getElementType(), 1)) { if (!Info.keepEvaluatingAfterFailure()) return false; @@ -3837,39 +4556,54 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { } } - if (!Result.hasArrayFiller()) return Success; - assert(E->hasArrayFiller() && "no array filler for incomplete init list"); - // 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] = {}; - return EvaluateInPlace(Result.getArrayFiller(), Info, - Subobject, E->getArrayFiller()) && Success; + if (!Result.hasArrayFiller()) + return Success; + + // If we get here, we have a trivial filler, which we can just evaluate + // once and splat over the rest of the array elements. + assert(FillerExpr && "no array filler for incomplete init list"); + return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, + FillerExpr) && Success; } bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { - // 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; + return VisitCXXConstructExpr(E, This, &Result, E->getType()); +} - APValue *Value = &Result; - bool HadZeroInit = true; - QualType ElemTy = E->getType(); - while (const ConstantArrayType *CAT = - Info.Ctx.getAsConstantArrayType(ElemTy)) { - Subobject.addArray(Info, E, CAT); - HadZeroInit &= !Value->isUninit(); - if (!HadZeroInit) - *Value = APValue(APValue::UninitArray(), 0, CAT->getSize().getZExtValue()); - if (!Value->hasArrayFiller()) - return true; - Value = &Value->getArrayFiller(); - ElemTy = CAT->getElementType(); +bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, + const LValue &Subobject, + APValue *Value, + QualType Type) { + bool HadZeroInit = !Value->isUninit(); + + if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(Type)) { + unsigned N = CAT->getSize().getZExtValue(); + + // Preserve the array filler if we had prior zero-initialization. + APValue Filler = + HadZeroInit && Value->hasArrayFiller() ? Value->getArrayFiller() + : APValue(); + + *Value = APValue(APValue::UninitArray(), N, N); + + if (HadZeroInit) + for (unsigned I = 0; I != N; ++I) + Value->getArrayInitializedElt(I) = Filler; + + // Initialize the elements. + LValue ArrayElt = Subobject; + ArrayElt.addArray(Info, E, CAT); + for (unsigned I = 0; I != N; ++I) + if (!VisitCXXConstructExpr(E, ArrayElt, &Value->getArrayInitializedElt(I), + CAT->getElementType()) || + !HandleLValueArrayAdjustment(Info, E, ArrayElt, + CAT->getElementType(), 1)) + return false; + + return true; } - if (!ElemTy->isRecordType()) + if (!Type->isRecordType()) return Error(E); const CXXConstructorDecl *FD = E->getConstructor(); @@ -3880,7 +4614,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { return true; if (ZeroInit) { - ImplicitValueInitExpr VIE(ElemTy); + ImplicitValueInitExpr VIE(Type); return EvaluateInPlace(*Value, Info, Subobject, &VIE); } @@ -3901,7 +4635,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { return false; if (ZeroInit && !HadZeroInit) { - ImplicitValueInitExpr VIE(ElemTy); + ImplicitValueInitExpr VIE(Type); if (!EvaluateInPlace(*Value, Info, Subobject, &VIE)) return false; } @@ -5182,6 +5916,10 @@ CharUnits IntExprEvaluator::GetAlignOfType(QualType T) { CharUnits IntExprEvaluator::GetAlignOfExpr(const Expr *E) { E = E->IgnoreParens(); + // The kinds of expressions that we have special-case logic here for + // should be kept up to date with the special checks for those + // expressions in Sema. + // alignof decl is always accepted, even if it doesn't make sense: we default // to 1 in those cases. if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) @@ -6267,7 +7005,7 @@ static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) { if (E->isGLValue()) { LValue LV; LV.setFrom(Info.Ctx, Result); - if (!HandleLValueToRValueConversion(Info, E, E->getType(), LV, Result)) + if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result)) return false; } @@ -6501,6 +7239,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::CXXDynamicCastExprClass: case Expr::CXXTypeidExprClass: case Expr::CXXUuidofExprClass: + case Expr::MSPropertyRefExprClass: case Expr::CXXNullPtrLiteralExprClass: case Expr::UserDefinedLiteralClass: case Expr::CXXThisExprClass: @@ -6819,6 +7558,8 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { } case Expr::CXXDefaultArgExprClass: return CheckICE(cast<CXXDefaultArgExpr>(E)->getExpr(), Ctx); + case Expr::CXXDefaultInitExprClass: + return CheckICE(cast<CXXDefaultInitExpr>(E)->getExpr(), Ctx); case Expr::ChooseExprClass: { return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(Ctx), Ctx); } |