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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
} }
......
...@@ -1404,9 +1404,9 @@ static void set_type(var_t *v, decl_spec_t *decl_spec, const declarator_t *decl, ...@@ -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, ...@@ -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, ...@@ -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
*ptype = type_new_array((*ptype)->name,
if (atype->type != RPC_FC_CARRAY && !is_ptr(atype)) 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, ...@@ -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, ...@@ -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 */
......
...@@ -120,6 +120,15 @@ const char *string_of_type(unsigned char type) ...@@ -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) ...@@ -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) ...@@ -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 *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); unsigned int align = 0;
if (is_user_type(rt)) size_t size = type_memsize(elem_type, &align);
return RPC_FC_BOGUS_ARRAY; if (size * type_array_get_dim(type) > 0xffffuL)
switch (get_struct_type(rt)) 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_BOGUS_STRUCT:
case RPC_FC_NON_ENCAPSULATED_UNION: fc = RPC_FC_BOGUS_ARRAY;
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; 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) int is_struct(unsigned char type)
......
...@@ -190,8 +190,13 @@ unsigned short get_type_vt(type_t *t) ...@@ -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"))
......
...@@ -78,6 +78,20 @@ type_t *type_new_module(char *name) ...@@ -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;
......
...@@ -28,6 +28,8 @@ type_t *type_new_function(var_list_t *args); ...@@ -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);
......
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