widl: Determine the type of an array entirely at code generation time instead of at parse time.

Previously, this was done partially (for fixed array types only).
This commit is contained in:
Rob Shearman 2009-01-06 23:20:59 +00:00 committed by Alexandre Julliard
parent 2b69813222
commit 77228b52e6
6 changed files with 138 additions and 75 deletions

View File

@ -116,9 +116,7 @@ int is_void(const type_t *t)
int is_conformant_array(const type_t *t) int is_conformant_array(const type_t *t)
{ {
return t->type == RPC_FC_CARRAY return is_array(t) && type_array_has_conformance(t);
|| t->type == RPC_FC_CVARRAY
|| (t->type == RPC_FC_BOGUS_ARRAY && type_array_has_conformance(t));
} }
void write_guid(FILE *f, const char *guid_prefix, const char *name, const UUID *uuid) 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) int needs_space_after(type_t *t)
{ {
return (type_is_alias(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) 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 { else {
if (t->sign > 0) fprintf(h, "signed "); if (t->sign > 0) fprintf(h, "signed ");
else if (t->sign < 0) fprintf(h, "unsigned "); 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_ENUM16:
case RPC_FC_ENUM32: case RPC_FC_ENUM32:
if (!declonly && t->defined && !t->written) { 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)) ? " " : ""); fprintf(h, "%s*", needs_space_after(type_pointer_get_ref(t)) ? " " : "");
if (is_attr(t->attrs, ATTR_CONST)) fprintf(h, "const "); if (is_attr(t->attrs, ATTR_CONST)) fprintf(h, "const ");
break; 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: default:
fprintf(h, "%s", t->name); fprintf(h, "%s", t->name);
} }

View File

@ -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 *sizes = get_attrp(v->attrs, ATTR_SIZEIS);
expr_list_t *lengs = get_attrp(v->attrs, ATTR_LENGTHIS); expr_list_t *lengs = get_attrp(v->attrs, ATTR_LENGTHIS);
int sizeless, has_varconf; int sizeless;
expr_t *dim; expr_t *dim;
type_t *atype, **ptype; type_t **ptype;
array_dims_t *arr = decl ? decl->array : NULL; array_dims_t *arr = decl ? decl->array : NULL;
type_t *func_type = decl ? decl->func_type : NULL; type_t *func_type = decl ? decl->func_type : NULL;
type_t *type = decl_spec->type; 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); error_loc("'%s': [v1_enum] attribute applied to non-enum type\n", v->name);
} }
ptype = &v->type;
sizeless = FALSE; sizeless = FALSE;
if (arr) LIST_FOR_EACH_ENTRY_REV(dim, arr, expr_t, entry) 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) 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 else
{
sizeless = TRUE; sizeless = TRUE;
v->type = make_type(RPC_FC_CARRAY, v->type);
}
v->type->declarray = TRUE; *ptype = type_new_array(NULL, *ptype, TRUE,
v->type->details.array.dim = dim->cval; dim->is_const ? dim->cval : 0,
dim->is_const ? NULL : dim, NULL);
} }
ptype = &v->type; ptype = &v->type;
has_varconf = FALSE;
if (sizes) LIST_FOR_EACH_ENTRY(dim, sizes, expr_t, entry) if (sizes) LIST_FOR_EACH_ENTRY(dim, sizes, expr_t, entry)
{ {
if (dim->type != EXPR_VOID) if (dim->type != EXPR_VOID)
{ {
has_varconf = TRUE; if (is_array(*ptype))
atype = *ptype = duptype(*ptype, 0); {
if (type_array_get_conformance(*ptype)->is_const)
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); error_loc("%s: cannot specify size_is for a fixed sized array\n", v->name);
else
if (atype->type != RPC_FC_CARRAY && !is_ptr(atype)) *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); 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; 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) if (dim->type != EXPR_VOID)
{ {
has_varconf = TRUE; if (is_array(*ptype))
atype = *ptype = duptype(*ptype, 0); {
*ptype = type_new_array((*ptype)->name,
if (atype->type == RPC_FC_SMFARRAY) type_array_get_element(*ptype),
atype->type = RPC_FC_SMVARRAY; (*ptype)->declarray,
else if (atype->type == RPC_FC_LGFARRAY) type_array_get_dim(*ptype),
atype->type = RPC_FC_LGVARRAY; type_array_get_conformance(*ptype),
else if (atype->type == RPC_FC_CARRAY) dim);
atype->type = RPC_FC_CVARRAY; }
else else
error_loc("%s: length_is attribute applied to illegal type\n", v->name); error_loc("%s: length_is attribute applied to illegal type\n", v->name);
atype->details.array.length_is = dim;
} }
ptype = &(*ptype)->ref; 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); 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 /* 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 * 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 */ * function and make v->type point to the function side of the declaration */

View File

@ -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) static int get_struct_type(const type_t *type)
{ {
int has_pointer = 0; int has_pointer = 0;
@ -210,6 +219,10 @@ static int get_struct_type(const type_t *type)
has_pointer = 1; has_pointer = 1;
break; break;
case RPC_FC_SMFARRAY:
case RPC_FC_LGFARRAY:
case RPC_FC_SMVARRAY:
case RPC_FC_LGVARRAY:
case RPC_FC_CARRAY: case RPC_FC_CARRAY:
case RPC_FC_CVARRAY: case RPC_FC_CVARRAY:
case RPC_FC_BOGUS_ARRAY: case RPC_FC_BOGUS_ARRAY:
@ -281,37 +294,70 @@ static int get_struct_type(const type_t *type)
return RPC_FC_STRUCT; 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 *rt = type_array_get_element(type); const type_t *elem_type;
if (is_user_type(rt))
return RPC_FC_BOGUS_ARRAY;
switch (get_struct_type(rt))
{
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;
break;
}
if (type->type == RPC_FC_LGFARRAY || type->type == RPC_FC_LGVARRAY) if (!is_array(type))
return type->type;
elem_type = type_array_get_element(type);
size_is = type_array_get_conformance(type);
if (!size_is)
{ {
unsigned int align = 0; unsigned int align = 0;
size_t size = type_memsize(type, &align); size_t size = type_memsize(elem_type, &align);
if (size * type_array_get_dim(type) <= 0xffff) if (size * type_array_get_dim(type) > 0xffffuL)
return (type->type == RPC_FC_LGFARRAY) ? RPC_FC_SMFARRAY : RPC_FC_SMVARRAY; 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:
fc = RPC_FC_BOGUS_ARRAY;
break;
} }
} }
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) int is_struct(unsigned char type)

View File

@ -190,8 +190,13 @@ unsigned short get_type_vt(type_t *t)
case RPC_FC_UP: case RPC_FC_UP:
case RPC_FC_OP: case RPC_FC_OP:
case RPC_FC_FP: 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_CARRAY:
case RPC_FC_CVARRAY: case RPC_FC_CVARRAY:
case RPC_FC_BOGUS_ARRAY:
if(t->ref) if(t->ref)
{ {
if (match(t->ref->name, "SAFEARRAY")) if (match(t->ref->name, "SAFEARRAY"))

View File

@ -78,6 +78,20 @@ type_t *type_new_module(char *name)
return type; 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) static int compute_method_indexes(type_t *iface)
{ {
int idx; int idx;

View File

@ -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_pointer(type_t *ref, attr_list_t *attrs);
type_t *type_new_alias(type_t *t, const char *name); type_t *type_new_alias(type_t *t, const char *name);
type_t *type_new_module(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_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(type_t *iface, var_list_t *props, func_list_t *methods);
void type_dispinterface_define_from_iface(type_t *dispiface, type_t *iface); void type_dispinterface_define_from_iface(type_t *dispiface, type_t *iface);