From: Jordan Rose Date: Tue, 29 Apr 2014 17:08:12 +0000 (+0000) Subject: [analyzer] Don't assert when combining using .* on a temporary. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fc2409b63768662b077c920d5b4a84250d100b2e;p=clang [analyzer] Don't assert when combining using .* on a temporary. While we don't model pointer-to-member operators yet (neither .* nor ->*), CallAndMessageChecker still checks to make sure the 'this' object is not null or undefined first. However, it also expects that the object should always have a valid MemRegion, something that's generally important elsewhere in the analyzer as well. Ensure this is true ahead of time, just like we do for member access. PR19531 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@207561 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 91b072f66c..b754ecbffe 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -81,6 +81,12 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, } } + // Although we don't yet model pointers-to-members, we do need to make + // sure that the members of temporaries have a valid 'this' pointer for + // other checks. + if (B->getOpcode() == BO_PtrMemD) + state = createTemporaryRegionIfNeeded(state, LCtx, LHS); + // Process non-assignments except commas or short-circuited // logical expressions (LAnd and LOr). SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType()); diff --git a/test/Analysis/member-expr.cpp b/test/Analysis/member-expr.cpp index cf437387d6..f8dd324e98 100644 --- a/test/Analysis/member-expr.cpp +++ b/test/Analysis/member-expr.cpp @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection %s -verify +void clang_analyzer_checkInlined(bool); void clang_analyzer_eval(int); namespace EnumsViaMemberExpr { @@ -20,4 +21,21 @@ namespace EnumsViaMemberExpr { void testEnumPtr(Foo *Baz) { clang_analyzer_eval(Baz->Bar == Foo::Bar); // expected-warning{{TRUE}} } -} \ No newline at end of file +} + +namespace PR19531 { + struct A { + A() : x(0) {} + bool h() const; + int x; + }; + + struct B { + void g(bool (A::*mp_f)() const) { + // This used to trigger an assertion because the 'this' pointer is a + // temporary. + (A().*mp_f)(); + } + void f() { g(&A::h); } + }; +}