[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