Author: Wim Lavrijsen <wlavrij...@lbl.gov> Branch: Changeset: r94435:e50e11af23f1 Date: 2018-04-23 19:57 -0700 http://bitbucket.org/pypy/pypy/changeset/e50e11af23f1/
Log: merge cppyy-packaging: move to latest backend (0.6.0) and support exceptions through wrappers diff --git a/pypy/module/_cppyy/__init__.py b/pypy/module/_cppyy/__init__.py --- a/pypy/module/_cppyy/__init__.py +++ b/pypy/module/_cppyy/__init__.py @@ -13,7 +13,7 @@ '_set_function_generator': 'interp_cppyy.set_function_generator', '_register_class' : 'interp_cppyy.register_class', '_get_nullptr' : 'interp_cppyy.get_nullptr', - 'CPPClassBase' : 'interp_cppyy.W_CPPClass', + 'CPPInstanceBase' : 'interp_cppyy.W_CPPInstance', 'addressof' : 'interp_cppyy.addressof', '_bind_object' : 'interp_cppyy._bind_object', 'bind_object' : 'interp_cppyy.bind_object', diff --git a/pypy/module/_cppyy/capi/loadable_capi.py b/pypy/module/_cppyy/capi/loadable_capi.py --- a/pypy/module/_cppyy/capi/loadable_capi.py +++ b/pypy/module/_cppyy/capi/loadable_capi.py @@ -121,11 +121,11 @@ # TODO: the following need to match up with the globally defined C_XYZ low-level # types (see capi/__init__.py), but by using strings here, that isn't guaranteed - c_opaque_ptr = state.c_ulong + c_opaque_ptr = state.c_ulong # not ptrdiff_t (which is signed) c_scope = c_opaque_ptr c_type = c_scope - c_object = c_opaque_ptr + c_object = c_opaque_ptr # not voidp (to stick with one handle type) c_method = c_opaque_ptr c_index = state.c_long c_index_array = state.c_voidp @@ -150,16 +150,17 @@ self.capi_call_ifaces = { # name to opaque C++ scope representation - 'num_scopes' : ([c_scope], c_int), - 'scope_name' : ([c_scope, c_int], c_ccharp), - 'resolve_name' : ([c_ccharp], c_ccharp), + 'resolve_enum' : ([c_ccharp], c_ccharp), 'get_scope' : ([c_ccharp], c_scope), 'actual_class' : ([c_type, c_object], c_type), + 'size_of_klass' : ([c_type], c_size_t), + 'size_of_type' : ([c_ccharp], c_size_t), # memory management 'allocate' : ([c_type], c_object), 'deallocate' : ([c_type, c_object], c_void), + 'construct' : ([c_type], c_object), 'destruct' : ([c_type, c_object], c_void), # method/function dispatching @@ -182,7 +183,8 @@ 'constructor' : ([c_method, c_object, c_int, c_voidp], c_object), 'call_o' : ([c_method, c_object, c_int, c_voidp, c_type], c_object), - 'get_function_address' : ([c_scope, c_index], c_voidp), # TODO: verify + 'function_address_from_index' : ([c_scope, c_index], c_voidp), # TODO: verify + 'function_address_from_method' : ([c_method], c_voidp), # id. # handling of function argument buffer 'allocate_function_args' : ([c_int], c_voidp), @@ -196,6 +198,8 @@ 'is_abstract' : ([c_type], c_int), 'is_enum' : ([c_ccharp], c_int), + 'get_all_cpp_names' : ([c_scope, c_voidp], c_voidp), # const char** + # type/class reflection information 'final_name' : ([c_type], c_ccharp), 'scoped_final_name' : ([c_type], c_ccharp), @@ -208,10 +212,10 @@ # method/function reflection information 'num_methods' : ([c_scope], c_int), - 'method_index_at' : ([c_scope, c_int], c_index), 'method_indices_from_name' : ([c_scope, c_ccharp], c_index_array), 'method_name' : ([c_scope, c_index], c_ccharp), + 'method_mangled_name' : ([c_scope, c_index], c_ccharp), 'method_result_type' : ([c_scope, c_index], c_ccharp), 'method_num_args' : ([c_scope, c_index], c_int), 'method_req_args' : ([c_scope, c_index], c_int), @@ -219,7 +223,9 @@ 'method_arg_default' : ([c_scope, c_index, c_int], c_ccharp), 'method_signature' : ([c_scope, c_index, c_int], c_ccharp), 'method_prototype' : ([c_scope, c_index, c_int], c_ccharp), + 'is_const_method' : ([c_method], c_int), + 'exists_method_template' : ([c_scope, c_ccharp], c_int), 'method_is_template' : ([c_scope, c_index], c_int), 'method_num_template_args' : ([c_scope, c_index], c_int), 'method_template_arg_name' : ([c_scope, c_index, c_index], c_ccharp), @@ -228,7 +234,9 @@ 'get_global_operator' : ([c_scope, c_scope, c_scope, c_ccharp], c_index), # method properties + 'is_public_method' : ([c_type, c_index], c_int), 'is_constructor' : ([c_type, c_index], c_int), + 'is_destructor' : ([c_type, c_index], c_int), 'is_staticmethod' : ([c_type, c_index], c_int), # data member reflection information @@ -236,12 +244,14 @@ 'datamember_name' : ([c_scope, c_int], c_ccharp), 'datamember_type' : ([c_scope, c_int], c_ccharp), 'datamember_offset' : ([c_scope, c_int], c_ptrdiff_t), - 'datamember_index' : ([c_scope, c_ccharp], c_int), # data member properties 'is_publicdata' : ([c_scope, c_int], c_int), 'is_staticdata' : ([c_scope, c_int], c_int), + 'is_const_data' : ([c_scope, c_int], c_int), + 'is_enum_data' : ([c_scope, c_int], c_int), + 'get_dimension_size' : ([c_scope, c_int, c_int], c_int), # misc helpers 'strtoll' : ([c_ccharp], c_llong), @@ -328,25 +338,27 @@ return rffi.cast(rffi.CCHARP, ptr) # name to opaque C++ scope representation ------------------------------------ -def c_num_scopes(space, cppscope): - return space.int_w(call_capi(space, 'num_scopes', [_ArgH(cppscope.handle)])) -def c_scope_name(space, cppscope, iscope): - args = [_ArgH(cppscope.handle), _ArgL(iscope)] - return charp2str_free(space, call_capi(space, 'scope_name', args)) - def c_resolve_name(space, name): return charp2str_free(space, call_capi(space, 'resolve_name', [_ArgS(name)])) +def c_resolve_enum(space, name): + return charp2str_free(space, call_capi(space, 'resolve_enum', [_ArgS(name)])) def c_get_scope_opaque(space, name): return rffi.cast(C_SCOPE, space.uint_w(call_capi(space, 'get_scope', [_ArgS(name)]))) def c_actual_class(space, cppclass, cppobj): args = [_ArgH(cppclass.handle), _ArgH(cppobj)] return rffi.cast(C_TYPE, space.uint_w(call_capi(space, 'actual_class', args))) +def c_size_of_klass(space, cppclass): + return _cdata_to_size_t(space, call_capi(space, 'size_of_klass', [_ArgH(cppclass.handle)])) +def c_size_of_type(space, name): + return _cdata_to_size_t(space, call_capi(space, 'size_of_type', [_ArgS(name)])) # memory management ---------------------------------------------------------- def c_allocate(space, cppclass): return _cdata_to_cobject(space, call_capi(space, 'allocate', [_ArgH(cppclass.handle)])) def c_deallocate(space, cppclass, cppobject): call_capi(space, 'deallocate', [_ArgH(cppclass.handle), _ArgH(cppobject)]) +def c_construct(space, cppclass): + return _cdata_to_cobject(space, call_capi(space, 'construct', [_ArgH(cppclass.handle)])) def c_destruct(space, cppclass, cppobject): call_capi(space, 'destruct', [_ArgH(cppclass.handle), _ArgH(cppobject)]) @@ -391,7 +403,7 @@ w_cstr = call_capi(space, 'call_s', [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs), _ArgP(rffi.cast(rffi.VOIDP, length))]) - cstr_len = intmask(length[0]) + cstr_len = int(intmask(length[0])) finally: lltype.free(length, flavor='raw') return _cdata_to_ccharp(space, w_cstr), cstr_len @@ -403,10 +415,13 @@ args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs), _ArgH(cppclass.handle)] return _cdata_to_cobject(space, call_capi(space, 'call_o', args)) -def c_get_function_address(space, cppscope, index): +def c_function_address_from_index(space, cppscope, index): args = [_ArgH(cppscope.handle), _ArgL(index)] return rffi.cast(C_FUNC_PTR, - _cdata_to_ptr(space, call_capi(space, 'get_function_address', args))) + _cdata_to_ptr(space, call_capi(space, 'function_address_from_index', args))) +def c_function_address_from_method(space, cppmethod): + return rffi.cast(C_FUNC_PTR, + _cdata_to_ptr(space, call_capi(space, 'function_address_from_method', _ArgH(cppmethod)))) # handling of function argument buffer --------------------------------------- def c_allocate_function_args(space, size): @@ -430,6 +445,23 @@ def c_is_enum(space, name): return space.bool_w(call_capi(space, 'is_enum', [_ArgS(name)])) +def c_get_all_cpp_names(space, scope): + sz = lltype.malloc(rffi.SIZE_TP.TO, 1, flavor='raw', zero=True) + try: + args = [_ArgH(scope.handle), _ArgP(rffi.cast(rffi.VOIDP, sz))] + rawnames = rffi.cast(rffi.CCHARPP, + _cdata_to_ptr(space, call_capi(space, 'get_all_cpp_names', args))) + count = int(intmask(sz[0])) + finally: + lltype.free(sz, flavor='raw') + allnames = [] + for i in range(count): + pystr = rffi.charp2str(rawnames[i]) + c_free(space, rffi.cast(rffi.VOIDP, rawnames[i])) # c_free defined below + allnames.append(pystr) + c_free(space, rffi.cast(rffi.VOIDP, rawnames)) # id. + return allnames + # type/class reflection information ------------------------------------------ def c_final_name(space, cpptype): return charp2str_free(space, call_capi(space, 'final_name', [_ArgH(cpptype)])) @@ -462,13 +494,10 @@ def c_num_methods(space, cppscope): args = [_ArgH(cppscope.handle)] return space.int_w(call_capi(space, 'num_methods', args)) -def c_method_index_at(space, cppscope, imethod): - args = [_ArgH(cppscope.handle), _ArgL(imethod)] - return space.int_w(call_capi(space, 'method_index_at', args)) def c_method_indices_from_name(space, cppscope, name): args = [_ArgH(cppscope.handle), _ArgS(name)] indices = rffi.cast(C_INDEX_ARRAY, - _cdata_to_ptr(space, call_capi(space, 'method_indices_from_name', args))) + _cdata_to_ptr(space, call_capi(space, 'method_indices_from_name', args))) if not indices: return [] py_indices = [] @@ -506,6 +535,9 @@ args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(show_formalargs)] return charp2str_free(space, call_capi(space, 'method_prototype', args)) +def c_exists_method_template(space, cppscope, name): + args = [_ArgH(cppscope.handle), _ArgS(name)] + return space.bool_w(call_capi(space, 'exists_method_template', args)) def c_method_is_template(space, cppscope, index): args = [_ArgH(cppscope.handle), _ArgL(index)] return space.bool_w(call_capi(space, 'method_is_template', args)) @@ -531,9 +563,15 @@ return rffi.cast(WLAVC_INDEX, -1) # method properties ---------------------------------------------------------- +def c_is_public_method(space, cppclass, index): + args = [_ArgH(cppclass.handle), _ArgL(index)] + return space.bool_w(call_capi(space, 'is_public_method', args)) def c_is_constructor(space, cppclass, index): args = [_ArgH(cppclass.handle), _ArgL(index)] return space.bool_w(call_capi(space, 'is_constructor', args)) +def c_is_destructor(space, cppclass, index): + args = [_ArgH(cppclass.handle), _ArgL(index)] + return space.bool_w(call_capi(space, 'is_destructor', args)) def c_is_staticmethod(space, cppclass, index): args = [_ArgH(cppclass.handle), _ArgL(index)] return space.bool_w(call_capi(space, 'is_staticmethod', args)) @@ -562,6 +600,15 @@ def c_is_staticdata(space, cppscope, datamember_index): args = [_ArgH(cppscope.handle), _ArgL(datamember_index)] return space.bool_w(call_capi(space, 'is_staticdata', args)) +def c_is_const_data(space, cppscope, datamember_index): + args = [_ArgH(cppscope.handle), _ArgL(datamember_index)] + return space.bool_w(call_capi(space, 'is_const_data', args)) +def c_is_enum_data(space, cppscope, datamember_index): + args = [_ArgH(cppscope.handle), _ArgL(datamember_index)] + return space.bool_w(call_capi(space, 'is_enum_data', args)) +def c_get_dimension_size(space, cppscope, datamember_index, dim_idx): + args = [_ArgH(cppscope.handle), _ArgL(datamember_index), _ArgL(dim_idx)] + return space.bool_w(call_capi(space, 'get_dimension_size', args)) # misc helpers --------------------------------------------------------------- def c_strtoll(space, svalue): @@ -585,7 +632,7 @@ try: w_cstr = call_capi(space, 'stdstring2charp', [_ArgH(cppstr), _ArgP(rffi.cast(rffi.VOIDP, sz))]) - cstr_len = intmask(sz[0]) + cstr_len = int(intmask(sz[0])) finally: lltype.free(sz, flavor='raw') return rffi.charpsize2str(_cdata_to_ccharp(space, w_cstr), cstr_len) @@ -607,7 +654,7 @@ """Return a python string taking into account \0""" from pypy.module._cppyy import interp_cppyy - cppstr = space.interp_w(interp_cppyy.W_CPPClass, w_self, can_be_None=False) + cppstr = space.interp_w(interp_cppyy.W_CPPInstance, w_self, can_be_None=False) return space.newtext(c_stdstring2charp(space, cppstr._rawobject)) # setup pythonizations for later use at run-time diff --git a/pypy/module/_cppyy/converter.py b/pypy/module/_cppyy/converter.py --- a/pypy/module/_cppyy/converter.py +++ b/pypy/module/_cppyy/converter.py @@ -22,8 +22,8 @@ def get_rawobject(space, w_obj, can_be_None=True): - from pypy.module._cppyy.interp_cppyy import W_CPPClass - cppinstance = space.interp_w(W_CPPClass, w_obj, can_be_None=can_be_None) + from pypy.module._cppyy.interp_cppyy import W_CPPInstance + cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=can_be_None) if cppinstance: rawobject = cppinstance.get_rawobject() assert lltype.typeOf(rawobject) == capi.C_OBJECT @@ -31,15 +31,15 @@ return capi.C_NULL_OBJECT def set_rawobject(space, w_obj, address): - from pypy.module._cppyy.interp_cppyy import W_CPPClass - cppinstance = space.interp_w(W_CPPClass, w_obj, can_be_None=True) + from pypy.module._cppyy.interp_cppyy import W_CPPInstance + cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=True) if cppinstance: assert lltype.typeOf(cppinstance._rawobject) == capi.C_OBJECT cppinstance._rawobject = rffi.cast(capi.C_OBJECT, address) def get_rawobject_nonnull(space, w_obj): - from pypy.module._cppyy.interp_cppyy import W_CPPClass - cppinstance = space.interp_w(W_CPPClass, w_obj, can_be_None=True) + from pypy.module._cppyy.interp_cppyy import W_CPPInstance + cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=True) if cppinstance: cppinstance._nullcheck() rawobject = cppinstance.get_rawobject() @@ -502,8 +502,8 @@ self.clsdecl = clsdecl def _unwrap_object(self, space, w_obj): - from pypy.module._cppyy.interp_cppyy import W_CPPClass - if isinstance(w_obj, W_CPPClass): + from pypy.module._cppyy.interp_cppyy import W_CPPInstance + if isinstance(w_obj, W_CPPInstance): from pypy.module._cppyy.interp_cppyy import INSTANCE_FLAGS_IS_R_VALUE if w_obj.flags & INSTANCE_FLAGS_IS_R_VALUE: # reject moves as all are explicit @@ -534,8 +534,8 @@ class InstanceMoveConverter(InstanceRefConverter): def _unwrap_object(self, space, w_obj): # moving is same as by-ref, but have to check that move is allowed - from pypy.module._cppyy.interp_cppyy import W_CPPClass, INSTANCE_FLAGS_IS_R_VALUE - if isinstance(w_obj, W_CPPClass): + from pypy.module._cppyy.interp_cppyy import W_CPPInstance, INSTANCE_FLAGS_IS_R_VALUE + if isinstance(w_obj, W_CPPInstance): if w_obj.flags & INSTANCE_FLAGS_IS_R_VALUE: w_obj.flags &= ~INSTANCE_FLAGS_IS_R_VALUE return InstanceRefConverter._unwrap_object(self, space, w_obj) @@ -598,8 +598,8 @@ raise FastCallNotPossible def finalize_call(self, space, w_obj, call_local): - from pypy.module._cppyy.interp_cppyy import W_CPPClass - assert isinstance(w_obj, W_CPPClass) + from pypy.module._cppyy.interp_cppyy import W_CPPInstance + assert isinstance(w_obj, W_CPPInstance) r = rffi.cast(rffi.VOIDPP, call_local) w_obj._rawobject = rffi.cast(capi.C_OBJECT, r[0]) @@ -617,8 +617,8 @@ InstanceConverter.__init__(self, space, cppclass) def _unwrap_object(self, space, w_obj): - from pypy.module._cppyy.interp_cppyy import W_CPPClass - if isinstance(w_obj, W_CPPClass): + from pypy.module._cppyy.interp_cppyy import W_CPPInstance + if isinstance(w_obj, W_CPPInstance): arg = InstanceConverter._unwrap_object(self, space, w_obj) return capi.c_stdstring2stdstring(space, arg) else: @@ -749,8 +749,6 @@ return InstancePtrPtrConverter(space, clsdecl) elif compound == "": return InstanceConverter(space, clsdecl) - elif capi.c_is_enum(space, clean_name): - return _converters['unsigned'](space, default) # 5) void* or void converter (which fails on use) if 0 <= compound.find('*'): diff --git a/pypy/module/_cppyy/executor.py b/pypy/module/_cppyy/executor.py --- a/pypy/module/_cppyy/executor.py +++ b/pypy/module/_cppyy/executor.py @@ -289,8 +289,6 @@ return InstancePtrExecutor(space, cppclass) elif compound == '**' or compound == '*&': return InstancePtrPtrExecutor(space, cppclass) - elif capi.c_is_enum(space, clean_name): - return _executors['internal_enum_type_t'](space, None) # 4) additional special cases if compound == '*': diff --git a/pypy/module/_cppyy/include/capi.h b/pypy/module/_cppyy/include/capi.h --- a/pypy/module/_cppyy/include/capi.h +++ b/pypy/module/_cppyy/include/capi.h @@ -8,26 +8,29 @@ extern "C" { #endif // ifdef __cplusplus - typedef unsigned long cppyy_scope_t; + typedef ptrdiff_t cppyy_scope_t; typedef cppyy_scope_t cppyy_type_t; - typedef unsigned long cppyy_object_t; - typedef unsigned long cppyy_method_t; + typedef void* cppyy_object_t; + typedef ptrdiff_t cppyy_method_t; + typedef long cppyy_index_t; typedef void* cppyy_funcaddr_t; + typedef unsigned long cppyy_exctype_t; + /* name to opaque C++ scope representation -------------------------------- */ RPY_EXTERN - int cppyy_num_scopes(cppyy_scope_t parent); + char* cppyy_resolve_name(const char* cppitem_name); RPY_EXTERN - char* cppyy_scope_name(cppyy_scope_t parent, cppyy_index_t iscope); - RPY_EXTERN - char* cppyy_resolve_name(const char* cppitem_name); + char* cppyy_resolve_enum(const char* enum_type); RPY_EXTERN cppyy_scope_t cppyy_get_scope(const char* scope_name); RPY_EXTERN cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj); RPY_EXTERN - size_t cppyy_size_of(cppyy_type_t klass); + size_t cppyy_size_of_klass(cppyy_type_t klass); + RPY_EXTERN + size_t cppyy_size_of_type(const char* type_name); /* memory management ------------------------------------------------------ */ RPY_EXTERN @@ -35,48 +38,53 @@ RPY_EXTERN void cppyy_deallocate(cppyy_type_t type, cppyy_object_t self); RPY_EXTERN + cppyy_object_t cppyy_construct(cppyy_type_t type); + RPY_EXTERN void cppyy_destruct(cppyy_type_t type, cppyy_object_t self); /* method/function dispatching -------------------------------------------- */ RPY_EXTERN - void cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + void cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); RPY_EXTERN unsigned char cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); RPY_EXTERN - char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); RPY_EXTERN - short cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + short cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); RPY_EXTERN - int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); RPY_EXTERN - long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); RPY_EXTERN long long cppyy_call_ll(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); RPY_EXTERN - float cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + float cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); RPY_EXTERN double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); RPY_EXTERN long double cppyy_call_ld(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); RPY_EXTERN - void* cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + void* cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); RPY_EXTERN - char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args, size_t* length); - + char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args, size_t* length); RPY_EXTERN cppyy_object_t cppyy_constructor(cppyy_method_t method, cppyy_type_t klass, int nargs, void* args); RPY_EXTERN + void cppyy_destructor(cppyy_type_t type, cppyy_object_t self); + RPY_EXTERN cppyy_object_t cppyy_call_o(cppyy_method_t method, cppyy_object_t self, int nargs, void* args, cppyy_type_t result_type); RPY_EXTERN - cppyy_funcaddr_t cppyy_get_function_address(cppyy_scope_t scope, cppyy_index_t idx); + cppyy_funcaddr_t cppyy_function_address_from_index(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN + cppyy_funcaddr_t cppyy_function_address_from_method(cppyy_method_t method); /* handling of function argument buffer ----------------------------------- */ RPY_EXTERN - void* cppyy_allocate_function_args(int nargs); + void* cppyy_allocate_function_args(int nargs); RPY_EXTERN - void cppyy_deallocate_function_args(void* args); + void cppyy_deallocate_function_args(void* args); RPY_EXTERN size_t cppyy_function_arg_sizeof(); RPY_EXTERN @@ -92,6 +100,9 @@ RPY_EXTERN int cppyy_is_enum(const char* type_name); + RPY_EXTERN + const char** cppyy_get_all_cpp_names(cppyy_scope_t scope, size_t* count); + /* class reflection information ------------------------------------------- */ RPY_EXTERN char* cppyy_final_name(cppyy_type_t type); @@ -105,6 +116,10 @@ char* cppyy_base_name(cppyy_type_t type, int base_index); RPY_EXTERN int cppyy_is_subtype(cppyy_type_t derived, cppyy_type_t base); + RPY_EXTERN + int cppyy_smartptr_info(const char* name, cppyy_type_t* raw, cppyy_method_t* deref); + RPY_EXTERN + void cppyy_add_smartptr_type(const char* type_name); /* calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0 */ RPY_EXTERN @@ -114,8 +129,6 @@ RPY_EXTERN int cppyy_num_methods(cppyy_scope_t scope); RPY_EXTERN - cppyy_index_t cppyy_method_index_at(cppyy_scope_t scope, int imeth); - RPY_EXTERN cppyy_index_t* cppyy_method_indices_from_name(cppyy_scope_t scope, const char* name); RPY_EXTERN @@ -136,8 +149,12 @@ char* cppyy_method_signature(cppyy_scope_t scope, cppyy_index_t idx, int show_formalargs); RPY_EXTERN char* cppyy_method_prototype(cppyy_scope_t scope, cppyy_index_t idx, int show_formalargs); + RPY_EXTERN + int cppyy_is_const_method(cppyy_method_t); RPY_EXTERN + int cppyy_exists_method_template(cppyy_scope_t scope, const char* name); + RPY_EXTERN int cppyy_method_is_template(cppyy_scope_t scope, cppyy_index_t idx); RPY_EXTERN int cppyy_method_num_template_args(cppyy_scope_t scope, cppyy_index_t idx); @@ -169,15 +186,20 @@ char* cppyy_datamember_type(cppyy_scope_t scope, int datamember_index); RPY_EXTERN ptrdiff_t cppyy_datamember_offset(cppyy_scope_t scope, int datamember_index); - RPY_EXTERN int cppyy_datamember_index(cppyy_scope_t scope, const char* name); /* data member properties ------------------------------------------------- */ RPY_EXTERN - int cppyy_is_publicdata(cppyy_type_t type, int datamember_index); + int cppyy_is_publicdata(cppyy_type_t type, cppyy_index_t datamember_index); RPY_EXTERN - int cppyy_is_staticdata(cppyy_type_t type, int datamember_index); + int cppyy_is_staticdata(cppyy_type_t type, cppyy_index_t datamember_index); + RPY_EXTERN + int cppyy_is_const_data(cppyy_scope_t scope, cppyy_index_t idata); + RPY_EXTERN + int cppyy_is_enum_data(cppyy_scope_t scope, cppyy_index_t idata); + RPY_EXTERN + int cppyy_get_dimension_size(cppyy_scope_t scope, cppyy_index_t idata, int dimension); /* misc helpers ----------------------------------------------------------- */ RPY_EXTERN @@ -197,7 +219,7 @@ RPY_EXTERN const char* cppyy_stdvector_valuetype(const char* clname); RPY_EXTERN - size_t cppyy_stdvector_valuesize(const char* clname); + size_t cppyy_stdvector_valuesize(const char* clname); #ifdef __cplusplus } diff --git a/pypy/module/_cppyy/interp_cppyy.py b/pypy/module/_cppyy/interp_cppyy.py --- a/pypy/module/_cppyy/interp_cppyy.py +++ b/pypy/module/_cppyy/interp_cppyy.py @@ -19,6 +19,9 @@ INSTANCE_FLAGS_IS_REF = 0x0002 INSTANCE_FLAGS_IS_R_VALUE = 0x0004 +OVERLOAD_FLAGS_USE_FFI = 0x0001 + + class FastCallNotPossible(Exception): pass @@ -174,7 +177,7 @@ @staticmethod def unpack_cppthis(space, w_cppinstance, declaring_scope): - cppinstance = space.interp_w(W_CPPClass, w_cppinstance, can_be_None=False) + cppinstance = space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=False) cppinstance._nullcheck() return cppinstance.get_cppthis(declaring_scope) @@ -186,7 +189,7 @@ return rffi.cast(rffi.VOIDP, loc_idx) @jit.unroll_safe - def call(self, cppthis, args_w): + def call(self, cppthis, args_w, useffi): jit.promote(self) assert lltype.typeOf(cppthis) == capi.C_OBJECT @@ -218,16 +221,23 @@ try: # attempt to call directly through ffi chain - if self._funcaddr: + if useffi and self._funcaddr: try: return self.do_fast_call(cppthis, args_w, call_local) except FastCallNotPossible: pass # can happen if converters or executor does not implement ffi # ffi chain must have failed; using stub functions instead - args = self.prepare_arguments(args_w, call_local) + args, stat = self.prepare_arguments(args_w, call_local) try: - return self.executor.execute(self.space, self.cppmethod, cppthis, len(args_w), args) + result = self.executor.execute( + self.space, self.cppmethod, cppthis, len(args_w), args) + if stat[0] != rffi.cast(rffi.ULONG, 0): + what = rffi.cast(rffi.CCHARP, stat[1]) + pywhat = rffi.charp2str(what) + capi.c_free(self.space, rffi.cast(rffi.VOIDP, what)) + raise OperationError(self.space.w_Exception, self.space.newtext(pywhat)) + return result finally: self.finalize_call(args, args_w, call_local) finally: @@ -322,7 +332,7 @@ # Each CPPMethod corresponds one-to-one to a C++ equivalent and cppthis # has been offset to the matching class. Hence, the libffi pointer is # uniquely defined and needs to be setup only once. - funcaddr = capi.c_get_function_address(self.space, self.scope, self.index) + funcaddr = capi.c_function_address_from_index(self.space, self.scope, self.index) if funcaddr and cppthis: # methods only for now state = self.space.fromcache(ffitypes.State) @@ -373,7 +383,10 @@ conv.free_argument(self.space, rffi.cast(capi.C_OBJECT, arg_j), loc_j) capi.c_deallocate_function_args(self.space, args) raise - return args + stat = rffi.cast(rffi.ULONGP, + lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), int(len(args_w))*stride)) + stat[0] = rffi.cast(rffi.ULONG, 0) + return args, stat @jit.unroll_safe def finalize_call(self, args, args_w, call_local): @@ -435,7 +448,7 @@ # TODO: might have to specialize for CPPTemplatedCall on CPPMethod/CPPFunction here CPPMethod.__init__(self, space, declaring_scope, method_index, arg_defs, args_required) - def call(self, cppthis, args_w): + def call(self, cppthis, args_w, useffi): assert lltype.typeOf(cppthis) == capi.C_OBJECT for i in range(len(args_w)): try: @@ -447,10 +460,10 @@ raise oefmt(self.space.w_TypeError, "non-matching template (got %s where %s expected)", s, self.templ_args[i]) - return W_CPPBoundMethod(cppthis, self) + return W_CPPBoundMethod(cppthis, self, useffi) - def bound_call(self, cppthis, args_w): - return CPPMethod.call(self, cppthis, args_w) + def bound_call(self, cppthis, args_w, useffi): + return CPPMethod.call(self, cppthis, args_w, useffi) def __repr__(self): return "CPPTemplatedCall: %s" % self.prototype() @@ -468,11 +481,11 @@ def unpack_cppthis(space, w_cppinstance, declaring_scope): return rffi.cast(capi.C_OBJECT, declaring_scope.handle) - def call(self, cppthis, args_w): + def call(self, cppthis, args_w, useffi): # Note: this does not return a wrapped instance, just a pointer to the # new instance; the overload must still wrap it before returning. Also, # cppthis is declaring_scope.handle (as per unpack_cppthis(), above). - return CPPMethod.call(self, cppthis, args_w) + return CPPMethod.call(self, cppthis, args_w, useffi) def __repr__(self): return "CPPConstructor: %s" % self.prototype() @@ -485,7 +498,7 @@ _immutable_ = True - def call(self, cppthis, args_w): + def call(self, cppthis, args_w, useffi): end = len(args_w)-1 if 0 <= end: w_item = args_w[end] @@ -493,7 +506,7 @@ if self.converters is None: self._setup(cppthis) self.executor.set_item(self.space, w_item) # TODO: what about threads? - CPPMethod.call(self, cppthis, args_w) + CPPMethod.call(self, cppthis, args_w, useffi) class W_CPPOverload(W_Root): @@ -501,7 +514,7 @@ collection of (possibly) overloaded methods or functions. It calls these in order and deals with error handling and reporting.""" - _attrs_ = ['space', 'scope', 'functions'] + _attrs_ = ['space', 'scope', 'functions', 'flags'] _immutable_fields_ = ['scope', 'functions[*]'] def __init__(self, space, declaring_scope, functions): @@ -510,6 +523,19 @@ assert len(functions) from rpython.rlib import debug self.functions = debug.make_sure_not_resized(functions) + self.flags = 0 + self.flags |= OVERLOAD_FLAGS_USE_FFI + + # allow user to determine ffi use rules per overload + def fget_useffi(self, space): + return space.newbool(bool(self.flags & OVERLOAD_FLAGS_USE_FFI)) + + @unwrap_spec(value=bool) + def fset_useffi(self, space, value): + if space.is_true(value): + self.flags |= OVERLOAD_FLAGS_USE_FFI + else: + self.flags &= ~OVERLOAD_FLAGS_USE_FFI @jit.elidable_promote() def is_static(self): @@ -540,7 +566,7 @@ for i in range(len(self.functions)): cppyyfunc = self.functions[i] try: - return cppyyfunc.call(cppthis, args_w) + return cppyyfunc.call(cppthis, args_w, self.flags & OVERLOAD_FLAGS_USE_FFI) except Exception: pass @@ -553,7 +579,7 @@ for i in range(len(self.functions)): cppyyfunc = self.functions[i] try: - return cppyyfunc.call(cppthis, args_w) + return cppyyfunc.call(cppthis, args_w, self.flags & OVERLOAD_FLAGS_USE_FFI) except OperationError as e: # special case if there's just one function, to prevent clogging the error message if len(self.functions) == 1: @@ -588,6 +614,7 @@ 'CPPOverload', is_static = interp2app(W_CPPOverload.is_static), call = interp2app(W_CPPOverload.call), + __useffi__ = GetSetProperty(W_CPPOverload.fget_useffi, W_CPPOverload.fset_useffi), prototype = interp2app(W_CPPOverload.prototype), ) @@ -611,7 +638,7 @@ self.scope.name) w_result = W_CPPOverload.call(self, w_cppinstance, args_w) newthis = rffi.cast(capi.C_OBJECT, self.space.uint_w(w_result)) - cppinstance = self.space.interp_w(W_CPPClass, w_cppinstance, can_be_None=True) + cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True) if cppinstance is not None: cppinstance._rawobject = newthis memory_regulator.register(cppinstance) @@ -642,17 +669,18 @@ class W_CPPBoundMethod(W_Root): - _attrs_ = ['cppthis', 'method'] + _attrs_ = ['cppthis', 'method', 'useffi'] - def __init__(self, cppthis, method): + def __init__(self, cppthis, method, useffi): self.cppthis = cppthis self.method = method + self.useffi = useffi def __call__(self, args_w): - return self.method.bound_call(self.cppthis, args_w) + return self.method.bound_call(self.cppthis, args_w, self.useffi) def __repr__(self): - return "W_CPPBoundMethod(%s)" % [f.prototype() for f in self.functions] + return "W_CPPBoundMethod(%s)" % self.method.prototype() W_CPPBoundMethod.typedef = TypeDef( 'CPPBoundMethod', @@ -682,7 +710,7 @@ return offset def get(self, w_cppinstance, w_pycppclass): - cppinstance = self.space.interp_w(W_CPPClass, w_cppinstance, can_be_None=True) + cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True) if not cppinstance: raise oefmt(self.space.w_AttributeError, "attribute access requires an instance") @@ -690,7 +718,7 @@ return self.converter.from_memory(self.space, w_cppinstance, w_pycppclass, offset) def set(self, w_cppinstance, w_value): - cppinstance = self.space.interp_w(W_CPPClass, w_cppinstance, can_be_None=True) + cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True) if not cppinstance: raise oefmt(self.space.w_AttributeError, "attribute access requires an instance") @@ -845,24 +873,11 @@ return self.space.w_True def ns__dir__(self): - # Collect a list of everything (currently) available in the namespace. - # The backend can filter by returning empty strings. Special care is - # taken for functions, which need not be unique (overloading). - alldir = [] - for i in range(capi.c_num_scopes(self.space, self)): - sname = capi.c_scope_name(self.space, self, i) - if sname: alldir.append(self.space.newtext(sname)) - allmeth = {} - for i in range(capi.c_num_methods(self.space, self)): - idx = capi.c_method_index_at(self.space, self, i) - mname = capi.c_method_name(self.space, self, idx) - if mname: allmeth.setdefault(mname, 0) - for m in allmeth.keys(): - alldir.append(self.space.newtext(m)) - for i in range(capi.c_num_datamembers(self.space, self)): - dname = capi.c_datamember_name(self.space, self, i) - if dname: alldir.append(self.space.newtext(dname)) - return self.space.newlist(alldir) + alldir = capi.c_get_all_cpp_names(self.space, self) + w_alldir = self.space.newlist([]) + for name in alldir: + w_alldir.append(self.space.newtext(name)) + return w_alldir def missing_attribute_error(self, name): return oefmt(self.space.w_AttributeError, @@ -890,8 +905,7 @@ def _build_methods(self): assert len(self.methods) == 0 methods_temp = {} - for i in range(capi.c_num_methods(self.space, self)): - idx = capi.c_method_index_at(self.space, self, i) + for idx in range(capi.c_num_methods(self.space, self)): if capi.c_is_constructor(self.space, self, idx): pyname = '__init__' else: @@ -1029,7 +1043,7 @@ W_CPPComplexClassDecl.typedef.acceptable_as_base_class = False -class W_CPPClass(W_Root): +class W_CPPInstance(W_Root): _attrs_ = ['space', 'clsdecl', '_rawobject', 'flags', 'finalizer_registered'] _immutable_fields_ = ['clsdecl'] @@ -1109,8 +1123,8 @@ # find a global overload in gbl, in __gnu_cxx (for iterators), or in the # scopes of the argument classes (TODO: implement that last option) try: - # TODO: expecting w_other to be an W_CPPClass is too limiting - other = self.space.interp_w(W_CPPClass, w_other, can_be_None=False) + # TODO: expecting w_other to be an W_CPPInstance is too limiting + other = self.space.interp_w(W_CPPInstance, w_other, can_be_None=False) for name in ["", "__gnu_cxx", "__1"]: nss = scope_byname(self.space, name) meth_idx = capi.c_get_global_operator( @@ -1132,7 +1146,7 @@ # fallback 2: direct pointer comparison (the class comparison is needed since # the first data member in a struct and the struct have the same address) - other = self.space.interp_w(W_CPPClass, w_other, can_be_None=False) # TODO: factor out + other = self.space.interp_w(W_CPPInstance, w_other, can_be_None=False) # TODO: factor out iseq = (self._rawobject == other._rawobject) and (self.clsdecl == other.clsdecl) return self.space.newbool(iseq) @@ -1176,19 +1190,19 @@ if self.flags & INSTANCE_FLAGS_PYTHON_OWNS: self.destruct() -W_CPPClass.typedef = TypeDef( - 'CPPClass', - __python_owns__ = GetSetProperty(W_CPPClass.fget_python_owns, W_CPPClass.fset_python_owns), - __init__ = interp2app(W_CPPClass.instance__init__), - __eq__ = interp2app(W_CPPClass.instance__eq__), - __ne__ = interp2app(W_CPPClass.instance__ne__), - __nonzero__ = interp2app(W_CPPClass.instance__nonzero__), - __len__ = interp2app(W_CPPClass.instance__len__), - __cmp__ = interp2app(W_CPPClass.instance__cmp__), - __repr__ = interp2app(W_CPPClass.instance__repr__), - __destruct__ = interp2app(W_CPPClass.destruct), +W_CPPInstance.typedef = TypeDef( + 'CPPInstance', + __python_owns__ = GetSetProperty(W_CPPInstance.fget_python_owns, W_CPPInstance.fset_python_owns), + __init__ = interp2app(W_CPPInstance.instance__init__), + __eq__ = interp2app(W_CPPInstance.instance__eq__), + __ne__ = interp2app(W_CPPInstance.instance__ne__), + __nonzero__ = interp2app(W_CPPInstance.instance__nonzero__), + __len__ = interp2app(W_CPPInstance.instance__len__), + __cmp__ = interp2app(W_CPPInstance.instance__cmp__), + __repr__ = interp2app(W_CPPInstance.instance__repr__), + __destruct__ = interp2app(W_CPPInstance.destruct), ) -W_CPPClass.typedef.acceptable_as_base_class = True +W_CPPInstance.typedef.acceptable_as_base_class = True class MemoryRegulator: @@ -1200,7 +1214,7 @@ # Note that for now, the associated test carries an m_padding to make # a difference in the addresses. def __init__(self): - self.objects = rweakref.RWeakValueDictionary(int, W_CPPClass) + self.objects = rweakref.RWeakValueDictionary(int, W_CPPInstance) def register(self, obj): if not obj._rawobject: @@ -1266,8 +1280,8 @@ return obj # fresh creation - w_cppinstance = space.allocate_instance(W_CPPClass, w_pycppclass) - cppinstance = space.interp_w(W_CPPClass, w_cppinstance, can_be_None=False) + w_cppinstance = space.allocate_instance(W_CPPInstance, w_pycppclass) + cppinstance = space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=False) cppinstance.__init__(space, clsdecl, rawobject, is_ref, python_owns) memory_regulator.register(cppinstance) return w_cppinstance @@ -1311,7 +1325,7 @@ def move(space, w_obj): """Casts the given instance into an C++-style rvalue.""" - obj = space.interp_w(W_CPPClass, w_obj, can_be_None=True) + obj = space.interp_w(W_CPPInstance, w_obj, can_be_None=True) if obj: obj.flags |= INSTANCE_FLAGS_IS_R_VALUE return w_obj diff --git a/pypy/module/_cppyy/pythonify.py b/pypy/module/_cppyy/pythonify.py --- a/pypy/module/_cppyy/pythonify.py +++ b/pypy/module/_cppyy/pythonify.py @@ -7,7 +7,7 @@ # Metaclasses are needed to store C++ static data members as properties. Since # the interp-level does not support metaclasses, they are created at app-level. # These are the metaclass base classes: -class CPPMetaScope(type): +class CPPScope(type): def __getattr__(self, name): try: return get_scoped_pycppitem(self, name) # will cache on self @@ -15,11 +15,11 @@ raise AttributeError("%s object has no attribute '%s' (details: %s)" % (self, name, str(e))) -class CPPMetaNamespace(CPPMetaScope): +class CPPMetaNamespace(CPPScope): def __dir__(self): return self.__cppdecl__.__dir__() -class CPPMetaClass(CPPMetaScope): +class CPPClass(CPPScope): pass # namespace base class (class base class defined in _init_pythonify) @@ -173,7 +173,7 @@ # get a list of base classes for class creation bases = [get_pycppclass(base) for base in decl.get_base_names()] if not bases: - bases = [CPPClass,] + bases = [CPPInstance,] else: # it's possible that the required class now has been built if one of # the base classes uses it in e.g. a function interface @@ -214,7 +214,7 @@ # create a metaclass to allow properties (for static data write access) metabases = [type(base) for base in bases] - metacpp = type(CPPMetaScope)(cl_name+'_meta', _drop_cycles(metabases), d_meta) + metacpp = type(CPPScope)(cl_name+'_meta', _drop_cycles(metabases), d_meta) # create the python-side C++ class pycls = metacpp(cl_name, _drop_cycles(bases), d_class) @@ -412,11 +412,11 @@ # at pypy-c startup, rather than on the "import _cppyy" statement import _cppyy - # root of all proxy classes: CPPClass in pythonify exists to combine the - # CPPMetaScope metaclass with the interp-level CPPClassBase - global CPPClass - class CPPClass(_cppyy.CPPClassBase): - __metaclass__ = CPPMetaScope + # root of all proxy classes: CPPInstance in pythonify exists to combine + # the CPPScope metaclass with the interp-level CPPInstanceBase + global CPPInstance + class CPPInstance(_cppyy.CPPInstanceBase): + __metaclass__ = CPPScope pass # class generator callback @@ -438,9 +438,8 @@ gbl.std.move = _cppyy.move # install a type for enums to refer to - # TODO: this is correct for C++98, not for C++11 and in general there will - # be the same issue for all typedef'd builtin types setattr(gbl, 'internal_enum_type_t', int) + setattr(gbl, 'unsigned int', int) # if resolved # install for user access _cppyy.gbl = gbl diff --git a/pypy/module/_cppyy/src/dummy_backend.cxx b/pypy/module/_cppyy/src/dummy_backend.cxx --- a/pypy/module/_cppyy/src/dummy_backend.cxx +++ b/pypy/module/_cppyy/src/dummy_backend.cxx @@ -407,11 +407,9 @@ /* name to opaque C++ scope representation -------------------------------- */ -int cppyy_num_scopes(cppyy_scope_t handle) { - return 0; -} - char* cppyy_resolve_name(const char* cppitem_name) { + if (cppyy_is_enum(cppitem_name)) + return cppstring_to_cstring("internal_enum_type_t"); return cppstring_to_cstring(cppitem_name); } @@ -851,10 +849,13 @@ return (cppyy_object_t)result; } -cppyy_funcaddr_t cppyy_get_function_address(cppyy_scope_t /* scope */, cppyy_index_t /* idx */) { +cppyy_funcaddr_t cppyy_function_address_from_index(cppyy_scope_t /* scope */, cppyy_index_t /* idx */) { return (cppyy_funcaddr_t)0; } +cppyy_funcaddr_t cppyy_function_address_from_method(cppyy_method_t /* method */) { + return (cppyy_funcaddr_t)0; +} /* handling of function argument buffer ----------------------------------- */ void* cppyy_allocate_function_args(int nargs) { @@ -926,10 +927,6 @@ return s_scopes[handle].m_methods.size(); } -cppyy_index_t cppyy_method_index_at(cppyy_scope_t /* scope */, int imeth) { - return (cppyy_index_t)imeth; -} - char* cppyy_method_name(cppyy_scope_t handle, cppyy_index_t method_index) { return cppstring_to_cstring(s_scopes[handle].m_methods[(int)method_index].m_name); } @@ -978,8 +975,17 @@ return (cppyy_method_t)0; } +cppyy_index_t cppyy_get_global_operator(cppyy_scope_t /* scope */, + cppyy_scope_t /* lc */, cppyy_scope_t /* rc */, const char* /* op */) { + return (cppyy_index_t)-1; +} + /* method properties ----------------------------------------------------- */ +int cppyy_is_publicmethod(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) { + return 1; +} + int cppyy_is_constructor(cppyy_type_t handle, cppyy_index_t method_index) { if (s_scopes.find(handle) != s_scopes.end()) return s_scopes[handle].m_methods[method_index].m_type == kConstructor; @@ -987,6 +993,10 @@ return 0; } +int cppyy_is_destructor(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) { + return 0; +} + int cppyy_is_staticmethod(cppyy_type_t handle, cppyy_index_t method_index) { if (s_scopes.find(handle) != s_scopes.end()) return s_scopes[handle].m_methods[method_index].m_type == kStatic; @@ -1014,14 +1024,22 @@ /* data member properties ------------------------------------------------ */ -int cppyy_is_publicdata(cppyy_scope_t handle, int idatambr) { +int cppyy_is_publicdata(cppyy_scope_t /* handle */, cppyy_index_t /* idatambr */) { return 1; } -int cppyy_is_staticdata(cppyy_scope_t handle, int idatambr) { +int cppyy_is_staticdata(cppyy_scope_t handle, cppyy_index_t idatambr) { return s_scopes[handle].m_datambrs[idatambr].m_isstatic; } +int cppyy_is_const_data(cppyy_scope_t /* handle */, cppyy_index_t /* idatambr */) { + return 0; +} + +int cppyy_is_enum_data(cppyy_scope_t /* handle */, cppyy_index_t /* idatambr */) { + return 0; +} + /* misc helpers ----------------------------------------------------------- */ #if defined(_MSC_VER) diff --git a/pypy/module/_cppyy/test/Makefile b/pypy/module/_cppyy/test/Makefile --- a/pypy/module/_cppyy/test/Makefile +++ b/pypy/module/_cppyy/test/Makefile @@ -14,7 +14,7 @@ HASGENREFLEX:=$(shell command -v genreflex 2> /dev/null) -cppflags=-std=c++11 -O3 -m64 -fPIC -rdynamic +cppflags=-std=c++14 -O3 -m64 -fPIC -rdynamic ifdef HASGENREFLEX genreflex_flags:=$(shell genreflex --cppflags) cppflags+=$(genreflex_flags) diff --git a/pypy/module/_cppyy/test/advancedcpp.cxx b/pypy/module/_cppyy/test/advancedcpp.cxx --- a/pypy/module/_cppyy/test/advancedcpp.cxx +++ b/pypy/module/_cppyy/test/advancedcpp.cxx @@ -1,5 +1,7 @@ #include "advancedcpp.h" +#include <stdexcept> + // for testing of default arguments #define IMPLEMENT_DEFAULTER_CLASS(type, tname) \ @@ -112,3 +114,13 @@ std::string overload_the_other_way::gime() { return "aap"; } int overload_the_other_way::gime() const { return 1; } + + +// exception handling testing +void Thrower::throw_anything() { + throw 1; +} + +void Thrower::throw_exception() { + throw std::runtime_error("C++ function failed"); +} diff --git a/pypy/module/_cppyy/test/advancedcpp.h b/pypy/module/_cppyy/test/advancedcpp.h --- a/pypy/module/_cppyy/test/advancedcpp.h +++ b/pypy/module/_cppyy/test/advancedcpp.h @@ -59,7 +59,7 @@ class a_class { // for esoteric inheritance testing public: a_class() { m_a = 1; m_da = 1.1; } - ~a_class() {} + virtual ~a_class() {} virtual int get_value() = 0; public: @@ -221,6 +221,7 @@ //=========================================================================== class some_abstract_class { // to test abstract class handling public: + virtual ~some_abstract_class() {} virtual void a_virtual_method() = 0; }; @@ -399,3 +400,11 @@ std::string gime(); int gime() const; }; + + +//=========================================================================== +class Thrower { // exception handling testing +public: + void throw_anything(); + void throw_exception(); +}; diff --git a/pypy/module/_cppyy/test/advancedcpp.xml b/pypy/module/_cppyy/test/advancedcpp.xml --- a/pypy/module/_cppyy/test/advancedcpp.xml +++ b/pypy/module/_cppyy/test/advancedcpp.xml @@ -57,4 +57,6 @@ <class name="overload_one_way" /> <class name="overload_the_other_way" /> + <class name="Thrower" /> + </lcgdict> diff --git a/pypy/module/_cppyy/test/conftest.py b/pypy/module/_cppyy/test/conftest.py --- a/pypy/module/_cppyy/test/conftest.py +++ b/pypy/module/_cppyy/test/conftest.py @@ -55,7 +55,7 @@ separate_module_files=[srcpath.join('dummy_backend.cxx')], include_dirs=[incpath, tstpath, cdir], compile_extra=['-DRPY_EXTERN=RPY_EXPORTED', '-DCPPYY_DUMMY_BACKEND', - '-fno-strict-aliasing', '-std=c++11'], + '-fno-strict-aliasing', '-std=c++14'], use_cpp_linker=True, ) @@ -65,7 +65,7 @@ outputfilename='libcppyy_dummy_backend', standalone=False) except CompilationError as e: - if '-std=c++11' in str(e): + if '-std=c++14' in str(e): global disabled disabled = str(e) return diff --git a/pypy/module/_cppyy/test/fragile.h b/pypy/module/_cppyy/test/fragile.h --- a/pypy/module/_cppyy/test/fragile.h +++ b/pypy/module/_cppyy/test/fragile.h @@ -30,6 +30,7 @@ void overload(int, no_such_class* p = 0) {} }; + static const int dummy_location = 0xdead; class E { @@ -105,6 +106,7 @@ class M { public: + virtual ~M() {} enum E1 { kOnce=42 }; enum E2 { kTwice=12 }; }; diff --git a/pypy/module/_cppyy/test/test_advancedcpp.py b/pypy/module/_cppyy/test/test_advancedcpp.py --- a/pypy/module/_cppyy/test/test_advancedcpp.py +++ b/pypy/module/_cppyy/test/test_advancedcpp.py @@ -656,3 +656,22 @@ # TODO: currently fails b/c double** not understood as &double* #assert cppyy.gbl.my_global_ptr[0] == 1234. + def test22_exceptions(self): + """Catching of C++ exceptions""" + + import _cppyy as cppyy + Thrower = cppyy.gbl.Thrower + + # TODO: clean up this interface: + Thrower.__cppdecl__.get_overload('throw_anything').__useffi__ = False + Thrower.__cppdecl__.get_overload('throw_exception').__useffi__ = False + + t = Thrower() + + assert raises(Exception, t.throw_anything) + assert raises(Exception, t.throw_exception) + + try: + t.throw_exception() + except Exception, e: + "C++ function failed" in str(e) diff --git a/pypy/module/_cppyy/test/test_overloads.py b/pypy/module/_cppyy/test/test_overloads.py --- a/pypy/module/_cppyy/test/test_overloads.py +++ b/pypy/module/_cppyy/test/test_overloads.py @@ -15,7 +15,6 @@ spaceconfig = dict(usemodules=['_cppyy', '_rawffi', 'itertools']) def setup_class(cls): - env = os.environ cls.w_test_dct = cls.space.newtext(test_dct) cls.w_overloads = cls.space.appexec([], """(): import ctypes diff --git a/pypy/module/_cppyy/test/test_zjit.py b/pypy/module/_cppyy/test/test_zjit.py --- a/pypy/module/_cppyy/test/test_zjit.py +++ b/pypy/module/_cppyy/test/test_zjit.py @@ -137,6 +137,7 @@ executor.get_executor(self, 'int').__class__.c_stubcall = staticmethod(c_call_i) self.w_AttributeError = FakeException(self, "AttributeError") + self.w_Exception = FakeException(self, "Exception") self.w_KeyError = FakeException(self, "KeyError") self.w_NotImplementedError = FakeException(self, "NotImplementedError") self.w_ReferenceError = FakeException(self, "ReferenceError") @@ -282,7 +283,7 @@ inst = interp_cppyy._bind_object(space, FakeInt(0), cls, True) cls.get_overload("__init__").call(inst, [FakeInt(0)]) cppmethod = cls.get_overload(method_name) - assert isinstance(inst, interp_cppyy.W_CPPClass) + assert isinstance(inst, interp_cppyy.W_CPPInstance) i = 10 while i > 0: drv.jit_merge_point(inst=inst, cppmethod=cppmethod, i=i) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit