Commit 77228b52 authored by Rob Shearman's avatar Rob Shearman Committed by Alexandre Julliard

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).
parent 2b698132
......@@ -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);
}
......
......@@ -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 */
......
......@@ -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)
......
......@@ -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"))
......
......@@ -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;
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment