diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/lib/Analysis/BodyFarm.cpp | 38 | ||||
-rw-r--r-- | clang/test/Analysis/call_once.cpp | 9 |
2 files changed, 31 insertions, 16 deletions
diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp index a6597690c2a..81ad999e527 100644 --- a/clang/lib/Analysis/BodyFarm.cpp +++ b/clang/lib/Analysis/BodyFarm.cpp @@ -327,6 +327,28 @@ static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) { const ParmVarDecl *Flag = D->getParamDecl(0); 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"); + 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 { + DEBUG(llvm::dbgs() << "No field __state_ found on std::once_flag struct, " + << "unable to synthesize call_once body, ignoring " + << "the call.\n"); + return nullptr; + } bool isLambdaCall = CallbackType->getAsCXXRecordDecl() && CallbackType->getAsCXXRecordDecl()->isLambda(); @@ -355,27 +377,11 @@ static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) { CallbackCall = create_call_once_funcptr_call(C, M, Callback, CallArgs); } - QualType FlagType = Flag->getType().getNonReferenceType(); DeclRefExpr *FlagDecl = M.makeDeclRefExpr(Flag, /* RefersToEnclosingVariableOrCapture=*/true, /* GetNonReferenceType=*/true); - CXXRecordDecl *FlagCXXDecl = FlagType->getAsCXXRecordDecl(); - - // 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 { - DEBUG(llvm::dbgs() << "No field __state_ found on std::once_flag struct, " - << "unable to synthesize call_once body, ignoring " - << "the call.\n"); - return nullptr; - } MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FieldDecl); assert(Deref->isLValue()); diff --git a/clang/test/Analysis/call_once.cpp b/clang/test/Analysis/call_once.cpp index 030b3434290..324d9fceb3f 100644 --- a/clang/test/Analysis/call_once.cpp +++ b/clang/test/Analysis/call_once.cpp @@ -231,3 +231,12 @@ void test_non_std_call_once() { int x = call_once(); clang_analyzer_eval(x == 5); // expected-warning{{TRUE}} } + +namespace std { +template <typename d, typename e> +void call_once(d, e); +} +void g(); +void test_no_segfault_on_different_impl() { + std::call_once(g, false); // no-warning +} |