r315508 - [Analyzer] Support bodyfarming libstdc++ implementation of std::call_once.
George Karpenkov via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 11 13:53:01 PDT 2017
Author: george.karpenkov
Date: Wed Oct 11 13:53:01 2017
New Revision: 315508
URL: http://llvm.org/viewvc/llvm-project?rev=315508&view=rev
Log:
[Analyzer] Support bodyfarming libstdc++ implementation of std::call_once.
Differential Revision: https://reviews.llvm.org/D38810
Modified:
cfe/trunk/lib/Analysis/BodyFarm.cpp
cfe/trunk/test/Analysis/call_once.cpp
Modified: cfe/trunk/lib/Analysis/BodyFarm.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/BodyFarm.cpp?rev=315508&r1=315507&r2=315508&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/BodyFarm.cpp (original)
+++ cfe/trunk/lib/Analysis/BodyFarm.cpp Wed Oct 11 13:53:01 2017
@@ -108,7 +108,7 @@ public:
/// 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 &C;
@@ -234,7 +234,7 @@ MemberExpr *ASTMaker::makeMemberExpressi
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 @@ NamedDecl *ASTMaker::findMemberField(con
DeclContextLookupResult Decls = RD->lookup(DeclName);
for (NamedDecl *FoundDecl : Decls)
if (!FoundDecl->getDeclContext()->isFunctionOrMethod())
- return FoundDecl;
+ return cast<ValueDecl>(FoundDecl);
return nullptr;
}
@@ -328,25 +328,31 @@ static Stmt *create_call_once(ASTContext
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<RecordDecl>(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<ValueDecl>(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 @@ static Stmt *create_call_once(ASTContext
/* GetNonReferenceType=*/true);
- MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FieldDecl);
+ MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FlagFieldDecl);
assert(Deref->isLValue());
QualType DerefType = Deref->getType();
Modified: cfe/trunk/test/Analysis/call_once.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/call_once.cpp?rev=315508&r1=315507&r2=315508&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/call_once.cpp (original)
+++ cfe/trunk/test/Analysis/call_once.cpp Wed Oct 11 13:53:01 2017
@@ -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 <class Callable, class... Args>
void call_once(once_flag &o, Callable func, Args... args) {};
+
} // namespace std
// Check with Lambdas.
More information about the cfe-commits
mailing list