diff options
author | George Karpenkov <ekarpenkov@apple.com> | 2017-10-24 00:13:18 +0000 |
---|---|---|
committer | George Karpenkov <ekarpenkov@apple.com> | 2017-10-24 00:13:18 +0000 |
commit | 98e81cd3be8adea3cf817b4efae6b0c0ae35646f (patch) | |
tree | 9c3fdd4f053c0c70fe45bac4b87dc94abf66dc59 | |
parent | 619b3269fdaffbcb298c4d7b33cda7109a2082d6 (diff) | |
download | bcm5719-llvm-98e81cd3be8adea3cf817b4efae6b0c0ae35646f.tar.gz bcm5719-llvm-98e81cd3be8adea3cf817b4efae6b0c0ae35646f.zip |
[Analyzer] Handle implicit function reference in bodyfarming std::call_once
Differential Revision: https://reviews.llvm.org/D39201
llvm-svn: 316402
-rw-r--r-- | clang/lib/Analysis/BodyFarm.cpp | 28 | ||||
-rw-r--r-- | clang/test/Analysis/call_once.cpp | 13 |
2 files changed, 33 insertions, 8 deletions
diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp index dd348847b3c..8a56b761ecd 100644 --- a/clang/lib/Analysis/BodyFarm.cpp +++ b/clang/lib/Analysis/BodyFarm.cpp @@ -253,13 +253,23 @@ static CallExpr *create_call_once_funcptr_call(ASTContext &C, ASTMaker M, const ParmVarDecl *Callback, ArrayRef<Expr *> CallArgs) { - return new (C) CallExpr( - /*ASTContext=*/C, - /*StmtClass=*/M.makeLvalueToRvalue(/*Expr=*/Callback), - /*args=*/CallArgs, - /*QualType=*/C.VoidTy, - /*ExprValueType=*/VK_RValue, - /*SourceLocation=*/SourceLocation()); + QualType Ty = Callback->getType(); + DeclRefExpr *Call = M.makeDeclRefExpr(Callback); + CastKind CK; + if (Ty->isRValueReferenceType()) { + CK = CK_LValueToRValue; + } else { + assert(Ty->isLValueReferenceType()); + CK = CK_FunctionToPointerDecay; + Ty = C.getPointerType(Ty.getNonReferenceType()); + } + + return new (C) + CallExpr(C, M.makeImplicitCast(Call, Ty.getNonReferenceType(), CK), + /*args=*/CallArgs, + /*QualType=*/C.VoidTy, + /*ExprValueType=*/VK_RValue, + /*SourceLocation=*/SourceLocation()); } static CallExpr *create_call_once_lambda_call(ASTContext &C, ASTMaker M, @@ -366,9 +376,11 @@ static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) { CallbackFunctionType = CallbackRecordDecl->getLambdaCallOperator() ->getType() ->getAs<FunctionProtoType>(); - } else { + } else if (!CallbackType->getPointeeType().isNull()) { CallbackFunctionType = CallbackType->getPointeeType()->getAs<FunctionProtoType>(); + } else { + CallbackFunctionType = CallbackType->getAs<FunctionProtoType>(); } if (!CallbackFunctionType) diff --git a/clang/test/Analysis/call_once.cpp b/clang/test/Analysis/call_once.cpp index db701457f6a..2154be6f48b 100644 --- a/clang/test/Analysis/call_once.cpp +++ b/clang/test/Analysis/call_once.cpp @@ -290,3 +290,16 @@ void test_mutator_noref() { std::call_once(flag, &fail_mutator, a); clang_analyzer_eval(a == 42); // expected-warning{{FALSE}} } + +// Function is implicitly treated as a function pointer +// even when an ampersand is not explicitly set. +void callbackn(int ¶m) { + param = 42; +}; +void test_implicit_funcptr() { + int x = 0; + static std::once_flag flagn; + + std::call_once(flagn, callbackn, x); + clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} +} |