1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// This is a "No Compile Test" suite.
6// http://dev.chromium.org/developers/testing/no-compile-tests
7
8#include <utility>
9
10#include "base/bind.h"
11#include "base/callback.h"
12#include "base/macros.h"
13#include "base/memory/ref_counted.h"
14#include "base/test/bind_test_util.h"
15
16namespace base {
17
18// Do not put everything inside an anonymous namespace.  If you do, many of the
19// helper function declarations will generate unused definition warnings.
20
21static const int kParentValue = 1;
22static const int kChildValue = 2;
23
24class NoRef {
25 public:
26  void VoidMethod0() {}
27  void VoidConstMethod0() const {}
28  int IntMethod0() { return 1; }
29};
30
31class HasRef : public NoRef, public base::RefCounted<HasRef> {
32};
33
34class Parent {
35 public:
36  void AddRef() const {}
37  void Release() const {}
38  virtual void VirtualSet() { value = kParentValue; }
39  void NonVirtualSet() { value = kParentValue; }
40  int value;
41};
42
43class Child : public Parent {
44 public:
45  virtual void VirtualSet() { value = kChildValue; }
46  void NonVirtualSet() { value = kChildValue; }
47};
48
49class NoRefParent {
50 public:
51  virtual void VirtualSet() { value = kParentValue; }
52  void NonVirtualSet() { value = kParentValue; }
53  int value;
54};
55
56class NoRefChild : public NoRefParent {
57  virtual void VirtualSet() { value = kChildValue; }
58  void NonVirtualSet() { value = kChildValue; }
59};
60
61template <typename T>
62T PolymorphicIdentity(T t) {
63  return t;
64}
65
66int UnwrapParentRef(Parent& p) {
67  return p.value;
68}
69
70template <typename T>
71void VoidPolymorphic1(T t) {
72}
73
74void TakesMoveOnly(std::unique_ptr<int>) {
75}
76
77struct NonEmptyFunctor {
78  int x;
79  void operator()() const {}
80};
81
82// TODO(hans): Remove .* and update the static_assert expectations once we roll
83// past Clang r313315. https://crbug.com/765692.
84
85#if defined(NCTEST_METHOD_ON_CONST_OBJECT)  // [r"fatal error: static_assert failed .*\"Bound argument \|i\| of type \|Arg\| cannot be forwarded as \|Unwrapped\| to the bound functor, which declares it as \|Param\|\.\""]
86
87// Method bound to const-object.
88//
89// Only const methods should be allowed to work with const objects.
90void WontCompile() {
91  HasRef has_ref;
92  const HasRef* const_has_ref_ptr_ = &has_ref;
93  Callback<void()> method_to_const_cb =
94      Bind(&HasRef::VoidMethod0, const_has_ref_ptr_);
95  method_to_const_cb.Run();
96}
97
98#elif defined(NCTEST_METHOD_BIND_NEEDS_REFCOUNTED_OBJECT)  // [r"fatal error: static_assert failed \"Receivers may not be raw pointers\."]
99
100
101// Method bound to non-refcounted object.
102//
103// We require refcounts unless you have Unretained().
104void WontCompile() {
105  NoRef no_ref;
106  Callback<void()> no_ref_cb =
107      Bind(&NoRef::VoidMethod0, &no_ref);
108  no_ref_cb.Run();
109}
110
111#elif defined(NCTEST_CONST_METHOD_NEEDS_REFCOUNTED_OBJECT)  // [r"fatal error: static_assert failed \"Receivers may not be raw pointers\."]
112
113// Const Method bound to non-refcounted object.
114//
115// We require refcounts unless you have Unretained().
116void WontCompile() {
117  NoRef no_ref;
118  Callback<void()> no_ref_const_cb =
119      Bind(&NoRef::VoidConstMethod0, &no_ref);
120  no_ref_const_cb.Run();
121}
122
123#elif defined(NCTEST_CONST_POINTER)  // [r"fatal error: static_assert failed .*\"Bound argument \|i\| of type \|Arg\| cannot be forwarded as \|Unwrapped\| to the bound functor, which declares it as \|Param\|\.\""]
124
125// Const argument used with non-const pointer parameter of same type.
126//
127// This is just a const-correctness check.
128void WontCompile() {
129  const NoRef* const_no_ref_ptr;
130  Callback<NoRef*()> pointer_same_cb =
131      Bind(&PolymorphicIdentity<NoRef*>, const_no_ref_ptr);
132  pointer_same_cb.Run();
133}
134
135#elif defined(NCTEST_CONST_POINTER_SUBTYPE)  // [r"fatal error: static_assert failed .*\"Bound argument \|i\| of type \|Arg\| cannot be forwarded as \|Unwrapped\| to the bound functor, which declares it as \|Param\|\.\""]
136
137// Const argument used with non-const pointer parameter of super type.
138//
139// This is just a const-correctness check.
140void WontCompile() {
141  const NoRefChild* const_child_ptr;
142  Callback<NoRefParent*()> pointer_super_cb =
143    Bind(&PolymorphicIdentity<NoRefParent*>, const_child_ptr);
144  pointer_super_cb.Run();
145}
146
147#elif defined(DISABLED_NCTEST_DISALLOW_NON_CONST_REF_PARAM)  // [r"fatal error: no member named 'AddRef' in 'base::NoRef'"]
148// TODO(dcheng): I think there's a type safety promotion issue here where we can
149// pass a const ref to a non const-ref function, or vice versa accidentally. Or
150// we make a copy accidentally. Check.
151
152// Functions with reference parameters, unsupported.
153//
154// First, non-const reference parameters are disallowed by the Google
155// style guide. Second, since we are doing argument forwarding it becomes
156// very tricky to avoid copies, maintain const correctness, and not
157// accidentally have the function be modifying a temporary, or a copy.
158void WontCompile() {
159  Parent p;
160  Callback<int(Parent&)> ref_arg_cb = Bind(&UnwrapParentRef);
161  ref_arg_cb.Run(p);
162}
163
164#elif defined(NCTEST_DISALLOW_BIND_TO_NON_CONST_REF_PARAM)  // [r"fatal error: static_assert failed .*\"Bound argument \|i\| of type \|Arg\| cannot be forwarded as \|Unwrapped\| to the bound functor, which declares it as \|Param\|\.\""]
165
166// Binding functions with reference parameters, unsupported.
167//
168// See comment in NCTEST_DISALLOW_NON_CONST_REF_PARAM
169void WontCompile() {
170  Parent p;
171  Callback<int()> ref_cb = Bind(&UnwrapParentRef, p);
172  ref_cb.Run();
173}
174
175#elif defined(NCTEST_NO_IMPLICIT_ARRAY_PTR_CONVERSION)  // [r"fatal error: static_assert failed .*\"First bound argument to a method cannot be an array\.\""]
176
177// A method should not be bindable with an array of objects.
178//
179// This is likely not wanted behavior. We specifically check for it though
180// because it is possible, depending on how you implement prebinding, to
181// implicitly convert an array type to a pointer type.
182void WontCompile() {
183  HasRef p[10];
184  Callback<void()> method_bound_to_array_cb =
185      Bind(&HasRef::VoidMethod0, p);
186  method_bound_to_array_cb.Run();
187}
188
189#elif defined(NCTEST_NO_RVALUE_RAW_PTR_FOR_REFCOUNTED_TYPES)  // [r"fatal error: static_assert failed .*\"A parameter is a refcounted type and needs scoped_refptr\.\""]
190
191// Refcounted types should not be bound as a raw pointer.
192void WontCompile() {
193  HasRef for_raw_ptr;
194  int a;
195  Callback<void()> ref_count_as_raw_ptr_a =
196      Bind(&VoidPolymorphic1<int*>, &a);
197  Callback<void()> ref_count_as_raw_ptr =
198      Bind(&VoidPolymorphic1<HasRef*>, &for_raw_ptr);
199}
200
201#elif defined(NCTEST_NO_LVALUE_RAW_PTR_FOR_REFCOUNTED_TYPES)  // [r"fatal error: static_assert failed .*\"A parameter is a refcounted type and needs scoped_refptr\.\""]
202
203// Refcounted types should not be bound as a raw pointer.
204void WontCompile() {
205  HasRef* for_raw_ptr = nullptr;
206  Callback<void()> ref_count_as_raw_ptr =
207      Bind(&VoidPolymorphic1<HasRef*>, for_raw_ptr);
208}
209
210#elif defined(NCTEST_NO_RVALUE_CONST_RAW_PTR_FOR_REFCOUNTED_TYPES)  // [r"fatal error: static_assert failed .*\"A parameter is a refcounted type and needs scoped_refptr\.\""]
211
212// Refcounted types should not be bound as a raw pointer.
213void WontCompile() {
214  const HasRef for_raw_ptr;
215  Callback<void()> ref_count_as_raw_ptr =
216      Bind(&VoidPolymorphic1<const HasRef*>, &for_raw_ptr);
217}
218
219#elif defined(NCTEST_NO_LVALUE_CONST_RAW_PTR_FOR_REFCOUNTED_TYPES)  // [r"fatal error: static_assert failed .*\"A parameter is a refcounted type and needs scoped_refptr\.\""]
220
221// Refcounted types should not be bound as a raw pointer.
222void WontCompile() {
223  const HasRef* for_raw_ptr = nullptr;
224  Callback<void()> ref_count_as_raw_ptr =
225      Bind(&VoidPolymorphic1<const HasRef*>, for_raw_ptr);
226}
227
228#elif defined(NCTEST_WEAKPTR_BIND_MUST_RETURN_VOID)  // [r"fatal error: static_assert failed .*\"weak_ptrs can only bind to methods without return values\""]
229
230// WeakPtrs cannot be bound to methods with return types.
231void WontCompile() {
232  NoRef no_ref;
233  WeakPtrFactory<NoRef> weak_factory(&no_ref);
234  Callback<int()> weak_ptr_with_non_void_return_type =
235      Bind(&NoRef::IntMethod0, weak_factory.GetWeakPtr());
236  weak_ptr_with_non_void_return_type.Run();
237}
238
239#elif defined(NCTEST_DISALLOW_ASSIGN_DIFFERENT_TYPES)  // [r"fatal error: no viable conversion from 'Callback<MakeUnboundRunType<void \(\*\)\(int\)>>' to 'Callback<void \(\)>'"]
240
241// Bind result cannot be assigned to Callbacks with a mismatching type.
242void WontCompile() {
243  Closure callback_mismatches_bind_type = Bind(&VoidPolymorphic1<int>);
244}
245
246#elif defined(NCTEST_DISALLOW_CAPTURING_LAMBDA)  // [r"fatal error: implicit instantiation of undefined template 'base::internal::FunctorTraits<\(lambda at (\.\./)+base/bind_unittest.nc:[0-9]+:[0-9]+\), void>'"]
247
248void WontCompile() {
249  int i = 0, j = 0;
250  Bind([i,&j]() {j = i;});
251}
252
253#elif defined(NCTEST_DISALLOW_ONCECALLBACK_RUN_ON_LVALUE)  // [r"static_assert failed .*\"OnceCallback::Run\(\) may only be invoked on a non-const rvalue, i\.e\. std::move\(callback\)\.Run\(\)\.\""]
254
255void WontCompile() {
256  OnceClosure cb = Bind([] {});
257  cb.Run();
258}
259
260#elif defined(NCTEST_DISALLOW_ONCECALLBACK_RUN_ON_CONST_LVALUE)  // [r"static_assert failed .*\"OnceCallback::Run\(\) may only be invoked on a non-const rvalue, i\.e\. std::move\(callback\)\.Run\(\)\.\""]
261
262void WontCompile() {
263  const OnceClosure cb = Bind([] {});
264  cb.Run();
265}
266
267#elif defined(NCTEST_DISALLOW_ONCECALLBACK_RUN_ON_CONST_RVALUE)  // [r"static_assert failed .*\"OnceCallback::Run\(\) may only be invoked on a non-const rvalue, i\.e\. std::move\(callback\)\.Run\(\)\.\""]
268
269void WontCompile() {
270  const OnceClosure cb = Bind([] {});
271  std::move(cb).Run();
272}
273
274#elif defined(NCTEST_DISALLOW_BIND_ONCECALLBACK)  // [r"fatal error: static_assert failed .*\"BindRepeating cannot bind OnceCallback. Use BindOnce with std::move\(\)\.\""]
275
276void WontCompile() {
277  Bind(BindOnce([](int) {}), 42);
278}
279
280#elif defined(NCTEST_DISALLOW_BINDONCE_LVALUE_ONCECALLBACK)  // [r"fatal error: static_assert failed .*\"BindOnce requires non-const rvalue for OnceCallback binding\."]
281void WontCompile() {
282  auto cb = BindOnce([](int) {});
283  BindOnce(cb, 42);
284}
285
286#elif defined(NCTEST_DISALLOW_BINDONCE_RVALUE_CONST_ONCECALLBACK)  // [r"fatal error: static_assert failed .*\"BindOnce requires non-const rvalue for OnceCallback binding\."]
287
288void WontCompile() {
289  const auto cb = BindOnce([](int) {});
290  BindOnce(std::move(cb), 42);
291}
292
293#elif defined(NCTEST_BINDONCE_MOVEONLY_TYPE_BY_VALUE)  // [r"fatal error: static_assert failed .*\"Bound argument \|i\| is move-only but will be bound by copy\. Ensure \|Arg\| is mutable and bound using std::move\(\)\.\""]
294
295void WontCompile() {
296  std::unique_ptr<int> x;
297  BindOnce(&TakesMoveOnly, x);
298}
299
300#elif defined(NCTEST_BIND_MOVEONLY_TYPE_BY_VALUE)  // [r"Bound argument \|i\| is move-only but will be forwarded by copy\. Ensure \|Arg\| is bound using base::Passed\(\), not std::move\(\)."]
301
302void WontCompile() {
303  std::unique_ptr<int> x;
304  Bind(&TakesMoveOnly, x);
305}
306
307#elif defined(NCTEST_BIND_MOVEONLY_TYPE_WITH_STDMOVE)  // [r"Bound argument \|i\| is move-only but will be forwarded by copy\. Ensure \|Arg\| is bound using base::Passed\(\), not std::move\(\)."]
308
309void WontCompile() {
310  std::unique_ptr<int> x;
311  Bind(&TakesMoveOnly, std::move(x));
312}
313
314#elif defined(NCTEST_BIND_NON_EMPTY_FUNCTOR)  // [r"fatal error: implicit instantiation of undefined template 'base::internal::FunctorTraits<base::NonEmptyFunctor, void>'"]
315
316void WontCompile() {
317  Bind(NonEmptyFunctor());
318}
319
320#endif
321
322}  // namespace base
323