diff --git a/tools/widl/header.c b/tools/widl/header.c index fc09e63feb0..a3d225078b7 100644 --- a/tools/widl/header.c +++ b/tools/widl/header.c @@ -116,9 +116,7 @@ int is_void(const type_t *t) int is_conformant_array(const type_t *t) { - return t->type == RPC_FC_CARRAY - || t->type == RPC_FC_CVARRAY - || (t->type == RPC_FC_BOGUS_ARRAY && type_array_has_conformance(t)); + return is_array(t) && type_array_has_conformance(t); } void write_guid(FILE *f, const char *guid_prefix, const char *name, const UUID *uuid) @@ -186,7 +184,7 @@ static void write_enums(FILE *h, var_list_t *enums) int needs_space_after(type_t *t) { return (type_is_alias(t) || - (!is_ptr(t) && (!is_conformant_array(t) || t->declarray))); + (!is_ptr(t) && (!is_conformant_array(t) || t->declarray || (is_array(t) && t->name)))); } void write_type_left(FILE *h, type_t *t, int declonly) @@ -202,7 +200,11 @@ void write_type_left(FILE *h, type_t *t, int declonly) else { if (t->sign > 0) fprintf(h, "signed "); else if (t->sign < 0) fprintf(h, "unsigned "); - switch (t->type) { + + if (is_array(t) && !t->name) { + write_type_left(h, type_array_get_element(t), declonly); + fprintf(h, "%s*", needs_space_after(type_array_get_element(t)) ? " " : ""); + } else switch (t->type) { case RPC_FC_ENUM16: case RPC_FC_ENUM32: if (!declonly && t->defined && !t->written) { @@ -257,12 +259,6 @@ void write_type_left(FILE *h, type_t *t, int declonly) fprintf(h, "%s*", needs_space_after(type_pointer_get_ref(t)) ? " " : ""); if (is_attr(t->attrs, ATTR_CONST)) fprintf(h, "const "); break; - case RPC_FC_CARRAY: - case RPC_FC_CVARRAY: - case RPC_FC_BOGUS_ARRAY: - write_type_left(h, type_array_get_element(t), declonly); - fprintf(h, "%s*", needs_space_after(type_array_get_element(t)) ? " " : ""); - break; default: fprintf(h, "%s", t->name); } diff --git a/tools/widl/parser.y b/tools/widl/parser.y index 3593043df52..084b5b3d2a0 100644 --- a/tools/widl/parser.y +++ b/tools/widl/parser.y @@ -1404,9 +1404,9 @@ static void set_type(var_t *v, decl_spec_t *decl_spec, const declarator_t *decl, { expr_list_t *sizes = get_attrp(v->attrs, ATTR_SIZEIS); expr_list_t *lengs = get_attrp(v->attrs, ATTR_LENGTHIS); - int sizeless, has_varconf; + int sizeless; expr_t *dim; - type_t *atype, **ptype; + type_t **ptype; array_dims_t *arr = decl ? decl->array : NULL; type_t *func_type = decl ? decl->func_type : NULL; type_t *type = decl_spec->type; @@ -1469,6 +1469,7 @@ static void set_type(var_t *v, decl_spec_t *decl_spec, const declarator_t *decl, error_loc("'%s': [v1_enum] attribute applied to non-enum type\n", v->name); } + ptype = &v->type; sizeless = FALSE; if (arr) LIST_FOR_EACH_ENTRY_REV(dim, arr, expr_t, entry) { @@ -1477,35 +1478,46 @@ static void set_type(var_t *v, decl_spec_t *decl_spec, const declarator_t *decl, if (dim->is_const) { - v->type = make_type(RPC_FC_LGFARRAY, v->type); + if (dim->cval <= 0) + error_loc("%s: array dimension must be positive\n", v->name); + + /* FIXME: should use a type_memsize that allows us to pass in a pointer size */ + if (0) + { + unsigned int align = 0; + size_t size = type_memsize(v->type, &align); + + if (0xffffffffuL / size < (unsigned long) dim->cval) + error_loc("%s: total array size is too large\n", v->name); + } } else - { sizeless = TRUE; - v->type = make_type(RPC_FC_CARRAY, v->type); - } - v->type->declarray = TRUE; - v->type->details.array.dim = dim->cval; + *ptype = type_new_array(NULL, *ptype, TRUE, + dim->is_const ? dim->cval : 0, + dim->is_const ? NULL : dim, NULL); } ptype = &v->type; - has_varconf = FALSE; if (sizes) LIST_FOR_EACH_ENTRY(dim, sizes, expr_t, entry) { if (dim->type != EXPR_VOID) { - has_varconf = TRUE; - atype = *ptype = duptype(*ptype, 0); - - if (atype->type == RPC_FC_SMFARRAY || atype->type == RPC_FC_LGFARRAY) - error_loc("%s: cannot specify size_is for a fixed sized array\n", v->name); - - if (atype->type != RPC_FC_CARRAY && !is_ptr(atype)) + if (is_array(*ptype)) + { + if (type_array_get_conformance(*ptype)->is_const) + error_loc("%s: cannot specify size_is for a fixed sized array\n", v->name); + else + *ptype = type_new_array((*ptype)->name, + type_array_get_element(*ptype), TRUE, + 0, dim, NULL); + } + else if (is_ptr(*ptype)) + *ptype = type_new_array((*ptype)->name, type_pointer_get_ref(*ptype), FALSE, + 0, dim, NULL); + else error_loc("%s: size_is attribute applied to illegal type\n", v->name); - - atype->type = RPC_FC_CARRAY; - atype->details.array.size_is = dim; } ptype = &(*ptype)->ref; @@ -1518,19 +1530,17 @@ static void set_type(var_t *v, decl_spec_t *decl_spec, const declarator_t *decl, { if (dim->type != EXPR_VOID) { - has_varconf = TRUE; - atype = *ptype = duptype(*ptype, 0); - - if (atype->type == RPC_FC_SMFARRAY) - atype->type = RPC_FC_SMVARRAY; - else if (atype->type == RPC_FC_LGFARRAY) - atype->type = RPC_FC_LGVARRAY; - else if (atype->type == RPC_FC_CARRAY) - atype->type = RPC_FC_CVARRAY; + if (is_array(*ptype)) + { + *ptype = type_new_array((*ptype)->name, + type_array_get_element(*ptype), + (*ptype)->declarray, + type_array_get_dim(*ptype), + type_array_get_conformance(*ptype), + dim); + } else error_loc("%s: length_is attribute applied to illegal type\n", v->name); - - atype->details.array.length_is = dim; } ptype = &(*ptype)->ref; @@ -1538,16 +1548,6 @@ static void set_type(var_t *v, decl_spec_t *decl_spec, const declarator_t *decl, error_loc("%s: too many expressions in length_is attribute\n", v->name); } - if (has_varconf && !last_array(v->type)) - { - ptype = &v->type; - for (ptype = &v->type; is_array(*ptype); ptype = &(*ptype)->ref) - { - *ptype = duptype(*ptype, 0); - (*ptype)->type = RPC_FC_BOGUS_ARRAY; - } - } - /* v->type is currently pointing to the type on the left-side of the * declaration, so we need to fix this up so that it is the return type of the * function and make v->type point to the function side of the declaration */ diff --git a/tools/widl/typegen.c b/tools/widl/typegen.c index 2436f40b8c1..dfcb31e13e7 100644 --- a/tools/widl/typegen.c +++ b/tools/widl/typegen.c @@ -120,6 +120,15 @@ const char *string_of_type(unsigned char type) } } +static unsigned char get_pointer_fc(const type_t *type) +{ + assert(is_ptr(type)); + /* FIXME: see corresponding hack in set_type - we shouldn't be getting + * the pointer type from an alias, rather determining it from the + * position */ + return type->type; +} + static int get_struct_type(const type_t *type) { int has_pointer = 0; @@ -210,6 +219,10 @@ static int get_struct_type(const type_t *type) has_pointer = 1; break; + case RPC_FC_SMFARRAY: + case RPC_FC_LGFARRAY: + case RPC_FC_SMVARRAY: + case RPC_FC_LGVARRAY: case RPC_FC_CARRAY: case RPC_FC_CVARRAY: case RPC_FC_BOGUS_ARRAY: @@ -281,37 +294,70 @@ static int get_struct_type(const type_t *type) return RPC_FC_STRUCT; } -static int get_array_type(const type_t *type) +static unsigned char get_array_type(const type_t *type) { - if (is_array(type)) + unsigned char fc; + const expr_t *size_is; + const type_t *elem_type; + + if (!is_array(type)) + return type->type; + + elem_type = type_array_get_element(type); + size_is = type_array_get_conformance(type); + + if (!size_is) { - const type_t *rt = type_array_get_element(type); - if (is_user_type(rt)) - return RPC_FC_BOGUS_ARRAY; - switch (get_struct_type(rt)) + unsigned int align = 0; + size_t size = type_memsize(elem_type, &align); + if (size * type_array_get_dim(type) > 0xffffuL) + fc = RPC_FC_LGFARRAY; + else + fc = RPC_FC_SMFARRAY; + } + else + fc = RPC_FC_CARRAY; + + if (type_array_has_variance(type)) + { + if (fc == RPC_FC_SMFARRAY) + fc = RPC_FC_SMVARRAY; + else if (fc == RPC_FC_LGFARRAY) + fc = RPC_FC_LGVARRAY; + else if (fc == RPC_FC_CARRAY) + fc = RPC_FC_CVARRAY; + } + + if (is_user_type(elem_type)) + fc = RPC_FC_BOGUS_ARRAY; + else if (is_struct(elem_type->type)) + { + switch (get_struct_type(elem_type)) { case RPC_FC_BOGUS_STRUCT: - case RPC_FC_NON_ENCAPSULATED_UNION: - case RPC_FC_ENCAPSULATED_UNION: - case RPC_FC_ENUM16: - return RPC_FC_BOGUS_ARRAY; - /* FC_RP should be above, but widl overuses these, and will break things. */ - case RPC_FC_UP: - case RPC_FC_RP: - if (type_pointer_get_ref(rt)->type == RPC_FC_IP) - return RPC_FC_BOGUS_ARRAY; + fc = RPC_FC_BOGUS_ARRAY; break; } - - if (type->type == RPC_FC_LGFARRAY || type->type == RPC_FC_LGVARRAY) - { - unsigned int align = 0; - size_t size = type_memsize(type, &align); - if (size * type_array_get_dim(type) <= 0xffff) - return (type->type == RPC_FC_LGFARRAY) ? RPC_FC_SMFARRAY : RPC_FC_SMVARRAY; - } } - return type->type; + else if (elem_type->type == RPC_FC_ENUM16) + { + /* is 16-bit enum - if so, wire size differs from mem size and so + * the array cannot be block copied, which means the array is complex */ + fc = RPC_FC_BOGUS_ARRAY; + } + else if (is_union(elem_type->type)) + fc = RPC_FC_BOGUS_ARRAY; + else if (is_ptr(elem_type)) + { + /* ref pointers cannot just be block copied. unique pointers to + * interfaces need special treatment. either case means the array is + * complex */ + if (get_pointer_fc(elem_type) == RPC_FC_RP || + type_pointer_get_ref(elem_type)->type == RPC_FC_IP) + fc = RPC_FC_BOGUS_ARRAY; + } + + return fc; } int is_struct(unsigned char type) diff --git a/tools/widl/typelib.c b/tools/widl/typelib.c index d8ccd0ed151..55a2e22c4fa 100644 --- a/tools/widl/typelib.c +++ b/tools/widl/typelib.c @@ -190,8 +190,13 @@ unsigned short get_type_vt(type_t *t) case RPC_FC_UP: case RPC_FC_OP: case RPC_FC_FP: + case RPC_FC_SMFARRAY: + case RPC_FC_LGFARRAY: + case RPC_FC_SMVARRAY: + case RPC_FC_LGVARRAY: case RPC_FC_CARRAY: case RPC_FC_CVARRAY: + case RPC_FC_BOGUS_ARRAY: if(t->ref) { if (match(t->ref->name, "SAFEARRAY")) diff --git a/tools/widl/typetree.c b/tools/widl/typetree.c index d90fef1fa7e..5591ce6de21 100644 --- a/tools/widl/typetree.c +++ b/tools/widl/typetree.c @@ -78,6 +78,20 @@ type_t *type_new_module(char *name) return type; } +type_t *type_new_array(const char *name, type_t *element, int declarray, + unsigned long dim, expr_t *size_is, expr_t *length_is) +{ + type_t *t = make_type(RPC_FC_LGFARRAY, element); + if (name) t->name = xstrdup(name); + t->declarray = declarray; + t->details.array.length_is = length_is; + if (size_is) + t->details.array.size_is = size_is; + else + t->details.array.dim = dim; + return t; +} + static int compute_method_indexes(type_t *iface) { int idx; diff --git a/tools/widl/typetree.h b/tools/widl/typetree.h index 1538541197e..8efc62bd996 100644 --- a/tools/widl/typetree.h +++ b/tools/widl/typetree.h @@ -28,6 +28,8 @@ type_t *type_new_function(var_list_t *args); type_t *type_new_pointer(type_t *ref, attr_list_t *attrs); type_t *type_new_alias(type_t *t, const char *name); type_t *type_new_module(char *name); +type_t *type_new_array(const char *name, type_t *element, int declarray, + unsigned long dim, expr_t *size_is, expr_t *length_is); void type_interface_define(type_t *iface, type_t *inherit, statement_list_t *stmts); void type_dispinterface_define(type_t *iface, var_list_t *props, func_list_t *methods); void type_dispinterface_define_from_iface(type_t *dispiface, type_t *iface);