[WIDL] Sync with Wine Staging 4.0. CORE-15682
[reactos.git] / sdk / tools / widl / parser.y
index c895a87..7b06aa6 100644 (file)
@@ -38,7 +38,7 @@
 #include "expr.h"
 #include "typetree.h"
 
-static unsigned char pointer_default = RPC_FC_UP;
+static unsigned char pointer_default = FC_UP;
 
 typedef struct list typelist_t;
 struct typenode {
@@ -72,7 +72,7 @@ static attr_t *make_attr(enum attr_type type);
 static attr_t *make_attrv(enum attr_type type, unsigned int val);
 static attr_t *make_attrp(enum attr_type type, void *val);
 static expr_list_t *append_expr(expr_list_t *list, expr_t *expr);
-static array_dims_t *append_array(array_dims_t *list, expr_t *expr);
+static type_t *append_array(type_t *chain, expr_t *expr);
 static var_t *declare_var(attr_list_t *attrs, decl_spec_t *decl_spec, const declarator_t *decl, int top);
 static var_list_t *set_var_types(attr_list_t *attrs, decl_spec_t *decl_spec, declarator_list_t *decls);
 static ifref_list_t *append_ifref(ifref_list_t *list, ifref_t *iface);
@@ -82,7 +82,7 @@ static declarator_list_t *append_declarator(declarator_list_t *list, declarator_
 static declarator_t *make_declarator(var_t *var);
 static type_t *make_safearray(type_t *type);
 static typelib_t *make_library(const char *name, const attr_list_t *attrs);
-static type_t *append_ptrchain_type(type_t *ptrchain, type_t *type);
+static type_t *append_chain_type(type_t *chain, type_t *type);
 static warning_list_t *append_warning(warning_list_t *, int);
 
 static type_t *reg_typedefs(decl_spec_t *decl_spec, var_list_t *names, attr_list_t *attrs);
@@ -113,6 +113,8 @@ const char *get_attr_display_name(enum attr_type type);
 static void add_explicit_handle_if_necessary(const type_t *iface, var_t *func);
 static void check_def(const type_t *t);
 
+static void check_async_uuid(type_t *iface);
+
 static statement_t *make_statement(enum statement_type type);
 static statement_t *make_statement_type_decl(type_t *type);
 static statement_t *make_statement_reference(type_t *type);
@@ -134,6 +136,10 @@ static struct namespace global_namespace = {
 
 static struct namespace *current_namespace = &global_namespace;
 
+#ifndef __REACTOS__
+static typelib_t *current_typelib;
+#endif
+
 %}
 %union {
        attr_t *attr;
@@ -141,7 +147,6 @@ static struct namespace *current_namespace = &global_namespace;
        str_list_t *str_list;
        expr_t *expr;
        expr_list_t *expr_list;
-       array_dims_t *array_dims;
        type_t *type;
        var_t *var;
        var_list_t *var_list;
@@ -170,7 +175,7 @@ static struct namespace *current_namespace = &global_namespace;
 %token <dbl> aDOUBLE
 %token <str> aSTRING aWSTRING aSQSTRING
 %token <uuid> aUUID
-%token aEOF
+%token aEOF aACF
 %token SHL SHR
 %token MEMBERPTR
 %token EQUALITY INEQUALITY
@@ -207,7 +212,7 @@ static struct namespace *current_namespace = &global_namespace;
 %token tIMPORT tIMPORTLIB
 %token tIN tIN_LINE tINLINE
 %token tINPUTSYNC
-%token tINT tINT3264 tINT64
+%token tINT tINT32 tINT3264 tINT64
 %token tINTERFACE
 %token tLCID
 %token tLENGTHIS tLIBRARY
@@ -263,8 +268,9 @@ static struct namespace *current_namespace = &global_namespace;
 %token tWCHAR tWIREMARSHAL
 %token tAPARTMENT tNEUTRAL tSINGLE tFREE tBOTH
 
-%type <attr> attribute type_qualifier function_specifier
+%type <attr> attribute type_qualifier function_specifier acf_attribute
 %type <attr_list> m_attributes attributes attrib_list m_type_qual_list
+%type <attr_list> acf_attributes acf_attribute_list
 %type <str_list> str_list
 %type <expr> m_expr expr expr_const expr_int_const array m_bitfield
 %type <expr_list> m_exprs /* exprs expr_list */ expr_list_int_const
@@ -318,7 +324,7 @@ static struct namespace *current_namespace = &global_namespace;
 
 %%
 
-input:   gbl_statements                                { fix_incomplete();
+input: gbl_statements m_acf                    { fix_incomplete();
                                                  check_statements($1, FALSE);
                                                  check_all_user_types($1);
                                                  write_header($1);
@@ -327,11 +333,16 @@ input:   gbl_statements                           { fix_incomplete();
                                                  write_client($1);
                                                  write_server($1);
                                                  write_regscript($1);
+#ifndef __REACTOS__
+                                                 write_typelib_regscript($1);
+#endif
                                                  write_dlldata($1);
                                                  write_local_stubs($1);
                                                }
        ;
 
+m_acf: /* empty */ | aACF acf_statements
+
 gbl_statements:                                        { $$ = NULL; }
        | gbl_statements namespacedef '{' { push_namespace($2); } gbl_statements '}'
                                                { pop_namespace($2); $$ = append_statements($1, $5); }
@@ -425,21 +436,33 @@ import: import_start imp_statements aEOF  { $$ = $1->name;
        ;
 
 importlib: tIMPORTLIB '(' aSTRING ')'
+/* ifdef __REACTOS__ */
           semicolon_opt                        { $$ = $3; if(!parse_only) add_importlib($3); }
+/* else
+          semicolon_opt                        { $$ = $3; if(!parse_only) add_importlib($3, current_typelib); }
+*/
        ;
 
 libraryhdr: tLIBRARY aIDENTIFIER               { $$ = $2; }
        |   tLIBRARY aKNOWNTYPE                 { $$ = $2; }
        ;
 library_start: attributes libraryhdr '{'       { $$ = make_library($2, check_library_attrs($2, $1));
+/* ifdef __REACTOS__ */
                                                  if (!parse_only) start_typelib($$);
+/* else
+                                                 if (!parse_only && do_typelib) current_typelib = $$;
+*/
                                                }
        ;
 librarydef: library_start imp_statements '}'
+/* ifdef __REACTOS__ */
            semicolon_opt                       { $$ = $1;
                                                  $$->stmts = $2;
                                                  if (!parse_only) end_typelib();
                                                }
+/* else
+           semicolon_opt                       { $$ = $1; $$->stmts = $2; }
+*/
        ;
 
 m_args:                                                { $$ = NULL; }
@@ -468,8 +491,8 @@ arg:          attributes decl_spec m_any_declarator { if ($2->stgclass != STG_NONE && $
        ;
 
 array:   '[' expr ']'                          { $$ = $2;
-                                                 if (!$$->is_const)
-                                                     error_loc("array dimension is not an integer constant\n");
+                                                 if (!$$->is_const || $$->cval <= 0)
+                                                     error_loc("array dimension is not a positive integer constant\n");
                                                }
        | '[' '*' ']'                           { $$ = make_expr(EXPR_VOID); }
        | '[' ']'                               { $$ = make_expr(EXPR_VOID); }
@@ -816,10 +839,11 @@ m_int:
 int_std:  tINT                                 { $$ = type_new_int(TYPE_BASIC_INT, 0); }
        | tSHORT m_int                          { $$ = type_new_int(TYPE_BASIC_INT16, 0); }
        | tSMALL                                { $$ = type_new_int(TYPE_BASIC_INT8, 0); }
-       | tLONG m_int                           { $$ = type_new_int(TYPE_BASIC_INT32, 0); }
+       | tLONG m_int                           { $$ = type_new_int(TYPE_BASIC_LONG, 0); }
        | tHYPER m_int                          { $$ = type_new_int(TYPE_BASIC_HYPER, 0); }
        | tINT64                                { $$ = type_new_int(TYPE_BASIC_INT64, 0); }
        | tCHAR                                 { $$ = type_new_int(TYPE_BASIC_CHAR, 0); }
+       | tINT32                                { $$ = type_new_int(TYPE_BASIC_INT32, 0); }
        | tINT3264                              { $$ = type_new_int(TYPE_BASIC_INT3264, 0); }
        ;
 
@@ -909,6 +933,7 @@ interfacedef: interfacehdr inherit
                                                  if($$ == $2)
                                                    error_loc("Interface can't inherit from itself\n");
                                                  type_interface_define($$, $2, $4);
+                                                 check_async_uuid($$);
                                                  pointer_default = $1.old_pointer_default;
                                                }
 /* MIDL is able to import the definition of a base class from inside the
@@ -977,7 +1002,7 @@ decl_spec_no_type:
 
 declarator:
          '*' m_type_qual_list declarator %prec PPTR
-                                               { $$ = $3; $$->type = append_ptrchain_type($$->type, type_new_pointer(pointer_default, NULL, $2)); }
+                                               { $$ = $3; $$->type = append_chain_type($$->type, type_new_pointer(pointer_default, NULL, $2)); }
        | callconv declarator                   { $$ = $2; if ($$->func_type) $$->func_type->attrs = append_attr($$->func_type->attrs, make_attrp(ATTR_CALLCONV, $1));
                                                           else if ($$->type) $$->type->attrs = append_attr($$->type->attrs, make_attrp(ATTR_CALLCONV, $1)); }
        | direct_declarator
@@ -986,9 +1011,9 @@ declarator:
 direct_declarator:
          ident                                 { $$ = make_declarator($1); }
        | '(' declarator ')'                    { $$ = $2; }
-       | direct_declarator array               { $$ = $1; $$->array = append_array($$->array, $2); }
+       | direct_declarator array               { $$ = $1; $$->type = append_array($$->type, $2); }
        | direct_declarator '(' m_args ')'      { $$ = $1;
-                                                 $$->func_type = append_ptrchain_type($$->type, type_new_function($3));
+                                                 $$->func_type = append_chain_type($$->type, type_new_function($3));
                                                  $$->type = NULL;
                                                }
        ;
@@ -996,7 +1021,7 @@ direct_declarator:
 /* abstract declarator */
 abstract_declarator:
          '*' m_type_qual_list m_abstract_declarator %prec PPTR
-                                               { $$ = $3; $$->type = append_ptrchain_type($$->type, type_new_pointer(pointer_default, NULL, $2)); }
+                                               { $$ = $3; $$->type = append_chain_type($$->type, type_new_pointer(pointer_default, NULL, $2)); }
        | callconv m_abstract_declarator        { $$ = $2; if ($$->func_type) $$->func_type->attrs = append_attr($$->func_type->attrs, make_attrp(ATTR_CALLCONV, $1));
                                                           else if ($$->type) $$->type->attrs = append_attr($$->type->attrs, make_attrp(ATTR_CALLCONV, $1)); }
        | abstract_direct_declarator
@@ -1005,7 +1030,7 @@ abstract_declarator:
 /* abstract declarator without accepting direct declarator */
 abstract_declarator_no_direct:
          '*' m_type_qual_list m_any_declarator %prec PPTR
-                                               { $$ = $3; $$->type = append_ptrchain_type($$->type, type_new_pointer(pointer_default, NULL, $2)); }
+                                               { $$ = $3; $$->type = append_chain_type($$->type, type_new_pointer(pointer_default, NULL, $2)); }
        | callconv m_any_declarator             { $$ = $2; if ($$->func_type) $$->func_type->attrs = append_attr($$->func_type->attrs, make_attrp(ATTR_CALLCONV, $1));
                                                           else if ($$->type) $$->type->attrs = append_attr($$->type->attrs, make_attrp(ATTR_CALLCONV, $1)); }
        ;
@@ -1018,16 +1043,16 @@ m_abstract_declarator:                          { $$ = make_declarator(NULL); }
 /* abstract direct declarator */
 abstract_direct_declarator:
          '(' abstract_declarator_no_direct ')' { $$ = $2; }
-       | abstract_direct_declarator array      { $$ = $1; $$->array = append_array($$->array, $2); }
-       | array                                 { $$ = make_declarator(NULL); $$->array = append_array($$->array, $1); }
+       | abstract_direct_declarator array      { $$ = $1; $$->type = append_array($$->type, $2); }
+       | array                                 { $$ = make_declarator(NULL); $$->type = append_array($$->type, $1); }
        | '(' m_args ')'
                                                { $$ = make_declarator(NULL);
-                                                 $$->func_type = append_ptrchain_type($$->type, type_new_function($2));
+                                                 $$->func_type = append_chain_type($$->type, type_new_function($2));
                                                  $$->type = NULL;
                                                }
        | abstract_direct_declarator '(' m_args ')'
                                                { $$ = $1;
-                                                 $$->func_type = append_ptrchain_type($$->type, type_new_function($3));
+                                                 $$->func_type = append_chain_type($$->type, type_new_function($3));
                                                  $$->type = NULL;
                                                }
        ;
@@ -1035,7 +1060,7 @@ abstract_direct_declarator:
 /* abstract or non-abstract declarator */
 any_declarator:
          '*' m_type_qual_list m_any_declarator %prec PPTR
-                                               { $$ = $3; $$->type = append_ptrchain_type($$->type, type_new_pointer(pointer_default, NULL, $2)); }
+                                               { $$ = $3; $$->type = append_chain_type($$->type, type_new_pointer(pointer_default, NULL, $2)); }
        | callconv m_any_declarator             { $$ = $2; $$->type->attrs = append_attr($$->type->attrs, make_attrp(ATTR_CALLCONV, $1)); }
        | any_direct_declarator
        ;
@@ -1043,7 +1068,7 @@ any_declarator:
 /* abstract or non-abstract declarator without accepting direct declarator */
 any_declarator_no_direct:
          '*' m_type_qual_list m_any_declarator %prec PPTR
-                                               { $$ = $3; $$->type = append_ptrchain_type($$->type, type_new_pointer(pointer_default, NULL, $2)); }
+                                               { $$ = $3; $$->type = append_chain_type($$->type, type_new_pointer(pointer_default, NULL, $2)); }
        | callconv m_any_declarator             { $$ = $2; $$->type->attrs = append_attr($$->type->attrs, make_attrp(ATTR_CALLCONV, $1)); }
        ;
 
@@ -1058,16 +1083,16 @@ m_any_declarator:                               { $$ = make_declarator(NULL); }
 any_direct_declarator:
          ident                                 { $$ = make_declarator($1); }
        | '(' any_declarator_no_direct ')'      { $$ = $2; }
-       | any_direct_declarator array           { $$ = $1; $$->array = append_array($$->array, $2); }
-       | array                                 { $$ = make_declarator(NULL); $$->array = append_array($$->array, $1); }
+       | any_direct_declarator array           { $$ = $1; $$->type = append_array($$->type, $2); }
+       | array                                 { $$ = make_declarator(NULL); $$->type = append_array($$->type, $1); }
        | '(' m_args ')'
                                                { $$ = make_declarator(NULL);
-                                                 $$->func_type = append_ptrchain_type($$->type, type_new_function($2));
+                                                 $$->func_type = append_chain_type($$->type, type_new_function($2));
                                                  $$->type = NULL;
                                                }
        | any_direct_declarator '(' m_args ')'
                                                { $$ = $1;
-                                                 $$->func_type = append_ptrchain_type($$->type, type_new_function($3));
+                                                 $$->func_type = append_chain_type($$->type, type_new_function($3));
                                                  $$->type = NULL;
                                                }
        ;
@@ -1107,9 +1132,9 @@ threading_type:
        ;
 
 pointer_type:
-         tREF                                  { $$ = RPC_FC_RP; }
-       | tUNIQUE                               { $$ = RPC_FC_UP; }
-       | tPTR                                  { $$ = RPC_FC_FP; }
+         tREF                                  { $$ = FC_RP; }
+       | tUNIQUE                               { $$ = FC_UP; }
+       | tPTR                                  { $$ = FC_FP; }
        ;
 
 structdef: tSTRUCT t_ident '{' fields '}'      { $$ = type_new_struct($2, current_namespace, TRUE, $4); }
@@ -1147,6 +1172,40 @@ version:
        | aHEXNUM                               { $$ = $1; }
        ;
 
+acf_statements
+        : /* empty */
+        | acf_interface acf_statements
+
+acf_int_statements
+        : /* empty */
+        | acf_int_statement acf_int_statements
+
+acf_int_statement
+        : tTYPEDEF acf_attributes aKNOWNTYPE ';'
+                                                { type_t *type = find_type_or_error($3, 0);
+                                                  type->attrs = append_attr_list(type->attrs, $2);
+                                                }
+acf_interface
+        : acf_attributes tINTERFACE aKNOWNTYPE '{' acf_int_statements '}'
+                                                {  type_t *iface = find_type_or_error2($3, 0);
+                                                   if (type_get_type(iface) != TYPE_INTERFACE)
+                                                       error_loc("%s is not an interface\n", iface->name);
+                                                   iface->attrs = append_attr_list(iface->attrs, $1);
+                                                }
+
+acf_attributes
+        : /* empty */                           { $$ = NULL; };
+        | '[' acf_attribute_list ']'            { $$ = $2; };
+
+acf_attribute_list
+        : acf_attribute                         { $$ = append_attr(NULL, $1); }
+        | acf_attribute_list ',' acf_attribute  { $$ = append_attr($1, $3); }
+
+acf_attribute
+        : tENCODE                               { $$ = make_attr(ATTR_ENCODE); }
+        | tDECODE                               { $$ = make_attr(ATTR_DECODE); }
+        | tEXPLICITHANDLE                       { $$ = make_attr(ATTR_EXPLICIT_HANDLE); }
+
 %%
 
 static void decl_builtin_basic(const char *name, enum type_basic_type type)
@@ -1236,10 +1295,13 @@ static attr_list_t *append_attr_list(attr_list_t *new_list, attr_list_t *old_lis
   return new_list;
 }
 
-static attr_list_t *dupattrs(const attr_list_t *list)
+typedef int (*map_attrs_filter_t)(attr_list_t*,const attr_t*);
+
+static attr_list_t *map_attrs(const attr_list_t *list, map_attrs_filter_t filter)
 {
   attr_list_t *new_list;
   const attr_t *attr;
+  attr_t *new_attr;
 
   if (!list) return NULL;
 
@@ -1247,7 +1309,8 @@ static attr_list_t *dupattrs(const attr_list_t *list)
   list_init( new_list );
   LIST_FOR_EACH_ENTRY(attr, list, const attr_t, entry)
   {
-    attr_t *new_attr = xmalloc(sizeof(*new_attr));
+    if (filter && !filter(new_list, attr)) continue;
+    new_attr = xmalloc(sizeof(*new_attr));
     *new_attr = *attr;
     list_add_tail(new_list, &new_attr->entry);
   }
@@ -1297,7 +1360,7 @@ static decl_spec_t *make_decl_spec(type_t *type, decl_spec_t *left, decl_spec_t
   {
     attr_list_t *attrs;
     declspec->type = duptype(type, 1);
-    attrs = dupattrs(type->attrs);
+    attrs = map_attrs(type->attrs, NULL);
     declspec->type->attrs = append_attr_list(attrs, declspec->attrs);
     declspec->attrs = NULL;
   }
@@ -1341,16 +1404,19 @@ static expr_list_t *append_expr(expr_list_t *list, expr_t *expr)
     return list;
 }
 
-static array_dims_t *append_array(array_dims_t *list, expr_t *expr)
+static type_t *append_array(type_t *chain, expr_t *expr)
 {
-    if (!expr) return list;
-    if (!list)
-    {
-        list = xmalloc( sizeof(*list) );
-        list_init( list );
-    }
-    list_add_tail( list, &expr->entry );
-    return list;
+    type_t *array;
+
+    if (!expr)
+        return chain;
+
+    /* An array is always a reference pointer unless explicitly marked otherwise
+     * (regardless of what the default pointer attribute is). */
+    array = type_new_array(NULL, NULL, FALSE, expr->is_const ? expr->cval : 0,
+            expr->is_const ? NULL : expr, NULL, FC_RP);
+
+    return append_chain_type(chain, array);
 }
 
 static struct list type_pool = LIST_INIT(type_pool);
@@ -1406,6 +1472,7 @@ static int is_allowed_range_type(const type_t *type)
         case TYPE_BASIC_INT64:
         case TYPE_BASIC_INT:
         case TYPE_BASIC_INT3264:
+        case TYPE_BASIC_LONG:
         case TYPE_BASIC_BYTE:
         case TYPE_BASIC_CHAR:
         case TYPE_BASIC_WCHAR:
@@ -1423,16 +1490,32 @@ static int is_allowed_range_type(const type_t *type)
     }
 }
 
-static type_t *append_ptrchain_type(type_t *ptrchain, type_t *type)
+static type_t *get_array_or_ptr_ref(type_t *type)
 {
-  type_t *ptrchain_type;
-  if (!ptrchain)
-    return type;
-  for (ptrchain_type = ptrchain; type_pointer_get_ref(ptrchain_type); ptrchain_type = type_pointer_get_ref(ptrchain_type))
-    ;
-  assert(ptrchain_type->type_type == TYPE_POINTER);
-  ptrchain_type->details.pointer.ref = type;
-  return ptrchain;
+    if (is_ptr(type))
+        return type_pointer_get_ref(type);
+    else if (is_array(type))
+        return type_array_get_element(type);
+    return NULL;
+}
+
+static type_t *append_chain_type(type_t *chain, type_t *type)
+{
+    type_t *chain_type;
+
+    if (!chain)
+        return type;
+    for (chain_type = chain; get_array_or_ptr_ref(chain_type); chain_type = get_array_or_ptr_ref(chain_type))
+        ;
+
+    if (is_ptr(chain_type))
+        chain_type->details.pointer.ref = type;
+    else if (is_array(chain_type))
+        chain_type->details.array.elem = type;
+    else
+        assert(0);
+
+    return chain;
 }
 
 static warning_list_t *append_warning(warning_list_t *list, int num)
@@ -1456,10 +1539,8 @@ static var_t *declare_var(attr_list_t *attrs, decl_spec_t *decl_spec, const decl
   var_t *v = decl->var;
   expr_list_t *sizes = get_attrp(attrs, ATTR_SIZEIS);
   expr_list_t *lengs = get_attrp(attrs, ATTR_LENGTHIS);
-  int sizeless;
   expr_t *dim;
   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;
 
@@ -1478,13 +1559,13 @@ static var_t *declare_var(attr_list_t *attrs, decl_spec_t *decl_spec, const decl
   }
 
   /* add type onto the end of the pointers in pident->type */
-  v->type = append_ptrchain_type(decl ? decl->type : NULL, type);
+  v->type = append_chain_type(decl ? decl->type : NULL, type);
   v->stgclass = decl_spec->stgclass;
   v->attrs = attrs;
 
   /* check for pointer attribute being applied to non-pointer, non-array
    * type */
-  if (!arr)
+  if (!is_array(v->type))
   {
     int ptr_attr = get_attrv(v->attrs, ATTR_POINTERTYPE);
     const type_t *ptr = NULL;
@@ -1501,12 +1582,12 @@ static var_t *declare_var(attr_list_t *attrs, decl_spec_t *decl_spec, const decl
     }
     if (is_ptr(ptr))
     {
-      if (ptr_attr && ptr_attr != RPC_FC_UP &&
+      if (ptr_attr && ptr_attr != FC_UP &&
           type_get_type(type_pointer_get_ref(ptr)) == TYPE_INTERFACE)
           warning_loc_info(&v->loc_info,
                            "%s: pointer attribute applied to interface "
                            "pointer type has no effect\n", v->name);
-      if (!ptr_attr && top && (*pt)->details.pointer.def_fc != RPC_FC_RP)
+      if (!ptr_attr && top && (*pt)->details.pointer.def_fc != FC_RP)
       {
         /* FIXME: this is a horrible hack to cope with the issue that we
          * store an offset to the typeformat string in the type object, but
@@ -1523,17 +1604,24 @@ static var_t *declare_var(attr_list_t *attrs, decl_spec_t *decl_spec, const decl
   {
     type_t *t = type;
 
-    if (!is_ptr(v->type) && !arr)
+    if (!is_ptr(v->type) && !is_array(v->type))
       error_loc("'%s': [string] attribute applied to non-pointer, non-array type\n",
                 v->name);
 
-    while (is_ptr(t))
-      t = type_pointer_get_ref(t);
+    for (;;)
+    {
+        if (is_ptr(t))
+            t = type_pointer_get_ref(t);
+        else if (is_array(t))
+            t = type_array_get_element(t);
+        else
+            break;
+    }
 
     if (type_get_type(t) != TYPE_BASIC &&
-        (get_basic_fc(t) != RPC_FC_CHAR &&
-         get_basic_fc(t) != RPC_FC_BYTE &&
-         get_basic_fc(t) != RPC_FC_WCHAR))
+        (get_basic_fc(t) != FC_CHAR &&
+         get_basic_fc(t) != FC_BYTE &&
+         get_basic_fc(t) != FC_WCHAR))
     {
       error_loc("'%s': [string] attribute is only valid on 'char', 'byte', or 'wchar_t' pointers and arrays\n",
                 v->name);
@@ -1550,36 +1638,6 @@ static var_t *declare_var(attr_list_t *attrs, decl_spec_t *decl_spec, const decl
     error_loc("'%s': [range] attribute applied to non-integer type\n",
               v->name);
 
-  ptype = &v->type;
-  sizeless = FALSE;
-  if (arr) LIST_FOR_EACH_ENTRY_REV(dim, arr, expr_t, entry)
-  {
-    if (sizeless)
-      error_loc("%s: only the first array dimension can be unspecified\n", v->name);
-
-    if (dim->is_const)
-    {
-      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 size = type_memsize(v->type);
-
-        if (0xffffffffu / size < dim->cval)
-          error_loc("%s: total array size is too large\n", v->name);
-      }
-    }
-    else
-      sizeless = TRUE;
-
-    *ptype = type_new_array(NULL, *ptype, FALSE,
-                            dim->is_const ? dim->cval : 0,
-                            dim->is_const ? NULL : dim, NULL,
-                            pointer_default);
-  }
-
   ptype = &v->type;
   if (sizes) LIST_FOR_EACH_ENTRY(dim, sizes, expr_t, entry)
   {
@@ -1739,6 +1797,18 @@ var_t *make_var(char *name)
   return v;
 }
 
+static var_t *copy_var(var_t *src, char *name, map_attrs_filter_t attr_filter)
+{
+  var_t *v = xmalloc(sizeof(var_t));
+  v->name = name;
+  v->type = src->type;
+  v->attrs = map_attrs(src->attrs, attr_filter);
+  v->eval = src->eval;
+  v->stgclass = src->stgclass;
+  v->loc_info = src->loc_info;
+  return v;
+}
+
 static declarator_list_t *append_declarator(declarator_list_t *list, declarator_t *d)
 {
   if (!d) return list;
@@ -1756,7 +1826,6 @@ static declarator_t *make_declarator(var_t *var)
   d->var = var ? var : make_var(NULL);
   d->type = NULL;
   d->func_type = NULL;
-  d->array = NULL;
   d->bits = NULL;
   return d;
 }
@@ -1764,7 +1833,7 @@ static declarator_t *make_declarator(var_t *var)
 static type_t *make_safearray(type_t *type)
 {
   return type_new_array(NULL, type_new_alias(type, "SAFEARRAY"), TRUE, 0,
-                        NULL, NULL, RPC_FC_RP);
+                        NULL, NULL, FC_RP);
 }
 
 static typelib_t *make_library(const char *name, const attr_list_t *attrs)
@@ -2415,6 +2484,7 @@ static int is_allowed_conf_type(const type_t *type)
         case TYPE_BASIC_INT32:
         case TYPE_BASIC_INT64:
         case TYPE_BASIC_INT:
+        case TYPE_BASIC_LONG:
         case TYPE_BASIC_CHAR:
         case TYPE_BASIC_HYPER:
         case TYPE_BASIC_BYTE:
@@ -2755,6 +2825,87 @@ static void check_functions(const type_t *iface, int is_inside_library)
     }
 }
 
+static char *concat_str(const char *prefix, const char *str)
+{
+    char *ret = xmalloc(strlen(prefix) + strlen(str) + 1);
+    strcpy(ret, prefix);
+    strcat(ret, str);
+    return ret;
+}
+
+static int async_iface_attrs(attr_list_t *attrs, const attr_t *attr)
+{
+    switch(attr->type)
+    {
+    case ATTR_UUID:
+        return 0;
+    case ATTR_ASYNCUUID:
+        append_attr(attrs, make_attrp(ATTR_UUID, attr->u.pval));
+        return 0;
+    default:
+        return 1;
+    }
+}
+
+static int arg_in_attrs(attr_list_t *attrs, const attr_t *attr)
+{
+    return attr->type != ATTR_OUT && attr->type != ATTR_RETVAL;
+}
+
+static int arg_out_attrs(attr_list_t *attrs, const attr_t *attr)
+{
+    return attr->type != ATTR_IN;
+}
+
+static void check_async_uuid(type_t *iface)
+{
+    statement_list_t *stmts = NULL;
+    statement_t *stmt;
+    type_t *async_iface;
+    type_t *inherit;
+
+    if (!is_attr(iface->attrs, ATTR_ASYNCUUID)) return;
+
+    inherit = iface->details.iface->inherit;
+    if (inherit && strcmp(inherit->name, "IUnknown"))
+        inherit = inherit->details.iface->async_iface;
+    if (!inherit)
+        error_loc("async_uuid applied to an interface with incompatible parent\n");
+
+    async_iface = get_type(TYPE_INTERFACE, concat_str("Async", iface->name), iface->namespace, 0);
+    async_iface->attrs = map_attrs(iface->attrs, async_iface_attrs);
+
+    STATEMENTS_FOR_EACH_FUNC( stmt, type_iface_get_stmts(iface) )
+    {
+        var_t *begin_func, *finish_func, *func = stmt->u.var, *arg;
+        var_list_t *begin_args = NULL, *finish_args = NULL, *args;
+
+        args = func->type->details.function->args;
+        if (args) LIST_FOR_EACH_ENTRY(arg, args, var_t, entry)
+        {
+            if (is_attr(arg->attrs, ATTR_IN) || !is_attr(arg->attrs, ATTR_OUT))
+                begin_args = append_var(begin_args, copy_var(arg, strdup(arg->name), arg_in_attrs));
+            if (is_attr(arg->attrs, ATTR_OUT))
+                finish_args = append_var(finish_args, copy_var(arg, strdup(arg->name), arg_out_attrs));
+        }
+
+        begin_func = copy_var(func, concat_str("Begin_", func->name), NULL);
+        begin_func->type = type_new_function(begin_args);
+        begin_func->type->attrs = func->attrs;
+        begin_func->type->details.function->retval = func->type->details.function->retval;
+        stmts = append_statement(stmts, make_statement_declaration(begin_func));
+
+        finish_func = copy_var(func, concat_str("Finish_", func->name), NULL);
+        finish_func->type = type_new_function(finish_args);
+        finish_func->type->attrs = func->attrs;
+        finish_func->type->details.function->retval = func->type->details.function->retval;
+        stmts = append_statement(stmts, make_statement_declaration(finish_func));
+    }
+
+    type_interface_define(async_iface, inherit, stmts);
+    iface->details.iface->async_iface = async_iface->details.iface->async_iface = async_iface;
+}
+
 static void check_statements(const statement_list_t *stmts, int is_inside_library)
 {
     const statement_t *stmt;