Index: lib/Analysis/BodyFarm.cpp =================================================================== --- lib/Analysis/BodyFarm.cpp +++ lib/Analysis/BodyFarm.cpp @@ -395,8 +395,8 @@ // First two arguments are used for the flag and for the callback. if (D->getNumParams() != CallbackFunctionType->getNumParams() + 2) { - DEBUG(llvm::dbgs() << "Types of params of the callback do not match " - << "params passed to std::call_once, " + DEBUG(llvm::dbgs() << "Length of params of the callback does not match " + << "length params passed to std::call_once, " << "ignoring the call\n"); return nullptr; } @@ -407,9 +407,18 @@ for (unsigned int ParamIdx = 2; ParamIdx < D->getNumParams(); ParamIdx++) { const ParmVarDecl *PDecl = D->getParamDecl(ParamIdx); Expr *ParamExpr = M.makeDeclRefExpr(PDecl); - if (!CallbackFunctionType->getParamType(ParamIdx - 2)->isReferenceType()) { - QualType PTy = PDecl->getType().getNonReferenceType(); - ParamExpr = M.makeLvalueToRvalue(ParamExpr, PTy); + QualType CallbackParamType = + CallbackFunctionType->getParamType(ParamIdx - 2); + QualType PTy = PDecl->getType(); + if (!CallbackParamType->isReferenceType()) + ParamExpr = M.makeLvalueToRvalue(ParamExpr, PTy.getNonReferenceType()); + + if (CallbackParamType.getNonReferenceType().getCanonicalType() != + PTy.getNonReferenceType().getCanonicalType()) { + DEBUG(llvm::dbgs() << "Types of params of the callback do not match " + << "params passed to std::call_once, " + << "ignoring the call\n"); + return nullptr; } CallArgs.push_back(ParamExpr); } @@ -816,4 +825,3 @@ return Val.getValue(); } - Index: test/Analysis/call_once.cpp =================================================================== --- test/Analysis/call_once.cpp +++ test/Analysis/call_once.cpp @@ -9,9 +9,26 @@ void clang_analyzer_eval(bool); -// Faking std::std::call_once implementation. +// Faking std::call_once implementation. namespace std { +// Fake std::function implementation. +template +class function; +class function_base { + public: + long field; +}; +template +class function : function_base { + public: + R operator()(P...) const { + + // Read from a super-class necessary to reproduce a crash. + bool a = field; + } +}; + #ifndef EMULATE_LIBSTDCPP typedef struct once_flag_s { unsigned long __state_ = 0; @@ -360,3 +377,25 @@ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} #endif } + +int param_passed(int *x) { + return *x; // no-warning, as std::function is not working yet. +} + +void callback_taking_func_ok(std::function &innerCallback) { + innerCallback(nullptr); +} + +void callback_with_implicit_cast_ok() { + std::once_flag flag; + call_once(flag, callback_taking_func_ok, ¶m_passed); +} + +void callback_taking_func(std::function &innerCallback) { + innerCallback(); +} + +void callback_with_implicit_cast() { + std::once_flag flag; + call_once(flag, callback_taking_func, callback_with_implicit_cast); +}