diff --git a/Analysis/GRExprEngine.cpp b/Analysis/GRExprEngine.cpp index 75ced576f4..fb6dc80e0d 100644 --- a/Analysis/GRExprEngine.cpp +++ b/Analysis/GRExprEngine.cpp @@ -24,7 +24,7 @@ using llvm::cast; using llvm::APSInt; GRExprEngine::StateTy -GRExprEngine::SetValue(StateTy St, Expr* S, const RValue& V) { +GRExprEngine::SetRVal(StateTy St, Expr* Ex, const RVal& V) { if (!StateCleaned) { St = RemoveDeadBindings(CurrentStmt, St); @@ -33,44 +33,41 @@ GRExprEngine::SetValue(StateTy St, Expr* S, const RValue& V) { bool isBlkExpr = false; - if (S == CurrentStmt) { - isBlkExpr = getCFG().isBlkExpr(S); + if (Ex == CurrentStmt) { + isBlkExpr = getCFG().isBlkExpr(Ex); if (!isBlkExpr) return St; } - return StateMgr.SetValue(St, S, isBlkExpr, V); + return StateMgr.SetRVal(St, Ex, isBlkExpr, V); } const GRExprEngine::StateTy::BufferTy& -GRExprEngine::SetValue(StateTy St, Expr* S, const RValue::BufferTy& RB, +GRExprEngine::SetRVal(StateTy St, Expr* Ex, const RVal::BufferTy& RB, StateTy::BufferTy& RetBuf) { assert (RetBuf.empty()); - for (RValue::BufferTy::const_iterator I=RB.begin(), E=RB.end(); I!=E; ++I) - RetBuf.push_back(SetValue(St, S, *I)); + for (RVal::BufferTy::const_iterator I = RB.begin(), E = RB.end(); I!=E; ++I) + RetBuf.push_back(SetRVal(St, Ex, *I)); return RetBuf; } GRExprEngine::StateTy -GRExprEngine::SetValue(StateTy St, const LValue& LV, const RValue& V) { - - if (LV.isUnknown()) - return St; +GRExprEngine::SetRVal(StateTy St, const LVal& LV, const RVal& RV) { if (!StateCleaned) { St = RemoveDeadBindings(CurrentStmt, St); StateCleaned = true; } - return StateMgr.SetValue(St, LV, V); + return StateMgr.SetRVal(St, LV, RV); } void GRExprEngine::ProcessBranch(Expr* Condition, Stmt* Term, - BranchNodeBuilder& builder) { + BranchNodeBuilder& builder) { // Remove old bindings for subexpressions. StateTy PrevState = StateMgr.RemoveSubExprBindings(builder.getState()); @@ -90,18 +87,18 @@ void GRExprEngine::ProcessBranch(Expr* Condition, Stmt* Term, return; } - RValue V = GetValue(PrevState, Condition); + RVal V = GetRVal(PrevState, Condition); switch (V.getBaseKind()) { default: break; - case RValue::UnknownKind: + case RVal::UnknownKind: builder.generateNode(PrevState, true); builder.generateNode(PrevState, false); return; - case RValue::UninitializedKind: { + case RVal::UninitializedKind: { NodeTy* N = builder.generateNode(PrevState, true); if (N) { @@ -162,7 +159,7 @@ void GRExprEngine::ProcessBranch(Expr* Condition, Stmt* Term, void GRExprEngine::ProcessIndirectGoto(IndirectGotoNodeBuilder& builder) { StateTy St = builder.getState(); - LValue V = cast(GetValue(St, builder.getTarget())); + RVal V = GetRVal(St, builder.getTarget()); // Three possibilities: // @@ -196,7 +193,7 @@ void GRExprEngine::ProcessIndirectGoto(IndirectGotoNodeBuilder& builder) { // This is really a catch-all. We don't support symbolics yet. - assert (isa(V)); + assert (V.isUnknown()); for (iterator I=builder.begin(), E=builder.end(); I != E; ++I) builder.generateNode(I, St); @@ -210,9 +207,9 @@ void GRExprEngine::ProcessSwitch(SwitchNodeBuilder& builder) { StateTy St = builder.getState(); Expr* CondE = builder.getCondition(); - NonLValue CondV = cast(GetValue(St, CondE)); + RVal CondV = GetRVal(St, CondE); - if (isa(CondV)) { + if (CondV.isUninit()) { NodeTy* N = builder.generateDefaultCaseNode(St, true); UninitBranches.insert(N); return; @@ -229,7 +226,7 @@ void GRExprEngine::ProcessSwitch(SwitchNodeBuilder& builder) { APSInt V1(bits, false); APSInt V2 = V1; - for (iterator I=builder.begin(), E=builder.end(); I!=E; ++I) { + for (iterator I = builder.begin(), EI = builder.end(); I != EI; ++I) { CaseStmt* Case = cast(I.getCase()); @@ -254,12 +251,12 @@ void GRExprEngine::ProcessSwitch(SwitchNodeBuilder& builder) { // FIXME: Eventually we should replace the logic below with a range // comparison, rather than concretize the values within the range. - // This should be easy once we have "ranges" for NonLValues. + // This should be easy once we have "ranges" for NonLVals. do { nonlval::ConcreteInt CaseVal(ValMgr.getValue(V1)); - NonLValue Res = EvalBinaryOp(BinaryOperator::EQ, CondV, CaseVal); + RVal Res = EvalBinOp(BinaryOperator::EQ, CondV, CaseVal); // Now "assume" that the case matches. bool isFeasible = false; @@ -297,22 +294,22 @@ void GRExprEngine::ProcessSwitch(SwitchNodeBuilder& builder) { void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, - NodeSet& Dst) { + NodeSet& Dst) { bool hasR2; StateTy PrevState = Pred->getState(); - RValue R1 = GetValue(PrevState, B->getLHS()); - RValue R2 = GetValue(PrevState, B->getRHS(), hasR2); + RVal R1 = GetRVal(PrevState, B->getLHS()); + RVal R2 = GetRVal(PrevState, B->getRHS(), hasR2); if (hasR2) { - if (isa(R2) || isa(R2)) { - Nodify(Dst, B, Pred, SetValue(PrevState, B, R2)); + if (R2.isUnknownOrUninit()) { + Nodify(Dst, B, Pred, SetRVal(PrevState, B, R2)); return; } } - else if (isa(R1) || isa(R1)) { - Nodify(Dst, B, Pred, SetValue(PrevState, B, R1)); + else if (R1.isUnknownOrUninit()) { + Nodify(Dst, B, Pred, SetRVal(PrevState, B, R1)); return; } @@ -321,7 +318,7 @@ void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, // hasR2 == 'false' means that LHS evaluated to 'false' and that // we short-circuited, leading to a value of '0' for the '&&' expression. if (hasR2 == false) { - Nodify(Dst, B, Pred, SetValue(PrevState, B, GetRValueConstant(0U, B))); + Nodify(Dst, B, Pred, SetRVal(PrevState, B, MakeConstantVal(0U, B))); return; } } @@ -330,7 +327,7 @@ void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, // hasR2 == 'false' means that the LHS evaluate to 'true' and that // we short-circuited, leading to a value of '1' for the '||' expression. if (hasR2 == false) { - Nodify(Dst, B, Pred, SetValue(PrevState, B, GetRValueConstant(1U, B))); + Nodify(Dst, B, Pred, SetRVal(PrevState, B, MakeConstantVal(1U, B))); return; } } @@ -342,19 +339,19 @@ void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, StateTy St = Assume(PrevState, R2, true, isFeasible); if (isFeasible) - Nodify(Dst, B, Pred, SetValue(PrevState, B, GetRValueConstant(1U, B))); + Nodify(Dst, B, Pred, SetRVal(PrevState, B, MakeConstantVal(1U, B))); St = Assume(PrevState, R2, false, isFeasible); if (isFeasible) - Nodify(Dst, B, Pred, SetValue(PrevState, B, GetRValueConstant(0U, B))); + Nodify(Dst, B, Pred, SetRVal(PrevState, B, MakeConstantVal(0U, B))); } void GRExprEngine::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) { - Builder = &builder; + Builder = &builder; StmtEntryNode = builder.getLastNode(); CurrentStmt = S; NodeSet Dst; @@ -364,11 +361,14 @@ void GRExprEngine::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) { // If no nodes were generated, generate a new node that has all the // dead mappings removed. + if (Dst.size() == 1 && *Dst.begin() == StmtEntryNode) { StateTy St = RemoveDeadBindings(S, StmtEntryNode->getState()); builder.generateNode(S, St, StmtEntryNode); } + // For safety, NULL out these variables. + CurrentStmt = NULL; StmtEntryNode = NULL; Builder = NULL; @@ -383,6 +383,7 @@ GRExprEngine::Nodify(NodeSet& Dst, Stmt* S, NodeTy* Pred, StateTy St) { NodeTy* N = Builder->generateNode(S, St, Pred); Dst.Add(N); + return N; } @@ -394,6 +395,7 @@ void GRExprEngine::Nodify(NodeSet& Dst, Stmt* S, NodeTy* Pred, } void GRExprEngine::VisitDeclRefExpr(DeclRefExpr* D, NodeTy* Pred, NodeSet& Dst){ + if (D != CurrentStmt) { Dst.Add(Pred); // No-op. Simply propagate the current state unchanged. return; @@ -402,77 +404,85 @@ void GRExprEngine::VisitDeclRefExpr(DeclRefExpr* D, NodeTy* Pred, NodeSet& Dst){ // If we are here, we are loading the value of the decl and binding // it to the block-level expression. - StateTy St = Pred->getState(); - - Nodify(Dst, D, Pred, SetValue(St, D, GetValue(St, D))); + StateTy St = Pred->getState(); + Nodify(Dst, D, Pred, SetRVal(St, D, GetRVal(St, D))); } void GRExprEngine::VisitCall(CallExpr* CE, NodeTy* Pred, - CallExpr::arg_iterator I, CallExpr::arg_iterator E, + CallExpr::arg_iterator AI, + CallExpr::arg_iterator AE, NodeSet& Dst) { - if (I != E) { - NodeSet DstTmp; - Visit(*I, Pred, DstTmp); - ++I; + // Process the arguments. + + if (AI != AE) { - for (NodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI!=DE; ++DI) - VisitCall(CE, *DI, I, E, Dst); + NodeSet DstTmp; + Visit(*AI, Pred, DstTmp); + ++AI; + + for (NodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI != DE; ++DI) + VisitCall(CE, *DI, AI, AE, Dst); return; } // If we reach here we have processed all of the arguments. Evaluate // the callee expression. - NodeSet DstTmp; + NodeSet DstTmp; Visit(CE->getCallee(), Pred, DstTmp); // Finally, evaluate the function call. - for (NodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI!=DE; ++DI) { + for (NodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI!=DE; ++DI) { + StateTy St = (*DI)->getState(); - LValue L = GetLValue(St, CE->getCallee()); + RVal L = GetLVal(St, CE->getCallee()); // Check for uninitialized control-flow. - if (isa(L)) { + + if (L.isUninit()) { + NodeTy* N = Builder->generateNode(CE, St, *DI); N->markAsSink(); UninitBranches.insert(N); continue; } - // Note: EvalCall must handle the case where the callee is "UnknownVal." - Nodify(Dst, CE, *DI, EvalCall(CE, (*DI)->getState())); + // FIXME: EvalCall must handle the case where the callee is Unknown. + assert (!L.isUnknown()); + + Nodify(Dst, CE, *DI, EvalCall(CE, cast(L), (*DI)->getState())); } } -void GRExprEngine::VisitCast(Expr* CastE, Expr* E, NodeTy* Pred, NodeSet& Dst) { +void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst){ NodeSet S1; - Visit(E, Pred, S1); + Visit(Ex, Pred, S1); QualType T = CastE->getType(); // Check for redundant casts or casting to "void" if (T->isVoidType() || - E->getType() == T || - (T->isPointerType() && E->getType()->isFunctionType())) { + Ex->getType() == T || + (T->isPointerType() && Ex->getType()->isFunctionType())) { - for (NodeSet::iterator I1=S1.begin(), E1=S1.end(); I1 != E1; ++I1) + for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) Dst.Add(*I1); return; } - for (NodeSet::iterator I1=S1.begin(), E1=S1.end(); I1 != E1; ++I1) { + for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) { NodeTy* N = *I1; StateTy St = N->getState(); - const RValue& V = GetValue(St, E); - Nodify(Dst, CastE, N, SetValue(St, CastE, EvalCast(ValMgr, V, CastE))); + RVal V = GetRVal(St, Ex); + Nodify(Dst, CastE, N, SetRVal(St, CastE, EvalCast(ValMgr, V, CastE))); } } void GRExprEngine::VisitDeclStmt(DeclStmt* DS, GRExprEngine::NodeTy* Pred, - GRExprEngine::NodeSet& Dst) { + GRExprEngine::NodeSet& Dst) { StateTy St = Pred->getState(); @@ -483,72 +493,80 @@ void GRExprEngine::VisitDeclStmt(DeclStmt* DS, GRExprEngine::NodeTy* Pred, if (VD->getType()->isArrayType()) continue; - const Expr* E = VD->getInit(); - St = SetValue(St, lval::DeclVal(VD), - E ? GetValue(St, E) : UninitializedVal()); + const Expr* Ex = VD->getInit(); + + St = SetRVal(St, lval::DeclVal(VD), + Ex ? GetRVal(St, Ex) : UninitializedVal()); } Nodify(Dst, DS, Pred, St); - if (Dst.empty()) - Dst.Add(Pred); + if (Dst.empty()) { Dst.Add(Pred); } } -void GRExprEngine::VisitGuardedExpr(Expr* S, Expr* LHS, Expr* RHS, +void GRExprEngine::VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, NodeTy* Pred, NodeSet& Dst) { StateTy St = Pred->getState(); - RValue R = GetValue(St, LHS); - if (isa(R)) R = GetValue(St, RHS); + RVal V = GetRVal(St, L); + if (isa(V)) V = GetRVal(St, R); - Nodify(Dst, S, Pred, SetValue(St, S, R)); + Nodify(Dst, Ex, Pred, SetRVal(St, Ex, V)); } /// VisitSizeOfAlignOfTypeExpr - Transfer function for sizeof(type). -void GRExprEngine::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr* S, - NodeTy* Pred, - NodeSet& Dst) { +void GRExprEngine::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr* Ex, + NodeTy* Pred, + NodeSet& Dst) { + + assert (Ex->isSizeOf() && "AlignOf(Expr) not yet implemented."); // 6.5.3.4 sizeof: "The result type is an integer." - QualType T = S->getArgumentType(); + QualType T = Ex->getArgumentType(); + // FIXME: Implement alignof + // FIXME: Add support for sizeof(void) // FIXME: Add support for VLAs. + if (!T.getTypePtr()->isConstantSizeType()) return; - SourceLocation L = S->getExprLoc(); - uint64_t size = getContext().getTypeSize(T, L) / 8; + SourceLocation Loc = Ex->getExprLoc(); + uint64_t size = getContext().getTypeSize(T, Loc) / 8; - Nodify(Dst, S, Pred, - SetValue(Pred->getState(), S, - NonLValue::GetValue(ValMgr, size, S->getType(), L))); + Nodify(Dst, Ex, Pred, + SetRVal(Pred->getState(), Ex, + NonLVal::MakeVal(ValMgr, size, Ex->getType(), Loc))); } void GRExprEngine::VisitDeref(UnaryOperator* U, NodeTy* Pred, NodeSet& Dst) { - Expr* E = U->getSubExpr()->IgnoreParens(); + Expr* Ex = U->getSubExpr()->IgnoreParens(); NodeSet DstTmp; - if (!isa(E)) + if (!isa(Ex)) DstTmp.Add(Pred); else - Visit(E, Pred, DstTmp); + Visit(Ex, Pred, DstTmp); - for (NodeSet::iterator I=DstTmp.begin(), DE=DstTmp.end(); I != DE; ++I) { + for (NodeSet::iterator I = DstTmp.begin(), DE = DstTmp.end(); I != DE; ++I) { NodeTy* N = *I; StateTy St = N->getState(); // FIXME: Bifurcate when dereferencing a symbolic with no constraints? - LValue L = cast(GetValue(St, E)); + RVal V = GetRVal(St, Ex); - if (isa(L)) { + // Check for dereferences of uninitialized values. + + if (V.isUninit()) { + NodeTy* Succ = Builder->generateNode(U, St, N); if (Succ) { @@ -559,7 +577,9 @@ void GRExprEngine::VisitDeref(UnaryOperator* U, NodeTy* Pred, NodeSet& Dst) { continue; } - if (L.isUnknown()) { + // Check for dereferences of unknown values. Treat as No-Ops. + + if (V.isUnknown()) { Dst.Add(N); continue; } @@ -570,48 +590,56 @@ void GRExprEngine::VisitDeref(UnaryOperator* U, NodeTy* Pred, NodeSet& Dst) { // // We add these assumptions. + LVal LV = cast(V); bool isFeasibleNotNull; // "Assume" that the pointer is Not-NULL. - StateTy StNotNull = Assume(St, L, true, isFeasibleNotNull); + + StateTy StNotNull = Assume(St, LV, true, isFeasibleNotNull); if (isFeasibleNotNull) { - QualType T = U->getType(); // FIXME: Currently symbolic analysis "generates" new symbols // for the contents of values. We need a better approach. - Nodify(Dst, U, N, SetValue(StNotNull, U, GetValue(StNotNull, L, &T))); + Nodify(Dst, U, N, SetRVal(StNotNull, U, + GetRVal(StNotNull, LV, U->getType()))); } bool isFeasibleNull; - // "Assume" that the pointer is NULL. - StateTy StNull = Assume(St, L, false, isFeasibleNull); + // Now "assume" that the pointer is NULL. + + StateTy StNull = Assume(St, LV, false, isFeasibleNull); if (isFeasibleNull) { + // We don't use "Nodify" here because the node will be a sink // and we have no intention of processing it later. + NodeTy* NullNode = Builder->generateNode(U, StNull, N); if (NullNode) { + NullNode->markAsSink(); - if (isFeasibleNotNull) - ImplicitNullDeref.insert(NullNode); - else - ExplicitNullDeref.insert(NullNode); + if (isFeasibleNotNull) ImplicitNullDeref.insert(NullNode); + else ExplicitNullDeref.insert(NullNode); } } } } -void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, - NodeTy* Pred, NodeSet& Dst) { +void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred, + NodeSet& Dst) { NodeSet S1; assert (U->getOpcode() != UnaryOperator::Deref); + assert (U->getOpcode() != UnaryOperator::SizeOf); + assert (U->getOpcode() != UnaryOperator::AlignOf); + + bool use_GetLVal = false; switch (U->getOpcode()) { case UnaryOperator::PostInc: @@ -619,14 +647,9 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, case UnaryOperator::PreInc: case UnaryOperator::PreDec: case UnaryOperator::AddrOf: - // Evalue subexpression as an LValue. - VisitLValue(U->getSubExpr(), Pred, S1); - break; - - case UnaryOperator::SizeOf: - case UnaryOperator::AlignOf: - // Do not evaluate subexpression. - S1.Add(Pred); + // Evalue subexpression as an LVal. + use_GetLVal = true; + VisitLVal(U->getSubExpr(), Pred, S1); break; default: @@ -634,29 +657,53 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, break; } - for (NodeSet::iterator I1=S1.begin(), E1=S1.end(); I1 != E1; ++I1) { + for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) { NodeTy* N1 = *I1; StateTy St = N1->getState(); + + RVal SubV = use_GetLVal ? GetLVal(St, U->getSubExpr()) : + GetRVal(St, U->getSubExpr()); + + if (SubV.isUnknown()) { + Dst.Add(N1); + continue; + } + + if (SubV.isUninit()) { + Nodify(Dst, U, N1, SetRVal(St, U, SubV)); + continue; + } if (U->isIncrementDecrementOp()) { // Handle ++ and -- (both pre- and post-increment). - const LValue& L1 = GetLValue(St, U->getSubExpr()); - QualType T = U->getType(); - RValue R1 = GetValue(St, L1, &T); + LVal SubLV = cast(SubV); + RVal V = GetRVal(St, SubLV, U->getType()); + + // An LVal should never bind to UnknownVal. + assert (!V.isUnknown()); + + // Propagate uninitialized values. + if (V.isUninit()) { + Nodify(Dst, U, N1, SetRVal(St, U, V)); + continue; + } + + // Handle all NonLVals. BinaryOperator::Opcode Op = U->isIncrementOp() ? BinaryOperator::Add : BinaryOperator::Sub; - RValue Result = EvalBinaryOp(Op, R1, GetRValueConstant(1U, U)); + RVal Result = EvalBinOp(Op, cast(V), MakeConstantVal(1U, U)); if (U->isPostfix()) - Nodify(Dst, U, N1, SetValue(SetValue(St, U, R1), L1, Result)); + St = SetRVal(SetRVal(St, U, V), SubLV, Result); else - Nodify(Dst, U, N1, SetValue(SetValue(St, U, Result), L1, Result)); + St = SetRVal(SetRVal(St, U, Result), SubLV, Result); + Nodify(Dst, U, N1, St); continue; } @@ -664,104 +711,90 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, switch (U->getOpcode()) { - case UnaryOperator::Minus: { - const NonLValue& R1 = cast(GetValue(St, U->getSubExpr())); - Nodify(Dst, U, N1, SetValue(St, U, EvalMinus(ValMgr, U, R1))); + case UnaryOperator::Minus: + St = SetRVal(St, U, EvalMinus(U, cast(SubV))); break; - } - case UnaryOperator::Plus: { - const NonLValue& R1 = cast(GetValue(St, U->getSubExpr())); - Nodify(Dst, U, N1, SetValue(St, U, EvalPlus(ValMgr, U, R1))); + case UnaryOperator::Not: + St = SetRVal(St, U, EvalComplement(cast(SubV))); break; - } - case UnaryOperator::Not: { - const NonLValue& R1 = cast(GetValue(St, U->getSubExpr())); - Nodify(Dst, U, N1, SetValue(St, U, EvalComplement(ValMgr, R1))); - break; - } + case UnaryOperator::LNot: - case UnaryOperator::LNot: { // C99 6.5.3.3: "The expression !E is equivalent to (0==E)." // // Note: technically we do "E == 0", but this is the same in the // transfer functions as "0 == E". - - RValue V1 = GetValue(St, U->getSubExpr()); - - if (isa(V1)) { - const LValue& L1 = cast(V1); - lval::ConcreteInt V2(ValMgr.getZeroWithPtrWidth()); - Nodify(Dst, U, N1, - SetValue(St, U, EvalBinaryOp(BinaryOperator::EQ, - L1, V2))); + + if (isa(SubV)) { + lval::ConcreteInt V(ValMgr.getZeroWithPtrWidth()); + RVal Result = EvalBinOp(BinaryOperator::EQ, cast(SubV), V); + St = SetRVal(St, U, Result); } else { - const NonLValue& R1 = cast(V1); - nonlval::ConcreteInt V2(ValMgr.getZeroWithPtrWidth()); - Nodify(Dst, U, N1, - SetValue(St, U, EvalBinaryOp(BinaryOperator::EQ, - R1, V2))); + nonlval::ConcreteInt V(ValMgr.getZeroWithPtrWidth()); + RVal Result = EvalBinOp(BinaryOperator::EQ, cast(SubV), V); + St = SetRVal(St, U, Result); } break; - } - - case UnaryOperator::SizeOf: { - // 6.5.3.4 sizeof: "The result type is an integer." - - QualType T = U->getSubExpr()->getType(); - - // FIXME: Add support for VLAs. - if (!T.getTypePtr()->isConstantSizeType()) - return; - - SourceLocation L = U->getExprLoc(); - uint64_t size = getContext().getTypeSize(T, L) / 8; - - Nodify(Dst, U, N1, - SetValue(St, U, NonLValue::GetValue(ValMgr, size, - U->getType(), L))); - - break; - } case UnaryOperator::AddrOf: { - const LValue& L1 = GetLValue(St, U->getSubExpr()); - Nodify(Dst, U, N1, SetValue(St, U, L1)); + assert (isa(SubV)); + St = SetRVal(St, U, SubV); break; } default: ; assert (false && "Not implemented."); - } + } + + Nodify(Dst, U, N1, St); } } -void GRExprEngine::VisitLValue(Expr* E, NodeTy* Pred, NodeSet& Dst) { +void GRExprEngine::VisitSizeOfExpr(UnaryOperator* U, NodeTy* Pred, + NodeSet& Dst) { - E = E->IgnoreParens(); + QualType T = U->getSubExpr()->getType(); - if (isa(E)) { + // FIXME: Add support for VLAs. + if (!T.getTypePtr()->isConstantSizeType()) + return; + + SourceLocation Loc = U->getExprLoc(); + uint64_t size = getContext().getTypeSize(T, Loc) / 8; + StateTy St = Pred->getState(); + St = SetRVal(St, U, NonLVal::MakeVal(ValMgr, size, U->getType(), Loc)); + + Nodify(Dst, U, Pred, St); +} + +void GRExprEngine::VisitLVal(Expr* Ex, NodeTy* Pred, NodeSet& Dst) { + + assert (Ex != CurrentStmt && !getCFG().isBlkExpr(Ex)); + + Ex = Ex->IgnoreParens(); + + if (isa(Ex)) { Dst.Add(Pred); return; } - if (UnaryOperator* U = dyn_cast(E)) { + if (UnaryOperator* U = dyn_cast(Ex)) { if (U->getOpcode() == UnaryOperator::Deref) { - E = U->getSubExpr()->IgnoreParens(); + Ex = U->getSubExpr()->IgnoreParens(); - if (isa(E)) + if (isa(Ex)) Dst.Add(Pred); else - Visit(E, Pred, Dst); + Visit(Ex, Pred, Dst); return; } } - Visit(E, Pred, Dst); + Visit(Ex, Pred, Dst); } void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, @@ -770,119 +803,152 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, NodeSet S1; if (B->isAssignmentOp()) - VisitLValue(B->getLHS(), Pred, S1); + VisitLVal(B->getLHS(), Pred, S1); else Visit(B->getLHS(), Pred, S1); for (NodeSet::iterator I1=S1.begin(), E1=S1.end(); I1 != E1; ++I1) { + NodeTy* N1 = *I1; // When getting the value for the LHS, check if we are in an assignment. - // In such cases, we want to (initially) treat the LHS as an LValue, - // so we use GetLValue instead of GetValue so that DeclRefExpr's are - // evaluated to LValueDecl's instead of to an NonLValue. - const RValue& V1 = - B->isAssignmentOp() ? GetLValue(N1->getState(), B->getLHS()) - : GetValue(N1->getState(), B->getLHS()); + // In such cases, we want to (initially) treat the LHS as an LVal, + // so we use GetLVal instead of GetRVal so that DeclRefExpr's are + // evaluated to LValDecl's instead of to an NonLVal. + + RVal LeftV = B->isAssignmentOp() ? GetLVal(N1->getState(), B->getLHS()) + : GetRVal(N1->getState(), B->getLHS()); - NodeSet S2; + // Visit the RHS... + + NodeSet S2; Visit(B->getRHS(), N1, S2); + + // Process the binary operator. - for (NodeSet::iterator I2=S2.begin(), E2=S2.end(); I2 != E2; ++I2) { + for (NodeSet::iterator I2 = S2.begin(), E2 = S2.end(); I2 != E2; ++I2) { NodeTy* N2 = *I2; - StateTy St = N2->getState(); - const RValue& V2 = GetValue(St, B->getRHS()); + StateTy St = N2->getState(); + RVal RightV = GetRVal(St, B->getRHS()); BinaryOperator::Opcode Op = B->getOpcode(); if (Op <= BinaryOperator::Or) { - if (isa(V1) || isa(V1)) { - Nodify(Dst, B, N2, SetValue(St, B, V1)); + // Process non-assignements except commas or short-circuited + // logical expressions (LAnd and LOr). + + RVal Result = EvalBinOp(Op, LeftV, RightV); + + if (Result.isUnknown()) { + Dst.Add(N2); continue; } - Nodify(Dst, B, N2, SetValue(St, B, EvalBinaryOp(Op, V1, V2))); + Nodify(Dst, B, N2, SetRVal(St, B, Result)); continue; - } - - switch (Op) { + + // Process assignments. + + switch (Op) { + case BinaryOperator::Assign: { - const LValue& L1 = cast(V1); + + // Simple assignments. - if (isa(L1)) + if (LeftV.isUninit()) { HandleUninitializedStore(B, N2); - else - Nodify(Dst, B, N2, SetValue(SetValue(St, B, V2), L1, V2)); + continue; + } + + if (LeftV.isUnknown()) { + St = SetRVal(St, B, RightV); + break; + } + St = SetRVal(SetRVal(St, B, RightV), cast(LeftV), RightV); break; } - default: { // Compound assignment operators. + // Compound assignment operators. - assert (B->isCompoundAssignmentOp()); - - const LValue& L1 = cast(V1); + default: { - if (isa(L1)) { + assert (B->isCompoundAssignmentOp()); + + if (LeftV.isUninit()) { HandleUninitializedStore(B, N2); + continue; + } + + if (LeftV.isUnknown()) { + + // While we do not know the location to store RightV, + // the entire expression does evaluate to RightV. + + if (RightV.isUnknown()) { + Dst.Add(N2); + continue; + } + + St = SetRVal(St, B, RightV); break; } - if (isa(V2)) { - Nodify(Dst, B, N2, SetValue(SetValue(St, B, V2), L1, V2)); + // At this pointer we know that the LHS evaluates to an LVal + // that is neither "Unknown" or "Unintialized." + + LVal LeftLV = cast(LeftV); + + // Propagate uninitialized values (right-side). + + if (RightV.isUninit()) { + St = SetRVal(SetRVal(St, B, RightV), LeftLV, RightV); break; } - RValue Result = cast(UnknownVal()); + // Fetch the value of the LHS (the value of the variable, etc.). + + RVal V = GetRVal(N1->getState(), LeftLV, B->getLHS()->getType()); + + // Propagate uninitialized value (left-side). + + if (V.isUninit()) { + St = SetRVal(St, B, V); + break; + } + + // Propagate unknown values. + + assert (!V.isUnknown() && + "An LVal should never bind to UnknownVal"); + + if (RightV.isUnknown()) { + St = SetRVal(SetRVal(St, LeftLV, RightV), B, RightV); + break; + } + + // Neither the LHS or the RHS have Unknown/Uninit values. Process + // the operation and store the result. if (Op >= BinaryOperator::AndAssign) ((int&) Op) -= (BinaryOperator::AndAssign - BinaryOperator::And); else ((int&) Op) -= BinaryOperator::MulAssign; - if (B->getType()->isPointerType()) { // Perform pointer arithmetic. - const NonLValue& R2 = cast(V2); - Result = EvalBinaryOp(Op, L1, R2); - } - else if (isa(V2)) { - const LValue& L2 = cast(V2); - - if (B->getRHS()->getType()->isPointerType()) { - // LValue comparison. - Result = EvalBinaryOp(Op, L1, L2); - } - else { - QualType T1 = B->getLHS()->getType(); - QualType T2 = B->getRHS()->getType(); - - // An operation between two variables of a non-lvalue type. - Result = - EvalBinaryOp(Op, - cast(GetValue(N1->getState(), L1, &T1)), - cast(GetValue(N2->getState(), L2, &T2))); - } - } - else { // Any other operation between two Non-LValues. - QualType T = B->getLHS()->getType(); - const NonLValue& R1 = cast(GetValue(N1->getState(), - L1, &T)); - const NonLValue& R2 = cast(V2); - Result = EvalBinaryOp(Op, R1, R2); - } - - Nodify(Dst, B, N2, SetValue(SetValue(St, B, Result), L1, Result)); - break; + RVal Result = EvalBinOp(Op, V, RightV); + St = SetRVal(SetRVal(St, B, Result), LeftLV, Result); } } + + Nodify(Dst, B, N2, St); } } } -void GRExprEngine::HandleUninitializedStore(Stmt* S, NodeTy* Pred) { - +void GRExprEngine::HandleUninitializedStore(Stmt* S, NodeTy* Pred) { NodeTy* N = Builder->generateNode(S, Pred->getState(), Pred); N->markAsSink(); UninitStores.insert(N); @@ -917,7 +983,7 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { } else if (B->getOpcode() == BinaryOperator::Comma) { StateTy St = Pred->getState(); - Nodify(Dst, B, Pred, SetValue(St, B, GetValue(St, B->getRHS()))); + Nodify(Dst, B, Pred, SetRVal(St, B, GetRVal(St, B->getRHS()))); break; } @@ -944,12 +1010,15 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { case Stmt::CharacterLiteralClass: { CharacterLiteral* C = cast(S); StateTy St = Pred->getState(); - NonLValue X = NonLValue::GetValue(ValMgr, C->getValue(), C->getType(), + NonLVal X = NonLVal::MakeVal(ValMgr, C->getValue(), C->getType(), C->getLoc()); - Nodify(Dst, C, Pred, SetValue(St, C, X)); + Nodify(Dst, C, Pred, SetRVal(St, C, X)); break; } + // FIXME: ChooseExpr is really a constant. We need to fix + // the CFG do not model them as explicit control-flow. + case Stmt::ChooseExprClass: { // __builtin_choose_expr ChooseExpr* C = cast(S); VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); @@ -981,8 +1050,8 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { case Stmt::IntegerLiteralClass: { StateTy St = Pred->getState(); IntegerLiteral* I = cast(S); - NonLValue X = NonLValue::GetValue(ValMgr, I); - Nodify(Dst, I, Pred, SetValue(St, I, X)); + NonLVal X = NonLVal::MakeVal(ValMgr, I); + Nodify(Dst, I, Pred, SetRVal(St, I, X)); break; } @@ -1005,10 +1074,14 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { StateTy St = Pred->getState(); Expr* LastExpr = cast(*SE->getSubStmt()->body_rbegin()); - Nodify(Dst, SE, Pred, SetValue(St, SE, GetValue(St, LastExpr))); + Nodify(Dst, SE, Pred, SetRVal(St, SE, GetRVal(St, LastExpr))); break; } + // FIXME: We may wish to always bind state to ReturnStmts so + // that users can quickly query what was the state at the + // exit points of a function. + case Stmt::ReturnStmtClass: { if (Expr* R = cast(S)->getRetValue()) Visit(R, Pred, Dst); @@ -1021,10 +1094,12 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { case Stmt::UnaryOperatorClass: { UnaryOperator* U = cast(S); - if (U->getOpcode() == UnaryOperator::Deref) - VisitDeref(U, Pred, Dst); - else - VisitUnaryOperator(U, Pred, Dst); + switch (U->getOpcode()) { + case UnaryOperator::Deref: VisitDeref(U, Pred, Dst); break; + case UnaryOperator::Plus: Visit(U->getSubExpr(), Pred, Dst); break; + case UnaryOperator::SizeOf: VisitSizeOfExpr(U, Pred, Dst); break; + default: VisitUnaryOperator(U, Pred, Dst); break; + } break; } @@ -1035,20 +1110,12 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { // "Assume" logic. //===----------------------------------------------------------------------===// -GRExprEngine::StateTy GRExprEngine::Assume(StateTy St, LValue Cond, +GRExprEngine::StateTy GRExprEngine::Assume(StateTy St, LVal Cond, bool Assumption, - bool& isFeasible) { - - assert (!isa(Cond)); - - if (isa(Cond)) { - isFeasible = true; - return St; - } - + bool& isFeasible) { switch (Cond.getSubKind()) { default: - assert (false && "'Assume' not implemented for this LValue."); + assert (false && "'Assume' not implemented for this LVal."); return St; case lval::SymbolValKind: @@ -1072,20 +1139,12 @@ GRExprEngine::StateTy GRExprEngine::Assume(StateTy St, LValue Cond, } } -GRExprEngine::StateTy GRExprEngine::Assume(StateTy St, NonLValue Cond, +GRExprEngine::StateTy GRExprEngine::Assume(StateTy St, NonLVal Cond, bool Assumption, - bool& isFeasible) { - - assert (!isa(Cond)); - - if (isa(Cond)) { - isFeasible = true; - return St; - } - + bool& isFeasible) { switch (Cond.getSubKind()) { default: - assert (false && "'Assume' not implemented for this NonLValue."); + assert (false && "'Assume' not implemented for this NonLVal."); return St; @@ -1259,26 +1318,26 @@ struct VISIBILITY_HIDDEN DOTGraphTraits : } static void PrintEQ(std::ostream& Out, GRExprEngine::StateTy St) { - ValueState::ConstantEqTy CE = St.getImpl()->ConstantEq; + ValueState::ConstEqTy CE = St.getImpl()->ConstEq; if (CE.isEmpty()) return; Out << "\\l\\|'==' constraints:"; - for (ValueState::ConstantEqTy::iterator I=CE.begin(), E=CE.end(); I!=E;++I) + for (ValueState::ConstEqTy::iterator I=CE.begin(), E=CE.end(); I!=E;++I) Out << "\\l $" << I.getKey() << " : " << I.getData()->toString(); } static void PrintNE(std::ostream& Out, GRExprEngine::StateTy St) { - ValueState::ConstantNotEqTy NE = St.getImpl()->ConstantNotEq; + ValueState::ConstNotEqTy NE = St.getImpl()->ConstNotEq; if (NE.isEmpty()) return; Out << "\\l\\|'!=' constraints:"; - for (ValueState::ConstantNotEqTy::iterator I=NE.begin(), EI=NE.end(); + for (ValueState::ConstNotEqTy::iterator I=NE.begin(), EI=NE.end(); I != EI; ++I){ Out << "\\l $" << I.getKey() << " : "; @@ -1340,7 +1399,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits : Out << "\\|Dereference of uninitialied value.\\l"; } else if (GraphPrintCheckerState->isUninitStore(N)) { - Out << "\\|Store to Uninitialized LValue."; + Out << "\\|Store to Uninitialized LVal."; } break; diff --git a/Analysis/GRSimpleVals.cpp b/Analysis/GRSimpleVals.cpp index a76acb3d1f..675882f42e 100644 --- a/Analysis/GRSimpleVals.cpp +++ b/Analysis/GRSimpleVals.cpp @@ -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 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((*I)->getLocation()); + Expr* Exp = cast(L.getStmt()); - GRCoreEngine 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((*I)->getLocation()); - Expr* Exp = cast(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(X) && !isa(X)); +RVal GRSimpleVals::EvalCast(ValueManager& ValMgr, NonLVal X, Expr* CastExpr) { if (!isa(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(X) && !isa(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(X) && !isa(X)); +RVal GRSimpleVals::EvalMinus(ValueManager& ValMgr, UnaryOperator* U, NonLVal X){ switch (X.getSubKind()) { + case nonlval::ConcreteIntKind: return cast(X).EvalMinus(ValMgr, U); + default: - return cast(UnknownVal()); + return UnknownVal(); } } -NonLValue GRSimpleVals::EvalPlus(ValueManager& ValMgr, UnaryOperator* U, - NonLValue X) { - - assert (!isa(X) && !isa(X)); - - switch (X.getSubKind()) { - case nonlval::ConcreteIntKind: - return cast(X).EvalPlus(ValMgr, U); - default: - return cast(UnknownVal()); - } -} - - -NonLValue GRSimpleVals::EvalComplement(ValueManager& ValMgr, NonLValue X) { - - assert (!isa(X) && !isa(X)); - +RVal GRSimpleVals::EvalComplement(ValueManager& ValMgr, NonLVal X) { + switch (X.getSubKind()) { + case nonlval::ConcreteIntKind: return cast(X).EvalComplement(ValMgr); + default: - return cast(UnknownVal()); + return UnknownVal(); } } // Binary operators. -NonLValue GRSimpleVals::EvalBinaryOp(ValueManager& ValMgr, - BinaryOperator::Opcode Op, - NonLValue LHS, NonLValue RHS) { - - assert (!isa(LHS) && !isa(LHS)); - assert (!isa(RHS) && !isa(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(UnknownVal()); + return cast(UnknownVal()); case nonlval::ConcreteIntKind: - if (isa(RHS)) { - const nonlval::ConcreteInt& LHS_CI = cast(LHS); - const nonlval::ConcreteInt& RHS_CI = cast(RHS); - return LHS_CI.EvalBinaryOp(ValMgr, Op, RHS_CI); + if (isa(R)) { + const nonlval::ConcreteInt& L_CI = cast(L); + const nonlval::ConcreteInt& R_CI = cast(R); + return L_CI.EvalBinOp(ValMgr, Op, R_CI); } - else if(isa(RHS)) - return cast(UnknownVal()); else { - NonLValue tmp = RHS; - RHS = LHS; - LHS = tmp; + NonLVal tmp = R; + R = L; + L = tmp; continue; } case nonlval::SymbolValKind: { - if (isa(RHS)) { + + if (isa(R)) { const SymIntConstraint& C = - ValMgr.getConstraint(cast(LHS).getSymbol(), Op, - cast(RHS).getValue()); + ValMgr.getConstraint(cast(L).getSymbol(), Op, + cast(R).getValue()); return nonlval::SymIntConstraintVal(C); } else - return cast(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(LHS) && !isa(LHS)); - assert (!isa(RHS) && !isa(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(LHS) && !isa(LHS)); - assert (!isa(RHS) && !isa(RHS)); - - return cast(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(LHS) && !isa(LHS)); - assert (!isa(RHS) && !isa(RHS)); - - switch (LHS.getSubKind()) { default: - assert(false && "EQ not implemented for this LValue."); - return cast(UnknownVal()); + assert(false && "EQ not implemented for this LVal."); + return UnknownVal(); case lval::ConcreteIntKind: - if (isa(RHS)) { - bool b = cast(LHS).getValue() == - cast(RHS).getValue(); + + if (isa(R)) { + bool b = cast(L).getValue() == + cast(R).getValue(); - return NonLValue::GetIntTruthValue(ValMgr, b); + return NonLVal::MakeIntTruthVal(ValMgr, b); } - else if (isa(RHS)) { + else if (isa(R)) { const SymIntConstraint& C = - ValMgr.getConstraint(cast(RHS).getSymbol(), + ValMgr.getConstraint(cast(R).getSymbol(), BinaryOperator::EQ, - cast(LHS).getValue()); + cast(L).getValue()); return nonlval::SymIntConstraintVal(C); } break; - case lval::SymbolValKind: { - if (isa(RHS)) { - const SymIntConstraint& C = - ValMgr.getConstraint(cast(LHS).getSymbol(), - BinaryOperator::EQ, - cast(RHS).getValue()); - - return nonlval::SymIntConstraintVal(C); - } + case lval::SymbolValKind: { + + if (isa(R)) { + const SymIntConstraint& C = + ValMgr.getConstraint(cast(L).getSymbol(), + BinaryOperator::EQ, + cast(R).getValue()); - // FIXME: Implement unification - return cast(UnknownVal()); - //assert (!isa(RHS) && "FIXME: Implement unification."); - - break; + return nonlval::SymIntConstraintVal(C); } - case lval::DeclValKind: + // FIXME: Implement unification + return cast(UnknownVal()); + //assert (!isa(R) && "FIXME: Implement unification."); - if (isa(RHS)) { - bool b = cast(LHS) == cast(RHS); - return NonLValue::GetIntTruthValue(ValMgr, b); - } + break; + } - break; + case lval::DeclValKind: + + if (isa(R)) { + bool b = cast(L) == cast(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(LHS) && !isa(LHS)); - assert (!isa(RHS) && !isa(RHS)); + switch (L.getSubKind()) { - switch (LHS.getSubKind()) { default: - assert(false && "NE not implemented for this LValue."); - return cast(UnknownVal()); + assert(false && "NE not implemented for this LVal."); + return UnknownVal(); case lval::ConcreteIntKind: - if (isa(RHS)) { - bool b = cast(LHS).getValue() != - cast(RHS).getValue(); + + if (isa(R)) { + bool b = cast(L).getValue() != + cast(R).getValue(); - return NonLValue::GetIntTruthValue(ValMgr, b); + return NonLVal::MakeIntTruthVal(ValMgr, b); } - else if (isa(RHS)) { + else if (isa(R)) { const SymIntConstraint& C = - ValMgr.getConstraint(cast(RHS).getSymbol(), + ValMgr.getConstraint(cast(R).getSymbol(), BinaryOperator::NE, - cast(LHS).getValue()); + cast(L).getValue()); return nonlval::SymIntConstraintVal(C); } break; - case lval::SymbolValKind: { - if (isa(RHS)) { - const SymIntConstraint& C = - ValMgr.getConstraint(cast(LHS).getSymbol(), - BinaryOperator::NE, - cast(RHS).getValue()); - - return nonlval::SymIntConstraintVal(C); - } + case lval::SymbolValKind: { + if (isa(R)) { + const SymIntConstraint& C = + ValMgr.getConstraint(cast(L).getSymbol(), + BinaryOperator::NE, + cast(R).getValue()); - assert (!isa(RHS) && "FIXME: Implement sym !=."); - - break; + return nonlval::SymIntConstraintVal(C); } - case lval::DeclValKind: - if (isa(RHS)) { - bool b = cast(LHS) == cast(RHS); - return NonLValue::GetIntTruthValue(ValMgr, b); - } + assert (!isa(R) && "FIXME: Implement sym !=."); break; + } + + case lval::DeclValKind: + if (isa(R)) { + bool b = cast(L) == cast(R); + return NonLVal::MakeIntTruthVal(ValMgr, b); + } + + break; } - return NonLValue::GetIntTruthValue(ValMgr, true); + return NonLVal::MakeIntTruthVal(ValMgr, true); } diff --git a/Analysis/GRSimpleVals.h b/Analysis/GRSimpleVals.h index 3a73e41033..28286ec11f 100644 --- a/Analysis/GRSimpleVals.h +++ b/Analysis/GRSimpleVals.h @@ -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 diff --git a/Analysis/GRTransferFuncs.cpp b/Analysis/GRTransferFuncs.cpp index 3716ed9691..29d6216b71 100644 --- a/Analysis/GRTransferFuncs.cpp +++ b/Analysis/GRTransferFuncs.cpp @@ -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(X), CastExpr); + case RVal::LValKind: + return EvalCast(ValMgr, cast(X), CastExpr); - case RValue::NonLValueKind: - return EvalCast(ValMgr, cast(X), CastExpr); + case RVal::NonLValKind: + return EvalCast(ValMgr, cast(X), CastExpr); - case RValue::UninitializedKind: - case RValue::UnknownKind: break; + case RVal::UninitializedKind: + case RVal::UnknownKind: break; } return X; diff --git a/Analysis/RValues.cpp b/Analysis/RValues.cpp index c4041b866d..178d794065 100644 --- a/Analysis/RValues.cpp +++ b/Analysis/RValues.cpp @@ -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(this)) { - if (isa(this)) - return (symbol_iterator) (&Data); - } - else { - if (isa(this)) - return (symbol_iterator) (&Data); - else if (isa(this)) { - const SymIntConstraint& C = - cast(this)->getConstraint(); - return (symbol_iterator) &C.getSymbol(); - } +RVal::symbol_iterator RVal::symbol_begin() const { + if (isa(this)) + return (symbol_iterator) (&Data); + else if (isa(this)) + return (symbol_iterator) (&Data); + else if (isa(this)) { + const SymIntConstraint& C = + cast(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(UnknownVal()); + assert(false && "EQ not implemented for this LVal."); + break; case lval::ConcreteIntKind: - if (isa(RHS)) { + if (isa(R)) { bool b = cast(this)->getValue() == - cast(RHS).getValue(); + cast(R).getValue(); - return NonLValue::GetIntTruthValue(ValMgr, b); + return NonLVal::MakeIntTruthVal(ValMgr, b); } - else if (isa(RHS)) { + else if (isa(R)) { const SymIntConstraint& C = - ValMgr.getConstraint(cast(RHS).getSymbol(), - BinaryOperator::EQ, - cast(this)->getValue()); + ValMgr.getConstraint(cast(R).getSymbol(), + BinaryOperator::EQ, + cast(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(RHS)) { + if (isa(R)) { const SymIntConstraint& C = - ValMgr.getConstraint(cast(this)->getSymbol(), - BinaryOperator::EQ, - cast(RHS).getValue()); + ValMgr.getConstraint(cast(this)->getSymbol(), + BinaryOperator::EQ, + cast(R).getValue()); return nonlval::SymIntConstraintVal(C); } - assert (!isa(RHS) && "FIXME: Implement unification."); + assert (!isa(R) && "FIXME: Implement unification."); break; } case lval::DeclValKind: - if (isa(RHS)) { - bool b = cast(*this) == cast(RHS); - return NonLValue::GetIntTruthValue(ValMgr, b); + if (isa(R)) { + bool b = cast(*this) == cast(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(UnknownVal()); + assert(false && "NE not implemented for this LVal."); + break; case lval::ConcreteIntKind: - if (isa(RHS)) { + if (isa(R)) { bool b = cast(this)->getValue() != - cast(RHS).getValue(); + cast(R).getValue(); - return NonLValue::GetIntTruthValue(ValMgr, b); + return NonLVal::MakeIntTruthVal(ValMgr, b); } - else if (isa(RHS)) { + else if (isa(R)) { const SymIntConstraint& C = - ValMgr.getConstraint(cast(RHS).getSymbol(), + ValMgr.getConstraint(cast(R).getSymbol(), BinaryOperator::NE, cast(this)->getValue()); @@ -178,55 +166,56 @@ NonLValue LValue::NE(ValueManager& ValMgr, const LValue& RHS) const { break; case lval::SymbolValKind: { - if (isa(RHS)) { + if (isa(R)) { const SymIntConstraint& C = ValMgr.getConstraint(cast(this)->getSymbol(), BinaryOperator::NE, - cast(RHS).getValue()); + cast(R).getValue()); return nonlval::SymIntConstraintVal(C); } - assert (!isa(RHS) && "FIXME: Implement sym !=."); + assert (!isa(R) && "FIXME: Implement sym !=."); break; } case lval::DeclValKind: - if (isa(RHS)) { - bool b = cast(*this) == cast(RHS); - return NonLValue::GetIntTruthValue(ValMgr, b); - } + if (isa(R)) { + bool b = cast(*this) == cast(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(this)->print(Out); - break; + case NonLValKind: + cast(this)->print(Out); break; - case LValueKind: - cast(this)->print(Out); - break; + case LValKind: + cast(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(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(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; } } - diff --git a/Analysis/ValueState.cpp b/Analysis/ValueState.cpp index d756980306..db2ef6badc 100644 --- a/Analysis/ValueState.cpp +++ b/Analysis/ValueState.cpp @@ -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(X)) { lval::DeclVal LV = cast(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(GetValue(St, lval::DeclVal(cast(V)))); + const LVal& LV = + cast(GetRVal(St, lval::DeclVal(cast(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(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(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(cast(LV).getDecl())); + St->VarBindings.SlimFind(cast(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(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(E)); + case Stmt::AddrLabelExprClass: + return LVal::MakeVal(cast(E)); // ParenExprs are no-ops. - case Stmt::ParenExprClass: + case Stmt::ParenExprClass: E = cast(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(E)->getDecl(); - if (VarDecl* VD = dyn_cast(D)) - return GetValue(St, lval::DeclVal(VD)); + if (VarDecl* VD = dyn_cast(D)) { + return GetRVal(St, lval::DeclVal(VD)); + } else if (EnumConstantDecl* ED = dyn_cast(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(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(E)); - - case Stmt::CharacterLiteralClass: { - CharacterLiteral* C = cast(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(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(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(E)) { lval::DeclVal X(cast(DR->getDecl())); - return cast(GetValue(St, X)); + return GetRVal(St, X); } else - return cast(GetValue(St, E)); + return GetRVal(St, E); } - return cast(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(LV)) - return St; - - assert (!isa(LV)); - switch (LV.getSubKind()) { + case lval::DeclValKind: - return V.isKnown() // FIXME: Have DeclVal only contain VarDecl - ? BindVar(St, cast(cast(LV).getDecl()), V) - : UnbindVar(St, cast(cast(LV).getDecl())); + return V.isUnknown() + ? UnbindVar(St, cast(LV).getDecl()) + : BindVar(St, cast(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; diff --git a/Analysis/ValueState.h b/Analysis/ValueState.h index 38c34cb84a..424b832258 100644 --- a/Analysis/ValueState.h +++ b/Analysis/ValueState.h @@ -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 IntSetTy; - typedef llvm::ImmutableMap ExprBindingsTy; - typedef llvm::ImmutableMap VarBindingsTy; - typedef llvm::ImmutableMap ConstantNotEqTy; - typedef llvm::ImmutableMap ConstantEqTy; + typedef llvm::ImmutableMap ExprBindingsTy; + typedef llvm::ImmutableMap VarBindingsTy; + typedef llvm::ImmutableMap ConstNotEqTy; + typedef llvm::ImmutableMap 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 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 { static inline ValueState toState(void* P) { return ValueState(static_cast(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 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); diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index 9220238ca0..fbb0275dd4 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -45,37 +45,38 @@ namespace clang { class GRExprEngine { public: - typedef ValueStateManager::StateTy StateTy; + typedef ValueStateManager::StateTy StateTy; typedef ExplodedGraph GraphTy; - typedef GraphTy::NodeTy NodeTy; + typedef GraphTy::NodeTy NodeTy; // Builders. - typedef GRStmtNodeBuilder StmtNodeBuilder; - typedef GRBranchNodeBuilder BranchNodeBuilder; - typedef GRIndirectGotoNodeBuilder IndirectGotoNodeBuilder; - typedef GRSwitchNodeBuilder SwitchNodeBuilder; + typedef GRStmtNodeBuilder StmtNodeBuilder; + typedef GRBranchNodeBuilder BranchNodeBuilder; + typedef GRIndirectGotoNodeBuilder IndirectGotoNodeBuilder; + typedef GRSwitchNodeBuilder SwitchNodeBuilder; class NodeSet { typedef llvm::SmallVector 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(S), V); + StateTy SetRVal(StateTy St, const Expr* Ex, const RVal& V) { + return SetRVal(St, const_cast(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(S)); + RVal GetRVal(const StateTy& St, const Expr* Ex) { + return GetRVal(St, const_cast(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(Cond)) - return Assume(St, cast(Cond), Assumption, isFeasible); + StateTy Assume(StateTy St, RVal Cond, bool Assumption, bool& isFeasible) { + + if (Cond.isUnknown()) { + isFeasible = true; + return St; + } + + if (isa(Cond)) + return Assume(St, cast(Cond), Assumption, isFeasible); else - return Assume(St, cast(Cond), Assumption, isFeasible); + return Assume(St, cast(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(X) || isa(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(X) || isa(X)) - return X; - - return TF->EvalMinus(ValMgr, U, X); + RVal EvalMinus(UnaryOperator* U, RVal X) { + return X.isValid() ? TF->EvalMinus(ValMgr, U, cast(X)) : X; } - inline NonLValue EvalPlus(ValueManager& ValMgr, UnaryOperator* U, - NonLValue X) { - if (isa(X) || isa(X)) - return X; - - return TF->EvalPlus(ValMgr, U, X); + RVal EvalComplement(RVal X) { + return X.isValid() ? TF->EvalComplement(ValMgr, cast(X)) : X; } - inline NonLValue EvalComplement(ValueManager& ValMgr, NonLValue X) { - if (isa(X) || isa(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(R)) : R; } - inline NonLValue EvalBinaryOp(BinaryOperator::Opcode Op, - NonLValue LHS, NonLValue RHS) { - - if (isa(LHS) || isa(RHS)) - return cast(UninitializedVal()); - - if (isa(LHS) || isa(RHS)) - return cast(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(R)) : R; + } - inline RValue EvalBinaryOp(BinaryOperator::Opcode Op, - LValue LHS, LValue RHS) { + RVal EvalBinOp(BinaryOperator::Opcode Op, RVal L, RVal R) { - if (isa(LHS) || isa(RHS)) + if (L.isUninit() || R.isUninit()) return UninitializedVal(); - if (isa(LHS) || isa(RHS)) + if (L.isUnknown() || R.isUnknown()) return UnknownVal(); + + if (isa(L)) { + if (isa(R)) + return TF->EvalBinOp(ValMgr, Op, cast(L), cast(R)); + else + return TF->EvalBinOp(ValMgr, Op, cast(L), cast(R)); + } - return TF->EvalBinaryOp(ValMgr, Op, LHS, RHS); + return TF->EvalBinOp(ValMgr, Op, cast(L), cast(R)); } - inline RValue EvalBinaryOp(BinaryOperator::Opcode Op, - LValue LHS, NonLValue RHS) { - - if (isa(LHS) || isa(RHS)) - return UninitializedVal(); - - if (isa(LHS) || isa(RHS)) - return UnknownVal(); - - return TF->EvalBinaryOp(ValMgr, Op, LHS, RHS); - } - - inline RValue EvalBinaryOp(BinaryOperator::Opcode Op, - RValue LHS, RValue RHS) { - - if (isa(LHS) || isa(RHS)) - return UninitializedVal(); - - if (isa(LHS) || isa(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; } }; diff --git a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h index 8aca43a89e..faa559ee58 100644 --- a/include/clang/Analysis/PathSensitive/GRTransferFuncs.h +++ b/include/clang/Analysis/PathSensitive/GRTransferFuncs.h @@ -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(L)) { - if (isa(R)) - return EvalBinaryOp(ValMgr, Op, cast(L), cast(R)); - else - return EvalBinaryOp(ValMgr, Op, cast(L), cast(R)); - } - else - return EvalBinaryOp(ValMgr, Op, cast(L), cast(R)); - } + virtual RVal EvalBinOp(ValueManager& ValMgr, BinaryOperator::Opcode Op, + LVal L, NonLVal R) = 0; }; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/RValues.h b/include/clang/Analysis/PathSensitive/RValues.h index beeb1c8216..df23431e4b 100644 --- a/include/clang/Analysis/PathSensitive/RValues.h +++ b/include/clang/Analysis/PathSensitive/RValues.h @@ -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(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 BufferTy; + /// BufferTy - A temporary buffer to hold a set of RVals. + typedef llvm::SmallVector 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(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 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 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(D), - true, SubKind) {} - + LVal(unsigned SubKind, const void* D) + : RVal(const_cast(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 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((uintptr_t) SymID)) {} - - SymbolID getSymbol() const { - return (SymbolID) reinterpret_cast(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((uintptr_t) SymID)) {} - class SymIntConstraintVal : public NonLValue { - public: - SymIntConstraintVal(const SymIntConstraint& C) - : NonLValue(SymIntConstraintValKind, reinterpret_cast(&C)) {} + SymbolID getSymbol() const { + return (SymbolID) reinterpret_cast(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(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(&C)) {} - class ConcreteInt : public NonLValue { - public: - ConcreteInt(const llvm::APSInt& V) : NonLValue(ConcreteIntKind, &V) {} - - const llvm::APSInt& getValue() const { - return *static_cast(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 support. - static inline bool classof(const RValue* V) { - return V->getBaseKind() == NonLValueKind && - V->getSubKind() == ConcreteIntKind; - } - }; + const SymIntConstraint& getConstraint() const { + return *reinterpret_cast(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(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 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((uintptr_t) SymID)) {} - - SymbolID getSymbol() const { - return (SymbolID) reinterpret_cast(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(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(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 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(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 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(Data); - } - +class SymbolVal : public LVal { +public: + SymbolVal(unsigned SymID) + : LVal(SymbolValKind, reinterpret_cast((uintptr_t) SymID)) {} + + SymbolID getSymbol() const { + return (SymbolID) reinterpret_cast(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 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(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(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 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(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 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(Data); + } + + // Transfer functions for binary/unary operations on ConcreteInts. + ConcreteInt EvalBinOp(ValueManager& ValMgr, + BinaryOperator::Opcode Op, + const ConcreteInt& R) const; + + // Implement isa 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