// reference.
for (unsigned int ParamIdx = 2; ParamIdx < D->getNumParams(); ParamIdx++) {
const ParmVarDecl *PDecl = D->getParamDecl(ParamIdx);
+ if (PDecl &&
+ CallbackFunctionType->getParamType(ParamIdx - 2)
+ .getNonReferenceType()
+ .getCanonicalType() !=
+ PDecl->getType().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;
+ }
Expr *ParamExpr = M.makeDeclRefExpr(PDecl);
if (!CallbackFunctionType->getParamType(ParamIdx - 2)->isReferenceType()) {
QualType PTy = PDecl->getType().getNonReferenceType();
return Val.getValue();
}
-
void clang_analyzer_eval(bool);
-// Faking std::std::call_once implementation.
+// Faking std::call_once implementation.
namespace std {
+// Fake std::function implementation.
+template <typename>
+class function;
+class function_base {
+ public:
+ long field;
+};
+template <typename R, typename... P>
+class function<R(P...)> : 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;
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<void(int*)> &innerCallback) {
+ innerCallback(nullptr);
+}
+
+// The provided callback expects an std::function, but instead a pointer
+// to a C++ function is provided.
+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<void()> &innerCallback) {
+ innerCallback();
+}
+
+// The provided callback expects an std::function, but instead a C function
+// name is provided, and C++ implicitly auto-constructs a pointer from it.
+void callback_with_implicit_cast() {
+ std::once_flag flag;
+ call_once(flag, callback_taking_func, callback_with_implicit_cast);
+}