зеркало из https://github.com/microsoft/clang-1.git
Major cleanup of path-sensitive analysis engine and the current analysis
based on constant. prop. and limited symbolics. - Renamed class: RValue -> RVal, LValue -> LVal, etc. - Minor method renamings and interface cleanups. - Tightened the RVal "type system" so that UninitializedVal and UnknownVal cannot be cast to LVal or NonLVal. This forces these corner cases values to be explicitly handled early before being dispatched to plug-in transfer function logic. - Major cleanup in the transfer function logic for binary and unary operators. Still fixing some regressions, but we now explicitly handle Uninitialized and Unknown values in a more rigorous way. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@47441 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
3b707e7476
Коммит
aa1c4e5a6b
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -19,47 +19,46 @@
|
|||
using namespace clang;
|
||||
|
||||
namespace clang {
|
||||
unsigned RunGRSimpleVals(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx,
|
||||
Diagnostic& Diag, bool Visualize) {
|
||||
|
||||
unsigned RunGRSimpleVals(CFG& cfg, FunctionDecl& FD, ASTContext& Ctx,
|
||||
Diagnostic& Diag, bool Visualize) {
|
||||
|
||||
if (Diag.hasErrorOccurred())
|
||||
return 0;
|
||||
|
||||
GRCoreEngine<GRExprEngine> Engine(cfg, FD, Ctx);
|
||||
GRExprEngine* CheckerState = &Engine.getCheckerState();
|
||||
GRSimpleVals GRSV;
|
||||
CheckerState->setTransferFunctions(GRSV);
|
||||
|
||||
// Execute the worklist algorithm.
|
||||
Engine.ExecuteWorkList(10000);
|
||||
|
||||
// Look for explicit-Null dereferences and warn about them.
|
||||
for (GRExprEngine::null_iterator I=CheckerState->null_begin(),
|
||||
E=CheckerState->null_end(); I!=E; ++I) {
|
||||
|
||||
if (Diag.hasErrorOccurred())
|
||||
return 0;
|
||||
const PostStmt& L = cast<PostStmt>((*I)->getLocation());
|
||||
Expr* Exp = cast<Expr>(L.getStmt());
|
||||
|
||||
GRCoreEngine<GRExprEngine> Engine(cfg, FD, Ctx);
|
||||
GRExprEngine* CheckerState = &Engine.getCheckerState();
|
||||
GRSimpleVals GRSV;
|
||||
CheckerState->setTransferFunctions(GRSV);
|
||||
|
||||
// Execute the worklist algorithm.
|
||||
Engine.ExecuteWorkList(10000);
|
||||
|
||||
// Look for explicit-Null dereferences and warn about them.
|
||||
for (GRExprEngine::null_iterator I=CheckerState->null_begin(),
|
||||
E=CheckerState->null_end(); I!=E; ++I) {
|
||||
|
||||
const PostStmt& L = cast<PostStmt>((*I)->getLocation());
|
||||
Expr* Exp = cast<Expr>(L.getStmt());
|
||||
|
||||
Diag.Report(FullSourceLoc(Exp->getExprLoc(), Ctx.getSourceManager()),
|
||||
diag::chkr_null_deref_after_check);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (Visualize) CheckerState->ViewGraph();
|
||||
#endif
|
||||
|
||||
return Engine.getGraph().size();
|
||||
Diag.Report(FullSourceLoc(Exp->getExprLoc(), Ctx.getSourceManager()),
|
||||
diag::chkr_null_deref_after_check);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (Visualize) CheckerState->ViewGraph();
|
||||
#endif
|
||||
|
||||
return Engine.getGraph().size();
|
||||
}
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Transfer function for Casts.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
RValue GRSimpleVals::EvalCast(ValueManager& ValMgr, NonLValue X,
|
||||
Expr* CastExpr) {
|
||||
|
||||
assert (!isa<UnknownVal>(X) && !isa<UninitializedVal>(X));
|
||||
RVal GRSimpleVals::EvalCast(ValueManager& ValMgr, NonLVal X, Expr* CastExpr) {
|
||||
|
||||
if (!isa<nonlval::ConcreteInt>(X))
|
||||
return UnknownVal();
|
||||
|
@ -77,10 +76,8 @@ RValue GRSimpleVals::EvalCast(ValueManager& ValMgr, NonLValue X,
|
|||
|
||||
// Casts.
|
||||
|
||||
RValue GRSimpleVals::EvalCast(ValueManager& ValMgr, LValue X, Expr* CastExpr) {
|
||||
RVal GRSimpleVals::EvalCast(ValueManager& ValMgr, LVal X, Expr* CastExpr) {
|
||||
|
||||
assert (!isa<UnknownVal>(X) && !isa<UninitializedVal>(X));
|
||||
|
||||
if (CastExpr->getType()->isPointerType())
|
||||
return X;
|
||||
|
||||
|
@ -99,86 +96,65 @@ RValue GRSimpleVals::EvalCast(ValueManager& ValMgr, LValue X, Expr* CastExpr) {
|
|||
|
||||
// Unary operators.
|
||||
|
||||
NonLValue GRSimpleVals::EvalMinus(ValueManager& ValMgr, UnaryOperator* U,
|
||||
NonLValue X) {
|
||||
|
||||
assert (!isa<UnknownVal>(X) && !isa<UninitializedVal>(X));
|
||||
RVal GRSimpleVals::EvalMinus(ValueManager& ValMgr, UnaryOperator* U, NonLVal X){
|
||||
|
||||
switch (X.getSubKind()) {
|
||||
|
||||
case nonlval::ConcreteIntKind:
|
||||
return cast<nonlval::ConcreteInt>(X).EvalMinus(ValMgr, U);
|
||||
|
||||
default:
|
||||
return cast<NonLValue>(UnknownVal());
|
||||
return UnknownVal();
|
||||
}
|
||||
}
|
||||
|
||||
NonLValue GRSimpleVals::EvalPlus(ValueManager& ValMgr, UnaryOperator* U,
|
||||
NonLValue X) {
|
||||
|
||||
assert (!isa<UnknownVal>(X) && !isa<UninitializedVal>(X));
|
||||
|
||||
switch (X.getSubKind()) {
|
||||
case nonlval::ConcreteIntKind:
|
||||
return cast<nonlval::ConcreteInt>(X).EvalPlus(ValMgr, U);
|
||||
default:
|
||||
return cast<NonLValue>(UnknownVal());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NonLValue GRSimpleVals::EvalComplement(ValueManager& ValMgr, NonLValue X) {
|
||||
|
||||
assert (!isa<UnknownVal>(X) && !isa<UninitializedVal>(X));
|
||||
|
||||
RVal GRSimpleVals::EvalComplement(ValueManager& ValMgr, NonLVal X) {
|
||||
|
||||
switch (X.getSubKind()) {
|
||||
|
||||
case nonlval::ConcreteIntKind:
|
||||
return cast<nonlval::ConcreteInt>(X).EvalComplement(ValMgr);
|
||||
|
||||
default:
|
||||
return cast<NonLValue>(UnknownVal());
|
||||
return UnknownVal();
|
||||
}
|
||||
}
|
||||
|
||||
// Binary operators.
|
||||
|
||||
NonLValue GRSimpleVals::EvalBinaryOp(ValueManager& ValMgr,
|
||||
BinaryOperator::Opcode Op,
|
||||
NonLValue LHS, NonLValue RHS) {
|
||||
|
||||
assert (!isa<UnknownVal>(LHS) && !isa<UninitializedVal>(LHS));
|
||||
assert (!isa<UnknownVal>(RHS) && !isa<UninitializedVal>(RHS));
|
||||
|
||||
while(1) {
|
||||
RVal GRSimpleVals::EvalBinOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
|
||||
NonLVal L, NonLVal R) {
|
||||
while (1) {
|
||||
|
||||
switch (LHS.getSubKind()) {
|
||||
switch (L.getSubKind()) {
|
||||
default:
|
||||
return cast<NonLValue>(UnknownVal());
|
||||
return cast<NonLVal>(UnknownVal());
|
||||
|
||||
case nonlval::ConcreteIntKind:
|
||||
|
||||
if (isa<nonlval::ConcreteInt>(RHS)) {
|
||||
const nonlval::ConcreteInt& LHS_CI = cast<nonlval::ConcreteInt>(LHS);
|
||||
const nonlval::ConcreteInt& RHS_CI = cast<nonlval::ConcreteInt>(RHS);
|
||||
return LHS_CI.EvalBinaryOp(ValMgr, Op, RHS_CI);
|
||||
if (isa<nonlval::ConcreteInt>(R)) {
|
||||
const nonlval::ConcreteInt& L_CI = cast<nonlval::ConcreteInt>(L);
|
||||
const nonlval::ConcreteInt& R_CI = cast<nonlval::ConcreteInt>(R);
|
||||
return L_CI.EvalBinOp(ValMgr, Op, R_CI);
|
||||
}
|
||||
else if(isa<UnknownVal>(RHS))
|
||||
return cast<NonLValue>(UnknownVal());
|
||||
else {
|
||||
NonLValue tmp = RHS;
|
||||
RHS = LHS;
|
||||
LHS = tmp;
|
||||
NonLVal tmp = R;
|
||||
R = L;
|
||||
L = tmp;
|
||||
continue;
|
||||
}
|
||||
|
||||
case nonlval::SymbolValKind: {
|
||||
if (isa<nonlval::ConcreteInt>(RHS)) {
|
||||
|
||||
if (isa<nonlval::ConcreteInt>(R)) {
|
||||
const SymIntConstraint& C =
|
||||
ValMgr.getConstraint(cast<nonlval::SymbolVal>(LHS).getSymbol(), Op,
|
||||
cast<nonlval::ConcreteInt>(RHS).getValue());
|
||||
ValMgr.getConstraint(cast<nonlval::SymbolVal>(L).getSymbol(), Op,
|
||||
cast<nonlval::ConcreteInt>(R).getValue());
|
||||
|
||||
return nonlval::SymIntConstraintVal(C);
|
||||
}
|
||||
else
|
||||
return cast<NonLValue>(UnknownVal());
|
||||
return UnknownVal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -187,150 +163,140 @@ NonLValue GRSimpleVals::EvalBinaryOp(ValueManager& ValMgr,
|
|||
|
||||
// Binary Operators (except assignments and comma).
|
||||
|
||||
RValue GRSimpleVals::EvalBinaryOp(ValueManager& ValMgr,
|
||||
BinaryOperator::Opcode Op,
|
||||
LValue LHS, LValue RHS) {
|
||||
|
||||
assert (!isa<UnknownVal>(LHS) && !isa<UninitializedVal>(LHS));
|
||||
assert (!isa<UnknownVal>(RHS) && !isa<UninitializedVal>(RHS));
|
||||
RVal GRSimpleVals::EvalBinOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
|
||||
LVal L, LVal R) {
|
||||
|
||||
switch (Op) {
|
||||
|
||||
default:
|
||||
return UnknownVal();
|
||||
|
||||
case BinaryOperator::EQ:
|
||||
return EvalEQ(ValMgr, LHS, RHS);
|
||||
return EvalEQ(ValMgr, L, R);
|
||||
|
||||
case BinaryOperator::NE:
|
||||
return EvalNE(ValMgr, LHS, RHS);
|
||||
return EvalNE(ValMgr, L, R);
|
||||
}
|
||||
}
|
||||
|
||||
// Pointer arithmetic.
|
||||
|
||||
LValue GRSimpleVals::EvalBinaryOp(ValueManager& ValMgr,
|
||||
BinaryOperator::Opcode Op,
|
||||
LValue LHS, NonLValue RHS) {
|
||||
|
||||
assert (!isa<UnknownVal>(LHS) && !isa<UninitializedVal>(LHS));
|
||||
assert (!isa<UnknownVal>(RHS) && !isa<UninitializedVal>(RHS));
|
||||
|
||||
return cast<LValue>(UnknownVal());
|
||||
RVal GRSimpleVals::EvalBinOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
|
||||
LVal L, NonLVal R) {
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
// Equality operators for LValues.
|
||||
// Equality operators for LVals.
|
||||
|
||||
RVal GRSimpleVals::EvalEQ(ValueManager& ValMgr, LVal L, LVal R) {
|
||||
|
||||
switch (L.getSubKind()) {
|
||||
|
||||
NonLValue GRSimpleVals::EvalEQ(ValueManager& ValMgr, LValue LHS, LValue RHS) {
|
||||
|
||||
assert (!isa<UnknownVal>(LHS) && !isa<UninitializedVal>(LHS));
|
||||
assert (!isa<UnknownVal>(RHS) && !isa<UninitializedVal>(RHS));
|
||||
|
||||
switch (LHS.getSubKind()) {
|
||||
default:
|
||||
assert(false && "EQ not implemented for this LValue.");
|
||||
return cast<NonLValue>(UnknownVal());
|
||||
assert(false && "EQ not implemented for this LVal.");
|
||||
return UnknownVal();
|
||||
|
||||
case lval::ConcreteIntKind:
|
||||
if (isa<lval::ConcreteInt>(RHS)) {
|
||||
bool b = cast<lval::ConcreteInt>(LHS).getValue() ==
|
||||
cast<lval::ConcreteInt>(RHS).getValue();
|
||||
|
||||
if (isa<lval::ConcreteInt>(R)) {
|
||||
bool b = cast<lval::ConcreteInt>(L).getValue() ==
|
||||
cast<lval::ConcreteInt>(R).getValue();
|
||||
|
||||
return NonLValue::GetIntTruthValue(ValMgr, b);
|
||||
return NonLVal::MakeIntTruthVal(ValMgr, b);
|
||||
}
|
||||
else if (isa<lval::SymbolVal>(RHS)) {
|
||||
else if (isa<lval::SymbolVal>(R)) {
|
||||
|
||||
const SymIntConstraint& C =
|
||||
ValMgr.getConstraint(cast<lval::SymbolVal>(RHS).getSymbol(),
|
||||
ValMgr.getConstraint(cast<lval::SymbolVal>(R).getSymbol(),
|
||||
BinaryOperator::EQ,
|
||||
cast<lval::ConcreteInt>(LHS).getValue());
|
||||
cast<lval::ConcreteInt>(L).getValue());
|
||||
|
||||
return nonlval::SymIntConstraintVal(C);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case lval::SymbolValKind: {
|
||||
if (isa<lval::ConcreteInt>(RHS)) {
|
||||
const SymIntConstraint& C =
|
||||
ValMgr.getConstraint(cast<lval::SymbolVal>(LHS).getSymbol(),
|
||||
BinaryOperator::EQ,
|
||||
cast<lval::ConcreteInt>(RHS).getValue());
|
||||
|
||||
return nonlval::SymIntConstraintVal(C);
|
||||
}
|
||||
case lval::SymbolValKind: {
|
||||
|
||||
if (isa<lval::ConcreteInt>(R)) {
|
||||
const SymIntConstraint& C =
|
||||
ValMgr.getConstraint(cast<lval::SymbolVal>(L).getSymbol(),
|
||||
BinaryOperator::EQ,
|
||||
cast<lval::ConcreteInt>(R).getValue());
|
||||
|
||||
// FIXME: Implement unification
|
||||
return cast<NonLValue>(UnknownVal());
|
||||
//assert (!isa<lval::SymbolVal>(RHS) && "FIXME: Implement unification.");
|
||||
|
||||
break;
|
||||
return nonlval::SymIntConstraintVal(C);
|
||||
}
|
||||
|
||||
case lval::DeclValKind:
|
||||
// FIXME: Implement unification
|
||||
return cast<NonLVal>(UnknownVal());
|
||||
//assert (!isa<lval::SymbolVal>(R) && "FIXME: Implement unification.");
|
||||
|
||||
if (isa<lval::DeclVal>(RHS)) {
|
||||
bool b = cast<lval::DeclVal>(LHS) == cast<lval::DeclVal>(RHS);
|
||||
return NonLValue::GetIntTruthValue(ValMgr, b);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case lval::DeclValKind:
|
||||
|
||||
if (isa<lval::DeclVal>(R)) {
|
||||
bool b = cast<lval::DeclVal>(L) == cast<lval::DeclVal>(R);
|
||||
return NonLVal::MakeIntTruthVal(ValMgr, b);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return NonLValue::GetIntTruthValue(ValMgr, false);
|
||||
return NonLVal::MakeIntTruthVal(ValMgr, false);
|
||||
}
|
||||
|
||||
NonLValue GRSimpleVals::EvalNE(ValueManager& ValMgr, LValue LHS, LValue RHS) {
|
||||
RVal GRSimpleVals::EvalNE(ValueManager& ValMgr, LVal L, LVal R) {
|
||||
|
||||
assert (!isa<UnknownVal>(LHS) && !isa<UninitializedVal>(LHS));
|
||||
assert (!isa<UnknownVal>(RHS) && !isa<UninitializedVal>(RHS));
|
||||
switch (L.getSubKind()) {
|
||||
|
||||
switch (LHS.getSubKind()) {
|
||||
default:
|
||||
assert(false && "NE not implemented for this LValue.");
|
||||
return cast<NonLValue>(UnknownVal());
|
||||
assert(false && "NE not implemented for this LVal.");
|
||||
return UnknownVal();
|
||||
|
||||
case lval::ConcreteIntKind:
|
||||
if (isa<lval::ConcreteInt>(RHS)) {
|
||||
bool b = cast<lval::ConcreteInt>(LHS).getValue() !=
|
||||
cast<lval::ConcreteInt>(RHS).getValue();
|
||||
|
||||
if (isa<lval::ConcreteInt>(R)) {
|
||||
bool b = cast<lval::ConcreteInt>(L).getValue() !=
|
||||
cast<lval::ConcreteInt>(R).getValue();
|
||||
|
||||
return NonLValue::GetIntTruthValue(ValMgr, b);
|
||||
return NonLVal::MakeIntTruthVal(ValMgr, b);
|
||||
}
|
||||
else if (isa<lval::SymbolVal>(RHS)) {
|
||||
else if (isa<lval::SymbolVal>(R)) {
|
||||
const SymIntConstraint& C =
|
||||
ValMgr.getConstraint(cast<lval::SymbolVal>(RHS).getSymbol(),
|
||||
ValMgr.getConstraint(cast<lval::SymbolVal>(R).getSymbol(),
|
||||
BinaryOperator::NE,
|
||||
cast<lval::ConcreteInt>(LHS).getValue());
|
||||
cast<lval::ConcreteInt>(L).getValue());
|
||||
|
||||
return nonlval::SymIntConstraintVal(C);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case lval::SymbolValKind: {
|
||||
if (isa<lval::ConcreteInt>(RHS)) {
|
||||
const SymIntConstraint& C =
|
||||
ValMgr.getConstraint(cast<lval::SymbolVal>(LHS).getSymbol(),
|
||||
BinaryOperator::NE,
|
||||
cast<lval::ConcreteInt>(RHS).getValue());
|
||||
|
||||
return nonlval::SymIntConstraintVal(C);
|
||||
}
|
||||
case lval::SymbolValKind: {
|
||||
if (isa<lval::ConcreteInt>(R)) {
|
||||
const SymIntConstraint& C =
|
||||
ValMgr.getConstraint(cast<lval::SymbolVal>(L).getSymbol(),
|
||||
BinaryOperator::NE,
|
||||
cast<lval::ConcreteInt>(R).getValue());
|
||||
|
||||
assert (!isa<lval::SymbolVal>(RHS) && "FIXME: Implement sym !=.");
|
||||
|
||||
break;
|
||||
return nonlval::SymIntConstraintVal(C);
|
||||
}
|
||||
|
||||
case lval::DeclValKind:
|
||||
if (isa<lval::DeclVal>(RHS)) {
|
||||
bool b = cast<lval::DeclVal>(LHS) == cast<lval::DeclVal>(RHS);
|
||||
return NonLValue::GetIntTruthValue(ValMgr, b);
|
||||
}
|
||||
assert (!isa<lval::SymbolVal>(R) && "FIXME: Implement sym !=.");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case lval::DeclValKind:
|
||||
if (isa<lval::DeclVal>(R)) {
|
||||
bool b = cast<lval::DeclVal>(L) == cast<lval::DeclVal>(R);
|
||||
return NonLVal::MakeIntTruthVal(ValMgr, b);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return NonLValue::GetIntTruthValue(ValMgr, true);
|
||||
return NonLVal::MakeIntTruthVal(ValMgr, true);
|
||||
}
|
||||
|
|
|
@ -28,40 +28,35 @@ public:
|
|||
|
||||
// Casts.
|
||||
|
||||
virtual RValue EvalCast(ValueManager& ValMgr, NonLValue V, Expr* CastExpr);
|
||||
virtual RValue EvalCast(ValueManager& ValMgr, LValue V, Expr* CastExpr);
|
||||
virtual RVal EvalCast(ValueManager& ValMgr, NonLVal V, Expr* CastExpr);
|
||||
virtual RVal EvalCast(ValueManager& ValMgr, LVal V, Expr* CastExpr);
|
||||
|
||||
// Unary Operators.
|
||||
|
||||
virtual NonLValue EvalMinus(ValueManager& ValMgr, UnaryOperator* U,
|
||||
NonLValue X);
|
||||
|
||||
virtual NonLValue EvalPlus(ValueManager& ValMgr, UnaryOperator* U,
|
||||
NonLValue X);
|
||||
|
||||
virtual NonLValue EvalComplement(ValueManager& ValMgr, NonLValue X);
|
||||
virtual RVal EvalMinus(ValueManager& ValMgr, UnaryOperator* U, NonLVal X);
|
||||
|
||||
virtual RVal EvalComplement(ValueManager& ValMgr, NonLVal X);
|
||||
|
||||
// Binary Operators.
|
||||
|
||||
virtual NonLValue EvalBinaryOp(ValueManager& ValMgr,
|
||||
BinaryOperator::Opcode Op,
|
||||
NonLValue LHS, NonLValue RHS);
|
||||
virtual RVal EvalBinOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
|
||||
NonLVal L, NonLVal R);
|
||||
|
||||
virtual RValue EvalBinaryOp(ValueManager& ValMgr,
|
||||
BinaryOperator::Opcode Op,
|
||||
LValue LHS, LValue RHS);
|
||||
virtual RVal EvalBinOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
|
||||
LVal L, LVal R);
|
||||
|
||||
// Pointer arithmetic.
|
||||
|
||||
virtual LValue EvalBinaryOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
|
||||
LValue LHS, NonLValue RHS);
|
||||
virtual RVal EvalBinOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
|
||||
LVal L, NonLVal R);
|
||||
|
||||
protected:
|
||||
// Equality operators for LValues.
|
||||
NonLValue EvalEQ(ValueManager& ValMgr, LValue LHS, LValue RHS);
|
||||
NonLValue EvalNE(ValueManager& ValMgr, LValue LHS, LValue RHS);
|
||||
};
|
||||
|
||||
// Equality operators for LVals.
|
||||
|
||||
RVal EvalEQ(ValueManager& ValMgr, LVal L, LVal R);
|
||||
RVal EvalNE(ValueManager& ValMgr, LVal L, LVal R);
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
|
|
|
@ -20,21 +20,21 @@ using namespace clang;
|
|||
// Transfer function for Casts.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
RValue GRTransferFuncs::EvalCast(ValueManager& ValMgr, RValue X,
|
||||
Expr* CastExpr) {
|
||||
RVal GRTransferFuncs::EvalCast(ValueManager& ValMgr, RVal X, Expr* CastExpr) {
|
||||
|
||||
switch (X.getBaseKind()) {
|
||||
|
||||
default:
|
||||
assert(false && "Invalid RValue."); break;
|
||||
assert(false && "Invalid RVal."); break;
|
||||
|
||||
case RValue::LValueKind:
|
||||
return EvalCast(ValMgr, cast<LValue>(X), CastExpr);
|
||||
case RVal::LValKind:
|
||||
return EvalCast(ValMgr, cast<LVal>(X), CastExpr);
|
||||
|
||||
case RValue::NonLValueKind:
|
||||
return EvalCast(ValMgr, cast<NonLValue>(X), CastExpr);
|
||||
case RVal::NonLValKind:
|
||||
return EvalCast(ValMgr, cast<NonLVal>(X), CastExpr);
|
||||
|
||||
case RValue::UninitializedKind:
|
||||
case RValue::UnknownKind: break;
|
||||
case RVal::UninitializedKind:
|
||||
case RVal::UnknownKind: break;
|
||||
}
|
||||
|
||||
return X;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This files defines RValue, LValue, and NonLValue, classes that represent
|
||||
// This files defines RVal, LVal, and NonLVal, classes that represent
|
||||
// abstract r-values for use with path-sensitive value tracking.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -24,45 +24,40 @@ using llvm::APSInt;
|
|||
// Symbol Iteration.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
RValue::symbol_iterator RValue::symbol_begin() const {
|
||||
if (isa<LValue>(this)) {
|
||||
if (isa<lval::SymbolVal>(this))
|
||||
return (symbol_iterator) (&Data);
|
||||
}
|
||||
else {
|
||||
if (isa<nonlval::SymbolVal>(this))
|
||||
return (symbol_iterator) (&Data);
|
||||
else if (isa<nonlval::SymIntConstraintVal>(this)) {
|
||||
const SymIntConstraint& C =
|
||||
cast<nonlval::SymIntConstraintVal>(this)->getConstraint();
|
||||
return (symbol_iterator) &C.getSymbol();
|
||||
}
|
||||
RVal::symbol_iterator RVal::symbol_begin() const {
|
||||
if (isa<lval::SymbolVal>(this))
|
||||
return (symbol_iterator) (&Data);
|
||||
else if (isa<nonlval::SymbolVal>(this))
|
||||
return (symbol_iterator) (&Data);
|
||||
else if (isa<nonlval::SymIntConstraintVal>(this)) {
|
||||
const SymIntConstraint& C =
|
||||
cast<nonlval::SymIntConstraintVal>(this)->getConstraint();
|
||||
|
||||
return (symbol_iterator) &C.getSymbol();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RValue::symbol_iterator RValue::symbol_end() const {
|
||||
RVal::symbol_iterator RVal::symbol_end() const {
|
||||
symbol_iterator X = symbol_begin();
|
||||
return X ? X+1 : NULL;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Transfer function dispatch for Non-LValues.
|
||||
// Transfer function dispatch for Non-LVals.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
nonlval::ConcreteInt
|
||||
nonlval::ConcreteInt::EvalBinaryOp(ValueManager& ValMgr,
|
||||
BinaryOperator::Opcode Op,
|
||||
const nonlval::ConcreteInt& RHS) const {
|
||||
|
||||
return ValMgr.EvaluateAPSInt(Op, getValue(), RHS.getValue());
|
||||
nonlval::ConcreteInt::EvalBinOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
|
||||
const nonlval::ConcreteInt& R) const {
|
||||
|
||||
return ValMgr.EvaluateAPSInt(Op, getValue(), R.getValue());
|
||||
}
|
||||
|
||||
|
||||
// Bitwise-Complement.
|
||||
|
||||
|
||||
nonlval::ConcreteInt
|
||||
nonlval::ConcreteInt::EvalComplement(ValueManager& ValMgr) const {
|
||||
return ValMgr.getValue(~getValue());
|
||||
|
@ -77,47 +72,40 @@ nonlval::ConcreteInt::EvalMinus(ValueManager& ValMgr, UnaryOperator* U) const {
|
|||
return ValMgr.getValue(-getValue());
|
||||
}
|
||||
|
||||
nonlval::ConcreteInt
|
||||
nonlval::ConcreteInt::EvalPlus(ValueManager& ValMgr, UnaryOperator* U) const {
|
||||
assert (U->getType() == U->getSubExpr()->getType());
|
||||
assert (U->getType()->isIntegerType());
|
||||
return ValMgr.getValue(getValue());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Transfer function dispatch for LValues.
|
||||
// Transfer function dispatch for LVals.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
lval::ConcreteInt
|
||||
lval::ConcreteInt::EvalBinaryOp(ValueManager& ValMgr,
|
||||
BinaryOperator::Opcode Op,
|
||||
const lval::ConcreteInt& RHS) const {
|
||||
lval::ConcreteInt::EvalBinOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
|
||||
const lval::ConcreteInt& R) const {
|
||||
|
||||
assert (Op == BinaryOperator::Add || Op == BinaryOperator::Sub ||
|
||||
(Op >= BinaryOperator::LT && Op <= BinaryOperator::NE));
|
||||
|
||||
return ValMgr.EvaluateAPSInt(Op, getValue(), RHS.getValue());
|
||||
return ValMgr.EvaluateAPSInt(Op, getValue(), R.getValue());
|
||||
}
|
||||
|
||||
NonLValue LValue::EQ(ValueManager& ValMgr, const LValue& RHS) const {
|
||||
NonLVal LVal::EQ(ValueManager& ValMgr, const LVal& R) const {
|
||||
|
||||
switch (getSubKind()) {
|
||||
default:
|
||||
assert(false && "EQ not implemented for this LValue.");
|
||||
return cast<NonLValue>(UnknownVal());
|
||||
assert(false && "EQ not implemented for this LVal.");
|
||||
break;
|
||||
|
||||
case lval::ConcreteIntKind:
|
||||
if (isa<lval::ConcreteInt>(RHS)) {
|
||||
if (isa<lval::ConcreteInt>(R)) {
|
||||
bool b = cast<lval::ConcreteInt>(this)->getValue() ==
|
||||
cast<lval::ConcreteInt>(RHS).getValue();
|
||||
cast<lval::ConcreteInt>(R).getValue();
|
||||
|
||||
return NonLValue::GetIntTruthValue(ValMgr, b);
|
||||
return NonLVal::MakeIntTruthVal(ValMgr, b);
|
||||
}
|
||||
else if (isa<lval::SymbolVal>(RHS)) {
|
||||
else if (isa<lval::SymbolVal>(R)) {
|
||||
|
||||
const SymIntConstraint& C =
|
||||
ValMgr.getConstraint(cast<lval::SymbolVal>(RHS).getSymbol(),
|
||||
BinaryOperator::EQ,
|
||||
cast<lval::ConcreteInt>(this)->getValue());
|
||||
ValMgr.getConstraint(cast<lval::SymbolVal>(R).getSymbol(),
|
||||
BinaryOperator::EQ,
|
||||
cast<lval::ConcreteInt>(this)->getValue());
|
||||
|
||||
return nonlval::SymIntConstraintVal(C);
|
||||
}
|
||||
|
@ -125,50 +113,50 @@ NonLValue LValue::EQ(ValueManager& ValMgr, const LValue& RHS) const {
|
|||
break;
|
||||
|
||||
case lval::SymbolValKind: {
|
||||
if (isa<lval::ConcreteInt>(RHS)) {
|
||||
if (isa<lval::ConcreteInt>(R)) {
|
||||
|
||||
const SymIntConstraint& C =
|
||||
ValMgr.getConstraint(cast<lval::SymbolVal>(this)->getSymbol(),
|
||||
BinaryOperator::EQ,
|
||||
cast<lval::ConcreteInt>(RHS).getValue());
|
||||
ValMgr.getConstraint(cast<lval::SymbolVal>(this)->getSymbol(),
|
||||
BinaryOperator::EQ,
|
||||
cast<lval::ConcreteInt>(R).getValue());
|
||||
|
||||
return nonlval::SymIntConstraintVal(C);
|
||||
}
|
||||
|
||||
assert (!isa<lval::SymbolVal>(RHS) && "FIXME: Implement unification.");
|
||||
assert (!isa<lval::SymbolVal>(R) && "FIXME: Implement unification.");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case lval::DeclValKind:
|
||||
if (isa<lval::DeclVal>(RHS)) {
|
||||
bool b = cast<lval::DeclVal>(*this) == cast<lval::DeclVal>(RHS);
|
||||
return NonLValue::GetIntTruthValue(ValMgr, b);
|
||||
if (isa<lval::DeclVal>(R)) {
|
||||
bool b = cast<lval::DeclVal>(*this) == cast<lval::DeclVal>(R);
|
||||
return NonLVal::MakeIntTruthVal(ValMgr, b);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return NonLValue::GetIntTruthValue(ValMgr, false);
|
||||
return NonLVal::MakeIntTruthVal(ValMgr, false);
|
||||
}
|
||||
|
||||
NonLValue LValue::NE(ValueManager& ValMgr, const LValue& RHS) const {
|
||||
NonLVal LVal::NE(ValueManager& ValMgr, const LVal& R) const {
|
||||
switch (getSubKind()) {
|
||||
default:
|
||||
assert(false && "NE not implemented for this LValue.");
|
||||
return cast<NonLValue>(UnknownVal());
|
||||
assert(false && "NE not implemented for this LVal.");
|
||||
break;
|
||||
|
||||
case lval::ConcreteIntKind:
|
||||
if (isa<lval::ConcreteInt>(RHS)) {
|
||||
if (isa<lval::ConcreteInt>(R)) {
|
||||
bool b = cast<lval::ConcreteInt>(this)->getValue() !=
|
||||
cast<lval::ConcreteInt>(RHS).getValue();
|
||||
cast<lval::ConcreteInt>(R).getValue();
|
||||
|
||||
return NonLValue::GetIntTruthValue(ValMgr, b);
|
||||
return NonLVal::MakeIntTruthVal(ValMgr, b);
|
||||
}
|
||||
else if (isa<lval::SymbolVal>(RHS)) {
|
||||
else if (isa<lval::SymbolVal>(R)) {
|
||||
|
||||
const SymIntConstraint& C =
|
||||
ValMgr.getConstraint(cast<lval::SymbolVal>(RHS).getSymbol(),
|
||||
ValMgr.getConstraint(cast<lval::SymbolVal>(R).getSymbol(),
|
||||
BinaryOperator::NE,
|
||||
cast<lval::ConcreteInt>(this)->getValue());
|
||||
|
||||
|
@ -178,55 +166,56 @@ NonLValue LValue::NE(ValueManager& ValMgr, const LValue& RHS) const {
|
|||
break;
|
||||
|
||||
case lval::SymbolValKind: {
|
||||
if (isa<lval::ConcreteInt>(RHS)) {
|
||||
if (isa<lval::ConcreteInt>(R)) {
|
||||
|
||||
const SymIntConstraint& C =
|
||||
ValMgr.getConstraint(cast<lval::SymbolVal>(this)->getSymbol(),
|
||||
BinaryOperator::NE,
|
||||
cast<lval::ConcreteInt>(RHS).getValue());
|
||||
cast<lval::ConcreteInt>(R).getValue());
|
||||
|
||||
return nonlval::SymIntConstraintVal(C);
|
||||
}
|
||||
|
||||
assert (!isa<lval::SymbolVal>(RHS) && "FIXME: Implement sym !=.");
|
||||
assert (!isa<lval::SymbolVal>(R) && "FIXME: Implement sym !=.");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case lval::DeclValKind:
|
||||
if (isa<lval::DeclVal>(RHS)) {
|
||||
bool b = cast<lval::DeclVal>(*this) == cast<lval::DeclVal>(RHS);
|
||||
return NonLValue::GetIntTruthValue(ValMgr, b);
|
||||
}
|
||||
if (isa<lval::DeclVal>(R)) {
|
||||
bool b = cast<lval::DeclVal>(*this) == cast<lval::DeclVal>(R);
|
||||
return NonLVal::MakeIntTruthVal(ValMgr, b);
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
return NonLValue::GetIntTruthValue(ValMgr, true);
|
||||
return NonLVal::MakeIntTruthVal(ValMgr, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Utility methods for constructing Non-LValues.
|
||||
// Utility methods for constructing Non-LVals.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
NonLValue NonLValue::GetValue(ValueManager& ValMgr, uint64_t X, QualType T,
|
||||
SourceLocation Loc) {
|
||||
|
||||
NonLVal NonLVal::MakeVal(ValueManager& ValMgr, uint64_t X, QualType T,
|
||||
SourceLocation Loc) {
|
||||
|
||||
return nonlval::ConcreteInt(ValMgr.getValue(X, T, Loc));
|
||||
}
|
||||
|
||||
NonLValue NonLValue::GetValue(ValueManager& ValMgr, IntegerLiteral* I) {
|
||||
NonLVal NonLVal::MakeVal(ValueManager& ValMgr, IntegerLiteral* I) {
|
||||
|
||||
return nonlval::ConcreteInt(ValMgr.getValue(APSInt(I->getValue(),
|
||||
I->getType()->isUnsignedIntegerType())));
|
||||
I->getType()->isUnsignedIntegerType())));
|
||||
}
|
||||
|
||||
NonLValue NonLValue::GetIntTruthValue(ValueManager& ValMgr, bool b) {
|
||||
NonLVal NonLVal::MakeIntTruthVal(ValueManager& ValMgr, bool b) {
|
||||
|
||||
return nonlval::ConcreteInt(ValMgr.getTruthValue(b));
|
||||
}
|
||||
|
||||
RValue RValue::GetSymbolValue(SymbolManager& SymMgr, ParmVarDecl* D) {
|
||||
RVal RVal::GetSymbolValue(SymbolManager& SymMgr, ParmVarDecl* D) {
|
||||
|
||||
QualType T = D->getType();
|
||||
|
||||
if (T->isPointerType() || T->isReferenceType())
|
||||
|
@ -236,68 +225,66 @@ RValue RValue::GetSymbolValue(SymbolManager& SymMgr, ParmVarDecl* D) {
|
|||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Utility methods for constructing LValues.
|
||||
// Utility methods for constructing LVals.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
LValue LValue::GetValue(AddrLabelExpr* E) {
|
||||
return lval::GotoLabel(E->getLabel());
|
||||
}
|
||||
LVal LVal::MakeVal(AddrLabelExpr* E) { return lval::GotoLabel(E->getLabel()); }
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Pretty-Printing.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void RValue::printStdErr() const {
|
||||
print(*llvm::cerr.stream());
|
||||
}
|
||||
void RVal::printStdErr() const { print(*llvm::cerr.stream()); }
|
||||
|
||||
void RVal::print(std::ostream& Out) const {
|
||||
|
||||
void RValue::print(std::ostream& Out) const {
|
||||
switch (getBaseKind()) {
|
||||
|
||||
case UnknownKind:
|
||||
Out << "Invalid";
|
||||
break;
|
||||
Out << "Invalid"; break;
|
||||
|
||||
case NonLValueKind:
|
||||
cast<NonLValue>(this)->print(Out);
|
||||
break;
|
||||
case NonLValKind:
|
||||
cast<NonLVal>(this)->print(Out); break;
|
||||
|
||||
case LValueKind:
|
||||
cast<LValue>(this)->print(Out);
|
||||
break;
|
||||
case LValKind:
|
||||
cast<LVal>(this)->print(Out); break;
|
||||
|
||||
case UninitializedKind:
|
||||
Out << "Uninitialized";
|
||||
break;
|
||||
Out << "Uninitialized"; break;
|
||||
|
||||
default:
|
||||
assert (false && "Invalid RValue.");
|
||||
assert (false && "Invalid RVal.");
|
||||
}
|
||||
}
|
||||
|
||||
static void printOpcode(std::ostream& Out, BinaryOperator::Opcode Op) {
|
||||
switch (Op) {
|
||||
case BinaryOperator::Mul: Out << "*"; break;
|
||||
case BinaryOperator::Div: Out << "/"; break;
|
||||
case BinaryOperator::Rem: Out << "%" ; break;
|
||||
case BinaryOperator::Add: Out << "+" ; break;
|
||||
case BinaryOperator::Sub: Out << "-" ; break;
|
||||
|
||||
switch (Op) {
|
||||
case BinaryOperator::Mul: Out << '*' ; break;
|
||||
case BinaryOperator::Div: Out << '/' ; break;
|
||||
case BinaryOperator::Rem: Out << '%' ; break;
|
||||
case BinaryOperator::Add: Out << '+' ; break;
|
||||
case BinaryOperator::Sub: Out << '-' ; break;
|
||||
case BinaryOperator::Shl: Out << "<<" ; break;
|
||||
case BinaryOperator::Shr: Out << ">>" ; break;
|
||||
case BinaryOperator::LT: Out << "<" ; break;
|
||||
case BinaryOperator::GT: Out << ">" ; break;
|
||||
case BinaryOperator::LE: Out << "<=" ; break;
|
||||
case BinaryOperator::GE: Out << ">=" ; break;
|
||||
case BinaryOperator::EQ: Out << "=="; break;
|
||||
case BinaryOperator::NE: Out << "!="; break;
|
||||
case BinaryOperator::And: Out << "&" ; break;
|
||||
case BinaryOperator::Xor: Out << "^" ; break;
|
||||
case BinaryOperator::Or: Out << "|" ; break;
|
||||
case BinaryOperator::LT: Out << "<" ; break;
|
||||
case BinaryOperator::GT: Out << '>' ; break;
|
||||
case BinaryOperator::LE: Out << "<=" ; break;
|
||||
case BinaryOperator::GE: Out << ">=" ; break;
|
||||
case BinaryOperator::EQ: Out << "==" ; break;
|
||||
case BinaryOperator::NE: Out << "!=" ; break;
|
||||
case BinaryOperator::And: Out << '&' ; break;
|
||||
case BinaryOperator::Xor: Out << '^' ; break;
|
||||
case BinaryOperator::Or: Out << '|' ; break;
|
||||
|
||||
default: assert(false && "Not yet implemented.");
|
||||
}
|
||||
}
|
||||
|
||||
void NonLValue::print(std::ostream& Out) const {
|
||||
void NonLVal::print(std::ostream& Out) const {
|
||||
|
||||
switch (getSubKind()) {
|
||||
|
||||
case nonlval::ConcreteIntKind:
|
||||
Out << cast<nonlval::ConcreteInt>(this)->getValue().toString();
|
||||
|
||||
|
@ -325,17 +312,18 @@ void NonLValue::print(std::ostream& Out) const {
|
|||
}
|
||||
|
||||
default:
|
||||
assert (false && "Pretty-printed not implemented for this NonLValue.");
|
||||
assert (false && "Pretty-printed not implemented for this NonLVal.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LValue::print(std::ostream& Out) const {
|
||||
void LVal::print(std::ostream& Out) const {
|
||||
|
||||
switch (getSubKind()) {
|
||||
|
||||
case lval::ConcreteIntKind:
|
||||
Out << cast<lval::ConcreteInt>(this)->getValue().toString()
|
||||
<< " (LValue)";
|
||||
<< " (LVal)";
|
||||
break;
|
||||
|
||||
case lval::SymbolValKind:
|
||||
|
@ -358,8 +346,7 @@ void LValue::print(std::ostream& Out) const {
|
|||
break;
|
||||
|
||||
default:
|
||||
assert (false && "Pretty-printed not implemented for this LValue.");
|
||||
assert (false && "Pretty-printing not implemented for this LVal.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,18 +17,16 @@
|
|||
using namespace clang;
|
||||
|
||||
bool ValueState::isNotEqual(SymbolID sym, const llvm::APSInt& V) const {
|
||||
// First, retrieve the NE-set associated with the given symbol.
|
||||
ConstantNotEqTy::TreeTy* T = Data->ConstantNotEq.SlimFind(sym);
|
||||
|
||||
if (!T)
|
||||
return false;
|
||||
|
||||
// Second, see if V is present in the NE-set.
|
||||
return T->getValue().second.contains(&V);
|
||||
|
||||
// Retrieve the NE-set associated with the given symbol.
|
||||
ConstNotEqTy::TreeTy* T = Data->ConstNotEq.SlimFind(sym);
|
||||
|
||||
// See if V is present in the NE-set.
|
||||
return T ? T->getValue().second.contains(&V) : false;
|
||||
}
|
||||
|
||||
const llvm::APSInt* ValueState::getSymVal(SymbolID sym) const {
|
||||
ConstantEqTy::TreeTy* T = Data->ConstantEq.SlimFind(sym);
|
||||
ConstEqTy::TreeTy* T = Data->ConstEq.SlimFind(sym);
|
||||
return T ? T->getValue().second : NULL;
|
||||
}
|
||||
|
||||
|
@ -53,21 +51,23 @@ ValueStateManager::RemoveDeadBindings(ValueState St, Stmt* Loc,
|
|||
NewSt.SubExprBindings = EXFactory.GetEmptyMap();
|
||||
|
||||
// Iterate over the block-expr bindings.
|
||||
for (ValueState::beb_iterator I=St.beb_begin(), E=St.beb_end(); I!=E ; ++I) {
|
||||
|
||||
|
||||
for (ValueState::beb_iterator I = St.beb_begin(), E = St.beb_end();
|
||||
I!=E ; ++I) {
|
||||
Expr* BlkExpr = I.getKey();
|
||||
|
||||
if (Liveness.isLive(Loc, BlkExpr)) {
|
||||
RValue X = I.getData();
|
||||
RVal X = I.getData();
|
||||
|
||||
if (isa<lval::DeclVal>(X)) {
|
||||
lval::DeclVal LV = cast<lval::DeclVal>(X);
|
||||
WList.push_back(LV.getDecl());
|
||||
}
|
||||
|
||||
for (RValue::symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end();
|
||||
SI != SE; ++SI)
|
||||
MarkedSymbols.insert(*SI);
|
||||
for (RVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end();
|
||||
SI != SE; ++SI) {
|
||||
MarkedSymbols.insert(*SI);
|
||||
}
|
||||
}
|
||||
else
|
||||
NewSt.BlockExprBindings = Remove(NewSt, BlkExpr);
|
||||
|
@ -76,12 +76,15 @@ ValueStateManager::RemoveDeadBindings(ValueState St, Stmt* Loc,
|
|||
}
|
||||
|
||||
// Iterate over the variable bindings.
|
||||
|
||||
for (ValueState::vb_iterator I = St.vb_begin(), E = St.vb_end(); I!=E ; ++I)
|
||||
if (Liveness.isLive(Loc, I.getKey()))
|
||||
WList.push_back(I.getKey());
|
||||
|
||||
|
||||
// Perform the mark-and-sweep.
|
||||
|
||||
while (!WList.empty()) {
|
||||
|
||||
ValueDecl* V = WList.back();
|
||||
WList.pop_back();
|
||||
|
||||
|
@ -91,12 +94,13 @@ ValueStateManager::RemoveDeadBindings(ValueState St, Stmt* Loc,
|
|||
Marked.insert(V);
|
||||
|
||||
if (V->getType()->isPointerType()) {
|
||||
const LValue& LV =
|
||||
cast<LValue>(GetValue(St, lval::DeclVal(cast<VarDecl>(V))));
|
||||
const LVal& LV =
|
||||
cast<LVal>(GetRVal(St, lval::DeclVal(cast<VarDecl>(V))));
|
||||
|
||||
for (RValue::symbol_iterator SI=LV.symbol_begin(), SE=LV.symbol_end();
|
||||
SI != SE; ++SI)
|
||||
MarkedSymbols.insert(*SI);
|
||||
for (RVal::symbol_iterator SI = LV.symbol_begin(), SE = LV.symbol_end();
|
||||
SI != SE; ++SI) {
|
||||
MarkedSymbols.insert(*SI);
|
||||
}
|
||||
|
||||
if (!isa<lval::DeclVal>(LV))
|
||||
continue;
|
||||
|
@ -114,18 +118,18 @@ ValueStateManager::RemoveDeadBindings(ValueState St, Stmt* Loc,
|
|||
// Remove dead symbols.
|
||||
for (ValueState::ce_iterator I = St.ce_begin(), E=St.ce_end(); I!=E; ++I)
|
||||
if (!MarkedSymbols.count(I.getKey()))
|
||||
NewSt.ConstantEq = CEFactory.Remove(NewSt.ConstantEq, I.getKey());
|
||||
NewSt.ConstEq = CEFactory.Remove(NewSt.ConstEq, I.getKey());
|
||||
|
||||
for (ValueState::cne_iterator I = St.cne_begin(), E=St.cne_end(); I!=E; ++I)
|
||||
if (!MarkedSymbols.count(I.getKey()))
|
||||
NewSt.ConstantNotEq = CNEFactory.Remove(NewSt.ConstantNotEq, I.getKey());
|
||||
NewSt.ConstNotEq = CNEFactory.Remove(NewSt.ConstNotEq, I.getKey());
|
||||
|
||||
return getPersistentState(NewSt);
|
||||
}
|
||||
|
||||
|
||||
RValue ValueStateManager::GetValue(ValueState St, const LValue& LV,
|
||||
QualType* T) {
|
||||
RVal ValueStateManager::GetRVal(ValueState St, const LVal& LV, QualType T) {
|
||||
|
||||
if (isa<UnknownVal>(LV))
|
||||
return UnknownVal();
|
||||
|
||||
|
@ -134,27 +138,25 @@ RValue ValueStateManager::GetValue(ValueState St, const LValue& LV,
|
|||
switch (LV.getSubKind()) {
|
||||
case lval::DeclValKind: {
|
||||
ValueState::VarBindingsTy::TreeTy* T =
|
||||
// FIXME: We should make lval::DeclVal only contain VarDecl
|
||||
St->VarBindings.SlimFind(
|
||||
cast<VarDecl>(cast<lval::DeclVal>(LV).getDecl()));
|
||||
St->VarBindings.SlimFind(cast<lval::DeclVal>(LV).getDecl());
|
||||
|
||||
return T ? T->getValue().second : UnknownVal();
|
||||
}
|
||||
|
||||
// FIXME: We should bind how far a "ContentsOf" will go...
|
||||
// FIXME: We should limit how far a "ContentsOf" will go...
|
||||
|
||||
case lval::SymbolValKind: {
|
||||
const lval::SymbolVal& SV = cast<lval::SymbolVal>(LV);
|
||||
assert (T);
|
||||
assert (T.getTypePtr());
|
||||
|
||||
if (T->getTypePtr()->isPointerType())
|
||||
if (T.getTypePtr()->isPointerType())
|
||||
return lval::SymbolVal(SymMgr.getContentsOfSymbol(SV.getSymbol()));
|
||||
else
|
||||
return nonlval::SymbolVal(SymMgr.getContentsOfSymbol(SV.getSymbol()));
|
||||
}
|
||||
|
||||
default:
|
||||
assert (false && "Invalid LValue.");
|
||||
assert (false && "Invalid LVal.");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -163,18 +165,17 @@ RValue ValueStateManager::GetValue(ValueState St, const LValue& LV,
|
|||
|
||||
ValueState
|
||||
ValueStateManager::AddNE(ValueState St, SymbolID sym, const llvm::APSInt& V) {
|
||||
|
||||
// First, retrieve the NE-set associated with the given symbol.
|
||||
ValueState::ConstantNotEqTy::TreeTy* T = St->ConstantNotEq.SlimFind(sym);
|
||||
|
||||
ValueState::ConstNotEqTy::TreeTy* T = St->ConstNotEq.SlimFind(sym);
|
||||
ValueState::IntSetTy S = T ? T->getValue().second : ISetFactory.GetEmptySet();
|
||||
|
||||
// Now add V to the NE set.
|
||||
// Now add V to the NE set.
|
||||
S = ISetFactory.Add(S, &V);
|
||||
|
||||
// Create a new state with the old binding replaced.
|
||||
ValueStateImpl NewSt = *St;
|
||||
NewSt.ConstantNotEq = CNEFactory.Add(NewSt.ConstantNotEq,
|
||||
sym, S);
|
||||
NewSt.ConstNotEq = CNEFactory.Add(NewSt.ConstNotEq, sym, S);
|
||||
|
||||
// Get the persistent copy.
|
||||
return getPersistentState(NewSt);
|
||||
|
@ -182,43 +183,49 @@ ValueStateManager::AddNE(ValueState St, SymbolID sym, const llvm::APSInt& V) {
|
|||
|
||||
ValueState
|
||||
ValueStateManager::AddEQ(ValueState St, SymbolID sym, const llvm::APSInt& V) {
|
||||
|
||||
// Create a new state with the old binding replaced.
|
||||
ValueStateImpl NewSt = *St;
|
||||
NewSt.ConstantEq = CEFactory.Add(NewSt.ConstantEq, sym, &V);
|
||||
NewSt.ConstEq = CEFactory.Add(NewSt.ConstEq, sym, &V);
|
||||
|
||||
// Get the persistent copy.
|
||||
return getPersistentState(NewSt);
|
||||
}
|
||||
|
||||
RValue ValueStateManager::GetValue(ValueState St, Expr* E, bool* hasVal) {
|
||||
RVal ValueStateManager::GetRVal(ValueState St, Expr* E, bool* hasVal) {
|
||||
|
||||
for (;;) {
|
||||
|
||||
switch (E->getStmtClass()) {
|
||||
|
||||
case Stmt::AddrLabelExprClass:
|
||||
return LValue::GetValue(cast<AddrLabelExpr>(E));
|
||||
case Stmt::AddrLabelExprClass:
|
||||
return LVal::MakeVal(cast<AddrLabelExpr>(E));
|
||||
|
||||
// ParenExprs are no-ops.
|
||||
|
||||
case Stmt::ParenExprClass:
|
||||
case Stmt::ParenExprClass:
|
||||
E = cast<ParenExpr>(E)->getSubExpr();
|
||||
continue;
|
||||
|
||||
// DeclRefExprs can either evaluate to an LValue or a Non-LValue
|
||||
// DeclRefExprs can either evaluate to an LVal or a Non-LVal
|
||||
// (assuming an implicit "load") depending on the context. In this
|
||||
// context we assume that we are retrieving the value contained
|
||||
// within the referenced variables.
|
||||
|
||||
case Stmt::DeclRefExprClass: {
|
||||
|
||||
ValueDecl* D = cast<DeclRefExpr>(E)->getDecl();
|
||||
|
||||
if (VarDecl* VD = dyn_cast<VarDecl>(D))
|
||||
return GetValue(St, lval::DeclVal(VD));
|
||||
if (VarDecl* VD = dyn_cast<VarDecl>(D)) {
|
||||
return GetRVal(St, lval::DeclVal(VD));
|
||||
}
|
||||
else if (EnumConstantDecl* ED = dyn_cast<EnumConstantDecl>(D)) {
|
||||
|
||||
// FIXME: Do we need to cache a copy of this enum, since it
|
||||
// already has persistent storage? We do this because we
|
||||
// are comparing states using pointer equality. Perhaps there is
|
||||
// a better way, since APInts are fairly lightweight.
|
||||
return nonlval::ConcreteInt(ValMgr.getValue(ED->getInitVal()));
|
||||
return nonlval::ConcreteInt(ValMgr.getValue(ED->getInitVal()));
|
||||
}
|
||||
else if (FunctionDecl* FD = dyn_cast<FunctionDecl>(D))
|
||||
return lval::FuncVal(FD);
|
||||
|
@ -228,28 +235,13 @@ RValue ValueStateManager::GetValue(ValueState St, Expr* E, bool* hasVal) {
|
|||
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
|
||||
// Integer literals evaluate to an RValue. Simply retrieve the
|
||||
// RValue for the literal.
|
||||
#if 0
|
||||
case Stmt::IntegerLiteralClass:
|
||||
return NonLValue::GetValue(ValMgr, cast<IntegerLiteral>(E));
|
||||
|
||||
case Stmt::CharacterLiteralClass: {
|
||||
CharacterLiteral* C = cast<CharacterLiteral>(E);
|
||||
|
||||
return NonLValue::GetValue(ValMgr, C->getValue(), C->getType(),
|
||||
C->getLoc());
|
||||
}
|
||||
#endif
|
||||
|
||||
// Casts where the source and target type are the same
|
||||
// are no-ops. We blast through these to get the descendant
|
||||
// subexpression that has a value.
|
||||
|
||||
|
||||
case Stmt::ImplicitCastExprClass: {
|
||||
|
||||
ImplicitCastExpr* C = cast<ImplicitCastExpr>(E);
|
||||
QualType CT = C->getType();
|
||||
|
||||
|
@ -262,6 +254,7 @@ RValue ValueStateManager::GetValue(ValueState St, Expr* E, bool* hasVal) {
|
|||
E = C->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -277,10 +270,23 @@ RValue ValueStateManager::GetValue(ValueState St, Expr* E, bool* hasVal) {
|
|||
E = C->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle all other Stmt* using a lookup.
|
||||
case Stmt::UnaryOperatorClass: {
|
||||
|
||||
UnaryOperator* U = cast<UnaryOperator>(E);
|
||||
|
||||
if (U->getOpcode() == UnaryOperator::Plus) {
|
||||
E = U->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle all other Expr* using a lookup.
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -308,7 +314,7 @@ RValue ValueStateManager::GetValue(ValueState St, Expr* E, bool* hasVal) {
|
|||
}
|
||||
}
|
||||
|
||||
LValue ValueStateManager::GetLValue(ValueState St, Expr* E) {
|
||||
RVal ValueStateManager::GetLVal(ValueState St, Expr* E) {
|
||||
|
||||
E = E->IgnoreParens();
|
||||
|
||||
|
@ -327,18 +333,17 @@ LValue ValueStateManager::GetLValue(ValueState St, Expr* E) {
|
|||
|
||||
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E)) {
|
||||
lval::DeclVal X(cast<VarDecl>(DR->getDecl()));
|
||||
return cast<LValue>(GetValue(St, X));
|
||||
return GetRVal(St, X);
|
||||
}
|
||||
else
|
||||
return cast<LValue>(GetValue(St, E));
|
||||
return GetRVal(St, E);
|
||||
}
|
||||
|
||||
return cast<LValue>(GetValue(St, E));
|
||||
return GetRVal(St, E);
|
||||
}
|
||||
|
||||
ValueState
|
||||
ValueStateManager::SetValue(ValueState St, Expr* E, bool isBlkExpr,
|
||||
const RValue& V) {
|
||||
ValueStateManager::SetRVal(ValueState St, Expr* E, bool isBlkExpr, RVal V) {
|
||||
|
||||
assert (E);
|
||||
|
||||
|
@ -347,36 +352,33 @@ ValueStateManager::SetValue(ValueState St, Expr* E, bool isBlkExpr,
|
|||
|
||||
ValueStateImpl NewSt = *St;
|
||||
|
||||
if (isBlkExpr)
|
||||
if (isBlkExpr) {
|
||||
NewSt.BlockExprBindings = EXFactory.Add(NewSt.BlockExprBindings, E, V);
|
||||
else
|
||||
}
|
||||
else {
|
||||
NewSt.SubExprBindings = EXFactory.Add(NewSt.SubExprBindings, E, V);
|
||||
}
|
||||
|
||||
return getPersistentState(NewSt);
|
||||
}
|
||||
|
||||
ValueState
|
||||
ValueStateManager::SetValue(ValueState St, const LValue& LV, const RValue& V) {
|
||||
ValueStateManager::SetRVal(ValueState St, LVal LV, RVal V) {
|
||||
|
||||
if (isa<UnknownVal>(LV))
|
||||
return St;
|
||||
|
||||
assert (!isa<UninitializedVal>(LV));
|
||||
|
||||
switch (LV.getSubKind()) {
|
||||
|
||||
case lval::DeclValKind:
|
||||
return V.isKnown() // FIXME: Have DeclVal only contain VarDecl
|
||||
? BindVar(St, cast<VarDecl>(cast<lval::DeclVal>(LV).getDecl()), V)
|
||||
: UnbindVar(St, cast<VarDecl>(cast<lval::DeclVal>(LV).getDecl()));
|
||||
return V.isUnknown()
|
||||
? UnbindVar(St, cast<lval::DeclVal>(LV).getDecl())
|
||||
: BindVar(St, cast<lval::DeclVal>(LV).getDecl(), V);
|
||||
|
||||
default:
|
||||
assert ("SetValue for given LValue type not yet implemented.");
|
||||
assert ("SetRVal for given LVal type not yet implemented.");
|
||||
return St;
|
||||
}
|
||||
}
|
||||
|
||||
ValueState
|
||||
ValueStateManager::BindVar(ValueState St, VarDecl* D, const RValue& V) {
|
||||
ValueState ValueStateManager::BindVar(ValueState St, VarDecl* D, RVal V) {
|
||||
|
||||
// Create a new state with the old binding removed.
|
||||
ValueStateImpl NewSt = *St;
|
||||
|
@ -386,8 +388,7 @@ ValueStateManager::BindVar(ValueState St, VarDecl* D, const RValue& V) {
|
|||
return getPersistentState(NewSt);
|
||||
}
|
||||
|
||||
ValueState
|
||||
ValueStateManager::UnbindVar(ValueState St, VarDecl* D) {
|
||||
ValueState ValueStateManager::UnbindVar(ValueState St, VarDecl* D) {
|
||||
|
||||
// Create a new state with the old binding removed.
|
||||
ValueStateImpl NewSt = *St;
|
||||
|
@ -397,8 +398,7 @@ ValueStateManager::UnbindVar(ValueState St, VarDecl* D) {
|
|||
return getPersistentState(NewSt);
|
||||
}
|
||||
|
||||
ValueState
|
||||
ValueStateManager::getInitialState() {
|
||||
ValueState ValueStateManager::getInitialState() {
|
||||
|
||||
// Create a state with empty variable bindings.
|
||||
ValueStateImpl StateImpl(EXFactory.GetEmptyMap(),
|
||||
|
@ -409,8 +409,7 @@ ValueStateManager::getInitialState() {
|
|||
return getPersistentState(StateImpl);
|
||||
}
|
||||
|
||||
ValueState
|
||||
ValueStateManager::getPersistentState(const ValueStateImpl &State) {
|
||||
ValueState ValueStateManager::getPersistentState(const ValueStateImpl &State) {
|
||||
|
||||
llvm::FoldingSetNodeID ID;
|
||||
State.Profile(ID);
|
||||
|
@ -426,17 +425,16 @@ ValueStateManager::getPersistentState(const ValueStateImpl &State) {
|
|||
}
|
||||
|
||||
void ValueState::printDOT(std::ostream& Out) const {
|
||||
|
||||
// Print Variable Bindings
|
||||
Out << "Variables:\\l";
|
||||
|
||||
bool isFirst = true;
|
||||
|
||||
for (vb_iterator I=vb_begin(), E=vb_end(); I!=E; ++I) {
|
||||
for (vb_iterator I = vb_begin(), E = vb_end(); I != E; ++I) {
|
||||
|
||||
if (isFirst)
|
||||
isFirst = false;
|
||||
else
|
||||
Out << "\\l";
|
||||
if (isFirst) isFirst = false;
|
||||
else Out << "\\l";
|
||||
|
||||
Out << ' ' << I.getKey()->getName() << " : ";
|
||||
I.getData().print(Out);
|
||||
|
@ -446,14 +444,13 @@ void ValueState::printDOT(std::ostream& Out) const {
|
|||
|
||||
isFirst = true;
|
||||
|
||||
for (seb_iterator I=seb_begin(), E=seb_end(); I != E;++I) {
|
||||
for (seb_iterator I = seb_begin(), E = seb_end(); I != E; ++I) {
|
||||
|
||||
if (isFirst) {
|
||||
Out << "\\l\\lSub-Expressions:\\l";
|
||||
isFirst = false;
|
||||
}
|
||||
else
|
||||
Out << "\\l";
|
||||
else { Out << "\\l"; }
|
||||
|
||||
Out << " (" << (void*) I.getKey() << ") ";
|
||||
I.getKey()->printPretty(Out);
|
||||
|
@ -465,14 +462,13 @@ void ValueState::printDOT(std::ostream& Out) const {
|
|||
|
||||
isFirst = true;
|
||||
|
||||
for (beb_iterator I=beb_begin(), E=beb_end(); I != E; ++I) {
|
||||
for (beb_iterator I = beb_begin(), E = beb_end(); I != E; ++I) {
|
||||
|
||||
if (isFirst) {
|
||||
Out << "\\l\\lBlock-level Expressions:\\l";
|
||||
isFirst = false;
|
||||
}
|
||||
else
|
||||
Out << "\\l";
|
||||
else { Out << "\\l"; }
|
||||
|
||||
Out << " (" << (void*) I.getKey() << ") ";
|
||||
I.getKey()->printPretty(Out);
|
||||
|
@ -482,29 +478,31 @@ void ValueState::printDOT(std::ostream& Out) const {
|
|||
|
||||
// Print equality constraints.
|
||||
|
||||
if (!Data->ConstantEq.isEmpty()) {
|
||||
if (!Data->ConstEq.isEmpty()) {
|
||||
|
||||
Out << "\\l\\|'==' constraints:";
|
||||
|
||||
for (ConstantEqTy::iterator I=Data->ConstantEq.begin(),
|
||||
E=Data->ConstantEq.end(); I!=E;++I)
|
||||
Out << "\\l $" << I.getKey() << " : " << I.getData()->toString();
|
||||
for (ConstEqTy::iterator I = Data->ConstEq.begin(),
|
||||
E = Data->ConstEq.end(); I!=E; ++I) {
|
||||
|
||||
Out << "\\l $" << I.getKey()
|
||||
<< " : " << I.getData()->toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Print != constraints.
|
||||
|
||||
if (!Data->ConstantNotEq.isEmpty()) {
|
||||
if (!Data->ConstNotEq.isEmpty()) {
|
||||
|
||||
Out << "\\l\\|'!=' constraints:";
|
||||
|
||||
for (ConstantNotEqTy::iterator I=Data->ConstantNotEq.begin(),
|
||||
EI=Data->ConstantNotEq.end(); I != EI; ++I) {
|
||||
for (ConstNotEqTy::iterator I = Data->ConstNotEq.begin(),
|
||||
EI = Data->ConstNotEq.end(); I != EI; ++I) {
|
||||
|
||||
Out << "\\l $" << I.getKey() << " : ";
|
||||
isFirst = true;
|
||||
|
||||
IntSetTy::iterator J=I.getData().begin(), EJ=I.getData().end();
|
||||
IntSetTy::iterator J = I.getData().begin(), EJ = I.getData().end();
|
||||
|
||||
for ( ; J != EJ; ++J) {
|
||||
if (isFirst) isFirst = false;
|
||||
|
|
|
@ -39,16 +39,16 @@
|
|||
namespace clang {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ValueState - An ImmutableMap type Stmt*/Decl*/Symbols to RValues.
|
||||
// ValueState - An ImmutableMap type Stmt*/Decl*/Symbols to RVals.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace vstate {
|
||||
typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy;
|
||||
|
||||
typedef llvm::ImmutableMap<Expr*,RValue> ExprBindingsTy;
|
||||
typedef llvm::ImmutableMap<VarDecl*,RValue> VarBindingsTy;
|
||||
typedef llvm::ImmutableMap<SymbolID,IntSetTy> ConstantNotEqTy;
|
||||
typedef llvm::ImmutableMap<SymbolID,const llvm::APSInt*> ConstantEqTy;
|
||||
typedef llvm::ImmutableMap<Expr*,RVal> ExprBindingsTy;
|
||||
typedef llvm::ImmutableMap<VarDecl*,RVal> VarBindingsTy;
|
||||
typedef llvm::ImmutableMap<SymbolID,IntSetTy> ConstNotEqTy;
|
||||
typedef llvm::ImmutableMap<SymbolID,const llvm::APSInt*> ConstEqTy;
|
||||
}
|
||||
|
||||
/// ValueStateImpl - This class encapsulates the actual data values for
|
||||
|
@ -63,19 +63,17 @@ public:
|
|||
vstate::ExprBindingsTy SubExprBindings;
|
||||
vstate::ExprBindingsTy BlockExprBindings;
|
||||
vstate::VarBindingsTy VarBindings;
|
||||
vstate::ConstantNotEqTy ConstantNotEq;
|
||||
vstate::ConstantEqTy ConstantEq;
|
||||
vstate::ConstNotEqTy ConstNotEq;
|
||||
vstate::ConstEqTy ConstEq;
|
||||
|
||||
/// This ctor is used when creating the first ValueStateImpl object.
|
||||
ValueStateImpl(vstate::ExprBindingsTy EB,
|
||||
vstate::VarBindingsTy VB,
|
||||
vstate::ConstantNotEqTy CNE,
|
||||
vstate::ConstantEqTy CE)
|
||||
ValueStateImpl(vstate::ExprBindingsTy EB, vstate::VarBindingsTy VB,
|
||||
vstate::ConstNotEqTy CNE, vstate::ConstEqTy CE)
|
||||
: SubExprBindings(EB),
|
||||
BlockExprBindings(EB),
|
||||
VarBindings(VB),
|
||||
ConstantNotEq(CNE),
|
||||
ConstantEq(CE) {}
|
||||
ConstNotEq(CNE),
|
||||
ConstEq(CE) {}
|
||||
|
||||
/// Copy ctor - We must explicitly define this or else the "Next" ptr
|
||||
/// in FoldingSetNode will also get copied.
|
||||
|
@ -84,10 +82,8 @@ public:
|
|||
SubExprBindings(RHS.SubExprBindings),
|
||||
BlockExprBindings(RHS.BlockExprBindings),
|
||||
VarBindings(RHS.VarBindings),
|
||||
ConstantNotEq(RHS.ConstantNotEq),
|
||||
ConstantEq(RHS.ConstantEq) {}
|
||||
|
||||
|
||||
ConstNotEq(RHS.ConstNotEq),
|
||||
ConstEq(RHS.ConstEq) {}
|
||||
|
||||
/// Profile - Profile the contents of a ValueStateImpl object for use
|
||||
/// in a FoldingSet.
|
||||
|
@ -95,8 +91,8 @@ public:
|
|||
V.SubExprBindings.Profile(ID);
|
||||
V.BlockExprBindings.Profile(ID);
|
||||
V.VarBindings.Profile(ID);
|
||||
V.ConstantNotEq.Profile(ID);
|
||||
V.ConstantEq.Profile(ID);
|
||||
V.ConstNotEq.Profile(ID);
|
||||
V.ConstEq.Profile(ID);
|
||||
}
|
||||
|
||||
/// Profile - Used to profile the contents of this object for inclusion
|
||||
|
@ -129,8 +125,8 @@ public:
|
|||
typedef vstate::IntSetTy IntSetTy;
|
||||
typedef vstate::ExprBindingsTy ExprBindingsTy;
|
||||
typedef vstate::VarBindingsTy VarBindingsTy;
|
||||
typedef vstate::ConstantNotEqTy ConstantNotEqTy;
|
||||
typedef vstate::ConstantEqTy ConstantEqTy;
|
||||
typedef vstate::ConstNotEqTy ConstNotEqTy;
|
||||
typedef vstate::ConstEqTy ConstEqTy;
|
||||
|
||||
typedef llvm::SmallVector<ValueState,5> BufferTy;
|
||||
|
||||
|
@ -153,13 +149,13 @@ public:
|
|||
beb_iterator beb_begin() const { return Data->BlockExprBindings.begin(); }
|
||||
beb_iterator beb_end() const { return Data->BlockExprBindings.end(); }
|
||||
|
||||
typedef ConstantNotEqTy::iterator cne_iterator;
|
||||
cne_iterator cne_begin() const { return Data->ConstantNotEq.begin(); }
|
||||
cne_iterator cne_end() const { return Data->ConstantNotEq.end(); }
|
||||
typedef ConstNotEqTy::iterator cne_iterator;
|
||||
cne_iterator cne_begin() const { return Data->ConstNotEq.begin(); }
|
||||
cne_iterator cne_end() const { return Data->ConstNotEq.end(); }
|
||||
|
||||
typedef ConstantEqTy::iterator ce_iterator;
|
||||
ce_iterator ce_begin() const { return Data->ConstantEq.begin(); }
|
||||
ce_iterator ce_end() const { return Data->ConstantEq.end(); }
|
||||
typedef ConstEqTy::iterator ce_iterator;
|
||||
ce_iterator ce_begin() const { return Data->ConstEq.begin(); }
|
||||
ce_iterator ce_end() const { return Data->ConstEq.end(); }
|
||||
|
||||
// Profiling and equality testing.
|
||||
|
||||
|
@ -177,7 +173,7 @@ public:
|
|||
|
||||
void printDOT(std::ostream& Out) const;
|
||||
void print(std::ostream& Out) const;
|
||||
void print() const { print(*llvm::cerr); }
|
||||
void printStdErr() const { print(*llvm::cerr); }
|
||||
|
||||
};
|
||||
|
||||
|
@ -188,25 +184,24 @@ template<> struct GRTrait<ValueState> {
|
|||
static inline ValueState toState(void* P) {
|
||||
return ValueState(static_cast<ValueStateImpl*>(P));
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
class ValueStateManager {
|
||||
public:
|
||||
typedef ValueState StateTy;
|
||||
|
||||
private:
|
||||
ValueState::IntSetTy::Factory ISetFactory;
|
||||
ValueState::ExprBindingsTy::Factory EXFactory;
|
||||
ValueState::VarBindingsTy::Factory VBFactory;
|
||||
ValueState::ConstantNotEqTy::Factory CNEFactory;
|
||||
ValueState::ConstantEqTy::Factory CEFactory;
|
||||
ValueState::IntSetTy::Factory ISetFactory;
|
||||
ValueState::ExprBindingsTy::Factory EXFactory;
|
||||
ValueState::VarBindingsTy::Factory VBFactory;
|
||||
ValueState::ConstNotEqTy::Factory CNEFactory;
|
||||
ValueState::ConstEqTy::Factory CEFactory;
|
||||
|
||||
/// StateSet - FoldingSet containing all the states created for analyzing
|
||||
/// a particular function. This is used to unique states.
|
||||
llvm::FoldingSet<ValueStateImpl> StateSet;
|
||||
|
||||
/// ValueMgr - Object that manages the data for all created RValues.
|
||||
/// ValueMgr - Object that manages the data for all created RVals.
|
||||
ValueManager ValMgr;
|
||||
|
||||
/// SymMgr - Object that manages the symbol information.
|
||||
|
@ -233,7 +228,7 @@ private:
|
|||
return Remove(V.VarBindings, D);
|
||||
}
|
||||
|
||||
ValueState BindVar(ValueState St, VarDecl* D, const RValue& V);
|
||||
ValueState BindVar(ValueState St, VarDecl* D, RVal V);
|
||||
ValueState UnbindVar(ValueState St, VarDecl* D);
|
||||
|
||||
public:
|
||||
|
@ -243,7 +238,8 @@ public:
|
|||
VBFactory(alloc),
|
||||
CNEFactory(alloc),
|
||||
CEFactory(alloc),
|
||||
ValMgr(Ctx, alloc), Alloc(alloc) {}
|
||||
ValMgr(Ctx, alloc),
|
||||
Alloc(alloc) {}
|
||||
|
||||
ValueState getInitialState();
|
||||
|
||||
|
@ -258,14 +254,13 @@ public:
|
|||
NewSt.SubExprBindings = EXFactory.GetEmptyMap();
|
||||
return getPersistentState(NewSt);
|
||||
}
|
||||
|
||||
|
||||
ValueState SetValue(ValueState St, Expr* S, bool isBlkExpr, const RValue& V);
|
||||
ValueState SetValue(ValueState St, const LValue& LV, const RValue& V);
|
||||
ValueState SetRVal(ValueState St, Expr* E, bool isBlkExpr, RVal V);
|
||||
ValueState SetRVal(ValueState St, LVal LV, RVal V);
|
||||
|
||||
RValue GetValue(ValueState St, Expr* S, bool* hasVal = NULL);
|
||||
RValue GetValue(ValueState St, const LValue& LV, QualType* T = NULL);
|
||||
LValue GetLValue(ValueState St, Expr* S);
|
||||
RVal GetRVal(ValueState St, Expr* E, bool* hasVal = NULL);
|
||||
RVal GetRVal(ValueState St, const LVal& LV, QualType T = QualType());
|
||||
RVal GetLVal(ValueState St, Expr* E);
|
||||
|
||||
ValueState getPersistentState(const ValueStateImpl& Impl);
|
||||
|
||||
|
|
|
@ -45,37 +45,38 @@ namespace clang {
|
|||
class GRExprEngine {
|
||||
|
||||
public:
|
||||
typedef ValueStateManager::StateTy StateTy;
|
||||
typedef ValueStateManager::StateTy StateTy;
|
||||
typedef ExplodedGraph<GRExprEngine> GraphTy;
|
||||
typedef GraphTy::NodeTy NodeTy;
|
||||
typedef GraphTy::NodeTy NodeTy;
|
||||
|
||||
// Builders.
|
||||
typedef GRStmtNodeBuilder<GRExprEngine> StmtNodeBuilder;
|
||||
typedef GRBranchNodeBuilder<GRExprEngine> BranchNodeBuilder;
|
||||
typedef GRIndirectGotoNodeBuilder<GRExprEngine> IndirectGotoNodeBuilder;
|
||||
typedef GRSwitchNodeBuilder<GRExprEngine> SwitchNodeBuilder;
|
||||
typedef GRStmtNodeBuilder<GRExprEngine> StmtNodeBuilder;
|
||||
typedef GRBranchNodeBuilder<GRExprEngine> BranchNodeBuilder;
|
||||
typedef GRIndirectGotoNodeBuilder<GRExprEngine> IndirectGotoNodeBuilder;
|
||||
typedef GRSwitchNodeBuilder<GRExprEngine> SwitchNodeBuilder;
|
||||
|
||||
class NodeSet {
|
||||
typedef llvm::SmallVector<NodeTy*,3> ImplTy;
|
||||
ImplTy Impl;
|
||||
|
||||
public:
|
||||
|
||||
NodeSet() {}
|
||||
|
||||
NodeSet(NodeTy* N) { assert (N && !N->isSink()); Impl.push_back(N); }
|
||||
NodeSet() {}
|
||||
|
||||
void Add(NodeTy* N) { if (N && !N->isSink()) Impl.push_back(N); }
|
||||
inline void Add(NodeTy* N) { if (N && !N->isSink()) Impl.push_back(N); }
|
||||
|
||||
typedef ImplTy::iterator iterator;
|
||||
typedef ImplTy::const_iterator const_iterator;
|
||||
|
||||
unsigned size() const { return Impl.size(); }
|
||||
bool empty() const { return Impl.empty(); }
|
||||
inline unsigned size() const { return Impl.size(); }
|
||||
inline bool empty() const { return Impl.empty(); }
|
||||
|
||||
iterator begin() { return Impl.begin(); }
|
||||
iterator end() { return Impl.end(); }
|
||||
inline iterator begin() { return Impl.begin(); }
|
||||
inline iterator end() { return Impl.end(); }
|
||||
|
||||
const_iterator begin() const { return Impl.begin(); }
|
||||
const_iterator end() const { return Impl.end(); }
|
||||
inline const_iterator begin() const { return Impl.begin(); }
|
||||
inline const_iterator end() const { return Impl.end(); }
|
||||
};
|
||||
|
||||
protected:
|
||||
|
@ -93,11 +94,11 @@ protected:
|
|||
/// StateMgr - Object that manages the data for all created states.
|
||||
ValueStateManager StateMgr;
|
||||
|
||||
/// ValueMgr - Object that manages the data for all created RValues.
|
||||
/// ValueMgr - Object that manages the data for all created RVals.
|
||||
ValueManager& ValMgr;
|
||||
|
||||
/// TF - Object that represents a bundle of transfer functions
|
||||
/// for manipulating and creating RValues.
|
||||
/// for manipulating and creating RVals.
|
||||
GRTransferFuncs* TF;
|
||||
|
||||
/// SymMgr - Object that manages the symbol information.
|
||||
|
@ -165,9 +166,11 @@ public:
|
|||
// Iterate the parameters.
|
||||
FunctionDecl& F = G.getFunctionDecl();
|
||||
|
||||
for (FunctionDecl::param_iterator I=F.param_begin(), E=F.param_end();
|
||||
I!=E; ++I)
|
||||
St = SetValue(St, lval::DeclVal(*I), RValue::GetSymbolValue(SymMgr, *I));
|
||||
for (FunctionDecl::param_iterator I = F.param_begin(), E = F.param_end();
|
||||
I != E; ++I) {
|
||||
St = SetRVal(St, lval::DeclVal(*I),
|
||||
RVal::GetSymbolValue(SymMgr, *I));
|
||||
}
|
||||
|
||||
return St;
|
||||
}
|
||||
|
@ -220,58 +223,63 @@ public:
|
|||
return StateMgr.RemoveDeadBindings(St, S, Liveness);
|
||||
}
|
||||
|
||||
StateTy SetValue(StateTy St, Expr* S, const RValue& V);
|
||||
StateTy SetRVal(StateTy St, Expr* Ex, const RVal& V);
|
||||
|
||||
StateTy SetValue(StateTy St, const Expr* S, const RValue& V) {
|
||||
return SetValue(St, const_cast<Expr*>(S), V);
|
||||
StateTy SetRVal(StateTy St, const Expr* Ex, const RVal& V) {
|
||||
return SetRVal(St, const_cast<Expr*>(Ex), V);
|
||||
}
|
||||
|
||||
/// SetValue - This version of SetValue is used to batch process a set
|
||||
/// of different possible RValues and return a set of different states.
|
||||
const StateTy::BufferTy& SetValue(StateTy St, Expr* S,
|
||||
const RValue::BufferTy& V,
|
||||
StateTy::BufferTy& RetBuf);
|
||||
/// SetRVal - This version of SetRVal is used to batch process a set
|
||||
/// of different possible RVals and return a set of different states.
|
||||
const StateTy::BufferTy& SetRVal(StateTy St, Expr* Ex,
|
||||
const RVal::BufferTy& V,
|
||||
StateTy::BufferTy& RetBuf);
|
||||
|
||||
StateTy SetValue(StateTy St, const LValue& LV, const RValue& V);
|
||||
StateTy SetRVal(StateTy St, const LVal& LV, const RVal& V);
|
||||
|
||||
inline RValue GetValue(const StateTy& St, Expr* S) {
|
||||
return StateMgr.GetValue(St, S);
|
||||
RVal GetRVal(const StateTy& St, Expr* Ex) {
|
||||
return StateMgr.GetRVal(St, Ex);
|
||||
}
|
||||
|
||||
inline RValue GetValue(const StateTy& St, Expr* S, bool& hasVal) {
|
||||
return StateMgr.GetValue(St, S, &hasVal);
|
||||
RVal GetRVal(const StateTy& St, Expr* Ex, bool& hasVal) {
|
||||
return StateMgr.GetRVal(St, Ex, &hasVal);
|
||||
}
|
||||
|
||||
inline RValue GetValue(const StateTy& St, const Expr* S) {
|
||||
return GetValue(St, const_cast<Expr*>(S));
|
||||
RVal GetRVal(const StateTy& St, const Expr* Ex) {
|
||||
return GetRVal(St, const_cast<Expr*>(Ex));
|
||||
}
|
||||
|
||||
inline RValue GetValue(const StateTy& St, const LValue& LV,
|
||||
QualType* T = NULL) {
|
||||
RVal GetRVal(const StateTy& St, const LVal& LV,
|
||||
QualType T = QualType()) {
|
||||
|
||||
return StateMgr.GetValue(St, LV, T);
|
||||
return StateMgr.GetRVal(St, LV, T);
|
||||
}
|
||||
|
||||
inline LValue GetLValue(const StateTy& St, Expr* S) {
|
||||
return StateMgr.GetLValue(St, S);
|
||||
RVal GetLVal(const StateTy& St, Expr* Ex) {
|
||||
return StateMgr.GetLVal(St, Ex);
|
||||
}
|
||||
|
||||
inline NonLValue GetRValueConstant(uint64_t X, Expr* E) {
|
||||
return NonLValue::GetValue(ValMgr, X, E->getType(), E->getLocStart());
|
||||
inline NonLVal MakeConstantVal(uint64_t X, Expr* Ex) {
|
||||
return NonLVal::MakeVal(ValMgr, X, Ex->getType(), Ex->getLocStart());
|
||||
}
|
||||
|
||||
/// Assume - Create new state by assuming that a given expression
|
||||
/// is true or false.
|
||||
inline StateTy Assume(StateTy St, RValue Cond, bool Assumption,
|
||||
bool& isFeasible) {
|
||||
if (isa<LValue>(Cond))
|
||||
return Assume(St, cast<LValue>(Cond), Assumption, isFeasible);
|
||||
StateTy Assume(StateTy St, RVal Cond, bool Assumption, bool& isFeasible) {
|
||||
|
||||
if (Cond.isUnknown()) {
|
||||
isFeasible = true;
|
||||
return St;
|
||||
}
|
||||
|
||||
if (isa<LVal>(Cond))
|
||||
return Assume(St, cast<LVal>(Cond), Assumption, isFeasible);
|
||||
else
|
||||
return Assume(St, cast<NonLValue>(Cond), Assumption, isFeasible);
|
||||
return Assume(St, cast<NonLVal>(Cond), Assumption, isFeasible);
|
||||
}
|
||||
|
||||
StateTy Assume(StateTy St, LValue Cond, bool Assumption, bool& isFeasible);
|
||||
StateTy Assume(StateTy St, NonLValue Cond, bool Assumption, bool& isFeasible);
|
||||
StateTy Assume(StateTy St, LVal Cond, bool Assumption, bool& isFeasible);
|
||||
StateTy Assume(StateTy St, NonLVal Cond, bool Assumption, bool& isFeasible);
|
||||
|
||||
StateTy AssumeSymNE(StateTy St, SymbolID sym, const llvm::APSInt& V,
|
||||
bool& isFeasible);
|
||||
|
@ -289,7 +297,7 @@ public:
|
|||
void Nodify(NodeSet& Dst, Stmt* S, NodeTy* Pred, const StateTy::BufferTy& SB);
|
||||
|
||||
/// HandleUninitializedStore - Create the necessary sink node to represent
|
||||
/// a store to an "uninitialized" LValue.
|
||||
/// a store to an "uninitialized" LVal.
|
||||
void HandleUninitializedStore(Stmt* S, NodeTy* Pred);
|
||||
|
||||
/// Visit - Transfer function logic for all statements. Dispatches to
|
||||
|
@ -299,15 +307,15 @@ public:
|
|||
/// VisitBinaryOperator - Transfer function logic for binary operators.
|
||||
void VisitBinaryOperator(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
void VisitLValue(Expr* E, NodeTy* Pred, NodeSet& Dst);
|
||||
void VisitLVal(Expr* Ex, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitCall - Transfer function for function calls.
|
||||
void VisitCall(CallExpr* CE, NodeTy* Pred,
|
||||
CallExpr::arg_iterator I, CallExpr::arg_iterator E,
|
||||
CallExpr::arg_iterator AI, CallExpr::arg_iterator AE,
|
||||
NodeSet& Dst);
|
||||
|
||||
/// VisitCast - Transfer function logic for all casts (implicit and explicit).
|
||||
void VisitCast(Expr* CastE, Expr* E, NodeTy* Pred, NodeSet& Dst);
|
||||
void VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitDeclRefExpr - Transfer function logic for DeclRefExprs.
|
||||
void VisitDeclRefExpr(DeclRefExpr* DR, NodeTy* Pred, NodeSet& Dst);
|
||||
|
@ -316,101 +324,62 @@ public:
|
|||
void VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose
|
||||
void VisitGuardedExpr(Expr* S, Expr* LHS, Expr* RHS,
|
||||
NodeTy* Pred, NodeSet& Dst);
|
||||
void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitLogicalExpr - Transfer function logic for '&&', '||'
|
||||
void VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitSizeOfAlignOfTypeExpr - Transfer function for sizeof(type).
|
||||
void VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr* S, NodeTy* Pred,
|
||||
void VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr* Ex, NodeTy* Pred,
|
||||
NodeSet& Dst);
|
||||
|
||||
// VisitSizeOfExpr - Transfer function for sizeof(expr).
|
||||
void VisitSizeOfExpr(UnaryOperator* U, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
/// VisitUnaryOperator - Transfer function logic for unary operators.
|
||||
void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
void VisitDeref(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst);
|
||||
|
||||
|
||||
inline RValue EvalCast(ValueManager& ValMgr, RValue X, Expr* CastExpr) {
|
||||
if (isa<UnknownVal>(X) || isa<UninitializedVal>(X))
|
||||
return X;
|
||||
|
||||
return TF->EvalCast(ValMgr, X, CastExpr);
|
||||
RVal EvalCast(ValueManager& ValMgr, RVal X, Expr* CastExpr) {
|
||||
return X.isValid() ? TF->EvalCast(ValMgr, X, CastExpr) : X;
|
||||
}
|
||||
|
||||
inline NonLValue EvalMinus(ValueManager& ValMgr, UnaryOperator* U,
|
||||
NonLValue X) {
|
||||
if (isa<UnknownVal>(X) || isa<UninitializedVal>(X))
|
||||
return X;
|
||||
|
||||
return TF->EvalMinus(ValMgr, U, X);
|
||||
RVal EvalMinus(UnaryOperator* U, RVal X) {
|
||||
return X.isValid() ? TF->EvalMinus(ValMgr, U, cast<NonLVal>(X)) : X;
|
||||
}
|
||||
|
||||
inline NonLValue EvalPlus(ValueManager& ValMgr, UnaryOperator* U,
|
||||
NonLValue X) {
|
||||
if (isa<UnknownVal>(X) || isa<UninitializedVal>(X))
|
||||
return X;
|
||||
|
||||
return TF->EvalPlus(ValMgr, U, X);
|
||||
RVal EvalComplement(RVal X) {
|
||||
return X.isValid() ? TF->EvalComplement(ValMgr, cast<NonLVal>(X)) : X;
|
||||
}
|
||||
|
||||
inline NonLValue EvalComplement(ValueManager& ValMgr, NonLValue X) {
|
||||
if (isa<UnknownVal>(X) || isa<UninitializedVal>(X))
|
||||
return X;
|
||||
|
||||
return TF->EvalComplement(ValMgr, X);
|
||||
RVal EvalBinOp(BinaryOperator::Opcode Op, LVal L, RVal R) {
|
||||
return R.isValid() ? TF->EvalBinOp(ValMgr, Op, L, cast<NonLVal>(R)) : R;
|
||||
}
|
||||
|
||||
inline NonLValue EvalBinaryOp(BinaryOperator::Opcode Op,
|
||||
NonLValue LHS, NonLValue RHS) {
|
||||
|
||||
if (isa<UninitializedVal>(LHS) || isa<UninitializedVal>(RHS))
|
||||
return cast<NonLValue>(UninitializedVal());
|
||||
|
||||
if (isa<UnknownVal>(LHS) || isa<UnknownVal>(RHS))
|
||||
return cast<NonLValue>(UnknownVal());
|
||||
|
||||
return TF->EvalBinaryOp(ValMgr, Op, LHS, RHS);
|
||||
}
|
||||
RVal EvalBinOp(BinaryOperator::Opcode Op, NonLVal L, RVal R) {
|
||||
return R.isValid() ? TF->EvalBinOp(ValMgr, Op, L, cast<NonLVal>(R)) : R;
|
||||
}
|
||||
|
||||
inline RValue EvalBinaryOp(BinaryOperator::Opcode Op,
|
||||
LValue LHS, LValue RHS) {
|
||||
RVal EvalBinOp(BinaryOperator::Opcode Op, RVal L, RVal R) {
|
||||
|
||||
if (isa<UninitializedVal>(LHS) || isa<UninitializedVal>(RHS))
|
||||
if (L.isUninit() || R.isUninit())
|
||||
return UninitializedVal();
|
||||
|
||||
if (isa<UnknownVal>(LHS) || isa<UnknownVal>(RHS))
|
||||
if (L.isUnknown() || R.isUnknown())
|
||||
return UnknownVal();
|
||||
|
||||
if (isa<LVal>(L)) {
|
||||
if (isa<LVal>(R))
|
||||
return TF->EvalBinOp(ValMgr, Op, cast<LVal>(L), cast<LVal>(R));
|
||||
else
|
||||
return TF->EvalBinOp(ValMgr, Op, cast<LVal>(L), cast<NonLVal>(R));
|
||||
}
|
||||
|
||||
return TF->EvalBinaryOp(ValMgr, Op, LHS, RHS);
|
||||
return TF->EvalBinOp(ValMgr, Op, cast<NonLVal>(L), cast<NonLVal>(R));
|
||||
}
|
||||
|
||||
inline RValue EvalBinaryOp(BinaryOperator::Opcode Op,
|
||||
LValue LHS, NonLValue RHS) {
|
||||
|
||||
if (isa<UninitializedVal>(LHS) || isa<UninitializedVal>(RHS))
|
||||
return UninitializedVal();
|
||||
|
||||
if (isa<UnknownVal>(LHS) || isa<UnknownVal>(RHS))
|
||||
return UnknownVal();
|
||||
|
||||
return TF->EvalBinaryOp(ValMgr, Op, LHS, RHS);
|
||||
}
|
||||
|
||||
inline RValue EvalBinaryOp(BinaryOperator::Opcode Op,
|
||||
RValue LHS, RValue RHS) {
|
||||
|
||||
if (isa<UninitializedVal>(LHS) || isa<UninitializedVal>(RHS))
|
||||
return UninitializedVal();
|
||||
|
||||
if (isa<UnknownVal>(LHS) || isa<UnknownVal>(RHS))
|
||||
return UnknownVal();
|
||||
|
||||
return TF->EvalBinaryOp(ValMgr, Op, LHS, RHS);
|
||||
}
|
||||
|
||||
StateTy EvalCall(CallExpr* CE, StateTy St) {
|
||||
StateTy EvalCall(CallExpr* CE, LVal L, StateTy St) {
|
||||
return St;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -26,47 +26,28 @@ public:
|
|||
|
||||
// Casts.
|
||||
|
||||
RValue EvalCast(ValueManager& ValMgr, RValue V, Expr* CastExpr);
|
||||
virtual RValue EvalCast(ValueManager& ValMgr, NonLValue V, Expr* CastExpr) =0;
|
||||
virtual RValue EvalCast(ValueManager& ValMgr, LValue V, Expr* CastExpr) = 0;
|
||||
RVal EvalCast(ValueManager& ValMgr, RVal V, Expr* CastExpr);
|
||||
virtual RVal EvalCast(ValueManager& ValMgr, NonLVal V, Expr* CastExpr) =0;
|
||||
virtual RVal EvalCast(ValueManager& ValMgr, LVal V, Expr* CastExpr) = 0;
|
||||
|
||||
// Unary Operators.
|
||||
|
||||
virtual NonLValue EvalMinus(ValueManager& ValMgr, UnaryOperator* U,
|
||||
NonLValue X) = 0;
|
||||
virtual RVal EvalMinus(ValueManager& ValMgr, UnaryOperator* U, NonLVal X) = 0;
|
||||
|
||||
virtual NonLValue EvalPlus(ValueManager& ValMgr, UnaryOperator* U,
|
||||
NonLValue X) = 0;
|
||||
|
||||
virtual NonLValue EvalComplement(ValueManager& ValMgr, NonLValue X) = 0;
|
||||
virtual RVal EvalComplement(ValueManager& ValMgr, NonLVal X) = 0;
|
||||
|
||||
// Binary Operators.
|
||||
|
||||
virtual NonLValue EvalBinaryOp(ValueManager& ValMgr,
|
||||
BinaryOperator::Opcode Op,
|
||||
NonLValue LHS, NonLValue RHS) = 0;
|
||||
virtual RVal EvalBinOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
|
||||
NonLVal L, NonLVal R) = 0;
|
||||
|
||||
virtual RValue EvalBinaryOp(ValueManager& ValMgr,
|
||||
BinaryOperator::Opcode Op,
|
||||
LValue LHS, LValue RHS) = 0;
|
||||
virtual RVal EvalBinOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
|
||||
LVal L, LVal R) = 0;
|
||||
|
||||
// Pointer arithmetic.
|
||||
|
||||
virtual LValue EvalBinaryOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
|
||||
LValue LHS, NonLValue RHS) = 0;
|
||||
|
||||
inline RValue EvalBinaryOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
|
||||
const RValue& L, const RValue& R) {
|
||||
|
||||
if (isa<LValue>(L)) {
|
||||
if (isa<LValue>(R))
|
||||
return EvalBinaryOp(ValMgr, Op, cast<LValue>(L), cast<LValue>(R));
|
||||
else
|
||||
return EvalBinaryOp(ValMgr, Op, cast<LValue>(L), cast<NonLValue>(R));
|
||||
}
|
||||
else
|
||||
return EvalBinaryOp(ValMgr, Op, cast<NonLValue>(L), cast<NonLValue>(R));
|
||||
}
|
||||
virtual RVal EvalBinOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
|
||||
LVal L, NonLVal R) = 0;
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This files defines RValue, LValue, and NonLValue, classes that represent
|
||||
// This files defines RVal, LVal, and NonLVal, classes that represent
|
||||
// abstract r-values for use with path-sensitive value tracking.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -19,57 +19,64 @@
|
|||
#include "llvm/Support/Casting.h"
|
||||
|
||||
//==------------------------------------------------------------------------==//
|
||||
// Base RValue types.
|
||||
// Base RVal types.
|
||||
//==------------------------------------------------------------------------==//
|
||||
|
||||
namespace clang {
|
||||
|
||||
class RValue {
|
||||
class RVal {
|
||||
public:
|
||||
enum BaseKind { LValueKind=0x0,
|
||||
NonLValueKind=0x1,
|
||||
UninitializedKind=0x2,
|
||||
UnknownKind=0x3 };
|
||||
|
||||
enum { BaseBits = 2,
|
||||
BaseMask = 0x3 };
|
||||
enum BaseKind { UninitializedKind, UnknownKind, LValKind, NonLValKind };
|
||||
enum { BaseBits = 2, BaseMask = 0x3 };
|
||||
|
||||
protected:
|
||||
void* Data;
|
||||
unsigned Kind;
|
||||
|
||||
protected:
|
||||
RValue(const void* d, bool isLValue, unsigned ValKind)
|
||||
RVal(const void* d, bool isLVal, unsigned ValKind)
|
||||
: Data(const_cast<void*>(d)),
|
||||
Kind((isLValue ? LValueKind : NonLValueKind) | (ValKind << BaseBits)) {}
|
||||
Kind((isLVal ? LValKind : NonLValKind) | (ValKind << BaseBits)) {}
|
||||
|
||||
explicit RValue(BaseKind k)
|
||||
explicit RVal(BaseKind k)
|
||||
: Data(0), Kind(k) {}
|
||||
|
||||
public:
|
||||
~RValue() {};
|
||||
~RVal() {};
|
||||
|
||||
/// BufferTy - A temporary buffer to hold a set of RValues.
|
||||
typedef llvm::SmallVector<RValue,5> BufferTy;
|
||||
/// BufferTy - A temporary buffer to hold a set of RVals.
|
||||
typedef llvm::SmallVector<RVal,5> BufferTy;
|
||||
|
||||
unsigned getRawKind() const { return Kind; }
|
||||
BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); }
|
||||
unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; }
|
||||
inline unsigned getRawKind() const { return Kind; }
|
||||
inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); }
|
||||
inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
inline void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
ID.AddInteger((unsigned) getRawKind());
|
||||
ID.AddPointer(reinterpret_cast<void*>(Data));
|
||||
}
|
||||
|
||||
bool operator==(const RValue& RHS) const {
|
||||
return getRawKind() == RHS.getRawKind() && Data == RHS.Data;
|
||||
inline bool operator==(const RVal& R) const {
|
||||
return getRawKind() == R.getRawKind() && Data == R.Data;
|
||||
}
|
||||
|
||||
static RValue GetSymbolValue(SymbolManager& SymMgr, ParmVarDecl *D);
|
||||
static RVal GetSymbolValue(SymbolManager& SymMgr, ParmVarDecl *D);
|
||||
|
||||
inline bool isUnknown() const {
|
||||
return getRawKind() == UnknownKind;
|
||||
}
|
||||
|
||||
inline bool isUninit() const {
|
||||
return getRawKind() == UninitializedKind;
|
||||
}
|
||||
|
||||
inline bool isUnknownOrUninit() const {
|
||||
return getRawKind() <= UnknownKind;
|
||||
}
|
||||
|
||||
inline bool isKnown() const { return getRawKind() != UnknownKind; }
|
||||
inline bool isUnknown() const { return getRawKind() == UnknownKind; }
|
||||
inline bool isValid() const {
|
||||
return getRawKind() > UnknownKind;
|
||||
}
|
||||
|
||||
void print(std::ostream& OS) const;
|
||||
void printStdErr() const;
|
||||
|
@ -79,247 +86,269 @@ public:
|
|||
symbol_iterator symbol_end() const;
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RValue*) { return true; }
|
||||
static inline bool classof(const RVal*) { return true; }
|
||||
};
|
||||
|
||||
class UnknownVal : public RValue {
|
||||
class UnknownVal : public RVal {
|
||||
public:
|
||||
UnknownVal() : RValue(UnknownKind) {}
|
||||
UnknownVal() : RVal(UnknownKind) {}
|
||||
|
||||
static inline bool classof(const RValue* V) {
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == UnknownKind;
|
||||
}
|
||||
};
|
||||
|
||||
class UninitializedVal : public RValue {
|
||||
class UninitializedVal : public RVal {
|
||||
public:
|
||||
UninitializedVal() : RValue(UninitializedKind) {}
|
||||
UninitializedVal() : RVal(UninitializedKind) {}
|
||||
|
||||
static inline bool classof(const RValue* V) {
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == UninitializedKind;
|
||||
}
|
||||
};
|
||||
|
||||
class NonLValue : public RValue {
|
||||
class NonLVal : public RVal {
|
||||
protected:
|
||||
NonLValue(unsigned SubKind, const void* d) : RValue(d, false, SubKind) {}
|
||||
NonLVal(unsigned SubKind, const void* d) : RVal(d, false, SubKind) {}
|
||||
|
||||
public:
|
||||
void print(std::ostream& Out) const;
|
||||
|
||||
// Utility methods to create NonLValues.
|
||||
static NonLValue GetValue(ValueManager& ValMgr, uint64_t X, QualType T,
|
||||
SourceLocation Loc = SourceLocation());
|
||||
// Utility methods to create NonLVals.
|
||||
static NonLVal MakeVal(ValueManager& ValMgr, uint64_t X, QualType T,
|
||||
SourceLocation Loc = SourceLocation());
|
||||
|
||||
static NonLValue GetValue(ValueManager& ValMgr, IntegerLiteral* I);
|
||||
static NonLVal MakeVal(ValueManager& ValMgr, IntegerLiteral* I);
|
||||
|
||||
static NonLValue GetIntTruthValue(ValueManager& ValMgr, bool b);
|
||||
static NonLVal MakeIntTruthVal(ValueManager& ValMgr, bool b);
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RValue* V) {
|
||||
return V->getBaseKind() >= NonLValueKind;
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == NonLValKind;
|
||||
}
|
||||
};
|
||||
|
||||
class LValue : public RValue {
|
||||
class LVal : public RVal {
|
||||
protected:
|
||||
LValue(unsigned SubKind, const void* D) : RValue(const_cast<void*>(D),
|
||||
true, SubKind) {}
|
||||
|
||||
LVal(unsigned SubKind, const void* D)
|
||||
: RVal(const_cast<void*>(D), true, SubKind) {}
|
||||
|
||||
// Equality operators.
|
||||
NonLValue EQ(ValueManager& ValMgr, const LValue& RHS) const;
|
||||
NonLValue NE(ValueManager& ValMgr, const LValue& RHS) const;
|
||||
NonLVal EQ(ValueManager& ValMgr, const LVal& R) const;
|
||||
NonLVal NE(ValueManager& ValMgr, const LVal& R) const;
|
||||
|
||||
public:
|
||||
void print(std::ostream& Out) const;
|
||||
|
||||
static LValue GetValue(AddrLabelExpr* E);
|
||||
static LVal MakeVal(AddrLabelExpr* E);
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RValue* V) {
|
||||
return V->getBaseKind() != NonLValueKind;
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == LValKind;
|
||||
}
|
||||
};
|
||||
|
||||
//==------------------------------------------------------------------------==//
|
||||
// Subclasses of NonLValue.
|
||||
// Subclasses of NonLVal.
|
||||
//==------------------------------------------------------------------------==//
|
||||
|
||||
namespace nonlval {
|
||||
|
||||
enum Kind { ConcreteIntKind,
|
||||
SymbolValKind,
|
||||
SymIntConstraintValKind,
|
||||
NumKind };
|
||||
enum Kind { ConcreteIntKind, SymbolValKind, SymIntConstraintValKind };
|
||||
|
||||
class SymbolVal : public NonLValue {
|
||||
public:
|
||||
SymbolVal(unsigned SymID)
|
||||
: NonLValue(SymbolValKind,
|
||||
reinterpret_cast<void*>((uintptr_t) SymID)) {}
|
||||
|
||||
SymbolID getSymbol() const {
|
||||
return (SymbolID) reinterpret_cast<uintptr_t>(Data);
|
||||
}
|
||||
|
||||
static inline bool classof(const RValue* V) {
|
||||
return V->getBaseKind() == NonLValueKind &&
|
||||
V->getSubKind() == SymbolValKind;
|
||||
}
|
||||
};
|
||||
class SymbolVal : public NonLVal {
|
||||
public:
|
||||
SymbolVal(unsigned SymID)
|
||||
: NonLVal(SymbolValKind, reinterpret_cast<void*>((uintptr_t) SymID)) {}
|
||||
|
||||
class SymIntConstraintVal : public NonLValue {
|
||||
public:
|
||||
SymIntConstraintVal(const SymIntConstraint& C)
|
||||
: NonLValue(SymIntConstraintValKind, reinterpret_cast<const void*>(&C)) {}
|
||||
SymbolID getSymbol() const {
|
||||
return (SymbolID) reinterpret_cast<uintptr_t>(Data);
|
||||
}
|
||||
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == NonLValKind &&
|
||||
V->getSubKind() == SymbolValKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const NonLVal* V) {
|
||||
return V->getSubKind() == SymbolValKind;
|
||||
}
|
||||
};
|
||||
|
||||
const SymIntConstraint& getConstraint() const {
|
||||
return *reinterpret_cast<SymIntConstraint*>(Data);
|
||||
}
|
||||
|
||||
static inline bool classof(const RValue* V) {
|
||||
return V->getBaseKind() == NonLValueKind &&
|
||||
V->getSubKind() == SymIntConstraintValKind;
|
||||
}
|
||||
};
|
||||
class SymIntConstraintVal : public NonLVal {
|
||||
public:
|
||||
SymIntConstraintVal(const SymIntConstraint& C)
|
||||
: NonLVal(SymIntConstraintValKind, reinterpret_cast<const void*>(&C)) {}
|
||||
|
||||
class ConcreteInt : public NonLValue {
|
||||
public:
|
||||
ConcreteInt(const llvm::APSInt& V) : NonLValue(ConcreteIntKind, &V) {}
|
||||
|
||||
const llvm::APSInt& getValue() const {
|
||||
return *static_cast<llvm::APSInt*>(Data);
|
||||
}
|
||||
|
||||
// Transfer functions for binary/unary operations on ConcreteInts.
|
||||
ConcreteInt EvalBinaryOp(ValueManager& ValMgr,
|
||||
BinaryOperator::Opcode Op,
|
||||
const ConcreteInt& RHS) const;
|
||||
|
||||
ConcreteInt EvalComplement(ValueManager& ValMgr) const;
|
||||
ConcreteInt EvalMinus(ValueManager& ValMgr, UnaryOperator* U) const;
|
||||
ConcreteInt EvalPlus(ValueManager& ValMgr, UnaryOperator* U) const;
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RValue* V) {
|
||||
return V->getBaseKind() == NonLValueKind &&
|
||||
V->getSubKind() == ConcreteIntKind;
|
||||
}
|
||||
};
|
||||
const SymIntConstraint& getConstraint() const {
|
||||
return *reinterpret_cast<SymIntConstraint*>(Data);
|
||||
}
|
||||
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == NonLValKind &&
|
||||
V->getSubKind() == SymIntConstraintValKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const NonLVal* V) {
|
||||
return V->getSubKind() == SymIntConstraintValKind;
|
||||
}
|
||||
};
|
||||
|
||||
class ConcreteInt : public NonLVal {
|
||||
public:
|
||||
ConcreteInt(const llvm::APSInt& V) : NonLVal(ConcreteIntKind, &V) {}
|
||||
|
||||
const llvm::APSInt& getValue() const {
|
||||
return *static_cast<llvm::APSInt*>(Data);
|
||||
}
|
||||
|
||||
// Transfer functions for binary/unary operations on ConcreteInts.
|
||||
ConcreteInt EvalBinOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
|
||||
const ConcreteInt& R) const;
|
||||
|
||||
ConcreteInt EvalComplement(ValueManager& ValMgr) const;
|
||||
|
||||
ConcreteInt EvalMinus(ValueManager& ValMgr, UnaryOperator* U) const;
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == NonLValKind &&
|
||||
V->getSubKind() == ConcreteIntKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const NonLVal* V) {
|
||||
return V->getSubKind() == ConcreteIntKind;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang::nonlval
|
||||
|
||||
//==------------------------------------------------------------------------==//
|
||||
// Subclasses of LValue.
|
||||
// Subclasses of LVal.
|
||||
//==------------------------------------------------------------------------==//
|
||||
|
||||
namespace lval {
|
||||
|
||||
enum Kind { SymbolValKind,
|
||||
GotoLabelKind,
|
||||
DeclValKind,
|
||||
FuncValKind,
|
||||
ConcreteIntKind,
|
||||
NumKind };
|
||||
|
||||
class SymbolVal : public LValue {
|
||||
public:
|
||||
SymbolVal(unsigned SymID)
|
||||
: LValue(SymbolValKind, reinterpret_cast<void*>((uintptr_t) SymID)) {}
|
||||
|
||||
SymbolID getSymbol() const {
|
||||
return (SymbolID) reinterpret_cast<uintptr_t>(Data);
|
||||
}
|
||||
|
||||
static inline bool classof(const RValue* V) {
|
||||
return V->getBaseKind() == LValueKind &&
|
||||
V->getSubKind() == SymbolValKind;
|
||||
}
|
||||
};
|
||||
|
||||
class GotoLabel : public LValue {
|
||||
public:
|
||||
GotoLabel(LabelStmt* Label) : LValue(GotoLabelKind, Label) {}
|
||||
|
||||
LabelStmt* getLabel() const {
|
||||
return static_cast<LabelStmt*>(Data);
|
||||
}
|
||||
|
||||
static inline bool classof(const RValue* V) {
|
||||
return V->getBaseKind() == LValueKind &&
|
||||
V->getSubKind() == GotoLabelKind;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class DeclVal : public LValue {
|
||||
public:
|
||||
DeclVal(const VarDecl* vd) : LValue(DeclValKind, vd) {}
|
||||
|
||||
VarDecl* getDecl() const {
|
||||
return static_cast<VarDecl*>(Data);
|
||||
}
|
||||
|
||||
inline bool operator==(const DeclVal& R) const {
|
||||
return getDecl() == R.getDecl();
|
||||
}
|
||||
|
||||
inline bool operator!=(const DeclVal& R) const {
|
||||
return getDecl() != R.getDecl();
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RValue* V) {
|
||||
return V->getBaseKind() == LValueKind &&
|
||||
V->getSubKind() == DeclValKind;
|
||||
}
|
||||
};
|
||||
|
||||
class FuncVal : public LValue {
|
||||
public:
|
||||
FuncVal(const FunctionDecl* fd) : LValue(FuncValKind, fd) {}
|
||||
|
||||
FunctionDecl* getDecl() const {
|
||||
return static_cast<FunctionDecl*>(Data);
|
||||
}
|
||||
|
||||
inline bool operator==(const FuncVal& R) const {
|
||||
return getDecl() == R.getDecl();
|
||||
}
|
||||
|
||||
inline bool operator!=(const FuncVal& R) const {
|
||||
return getDecl() != R.getDecl();
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RValue* V) {
|
||||
return V->getBaseKind() == LValueKind &&
|
||||
V->getSubKind() == FuncValKind;
|
||||
}
|
||||
};
|
||||
enum Kind { SymbolValKind, GotoLabelKind, DeclValKind, FuncValKind,
|
||||
ConcreteIntKind };
|
||||
|
||||
class ConcreteInt : public LValue {
|
||||
public:
|
||||
ConcreteInt(const llvm::APSInt& V) : LValue(ConcreteIntKind, &V) {}
|
||||
|
||||
const llvm::APSInt& getValue() const {
|
||||
return *static_cast<llvm::APSInt*>(Data);
|
||||
}
|
||||
|
||||
class SymbolVal : public LVal {
|
||||
public:
|
||||
SymbolVal(unsigned SymID)
|
||||
: LVal(SymbolValKind, reinterpret_cast<void*>((uintptr_t) SymID)) {}
|
||||
|
||||
SymbolID getSymbol() const {
|
||||
return (SymbolID) reinterpret_cast<uintptr_t>(Data);
|
||||
}
|
||||
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == LValKind &&
|
||||
V->getSubKind() == SymbolValKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const LVal* V) {
|
||||
return V->getSubKind() == SymbolValKind;
|
||||
}
|
||||
};
|
||||
|
||||
// Transfer functions for binary/unary operations on ConcreteInts.
|
||||
ConcreteInt EvalBinaryOp(ValueManager& ValMgr,
|
||||
BinaryOperator::Opcode Op,
|
||||
const ConcreteInt& RHS) const;
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RValue* V) {
|
||||
return V->getBaseKind() == LValueKind &&
|
||||
V->getSubKind() == ConcreteIntKind;
|
||||
}
|
||||
};
|
||||
class GotoLabel : public LVal {
|
||||
public:
|
||||
GotoLabel(LabelStmt* Label) : LVal(GotoLabelKind, Label) {}
|
||||
|
||||
LabelStmt* getLabel() const {
|
||||
return static_cast<LabelStmt*>(Data);
|
||||
}
|
||||
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == LValKind &&
|
||||
V->getSubKind() == GotoLabelKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const LVal* V) {
|
||||
return V->getSubKind() == GotoLabelKind;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class DeclVal : public LVal {
|
||||
public:
|
||||
DeclVal(const VarDecl* vd) : LVal(DeclValKind, vd) {}
|
||||
|
||||
VarDecl* getDecl() const {
|
||||
return static_cast<VarDecl*>(Data);
|
||||
}
|
||||
|
||||
inline bool operator==(const DeclVal& R) const {
|
||||
return getDecl() == R.getDecl();
|
||||
}
|
||||
|
||||
inline bool operator!=(const DeclVal& R) const {
|
||||
return getDecl() != R.getDecl();
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == LValKind &&
|
||||
V->getSubKind() == DeclValKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const LVal* V) {
|
||||
return V->getSubKind() == DeclValKind;
|
||||
}
|
||||
};
|
||||
|
||||
class FuncVal : public LVal {
|
||||
public:
|
||||
FuncVal(const FunctionDecl* fd) : LVal(FuncValKind, fd) {}
|
||||
|
||||
FunctionDecl* getDecl() const {
|
||||
return static_cast<FunctionDecl*>(Data);
|
||||
}
|
||||
|
||||
inline bool operator==(const FuncVal& R) const {
|
||||
return getDecl() == R.getDecl();
|
||||
}
|
||||
|
||||
inline bool operator!=(const FuncVal& R) const {
|
||||
return getDecl() != R.getDecl();
|
||||
}
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == LValKind &&
|
||||
V->getSubKind() == FuncValKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const LVal* V) {
|
||||
return V->getSubKind() == FuncValKind;
|
||||
}
|
||||
};
|
||||
|
||||
class ConcreteInt : public LVal {
|
||||
public:
|
||||
ConcreteInt(const llvm::APSInt& V) : LVal(ConcreteIntKind, &V) {}
|
||||
|
||||
const llvm::APSInt& getValue() const {
|
||||
return *static_cast<llvm::APSInt*>(Data);
|
||||
}
|
||||
|
||||
// Transfer functions for binary/unary operations on ConcreteInts.
|
||||
ConcreteInt EvalBinOp(ValueManager& ValMgr,
|
||||
BinaryOperator::Opcode Op,
|
||||
const ConcreteInt& R) const;
|
||||
|
||||
// Implement isa<T> support.
|
||||
static inline bool classof(const RVal* V) {
|
||||
return V->getBaseKind() == LValKind &&
|
||||
V->getSubKind() == ConcreteIntKind;
|
||||
}
|
||||
|
||||
static inline bool classof(const LVal* V) {
|
||||
return V->getSubKind() == ConcreteIntKind;
|
||||
}
|
||||
};
|
||||
|
||||
} // end clang::lval namespace
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче