widl: Move determination of the exact type of structures and array to the code generation phase.

The exact type can depend on the size of the type in memory, and that
can vary depending on whether we are generating 32-bit or 64-bit code.
This commit is contained in:
Alexandre Julliard 2008-12-26 16:26:59 +01:00
parent e9e12744b5
commit a011f0cd5b
2 changed files with 225 additions and 224 deletions

View File

@ -132,7 +132,6 @@ static type_t *find_type_or_error(const char *name, int t);
static type_t *find_type_or_error2(char *name, int t);
static type_t *get_type(unsigned char type, char *name, int t);
static type_t *get_typev(unsigned char type, var_t *name, int t);
static int get_struct_type(var_list_t *fields);
static var_t *reg_const(var_t *var);
@ -1061,9 +1060,7 @@ pointer_type:
;
structdef: tSTRUCT t_ident '{' fields '}' { $$ = get_typev(RPC_FC_STRUCT, $2, tsSTRUCT);
/* overwrite RPC_FC_STRUCT with a more exact type */
check_def($$);
$$->type = get_struct_type( $4 );
$$->kind = TKIND_RECORD;
$$->fields_or_args = $4;
$$->defined = TRUE;
@ -1502,18 +1499,7 @@ static void set_type(var_t *v, decl_spec_t *decl_spec, const declarator_t *decl,
if (dim->is_const)
{
unsigned int align = 0;
size_t size = type_memsize(v->type, &align);
if (dim->cval <= 0)
error_loc("%s: array dimension must be positive\n", v->name);
if (0xffffffffuL / size < (unsigned long) dim->cval)
error_loc("%s: total array size is too large\n", v->name);
else if (0xffffuL < size * dim->cval)
v->type = make_type(RPC_FC_LGFARRAY, v->type);
else
v->type = make_type(RPC_FC_SMFARRAY, v->type);
v->type = make_type(RPC_FC_LGFARRAY, v->type);
}
else
{
@ -1584,29 +1570,6 @@ static void set_type(var_t *v, decl_spec_t *decl_spec, const declarator_t *decl,
}
}
if (is_array(v->type))
{
const type_t *rt = v->type->ref;
if (is_user_type(rt))
v->type->type = RPC_FC_BOGUS_ARRAY;
else
switch (rt->type)
{
case RPC_FC_BOGUS_STRUCT:
case RPC_FC_NON_ENCAPSULATED_UNION:
case RPC_FC_ENCAPSULATED_UNION:
case RPC_FC_ENUM16:
v->type->type = RPC_FC_BOGUS_ARRAY;
break;
/* FC_RP should be above, but widl overuses these, and will break things. */
case RPC_FC_UP:
case RPC_FC_RP:
if (rt->ref->type == RPC_FC_IP)
v->type->type = RPC_FC_BOGUS_ARRAY;
break;
}
}
/* 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 */
@ -1975,163 +1938,6 @@ static type_t *get_typev(unsigned char type, var_t *name, int t)
return get_type(type, sname, t);
}
static int get_struct_type(var_list_t *fields)
{
int has_pointer = 0;
int has_conformance = 0;
int has_variance = 0;
var_t *field;
if (get_padding(fields))
return RPC_FC_BOGUS_STRUCT;
if (fields) LIST_FOR_EACH_ENTRY( field, fields, var_t, entry )
{
type_t *t = field->type;
if (is_user_type(t))
return RPC_FC_BOGUS_STRUCT;
if (is_ptr(t))
{
do
t = t->ref;
while (is_ptr(t));
switch (t->type)
{
case RPC_FC_IP:
case RPC_FC_ENCAPSULATED_UNION:
case RPC_FC_NON_ENCAPSULATED_UNION:
case RPC_FC_BOGUS_STRUCT:
return RPC_FC_BOGUS_STRUCT;
}
has_pointer = 1;
continue;
}
if (field->type->declarray)
{
if (is_string_type(field->attrs, field->type))
{
if (is_conformant_array(field->type))
has_conformance = 1;
has_variance = 1;
continue;
}
if (is_array(field->type->ref))
return RPC_FC_BOGUS_STRUCT;
if (is_conformant_array(field->type))
{
has_conformance = 1;
if (field->type->declarray && list_next(fields, &field->entry))
error_loc("field '%s' deriving from a conformant array must be the last field in the structure\n",
field->name);
}
if (field->type->length_is)
has_variance = 1;
t = field->type->ref;
}
switch (t->type)
{
/*
* RPC_FC_BYTE, RPC_FC_STRUCT, etc
* Simple types don't effect the type of struct.
* A struct containing a simple struct is still a simple struct.
* So long as we can block copy the data, we return RPC_FC_STRUCT.
*/
case 0: /* void pointer */
case RPC_FC_BYTE:
case RPC_FC_CHAR:
case RPC_FC_SMALL:
case RPC_FC_USMALL:
case RPC_FC_WCHAR:
case RPC_FC_SHORT:
case RPC_FC_USHORT:
case RPC_FC_LONG:
case RPC_FC_ULONG:
case RPC_FC_INT3264:
case RPC_FC_UINT3264:
case RPC_FC_HYPER:
case RPC_FC_FLOAT:
case RPC_FC_DOUBLE:
case RPC_FC_STRUCT:
case RPC_FC_ENUM32:
break;
case RPC_FC_RP:
case RPC_FC_UP:
case RPC_FC_FP:
case RPC_FC_OP:
case RPC_FC_CARRAY:
case RPC_FC_CVARRAY:
case RPC_FC_BOGUS_ARRAY:
has_pointer = 1;
break;
/*
* Propagate member attributes
* a struct should be at least as complex as its member
*/
case RPC_FC_CVSTRUCT:
has_conformance = 1;
has_variance = 1;
has_pointer = 1;
break;
case RPC_FC_CPSTRUCT:
has_conformance = 1;
if (list_next( fields, &field->entry ))
error_loc("field '%s' deriving from a conformant array must be the last field in the structure\n",
field->name);
has_pointer = 1;
break;
case RPC_FC_CSTRUCT:
has_conformance = 1;
if (list_next( fields, &field->entry ))
error_loc("field '%s' deriving from a conformant array must be the last field in the structure\n",
field->name);
break;
case RPC_FC_PSTRUCT:
has_pointer = 1;
break;
default:
error_loc("Unknown struct member %s with type (0x%02x)\n", field->name, t->type);
/* fallthru - treat it as complex */
/* as soon as we see one of these these members, it's bogus... */
case RPC_FC_ENCAPSULATED_UNION:
case RPC_FC_NON_ENCAPSULATED_UNION:
case RPC_FC_BOGUS_STRUCT:
case RPC_FC_ENUM16:
return RPC_FC_BOGUS_STRUCT;
}
}
if( has_variance )
{
if ( has_conformance )
return RPC_FC_CVSTRUCT;
else
return RPC_FC_BOGUS_STRUCT;
}
if( has_conformance && has_pointer )
return RPC_FC_CPSTRUCT;
if( has_conformance )
return RPC_FC_CSTRUCT;
if( has_pointer )
return RPC_FC_PSTRUCT;
return RPC_FC_STRUCT;
}
/***** constant repository *****/
struct rconst {

View File

@ -120,6 +120,197 @@ const char *string_of_type(unsigned char type)
}
}
static int get_struct_type(const type_t *type)
{
int has_pointer = 0;
int has_conformance = 0;
int has_variance = 0;
var_t *field;
if (type->type != RPC_FC_STRUCT) return type->type;
if (get_padding(type->fields_or_args))
return RPC_FC_BOGUS_STRUCT;
if (type->fields_or_args) LIST_FOR_EACH_ENTRY( field, type->fields_or_args, var_t, entry )
{
type_t *t = field->type;
if (is_user_type(t))
return RPC_FC_BOGUS_STRUCT;
if (is_ptr(t))
{
do
t = t->ref;
while (is_ptr(t));
switch (get_struct_type(t))
{
case RPC_FC_IP:
case RPC_FC_ENCAPSULATED_UNION:
case RPC_FC_NON_ENCAPSULATED_UNION:
case RPC_FC_BOGUS_STRUCT:
return RPC_FC_BOGUS_STRUCT;
}
has_pointer = 1;
continue;
}
if (field->type->declarray)
{
if (is_string_type(field->attrs, field->type))
{
if (is_conformant_array(field->type))
has_conformance = 1;
has_variance = 1;
continue;
}
if (is_array(field->type->ref))
return RPC_FC_BOGUS_STRUCT;
if (is_conformant_array(field->type))
{
has_conformance = 1;
if (field->type->declarray && list_next(type->fields_or_args, &field->entry))
error_loc("field '%s' deriving from a conformant array must be the last field in the structure\n",
field->name);
}
if (field->type->length_is)
has_variance = 1;
t = field->type->ref;
}
switch (get_struct_type(t))
{
/*
* RPC_FC_BYTE, RPC_FC_STRUCT, etc
* Simple types don't effect the type of struct.
* A struct containing a simple struct is still a simple struct.
* So long as we can block copy the data, we return RPC_FC_STRUCT.
*/
case 0: /* void pointer */
case RPC_FC_BYTE:
case RPC_FC_CHAR:
case RPC_FC_SMALL:
case RPC_FC_USMALL:
case RPC_FC_WCHAR:
case RPC_FC_SHORT:
case RPC_FC_USHORT:
case RPC_FC_LONG:
case RPC_FC_ULONG:
case RPC_FC_INT3264:
case RPC_FC_UINT3264:
case RPC_FC_HYPER:
case RPC_FC_FLOAT:
case RPC_FC_DOUBLE:
case RPC_FC_STRUCT:
case RPC_FC_ENUM32:
break;
case RPC_FC_RP:
case RPC_FC_UP:
case RPC_FC_FP:
case RPC_FC_OP:
case RPC_FC_CARRAY:
case RPC_FC_CVARRAY:
case RPC_FC_BOGUS_ARRAY:
has_pointer = 1;
break;
/*
* Propagate member attributes
* a struct should be at least as complex as its member
*/
case RPC_FC_CVSTRUCT:
has_conformance = 1;
has_variance = 1;
has_pointer = 1;
break;
case RPC_FC_CPSTRUCT:
has_conformance = 1;
if (list_next( type->fields_or_args, &field->entry ))
error_loc("field '%s' deriving from a conformant array must be the last field in the structure\n",
field->name);
has_pointer = 1;
break;
case RPC_FC_CSTRUCT:
has_conformance = 1;
if (list_next( type->fields_or_args, &field->entry ))
error_loc("field '%s' deriving from a conformant array must be the last field in the structure\n",
field->name);
break;
case RPC_FC_PSTRUCT:
has_pointer = 1;
break;
default:
error_loc("Unknown struct member %s with type (0x%02x)\n", field->name, t->type);
/* fallthru - treat it as complex */
/* as soon as we see one of these these members, it's bogus... */
case RPC_FC_ENCAPSULATED_UNION:
case RPC_FC_NON_ENCAPSULATED_UNION:
case RPC_FC_BOGUS_STRUCT:
case RPC_FC_ENUM16:
return RPC_FC_BOGUS_STRUCT;
}
}
if( has_variance )
{
if ( has_conformance )
return RPC_FC_CVSTRUCT;
else
return RPC_FC_BOGUS_STRUCT;
}
if( has_conformance && has_pointer )
return RPC_FC_CPSTRUCT;
if( has_conformance )
return RPC_FC_CSTRUCT;
if( has_pointer )
return RPC_FC_PSTRUCT;
return RPC_FC_STRUCT;
}
static int get_array_type(const type_t *type)
{
if (is_array(type))
{
const type_t *rt = type->ref;
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 (rt->ref->type == RPC_FC_IP) return 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->dim <= 0xffff)
return (type->type == RPC_FC_LGFARRAY) ? RPC_FC_SMFARRAY : RPC_FC_SMVARRAY;
}
}
return type->type;
}
int is_struct(unsigned char type)
{
switch (type)
@ -138,7 +329,7 @@ int is_struct(unsigned char type)
static int is_non_complex_struct(const type_t *type)
{
switch (type->type)
switch (get_struct_type(type))
{
case RPC_FC_STRUCT:
case RPC_FC_PSTRUCT:
@ -971,7 +1162,7 @@ static int user_type_has_variable_size(const type_t *t)
if (is_ptr(t))
return TRUE;
else
switch (t->type)
switch (get_struct_type(t))
{
case RPC_FC_PSTRUCT:
case RPC_FC_CSTRUCT:
@ -1063,7 +1254,7 @@ static void write_member_type(FILE *file, const type_t *cont,
}
else if (is_ptr(type) || is_conformant_array(type))
{
unsigned char fc = (cont->type == RPC_FC_BOGUS_STRUCT
unsigned char fc = (get_struct_type(cont) == RPC_FC_BOGUS_STRUCT
? RPC_FC_POINTER
: RPC_FC_LONG);
print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
@ -1284,8 +1475,9 @@ static int write_fixed_array_pointer_descriptions(
{
unsigned int align;
int pointer_count = 0;
int real_type = get_array_type( type );
if (type->type == RPC_FC_SMFARRAY || type->type == RPC_FC_LGFARRAY)
if (real_type == RPC_FC_SMFARRAY || real_type == RPC_FC_LGFARRAY)
{
unsigned int temp = 0;
/* unfortunately, this needs to be done in two passes to avoid
@ -1506,7 +1698,7 @@ static void write_pointer_description(FILE *file, type_t *type,
if ((!type->declarray || !current_structure) && is_conformant_array(type))
write_conformant_array_pointer_descriptions(
file, NULL, type, 0, typestring_offset);
else if (type->type == RPC_FC_CPSTRUCT)
else if (get_struct_type(type) == RPC_FC_CPSTRUCT)
{
unsigned int align = 0;
type_t *carray = find_array_or_string_in_struct(type)->type;
@ -1625,6 +1817,7 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type
unsigned int align = 0;
size_t size;
size_t start_offset;
int real_type;
int has_pointer;
int pointer_type = get_attrv(attrs, ATTR_POINTERTYPE);
unsigned int baseoff
@ -1642,20 +1835,19 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type
align = 0;
size = type_memsize((is_conformant_array(type) ? type->ref : type), &align);
real_type = get_array_type( type );
start_offset = *typestring_offset;
update_tfsoff(type, start_offset, file);
print_start_tfs_comment(file, type, start_offset);
print_file(file, 2, "0x%02x,\t/* %s */\n", type->type, string_of_type(type->type));
print_file(file, 2, "0x%02x,\t/* %s */\n", real_type, string_of_type(real_type));
print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
*typestring_offset += 2;
align = 0;
if (type->type != RPC_FC_BOGUS_ARRAY)
if (real_type != RPC_FC_BOGUS_ARRAY)
{
unsigned char tc = type->type;
if (tc == RPC_FC_LGFARRAY || tc == RPC_FC_LGVARRAY)
if (real_type == RPC_FC_LGFARRAY || real_type == RPC_FC_LGVARRAY)
{
print_file(file, 2, "NdrFcLong(0x%x),\t/* %lu */\n", size, size);
*typestring_offset += 4;
@ -1671,12 +1863,12 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type
+= write_conf_or_var_desc(file, current_structure, baseoff,
type, size_is);
if (type->type == RPC_FC_SMVARRAY || type->type == RPC_FC_LGVARRAY)
if (real_type == RPC_FC_SMVARRAY || real_type == RPC_FC_LGVARRAY)
{
unsigned int elalign = 0;
size_t elsize = type_memsize(type->ref, &elalign);
if (type->type == RPC_FC_LGVARRAY)
if (real_type == RPC_FC_LGVARRAY)
{
print_file(file, 2, "NdrFcLong(0x%x),\t/* %lu */\n", type->dim, type->dim);
*typestring_offset += 4;
@ -1731,6 +1923,7 @@ static const var_t *find_array_or_string_in_struct(const type_t *type)
{
const var_t *last_field;
const type_t *ft;
int real_type;
if (!type->fields_or_args || list_empty(type->fields_or_args))
return NULL;
@ -1741,7 +1934,8 @@ static const var_t *find_array_or_string_in_struct(const type_t *type)
if (ft->declarray && is_conformant_array(ft))
return last_field;
if (ft->type == RPC_FC_CSTRUCT || ft->type == RPC_FC_CPSTRUCT || ft->type == RPC_FC_CVSTRUCT)
real_type = get_struct_type( type );
if (real_type == RPC_FC_CSTRUCT || real_type == RPC_FC_CPSTRUCT || real_type == RPC_FC_CVSTRUCT)
return find_array_or_string_in_struct(ft);
else
return NULL;
@ -1812,6 +2006,7 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
unsigned int align = 0;
unsigned int corroff;
var_t *f;
int real_type = get_struct_type( type );
guard_rec(type);
current_structure = type;
@ -1839,7 +2034,7 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
start_offset = *tfsoff;
update_tfsoff(type, start_offset, file);
print_start_tfs_comment(file, type, start_offset);
print_file(file, 2, "0x%x,\t/* %s */\n", type->type, string_of_type(type->type));
print_file(file, 2, "0x%x,\t/* %s */\n", real_type, string_of_type(real_type));
print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", total_size, total_size);
*tfsoff += 4;
@ -1852,13 +2047,13 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
reloff, reloff, absoff);
*tfsoff += 2;
}
else if (type->type == RPC_FC_BOGUS_STRUCT)
else if (real_type == RPC_FC_BOGUS_STRUCT)
{
print_file(file, 2, "NdrFcShort(0x0),\n");
*tfsoff += 2;
}
if (type->type == RPC_FC_BOGUS_STRUCT)
if (real_type == RPC_FC_BOGUS_STRUCT)
{
/* On the sizing pass, type->ptrdesc may be zero, but it's ok as
nothing is written to file yet. On the actual writing pass,
@ -1870,9 +2065,9 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
reloff, reloff, absoff);
*tfsoff += 2;
}
else if ((type->type == RPC_FC_PSTRUCT) ||
(type->type == RPC_FC_CPSTRUCT) ||
(type->type == RPC_FC_CVSTRUCT && has_pointers))
else if ((real_type == RPC_FC_PSTRUCT) ||
(real_type == RPC_FC_CPSTRUCT) ||
(real_type == RPC_FC_CVSTRUCT && has_pointers))
{
print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
@ -1884,7 +2079,7 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
write_struct_members(file, type, &corroff, tfsoff);
if (type->type == RPC_FC_BOGUS_STRUCT)
if (real_type == RPC_FC_BOGUS_STRUCT)
{
const var_list_t *fs = type->fields_or_args;
const var_t *f;
@ -2474,7 +2669,7 @@ static unsigned int get_required_buffer_size_type(
}
else
{
switch (type->type)
switch (get_struct_type(type))
{
case RPC_FC_BYTE:
case RPC_FC_CHAR:
@ -2513,7 +2708,7 @@ static unsigned int get_required_buffer_size_type(
case RPC_FC_RP:
return
is_base_type( type->ref->type ) || type->ref->type == RPC_FC_STRUCT
is_base_type( type->ref->type ) || get_struct_type(type->ref) == RPC_FC_STRUCT
? get_required_buffer_size_type( type->ref, name, alignment )
: 0;
@ -2833,7 +3028,7 @@ static void write_remoting_arg(FILE *file, int indent, const func_t *func, const
}
write_parameter_conf_or_var_exprs(file, indent, local_var_prefix, phase, var);
rtype = type->type;
rtype = get_struct_type(type);
if (is_context_handle(type))
{
@ -2899,7 +3094,7 @@ static void write_remoting_arg(FILE *file, int indent, const func_t *func, const
}
else if (is_array(type))
{
unsigned char tc = type->type;
unsigned char tc = get_array_type( type );
const char *array_type = "FixedArray";
/* We already have the size_is expression since it's at the
@ -2929,10 +3124,10 @@ static void write_remoting_arg(FILE *file, int indent, const func_t *func, const
if (phase == PHASE_FREE && pointer_type == RPC_FC_RP)
{
/* these are all unmarshalled by allocating memory */
if (type->type == RPC_FC_BOGUS_ARRAY ||
type->type == RPC_FC_CVARRAY ||
((type->type == RPC_FC_SMVARRAY || type->type == RPC_FC_LGVARRAY) && in_attr) ||
(type->type == RPC_FC_CARRAY && !in_attr))
if (tc == RPC_FC_BOGUS_ARRAY ||
tc == RPC_FC_CVARRAY ||
((tc == RPC_FC_SMVARRAY || tc == RPC_FC_LGVARRAY) && in_attr) ||
(tc == RPC_FC_CARRAY && !in_attr))
{
print_file(file, indent, "if (%s%s)\n", local_var_prefix, var->name);
indent++;
@ -2975,7 +3170,7 @@ static void write_remoting_arg(FILE *file, int indent, const func_t *func, const
if (phase != PHASE_FREE)
print_phase_basetype(file, indent, local_var_prefix, phase, pass, var, var->name);
}
else if (type->type == RPC_FC_RP && ref->type == RPC_FC_STRUCT &&
else if (type->type == RPC_FC_RP && get_struct_type(ref) == RPC_FC_STRUCT &&
!is_user_type(ref))
{
if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)