aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2011-10-16 21:26:27 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2011-10-16 21:26:27 +0000
commit1e12c59e8f9bb76c23628c4e0d0a1dfced0b1fa0 (patch)
tree921669eca776599266b3e7f8e2564564e5cdc25d
parent20cdbeb8f36576f469db195b4140c293c7281718 (diff)
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
-rw-r--r--include/clang/AST/Expr.h22
-rw-r--r--lib/AST/ExprConstant.cpp99
-rw-r--r--test/SemaCXX/constant-expression.cpp10
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<const OpaqueValueExpr*, APValue> 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<HasSideEffect, bool> {
- 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}}
+ ;
+ }
+}