forked from OSchip/llvm-project
[Analyzer] Support bodyfarming libstdc++ implementation of std::call_once.
Differential Revision: https://reviews.llvm.org/D38810 llvm-svn: 315508
This commit is contained in:
parent
450ae592b4
commit
c928e1f595
|
@ -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::makeMemberExpression(Expr *base, ValueDecl *MemberDecl,
|
|||
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(const CXXRecordDecl *RD, StringRef Name) {
|
|||
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 &C, const FunctionDecl *D) {
|
|||
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 &C, const FunctionDecl *D) {
|
|||
/* GetNonReferenceType=*/true);
|
||||
|
||||
|
||||
MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FieldDecl);
|
||||
MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FlagFieldDecl);
|
||||
assert(Deref->isLValue());
|
||||
QualType DerefType = Deref->getType();
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue