aboutsummaryrefslogtreecommitdiff
path: root/lib/AST/ExprConstant.cpp
diff options
context:
space:
mode:
authorEli Friedman <eli.friedman@gmail.com>2008-11-12 09:44:48 +0000
committerEli Friedman <eli.friedman@gmail.com>2008-11-12 09:44:48 +0000
commit4efaa276bc0ce8f7baf6138ead11915f3e3e58d9 (patch)
tree0ed7f53e97397eeda48dcb5fdfda0605a84fe2c0 /lib/AST/ExprConstant.cpp
parent9802a5173ffd403d9ede2d4b6b6107fa2e220544 (diff)
Some additions to tryEvaluate I've had sitting around for a while.
This pushes it a lot closer to being able to deal with most of the stuff CodeGen's constant expression evaluator knows how to deal with. This also fixes PR3003. The test could possibly use some improvement, but this'll work for now. Test 6 is inspired by PR3003; the other tests are mostly just designed to exercise the new code. The reason for the funny structure of the tests is that type fixing for arrays inside of structs is the only place in Sema that calls tryEvaluate, at least for the moment. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59125 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r--lib/AST/ExprConstant.cpp227
1 files changed, 202 insertions, 25 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 887a3aac5d..98400a450d 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/TargetInfo.h"
@@ -62,11 +63,112 @@ struct EvalInfo {
};
+static bool EvaluateLValue(const Expr *E, APValue &Result, EvalInfo &Info);
static bool EvaluatePointer(const Expr *E, APValue &Result, EvalInfo &Info);
static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info);
static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info);
//===----------------------------------------------------------------------===//
+// Misc utilities
+//===----------------------------------------------------------------------===//
+
+static bool HandleConversionToBool(Expr* E, bool& Result, EvalInfo &Info) {
+ if (E->getType()->isIntegralType()) {
+ APSInt IntResult;
+ if (!EvaluateInteger(E, IntResult, Info))
+ return false;
+ Result = IntResult != 0;
+ return true;
+ } else if (E->getType()->isRealFloatingType()) {
+ APFloat FloatResult(0.0);
+ if (!EvaluateFloat(E, FloatResult, Info))
+ return false;
+ Result = !FloatResult.isZero();
+ return true;
+ } else if (E->getType()->isPointerType()) {
+ APValue PointerResult;
+ if (!EvaluatePointer(E, PointerResult, Info))
+ return false;
+ // FIXME: Is this accurate for all kinds of bases? If not, what would
+ // the check look like?
+ Result = PointerResult.getLValueBase() || PointerResult.getLValueOffset();
+ return true;
+ }
+
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// LValue Evaluation
+//===----------------------------------------------------------------------===//
+namespace {
+class VISIBILITY_HIDDEN LValueExprEvaluator
+ : public StmtVisitor<LValueExprEvaluator, APValue> {
+ EvalInfo &Info;
+public:
+
+ LValueExprEvaluator(EvalInfo &info) : Info(info) {}
+
+ APValue VisitStmt(Stmt *S) {
+ // FIXME: Remove this when we support more expressions.
+ printf("Unhandled pointer statement\n");
+ S->dump();
+ return APValue();
+ }
+
+ APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ APValue VisitDeclRefExpr(DeclRefExpr *E) { return APValue(E, 0); }
+ APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E, 0); }
+ APValue VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
+ APValue VisitMemberExpr(MemberExpr *E);
+ APValue VisitStringLiteral(StringLiteral *E) { return APValue(E, 0); }
+};
+} // end anonymous namespace
+
+static bool EvaluateLValue(const Expr* E, APValue& Result, EvalInfo &Info) {
+ Result = LValueExprEvaluator(Info).Visit(const_cast<Expr*>(E));
+ return Result.isLValue();
+}
+
+APValue LValueExprEvaluator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+ if (E->isFileScope())
+ return APValue(E, 0);
+ return APValue();
+}
+
+APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
+ APValue result;
+ QualType Ty;
+ if (E->isArrow()) {
+ if (!EvaluatePointer(E->getBase(), result, Info))
+ return APValue();
+ Ty = E->getBase()->getType()->getAsPointerType()->getPointeeType();
+ } else {
+ result = Visit(E->getBase());
+ if (result.isUninit())
+ return APValue();
+ Ty = E->getBase()->getType();
+ }
+
+ RecordDecl *RD = Ty->getAsRecordType()->getDecl();
+ const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
+ FieldDecl *FD = E->getMemberDecl();
+
+ // FIXME: This is linear time.
+ unsigned i = 0, e = 0;
+ for (i = 0, e = RD->getNumMembers(); i != e; i++) {
+ if (RD->getMember(i) == FD)
+ break;
+ }
+
+ result.setLValue(result.getLValueBase(),
+ result.getLValueOffset() + RL.getFieldOffset(i) / 8);
+
+ return result;
+}
+
+
+//===----------------------------------------------------------------------===//
// Pointer Evaluation
//===----------------------------------------------------------------------===//
@@ -86,6 +188,10 @@ public:
APValue VisitBinaryOperator(const BinaryOperator *E);
APValue VisitCastExpr(const CastExpr* E);
+ APValue VisitUnaryOperator(const UnaryOperator *E);
+ APValue VisitObjCStringLiteral(ObjCStringLiteral *E)
+ { return APValue(E, 0); }
+ APValue VisitConditionalOperator(ConditionalOperator *E);
};
} // end anonymous namespace
@@ -114,14 +220,33 @@ APValue PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (!EvaluateInteger(IExp, AdditionalOffset, Info))
return APValue();
+ QualType PointeeType = PExp->getType()->getAsPointerType()->getPointeeType();
+ uint64_t SizeOfPointee = Info.Ctx.getTypeSize(PointeeType) / 8;
+
uint64_t Offset = ResultLValue.getLValueOffset();
+
if (E->getOpcode() == BinaryOperator::Add)
- Offset += AdditionalOffset.getZExtValue();
+ Offset += AdditionalOffset.getLimitedValue() * SizeOfPointee;
else
- Offset -= AdditionalOffset.getZExtValue();
-
+ Offset -= AdditionalOffset.getLimitedValue() * SizeOfPointee;
+
return APValue(ResultLValue.getLValueBase(), Offset);
}
+
+APValue PointerExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
+ if (E->getOpcode() == UnaryOperator::Extension) {
+ // FIXME: Deal with warnings?
+ return Visit(E->getSubExpr());
+ }
+
+ if (E->getOpcode() == UnaryOperator::AddrOf) {
+ APValue result;
+ if (EvaluateLValue(E->getSubExpr(), result, Info))
+ return result;
+ }
+
+ return APValue();
+}
APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
@@ -142,11 +267,31 @@ APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
return APValue(0, Result.getZExtValue());
}
}
-
- assert(0 && "Unhandled cast");
+
+ if (SubExpr->getType()->isFunctionType() ||
+ SubExpr->getType()->isArrayType()) {
+ APValue Result;
+ if (EvaluateLValue(SubExpr, Result, Info))
+ return Result;
+ return APValue();
+ }
+
+ //assert(0 && "Unhandled cast");
return APValue();
}
+APValue PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) {
+ bool BoolResult;
+ if (!HandleConversionToBool(E->getCond(), BoolResult, Info))
+ return APValue();
+
+ Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr();
+
+ APValue Result;
+ if (EvaluatePointer(EvalExpr, Result, Info))
+ return Result;
+ return APValue();
+}
//===----------------------------------------------------------------------===//
// Integer Evaluation
@@ -349,8 +494,8 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
return false;
// X && 0 -> 0, X || 1 -> 1.
- if (E->getOpcode() == BinaryOperator::LAnd && RHS == 0 ||
- E->getOpcode() == BinaryOperator::LOr && RHS != 0) {
+ if ((E->getOpcode() == BinaryOperator::LAnd && RHS == 0) ||
+ (E->getOpcode() == BinaryOperator::LOr && RHS != 0)) {
Result = RHS != 0;
Result.zextOrTrunc(getIntTypeSizeInBits(E->getType()));
Result.setIsUnsigned(E->getType()->isUnsignedIntegerType());
@@ -470,10 +615,13 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
QualType SrcTy = E->getTypeOfArgument();
// sizeof(void) and __alignof__(void) = 1 as a gcc extension.
- if (SrcTy->isVoidType())
+ if (SrcTy->isVoidType()) {
Result = 1;
+ return true;
+ }
// sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
+ // FIXME: But alignof(vla) is!
if (!SrcTy->isConstantSizeType()) {
// FIXME: Should we attempt to evaluate this?
return false;
@@ -491,7 +639,7 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
// Get information about the size or align.
unsigned CharSize = Info.Ctx.Target.getCharWidth();
if (isSizeOf)
- Result = getIntTypeSizeInBits(SrcTy) / CharSize;
+ Result = Info.Ctx.getTypeSize(SrcTy) / CharSize;
else
Result = Info.Ctx.getTypeAlign(SrcTy) / CharSize;
return true;
@@ -547,6 +695,16 @@ bool IntExprEvaluator::HandleCast(SourceLocation CastLoc,
Expr *SubExpr, QualType DestType) {
unsigned DestWidth = getIntTypeSizeInBits(DestType);
+ if (DestType->isBooleanType()) {
+ bool BoolResult;
+ if (!HandleConversionToBool(SubExpr, BoolResult, Info))
+ return false;
+ Result.zextOrTrunc(DestWidth);
+ Result.setIsUnsigned(DestType->isUnsignedIntegerType());
+ Result = BoolResult;
+ return true;
+ }
+
// Handle simple integer->integer casts.
if (SubExpr->getType()->isIntegerType()) {
if (!Visit(SubExpr))
@@ -554,12 +712,7 @@ bool IntExprEvaluator::HandleCast(SourceLocation CastLoc,
// Figure out if this is a truncate, extend or noop cast.
// If the input is signed, do a sign extend, noop, or truncate.
- if (DestType->isBooleanType()) {
- // Conversion to bool compares against zero.
- Result = Result != 0;
- Result.zextOrTrunc(DestWidth);
- } else
- Result.extOrTrunc(DestWidth);
+ Result.extOrTrunc(DestWidth);
Result.setIsUnsigned(DestType->isUnsignedIntegerType());
return true;
}
@@ -569,29 +722,22 @@ bool IntExprEvaluator::HandleCast(SourceLocation CastLoc,
APValue LV;
if (!EvaluatePointer(SubExpr, LV, Info))
return false;
+
if (LV.getLValueBase())
return false;
-
+
Result.extOrTrunc(DestWidth);
Result = LV.getLValueOffset();
Result.setIsUnsigned(DestType->isUnsignedIntegerType());
return true;
}
-
+
if (!SubExpr->getType()->isRealFloatingType())
return Error(CastLoc, diag::err_expr_not_constant, DestType);
APFloat F(0.0);
if (!EvaluateFloat(SubExpr, F, Info))
return Error(CastLoc, diag::err_expr_not_constant, DestType);
-
- // If the destination is boolean, compare against zero.
- if (DestType->isBooleanType()) {
- Result = !F.isZero();
- Result.zextOrTrunc(DestWidth);
- Result.setIsUnsigned(DestType->isUnsignedIntegerType());
- return true;
- }
// Determine whether we are converting to unsigned or signed.
bool DestSigned = DestType->isSignedIntegerType();
@@ -629,6 +775,8 @@ public:
bool VisitUnaryOperator(const UnaryOperator *E);
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitFloatingLiteral(const FloatingLiteral *E);
+ bool VisitCastExpr(CastExpr *E);
+ bool VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E);
};
} // end anonymous namespace
@@ -738,6 +886,35 @@ bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) {
return true;
}
+bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) {
+ Expr* SubExpr = E->getSubExpr();
+ const llvm::fltSemantics& destSemantics =
+ Info.Ctx.getFloatTypeSemantics(E->getType());
+ if (SubExpr->getType()->isIntegralType()) {
+ APSInt IntResult;
+ if (!EvaluateInteger(E, IntResult, Info))
+ return false;
+ Result = APFloat(destSemantics, 1);
+ Result.convertFromAPInt(IntResult, IntResult.isSigned(),
+ APFloat::rmNearestTiesToEven);
+ return true;
+ }
+ if (SubExpr->getType()->isRealFloatingType()) {
+ if (!Visit(SubExpr))
+ return false;
+ bool ignored;
+ Result.convert(destSemantics, APFloat::rmNearestTiesToEven, &ignored);
+ return true;
+ }
+
+ return false;
+}
+
+bool FloatExprEvaluator::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) {
+ Result = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(E->getType()));
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// Top level TryEvaluate.
//===----------------------------------------------------------------------===//