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:
parent
2b69813222
commit
77228b52e6
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue