2
# tag: cpp, cpp17, no-cpp-locals
3
# no-cpp-locals because the test is already run with it explicitly set
5
# cython: cpp_locals=True
9
from libcpp cimport bool as cppbool
13
static void print_C_destructor();
17
C() = delete; // look! No default constructor
18
C(int x, bool print_destructor=true) : x(x), print_destructor(print_destructor) {}
19
C(C&& rhs) : x(rhs.x), print_destructor(rhs.print_destructor) {
20
rhs.print_destructor = false; // moved-from instances are deleted silently
22
// also test that we don't require the assignment operator
23
C& operator=(C&& rhs) = delete;
24
C(const C& rhs) = delete;
25
C& operator=(const C& rhs) = default;
27
if (print_destructor) print_C_destructor();
30
int getX() const { return x; }
34
bool print_destructor;
45
C make_C(int) except + # needs a temp to receive
47
# this function just makes sure the output from the destructor can be captured by doctest
48
cdef void print_C_destructor "print_C_destructor" () with gil:
51
def maybe_assign_infer(assign, value, do_print):
53
>>> maybe_assign_infer(True, 5, True)
56
>>> maybe_assign_infer(False, 0, True)
57
Traceback (most recent call last):
59
UnboundLocalError: local variable 'x' referenced before assignment
60
>>> maybe_assign_infer(False, 0, False) # no destructor call here
67
def maybe_assign_cdef(assign, value):
69
>>> maybe_assign_cdef(True, 5)
72
>>> maybe_assign_cdef(False, 0)
73
Traceback (most recent call last):
75
UnboundLocalError: local variable 'x' referenced before assignment
82
def maybe_assign_annotation(assign, value):
84
>>> maybe_assign_annotation(True, 5)
87
>>> maybe_assign_annotation(False, 0)
88
Traceback (most recent call last):
90
UnboundLocalError: local variable 'x' referenced before assignment
97
def maybe_assign_directive1(assign, value):
99
>>> maybe_assign_directive1(True, 5)
102
>>> maybe_assign_directive1(False, 0)
103
Traceback (most recent call last):
105
UnboundLocalError: local variable 'x' referenced before assignment
107
x = cython.declare(C)
113
def maybe_assign_directive2(assign, value):
115
>>> maybe_assign_directive2(True, 5)
118
>>> maybe_assign_directive2(False, 0)
119
Traceback (most recent call last):
121
UnboundLocalError: local variable 'x' referenced before assignment
127
def maybe_assign_nocheck(assign, value):
129
>>> maybe_assign_nocheck(True, 5)
133
# unfortunately it's quite difficult to test not assigning because there's a decent chance it'll crash
137
with cython.initializedcheck(False):
142
needs a temp to handle the result of make_C - still doesn't use the default constructor
151
# c should not be optional - it isn't easy to check this, but we can at least check it compiles
152
cdef void has_argument(C c):
155
def call_has_argument():
157
>>> call_has_argument()
160
has_argument(C(50, False))
164
>>> inst = HoldsC(True, False)
167
>>> access_from_function_with_different_directive(inst)
170
>>> inst.getCX() # it was changed in access_from_function_with_different_directive
172
>>> inst = HoldsC(False, False)
174
Traceback (most recent call last):
176
AttributeError: C++ attribute 'value' is not initialized
177
>>> access_from_function_with_different_directive(inst)
178
Traceback (most recent call last):
180
AttributeError: C++ attribute 'value' is not initialized
183
def __cinit__(self, initialize, print_destructor):
185
self.value = C(10, print_destructor)
188
return self.value.getX()
193
@cython.cpp_locals(False)
194
def access_from_function_with_different_directive(HoldsC c):
195
# doctest is in HoldsC class
196
print(acceptC(c.value)) # this originally tried to pass a __Pyx_Optional<C> as a C instance
197
print(c.value.getX())
198
c.value = C(20, False) # make sure that we can change it too
200
def dont_test_on_pypy(f):
202
if not hasattr(sys, "pypy_version_info"):
205
@dont_test_on_pypy # non-deterministic destruction
206
def testHoldsCDestruction(initialize):
208
>>> testHoldsCDestruction(True)
210
>>> testHoldsCDestruction(False) # no destructor
212
x = HoldsC(initialize, True)
217
def initialize_global_var():
219
global_var = C(-1, False)
221
def read_global_var():
223
>>> read_global_var()
224
Traceback (most recent call last):
226
NameError: C++ global 'global_var' is not initialized
227
>>> initialize_global_var()
228
>>> read_global_var()
231
print(global_var.getX())