[PATCH 1/5] widl: Introduce an "aggregate_return" function attribute.

Henri Verbeet hverbeet at codeweavers.com
Thu Sep 4 01:14:27 CDT 2014


For MSVC style handling of aggregate return values. This probably doesn't make
anyone particularly happy; I'm open to suggestions. It may be possible to do
this without an attribute, based on the function declaration, but then we'd
have to figure out how MSVC decides when to use registers and when to use the
stack for the return value.
---
 tools/widl/header.c    |   61 ++++++++++++++++++++++++++++++++++++++++++++++++
 tools/widl/parser.l    |    1 +
 tools/widl/parser.y    |    4 +++-
 tools/widl/widltypes.h |    1 +
 4 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/tools/widl/header.c b/tools/widl/header.c
index 4f2222a..f5a37ca 100644
--- a/tools/widl/header.c
+++ b/tools/widl/header.c
@@ -910,12 +910,31 @@ static void write_cpp_method_def(FILE *header, const type_t *iface)
     if (!is_callas(func->attrs)) {
       const char *callconv = get_attrp(func->type->attrs, ATTR_CALLCONV);
       if (!callconv) callconv = "STDMETHODCALLTYPE";
+      if (is_attr(func->attrs, ATTR_AGGREGATE_RETURN)) {
+        fprintf(header, "#if defined(_MSC_VER)\n");
+      }
       indent(header, 0);
       fprintf(header, "virtual ");
       write_type_decl_left(header, type_function_get_rettype(func->type));
       fprintf(header, " %s %s(\n", callconv, get_name(func));
       write_args(header, type_get_function_args(func->type), iface->name, 2, TRUE);
       fprintf(header, ") = 0;\n");
+      if (is_attr(func->attrs, ATTR_AGGREGATE_RETURN)) {
+        fprintf(header, "#else\n");
+        indent(header, 0);
+        fprintf(header, "virtual ");
+        fprintf(header, "void %s %s(\n", callconv, get_name(func));
+        if (type_get_function_args(func->type)) {
+          write_args(header, type_get_function_args(func->type), iface->name, 2, TRUE);
+          fprintf(header, ",\n");
+        }
+        ++indentation;
+        indent(header, 0);
+        write_type_decl_left(header, type_function_get_rettype(func->type));
+        fprintf(header, " *__ret) = 0;\n");
+        --indentation;
+        fprintf(header, "#endif\n");
+      }
       fprintf(header, "\n");
     }
   }
@@ -942,6 +961,9 @@ static void write_inline_wrappers(FILE *header, const type_t *iface, const char
     if (!is_callas(func->attrs) && !is_inherited_method(iface, func)) {
       const var_t *arg;
 
+      if (is_attr(func->attrs, ATTR_AGGREGATE_RETURN)) {
+        fprintf(header, "#if defined(_MSC_VER)\n");
+      }
       fprintf(header, "static FORCEINLINE ");
       write_type_decl_left(header, type_function_get_rettype(func->type));
       fprintf(header, " %s_%s(", name, get_name(func));
@@ -954,6 +976,26 @@ static void write_inline_wrappers(FILE *header, const type_t *iface, const char
               fprintf(header, ",%s", arg->name);
       fprintf(header, ");\n");
       fprintf(header, "}\n");
+      if (is_attr(func->attrs, ATTR_AGGREGATE_RETURN)) {
+        fprintf(header, "#else\n");
+        fprintf(header, "static FORCEINLINE ");
+        write_type_decl_left(header, type_function_get_rettype(func->type));
+        fprintf(header, " %s_%s(", name, get_name(func));
+        write_args(header, type_get_function_args(func->type), name, 1, FALSE);
+        fprintf(header, ") {\n");
+        fprintf(header, "    ");
+        write_type_decl_left(header, type_function_get_rettype(func->type));
+        fprintf(header, " __ret;\n");
+        fprintf(header, "    ");
+        fprintf(header, "This->lpVtbl->%s(This", get_name(func));
+        if (type_get_function_args(func->type))
+          LIST_FOR_EACH_ENTRY(arg, type_get_function_args(func->type), const var_t, entry)
+            fprintf(header, ",%s", arg->name);
+        fprintf(header, ",&__ret);\n");
+        fprintf(header, "    return __ret;\n");
+        fprintf(header, "}\n");
+        fprintf(header, "#endif\n");
+      }
     }
   }
 }
@@ -977,6 +1019,9 @@ static void do_write_c_method_def(FILE *header, const type_t *iface, const char
     if (!is_callas(func->attrs)) {
       const char *callconv = get_attrp(func->type->attrs, ATTR_CALLCONV);
       if (!callconv) callconv = "STDMETHODCALLTYPE";
+      if (is_attr(func->attrs, ATTR_AGGREGATE_RETURN)) {
+        fprintf(header, "#if defined(_MSC_VER)\n");
+      }
       indent(header, 0);
       write_type_decl_left(header, type_function_get_rettype(func->type));
       if (is_inherited_method(iface, func))
@@ -985,6 +1030,22 @@ static void do_write_c_method_def(FILE *header, const type_t *iface, const char
         fprintf(header, " (%s *%s)(\n", callconv, get_name(func));
       write_args(header, type_get_function_args(func->type), name, 1, TRUE);
       fprintf(header, ");\n");
+      if (is_attr(func->attrs, ATTR_AGGREGATE_RETURN)) {
+        fprintf(header, "#else\n");
+        indent(header, 0);
+        if (is_inherited_method(iface, func))
+          fprintf(header, "void (%s *%s_%s)(\n", callconv, iface->name, func->name);
+        else
+          fprintf(header, "void (%s *%s)(\n", callconv, get_name(func));
+        write_args(header, type_get_function_args(func->type), name, 1, TRUE);
+        fprintf(header, ",\n");
+        ++indentation;
+        indent(header, 0);
+        write_type_decl_left(header, type_function_get_rettype(func->type));
+        fprintf(header, " *__ret);\n");
+        --indentation;
+        fprintf(header, "#endif\n");
+      }
       fprintf(header, "\n");
     }
   }
diff --git a/tools/widl/parser.l b/tools/widl/parser.l
index b911186..ed152c2 100644
--- a/tools/widl/parser.l
+++ b/tools/widl/parser.l
@@ -291,6 +291,7 @@ static const struct keyword keywords[] = {
 static const struct keyword attr_keywords[] =
 {
         {"aggregatable",                tAGGREGATABLE},
+        {"aggregate_return",            tAGGREGATE_RETURN},
         {"allocate",                    tALLOCATE},
         {"annotation",                  tANNOTATION},
         {"apartment",                   tAPARTMENT},
diff --git a/tools/widl/parser.y b/tools/widl/parser.y
index c0c77d7..10135d6 100644
--- a/tools/widl/parser.y
+++ b/tools/widl/parser.y
@@ -166,7 +166,7 @@ static attr_list_t *append_attribs(attr_list_t *, attr_list_t *);
 %token GREATEREQUAL LESSEQUAL
 %token LOGICALOR LOGICALAND
 %token ELLIPSIS
-%token tAGGREGATABLE tALLOCATE tANNOTATION tAPPOBJECT tASYNC tASYNCUUID
+%token tAGGREGATABLE tAGGREGATE_RETURN tALLOCATE tANNOTATION tAPPOBJECT tASYNC tASYNCUUID
 %token tAUTOHANDLE tBINDABLE tBOOLEAN tBROADCAST tBYTE tBYTECOUNT
 %token tCALLAS tCALLBACK tCASE tCDECL tCHAR tCOCLASS tCODE tCOMMSTATUS
 %token tCONST tCONTEXTHANDLE tCONTEXTHANDLENOSERIALIZE
@@ -464,6 +464,7 @@ str_list: aSTRING                               { $$ = append_str( NULL, $1 ); }
 
 attribute:					{ $$ = NULL; }
 	| tAGGREGATABLE				{ $$ = make_attr(ATTR_AGGREGATABLE); }
+	| tAGGREGATE_RETURN			{ $$ = make_attr(ATTR_AGGREGATE_RETURN); }
 	| tANNOTATION '(' aSTRING ')'		{ $$ = make_attrp(ATTR_ANNOTATION, $3); }
 	| tAPPOBJECT				{ $$ = make_attr(ATTR_APPOBJECT); }
 	| tASYNC				{ $$ = make_attr(ATTR_ASYNC); }
@@ -2020,6 +2021,7 @@ struct allowed_attr allowed_attr[] =
 {
     /* attr                        { D ACF I Fn ARG T En St Un Fi  L  DI M  C  <display name> } */
     /* ATTR_AGGREGATABLE */        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, "aggregatable" },
+    /* ATTR_AGGREGATE_RETURN */    { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "aggregate_return" },
     /* ATTR_ANNOTATION */          { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, "annotation" },
     /* ATTR_APPOBJECT */           { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, "appobject" },
     /* ATTR_ASYNC */               { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "async" },
diff --git a/tools/widl/widltypes.h b/tools/widl/widltypes.h
index 47c8844..4297283 100644
--- a/tools/widl/widltypes.h
+++ b/tools/widl/widltypes.h
@@ -67,6 +67,7 @@ typedef struct list statement_list_t;
 enum attr_type
 {
     ATTR_AGGREGATABLE,
+    ATTR_AGGREGATE_RETURN,
     ATTR_ANNOTATION,
     ATTR_APPOBJECT,
     ATTR_ASYNC,
-- 
1.7.10.4




More information about the wine-patches mailing list