summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorge Karpenkov <ekarpenkov@apple.com>2017-10-24 00:13:18 +0000
committerGeorge Karpenkov <ekarpenkov@apple.com>2017-10-24 00:13:18 +0000
commit98e81cd3be8adea3cf817b4efae6b0c0ae35646f (patch)
tree9c3fdd4f053c0c70fe45bac4b87dc94abf66dc59
parent619b3269fdaffbcb298c4d7b33cda7109a2082d6 (diff)
downloadbcm5719-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.cpp28
-rw-r--r--clang/test/Analysis/call_once.cpp13
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 &param) {
+ 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}}
+}
OpenPOWER on IntegriCloud