diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 41d06f454610..70ea990f559f 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -1022,6 +1022,14 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { case Stmt::ExprWithCleanupsClass: return VisitExprWithCleanups(cast(S), asc); + case Stmt::CXXDefaultArgExprClass: + // FIXME: The expression inside a CXXDefaultArgExpr is owned by the + // called function's declaration, not by the caller. If we simply add + // this expression to the CFG, we could end up with the same Expr + // appearing multiple times. + // PR13385 / + return VisitStmt(S, asc); + case Stmt::CXXBindTemporaryExprClass: return VisitCXXBindTemporaryExpr(cast(S), asc); diff --git a/clang/lib/StaticAnalyzer/Core/Environment.cpp b/clang/lib/StaticAnalyzer/Core/Environment.cpp index 52644f7702fc..534f37858c78 100644 --- a/clang/lib/StaticAnalyzer/Core/Environment.cpp +++ b/clang/lib/StaticAnalyzer/Core/Environment.cpp @@ -99,6 +99,9 @@ SVal Environment::getSVal(const EnvironmentEntry &Entry, case Stmt::SubstNonTypeTemplateParmExprClass: E = cast(E)->getReplacement(); continue; + case Stmt::CXXDefaultArgExprClass: + E = cast(E)->getExpr(); + continue; case Stmt::ObjCStringLiteralClass: { MemRegionManager &MRMgr = svalBuilder.getRegionManager(); const ObjCStringLiteral *SL = cast(E); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index a77a338b2797..d9b7ff57bff4 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -529,11 +529,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, break; } - // We don't handle default arguments either yet, but we can fake it - // for now by just skipping them. - case Stmt::CXXDefaultArgExprClass: - break; - case Stmt::ParenExprClass: llvm_unreachable("ParenExprs already handled."); case Stmt::GenericSelectionExprClass: @@ -619,6 +614,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::StringLiteralClass: case Stmt::ObjCStringLiteralClass: case Stmt::CXXBindTemporaryExprClass: + case Stmt::CXXDefaultArgExprClass: case Stmt::SubstNonTypeTemplateParmExprClass: case Stmt::CXXNullPtrLiteralExprClass: { Bldr.takeNodes(Pred); diff --git a/clang/test/Analysis/inline.cpp b/clang/test/Analysis/inline.cpp index 6b9a885f50f3..65907762662e 100644 --- a/clang/test/Analysis/inline.cpp +++ b/clang/test/Analysis/inline.cpp @@ -193,3 +193,37 @@ namespace Invalidation { } }; } + +namespace DefaultArgs { + int takesDefaultArgs(int i = 42) { + return -i; + } + + void testFunction() { + clang_analyzer_eval(takesDefaultArgs(1) == -1); // expected-warning{{TRUE}} + clang_analyzer_eval(takesDefaultArgs() == -42); // expected-warning{{TRUE}} + } + + class Secret { + public: + static const int value = 42; + int get(int i = value) { + return i; + } + }; + + void testMethod() { + Secret obj; + clang_analyzer_eval(obj.get(1) == 1); // expected-warning{{TRUE}} + + // FIXME: Should be 'TRUE'. See PR13673 or . + clang_analyzer_eval(obj.get() == 42); // expected-warning{{UNKNOWN}} + + // FIXME: Even if we constrain the variable, we still have a problem. + // See PR13385 or . + if (Secret::value != 42) + return; + clang_analyzer_eval(Secret::value == 42); // expected-warning{{TRUE}} + clang_analyzer_eval(obj.get() == 42); // expected-warning{{UNKNOWN}} + } +}