forked from OSchip/llvm-project
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. llvm-svn: 142159
This commit is contained in:
parent
053a7358d6
commit
725810a2bb
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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}}
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue