summaryrefslogtreecommitdiff
path: root/c/realize_c_type.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/realize_c_type.c')
-rw-r--r--c/realize_c_type.c797
1 files changed, 797 insertions, 0 deletions
diff --git a/c/realize_c_type.c b/c/realize_c_type.c
new file mode 100644
index 0000000..082c488
--- /dev/null
+++ b/c/realize_c_type.c
@@ -0,0 +1,797 @@
+
+typedef struct {
+ struct _cffi_type_context_s ctx; /* inlined substructure */
+ PyObject *types_dict;
+ PyObject *included_ffis;
+ PyObject *included_libs;
+ PyObject *_keepalive1;
+ PyObject *_keepalive2;
+} builder_c_t;
+
+
+static PyObject *all_primitives[_CFFI__NUM_PRIM];
+static CTypeDescrObject *g_ct_voidp, *g_ct_chararray;
+
+static PyObject *build_primitive_type(int num); /* forward */
+
+#define primitive_in_range(num) ((num) >= 0 && (num) < _CFFI__NUM_PRIM)
+#define get_primitive_type(num) \
+ ((primitive_in_range(num) && all_primitives[num] != NULL) ? \
+ all_primitives[num] : build_primitive_type(num))
+
+static int init_global_types_dict(PyObject *ffi_type_dict)
+{
+ int err;
+ PyObject *ct_void, *ct_char, *ct2, *pnull;
+ /* XXX some leaks in case these functions fail, but well,
+ MemoryErrors during importing an extension module are kind
+ of bad anyway */
+
+ ct_void = get_primitive_type(_CFFI_PRIM_VOID); // 'void'
+ if (ct_void == NULL)
+ return -1;
+
+ ct2 = new_pointer_type((CTypeDescrObject *)ct_void); // 'void *'
+ if (ct2 == NULL)
+ return -1;
+ g_ct_voidp = (CTypeDescrObject *)ct2;
+
+ ct_char = get_primitive_type(_CFFI_PRIM_CHAR); // 'char'
+ if (ct_char == NULL)
+ return -1;
+
+ ct2 = new_pointer_type((CTypeDescrObject *)ct_char); // 'char *'
+ if (ct2 == NULL)
+ return -1;
+
+ ct2 = new_array_type((CTypeDescrObject *)ct2, -1); // 'char[]'
+ if (ct2 == NULL)
+ return -1;
+ g_ct_chararray = (CTypeDescrObject *)ct2;
+
+ pnull = new_simple_cdata(NULL, g_ct_voidp);
+ if (pnull == NULL)
+ return -1;
+ err = PyDict_SetItemString(ffi_type_dict, "NULL", pnull);
+ Py_DECREF(pnull);
+ return err;
+}
+
+static void free_builder_c(builder_c_t *builder, int ctx_is_static)
+{
+ if (!ctx_is_static) {
+ size_t i;
+ const void *mem[] = {builder->ctx.types,
+ builder->ctx.globals,
+ builder->ctx.struct_unions,
+ //builder->ctx.fields: allocated with struct_unions
+ builder->ctx.enums,
+ builder->ctx.typenames};
+ for (i = 0; i < sizeof(mem) / sizeof(*mem); i++) {
+ if (mem[i] != NULL)
+ PyMem_Free((void *)mem[i]);
+ }
+ }
+ Py_XDECREF(builder->included_ffis);
+ Py_XDECREF(builder->included_libs);
+ Py_XDECREF(builder->types_dict);
+ Py_XDECREF(builder->_keepalive1);
+ Py_XDECREF(builder->_keepalive2);
+}
+
+static int init_builder_c(builder_c_t *builder,
+ const struct _cffi_type_context_s *ctx)
+{
+ PyObject *ldict = PyDict_New();
+ if (ldict == NULL)
+ return -1;
+
+ if (ctx)
+ builder->ctx = *ctx;
+ else
+ memset(&builder->ctx, 0, sizeof(builder->ctx));
+
+ builder->types_dict = ldict;
+ builder->included_ffis = NULL;
+ builder->included_libs = NULL;
+ builder->_keepalive1 = NULL;
+ builder->_keepalive2 = NULL;
+ return 0;
+}
+
+static PyObject *build_primitive_type(int num)
+{
+ /* XXX too many translations between here and new_primitive_type() */
+ static const char *primitive_name[] = {
+ NULL,
+ "_Bool",
+ "char",
+ "signed char",
+ "unsigned char",
+ "short",
+ "unsigned short",
+ "int",
+ "unsigned int",
+ "long",
+ "unsigned long",
+ "long long",
+ "unsigned long long",
+ "float",
+ "double",
+ "long double",
+ "wchar_t",
+ "int8_t",
+ "uint8_t",
+ "int16_t",
+ "uint16_t",
+ "int32_t",
+ "uint32_t",
+ "int64_t",
+ "uint64_t",
+ "intptr_t",
+ "uintptr_t",
+ "ptrdiff_t",
+ "size_t",
+ "ssize_t",
+ "int_least8_t",
+ "uint_least8_t",
+ "int_least16_t",
+ "uint_least16_t",
+ "int_least32_t",
+ "uint_least32_t",
+ "int_least64_t",
+ "uint_least64_t",
+ "int_fast8_t",
+ "uint_fast8_t",
+ "int_fast16_t",
+ "uint_fast16_t",
+ "int_fast32_t",
+ "uint_fast32_t",
+ "int_fast64_t",
+ "uint_fast64_t",
+ "intmax_t",
+ "uintmax_t",
+ "float _Complex",
+ "double _Complex",
+ "char16_t",
+ "char32_t",
+ };
+ PyObject *x;
+
+ assert(sizeof(primitive_name) == sizeof(*primitive_name) * _CFFI__NUM_PRIM);
+ if (num == _CFFI_PRIM_VOID) {
+ x = new_void_type();
+ }
+ else if (primitive_in_range(num) && primitive_name[num] != NULL) {
+ x = new_primitive_type(primitive_name[num]);
+ }
+ else if (num == _CFFI__UNKNOWN_PRIM) {
+ PyErr_SetString(FFIError, "primitive integer type with an unexpected "
+ "size (or not an integer type at all)");
+ return NULL;
+ }
+ else if (num == _CFFI__UNKNOWN_FLOAT_PRIM) {
+ PyErr_SetString(FFIError, "primitive floating-point type with an "
+ "unexpected size (or not a float type at all)");
+ return NULL;
+ }
+ else if (num == _CFFI__UNKNOWN_LONG_DOUBLE) {
+ PyErr_SetString(FFIError, "primitive floating-point type is "
+ "'long double', not supported for now with "
+ "the syntax 'typedef double... xxx;'");
+ return NULL;
+ }
+ else {
+ PyErr_Format(PyExc_NotImplementedError, "prim=%d", num);
+ return NULL;
+ }
+
+ all_primitives[num] = x;
+ return x;
+}
+
+static PyObject *realize_global_int(builder_c_t *builder, int gindex)
+{
+ int neg;
+ char got[64];
+ unsigned long long value;
+ struct _cffi_getconst_s gc;
+ const struct _cffi_global_s *g = &builder->ctx.globals[gindex];
+ gc.ctx = &builder->ctx;
+ gc.gindex = gindex;
+ /* note: we cast g->address to this function type; we do the same
+ in parse_c_type:parse_sequel() too. Note that the called function
+ may be declared simply with "unsigned long long *" as argument,
+ which is fine as it is the first field in _cffi_getconst_s. */
+ assert(&gc.value == (unsigned long long *)&gc);
+ neg = ((int(*)(struct _cffi_getconst_s *))g->address)(&gc);
+ value = gc.value;
+
+ switch (neg) {
+
+ case 0:
+ if (value <= (unsigned long long)LONG_MAX)
+ return PyInt_FromLong((long)value);
+ else
+ return PyLong_FromUnsignedLongLong(value);
+
+ case 1:
+ if ((long long)value >= (long long)LONG_MIN)
+ return PyInt_FromLong((long)value);
+ else
+ return PyLong_FromLongLong((long long)value);
+
+ default:
+ break;
+ }
+ if (neg == 2)
+ sprintf(got, "%llu (0x%llx)", value, value);
+ else
+ sprintf(got, "%lld", (long long)value);
+ PyErr_Format(FFIError, "the C compiler says '%.200s' is equal to %s, "
+ "but the cdef disagrees", g->name, got);
+ return NULL;
+}
+
+static CTypeDescrObject *
+unwrap_fn_as_fnptr(PyObject *x)
+{
+ assert(PyTuple_Check(x));
+ return (CTypeDescrObject *)PyTuple_GET_ITEM(x, 0);
+}
+
+static CTypeDescrObject *
+unexpected_fn_type(PyObject *x)
+{
+ CTypeDescrObject *ct = unwrap_fn_as_fnptr(x);
+ char *text1 = ct->ct_name;
+ char *text2 = text1 + ct->ct_name_position + 1;
+ assert(text2[-3] == '(');
+ text2[-3] = '\0';
+ PyErr_Format(FFIError, "the type '%s%s' is a function type, not a "
+ "pointer-to-function type", text1, text2);
+ text2[-3] = '(';
+ return NULL;
+}
+
+static PyObject *
+realize_c_type_or_func(builder_c_t *builder,
+ _cffi_opcode_t opcodes[], int index); /* forward */
+
+
+/* Interpret an opcodes[] array. If opcodes == ctx->types, store all
+ the intermediate types back in the opcodes[]. Returns a new
+ reference.
+*/
+static CTypeDescrObject *
+realize_c_type(builder_c_t *builder, _cffi_opcode_t opcodes[], int index)
+{
+ PyObject *x = realize_c_type_or_func(builder, opcodes, index);
+ if (x == NULL || CTypeDescr_Check(x))
+ return (CTypeDescrObject *)x;
+ else {
+ unexpected_fn_type(x);
+ Py_DECREF(x);
+ return NULL;
+ }
+}
+
+static void _realize_name(char *target, const char *prefix, const char *srcname)
+{
+ /* "xyz" => "struct xyz"
+ "$xyz" => "xyz"
+ "$1" => "struct $1"
+ */
+ if (srcname[0] == '$' && srcname[1] != '$' &&
+ !('0' <= srcname[1] && srcname[1] <= '9')) {
+ strcpy(target, &srcname[1]);
+ }
+ else {
+ strcpy(target, prefix);
+ strcat(target, srcname);
+ }
+}
+
+static void _unrealize_name(char *target, const char *srcname)
+{
+ /* reverse of _realize_name() */
+ if (strncmp(srcname, "struct ", 7) == 0) {
+ strcpy(target, &srcname[7]);
+ }
+ else if (strncmp(srcname, "union ", 6) == 0) {
+ strcpy(target, &srcname[6]);
+ }
+ else if (strncmp(srcname, "enum ", 5) == 0) {
+ strcpy(target, &srcname[5]);
+ }
+ else {
+ strcpy(target, "$");
+ strcat(target, srcname);
+ }
+}
+
+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;
+
+ if (sindex == _CFFI__IO_FILE_STRUCT) {
+ /* returns a single global cached opaque type */
+ static PyObject *file_struct = NULL;
+ if (file_struct == NULL)
+ file_struct = new_struct_or_union_type("FILE",
+ CT_STRUCT | CT_IS_FILE);
+ Py_XINCREF(file_struct);
+ return file_struct;
+ }
+
+ 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)
+ x = _realize_c_struct_or_union(builder, _CFFI__IO_FILE_STRUCT);
+ else
+ x = new_struct_or_union_type(name, flags);
+ if (x == NULL)
+ return NULL;
+
+ if (!(s->flags & _CFFI_F_OPAQUE)) {
+ assert(s->first_field_index >= 0);
+ ct = (CTypeDescrObject *)x;
+ ct->ct_size = (Py_ssize_t)s->size;
+ ct->ct_length = s->alignment; /* may be -1 */
+ ct->ct_flags &= ~CT_IS_OPAQUE;
+ ct->ct_flags |= CT_LAZY_FIELD_LIST;
+ ct->ct_extra = builder;
+ }
+ else
+ assert(s->first_field_index < 0);
+ }
+ else {
+ assert(s->first_field_index < 0);
+ 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;
+ }
+ if (!(s->flags & _CFFI_F_OPAQUE)) {
+ if (((CTypeDescrObject *)x)->ct_flags & CT_IS_OPAQUE) {
+ const char *prefix = (s->flags & _CFFI_F_UNION) ? "union"
+ : "struct";
+ PyErr_Format(PyExc_NotImplementedError,
+ "'%s %.200s' is opaque in the ffi.include(), "
+ "but no longer in the ffi doing the include "
+ "(workaround: don't use ffi.include() but "
+ "duplicate the declarations of everything "
+ "using %s %.200s)",
+ prefix, s->name, prefix, s->name);
+ Py_DECREF(x);
+ 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)
+{
+ PyObject *x, *y, *z;
+ _cffi_opcode_t op = opcodes[index];
+ Py_ssize_t length = -1;
+
+ if ((((uintptr_t)op) & 1) == 0) {
+ x = (PyObject *)op;
+ Py_INCREF(x);
+ return x;
+ }
+
+ switch (_CFFI_GETOP(op)) {
+
+ case _CFFI_OP_PRIMITIVE:
+ x = get_primitive_type(_CFFI_GETARG(op));
+ Py_XINCREF(x);
+ break;
+
+ case _CFFI_OP_POINTER:
+ y = realize_c_type_or_func(builder, opcodes, _CFFI_GETARG(op));
+ if (y == NULL)
+ return NULL;
+ if (CTypeDescr_Check(y)) {
+ x = new_pointer_type((CTypeDescrObject *)y);
+ }
+ else {
+ assert(PyTuple_Check(y)); /* from _CFFI_OP_FUNCTION */
+ x = PyTuple_GET_ITEM(y, 0);
+ Py_INCREF(x);
+ }
+ Py_DECREF(y);
+ break;
+
+ case _CFFI_OP_ARRAY:
+ length = (Py_ssize_t)opcodes[index + 1];
+ /* fall-through */
+ case _CFFI_OP_OPEN_ARRAY:
+ y = (PyObject *)realize_c_type(builder, opcodes, _CFFI_GETARG(op));
+ if (y == NULL)
+ return NULL;
+ z = new_pointer_type((CTypeDescrObject *)y);
+ Py_DECREF(y);
+ if (z == NULL)
+ return NULL;
+ x = new_array_type((CTypeDescrObject *)z, length);
+ Py_DECREF(z);
+ break;
+
+ case _CFFI_OP_STRUCT_UNION:
+ x = _realize_c_struct_or_union(builder, _CFFI_GETARG(op));
+ break;
+
+ case _CFFI_OP_ENUM:
+ {
+ const struct _cffi_enum_s *e;
+ _cffi_opcode_t op2;
+
+ e = &builder->ctx.enums[_CFFI_GETARG(op)];
+ op2 = builder->ctx.types[e->type_index];
+ if ((((uintptr_t)op2) & 1) == 0) {
+ x = (PyObject *)op2;
+ Py_INCREF(x);
+ }
+ else {
+ PyObject *enumerators = NULL, *enumvalues = NULL, *tmp;
+ Py_ssize_t i, j, n = 0;
+ const char *p;
+ int gindex;
+ PyObject *args;
+ PyObject *basetd = get_primitive_type(e->type_prim);
+ if (basetd == NULL)
+ return NULL;
+
+ if (*e->enumerators != '\0') {
+ n++;
+ for (p = e->enumerators; *p != '\0'; p++)
+ n += (*p == ',');
+ }
+ enumerators = PyTuple_New(n);
+ if (enumerators == NULL)
+ return NULL;
+
+ enumvalues = PyTuple_New(n);
+ if (enumvalues == NULL) {
+ Py_DECREF(enumerators);
+ return NULL;
+ }
+
+ p = e->enumerators;
+ for (i = 0; i < n; i++) {
+ j = 0;
+ while (p[j] != ',' && p[j] != '\0')
+ j++;
+ tmp = PyText_FromStringAndSize(p, j);
+ if (tmp == NULL)
+ break;
+ PyTuple_SET_ITEM(enumerators, i, tmp);
+
+ gindex = search_in_globals(&builder->ctx, p, j);
+ assert(gindex >= 0);
+ assert(builder->ctx.globals[gindex].type_op ==
+ _CFFI_OP(_CFFI_OP_ENUM, -1));
+
+ tmp = realize_global_int(builder, gindex);
+ if (tmp == NULL)
+ break;
+ PyTuple_SET_ITEM(enumvalues, i, tmp);
+
+ p += j + 1;
+ }
+
+ args = NULL;
+ if (!PyErr_Occurred()) {
+ char *name = alloca(6 + strlen(e->name));
+ _realize_name(name, "enum ", e->name);
+ args = Py_BuildValue("(sOOO)", name, enumerators,
+ enumvalues, basetd);
+ }
+ Py_DECREF(enumerators);
+ Py_DECREF(enumvalues);
+ if (args == NULL)
+ return NULL;
+
+ x = b_new_enum_type(NULL, args);
+ Py_DECREF(args);
+ if (x == NULL)
+ return NULL;
+
+ /* Update the "primary" _CFFI_OP_ENUM slot, which
+ may be the same or a different slot than the "current" one */
+ assert((((uintptr_t)x) & 1) == 0);
+ assert(builder->ctx.types[e->type_index] == op2);
+ Py_INCREF(x);
+ builder->ctx.types[e->type_index] = x;
+
+ /* 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;
+ }
+ break;
+ }
+
+ case _CFFI_OP_FUNCTION:
+ {
+ PyObject *fargs;
+ int i, base_index, num_args, ellipsis, abi;
+
+ y = (PyObject *)realize_c_type(builder, opcodes, _CFFI_GETARG(op));
+ if (y == NULL)
+ return NULL;
+
+ base_index = index + 1;
+ num_args = 0;
+ /* note that if the arguments are already built, they have a
+ pointer in the 'opcodes' array, and GETOP() returns a
+ random even value. But OP_FUNCTION_END is odd, so the
+ condition below still works correctly. */
+ while (_CFFI_GETOP(opcodes[base_index + num_args]) !=
+ _CFFI_OP_FUNCTION_END)
+ num_args++;
+
+ ellipsis = _CFFI_GETARG(opcodes[base_index + num_args]) & 0x01;
+ abi = _CFFI_GETARG(opcodes[base_index + num_args]) & 0xFE;
+ switch (abi) {
+ case 0:
+ abi = FFI_DEFAULT_ABI;
+ break;
+ case 2:
+#if defined(MS_WIN32) && !defined(_WIN64)
+ abi = FFI_STDCALL;
+#else
+ abi = FFI_DEFAULT_ABI;
+#endif
+ break;
+ default:
+ PyErr_Format(FFIError, "abi number %d not supported", abi);
+ Py_DECREF(y);
+ return NULL;
+ }
+
+ fargs = PyTuple_New(num_args);
+ if (fargs == NULL) {
+ Py_DECREF(y);
+ return NULL;
+ }
+
+ for (i = 0; i < num_args; i++) {
+ z = (PyObject *)realize_c_type(builder, opcodes, base_index + i);
+ if (z == NULL) {
+ Py_DECREF(fargs);
+ Py_DECREF(y);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(fargs, i, z);
+ }
+
+ z = new_function_type(fargs, (CTypeDescrObject *)y, ellipsis, abi);
+ Py_DECREF(fargs);
+ Py_DECREF(y);
+ if (z == NULL)
+ return NULL;
+
+ x = PyTuple_Pack(1, z); /* hack: hide the CT_FUNCTIONPTR. it will
+ be revealed again by the OP_POINTER */
+ Py_DECREF(z);
+ break;
+ }
+
+ case _CFFI_OP_NOOP:
+ x = realize_c_type_or_func(builder, opcodes, _CFFI_GETARG(op));
+ break;
+
+ case _CFFI_OP_TYPENAME:
+ {
+ /* essential: the TYPENAME opcode resolves the type index looked
+ up in the 'ctx->typenames' array, but it does so in 'ctx->types'
+ instead of in 'opcodes'! */
+ int type_index = builder->ctx.typenames[_CFFI_GETARG(op)].type_index;
+ x = realize_c_type_or_func(builder, builder->ctx.types, type_index);
+ break;
+ }
+
+ default:
+ PyErr_Format(PyExc_NotImplementedError, "op=%d", (int)_CFFI_GETOP(op));
+ return NULL;
+ }
+
+ 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);
+ opcodes[index] = x;
+ }
+ return x;
+};
+
+static CTypeDescrObject *
+realize_c_func_return_type(builder_c_t *builder,
+ _cffi_opcode_t opcodes[], int index)
+{
+ PyObject *x;
+ _cffi_opcode_t op = opcodes[index];
+
+ if ((((uintptr_t)op) & 1) == 0) {
+ /* already built: assert that it is a function and fish
+ for the return type */
+ x = (PyObject *)op;
+ assert(PyTuple_Check(x)); /* from _CFFI_OP_FUNCTION */
+ x = PyTuple_GET_ITEM(x, 0);
+ assert(CTypeDescr_Check(x));
+ assert(((CTypeDescrObject *)x)->ct_flags & CT_FUNCTIONPTR);
+ x = PyTuple_GET_ITEM(((CTypeDescrObject *)x)->ct_stuff, 1);
+ assert(CTypeDescr_Check(x));
+ Py_INCREF(x);
+ return (CTypeDescrObject *)x;
+ }
+ else {
+ assert(_CFFI_GETOP(op) == _CFFI_OP_FUNCTION);
+ return realize_c_type(builder, opcodes, _CFFI_GETARG(opcodes[index]));
+ }
+}
+
+static int do_realize_lazy_struct(CTypeDescrObject *ct)
+{
+ /* This is called by force_lazy_struct() in _cffi_backend.c */
+ assert(ct->ct_flags & (CT_STRUCT | CT_UNION));
+
+ if (ct->ct_flags & CT_LAZY_FIELD_LIST) {
+ builder_c_t *builder;
+ char *p;
+ int n, i, sflags;
+ const struct _cffi_struct_union_s *s;
+ const struct _cffi_field_s *fld;
+ PyObject *fields, *args, *res;
+
+ assert(!(ct->ct_flags & CT_IS_OPAQUE));
+
+ builder = ct->ct_extra;
+ assert(builder != NULL);
+
+ p = alloca(2 + strlen(ct->ct_name));
+ _unrealize_name(p, ct->ct_name);
+
+ n = search_in_struct_unions(&builder->ctx, p, strlen(p));
+ if (n < 0)
+ Py_FatalError("lost a struct/union!");
+
+ s = &builder->ctx.struct_unions[n];
+ fld = &builder->ctx.fields[s->first_field_index];
+
+ /* XXX painfully build all the Python objects that are the args
+ to b_complete_struct_or_union() */
+
+ fields = PyList_New(s->num_fields);
+ if (fields == NULL)
+ return -1;
+
+ for (i = 0; i < s->num_fields; i++, fld++) {
+ _cffi_opcode_t op = fld->field_type_op;
+ int fbitsize = -1;
+ PyObject *f;
+ CTypeDescrObject *ctf;
+
+ switch (_CFFI_GETOP(op)) {
+
+ case _CFFI_OP_BITFIELD:
+ assert(fld->field_size >= 0);
+ fbitsize = (int)fld->field_size;
+ /* fall-through */
+ case _CFFI_OP_NOOP:
+ ctf = realize_c_type(builder, builder->ctx.types,
+ _CFFI_GETARG(op));
+ break;
+
+ default:
+ Py_DECREF(fields);
+ PyErr_Format(PyExc_NotImplementedError, "field op=%d",
+ (int)_CFFI_GETOP(op));
+ return -1;
+ }
+
+ if (ctf != NULL && fld->field_offset == (size_t)-1) {
+ /* unnamed struct, with field positions and sizes entirely
+ determined by complete_struct_or_union() and not checked.
+ Or, bitfields (field_size >= 0), similarly not checked. */
+ assert(fld->field_size == (size_t)-1 || fbitsize >= 0);
+ }
+ else if (ctf == NULL || detect_custom_layout(ct, SF_STD_FIELD_POS,
+ ctf->ct_size, fld->field_size,
+ "wrong size for field '",
+ fld->name, "'") < 0) {
+ Py_DECREF(fields);
+ return -1;
+ }
+
+ f = Py_BuildValue("(sOin)", fld->name, ctf,
+ fbitsize, (Py_ssize_t)fld->field_offset);
+ if (f == NULL) {
+ Py_DECREF(fields);
+ return -1;
+ }
+ PyList_SET_ITEM(fields, i, f);
+ }
+
+ sflags = 0;
+ if (s->flags & _CFFI_F_CHECK_FIELDS)
+ sflags |= SF_STD_FIELD_POS;
+ if (s->flags & _CFFI_F_PACKED)
+ sflags |= SF_PACKED;
+
+ args = Py_BuildValue("(OOOnii)", ct, fields, Py_None,
+ (Py_ssize_t)s->size,
+ s->alignment,
+ sflags);
+ Py_DECREF(fields);
+ if (args == NULL)
+ return -1;
+
+ ct->ct_extra = NULL;
+ ct->ct_flags |= CT_IS_OPAQUE;
+ res = b_complete_struct_or_union(NULL, args);
+ ct->ct_flags &= ~CT_IS_OPAQUE;
+ Py_DECREF(args);
+
+ if (res == NULL) {
+ ct->ct_extra = builder;
+ return -1;
+ }
+
+ assert(ct->ct_stuff != NULL);
+ ct->ct_flags &= ~CT_LAZY_FIELD_LIST;
+ Py_DECREF(res);
+ return 1;
+ }
+ else {
+ assert(ct->ct_flags & CT_IS_OPAQUE);
+ return 0;
+ }
+}