diff options
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 6 | ||||
-rw-r--r-- | test/Analysis/operator-calls.cpp | 36 |
2 files changed, 41 insertions, 1 deletions
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 4759b51de7..885a5adeec 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -864,9 +864,13 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, const LocationContext *LCtx = Pred->getLocationContext(); ProgramStateRef NewState = createTemporaryRegionIfNeeded(State, LCtx, OCE->getArg(0)); - if (NewState != State) + if (NewState != State) { Pred = Bldr.generateNode(OCE, Pred, NewState, /*Tag=*/0, ProgramPoint::PreStmtKind); + // Did we cache out? + if (!Pred) + break; + } } } // FALLTHROUGH diff --git a/test/Analysis/operator-calls.cpp b/test/Analysis/operator-calls.cpp index 4f686e55fd..7461d75f67 100644 --- a/test/Analysis/operator-calls.cpp +++ b/test/Analysis/operator-calls.cpp @@ -49,3 +49,39 @@ namespace UserDefinedConversions { clang_analyzer_eval(obj); // expected-warning{{TRUE}} } } + + +namespace RValues { + struct SmallOpaque { + float x; + int operator +() const { + return (int)x; + } + }; + + struct LargeOpaque { + float x[4]; + int operator +() const { + return (int)x[0]; + } + }; + + SmallOpaque getSmallOpaque() { + SmallOpaque obj; + obj.x = 1.0; + return obj; + } + + LargeOpaque getLargeOpaque() { + LargeOpaque obj = LargeOpaque(); + obj.x[0] = 1.0; + return obj; + } + + void test(int coin) { + // Force a cache-out when we try to conjure a temporary region for the operator call. + // ...then, don't crash. + clang_analyzer_eval(+(coin ? getSmallOpaque() : getSmallOpaque())); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(+(coin ? getLargeOpaque() : getLargeOpaque())); // expected-warning{{UNKNOWN}} + } +} |