Author: Armin Rigo <ar...@tunes.org> Branch: cffi-1.0 Changeset: r1866:8218d7a07822 Date: 2015-04-27 23:48 +0200 http://bitbucket.org/cffi/cffi/changeset/8218d7a07822/
Log: Resolve the F_EXTERNAL struct names by following the ffi.include chain diff --git a/_cffi1/cffi1_module.c b/_cffi1/cffi1_module.c --- a/_cffi1/cffi1_module.c +++ b/_cffi1/cffi1_module.c @@ -114,7 +114,7 @@ if (lib == NULL || PyModule_AddObject(m, "lib", (PyObject *)lib) < 0) return -1; - if (make_included_tuples(ctx->includes, &ffi->included_ffis, + if (make_included_tuples(ctx->includes, &ffi->types_builder->included_ffis, &lib->l_includes) < 0) return -1; diff --git a/_cffi1/cffi_opcode.py b/_cffi1/cffi_opcode.py --- a/_cffi1/cffi_opcode.py +++ b/_cffi1/cffi_opcode.py @@ -100,6 +100,7 @@ F_UNION = 0x01 F_CHECK_FIELDS = 0x02 F_PACKED = 0x04 +F_EXTERNAL = 0x08 CLASS_NAME = {} for _name, _value in globals().items(): diff --git a/_cffi1/ffi_obj.c b/_cffi1/ffi_obj.c --- a/_cffi1/ffi_obj.c +++ b/_cffi1/ffi_obj.c @@ -26,7 +26,6 @@ struct _cffi_parse_info_s info; int ctx_is_static; builder_c_t *types_builder; - PyObject *included_ffis; }; static FFIObject *ffi_internal_new(PyTypeObject *ffitype, @@ -56,7 +55,6 @@ ffi->info.output = internal_output; ffi->info.output_size = FFI_COMPLEXITY_OUTPUT; ffi->ctx_is_static = (static_ctx != NULL); - ffi->included_ffis = NULL; #if 0 ffi->dynamic_types = NULL; #endif @@ -74,15 +72,14 @@ if (!ffi->ctx_is_static) free_builder_c(ffi->types_builder); - Py_XDECREF(ffi->included_ffis); Py_TYPE(ffi)->tp_free((PyObject *)ffi); } static int ffi_traverse(FFIObject *ffi, visitproc visit, void *arg) { Py_VISIT(ffi->types_builder->types_dict); + Py_VISIT(ffi->types_builder->included_ffis); Py_VISIT(ffi->gc_wrefs); - Py_VISIT(ffi->included_ffis); return 0; } @@ -809,3 +806,44 @@ ffiobj_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ }; + + +static PyObject * +_fetch_external_struct_or_union(const struct _cffi_struct_union_s *s, + PyObject *included_ffis, int recursion) +{ + if (included_ffis == NULL) + return NULL; + + if (recursion > 100) { + PyErr_SetString(PyExc_RuntimeError, + "recursion overflow in ffi.include() delegations"); + return NULL; + } + + Py_ssize_t i; + for (i = 0; i < PyTuple_GET_SIZE(included_ffis); i++) { + FFIObject *ffi1; + const struct _cffi_struct_union_s *s1; + int sindex; + PyObject *x; + + ffi1 = (FFIObject *)PyTuple_GET_ITEM(included_ffis, i); + sindex = search_in_struct_unions(&ffi1->types_builder->ctx, s->name, + strlen(s->name)); + if (sindex < 0) /* not found at all */ + continue; + s1 = &ffi1->types_builder->ctx.struct_unions[sindex]; + if ((s1->flags & (_CFFI_F_EXTERNAL | _CFFI_F_UNION)) + == (s->flags & _CFFI_F_UNION)) { + /* s1 is not external, and the same kind (struct or union) as s */ + return _realize_c_struct_or_union(ffi1->types_builder, sindex); + } + /* not found, look more recursively */ + x = _fetch_external_struct_or_union( + s, ffi1->types_builder->included_ffis, recursion + 1); + if (x != NULL || PyErr_Occurred()) + return x; /* either found, or got an error */ + } + return NULL; /* not found at all, leave without an error */ +} diff --git a/_cffi1/realize_c_type.c b/_cffi1/realize_c_type.c --- a/_cffi1/realize_c_type.c +++ b/_cffi1/realize_c_type.c @@ -2,6 +2,7 @@ typedef struct { struct _cffi_type_context_s ctx; /* inlined substructure */ PyObject *types_dict; + PyObject *included_ffis; } builder_c_t; @@ -74,6 +75,9 @@ if (mem[i] != NULL) PyMem_Free((void *)mem[i]); } + + Py_XDECREF(builder->included_ffis); + builder->included_ffis = NULL; } static void free_builder_c(builder_c_t *builder) @@ -101,6 +105,7 @@ memset(&builder->ctx, 0, sizeof(builder->ctx)); builder->types_dict = ldict; + builder->included_ffis = NULL; #if 0 builder->num_types_imported = 0; #endif @@ -268,6 +273,79 @@ } } +static PyObject * /* forward */ +_fetch_external_struct_or_union(const struct _cffi_struct_union_s *s, + PyObject *included_ffis, int recursion); + +static PyObject * +_realize_c_struct_or_union(builder_c_t *builder, int sindex) +{ + PyObject *x; + _cffi_opcode_t op2; + const struct _cffi_struct_union_s *s; + + s = &builder->ctx.struct_unions[sindex]; + op2 = builder->ctx.types[s->type_index]; + if ((((uintptr_t)op2) & 1) == 0) { + x = (PyObject *)op2; /* found already in the "primary" slot */ + Py_INCREF(x); + } + else { + CTypeDescrObject *ct = NULL; + + if (!(s->flags & _CFFI_F_EXTERNAL)) { + int flags = (s->flags & _CFFI_F_UNION) ? CT_UNION : CT_STRUCT; + char *name = alloca(8 + strlen(s->name)); + _realize_name(name, + (s->flags & _CFFI_F_UNION) ? "union " : "struct ", + s->name); + if (strcmp(name, "struct _IO_FILE") == 0) + flags |= CT_IS_FILE; + + x = new_struct_or_union_type(name, flags); + if (x == NULL) + return NULL; + + if (s->first_field_index >= 0) { + ct = (CTypeDescrObject *)x; + ct->ct_size = (Py_ssize_t)s->size; + ct->ct_length = s->alignment; + ct->ct_flags &= ~CT_IS_OPAQUE; + ct->ct_flags |= CT_LAZY_FIELD_LIST; + ct->ct_extra = builder; + } + } + else { + x = _fetch_external_struct_or_union(s, builder->included_ffis, 0); + if (x == NULL) { + if (!PyErr_Occurred()) + PyErr_Format(FFIError, "'%s %.200s' should come from " + "ffi.include() but was not found", + (s->flags & _CFFI_F_UNION) ? "union" + : "struct", s->name); + return NULL; + } + } + + /* Update the "primary" OP_STRUCT_UNION slot */ + assert((((uintptr_t)x) & 1) == 0); + assert(builder->ctx.types[s->type_index] == op2); + Py_INCREF(x); + builder->ctx.types[s->type_index] = x; + + if (ct != NULL && s->size == (size_t)-2) { + /* oops, this struct is unnamed and we couldn't generate + a C expression to get its size. We have to rely on + complete_struct_or_union() to compute it now. */ + if (do_realize_lazy_struct(ct) < 0) { + builder->ctx.types[s->type_index] = op2; + return NULL; + } + } + } + return x; +} + static PyObject * _realize_c_type_or_func(builder_c_t *builder, _cffi_opcode_t opcodes[], int index) @@ -320,62 +398,8 @@ break; case _CFFI_OP_STRUCT_UNION: - { - const struct _cffi_struct_union_s *s; - _cffi_opcode_t op2; - - s = &builder->ctx.struct_unions[_CFFI_GETARG(op)]; - op2 = builder->ctx.types[s->type_index]; - if ((((uintptr_t)op2) & 1) == 0) { - x = (PyObject *)op2; - Py_INCREF(x); - } - else { - int flags = (s->flags & _CFFI_F_UNION) ? CT_UNION : CT_STRUCT; - char *name = alloca(8 + strlen(s->name)); - _realize_name(name, - (s->flags & _CFFI_F_UNION) ? "union " : "struct ", - s->name); - if (strcmp(name, "struct _IO_FILE") == 0) - flags |= CT_IS_FILE; - - x = new_struct_or_union_type(name, flags); - - CTypeDescrObject *ct = NULL; - if (s->first_field_index >= 0) { - ct = (CTypeDescrObject *)x; - ct->ct_size = (Py_ssize_t)s->size; - ct->ct_length = s->alignment; - ct->ct_flags &= ~CT_IS_OPAQUE; - ct->ct_flags |= CT_LAZY_FIELD_LIST; - ct->ct_extra = builder; - } - - /* Update the "primary" OP_STRUCT_UNION slot, which - may be the same or a different slot than the "current" one */ - assert((((uintptr_t)x) & 1) == 0); - assert(builder->ctx.types[s->type_index] == op2); - Py_INCREF(x); - builder->ctx.types[s->type_index] = x; - - if (s->size == (size_t)-2) { - /* oops, this struct is unnamed and we couldn't generate - a C expression to get its size. We have to rely on - complete_struct_or_union() to compute it now. */ - assert(ct != NULL); - if (do_realize_lazy_struct(ct) < 0) { - builder->ctx.types[s->type_index] = op2; - return NULL; - } - } - - /* Done, leave without updating the "current" slot because - it may be done already above. If not, never mind, the - next call to realize_c_type() will do it. */ - return x; - } + x = _realize_c_struct_or_union(builder, _CFFI_GETARG(op)); break; - } case _CFFI_OP_ENUM: { @@ -530,7 +554,7 @@ return NULL; } - if (x != NULL && opcodes == builder->ctx.types) { + if (x != NULL && opcodes == builder->ctx.types && opcodes[index] != x) { assert((((uintptr_t)x) & 1) == 0); assert((((uintptr_t)opcodes[index]) & 1) == 1); Py_INCREF(x); diff --git a/_cffi1/test_recompiler.py b/_cffi1/test_recompiler.py --- a/_cffi1/test_recompiler.py +++ b/_cffi1/test_recompiler.py @@ -484,7 +484,7 @@ ffi.include(ffi1) ffi.cdef("struct foo_s *ff2(struct foo_s *);") lib = verify(ffi, "test_include_2", - "struct foo_s { int x, y; };\n" + "struct foo_s { int x, y; }; //usually from a #include\n" "struct foo_s *ff2(struct foo_s *p) { p->y++; return p; }") p = ffi.new("struct foo_s *") p.y = 41 _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit