<div dir="ltr">This revision might be the cause of <a href="https://bugs.llvm.org/show_bug.cgi?id=34869">https://bugs.llvm.org/show_bug.cgi?id=34869</a>. I'm still working on a reduced test case.</div><div class="gmail_extra"><br><div class="gmail_quote">On Sat, Sep 30, 2017 at 2:03 AM, George Karpenkov via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: george.karpenkov<br>
Date: Fri Sep 29 17:03:22 2017<br>
New Revision: 314571<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=314571&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=314571&view=rev</a><br>
Log:<br>
[Analyzer] Synthesize function body for std::call_once<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D37840" rel="noreferrer" target="_blank">https://reviews.llvm.org/<wbr>D37840</a><br>
<br>
Added:<br>
    cfe/trunk/test/Analysis/call_<wbr>once.cpp<br>
Modified:<br>
    cfe/trunk/lib/Analysis/<wbr>BodyFarm.cpp<br>
<br>
Modified: cfe/trunk/lib/Analysis/<wbr>BodyFarm.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/BodyFarm.cpp?rev=314571&r1=314570&r2=314571&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/<wbr>Analysis/BodyFarm.cpp?rev=<wbr>314571&r1=314570&r2=314571&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Analysis/<wbr>BodyFarm.cpp (original)<br>
+++ cfe/trunk/lib/Analysis/<wbr>BodyFarm.cpp Fri Sep 29 17:03:22 2017<br>
@@ -14,11 +14,18 @@<br>
<br>
 #include "BodyFarm.h"<br>
 #include "clang/AST/ASTContext.h"<br>
+#include "clang/AST/CXXInheritance.h"<br>
 #include "clang/AST/Decl.h"<br>
 #include "clang/AST/Expr.h"<br>
+#include "clang/AST/ExprCXX.h"<br>
 #include "clang/AST/ExprObjC.h"<br>
+#include "clang/AST/<wbr>NestedNameSpecifier.h"<br>
 #include "clang/Analysis/CodeInjector.<wbr>h"<br>
+#include "clang/Basic/OperatorKinds.h"<br>
 #include "llvm/ADT/StringSwitch.h"<br>
+#include "llvm/Support/Debug.h"<br>
+<br>
+#define DEBUG_TYPE "body-farm"<br>
<br>
 using namespace clang;<br>
<br>
@@ -55,7 +62,9 @@ public:<br>
   CompoundStmt *makeCompound(ArrayRef<Stmt*>)<wbr>;<br>
<br>
   /// Create a new DeclRefExpr for the referenced variable.<br>
-  DeclRefExpr *makeDeclRefExpr(const VarDecl *D);<br>
+  DeclRefExpr *makeDeclRefExpr(const VarDecl *D,<br>
+                               bool RefersToEnclosingVariableOrCap<wbr>ture = false,<br>
+                               bool GetNonReferenceType = false);<br>
<br>
   /// Create a new UnaryOperator representing a dereference.<br>
   UnaryOperator *makeDereference(const Expr *Arg, QualType Ty);<br>
@@ -66,9 +75,24 @@ public:<br>
   /// Create an implicit cast to a builtin boolean type.<br>
   ImplicitCastExpr *makeIntegralCastToBoolean(<wbr>const Expr *Arg);<br>
<br>
-  // Create an implicit cast for lvalue-to-rvaluate conversions.<br>
+  /// Create an implicit cast for lvalue-to-rvaluate conversions.<br>
   ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty);<br>
<br>
+  /// Create an implicit cast for lvalue-to-rvaluate conversions.<br>
+  ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg,<br>
+                                       bool GetNonReferenceType = false);<br>
+<br>
+  /// Make RValue out of variable declaration, creating a temporary<br>
+  /// DeclRefExpr in the process.<br>
+  ImplicitCastExpr *<br>
+  makeLvalueToRvalue(const VarDecl *Decl,<br>
+                     bool RefersToEnclosingVariableOrCap<wbr>ture = false,<br>
+                     bool GetNonReferenceType = false);<br>
+<br>
+  /// Create an implicit cast of the given type.<br>
+  ImplicitCastExpr *makeImplicitCast(const Expr *Arg, QualType Ty,<br>
+                                     CastKind CK = CK_LValueToRValue);<br>
+<br>
   /// Create an Objective-C bool literal.<br>
   ObjCBoolLiteralExpr *makeObjCBool(bool Val);<br>
<br>
@@ -78,6 +102,18 @@ public:<br>
   /// Create a Return statement.<br>
   ReturnStmt *makeReturn(const Expr *RetVal);<br>
<br>
+  /// Create an integer literal.<br>
+  IntegerLiteral *makeIntegerLiteral(uint64_t value);<br>
+<br>
+  /// Create a member expression.<br>
+  MemberExpr *makeMemberExpression(Expr *base, ValueDecl *MemberDecl,<br>
+                                   bool IsArrow = false,<br>
+                                   ExprValueKind ValueKind = VK_LValue);<br>
+<br>
+  /// Returns a *first* member field of a record declaration with a given name.<br>
+  /// \return an nullptr if no member with such a name exists.<br>
+  NamedDecl *findMemberField(const CXXRecordDecl *RD, StringRef Name);<br>
+<br>
 private:<br>
   ASTContext &C;<br>
 };<br>
@@ -106,16 +142,16 @@ CompoundStmt *ASTMaker::makeCompound(Arr<br>
   return new (C) CompoundStmt(C, Stmts, SourceLocation(), SourceLocation());<br>
 }<br>
<br>
-DeclRefExpr *ASTMaker::makeDeclRefExpr(<wbr>const VarDecl *D) {<br>
-  DeclRefExpr *DR =<br>
-    DeclRefExpr::Create(/* Ctx = */ C,<br>
-                        /* QualifierLoc = */ NestedNameSpecifierLoc(),<br>
-                        /* TemplateKWLoc = */ SourceLocation(),<br>
-                        /* D = */ const_cast<VarDecl*>(D),<br>
-                        /* RefersToEnclosingVariableOrCap<wbr>ture = */ false,<br>
-                        /* NameLoc = */ SourceLocation(),<br>
-                        /* T = */ D->getType(),<br>
-                        /* VK = */ VK_LValue);<br>
+DeclRefExpr *ASTMaker::makeDeclRefExpr(<wbr>const VarDecl *D,<br>
+                                       bool RefersToEnclosingVariableOrCap<wbr>ture,<br>
+                                       bool GetNonReferenceType) {<br>
+  auto Type = D->getType();<br>
+  if (GetNonReferenceType)<br>
+    Type = Type.getNonReferenceType();<br>
+<br>
+  DeclRefExpr *DR = DeclRefExpr::Create(<br>
+      C, NestedNameSpecifierLoc(), SourceLocation(), const_cast<VarDecl *>(D),<br>
+      RefersToEnclosingVariableOrCap<wbr>ture, SourceLocation(), Type, VK_LValue);<br>
   return DR;<br>
 }<br>
<br>
@@ -125,8 +161,38 @@ UnaryOperator *ASTMaker::makeDereference<br>
 }<br>
<br>
 ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(<wbr>const Expr *Arg, QualType Ty) {<br>
-  return ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,<br>
-                                  const_cast<Expr*>(Arg), nullptr, VK_RValue);<br>
+  return makeImplicitCast(Arg, Ty, CK_LValueToRValue);<br>
+}<br>
+<br>
+ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(<wbr>const Expr *Arg,<br>
+                                               bool GetNonReferenceType) {<br>
+<br>
+  QualType Type = Arg->getType();<br>
+  if (GetNonReferenceType)<br>
+    Type = Type.getNonReferenceType();<br>
+  return makeImplicitCast(Arg, Type, CK_LValueToRValue);<br>
+}<br>
+<br>
+ImplicitCastExpr *<br>
+ASTMaker::makeLvalueToRvalue(<wbr>const VarDecl *Arg,<br>
+                             bool RefersToEnclosingVariableOrCap<wbr>ture,<br>
+                             bool GetNonReferenceType) {<br>
+  auto Type = Arg->getType();<br>
+  if (GetNonReferenceType)<br>
+    Type = Type.getNonReferenceType();<br>
+  return makeLvalueToRvalue(<wbr>makeDeclRefExpr(Arg,<br>
+                                            RefersToEnclosingVariableOrCap<wbr>ture,<br>
+                                            GetNonReferenceType),<br>
+                            Type);<br>
+}<br>
+<br>
+ImplicitCastExpr *ASTMaker::makeImplicitCast(<wbr>const Expr *Arg, QualType Ty,<br>
+                                             CastKind CK) {<br>
+  return ImplicitCastExpr::Create(C, Ty,<br>
+                                  /* CastKind= */ CK,<br>
+                                  /* Expr= */ const_cast<Expr *>(Arg),<br>
+                                  /* CXXCastPath= */ nullptr,<br>
+                                  /* ExprValueKind= */ VK_RValue);<br>
 }<br>
<br>
 Expr *ASTMaker::makeIntegralCast(<wbr>const Expr *Arg, QualType Ty) {<br>
@@ -161,12 +227,196 @@ ReturnStmt *ASTMaker::makeReturn(const E<br>
                             nullptr);<br>
 }<br>
<br>
+IntegerLiteral *ASTMaker::makeIntegerLiteral(<wbr>uint64_t value) {<br>
+  return IntegerLiteral::Create(C,<br>
+                                llvm::APInt(<br>
+                                    /*numBits=*/C.getTypeSize(C.<wbr>IntTy), value),<br>
+                                /*QualType=*/C.IntTy, SourceLocation());<br>
+}<br>
+<br>
+MemberExpr *ASTMaker::<wbr>makeMemberExpression(Expr *base, ValueDecl *MemberDecl,<br>
+                                           bool IsArrow,<br>
+                                           ExprValueKind ValueKind) {<br>
+<br>
+  DeclAccessPair FoundDecl = DeclAccessPair::make(<wbr>MemberDecl, AS_public);<br>
+  return MemberExpr::Create(<br>
+      C, base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(),<br>
+      SourceLocation(), MemberDecl, FoundDecl,<br>
+      DeclarationNameInfo(<wbr>MemberDecl->getDeclName(), SourceLocation()),<br>
+      /* TemplateArgumentListInfo= */ nullptr, MemberDecl->getType(), ValueKind,<br>
+      OK_Ordinary);<br>
+}<br>
+<br>
+NamedDecl *ASTMaker::findMemberField(<wbr>const CXXRecordDecl *RD, StringRef Name) {<br>
+<br>
+  CXXBasePaths Paths(<br>
+      /* FindAmbiguities=*/false,<br>
+      /* RecordPaths=*/false,<br>
+      /* DetectVirtual= */ false);<br>
+  const IdentifierInfo &II = C.Idents.get(Name);<br>
+  DeclarationName DeclName = C.DeclarationNames.<wbr>getIdentifier(&II);<br>
+<br>
+  DeclContextLookupResult Decls = RD->lookup(DeclName);<br>
+  for (NamedDecl *FoundDecl : Decls)<br>
+    if (!FoundDecl->getDeclContext()-<wbr>>isFunctionOrMethod())<br>
+      return FoundDecl;<br>
+<br>
+  return nullptr;<br>
+}<br>
+<br>
 //===-------------------------<wbr>------------------------------<wbr>---------------===//<br>
 // Creation functions for faux ASTs.<br>
 //===-------------------------<wbr>------------------------------<wbr>---------------===//<br>
<br>
 typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);<br>
<br>
+static CallExpr *<br>
+create_call_once_funcptr_<wbr>call(ASTContext &C, ASTMaker M,<br>
+                              const ParmVarDecl *Callback,<br>
+                              SmallVectorImpl<Expr *> &CallArgs) {<br>
+<br>
+  return new (C) CallExpr(<br>
+      /*ASTContext=*/C,<br>
+      /*StmtClass=*/M.<wbr>makeLvalueToRvalue(/*Expr=*/<wbr>Callback),<br>
+      /*args=*/CallArgs,<br>
+      /*QualType=*/C.VoidTy,<br>
+      /*ExprValueType=*/VK_RValue,<br>
+      /*SourceLocation=*/<wbr>SourceLocation());<br>
+}<br>
+<br>
+static CallExpr *<br>
+create_call_once_lambda_call(<wbr>ASTContext &C, ASTMaker M,<br>
+                             const ParmVarDecl *Callback, QualType CallbackType,<br>
+                             SmallVectorImpl<Expr *> &CallArgs) {<br>
+<br>
+  CXXRecordDecl *CallbackDecl = CallbackType-><wbr>getAsCXXRecordDecl();<br>
+<br>
+  assert(CallbackDecl != nullptr);<br>
+  assert(CallbackDecl->isLambda(<wbr>));<br>
+  FunctionDecl *callOperatorDecl = CallbackDecl-><wbr>getLambdaCallOperator();<br>
+  assert(callOperatorDecl != nullptr);<br>
+<br>
+  DeclRefExpr *callOperatorDeclRef =<br>
+      DeclRefExpr::Create(/* Ctx = */ C,<br>
+                          /* QualifierLoc = */ NestedNameSpecifierLoc(),<br>
+                          /* TemplateKWLoc = */ SourceLocation(),<br>
+                          const_cast<FunctionDecl *>(callOperatorDecl),<br>
+                          /* RefersToEnclosingVariableOrCap<wbr>ture= */ false,<br>
+                          /* NameLoc = */ SourceLocation(),<br>
+                          /* T = */ callOperatorDecl->getType(),<br>
+                          /* VK = */ VK_LValue);<br>
+<br>
+  CallArgs.insert(<br>
+      CallArgs.begin(),<br>
+      M.makeDeclRefExpr(Callback,<br>
+                        /* RefersToEnclosingVariableOrCap<wbr>ture= */ true,<br>
+                        /* GetNonReferenceType= */ true));<br>
+<br>
+  return new (C)<br>
+      CXXOperatorCallExpr(/*<wbr>AstContext=*/C, OO_Call, callOperatorDeclRef,<br>
+                          /*args=*/CallArgs,<br>
+                          /*QualType=*/C.VoidTy,<br>
+                          /*ExprValueType=*/VK_RValue,<br>
+                          /*SourceLocation=*/<wbr>SourceLocation(), FPOptions());<br>
+}<br>
+<br>
+/// Create a fake body for std::call_once.<br>
+/// Emulates the following function body:<br>
+///<br>
+/// \code<br>
+/// typedef struct once_flag_s {<br>
+///   unsigned long __state = 0;<br>
+/// } once_flag;<br>
+/// template<class Callable><br>
+/// void call_once(once_flag& o, Callable func) {<br>
+///   if (!o.__state) {<br>
+///     func();<br>
+///   }<br>
+///   o.__state = 1;<br>
+/// }<br>
+/// \endcode<br>
+static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) {<br>
+  DEBUG(llvm::dbgs() << "Generating body for call_once\n");<br>
+<br>
+  // We need at least two parameters.<br>
+  if (D->param_size() < 2)<br>
+    return nullptr;<br>
+<br>
+  ASTMaker M(C);<br>
+<br>
+  const ParmVarDecl *Flag = D->getParamDecl(0);<br>
+  const ParmVarDecl *Callback = D->getParamDecl(1);<br>
+  QualType CallbackType = Callback->getType().<wbr>getNonReferenceType();<br>
+<br>
+  SmallVector<Expr *, 5> CallArgs;<br>
+<br>
+  // All arguments past first two ones are passed to the callback.<br>
+  for (unsigned int i = 2; i < D->getNumParams(); i++)<br>
+    CallArgs.push_back(M.<wbr>makeLvalueToRvalue(D-><wbr>getParamDecl(i)));<br>
+<br>
+  CallExpr *CallbackCall;<br>
+  if (CallbackType-><wbr>getAsCXXRecordDecl() &&<br>
+      CallbackType-><wbr>getAsCXXRecordDecl()-><wbr>isLambda()) {<br>
+<br>
+    CallbackCall =<br>
+        create_call_once_lambda_call(<wbr>C, M, Callback, CallbackType, CallArgs);<br>
+  } else {<br>
+<br>
+    // Function pointer case.<br>
+    CallbackCall = create_call_once_funcptr_call(<wbr>C, M, Callback, CallArgs);<br>
+  }<br>
+<br>
+  QualType FlagType = Flag->getType().<wbr>getNonReferenceType();<br>
+  DeclRefExpr *FlagDecl =<br>
+      M.makeDeclRefExpr(Flag,<br>
+                        /* RefersToEnclosingVariableOrCap<wbr>ture=*/true,<br>
+                        /* GetNonReferenceType=*/true);<br>
+<br>
+  CXXRecordDecl *FlagCXXDecl = FlagType->getAsCXXRecordDecl()<wbr>;<br>
+<br>
+  // Note: here we are assuming libc++ implementation of call_once,<br>
+  // which has a struct with a field `__state_`.<br>
+  // Body farming might not work for other `call_once` implementations.<br>
+  NamedDecl *FoundDecl = M.findMemberField(FlagCXXDecl, "__state_");<br>
+  ValueDecl *FieldDecl;<br>
+  if (FoundDecl) {<br>
+    FieldDecl = dyn_cast<ValueDecl>(FoundDecl)<wbr>;<br>
+  } else {<br>
+    DEBUG(llvm::dbgs() << "No field __state_ found on std::once_flag struct, "<br>
+                       << "unable to synthesize call_once body, ignoring "<br>
+                       << "the call.\n");<br>
+    return nullptr;<br>
+  }<br>
+<br>
+  MemberExpr *Deref = M.makeMemberExpression(<wbr>FlagDecl, FieldDecl);<br>
+  assert(Deref->isLValue());<br>
+  QualType DerefType = Deref->getType();<br>
+<br>
+  // Negation predicate.<br>
+  UnaryOperator *FlagCheck = new (C) UnaryOperator(<br>
+      /* input= */<br>
+      M.makeImplicitCast(M.<wbr>makeLvalueToRvalue(Deref, DerefType), DerefType,<br>
+                         CK_IntegralToBoolean),<br>
+      /* opc= */ UO_LNot,<br>
+      /* QualType= */ C.IntTy,<br>
+      /* ExprValueKind= */ VK_RValue,<br>
+      /* ExprObjectKind= */ OK_Ordinary, SourceLocation());<br>
+<br>
+  // Create assignment.<br>
+  BinaryOperator *FlagAssignment = M.makeAssignment(<br>
+      Deref, M.makeIntegralCast(M.<wbr>makeIntegerLiteral(1), DerefType), DerefType);<br>
+<br>
+  IfStmt *Out = new (C)<br>
+      IfStmt(C, SourceLocation(),<br>
+             /* IsConstexpr= */ false,<br>
+             /* init= */ nullptr,<br>
+             /* var= */ nullptr,<br>
+             /* cond= */ FlagCheck,<br>
+             /* then= */ M.makeCompound({CallbackCall, FlagAssignment}));<br>
+<br>
+  return Out;<br>
+}<br>
+<br>
 /// Create a fake body for dispatch_once.<br>
 static Stmt *create_dispatch_once(<wbr>ASTContext &C, const FunctionDecl *D) {<br>
   // Check if we have at least two parameters.<br>
@@ -202,15 +452,17 @@ static Stmt *create_dispatch_once(ASTCon<br>
   ASTMaker M(C);<br>
<br>
   // (1) Create the call.<br>
-  DeclRefExpr *DR = M.makeDeclRefExpr(Block);<br>
-  ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);<br>
-  CallExpr *CE = new (C) CallExpr(C, ICE, None, C.VoidTy, VK_RValue,<br>
-                                  SourceLocation());<br>
+  CallExpr *CE = new (C) CallExpr(<br>
+      /*ASTContext=*/C,<br>
+      /*StmtClass=*/M.<wbr>makeLvalueToRvalue(/*Expr=*/<wbr>Block),<br>
+      /*args=*/None,<br>
+      /*QualType=*/C.VoidTy,<br>
+      /*ExprValueType=*/VK_RValue,<br>
+      /*SourceLocation=*/<wbr>SourceLocation());<br>
<br>
   // (2) Create the assignment to the predicate.<br>
-  IntegerLiteral *IL =<br>
-    IntegerLiteral::Create(C, llvm::APInt(C.getTypeSize(C.<wbr>IntTy), (uint64_t) 1),<br>
-                           C.IntTy, SourceLocation());<br>
+  IntegerLiteral *IL = M.makeIntegerLiteral(1);<br>
+<br>
   BinaryOperator *B =<br>
     M.makeAssignment(<br>
        M.makeDereference(<br>
@@ -234,13 +486,20 @@ static Stmt *create_dispatch_once(ASTCon<br>
         PredicateTy),<br>
     PredicateTy);<br>
<br>
-  UnaryOperator *UO = new (C) UnaryOperator(LValToRval, UO_LNot, C.IntTy,<br>
-                                           VK_RValue, OK_Ordinary,<br>
-                                           SourceLocation());<br>
+  UnaryOperator *UO = new (C) UnaryOperator(<br>
+      /* input= */ LValToRval,<br>
+      /* opc= */ UO_LNot,<br>
+      /* QualType= */ C.IntTy,<br>
+      /* ExprValueKind= */ VK_RValue,<br>
+      /* ExprObjectKind= */ OK_Ordinary, SourceLocation());<br>
<br>
   // (5) Create the 'if' statement.<br>
-  IfStmt *If = new (C) IfStmt(C, SourceLocation(), false, nullptr, nullptr,<br>
-                              UO, CS);<br>
+  IfStmt *If = new (C) IfStmt(C, SourceLocation(),<br>
+                              /* IsConstexpr= */ false,<br>
+                              /* init= */ nullptr,<br>
+                              /* var= */ nullptr,<br>
+                              /* cond= */ UO,<br>
+                              /* then= */ CS);<br>
   return If;<br>
 }<br>
<br>
@@ -370,8 +629,9 @@ Stmt *BodyFarm::getBody(const FunctionDe<br>
   if (Name.startswith("<wbr>OSAtomicCompareAndSwap") ||<br>
       Name.startswith("objc_<wbr>atomicCompareAndSwap")) {<br>
     FF = create_OSAtomicCompareAndSwap;<br>
-  }<br>
-  else {<br>
+  } else if (Name == "call_once" && D->getDeclContext()-><wbr>isStdNamespace()) {<br>
+    FF = create_call_once;<br>
+  } else {<br>
     FF = llvm::StringSwitch<<wbr>FunctionFarmer>(Name)<br>
           .Case("dispatch_sync", create_dispatch_sync)<br>
           .Case("dispatch_once", create_dispatch_once)<br>
<br>
Added: cfe/trunk/test/Analysis/call_<wbr>once.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/call_once.cpp?rev=314571&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/<wbr>Analysis/call_once.cpp?rev=<wbr>314571&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/Analysis/call_<wbr>once.cpp (added)<br>
+++ cfe/trunk/test/Analysis/call_<wbr>once.cpp Fri Sep 29 17:03:22 2017<br>
@@ -0,0 +1,233 @@<br>
+// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.<wbr>ExprInspection -w -verify %s<br>
+<br>
+void clang_analyzer_eval(bool);<br>
+<br>
+// Faking std::std::call_once implementation.<br>
+namespace std {<br>
+typedef struct once_flag_s {<br>
+  unsigned long __state_ = 0;<br>
+} once_flag;<br>
+<br>
+template <class Callable, class... Args><br>
+void call_once(once_flag &o, Callable func, Args... args);<br>
+} // namespace std<br>
+<br>
+// Check with Lambdas.<br>
+void test_called_warning() {<br>
+  std::once_flag g_initialize;<br>
+  int z;<br>
+<br>
+  std::call_once(g_initialize, [&] {<br>
+    int *x = nullptr;<br>
+    int y = *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}<br>
+    z = 200;<br>
+  });<br>
+}<br>
+<br>
+void test_called_on_path_inside_no_<wbr>warning() {<br>
+  std::once_flag g_initialize;<br>
+<br>
+  int *x = nullptr;<br>
+  int y = 100;<br>
+  int z;<br>
+<br>
+  std::call_once(g_initialize, [&] {<br>
+    z = 200;<br>
+    x = &z;<br>
+  });<br>
+<br>
+  *x = 100; // no-warning<br>
+  clang_analyzer_eval(z == 100); // expected-warning{{TRUE}}<br>
+}<br>
+<br>
+void test_called_on_path_no_<wbr>warning() {<br>
+  std::once_flag g_initialize;<br>
+<br>
+  int *x = nullptr;<br>
+  int y = 100;<br>
+<br>
+  std::call_once(g_initialize, [&] {<br>
+    x = &y;<br>
+  });<br>
+<br>
+  *x = 100; // no-warning<br>
+}<br>
+<br>
+void test_called_on_path_warning() {<br>
+  std::once_flag g_initialize;<br>
+<br>
+  int y = 100;<br>
+  int *x = &y;<br>
+<br>
+  std::call_once(g_initialize, [&] {<br>
+    x = nullptr;<br>
+  });<br>
+<br>
+  *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}<br>
+}<br>
+<br>
+void test_called_once_warning() {<br>
+  std::once_flag g_initialize;<br>
+<br>
+  int *x = nullptr;<br>
+  int y = 100;<br>
+<br>
+  std::call_once(g_initialize, [&] {<br>
+    x = nullptr;<br>
+  });<br>
+<br>
+  std::call_once(g_initialize, [&] {<br>
+    x = &y;<br>
+  });<br>
+<br>
+  *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}<br>
+}<br>
+<br>
+void test_called_once_no_warning() {<br>
+  std::once_flag g_initialize;<br>
+<br>
+  int *x = nullptr;<br>
+  int y = 100;<br>
+<br>
+  std::call_once(g_initialize, [&] {<br>
+    x = &y;<br>
+  });<br>
+<br>
+  std::call_once(g_initialize, [&] {<br>
+    x = nullptr;<br>
+  });<br>
+<br>
+  *x = 100; // no-warning<br>
+}<br>
+<br>
+static int global = 0;<br>
+void funcPointer() {<br>
+  global = 1;<br>
+}<br>
+<br>
+void test_func_pointers() {<br>
+  static std::once_flag flag;<br>
+  std::call_once(flag, &funcPointer);<br>
+  clang_analyzer_eval(global == 1); // expected-warning{{TRUE}}<br>
+}<br>
+<br>
+template <class _Fp><br>
+class function; // undefined<br>
+template <class _Rp, class... _ArgTypes><br>
+struct function<_Rp(_ArgTypes...)> {<br>
+  _Rp operator()(_ArgTypes...) const;<br>
+  template <class _Fp><br>
+  function(_Fp);<br>
+};<br>
+<br>
+// Note: currently we do not support calls to std::function,<br>
+// but the analyzer should not crash either.<br>
+void test_function_objects_warning(<wbr>) {<br>
+  int x = 0;<br>
+  int *y = &x;<br>
+<br>
+  std::once_flag flag;<br>
+<br>
+  function<void()> func = [&]() {<br>
+    y = nullptr;<br>
+  };<br>
+<br>
+  std::call_once(flag, func);<br>
+<br>
+  func();<br>
+  int z = *y;<br>
+}<br>
+<br>
+void test_param_passing_lambda() {<br>
+  std::once_flag flag;<br>
+  int x = 120;<br>
+  int y = 0;<br>
+<br>
+  std::call_once(flag, [&](int p) {<br>
+    y = p;<br>
+  },<br>
+                 x);<br>
+<br>
+  clang_analyzer_eval(y == 120); // expected-warning{{TRUE}}<br>
+}<br>
+<br>
+void test_param_passing_lambda_<wbr>false() {<br>
+  std::once_flag flag;<br>
+  int x = 120;<br>
+<br>
+  std::call_once(flag, [&](int p) {<br>
+    x = 0;<br>
+  },<br>
+                 x);<br>
+<br>
+  clang_analyzer_eval(x == 120); // expected-warning{{FALSE}}<br>
+}<br>
+<br>
+void test_param_passing_stored_<wbr>lambda() {<br>
+  std::once_flag flag;<br>
+  int x = 120;<br>
+  int y = 0;<br>
+<br>
+  auto lambda = [&](int p) {<br>
+    y = p;<br>
+  };<br>
+<br>
+  std::call_once(flag, lambda, x);<br>
+  clang_analyzer_eval(y == 120); // expected-warning{{TRUE}}<br>
+}<br>
+<br>
+void test_multiparam_passing_<wbr>lambda() {<br>
+  std::once_flag flag;<br>
+  int x = 120;<br>
+<br>
+  std::call_once(flag, [&](int a, int b, int c) {<br>
+    x = a + b + c;<br>
+  },<br>
+                 1, 2, 3);<br>
+<br>
+  clang_analyzer_eval(x == 120); // expected-warning{{FALSE}}<br>
+  clang_analyzer_eval(x == 6); // expected-warning{{TRUE}}<br>
+}<br>
+<br>
+static int global2 = 0;<br>
+void test_param_passing_lambda_<wbr>global() {<br>
+  std::once_flag flag;<br>
+  global2 = 0;<br>
+  std::call_once(flag, [&](int a, int b, int c) {<br>
+    global2 = a + b + c;<br>
+  },<br>
+                 1, 2, 3);<br>
+  clang_analyzer_eval(global2 == 6); // expected-warning{{TRUE}}<br>
+}<br>
+<br>
+static int global3 = 0;<br>
+void funcptr(int a, int b, int c) {<br>
+  global3 = a + b + c;<br>
+}<br>
+<br>
+void test_param_passing_funcptr() {<br>
+  std::once_flag flag;<br>
+  global3 = 0;<br>
+<br>
+  std::call_once(flag, &funcptr, 1, 2, 3);<br>
+<br>
+  clang_analyzer_eval(global3 == 6); // expected-warning{{TRUE}}<br>
+}<br>
+<br>
+void test_blocks() {<br>
+  global3 = 0;<br>
+  std::once_flag flag;<br>
+  std::call_once(flag, ^{<br>
+    global3 = 120;<br>
+  });<br>
+  clang_analyzer_eval(global3 == 120); // expected-warning{{TRUE}}<br>
+}<br>
+<br>
+int call_once() {<br>
+  return 5;<br>
+}<br>
+<br>
+void test_non_std_call_once() {<br>
+  int x = call_once();<br>
+  clang_analyzer_eval(x == 5); // expected-warning{{TRUE}}<br>
+}<br>
<br>
<br>
______________________________<wbr>_________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>