[clang][analyzer] Correctly handle lambda-converted function pointers by flovent · Pull Request #144906 · llvm/llvm-project (original) (raw)
@llvm/pr-subscribers-clang
@llvm/pr-subscribers-clang-static-analyzer-1
Author: None (flovent)
Changes
For lambdas that are converted to C function pointers,
int (*ret_zero)() = []() { return 0; };
clang will generate conversion method like:
CXXConversionDecl implicit used constexpr operator int (*)() 'int (*() const noexcept)()' inline
-CompoundStmt
-ReturnStmt
-ImplicitCastExpr 'int (*)()' <FunctionToPointerDecay>
-DeclRefExpr 'int ()' lvalue CXXMethod 0x5ddb6fe35b18 '__invoke' 'int ()'
-CXXMethodDecl implicit used __invoke 'int ()' static inline
-CompoundStmt (empty)
Based on comment in Sema, __invoke's function body is left empty because it's will be filled in CodeGen, so in AST analysis phase we should get lambda's operator() directly instead of calling __invoke itself.
Full diff: https://github.com/llvm/llvm-project/pull/144906.diff
3 Files Affected:
- (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h (+2)
- (modified) clang/lib/StaticAnalyzer/Core/CallEvent.cpp (+12)
- (added) clang/test/Analysis/lambda-convert-to-func-ptr.cpp (+21)
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}} +}