[PATCH] D38810: [Analyzer] Support bodyfarming std::call_once for libstdc++

2017-10-11 Thread George Karpenkov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL315508: [Analyzer] Support bodyfarming libstdc++ 
implementation of std::call_once. (authored by george.karpenkov).

Changed prior to commit:
  https://reviews.llvm.org/D38810?vs=118644=118686#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D38810

Files:
  cfe/trunk/lib/Analysis/BodyFarm.cpp
  cfe/trunk/test/Analysis/call_once.cpp

Index: cfe/trunk/test/Analysis/call_once.cpp
===
--- cfe/trunk/test/Analysis/call_once.cpp
+++ cfe/trunk/test/Analysis/call_once.cpp
@@ -1,15 +1,24 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -w -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBSTDCPP -verify %s
 
 void clang_analyzer_eval(bool);
 
 // Faking std::std::call_once implementation.
 namespace std {
+
+#ifndef EMULATE_LIBSTDCPP
 typedef struct once_flag_s {
   unsigned long __state_ = 0;
 } once_flag;
+#else
+typedef struct once_flag_s {
+  int _M_once = 0;
+} once_flag;
+#endif
 
 template 
 void call_once(once_flag , Callable func, Args... args) {};
+
 } // namespace std
 
 // Check with Lambdas.
Index: cfe/trunk/lib/Analysis/BodyFarm.cpp
===
--- cfe/trunk/lib/Analysis/BodyFarm.cpp
+++ cfe/trunk/lib/Analysis/BodyFarm.cpp
@@ -108,7 +108,7 @@
 
   /// Returns a *first* member field of a record declaration with a given name.
   /// \return an nullptr if no member with such a name exists.
-  NamedDecl *findMemberField(const CXXRecordDecl *RD, StringRef Name);
+  ValueDecl *findMemberField(const RecordDecl *RD, StringRef Name);
 
 private:
   ASTContext 
@@ -234,7 +234,7 @@
   OK_Ordinary);
 }
 
-NamedDecl *ASTMaker::findMemberField(const CXXRecordDecl *RD, StringRef Name) {
+ValueDecl *ASTMaker::findMemberField(const RecordDecl *RD, StringRef Name) {
 
   CXXBasePaths Paths(
   /* FindAmbiguities=*/false,
@@ -246,7 +246,7 @@
   DeclContextLookupResult Decls = RD->lookup(DeclName);
   for (NamedDecl *FoundDecl : Decls)
 if (!FoundDecl->getDeclContext()->isFunctionOrMethod())
-  return FoundDecl;
+  return cast(FoundDecl);
 
   return nullptr;
 }
@@ -328,25 +328,31 @@
   const ParmVarDecl *Callback = D->getParamDecl(1);
   QualType CallbackType = Callback->getType().getNonReferenceType();
   QualType FlagType = Flag->getType().getNonReferenceType();
-  CXXRecordDecl *FlagCXXDecl = FlagType->getAsCXXRecordDecl();
-  if (!FlagCXXDecl) {
-DEBUG(llvm::dbgs() << "Flag field is not a CXX record: "
-   << "unknown std::call_once implementation."
-   << "Ignoring the call.\n");
+  auto *FlagRecordDecl = dyn_cast_or_null(FlagType->getAsTagDecl());
+
+  if (!FlagRecordDecl) {
+DEBUG(llvm::dbgs() << "Flag field is not a record: "
+   << "unknown std::call_once implementation, "
+   << "ignoring the call.\n");
 return nullptr;
   }
 
-  // Note: here we are assuming libc++ implementation of call_once,
-  // which has a struct with a field `__state_`.
-  // Body farming might not work for other `call_once` implementations.
-  NamedDecl *FoundDecl = M.findMemberField(FlagCXXDecl, "__state_");
-  ValueDecl *FieldDecl;
-  if (FoundDecl) {
-FieldDecl = dyn_cast(FoundDecl);
-  } else {
+  // We initially assume libc++ implementation of call_once,
+  // where the once_flag struct has a field `__state_`.
+  ValueDecl *FlagFieldDecl = M.findMemberField(FlagRecordDecl, "__state_");
+
+  // Otherwise, try libstdc++ implementation, with a field
+  // `_M_once`
+  if (!FlagFieldDecl) {
 DEBUG(llvm::dbgs() << "No field __state_ found on std::once_flag struct, "
-   << "unable to synthesize call_once body, ignoring "
-   << "the call.\n");
+   << "assuming libstdc++ implementation\n");
+FlagFieldDecl = M.findMemberField(FlagRecordDecl, "_M_once");
+  }
+
+  if (!FlagFieldDecl) {
+DEBUG(llvm::dbgs() << "No field _M_once found on std::once flag struct: "
+   << "unknown std::call_once implementation, "
+   << "ignoring the call");
 return nullptr;
   }
 
@@ -383,7 +389,7 @@
 /* GetNonReferenceType=*/true);
 
 
-  MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FieldDecl);
+  MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FlagFieldDecl);
   assert(Deref->isLValue());
   QualType DerefType = Deref->getType();
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D38810: [Analyzer] Support bodyfarming std::call_once for libstdc++

2017-10-11 Thread Devin Coughlin via Phabricator via cfe-commits
dcoughlin accepted this revision.
dcoughlin added a comment.
This revision is now accepted and ready to land.

LGTM with the dyn_cast mentioned inline changed.




Comment at: lib/Analysis/BodyFarm.cpp:359
 
+  ValueDecl *FieldDecl = dyn_cast(FoundDecl);
   bool isLambdaCall = CallbackType->getAsCXXRecordDecl() &&

Should this be a cast<>() rather than a dyn_cast<>()? Do you expect this to 
fail? If so then you should check the result for null. If not then the idiom is 
to use cast<>().

An alternative would be to change findMemberField() to return a FieldDecl.


https://reviews.llvm.org/D38810



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D38810: [Analyzer] Support bodyfarming std::call_once for libstdc++

2017-10-11 Thread George Karpenkov via Phabricator via cfe-commits
george.karpenkov created this revision.
Herald added subscribers: szepet, kristof.beyls, xazax.hun, javed.absar, 
aemerson.

https://reviews.llvm.org/D38810

Files:
  lib/Analysis/BodyFarm.cpp
  test/Analysis/call_once.cpp

Index: test/Analysis/call_once.cpp
===
--- test/Analysis/call_once.cpp
+++ test/Analysis/call_once.cpp
@@ -1,15 +1,24 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -w -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBSTDCPP -verify %s
 
 void clang_analyzer_eval(bool);
 
 // Faking std::std::call_once implementation.
 namespace std {
+
+#ifndef EMULATE_LIBSTDCPP
 typedef struct once_flag_s {
   unsigned long __state_ = 0;
 } once_flag;
+#else
+typedef struct once_flag_s {
+  int _M_once = 0;
+} once_flag;
+#endif
 
 template 
 void call_once(once_flag , Callable func, Args... args) {};
+
 } // namespace std
 
 // Check with Lambdas.
Index: lib/Analysis/BodyFarm.cpp
===
--- lib/Analysis/BodyFarm.cpp
+++ lib/Analysis/BodyFarm.cpp
@@ -108,7 +108,7 @@
 
   /// Returns a *first* member field of a record declaration with a given name.
   /// \return an nullptr if no member with such a name exists.
-  NamedDecl *findMemberField(const CXXRecordDecl *RD, StringRef Name);
+  NamedDecl *findMemberField(const RecordDecl *RD, StringRef Name);
 
 private:
   ASTContext 
@@ -234,7 +234,7 @@
   OK_Ordinary);
 }
 
-NamedDecl *ASTMaker::findMemberField(const CXXRecordDecl *RD, StringRef Name) {
+NamedDecl *ASTMaker::findMemberField(const RecordDecl *RD, StringRef Name) {
 
   CXXBasePaths Paths(
   /* FindAmbiguities=*/false,
@@ -328,28 +328,35 @@
   const ParmVarDecl *Callback = D->getParamDecl(1);
   QualType CallbackType = Callback->getType().getNonReferenceType();
   QualType FlagType = Flag->getType().getNonReferenceType();
-  CXXRecordDecl *FlagCXXDecl = FlagType->getAsCXXRecordDecl();
-  if (!FlagCXXDecl) {
-DEBUG(llvm::dbgs() << "Flag field is not a CXX record: "
-   << "unknown std::call_once implementation."
-   << "Ignoring the call.\n");
+  auto *FlagRecordDecl = dyn_cast_or_null(FlagType->getAsTagDecl());
+
+  if (!FlagRecordDecl) {
+DEBUG(llvm::dbgs() << "Flag field is not a record: "
+   << "unknown std::call_once implementation, "
+   << "ignoring the call.\n");
 return nullptr;
   }
 
-  // Note: here we are assuming libc++ implementation of call_once,
-  // which has a struct with a field `__state_`.
-  // Body farming might not work for other `call_once` implementations.
-  NamedDecl *FoundDecl = M.findMemberField(FlagCXXDecl, "__state_");
-  ValueDecl *FieldDecl;
-  if (FoundDecl) {
-FieldDecl = dyn_cast(FoundDecl);
-  } else {
+  // We initially assume libc++ implementation of call_once,
+  // where the once_flag struct has a field `__state_`.
+  NamedDecl *FoundDecl = M.findMemberField(FlagRecordDecl, "__state_");
+
+  // Otherwise, try libstdc++ implementation, with a field
+  // `_M_once`
+  if (!FoundDecl) {
 DEBUG(llvm::dbgs() << "No field __state_ found on std::once_flag struct, "
-   << "unable to synthesize call_once body, ignoring "
-   << "the call.\n");
+   << "trying libstdc++ implementation\n");
+FoundDecl = M.findMemberField(FlagRecordDecl, "_M_once");
+  }
+
+  if (!FoundDecl) {
+DEBUG(llvm::dbgs() << "No field _M_once found on std::once flag struct: "
+   << "unknown std::call_once implementation, "
+   << "ignoring the call");
 return nullptr;
   }
 
+  ValueDecl *FieldDecl = dyn_cast(FoundDecl);
   bool isLambdaCall = CallbackType->getAsCXXRecordDecl() &&
   CallbackType->getAsCXXRecordDecl()->isLambda();
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits