diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index f6a43bf5f493b..5dcf03f7a4648 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -554,6 +554,8 @@ class SimpleFunctionCall : public AnyFunctionCall { const FunctionDecl *getDecl() const override; + RuntimeDefinition getRuntimeDefinition() const override; + unsigned getNumArgs() const override { return getOriginExpr()->getNumArgs(); } const Expr *getArgExpr(unsigned Index) const override { diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index f78b1b84f9df6..34fcb9b64d555 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -688,6 +688,18 @@ const FunctionDecl *SimpleFunctionCall::getDecl() const { return getSVal(getOriginExpr()->getCallee()).getAsFunctionDecl(); } +RuntimeDefinition SimpleFunctionCall::getRuntimeDefinition() const { + // Clang converts lambdas to function pointers using an implicit conversion + // operator, which returns the lambda's '__invoke' method. However, Sema + // leaves the body of '__invoke' empty (it is generated later in CodeGen), so + // we need to skip '__invoke' and access the lambda's operator() directly. + if (const auto *CMD = dyn_cast_if_present(getDecl()); + CMD && CMD->isLambdaStaticInvoker()) + return RuntimeDefinition{CMD->getParent()->getLambdaCallOperator()}; + + return AnyFunctionCall::getRuntimeDefinition(); +} + const FunctionDecl *CXXInstanceCall::getDecl() const { const auto *CE = cast_or_null(getOriginExpr()); if (!CE) diff --git a/clang/test/Analysis/lambda-convert-to-func-ptr.cpp b/clang/test/Analysis/lambda-convert-to-func-ptr.cpp new file mode 100644 index 0000000000000..c2ad7cd2de34a --- /dev/null +++ b/clang/test/Analysis/lambda-convert-to-func-ptr.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s + +void clang_analyzer_eval(bool); + +void basic() { + int (*ret_zero)() = []() { return 0; }; + clang_analyzer_eval(ret_zero() == 0); // expected-warning{{TRUE}} +} + +void withParam() { + int (*add_ten)(int) = [](int b) { return b + 10; }; + clang_analyzer_eval(add_ten(1) == 11); // expected-warning{{TRUE}} +} + +int callBack(int (*fp)(int), int x) { + return fp(x); +} + +void passWithFunc() { + clang_analyzer_eval(callBack([](int x) { return x; }, 5) == 5); // expected-warning{{TRUE}} +}