diff options
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r-- | lib/AST/ExprConstant.cpp | 346 |
1 files changed, 149 insertions, 197 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 66a88b0..06c41a2 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -287,7 +287,9 @@ namespace { /// parameters' function scope indices. const APValue *Arguments; - typedef llvm::DenseMap<const Expr*, APValue> MapTy; + // Note that we intentionally use std::map here so that references to + // values are stable. + typedef std::map<const Expr*, APValue> MapTy; typedef MapTy::const_iterator temp_iterator; /// Temporaries - Temporary lvalues materialized within this stack frame. MapTy Temporaries; @@ -361,11 +363,6 @@ namespace { /// NextCallIndex - The next call index to assign. unsigned NextCallIndex; - typedef llvm::DenseMap<const OpaqueValueExpr*, APValue> MapTy; - /// OpaqueValues - Values used as the common expression in a - /// BinaryConditionalOperator. - MapTy OpaqueValues; - /// BottomFrame - The frame in which evaluation started. This must be /// initialized after CurrentCall and CallStackDepth. CallStackFrame BottomFrame; @@ -394,12 +391,6 @@ namespace { EvaluatingDecl(0), EvaluatingDeclValue(0), HasActiveDiagnostic(false), CheckingPotentialConstantExpression(false) {} - const APValue *getOpaqueValue(const OpaqueValueExpr *e) const { - MapTy::const_iterator i = OpaqueValues.find(e); - if (i == OpaqueValues.end()) return 0; - return &i->second; - } - void setEvaluatingDecl(const VarDecl *VD, APValue &Value) { EvaluatingDecl = VD; EvaluatingDeclValue = &Value; @@ -1072,8 +1063,8 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, } for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I) { - if (!CheckConstantExpression(Info, DiagLoc, (*I)->getType(), - Value.getStructField((*I)->getFieldIndex()))) + if (!CheckConstantExpression(Info, DiagLoc, I->getType(), + Value.getStructField(I->getFieldIndex()))) return false; } } @@ -1160,11 +1151,10 @@ static bool EvaluateAsBooleanCondition(const Expr *E, bool &Result, } template<typename T> -static bool HandleOverflow(EvalInfo &Info, const Expr *E, +static void HandleOverflow(EvalInfo &Info, const Expr *E, const T &SrcValue, QualType DestType) { - Info.Diag(E, diag::note_constexpr_overflow) + Info.CCEDiag(E, diag::note_constexpr_overflow) << SrcValue << DestType; - return false; } static bool HandleFloatToIntCast(EvalInfo &Info, const Expr *E, @@ -1178,7 +1168,7 @@ static bool HandleFloatToIntCast(EvalInfo &Info, const Expr *E, bool ignored; if (Value.convertToInteger(Result, llvm::APFloat::rmTowardZero, &ignored) & APFloat::opInvalidOp) - return HandleOverflow(Info, E, Value, DestType); + HandleOverflow(Info, E, Value, DestType); return true; } @@ -1190,7 +1180,7 @@ static bool HandleFloatToFloatCast(EvalInfo &Info, const Expr *E, if (Result.convert(Info.Ctx.getFloatTypeSemantics(DestType), APFloat::rmNearestTiesToEven, &ignored) & APFloat::opOverflow) - return HandleOverflow(Info, E, Value, DestType); + HandleOverflow(Info, E, Value, DestType); return true; } @@ -1213,7 +1203,7 @@ static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E, if (Result.convertFromAPInt(Value, Value.isSigned(), APFloat::rmNearestTiesToEven) & APFloat::opOverflow) - return HandleOverflow(Info, E, Value, DestType); + HandleOverflow(Info, E, Value, DestType); return true; } @@ -1282,6 +1272,7 @@ static bool CastToDerivedClass(EvalInfo &Info, const Expr *E, LValue &Result, // 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) { + if (RD->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); const CXXRecordDecl *Base = getAsBaseClass(D.Entries[I]); if (isVirtualBaseClass(D.Entries[I])) @@ -1294,13 +1285,18 @@ static bool CastToDerivedClass(EvalInfo &Info, const Expr *E, LValue &Result, return true; } -static void HandleLValueDirectBase(EvalInfo &Info, const Expr *E, LValue &Obj, +static bool 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); + if (!RL) { + if (Derived->isInvalidDecl()) return false; + RL = &Info.Ctx.getASTRecordLayout(Derived); + } + Obj.getLValueOffset() += RL->getBaseClassOffset(Base); Obj.addDecl(Info, E, Base, /*Virtual*/ false); + return true; } static bool HandleLValueBase(EvalInfo &Info, const Expr *E, LValue &Obj, @@ -1308,10 +1304,8 @@ static bool HandleLValueBase(EvalInfo &Info, const Expr *E, LValue &Obj, const CXXBaseSpecifier *Base) { const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl(); - if (!Base->isVirtual()) { - HandleLValueDirectBase(Info, E, Obj, DerivedDecl, BaseDecl); - return true; - } + if (!Base->isVirtual()) + return HandleLValueDirectBase(Info, E, Obj, DerivedDecl, BaseDecl); SubobjectDesignator &D = Obj.Designator; if (D.Invalid) @@ -1323,6 +1317,7 @@ static bool HandleLValueBase(EvalInfo &Info, const Expr *E, LValue &Obj, return false; // Find the virtual base class. + if (DerivedDecl->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl); Obj.getLValueOffset() += Layout.getVBaseClassOffset(BaseDecl); Obj.addDecl(Info, E, BaseDecl, /*Virtual*/ true); @@ -1331,24 +1326,29 @@ static bool HandleLValueBase(EvalInfo &Info, const Expr *E, LValue &Obj, /// 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, const Expr *E, LValue &LVal, +static bool HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal, const FieldDecl *FD, const ASTRecordLayout *RL = 0) { - if (!RL) + if (!RL) { + if (FD->getParent()->isInvalidDecl()) return false; RL = &Info.Ctx.getASTRecordLayout(FD->getParent()); + } unsigned I = FD->getFieldIndex(); LVal.Offset += Info.Ctx.toCharUnitsFromBits(RL->getFieldOffset(I)); LVal.addDecl(Info, E, FD); + return true; } /// Update LVal to refer to the given indirect field. -static void HandleLValueIndirectMember(EvalInfo &Info, const Expr *E, +static bool HandleLValueIndirectMember(EvalInfo &Info, const Expr *E, LValue &LVal, const IndirectFieldDecl *IFD) { for (IndirectFieldDecl::chain_iterator C = IFD->chain_begin(), CE = IFD->chain_end(); C != CE; ++C) - HandleLValueMember(Info, E, LVal, cast<FieldDecl>(*C)); + if (!HandleLValueMember(Info, E, LVal, cast<FieldDecl>(*C))) + return false; + return true; } /// Get the size of the given type in char units. @@ -1952,22 +1952,27 @@ 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, BO, LV, RD, Base); + if (!HandleLValueDirectBase(Info, BO, LV, RD, Base)) + return 0; RD = Base; } // Finally cast to the class containing the member. - HandleLValueDirectBase(Info, BO, LV, RD, MemPtr.getContainingRecord()); + if (!HandleLValueDirectBase(Info, BO, LV, RD, MemPtr.getContainingRecord())) + return 0; } // Add the member. Note that we cannot build bound member functions here. if (IncludeMember) { - if (const FieldDecl *FD = dyn_cast<FieldDecl>(MemPtr.getDecl())) - HandleLValueMember(Info, BO, LV, FD); - else if (const IndirectFieldDecl *IFD = - dyn_cast<IndirectFieldDecl>(MemPtr.getDecl())) - HandleLValueIndirectMember(Info, BO, LV, IFD); - else + if (const FieldDecl *FD = dyn_cast<FieldDecl>(MemPtr.getDecl())) { + if (!HandleLValueMember(Info, BO, LV, FD)) + return 0; + } else if (const IndirectFieldDecl *IFD = + dyn_cast<IndirectFieldDecl>(MemPtr.getDecl())) { + if (!HandleLValueIndirectMember(Info, BO, LV, IFD)) + return 0; + } else { llvm_unreachable("can't construct reference to bound member function"); + } } return MemPtr.getDecl(); @@ -2189,6 +2194,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, Result = APValue(APValue::UninitStruct(), RD->getNumBases(), std::distance(RD->field_begin(), RD->field_end())); + if (RD->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); bool Success = true; @@ -2212,11 +2218,13 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, "base class initializers not in expected order"); ++BaseIt; #endif - HandleLValueDirectBase(Info, (*I)->getInit(), Subobject, RD, - BaseType->getAsCXXRecordDecl(), &Layout); + if (!HandleLValueDirectBase(Info, (*I)->getInit(), Subobject, RD, + BaseType->getAsCXXRecordDecl(), &Layout)) + return false; Value = &Result.getStructBase(BasesSeen++); } else if (FieldDecl *FD = (*I)->getMember()) { - HandleLValueMember(Info, (*I)->getInit(), Subobject, FD, &Layout); + if (!HandleLValueMember(Info, (*I)->getInit(), Subobject, FD, &Layout)) + return false; if (RD->isUnion()) { Result = APValue(FD); Value = &Result.getUnionValue(); @@ -2244,7 +2252,8 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, *Value = APValue(APValue::UninitStruct(), CD->getNumBases(), std::distance(CD->field_begin(), CD->field_end())); } - HandleLValueMember(Info, (*I)->getInit(), Subobject, FD); + if (!HandleLValueMember(Info, (*I)->getInit(), Subobject, FD)) + return false; if (CD->isUnion()) Value = &Value->getUnionValue(); else @@ -2268,107 +2277,6 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, return Success; } -namespace { -class HasSideEffect - : public ConstStmtVisitor<HasSideEffect, bool> { - const ASTContext &Ctx; -public: - - HasSideEffect(const ASTContext &C) : Ctx(C) {} - - // Unhandled nodes conservatively default to having side effects. - bool VisitStmt(const Stmt *S) { - return true; - } - - bool VisitParenExpr(const ParenExpr *E) { return Visit(E->getSubExpr()); } - bool VisitGenericSelectionExpr(const GenericSelectionExpr *E) { - return Visit(E->getResultExpr()); - } - bool VisitDeclRefExpr(const DeclRefExpr *E) { - if (Ctx.getCanonicalType(E->getType()).isVolatileQualified()) - return true; - return false; - } - bool VisitObjCIvarRefExpr(const ObjCIvarRefExpr *E) { - if (Ctx.getCanonicalType(E->getType()).isVolatileQualified()) - return true; - return false; - } - - // We don't want to evaluate BlockExprs multiple times, as they generate - // a ton of code. - bool VisitBlockExpr(const BlockExpr *E) { return true; } - bool VisitPredefinedExpr(const PredefinedExpr *E) { return false; } - bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) - { return Visit(E->getInitializer()); } - bool VisitMemberExpr(const MemberExpr *E) { return Visit(E->getBase()); } - bool VisitIntegerLiteral(const IntegerLiteral *E) { return false; } - bool VisitFloatingLiteral(const FloatingLiteral *E) { return false; } - bool VisitStringLiteral(const StringLiteral *E) { return false; } - bool VisitCharacterLiteral(const CharacterLiteral *E) { return false; } - bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E) - { return false; } - bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E) - { return Visit(E->getLHS()) || Visit(E->getRHS()); } - bool VisitChooseExpr(const ChooseExpr *E) - { return Visit(E->getChosenSubExpr(Ctx)); } - bool VisitCastExpr(const CastExpr *E) { return Visit(E->getSubExpr()); } - bool VisitBinAssign(const BinaryOperator *E) { return true; } - bool VisitCompoundAssignOperator(const BinaryOperator *E) { return true; } - bool VisitBinaryOperator(const BinaryOperator *E) - { return Visit(E->getLHS()) || Visit(E->getRHS()); } - bool VisitUnaryPreInc(const UnaryOperator *E) { return true; } - bool VisitUnaryPostInc(const UnaryOperator *E) { return true; } - bool VisitUnaryPreDec(const UnaryOperator *E) { return true; } - bool VisitUnaryPostDec(const UnaryOperator *E) { return true; } - bool VisitUnaryDeref(const UnaryOperator *E) { - if (Ctx.getCanonicalType(E->getType()).isVolatileQualified()) - return true; - return Visit(E->getSubExpr()); - } - bool VisitUnaryOperator(const UnaryOperator *E) { return Visit(E->getSubExpr()); } - - // Has side effects if any element does. - bool VisitInitListExpr(const InitListExpr *E) { - for (unsigned i = 0, e = E->getNumInits(); i != e; ++i) - if (Visit(E->getInit(i))) return true; - if (const Expr *filler = E->getArrayFiller()) - return Visit(filler); - return false; - } - - bool VisitSizeOfPackExpr(const SizeOfPackExpr *) { return false; } -}; - -class OpaqueValueEvaluation { - EvalInfo &info; - OpaqueValueExpr *opaqueValue; - -public: - OpaqueValueEvaluation(EvalInfo &info, OpaqueValueExpr *opaqueValue, - Expr *value) - : info(info), opaqueValue(opaqueValue) { - - // If evaluation fails, fail immediately. - if (!Evaluate(info.OpaqueValues[opaqueValue], info, value)) { - this->opaqueValue = 0; - return; - } - } - - bool hasError() const { return opaqueValue == 0; } - - ~OpaqueValueEvaluation() { - // FIXME: For a recursive constexpr call, an outer stack frame might have - // been using this opaque value too, and will now have to re-evaluate the - // source expression. - if (opaqueValue) info.OpaqueValues.erase(opaqueValue); - } -}; - -} // end anonymous namespace - //===----------------------------------------------------------------------===// // Generic Evaluation //===----------------------------------------------------------------------===// @@ -2509,9 +2417,10 @@ public: } RetTy VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) { - // Cache the value of the common expression. - OpaqueValueEvaluation opaque(Info, E->getOpaqueValue(), E->getCommon()); - if (opaque.hasError()) + // Evaluate and cache the common expression. We treat it as a temporary, + // even though it's not quite the same thing. + if (!Evaluate(Info.CurrentCall->Temporaries[E->getOpaqueValue()], + Info, E->getCommon())) return false; return HandleConditionalOperator(E); @@ -2545,8 +2454,8 @@ public: } RetTy VisitOpaqueValueExpr(const OpaqueValueExpr *E) { - const APValue *Value = Info.getOpaqueValue(E); - if (!Value) { + APValue &Value = Info.CurrentCall->Temporaries[E]; + if (Value.isUninit()) { const Expr *Source = E->getSourceExpr(); if (!Source) return Error(E); @@ -2556,7 +2465,7 @@ public: } return StmtVisitorTy::Visit(Source); } - return DerivedSuccess(*Value, E); + return DerivedSuccess(Value, E); } RetTy VisitCallExpr(const CallExpr *E) { @@ -2773,9 +2682,11 @@ public: assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() == FD->getParent()->getCanonicalDecl() && "record / field mismatch"); (void)BaseTy; - HandleLValueMember(this->Info, E, Result, FD); + if (!HandleLValueMember(this->Info, E, Result, FD)) + return false; } else if (const IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(MD)) { - HandleLValueIndirectMember(this->Info, E, Result, IFD); + if (!HandleLValueIndirectMember(this->Info, E, Result, IFD)) + return false; } else return this->Error(E); @@ -2970,6 +2881,9 @@ bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) { if (E->isTypeOperand()) return Success(E); CXXRecordDecl *RD = E->getExprOperand()->getType()->getAsCXXRecordDecl(); + // FIXME: The standard says "a typeid expression whose operand is of a + // polymorphic class type" is not a constant expression, but it probably + // means "a typeid expression whose operand is potentially evaluated". if (RD && RD->isPolymorphic()) { Info.Diag(E, diag::note_constexpr_typeid_polymorphic) << E->getExprOperand()->getType() @@ -3073,7 +2987,7 @@ public: bool VisitUnaryAddrOf(const UnaryOperator *E); bool VisitObjCStringLiteral(const ObjCStringLiteral *E) { return Success(E); } - bool VisitObjCNumericLiteral(const ObjCNumericLiteral *E) + bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E) { return Success(E); } bool VisitAddrLabelExpr(const AddrLabelExpr *E) { return Success(E); } @@ -3373,6 +3287,7 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E, Result = APValue(APValue::UninitStruct(), CD ? CD->getNumBases() : 0, std::distance(RD->field_begin(), RD->field_end())); + if (RD->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); if (CD) { @@ -3381,7 +3296,8 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E, End = CD->bases_end(); I != End; ++I, ++Index) { const CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl(); LValue Subobject = This; - HandleLValueDirectBase(Info, E, Subobject, CD, Base, &Layout); + if (!HandleLValueDirectBase(Info, E, Subobject, CD, Base, &Layout)) + return false; if (!HandleClassZeroInitialization(Info, E, Base, Subobject, Result.getStructBase(Index))) return false; @@ -3391,15 +3307,16 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E, for (RecordDecl::field_iterator I = RD->field_begin(), End = RD->field_end(); I != End; ++I) { // -- if T is a reference type, no initialization is performed. - if ((*I)->getType()->isReferenceType()) + if (I->getType()->isReferenceType()) continue; LValue Subobject = This; - HandleLValueMember(Info, E, Subobject, *I, &Layout); + if (!HandleLValueMember(Info, E, Subobject, *I, &Layout)) + return false; - ImplicitValueInitExpr VIE((*I)->getType()); + ImplicitValueInitExpr VIE(I->getType()); if (!EvaluateInPlace( - Result.getStructField((*I)->getFieldIndex()), Info, Subobject, &VIE)) + Result.getStructField(I->getFieldIndex()), Info, Subobject, &VIE)) return false; } @@ -3408,6 +3325,7 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E, bool RecordExprEvaluator::ZeroInitialization(const Expr *E) { const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl(); + if (RD->isInvalidDecl()) return false; if (RD->isUnion()) { // C++11 [dcl.init]p5: If T is a (possibly cv-qualified) union type, the // object's first non-static named data member is zero-initialized @@ -3418,9 +3336,10 @@ bool RecordExprEvaluator::ZeroInitialization(const Expr *E) { } LValue Subobject = This; - HandleLValueMember(Info, E, Subobject, *I); + if (!HandleLValueMember(Info, E, Subobject, *I)) + return false; Result = APValue(*I); - ImplicitValueInitExpr VIE((*I)->getType()); + ImplicitValueInitExpr VIE(I->getType()); return EvaluateInPlace(Result.getUnionValue(), Info, Subobject, &VIE); } @@ -3470,6 +3389,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { return false; const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl(); + if (RD->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); if (RD->isUnion()) { @@ -3484,7 +3404,8 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { const Expr *InitExpr = E->getNumInits() ? E->getInit(0) : &VIE; LValue Subobject = This; - HandleLValueMember(Info, InitExpr, Subobject, Field, &Layout); + if (!HandleLValueMember(Info, InitExpr, Subobject, Field, &Layout)) + return false; return EvaluateInPlace(Result.getUnionValue(), Info, Subobject, InitExpr); } @@ -3507,15 +3428,16 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // FIXME: Diagnostics here should point to the end of the initializer // list, not the start. - HandleLValueMember(Info, HaveInit ? E->getInit(ElementNo) : E, Subobject, - *Field, &Layout); + if (!HandleLValueMember(Info, HaveInit ? E->getInit(ElementNo) : E, + Subobject, *Field, &Layout)) + return false; // Perform an implicit value-initialization for members beyond the end of // the initializer list. ImplicitValueInitExpr VIE(HaveInit ? Info.Ctx.IntTy : Field->getType()); if (!EvaluateInPlace( - Result.getStructField((*Field)->getFieldIndex()), + Result.getStructField(Field->getFieldIndex()), Info, Subobject, HaveInit ? E->getInit(ElementNo++) : &VIE)) { if (!Info.keepEvaluatingAfterFailure()) return false; @@ -3528,6 +3450,8 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { const CXXConstructorDecl *FD = E->getConstructor(); + if (FD->isInvalidDecl() || FD->getParent()->isInvalidDecl()) return false; + bool ZeroInit = E->requiresZeroInitialization(); if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD, ZeroInit)) { // If we've already performed zero-initialization, we're already done. @@ -3870,8 +3794,24 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { bool Success = true; + assert((!Result.isArray() || Result.getArrayInitializedElts() == 0) && + "zero-initialized array shouldn't have any initialized elts"); + APValue Filler; + if (Result.isArray() && Result.hasArrayFiller()) + Filler = Result.getArrayFiller(); + Result = APValue(APValue::UninitArray(), E->getNumInits(), CAT->getSize().getZExtValue()); + + // If the array was previously zero-initialized, preserve the + // zero-initialized values. + if (!Filler.isUninit()) { + for (unsigned I = 0, E = Result.getArrayInitializedElts(); I != E; ++I) + Result.getArrayInitializedElt(I) = Filler; + if (Result.hasArrayFiller()) + Result.getArrayFiller() = Filler; + } + LValue Subobject = This; Subobject.addArray(Info, E, CAT); unsigned Index = 0; @@ -3898,15 +3838,29 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { } bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { - const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(E->getType()); - if (!CAT) - return Error(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; - bool HadZeroInit = !Result.isUninit(); - if (!HadZeroInit) - Result = APValue(APValue::UninitArray(), 0, CAT->getSize().getZExtValue()); - if (!Result.hasArrayFiller()) - return true; + 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(); + } + + if (!ElemTy->isRecordType()) + return Error(E); const CXXConstructorDecl *FD = E->getConstructor(); @@ -3916,17 +3870,15 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { return true; if (ZeroInit) { - LValue Subobject = This; - Subobject.addArray(Info, E, CAT); - ImplicitValueInitExpr VIE(CAT->getElementType()); - return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, &VIE); + ImplicitValueInitExpr VIE(ElemTy); + return EvaluateInPlace(*Value, Info, Subobject, &VIE); } const CXXRecordDecl *RD = FD->getParent(); if (RD->isUnion()) - Result.getArrayFiller() = APValue((FieldDecl*)0); + *Value = APValue((FieldDecl*)0); else - Result.getArrayFiller() = + *Value = APValue(APValue::UninitStruct(), RD->getNumBases(), std::distance(RD->field_begin(), RD->field_end())); return true; @@ -3938,23 +3890,16 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition)) return false; - // FIXME: The Subobject here isn't necessarily right. This rarely matters, - // but sometimes does: - // struct S { constexpr S() : p(&p) {} void *p; }; - // S s[10]; - LValue Subobject = This; - Subobject.addArray(Info, E, CAT); - if (ZeroInit && !HadZeroInit) { - ImplicitValueInitExpr VIE(CAT->getElementType()); - if (!EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, &VIE)) + ImplicitValueInitExpr VIE(ElemTy); + if (!EvaluateInPlace(*Value, Info, Subobject, &VIE)) return false; } llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs()); return HandleConstructorCall(E->getExprLoc(), Subobject, Args, cast<CXXConstructorDecl>(Definition), - Info, Result.getArrayFiller()); + Info, *Value); } //===----------------------------------------------------------------------===// @@ -4288,10 +4233,16 @@ QualType IntExprEvaluator::GetObjectType(APValue::LValueBase B) { } bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E) { - // TODO: Perhaps we should let LLVM lower this? LValue Base; - if (!EvaluatePointer(E->getArg(0), Base, Info)) - return false; + + { + // The operand of __builtin_object_size is never evaluated for side-effects. + // If there are any, but we can determine the pointed-to object anyway, then + // ignore the side-effects. + SpeculativeEvaluationRAII SpeculativeEval(Info); + if (!EvaluatePointer(E->getArg(0), Base, Info)) + return false; + } // If we can prove the base is null, lower to zero now. if (!Base.getLValueBase()) return Success(0, E); @@ -4323,14 +4274,17 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { if (TryEvaluateBuiltinObjectSize(E)) return true; - // If evaluating the argument has side-effects we can't determine - // the size of the object and lower it to unknown now. + // If evaluating the argument has side-effects, we can't determine the size + // of the object, and so we lower it to unknown now. CodeGen relies on us to + // handle all cases where the expression has side-effects. if (E->getArg(0)->HasSideEffects(Info.Ctx)) { if (E->getArg(1)->EvaluateKnownConstInt(Info.Ctx).getZExtValue() <= 1) return Success(-1ULL, E); return Success(0, E); } + // Expression had no side effects, but we couldn't statically determine the + // size of the referenced object. return Error(E); } @@ -5280,6 +5234,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { if (!RT) return Error(OOE); RecordDecl *RD = RT->getDecl(); + if (RD->isInvalidDecl()) return false; const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); unsigned i = MemberDecl->getFieldIndex(); assert(i < RL.getFieldCount() && "offsetof field in wrong type"); @@ -5301,6 +5256,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { if (!RT) return Error(OOE); RecordDecl *RD = RT->getDecl(); + if (RD->isInvalidDecl()) return false; const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); // Find the base class itself. @@ -6385,10 +6341,6 @@ bool Expr::isEvaluatable(const ASTContext &Ctx) const { return EvaluateAsRValue(Result, Ctx) && !Result.HasSideEffects; } -bool Expr::HasSideEffects(const ASTContext &Ctx) const { - return HasSideEffect(Ctx).Visit(this); -} - APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx) const { EvalResult EvalResult; bool Result = EvaluateAsRValue(EvalResult, Ctx); @@ -6501,7 +6453,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::CXXDependentScopeMemberExprClass: case Expr::UnresolvedMemberExprClass: case Expr::ObjCStringLiteralClass: - case Expr::ObjCNumericLiteralClass: + case Expr::ObjCBoxedExprClass: case Expr::ObjCArrayLiteralClass: case Expr::ObjCDictionaryLiteralClass: case Expr::ObjCEncodeExprClass: |