diff options
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r-- | lib/AST/ExprConstant.cpp | 112 |
1 files changed, 99 insertions, 13 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index c02df9a70b..2a7e8a7d3b 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -290,7 +290,7 @@ namespace { // 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; @@ -913,6 +913,14 @@ 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. +static void EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) { + APValue Scratch; + if (!Evaluate(Scratch, Info, E)) + Info.EvalStatus.HasSideEffects = true; +} + /// Should this call expression be treated as a string literal? static bool IsStringLiteralCall(const CallExpr *E) { unsigned Builtin = E->isBuiltinCall(); @@ -1046,7 +1054,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. @@ -1461,6 +1469,15 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E, return true; } + // If this is a local variable, dig out its value. + if (VD->hasLocalStorage() && Frame && Frame->Index > 1) { + 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()) { @@ -1803,7 +1820,9 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, return false; } - 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 (LVal.CallIndex <= 1 || !VD->hasLocalStorage()) { if (VD->isConstexpr()) { // OK, we can read this variable. } else if (VT->isIntegralOrEnumerationType()) { @@ -1911,7 +1930,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; @@ -2060,20 +2079,61 @@ enum EvalStmtResult { }; } +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 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)) { + EvaluateIgnoredValue(Info, E); + // Don't bother evaluating beyond an expression-statement which couldn't + // be evaluated. + if (Info.EvalStatus.HasSideEffects && !Info.keepEvaluatingAfterFailure()) + 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; } @@ -2088,6 +2148,28 @@ 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 (VarDecl *CondDecl = IS->getConditionVariable()) { + if (!EvaluateDecl(Info, CondDecl)) + return ESR_Failed; + if (!HandleConversionToBool(Info.CurrentCall->Temporaries[CondDecl], + Cond)) + return ESR_Failed; + } else if (!EvaluateAsBooleanCondition(IS->getCond(), Cond, Info)) + 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; + } } } @@ -2181,7 +2263,10 @@ 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) + Info.Diag(Callee->getLocEnd(), diag::note_constexpr_no_return); + return ESR == ESR_Returned; } /// Evaluate a constructor call. @@ -2207,7 +2292,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 @@ -2307,7 +2394,8 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, } } - return Success; + return Success && + EvaluateStmt(Result, Info, Definition->getBody()) != ESR_Failed; } //===----------------------------------------------------------------------===// @@ -2660,9 +2748,7 @@ public: /// 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); } }; @@ -2868,7 +2954,7 @@ bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { if (!VD->getType()->isReferenceType()) { - if (isa<ParmVarDecl>(VD)) { + if (VD->hasLocalStorage() && Info.CurrentCall->Index > 1) { Result.set(VD, Info.CurrentCall->Index); return true; } |