From 1e12c59e8f9bb76c23628c4e0d0a1dfced0b1fa0 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sun, 16 Oct 2011 21:26:27 +0000 Subject: [PATCH] Split apart the state accumulated during constant expression evaluation and the end result. Use this split to propagate state information and diagnostics through more of constant expression evaluation. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142159 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Expr.h | 22 ++++--- lib/AST/ExprConstant.cpp | 99 +++++++++++++++------------- test/SemaCXX/constant-expression.cpp | 10 +++ 3 files changed, 76 insertions(+), 55 deletions(-) diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 1242f4e6c7..7c72b92e18 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -412,11 +412,8 @@ public: /// initializer, which can be emitted at compile-time. bool isConstantInitializer(ASTContext &Ctx, bool ForRef) const; - /// EvalResult is a struct with detailed info about an evaluated expression. - struct EvalResult { - /// Val - This is the value the expression can be folded to. - APValue Val; - + /// EvalStatus is a struct with detailed info about an evaluation in progress. + struct EvalStatus { /// HasSideEffects - Whether the evaluated expression has side effects. /// For example, (f() && 0) can be folded, but it still has side effects. bool HasSideEffects; @@ -433,11 +430,8 @@ public: const Expr *DiagExpr; SourceLocation DiagLoc; - EvalResult() : HasSideEffects(false), Diag(0), DiagExpr(0) {} + EvalStatus() : HasSideEffects(false), Diag(0), DiagExpr(0) {} - // isGlobalLValue - Return true if the evaluated lvalue expression - // is global. - bool isGlobalLValue() const; // hasSideEffects - Return true if the evaluated expression has // side effects. bool hasSideEffects() const { @@ -445,6 +439,16 @@ public: } }; + /// EvalResult is a struct with detailed info about an evaluated expression. + struct EvalResult : EvalStatus { + /// Val - This is the value the expression can be folded to. + APValue Val; + + // isGlobalLValue - Return true if the evaluated lvalue expression + // is global. + bool isGlobalLValue() const; + }; + /// Evaluate - Return true if this is a constant which we can fold using /// any crazy technique (that has nothing to do with language standards) that /// we want to. If this function returns true, it returns the folded constant diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index df75bc8a73..3c21dc4472 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -46,8 +46,8 @@ namespace { struct EvalInfo { const ASTContext &Ctx; - /// EvalResult - Contains information about the evaluation. - Expr::EvalResult &EvalResult; + /// EvalStatus - Contains information about the evaluation. + Expr::EvalStatus &EvalStatus; typedef llvm::DenseMap MapTy; MapTy OpaqueValues; @@ -57,8 +57,8 @@ namespace { return &i->second; } - EvalInfo(const ASTContext &ctx, Expr::EvalResult &evalresult) - : Ctx(ctx), EvalResult(evalresult) {} + EvalInfo(const ASTContext &C, Expr::EvalStatus &S) + : Ctx(C), EvalStatus(S) {} const LangOptions &getLangOpts() { return Ctx.getLangOptions(); } }; @@ -121,7 +121,7 @@ namespace { }; } -static bool Evaluate(EvalInfo &info, const Expr *E); +static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E); static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info); static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info); static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info); @@ -264,10 +264,10 @@ static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType, namespace { class HasSideEffect : public ConstStmtVisitor { - EvalInfo &Info; + const ASTContext &Ctx; public: - HasSideEffect(EvalInfo &info) : Info(info) {} + HasSideEffect(const ASTContext &C) : Ctx(C) {} // Unhandled nodes conservatively default to having side effects. bool VisitStmt(const Stmt *S) { @@ -279,17 +279,17 @@ public: return Visit(E->getResultExpr()); } bool VisitDeclRefExpr(const DeclRefExpr *E) { - if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified()) + if (Ctx.getCanonicalType(E->getType()).isVolatileQualified()) return true; return false; } bool VisitObjCIvarRefExpr(const ObjCIvarRefExpr *E) { - if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified()) + if (Ctx.getCanonicalType(E->getType()).isVolatileQualified()) return true; return false; } bool VisitBlockDeclRefExpr (const BlockDeclRefExpr *E) { - if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified()) + if (Ctx.getCanonicalType(E->getType()).isVolatileQualified()) return true; return false; } @@ -310,7 +310,7 @@ public: bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { return Visit(E->getLHS()) || Visit(E->getRHS()); } bool VisitChooseExpr(const ChooseExpr *E) - { return Visit(E->getChosenSubExpr(Info.Ctx)); } + { 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; } @@ -321,7 +321,7 @@ public: bool VisitUnaryPreDec(const UnaryOperator *E) { return true; } bool VisitUnaryPostDec(const UnaryOperator *E) { return true; } bool VisitUnaryDeref(const UnaryOperator *E) { - if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified()) + if (Ctx.getCanonicalType(E->getType()).isVolatileQualified()) return true; return Visit(E->getSubExpr()); } @@ -349,16 +349,17 @@ public: : info(info), opaqueValue(opaqueValue) { // If evaluation fails, fail immediately. - if (!Evaluate(info, value)) { + if (!Evaluate(info.OpaqueValues[opaqueValue], info, value)) { this->opaqueValue = 0; return; } - info.OpaqueValues[opaqueValue] = info.EvalResult.Val; } bool hasError() const { return opaqueValue == 0; } ~OpaqueValueEvaluation() { + // FIXME: This will not work for recursive constexpr functions using opaque + // values. Restore the former value. if (opaqueValue) info.OpaqueValues.erase(opaqueValue); } }; @@ -967,8 +968,9 @@ VectorExprEvaluator::GetZeroVector(QualType T) { } APValue VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { - if (!E->getSubExpr()->isEvaluatable(Info.Ctx)) - Info.EvalResult.HasSideEffects = true; + APValue Scratch; + if (!Evaluate(Scratch, Info, E->getSubExpr())) + Info.EvalStatus.HasSideEffects = true; return GetZeroVector(E->getType()); } @@ -1020,10 +1022,10 @@ public: bool Error(SourceLocation L, diag::kind D, const Expr *E) { // Take the first error. - if (Info.EvalResult.Diag == 0) { - Info.EvalResult.DiagLoc = L; - Info.EvalResult.Diag = D; - Info.EvalResult.DiagExpr = E; + if (Info.EvalStatus.Diag == 0) { + Info.EvalStatus.DiagLoc = L; + Info.EvalStatus.Diag = D; + Info.EvalStatus.DiagExpr = E; } return false; } @@ -1058,7 +1060,7 @@ public: bool VisitMemberExpr(const MemberExpr *E) { if (CheckReferencedDecl(E, E->getMemberDecl())) { // Conservatively assume a MemberExpr will have side-effects - Info.EvalResult.HasSideEffects = true; + Info.EvalStatus.HasSideEffects = true; return true; } @@ -1172,6 +1174,8 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) { VD->setEvaluatingValue(); Expr::EvalResult EResult; + // FIXME: Produce a diagnostic if the initializer isn't a constant + // expression. if (Init->Evaluate(EResult, Info.Ctx) && !EResult.HasSideEffects && EResult.Val.isInt()) { // Cache the evaluated value in the variable declaration. @@ -1350,8 +1354,9 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // If we can't evaluate the LHS, it might have side effects; // conservatively mark it. - if (!E->getLHS()->isEvaluatable(Info.Ctx)) - Info.EvalResult.HasSideEffects = true; + APValue Scratch; + if (!Evaluate(Scratch, Info, E->getLHS())) + Info.EvalStatus.HasSideEffects = true; return true; } @@ -1381,7 +1386,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { !rhsResult == (E->getOpcode() == BO_LAnd)) { // Since we weren't able to evaluate the left hand side, it // must have had side effects. - Info.EvalResult.HasSideEffects = true; + Info.EvalStatus.HasSideEffects = true; return Success(rhsResult, E); } @@ -1943,8 +1948,9 @@ bool IntExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { return Success(LV.getComplexIntImag(), E); } - if (!E->getSubExpr()->isEvaluatable(Info.Ctx)) - Info.EvalResult.HasSideEffects = true; + APValue Scratch; + if (!Evaluate(Scratch, Info, E->getSubExpr())) + Info.EvalStatus.HasSideEffects = true; return Success(0, E); } @@ -2145,8 +2151,9 @@ bool FloatExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { return true; } - if (!E->getSubExpr()->isEvaluatable(Info.Ctx)) - Info.EvalResult.HasSideEffects = true; + APValue Scratch; + if (!Evaluate(Scratch, Info, E->getSubExpr())) + Info.EvalStatus.HasSideEffects = true; const llvm::fltSemantics &Sem = Info.Ctx.getFloatTypeSemantics(E->getType()); Result = llvm::APFloat::getZero(Sem); return true; @@ -2176,8 +2183,9 @@ bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // If we can't evaluate the LHS, it might have side effects; // conservatively mark it. - if (!E->getLHS()->isEvaluatable(Info.Ctx)) - Info.EvalResult.HasSideEffects = true; + APValue Scratch; + if (!Evaluate(Scratch, Info, E->getLHS())) + Info.EvalStatus.HasSideEffects = true; return true; } @@ -2460,8 +2468,9 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // If we can't evaluate the LHS, it might have side effects; // conservatively mark it. - if (!E->getLHS()->isEvaluatable(Info.Ctx)) - Info.EvalResult.HasSideEffects = true; + APValue Scratch; + if (!Evaluate(Scratch, Info, E->getLHS())) + Info.EvalStatus.HasSideEffects = true; return true; } @@ -2616,15 +2625,15 @@ bool ComplexExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { // Top level Expr::Evaluate method. //===----------------------------------------------------------------------===// -static bool Evaluate(EvalInfo &Info, const Expr *E) { +static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) { if (E->getType()->isVectorType()) { - if (!EvaluateVector(E, Info.EvalResult.Val, Info)) + if (!EvaluateVector(E, Result, Info)) return false; } else if (E->getType()->isIntegralOrEnumerationType()) { - if (!IntExprEvaluator(Info, Info.EvalResult.Val).Visit(E)) + if (!IntExprEvaluator(Info, Result).Visit(E)) return false; - if (Info.EvalResult.Val.isLValue() && - !IsGlobalLValue(Info.EvalResult.Val.getLValueBase())) + if (Result.isLValue() && + !IsGlobalLValue(Result.getLValueBase())) return false; } else if (E->getType()->hasPointerRepresentation()) { LValue LV; @@ -2632,18 +2641,18 @@ static bool Evaluate(EvalInfo &Info, const Expr *E) { return false; if (!IsGlobalLValue(LV.Base)) return false; - LV.moveInto(Info.EvalResult.Val); + LV.moveInto(Result); } else if (E->getType()->isRealFloatingType()) { llvm::APFloat F(0.0); if (!EvaluateFloat(E, F, Info)) return false; - Info.EvalResult.Val = APValue(F); + Result = APValue(F); } else if (E->getType()->isAnyComplexType()) { ComplexValue C; if (!EvaluateComplex(E, C, Info)) return false; - C.moveInto(Info.EvalResult.Val); + C.moveInto(Result); } else return false; @@ -2656,19 +2665,19 @@ static bool Evaluate(EvalInfo &Info, const Expr *E) { /// in Result. bool Expr::Evaluate(EvalResult &Result, const ASTContext &Ctx) const { EvalInfo Info(Ctx, Result); - return ::Evaluate(Info, this); + return ::Evaluate(Result.Val, Info, this); } bool Expr::EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx) const { - EvalResult Scratch; + EvalStatus Scratch; EvalInfo Info(Ctx, Scratch); return HandleConversionToBool(this, Result, Info); } bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx) const { - EvalResult Scratch; + EvalStatus Scratch; EvalInfo Info(Ctx, Scratch); return EvaluateInteger(this, Result, Info) && !Scratch.HasSideEffects; @@ -2707,9 +2716,7 @@ bool Expr::isEvaluatable(const ASTContext &Ctx) const { } bool Expr::HasSideEffects(const ASTContext &Ctx) const { - Expr::EvalResult Result; - EvalInfo Info(Ctx, Result); - return HasSideEffect(Info).Visit(this); + return HasSideEffect(Ctx).Visit(this); } APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx) const { diff --git a/test/SemaCXX/constant-expression.cpp b/test/SemaCXX/constant-expression.cpp index 1341036d83..e3f45c5ec0 100644 --- a/test/SemaCXX/constant-expression.cpp +++ b/test/SemaCXX/constant-expression.cpp @@ -85,3 +85,13 @@ enum { a = sizeof(int) == 8, b = a? 8 : 4 }; + +void diags(int n) { + switch (n) { + case (1/0, 1): // expected-error {{not an integer constant expression}} expected-note {{division by zero}} + case (int)(1/0, 2.0): // expected-error {{not an integer constant expression}} expected-note {{division by zero}} + case __imag(1/0): // expected-error {{not an integer constant expression}} expected-note {{division by zero}} + case (int)__imag((double)(1/0)): // expected-error {{not an integer constant expression}} expected-note {{division by zero}} + ; + } +} -- 2.40.0