head	1.1;
branch	1.1.1;
access;
symbols
	netbsd-11-0-RC5:1.1.1.2
	netbsd-11-0-RC4:1.1.1.2
	netbsd-11-0-RC3:1.1.1.2
	netbsd-11-0-RC2:1.1.1.2
	netbsd-11-0-RC1:1.1.1.2
	perseant-exfatfs-base-20250801:1.1.1.2
	netbsd-11:1.1.1.2.0.10
	netbsd-11-base:1.1.1.2
	netbsd-10-1-RELEASE:1.1.1.2
	perseant-exfatfs-base-20240630:1.1.1.2
	perseant-exfatfs:1.1.1.2.0.8
	perseant-exfatfs-base:1.1.1.2
	netbsd-9-4-RELEASE:1.1.1.1
	netbsd-10-0-RELEASE:1.1.1.2
	netbsd-10-0-RC6:1.1.1.2
	netbsd-10-0-RC5:1.1.1.2
	netbsd-10-0-RC4:1.1.1.2
	netbsd-10-0-RC3:1.1.1.2
	netbsd-10-0-RC2:1.1.1.2
	netbsd-10-0-RC1:1.1.1.2
	netbsd-10:1.1.1.2.0.6
	netbsd-10-base:1.1.1.2
	netbsd-9-3-RELEASE:1.1.1.1
	cjep_sun2x:1.1.1.2.0.4
	cjep_sun2x-base:1.1.1.2
	cjep_staticlib_x-base1:1.1.1.2
	netbsd-9-2-RELEASE:1.1.1.1
	cjep_staticlib_x:1.1.1.2.0.2
	cjep_staticlib_x-base:1.1.1.2
	netbsd-9-1-RELEASE:1.1.1.1
	phil-wifi-20200421:1.1.1.2
	phil-wifi-20200411:1.1.1.2
	phil-wifi-20200406:1.1.1.2
	netbsd-9-0-RELEASE:1.1.1.1
	netbsd-9-0-RC2:1.1.1.1
	netbsd-9-0-RC1:1.1.1.1
	netbsd-9:1.1.1.1.0.6
	netbsd-9-base:1.1.1.1
	phil-wifi:1.1.1.1.0.4
	phil-wifi-20190609:1.1.1.1
	pgoyette-compat-merge-20190127:1.1.1.1.2.2
	pgoyette-compat-20190127:1.1.1.1
	pgoyette-compat-20190118:1.1.1.1
	pgoyette-compat-1226:1.1.1.1
	pgoyette-compat-1126:1.1.1.1
	pgoyette-compat-1020:1.1.1.1
	pgoyette-compat-0930:1.1.1.1
	pgoyette-compat-0906:1.1.1.1
	pgoyette-compat:1.1.1.1.0.2
	pgoyette-compat-0728:1.1.1.1
	clang-337282:1.1.1.1
	LLVM:1.1.1;
locks; strict;
comment	@// @;


1.1
date	2018.07.17.18.31.46;	author joerg;	state Exp;
branches
	1.1.1.1;
next	;
commitid	wDzL46ALjrCZgwKA;

1.1.1.1
date	2018.07.17.18.31.46;	author joerg;	state Exp;
branches
	1.1.1.1.2.1
	1.1.1.1.4.1;
next	1.1.1.2;
commitid	wDzL46ALjrCZgwKA;

1.1.1.2
date	2019.11.13.22.19.38;	author joerg;	state dead;
branches;
next	;
commitid	QD8YATxuNG34YJKB;

1.1.1.1.2.1
date	2018.07.17.18.31.46;	author pgoyette;	state dead;
branches;
next	1.1.1.1.2.2;
commitid	1UP1xAIUxv1ZgRLA;

1.1.1.1.2.2
date	2018.07.28.04.33.28;	author pgoyette;	state Exp;
branches;
next	;
commitid	1UP1xAIUxv1ZgRLA;

1.1.1.1.4.1
date	2018.07.17.18.31.46;	author christos;	state dead;
branches;
next	1.1.1.1.4.2;
commitid	jtc8rnCzWiEEHGqB;

1.1.1.1.4.2
date	2019.06.10.21.45.34;	author christos;	state Exp;
branches;
next	1.1.1.1.4.3;
commitid	jtc8rnCzWiEEHGqB;

1.1.1.1.4.3
date	2020.04.13.07.46.50;	author martin;	state dead;
branches;
next	;
commitid	X01YhRUPVUDaec4C;


desc
@@


1.1
log
@Initial revision
@
text
@// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -verify %s -o %t.report
// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBSTDCPP -verify %s -o %t.report

// We do NOT model libcxx03 implementation, but the analyzer should still
// not crash.
// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBCXX03 -verify %s -o %t.report
// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBCXX03 -DEMULATE_LIBSTDCPP -verify %s -o %t.report
// RUN: rm -rf %t.report

void clang_analyzer_eval(bool);

// 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;
} once_flag;
#else
typedef struct once_flag_s {
  int _M_once = 0;
} once_flag;
#endif

#ifndef EMULATE_LIBCXX03
template <class Callable, class... Args>
void call_once(once_flag &o, Callable&& func, Args&&... args) {};
#else
template <class Callable, class... Args> // libcxx03 call_once
void call_once(once_flag &o, Callable func, Args&&... args) {};
#endif

} // namespace std

// Check with Lambdas.
void test_called_warning() {
  std::once_flag g_initialize;
  int z;

  std::call_once(g_initialize, [&] {
    int *x = nullptr;
#ifndef EMULATE_LIBCXX03
    int y = *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
#endif
    z = 200;
  });
}

void test_called_on_path_inside_no_warning() {
  std::once_flag g_initialize;

  int *x = nullptr;
  int y = 100;
  int z;

  std::call_once(g_initialize, [&] {
    z = 200;
    x = &z;
  });

#ifndef EMULATE_LIBCXX03
  *x = 100; // no-warning
  clang_analyzer_eval(z == 100); // expected-warning{{TRUE}}
#endif
}

void test_called_on_path_no_warning() {
  std::once_flag g_initialize;

  int *x = nullptr;
  int y = 100;

  std::call_once(g_initialize, [&] {
    x = &y;
  });

#ifndef EMULATE_LIBCXX03
  *x = 100; // no-warning
#else
  *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
#endif
}

void test_called_on_path_warning() {
  std::once_flag g_initialize;

  int y = 100;
  int *x = &y;

  std::call_once(g_initialize, [&] {
    x = nullptr;
  });

#ifndef EMULATE_LIBCXX03
  *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
#endif
}

void test_called_once_warning() {
  std::once_flag g_initialize;

  int *x = nullptr;
  int y = 100;

  std::call_once(g_initialize, [&] {
    x = nullptr;
  });

  std::call_once(g_initialize, [&] {
    x = &y;
  });

#ifndef EMULATE_LIBCXX03
  *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
#endif
}

void test_called_once_no_warning() {
  std::once_flag g_initialize;

  int *x = nullptr;
  int y = 100;

  std::call_once(g_initialize, [&] {
    x = &y;
  });

  std::call_once(g_initialize, [&] {
    x = nullptr;
  });

#ifndef EMULATE_LIBCXX03
  *x = 100; // no-warning
#endif
}

static int global = 0;
void funcPointer() {
  global = 1;
}

void test_func_pointers() {
  static std::once_flag flag;
  std::call_once(flag, &funcPointer);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(global == 1); // expected-warning{{TRUE}}
#endif
}

template <class _Fp>
class function; // undefined
template <class _Rp, class... _ArgTypes>
struct function<_Rp(_ArgTypes...)> {
  _Rp operator()(_ArgTypes...) const {};
  template <class _Fp>
  function(_Fp) {};
};

// Note: currently we do not support calls to std::function,
// but the analyzer should not crash either.
void test_function_objects_warning() {
  int x = 0;
  int *y = &x;

  std::once_flag flag;

  function<void()> func = [&]() {
    y = nullptr;
  };

  std::call_once(flag, func);

  func();
  int z = *y;
}

void test_param_passing_lambda() {
  std::once_flag flag;
  int x = 120;
  int y = 0;

  std::call_once(flag, [&](int p) {
    y = p;
  },
                 x);

#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(y == 120); // expected-warning{{TRUE}}
#endif
}

void test_param_passing_lambda_false() {
  std::once_flag flag;
  int x = 120;

  std::call_once(flag, [&](int p) {
    x = 0;
  },
                 x);

#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(x == 120); // expected-warning{{FALSE}}
#endif
}

void test_param_passing_stored_lambda() {
  std::once_flag flag;
  int x = 120;
  int y = 0;

  auto lambda = [&](int p) {
    y = p;
  };

  std::call_once(flag, lambda, x);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(y == 120); // expected-warning{{TRUE}}
#endif
}

void test_multiparam_passing_lambda() {
  std::once_flag flag;
  int x = 120;

  std::call_once(flag, [&](int a, int b, int c) {
    x = a + b + c;
  },
                 1, 2, 3);

#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(x == 120); // expected-warning{{FALSE}}
  clang_analyzer_eval(x == 6); // expected-warning{{TRUE}}
#endif
}

static int global2 = 0;
void test_param_passing_lambda_global() {
  std::once_flag flag;
  global2 = 0;
  std::call_once(flag, [&](int a, int b, int c) {
    global2 = a + b + c;
  },
                 1, 2, 3);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(global2 == 6); // expected-warning{{TRUE}}
#endif
}

static int global3 = 0;
void funcptr(int a, int b, int c) {
  global3 = a + b + c;
}

void test_param_passing_funcptr() {
  std::once_flag flag;
  global3 = 0;

  std::call_once(flag, &funcptr, 1, 2, 3);

#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(global3 == 6); // expected-warning{{TRUE}}
#endif
}

void test_blocks() {
  global3 = 0;
  std::once_flag flag;
  std::call_once(flag, ^{
    global3 = 120;
  });
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(global3 == 120); // expected-warning{{TRUE}}
#endif
}

int call_once() {
  return 5;
}

void test_non_std_call_once() {
  int x = call_once();
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(x == 5); // expected-warning{{TRUE}}
#endif
}

namespace std {
template <typename d, typename e>
void call_once(d, e);
}
void g();
void test_no_segfault_on_different_impl() {
#ifndef EMULATE_LIBCXX03
  std::call_once(g, false); // no-warning
#endif
}

void test_lambda_refcapture() {
  static std::once_flag flag;
  int a = 6;
  std::call_once(flag, [&](int &a) { a = 42; }, a);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(a == 42); // expected-warning{{TRUE}}
#endif
}

void test_lambda_refcapture2() {
  static std::once_flag flag;
  int a = 6;
  std::call_once(flag, [=](int &a) { a = 42; }, a);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(a == 42); // expected-warning{{TRUE}}
#endif
}

void test_lambda_fail_refcapture() {
  static std::once_flag flag;
  int a = 6;
  std::call_once(flag, [=](int a) { a = 42; }, a);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(a == 42); // expected-warning{{FALSE}}
#endif
}

void mutator(int &param) {
  param = 42;
}
void test_reftypes_funcptr() {
  static std::once_flag flag;
  int a = 6;
  std::call_once(flag, &mutator, a);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(a == 42); // expected-warning{{TRUE}}
#endif
}

void fail_mutator(int param) {
  param = 42;
}
void test_mutator_noref() {
  static std::once_flag flag;
  int a = 6;
  std::call_once(flag, &fail_mutator, a);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(a == 42); // expected-warning{{FALSE}}
#endif
}

// Function is implicitly treated as a function pointer
// even when an ampersand is not explicitly set.
void callbackn(int &param) {
  param = 42;
}
void test_implicit_funcptr() {
  int x = 0;
  static std::once_flag flagn;

  std::call_once(flagn, callbackn, x);
#ifndef EMULATE_LIBCXX03
  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, &param_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);
}

std::once_flag another_once_flag;
typedef void (*my_callback_t)(int *);
my_callback_t callback;
int global_int;

void rdar40270582() {
  call_once(another_once_flag, callback, &global_int);
}
@


1.1.1.1
log
@Import clang r337282 from trunk
@
text
@@


1.1.1.2
log
@Mark old LLVM instance as dead.
@
text
@@


1.1.1.1.4.1
log
@file call_once.cpp was added on branch phil-wifi on 2019-06-10 21:45:34 +0000
@
text
@d1 414
@


1.1.1.1.4.2
log
@Sync with HEAD
@
text
@a0 414
// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -verify %s -o %t.report
// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBSTDCPP -verify %s -o %t.report

// We do NOT model libcxx03 implementation, but the analyzer should still
// not crash.
// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBCXX03 -verify %s -o %t.report
// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBCXX03 -DEMULATE_LIBSTDCPP -verify %s -o %t.report
// RUN: rm -rf %t.report

void clang_analyzer_eval(bool);

// 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;
} once_flag;
#else
typedef struct once_flag_s {
  int _M_once = 0;
} once_flag;
#endif

#ifndef EMULATE_LIBCXX03
template <class Callable, class... Args>
void call_once(once_flag &o, Callable&& func, Args&&... args) {};
#else
template <class Callable, class... Args> // libcxx03 call_once
void call_once(once_flag &o, Callable func, Args&&... args) {};
#endif

} // namespace std

// Check with Lambdas.
void test_called_warning() {
  std::once_flag g_initialize;
  int z;

  std::call_once(g_initialize, [&] {
    int *x = nullptr;
#ifndef EMULATE_LIBCXX03
    int y = *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
#endif
    z = 200;
  });
}

void test_called_on_path_inside_no_warning() {
  std::once_flag g_initialize;

  int *x = nullptr;
  int y = 100;
  int z;

  std::call_once(g_initialize, [&] {
    z = 200;
    x = &z;
  });

#ifndef EMULATE_LIBCXX03
  *x = 100; // no-warning
  clang_analyzer_eval(z == 100); // expected-warning{{TRUE}}
#endif
}

void test_called_on_path_no_warning() {
  std::once_flag g_initialize;

  int *x = nullptr;
  int y = 100;

  std::call_once(g_initialize, [&] {
    x = &y;
  });

#ifndef EMULATE_LIBCXX03
  *x = 100; // no-warning
#else
  *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
#endif
}

void test_called_on_path_warning() {
  std::once_flag g_initialize;

  int y = 100;
  int *x = &y;

  std::call_once(g_initialize, [&] {
    x = nullptr;
  });

#ifndef EMULATE_LIBCXX03
  *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
#endif
}

void test_called_once_warning() {
  std::once_flag g_initialize;

  int *x = nullptr;
  int y = 100;

  std::call_once(g_initialize, [&] {
    x = nullptr;
  });

  std::call_once(g_initialize, [&] {
    x = &y;
  });

#ifndef EMULATE_LIBCXX03
  *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
#endif
}

void test_called_once_no_warning() {
  std::once_flag g_initialize;

  int *x = nullptr;
  int y = 100;

  std::call_once(g_initialize, [&] {
    x = &y;
  });

  std::call_once(g_initialize, [&] {
    x = nullptr;
  });

#ifndef EMULATE_LIBCXX03
  *x = 100; // no-warning
#endif
}

static int global = 0;
void funcPointer() {
  global = 1;
}

void test_func_pointers() {
  static std::once_flag flag;
  std::call_once(flag, &funcPointer);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(global == 1); // expected-warning{{TRUE}}
#endif
}

template <class _Fp>
class function; // undefined
template <class _Rp, class... _ArgTypes>
struct function<_Rp(_ArgTypes...)> {
  _Rp operator()(_ArgTypes...) const {};
  template <class _Fp>
  function(_Fp) {};
};

// Note: currently we do not support calls to std::function,
// but the analyzer should not crash either.
void test_function_objects_warning() {
  int x = 0;
  int *y = &x;

  std::once_flag flag;

  function<void()> func = [&]() {
    y = nullptr;
  };

  std::call_once(flag, func);

  func();
  int z = *y;
}

void test_param_passing_lambda() {
  std::once_flag flag;
  int x = 120;
  int y = 0;

  std::call_once(flag, [&](int p) {
    y = p;
  },
                 x);

#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(y == 120); // expected-warning{{TRUE}}
#endif
}

void test_param_passing_lambda_false() {
  std::once_flag flag;
  int x = 120;

  std::call_once(flag, [&](int p) {
    x = 0;
  },
                 x);

#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(x == 120); // expected-warning{{FALSE}}
#endif
}

void test_param_passing_stored_lambda() {
  std::once_flag flag;
  int x = 120;
  int y = 0;

  auto lambda = [&](int p) {
    y = p;
  };

  std::call_once(flag, lambda, x);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(y == 120); // expected-warning{{TRUE}}
#endif
}

void test_multiparam_passing_lambda() {
  std::once_flag flag;
  int x = 120;

  std::call_once(flag, [&](int a, int b, int c) {
    x = a + b + c;
  },
                 1, 2, 3);

#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(x == 120); // expected-warning{{FALSE}}
  clang_analyzer_eval(x == 6); // expected-warning{{TRUE}}
#endif
}

static int global2 = 0;
void test_param_passing_lambda_global() {
  std::once_flag flag;
  global2 = 0;
  std::call_once(flag, [&](int a, int b, int c) {
    global2 = a + b + c;
  },
                 1, 2, 3);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(global2 == 6); // expected-warning{{TRUE}}
#endif
}

static int global3 = 0;
void funcptr(int a, int b, int c) {
  global3 = a + b + c;
}

void test_param_passing_funcptr() {
  std::once_flag flag;
  global3 = 0;

  std::call_once(flag, &funcptr, 1, 2, 3);

#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(global3 == 6); // expected-warning{{TRUE}}
#endif
}

void test_blocks() {
  global3 = 0;
  std::once_flag flag;
  std::call_once(flag, ^{
    global3 = 120;
  });
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(global3 == 120); // expected-warning{{TRUE}}
#endif
}

int call_once() {
  return 5;
}

void test_non_std_call_once() {
  int x = call_once();
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(x == 5); // expected-warning{{TRUE}}
#endif
}

namespace std {
template <typename d, typename e>
void call_once(d, e);
}
void g();
void test_no_segfault_on_different_impl() {
#ifndef EMULATE_LIBCXX03
  std::call_once(g, false); // no-warning
#endif
}

void test_lambda_refcapture() {
  static std::once_flag flag;
  int a = 6;
  std::call_once(flag, [&](int &a) { a = 42; }, a);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(a == 42); // expected-warning{{TRUE}}
#endif
}

void test_lambda_refcapture2() {
  static std::once_flag flag;
  int a = 6;
  std::call_once(flag, [=](int &a) { a = 42; }, a);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(a == 42); // expected-warning{{TRUE}}
#endif
}

void test_lambda_fail_refcapture() {
  static std::once_flag flag;
  int a = 6;
  std::call_once(flag, [=](int a) { a = 42; }, a);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(a == 42); // expected-warning{{FALSE}}
#endif
}

void mutator(int &param) {
  param = 42;
}
void test_reftypes_funcptr() {
  static std::once_flag flag;
  int a = 6;
  std::call_once(flag, &mutator, a);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(a == 42); // expected-warning{{TRUE}}
#endif
}

void fail_mutator(int param) {
  param = 42;
}
void test_mutator_noref() {
  static std::once_flag flag;
  int a = 6;
  std::call_once(flag, &fail_mutator, a);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(a == 42); // expected-warning{{FALSE}}
#endif
}

// Function is implicitly treated as a function pointer
// even when an ampersand is not explicitly set.
void callbackn(int &param) {
  param = 42;
}
void test_implicit_funcptr() {
  int x = 0;
  static std::once_flag flagn;

  std::call_once(flagn, callbackn, x);
#ifndef EMULATE_LIBCXX03
  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, &param_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);
}

std::once_flag another_once_flag;
typedef void (*my_callback_t)(int *);
my_callback_t callback;
int global_int;

void rdar40270582() {
  call_once(another_once_flag, callback, &global_int);
}
@


1.1.1.1.4.3
log
@Mostly merge changes from HEAD upto 20200411
@
text
@@


1.1.1.1.2.1
log
@file call_once.cpp was added on branch pgoyette-compat on 2018-07-28 04:33:28 +0000
@
text
@d1 414
@


1.1.1.1.2.2
log
@Sync with HEAD
@
text
@a0 414
// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -verify %s -o %t.report
// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBSTDCPP -verify %s -o %t.report

// We do NOT model libcxx03 implementation, but the analyzer should still
// not crash.
// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBCXX03 -verify %s -o %t.report
// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBCXX03 -DEMULATE_LIBSTDCPP -verify %s -o %t.report
// RUN: rm -rf %t.report

void clang_analyzer_eval(bool);

// 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;
} once_flag;
#else
typedef struct once_flag_s {
  int _M_once = 0;
} once_flag;
#endif

#ifndef EMULATE_LIBCXX03
template <class Callable, class... Args>
void call_once(once_flag &o, Callable&& func, Args&&... args) {};
#else
template <class Callable, class... Args> // libcxx03 call_once
void call_once(once_flag &o, Callable func, Args&&... args) {};
#endif

} // namespace std

// Check with Lambdas.
void test_called_warning() {
  std::once_flag g_initialize;
  int z;

  std::call_once(g_initialize, [&] {
    int *x = nullptr;
#ifndef EMULATE_LIBCXX03
    int y = *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
#endif
    z = 200;
  });
}

void test_called_on_path_inside_no_warning() {
  std::once_flag g_initialize;

  int *x = nullptr;
  int y = 100;
  int z;

  std::call_once(g_initialize, [&] {
    z = 200;
    x = &z;
  });

#ifndef EMULATE_LIBCXX03
  *x = 100; // no-warning
  clang_analyzer_eval(z == 100); // expected-warning{{TRUE}}
#endif
}

void test_called_on_path_no_warning() {
  std::once_flag g_initialize;

  int *x = nullptr;
  int y = 100;

  std::call_once(g_initialize, [&] {
    x = &y;
  });

#ifndef EMULATE_LIBCXX03
  *x = 100; // no-warning
#else
  *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
#endif
}

void test_called_on_path_warning() {
  std::once_flag g_initialize;

  int y = 100;
  int *x = &y;

  std::call_once(g_initialize, [&] {
    x = nullptr;
  });

#ifndef EMULATE_LIBCXX03
  *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
#endif
}

void test_called_once_warning() {
  std::once_flag g_initialize;

  int *x = nullptr;
  int y = 100;

  std::call_once(g_initialize, [&] {
    x = nullptr;
  });

  std::call_once(g_initialize, [&] {
    x = &y;
  });

#ifndef EMULATE_LIBCXX03
  *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
#endif
}

void test_called_once_no_warning() {
  std::once_flag g_initialize;

  int *x = nullptr;
  int y = 100;

  std::call_once(g_initialize, [&] {
    x = &y;
  });

  std::call_once(g_initialize, [&] {
    x = nullptr;
  });

#ifndef EMULATE_LIBCXX03
  *x = 100; // no-warning
#endif
}

static int global = 0;
void funcPointer() {
  global = 1;
}

void test_func_pointers() {
  static std::once_flag flag;
  std::call_once(flag, &funcPointer);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(global == 1); // expected-warning{{TRUE}}
#endif
}

template <class _Fp>
class function; // undefined
template <class _Rp, class... _ArgTypes>
struct function<_Rp(_ArgTypes...)> {
  _Rp operator()(_ArgTypes...) const {};
  template <class _Fp>
  function(_Fp) {};
};

// Note: currently we do not support calls to std::function,
// but the analyzer should not crash either.
void test_function_objects_warning() {
  int x = 0;
  int *y = &x;

  std::once_flag flag;

  function<void()> func = [&]() {
    y = nullptr;
  };

  std::call_once(flag, func);

  func();
  int z = *y;
}

void test_param_passing_lambda() {
  std::once_flag flag;
  int x = 120;
  int y = 0;

  std::call_once(flag, [&](int p) {
    y = p;
  },
                 x);

#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(y == 120); // expected-warning{{TRUE}}
#endif
}

void test_param_passing_lambda_false() {
  std::once_flag flag;
  int x = 120;

  std::call_once(flag, [&](int p) {
    x = 0;
  },
                 x);

#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(x == 120); // expected-warning{{FALSE}}
#endif
}

void test_param_passing_stored_lambda() {
  std::once_flag flag;
  int x = 120;
  int y = 0;

  auto lambda = [&](int p) {
    y = p;
  };

  std::call_once(flag, lambda, x);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(y == 120); // expected-warning{{TRUE}}
#endif
}

void test_multiparam_passing_lambda() {
  std::once_flag flag;
  int x = 120;

  std::call_once(flag, [&](int a, int b, int c) {
    x = a + b + c;
  },
                 1, 2, 3);

#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(x == 120); // expected-warning{{FALSE}}
  clang_analyzer_eval(x == 6); // expected-warning{{TRUE}}
#endif
}

static int global2 = 0;
void test_param_passing_lambda_global() {
  std::once_flag flag;
  global2 = 0;
  std::call_once(flag, [&](int a, int b, int c) {
    global2 = a + b + c;
  },
                 1, 2, 3);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(global2 == 6); // expected-warning{{TRUE}}
#endif
}

static int global3 = 0;
void funcptr(int a, int b, int c) {
  global3 = a + b + c;
}

void test_param_passing_funcptr() {
  std::once_flag flag;
  global3 = 0;

  std::call_once(flag, &funcptr, 1, 2, 3);

#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(global3 == 6); // expected-warning{{TRUE}}
#endif
}

void test_blocks() {
  global3 = 0;
  std::once_flag flag;
  std::call_once(flag, ^{
    global3 = 120;
  });
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(global3 == 120); // expected-warning{{TRUE}}
#endif
}

int call_once() {
  return 5;
}

void test_non_std_call_once() {
  int x = call_once();
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(x == 5); // expected-warning{{TRUE}}
#endif
}

namespace std {
template <typename d, typename e>
void call_once(d, e);
}
void g();
void test_no_segfault_on_different_impl() {
#ifndef EMULATE_LIBCXX03
  std::call_once(g, false); // no-warning
#endif
}

void test_lambda_refcapture() {
  static std::once_flag flag;
  int a = 6;
  std::call_once(flag, [&](int &a) { a = 42; }, a);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(a == 42); // expected-warning{{TRUE}}
#endif
}

void test_lambda_refcapture2() {
  static std::once_flag flag;
  int a = 6;
  std::call_once(flag, [=](int &a) { a = 42; }, a);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(a == 42); // expected-warning{{TRUE}}
#endif
}

void test_lambda_fail_refcapture() {
  static std::once_flag flag;
  int a = 6;
  std::call_once(flag, [=](int a) { a = 42; }, a);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(a == 42); // expected-warning{{FALSE}}
#endif
}

void mutator(int &param) {
  param = 42;
}
void test_reftypes_funcptr() {
  static std::once_flag flag;
  int a = 6;
  std::call_once(flag, &mutator, a);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(a == 42); // expected-warning{{TRUE}}
#endif
}

void fail_mutator(int param) {
  param = 42;
}
void test_mutator_noref() {
  static std::once_flag flag;
  int a = 6;
  std::call_once(flag, &fail_mutator, a);
#ifndef EMULATE_LIBCXX03
  clang_analyzer_eval(a == 42); // expected-warning{{FALSE}}
#endif
}

// Function is implicitly treated as a function pointer
// even when an ampersand is not explicitly set.
void callbackn(int &param) {
  param = 42;
}
void test_implicit_funcptr() {
  int x = 0;
  static std::once_flag flagn;

  std::call_once(flagn, callbackn, x);
#ifndef EMULATE_LIBCXX03
  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, &param_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);
}

std::once_flag another_once_flag;
typedef void (*my_callback_t)(int *);
my_callback_t callback;
int global_int;

void rdar40270582() {
  call_once(another_once_flag, callback, &global_int);
}
@


