From: Richard Pospesel Subject: [PATCH 10/15] widl: check for existance of named struct, union and enum to avoid duplicate type_t definitions Message-Id: <20190705215144.7474-9-richard@torproject.org> Date: Fri, 5 Jul 2019 14:51:39 -0700 In-Reply-To: <20190705215144.7474-8-richard@torproject.org> References: <20190705215003.7384-1-richard@torproject.org> <20190705215144.7474-1-richard@torproject.org> <20190705215144.7474-2-richard@torproject.org> <20190705215144.7474-3-richard@torproject.org> <20190705215144.7474-4-richard@torproject.org> <20190705215144.7474-5-richard@torproject.org> <20190705215144.7474-6-richard@torproject.org> <20190705215144.7474-7-richard@torproject.org> <20190705215144.7474-8-richard@torproject.org> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47035 Signed-off-by: Richard Pospesel --- 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