[Analyzer] Handle implicit function reference in bodyfarming std::call_once
authorGeorge Karpenkov <ekarpenkov@apple.com>
Tue, 24 Oct 2017 00:13:18 +0000 (00:13 +0000)
committerGeorge Karpenkov <ekarpenkov@apple.com>
Tue, 24 Oct 2017 00:13:18 +0000 (00:13 +0000)
Differential Revision: https://reviews.llvm.org/D39201

llvm-svn: 316402

clang/lib/Analysis/BodyFarm.cpp
clang/test/Analysis/call_once.cpp

index dd34884..8a56b76 100644 (file)
@@ -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)
index db70145..2154be6 100644 (file)
@@ -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}}
+}