Index: lib/Analysis/BodyFarm.cpp =================================================================== --- lib/Analysis/BodyFarm.cpp +++ lib/Analysis/BodyFarm.cpp @@ -325,6 +325,16 @@ const ParmVarDecl *Flag = D->getParamDecl(0); const ParmVarDecl *Callback = D->getParamDecl(1); + + if (!Callback->getType()->isReferenceType()) { + llvm::dbgs() << "libcxx03 std::call_once implementation, skipping.\n"; + return nullptr; + } + if (!Flag->getType()->isReferenceType()) { + llvm::dbgs() << "unknown std::call_once implementation, skipping.\n"; + return nullptr; + } + QualType CallbackType = Callback->getType().getNonReferenceType(); // Nullable pointer, non-null iff function is a CXXRecordDecl. @@ -346,15 +356,13 @@ // Otherwise, try libstdc++ implementation, with a field // `_M_once` if (!FlagFieldDecl) { - DEBUG(llvm::dbgs() << "No field __state_ found on std::once_flag struct, " - << "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"); + DEBUG(llvm::dbgs() << "No field _M_once or __state_ found on " + << "std::once_flag struct: unknown std::call_once " + << "implementation, ignoring the call."); return nullptr; } @@ -388,9 +396,9 @@ // First two arguments are used for the flag and for the callback. if (D->getNumParams() != CallbackFunctionType->getNumParams() + 2) { - DEBUG(llvm::dbgs() << "Number of params of the callback does not match " - << "the number of params passed to std::call_once, " - << "ignoring the call"); + DEBUG(llvm::dbgs() << "Types of params of the callback do not match " + << "params passed to std::call_once, " + << "ignoring the call\n"); return nullptr; } Index: test/Analysis/call_once.cpp =================================================================== --- test/Analysis/call_once.cpp +++ test/Analysis/call_once.cpp @@ -1,6 +1,12 @@ // 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 +// We do NOT model libcxx03 implementation, but the analyzer should still +// not crash. +// Note that the calls below don't have the -verify flag. +// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBCXX03 %s +// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBCXX03 -DEMULATE_LIBSTDCPP %s + void clang_analyzer_eval(bool); // Faking std::std::call_once implementation. @@ -16,8 +22,13 @@ } once_flag; #endif +#ifndef EMULATE_LIBCXX03 template void call_once(once_flag &o, Callable&& func, Args&&... args) {}; +#else +template // libcxx03 call_once +void call_once(once_flag &o, Callable func, Args&&... args) {}; +#endif } // namespace std