[PATCH 10/15] widl: check for existance of named struct, union and enum to avoid duplicate type_t definitions
Richard Pospesel
richard at torproject.org
Fri Jul 5 16:51:39 CDT 2019
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47035
Signed-off-by: Richard Pospesel <richard at torproject.org>
---
tools/widl/header.c | 31 ++++++-------
tools/widl/parser.y | 29 ++++++++++--
tools/widl/typetree.c | 103 ++++++++++++++++++++++++-----------------
tools/widl/typetree.h | 32 +++++++++++++
tools/widl/widltypes.h | 14 ++++++
5 files changed, 146 insertions(+), 63 deletions(-)
diff --git a/tools/widl/header.c b/tools/widl/header.c
index 9e9cd5f6ff..f58ad19927 100644
--- a/tools/widl/header.c
+++ b/tools/widl/header.c
@@ -43,7 +43,7 @@ user_type_list_t user_type_list = LIST_INIT(user_type_list);
context_handle_list_t context_handle_list = LIST_INIT(context_handle_list);
generic_handle_list_t generic_handle_list = LIST_INIT(generic_handle_list);
-static void write_type_def_or_decl(FILE *f, const decl_spec_t *ds, int field, const char *name);
+static void write_type_v(FILE *h, const decl_spec_t *ds, int is_field, int declonly, const char *name);
static void indent(FILE *h, int delta)
{
@@ -252,7 +252,7 @@ static void write_fields(FILE *h, var_list_t *fields)
default:
;
}
- write_type_def_or_decl(h, &v->declspec, TRUE, name);
+ write_type_v(h, &v->declspec, TRUE, v->declonly, name);
fprintf(h, ";\n");
}
}
@@ -317,7 +317,7 @@ void write_declspec_left(FILE* h, const decl_spec_t *ds, enum name_type name_typ
else {
switch (type_get_type_detect_alias(t)) {
case TYPE_ENUM:
- if (!declonly && t->defined && !t->written) {
+ if (!declonly && type_is_defined(t) && !t->written) {
if (name) fprintf(h, "enum %s {\n", name);
else fprintf(h, "enum {\n");
t->written = TRUE;
@@ -330,7 +330,7 @@ void write_declspec_left(FILE* h, const decl_spec_t *ds, enum name_type name_typ
break;
case TYPE_STRUCT:
case TYPE_ENCAPSULATED_UNION:
- if (!declonly && t->defined && !t->written) {
+ if (!declonly && type_is_defined(t) && !t->written) {
if (name) fprintf(h, "struct %s {\n", name);
else fprintf(h, "struct {\n");
t->written = TRUE;
@@ -345,7 +345,7 @@ void write_declspec_left(FILE* h, const decl_spec_t *ds, enum name_type name_typ
else fprintf(h, "struct %s", name ? name : "");
break;
case TYPE_UNION:
- if (!declonly && t->defined && !t->written) {
+ if (!declonly && type_is_defined(t) && !t->written) {
if (t->name) fprintf(h, "union %s {\n", t->name);
else fprintf(h, "union {\n");
t->written = TRUE;
@@ -539,12 +539,7 @@ static void write_type_v(FILE *h, const decl_spec_t *ds, int is_field, int declo
}
}
-static void write_type_def_or_decl(FILE *f, const decl_spec_t *ds, int field, const char *name)
-{
- write_type_v(f, ds, field, FALSE, name);
-}
-
-static void write_type_definition(FILE *f, type_t *t)
+static void write_type_definition(FILE *f, type_t *t, int declonly)
{
int in_namespace = t->namespace && !is_global_namespace(t->namespace);
int save_written = t->written;
@@ -555,14 +550,14 @@ static void write_type_definition(FILE *f, type_t *t)
write_namespace_start(f, t->namespace);
}
indent(f, 0);
- write_type_left(f, t, NAME_DEFAULT, FALSE);
+ write_type_left(f, t, NAME_DEFAULT, declonly);
fprintf(f, ";\n");
if(in_namespace) {
t->written = save_written;
write_namespace_end(f, t->namespace);
fprintf(f, "extern \"C\" {\n");
fprintf(f, "#else\n");
- write_type_left(f, t, NAME_C, FALSE);
+ write_type_left(f, t, NAME_C, declonly);
fprintf(f, ";\n");
fprintf(f, "#endif\n\n");
}
@@ -802,10 +797,10 @@ static void write_generic_handle_routines(FILE *header)
}
}
-static void write_typedef(FILE *header, type_t *type)
+static void write_typedef(FILE *header, type_t *type, int declonly)
{
fprintf(header, "typedef ");
- write_type_def_or_decl(header, type_alias_get_aliasee(type), FALSE, type->name);
+ write_type_v(header, type_alias_get_aliasee(type), FALSE, declonly, type->name);
fprintf(header, ";\n");
}
@@ -849,7 +844,7 @@ static void write_declaration(FILE *header, const var_t *v)
fprintf(header, "extern ");
break;
}
- write_type_def_or_decl(header, &v->declspec, FALSE, v->name);
+ write_type_v(header, &v->declspec, FALSE, FALSE, v->name);
fprintf(header, ";\n\n");
}
}
@@ -1731,7 +1726,7 @@ static void write_header_stmts(FILE *header, const statement_list_t *stmts, cons
write_coclass(header, stmt->u.type);
else
{
- write_type_definition(header, stmt->u.type);
+ write_type_definition(header, stmt->u.type, stmt->declonly);
}
break;
case STMT_TYPEREF:
@@ -1752,7 +1747,7 @@ static void write_header_stmts(FILE *header, const statement_list_t *stmts, cons
{
const type_list_t *type_entry = stmt->u.type_list;
for (; type_entry; type_entry = type_entry->next)
- write_typedef(header, type_entry->type);
+ write_typedef(header, type_entry->type, stmt->declonly);
break;
}
case STMT_LIBRARY:
diff --git a/tools/widl/parser.y b/tools/widl/parser.y
index de1dc709fc..f7c51c1d64 100644
--- a/tools/widl/parser.y
+++ b/tools/widl/parser.y
@@ -1821,6 +1821,10 @@ var_list_t *append_var(var_list_t *list, var_t *var)
list_init( list );
}
list_add_tail( list, &var->entry );
+
+ if (var->declspec.type)
+ var->declonly = !type_is_defined(var->declspec.type);
+
return list;
}
@@ -1844,6 +1848,7 @@ var_t *make_var(char *name)
v->attrs = NULL;
v->eval = NULL;
init_loc_info(&v->loc_info);
+ v->declonly = TRUE;
return v;
}
@@ -1979,14 +1984,14 @@ type_t *reg_type(type_t *type, const char *name, struct namespace *namespace, in
nt->t = t;
nt->next = namespace->type_hash[hash];
namespace->type_hash[hash] = nt;
- if ((t == tsSTRUCT || t == tsUNION))
+ if ((t == tsSTRUCT || t == tsUNION || t == tsENUM))
fix_incomplete_types(type);
return type;
}
static int is_incomplete(const type_t *t)
{
- return !t->defined &&
+ return !type_is_defined(t) &&
(type_get_type_detect_alias(t) == TYPE_ENUM ||
type_get_type_detect_alias(t) == TYPE_STRUCT ||
type_get_type_detect_alias(t) == TYPE_UNION ||
@@ -3046,6 +3051,10 @@ static statement_t *make_statement_type_decl(type_t *type)
{
statement_t *stmt = make_statement(STMT_TYPE);
stmt->u.type = type;
+ if (type_is_defined(type))
+ {
+ stmt->declonly = FALSE;
+ }
return stmt;
}
@@ -3121,6 +3130,7 @@ static statement_t *make_statement_typedef(declarator_list_t *decls)
declarator_t *decl, *next;
statement_t *stmt;
type_list_t **type_list;
+ int defined = TRUE;
if (!decls) return NULL;
@@ -3132,6 +3142,18 @@ static statement_t *make_statement_typedef(declarator_list_t *decls)
{
var_t *var = decl->var;
type_t *type = find_type_or_error(var->name, 0);
+
+ /* ensure that all of the types in this typedef statement have been defined
+ * before setting its declonly flag */
+ if (type_is_pointerish(type))
+ {
+ defined = defined & type_is_defined(type_get_pointer_chain_tail(type));
+ }
+ else
+ {
+ defined = defined & type_is_defined(type_get_real_type(type));
+ }
+
*type_list = xmalloc(sizeof(type_list_t));
(*type_list)->type = type;
(*type_list)->next = NULL;
@@ -3141,6 +3163,7 @@ static statement_t *make_statement_typedef(declarator_list_t *decls)
free(var);
}
+ stmt->declonly = !defined;
return stmt;
}
@@ -3181,7 +3204,7 @@ void init_loc_info(loc_info_t *i)
static void check_def(const type_t *t)
{
- if (t->defined)
+ if (type_is_defined(t))
error_loc("%s: redefinition error; original definition was at %s:%d\n",
t->name, t->loc_info.input_name, t->loc_info.line_number);
}
diff --git a/tools/widl/typetree.c b/tools/widl/typetree.c
index f08bee0bac..dc3e038dfa 100644
--- a/tools/widl/typetree.c
+++ b/tools/widl/typetree.c
@@ -198,7 +198,7 @@ type_t *type_new_alias(const decl_spec_t *ds, const char *name)
type_t *type_new_module(char *name)
{
type_t *type = get_type(TYPE_MODULE, name, NULL, 0);
- if (type->type_type != TYPE_MODULE || type->defined)
+ if (type->type_type != TYPE_MODULE || type_is_defined(type))
error_loc("%s: redefinition error; original definition was at %s:%d\n",
type->name, type->loc_info.input_name, type->loc_info.line_number);
type->name = name;
@@ -208,7 +208,7 @@ type_t *type_new_module(char *name)
type_t *type_new_coclass(char *name)
{
type_t *type = get_type(TYPE_COCLASS, name, NULL, 0);
- if (type->type_type != TYPE_COCLASS || type->defined)
+ if (type->type_type != TYPE_COCLASS || type_is_defined(type))
error_loc("%s: redefinition error; original definition was at %s:%d\n",
type->name, type->loc_info.input_name, type->loc_info.line_number);
type->name = name;
@@ -268,80 +268,99 @@ type_t *type_new_void(void)
type_t *type_new_enum(const char *name, struct namespace *namespace, int defined, var_list_t *enums)
{
- type_t *tag_type = name ? find_type(name, namespace, tsENUM) : NULL;
- type_t *t = make_type(TYPE_ENUM);
- t->name = name;
- t->namespace = namespace;
-
- if (tag_type && tag_type->details.enumeration)
- t->details.enumeration = tag_type->details.enumeration;
- else if (defined)
+ type_t *t = NULL;
+
+ if (name)
+ t = find_type(name, namespace, tsENUM);
+
+ if (!t)
{
- t->details.enumeration = xmalloc(sizeof(*t->details.enumeration));
- t->details.enumeration->enums = enums;
- t->defined = TRUE;
+ t = make_type(TYPE_ENUM);
+ t->name = name;
+ t->namespace = namespace;
+ if (name)
+ reg_type(t, name, namespace, tsENUM);
}
- if (name)
+ if (!type_is_defined(t))
{
if (defined)
- reg_type(t, name, namespace, tsENUM);
+ {
+ t->details.enumeration = xmalloc(sizeof(*t->details.enumeration));
+ t->details.enumeration->enums = enums;
+ t->defined = TRUE;
+ }
else
+ {
add_incomplete(t);
+ }
}
+
return t;
}
type_t *type_new_struct(char *name, struct namespace *namespace, int defined, var_list_t *fields)
{
- type_t *tag_type = name ? find_type(name, namespace, tsSTRUCT) : NULL;
- type_t *t;
+ type_t *t = NULL;
- /* avoid creating duplicate typelib type entries */
- if (tag_type && do_typelib) return tag_type;
-
- t = make_type(TYPE_STRUCT);
- t->name = name;
- t->namespace = namespace;
+ if (name)
+ t = find_type(name, namespace, tsSTRUCT);
- if (tag_type && tag_type->details.structure)
- t->details.structure = tag_type->details.structure;
- else if (defined)
+ if (!t)
{
- t->details.structure = xmalloc(sizeof(*t->details.structure));
- t->details.structure->fields = fields;
- t->defined = TRUE;
+ t = make_type(TYPE_STRUCT);
+ t->name = name;
+ t->namespace = namespace;
+ if (name)
+ reg_type(t, name, namespace, tsSTRUCT);
}
- if (name)
+
+ if (!type_is_defined(t))
{
if (defined)
- reg_type(t, name, namespace, tsSTRUCT);
+ {
+ t->details.structure = xmalloc(sizeof(*t->details.structure));
+ t->details.structure->fields = fields;
+ t->defined = TRUE;
+ }
else
+ {
add_incomplete(t);
+ }
}
+
return t;
}
type_t *type_new_nonencapsulated_union(const char *name, int defined, var_list_t *fields)
{
- type_t *tag_type = name ? find_type(name, NULL, tsUNION) : NULL;
- type_t *t = make_type(TYPE_UNION);
- t->name = name;
- if (tag_type && tag_type->details.structure)
- t->details.structure = tag_type->details.structure;
- else if (defined)
+ type_t *t = NULL;
+
+ if (name)
+ t = find_type(name, NULL, tsUNION);
+
+ if (!t)
{
- t->details.structure = xmalloc(sizeof(*t->details.structure));
- t->details.structure->fields = fields;
- t->defined = TRUE;
+ t = make_type(TYPE_UNION);
+ t->name = name;
+ if (name)
+ reg_type(t, name, NULL, tsUNION);
}
- if (name)
+
+ if (!type_is_defined(t))
{
if (defined)
- reg_type(t, name, NULL, tsUNION);
+ {
+ t->details.structure = xmalloc(sizeof(*t->details.structure));
+ t->details.structure->fields = fields;
+ t->defined = TRUE;
+ }
else
+ {
add_incomplete(t);
+ }
}
+
return t;
}
diff --git a/tools/widl/typetree.h b/tools/widl/typetree.h
index a68bc981cf..4ab8f8935b 100644
--- a/tools/widl/typetree.h
+++ b/tools/widl/typetree.h
@@ -379,4 +379,36 @@ static inline const details_t *type_get_const_details(const type_t* type)
return &type->details;
}
+static inline int type_is_pointerish(const type_t *type)
+{
+ type = type_get_real_type(type);
+ return type_get_type(type) == TYPE_ARRAY || type_get_type(type) == TYPE_POINTER;
+}
+
+static inline type_t * type_get_pointer_chain_tail(const type_t *type)
+{
+ type_t *pointee = NULL;
+ type_t *pointer = type_get_real_type(type);
+
+ if (type_get_type(pointer) == TYPE_ARRAY)
+ {
+ pointee = type_array_get_element_type(pointer);
+ }
+ else if (type_get_type(pointer) == TYPE_POINTER)
+ {
+ pointee = type_pointer_get_ref_type(pointer);
+ }
+ else
+ {
+ assert(FALSE);
+ }
+
+ if (type_is_pointerish(pointee))
+ {
+ return type_get_pointer_chain_tail(pointee);
+ }
+
+ return pointee;
+}
+
#endif /* WIDL_TYPE_TREE_H */
diff --git a/tools/widl/widltypes.h b/tools/widl/widltypes.h
index 108e537383..cd71e9af76 100644
--- a/tools/widl/widltypes.h
+++ b/tools/widl/widltypes.h
@@ -482,6 +482,13 @@ struct _var_t {
unsigned int typestring_offset;
struct _loc_info_t loc_info;
+ /* this flag indicates that this var's type (or pointed to type in the case of
+ * array or pointer) was not fully defined at the time of declaration.
+ * If this flag is set to TRUE then the type definition will not be written for this var
+ * If this flag is set to FALSE then the type definition will only be written if it has not
+ * been written yet (determined by the type_t's 'written' flag)
+ */
+ int declonly : 1;
/* parser-internal */
struct list entry;
@@ -565,6 +572,13 @@ struct _statement_t {
typelib_t *lib;
type_list_t *type_list;
} u;
+ /* this flag indicates that this statement's type (or pointed to type in the case of
+ * array or pointer) was not fully defined at the time of declaration.
+ * If this flag is set to TRUE then the type definition will not be written for this statement
+ * If this flag is set to FALSE then the type definition will only be written if it has not
+ * been written yet (determined by the type_t's 'written' flag)
+ */
+ int declonly : 1;
};
struct _warning_t {
--
2.17.1
More information about the wine-devel
mailing list