Module: wine Branch: master Commit: b42a15513eaa973b40ab967014b311af64acbb98 URL: http://source.winehq.org/git/wine.git/?a=commit;h=b42a15513eaa973b40ab967014...
Author: Henri Verbeet hverbeet@codeweavers.com Date: Fri Jul 21 13:03:41 2017 +0200
widl: Handle C++ aggregate returns in a MSVC compatible way.
This mainly affects 64-bit winelib applications, and potentially mingw-w64 usage of the Wine headers. As explained in commit fabfa59aea5c5b3201142382038beb3e76cb7567, MSVC returns aggregates through an implicit parameter immediately after the this/interface pointer. GCC's "ms_abi" attribute is supposed to match this, but unfortunately current versions of g++ (confirmed up to at least g++ 6.3) place the implicit return pointer before the this/interface pointer. See also https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52792.
This commit takes an approach similar to the earlier commit fabfa59aea5c5b3201142382038beb3e76cb7567: For ABI compatibility the return pointer is listed as an explicit parameter in the vtbl entry, while an inline helper is provided for source code compatibility.
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
tools/widl/header.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-)
diff --git a/tools/widl/header.c b/tools/widl/header.c index e48b488..b5fe232 100644 --- a/tools/widl/header.c +++ b/tools/widl/header.c @@ -1043,13 +1043,62 @@ static void write_cpp_method_def(FILE *header, const type_t *iface) const var_t *func = stmt->u.var; if (!is_callas(func->attrs)) { const char *callconv = get_attrp(func->type->attrs, ATTR_CALLCONV); + const var_list_t *args = type_get_function_args(func->type); + const var_t *arg; + if (!callconv) callconv = "STDMETHODCALLTYPE"; + + if (is_aggregate_return(func)) { + fprintf(header, "#ifdef WIDL_EXPLICIT_AGGREGATE_RETURNS\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)); + ++indentation; + indent(header, 0); + write_type_decl_left(header, type_function_get_rettype(func->type)); + fprintf(header, " *__ret"); + --indentation; + if (args) { + fprintf(header, ",\n"); + write_args(header, args, iface->name, 2, TRUE); + } + fprintf(header, ") = 0;\n"); + + indent(header, 0); + write_type_decl_left(header, type_function_get_rettype(func->type)); + fprintf(header, " %s %s(\n", callconv, get_name(func)); + write_args(header, args, iface->name, 2, TRUE); + fprintf(header, ")\n"); + indent(header, 0); + fprintf(header, "{\n"); + ++indentation; + indent(header, 0); + write_type_decl_left(header, type_function_get_rettype(func->type)); + fprintf(header, " __ret;\n"); + indent(header, 0); + fprintf(header, "return *%s(&__ret", get_name(func)); + if (args) + LIST_FOR_EACH_ENTRY(arg, args, const var_t, entry) + fprintf(header, ", %s", arg->name); + fprintf(header, ");\n"); + --indentation; + indent(header, 0); + fprintf(header, "}\n"); + + fprintf(header, "#else\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); + write_args(header, args, iface->name, 2, TRUE); fprintf(header, ") = 0;\n"); + + if (is_aggregate_return(func)) + fprintf(header, "#endif\n"); fprintf(header, "\n"); } }