This MR improves widl with : - fixes a segfault when inheriting from an incomplete interface (prints an error message instead), - supports (for C++) inheriting from interfaces which are declared after the declaration of the derived interface.
From: Eric Pouech epouech@codeweavers.com
Widl segfaults in .idl header translation when inherited interface is just a forward declaration (or when the intended declaration exists but with a typo in its name).
Print an error message instead.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- tools/widl/parser.y | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/tools/widl/parser.y b/tools/widl/parser.y index 54b143637cf..c612ed84c3e 100644 --- a/tools/widl/parser.y +++ b/tools/widl/parser.y @@ -2826,6 +2826,12 @@ static void check_all_user_types(const statement_list_t *stmts) !is_local(stmt->u.type->attrs)) { const statement_t *stmt_func; + const type_t *type = stmt->u.type; + if (type->details.iface && type->details.iface->inherit && !type_is_complete(type->details.iface->inherit)) + error_at( &type->where, + "interface %s can't inherit from incomplete interface %s\n", + type->name, type->details.iface->inherit->name); + STATEMENTS_FOR_EACH_FUNC(stmt_func, type_iface_get_stmts(stmt->u.type)) { const var_t *func = stmt_func->u.var; if (type_function_get_args(func->declspec.type))
From: Eric Pouech epouech@codeweavers.com
(pure refactoring, used in next patch)
Signed-off-by: Eric Pouech epouech@codeweavers.com --- tools/widl/header.c | 86 +++++++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 39 deletions(-)
diff --git a/tools/widl/header.c b/tools/widl/header.c index e2ce883b788..55da9e0d3f8 100644 --- a/tools/widl/header.c +++ b/tools/widl/header.c @@ -1977,6 +1977,52 @@ static void write_forward_decls(FILE *header, const statement_list_t *stmts) } }
+static void write_header_stmts(FILE *header, const statement_list_t *stmts, const type_t *iface, int ignore_funcs); + +static void write_type(FILE *header, /*const */ type_t *type, bool is_defined) +{ + if (type_get_type(type) == TYPE_INTERFACE || type_get_type(type) == TYPE_DELEGATE) + { + type_t *iface = type, *async_iface; + + if (type_get_type(type) == TYPE_DELEGATE) iface = type_delegate_get_iface(iface); + async_iface = type_iface_get_async_iface(iface); + if (is_object(iface)) is_object_interface++; + if (is_attr(type->attrs, ATTR_DISPINTERFACE) || is_object(type)) + { + write_com_interface_start(header, iface); + write_header_stmts(header, type_iface_get_stmts(iface), type, TRUE); + write_com_interface_end(header, iface); + if (async_iface) + { + write_com_interface_start(header, async_iface); + write_com_interface_end(header, async_iface); + } + } + else + { + write_rpc_interface_start(header, iface); + write_header_stmts(header, type_iface_get_stmts(iface), iface, FALSE); + write_rpc_interface_end(header, iface); + } + if (is_object(iface)) is_object_interface--; + } + else if (type_get_type(type) == TYPE_COCLASS) + write_coclass(header, type); + else if (type_get_type(type) == TYPE_APICONTRACT) + write_apicontract(header, type); + else if (type_get_type(type) == TYPE_RUNTIMECLASS) + write_runtimeclass(header, type); + else if (type_get_type(type) != TYPE_PARAMETERIZED_TYPE) + write_type_definition(header, type, is_defined); + else + { + is_object_interface++; + write_parameterized_implementation(header, type, is_defined); + is_object_interface--; + } +} + static void write_header_stmts(FILE *header, const statement_list_t *stmts, const type_t *iface, int ignore_funcs) { const statement_t *stmt; @@ -1985,45 +2031,7 @@ static void write_header_stmts(FILE *header, const statement_list_t *stmts, cons switch (stmt->type) { case STMT_TYPE: - if (type_get_type(stmt->u.type) == TYPE_INTERFACE || type_get_type(stmt->u.type) == TYPE_DELEGATE) - { - type_t *iface = stmt->u.type, *async_iface; - if (type_get_type(stmt->u.type) == TYPE_DELEGATE) iface = type_delegate_get_iface(iface); - async_iface = type_iface_get_async_iface(iface); - if (is_object(iface)) is_object_interface++; - if (is_attr(stmt->u.type->attrs, ATTR_DISPINTERFACE) || is_object(stmt->u.type)) - { - write_com_interface_start(header, iface); - write_header_stmts(header, type_iface_get_stmts(iface), stmt->u.type, TRUE); - write_com_interface_end(header, iface); - if (async_iface) - { - write_com_interface_start(header, async_iface); - write_com_interface_end(header, async_iface); - } - } - else - { - write_rpc_interface_start(header, iface); - write_header_stmts(header, type_iface_get_stmts(iface), iface, FALSE); - write_rpc_interface_end(header, iface); - } - if (is_object(iface)) is_object_interface--; - } - else if (type_get_type(stmt->u.type) == TYPE_COCLASS) - write_coclass(header, stmt->u.type); - else if (type_get_type(stmt->u.type) == TYPE_APICONTRACT) - write_apicontract(header, stmt->u.type); - else if (type_get_type(stmt->u.type) == TYPE_RUNTIMECLASS) - write_runtimeclass(header, stmt->u.type); - else if (type_get_type(stmt->u.type) != TYPE_PARAMETERIZED_TYPE) - write_type_definition(header, stmt->u.type, stmt->is_defined); - else - { - is_object_interface++; - write_parameterized_implementation(header, stmt->u.type, stmt->is_defined); - is_object_interface--; - } + write_type(header, stmt->u.type, stmt->is_defined); break; case STMT_TYPEREF: /* FIXME: shouldn't write out forward declarations for undefined
From: Eric Pouech epouech@codeweavers.com
If interface I1 inherits from interface I2, midl allows I2 declaration to appear after I1's declaration in .idl file. Keeping the .idl order is fine with C binding, but doesn't work for C++ classes (class I2 must be declared before being inherited from).
So ensure inherited interface is declared in header generation before using it.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- tools/widl/header.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/tools/widl/header.c b/tools/widl/header.c index 55da9e0d3f8..a14d3113869 100644 --- a/tools/widl/header.c +++ b/tools/widl/header.c @@ -1986,6 +1986,13 @@ static void write_type(FILE *header, /*const */ type_t *type, bool is_defined) type_t *iface = type, *async_iface;
if (type_get_type(type) == TYPE_DELEGATE) iface = type_delegate_get_iface(iface); + else /* TYPE_INTERFACE */ + { + if (iface->written) return; + if (iface->details.iface && iface->details.iface->inherit && + type_iface_get_inherit(iface->details.iface->inherit) /* skip IUnknown */) + write_type(header, type->details.iface->inherit, true); + } async_iface = type_iface_get_async_iface(iface); if (is_object(iface)) is_object_interface++; if (is_attr(type->attrs, ATTR_DISPINTERFACE) || is_object(type)) @@ -2006,6 +2013,7 @@ static void write_type(FILE *header, /*const */ type_t *type, bool is_defined) write_rpc_interface_end(header, iface); } if (is_object(iface)) is_object_interface--; + if (type_get_type(type) == TYPE_INTERFACE) type->written = true; } else if (type_get_type(type) == TYPE_COCLASS) write_coclass(header, type);
Rémi Bernon (@rbernon) commented about tools/widl/header.c:
type_t *iface = type, *async_iface; if (type_get_type(type) == TYPE_DELEGATE) iface = type_delegate_get_iface(iface);
- else /* TYPE_INTERFACE */
- {
if (iface->written) return;
if (iface->details.iface && iface->details.iface->inherit &&
type_iface_get_inherit(iface->details.iface->inherit) /* skip IUnknown */)
write_type(header, type->details.iface->inherit, true);
It might be more interesting to only extract the interface specific bits into a write_interface helper instead, as there's already some helpers for other kind of types, and as inherited type can only be an interface.
Rémi Bernon (@rbernon) commented about tools/widl/header.c:
} }
-static void write_header_stmts(FILE *header, const statement_list_t *stmts, const type_t *iface, int ignore_funcs) -{
- const statement_t *stmt;
- if (stmts) LIST_FOR_EACH_ENTRY( stmt, stmts, const statement_t, entry )
- {
- switch (stmt->type)
+static void write_header_stmts(FILE *header, const statement_list_t *stmts, const type_t *iface, int ignore_funcs);
+static void write_type(FILE *header, /*const */ type_t *type, bool is_defined)
Let's fix indentation (4 spaces) and style (as it seems we're adopting ntdll style with space in parentheses for new widl code) while we're moving things.
Rémi Bernon (@rbernon) commented about tools/widl/parser.y:
!is_local(stmt->u.type->attrs)) { const statement_t *stmt_func;
const type_t *type = stmt->u.type;
if (type->details.iface && type->details.iface->inherit && !type_is_complete(type->details.iface->inherit))
error_at( &type->where,
"interface %s can't inherit from incomplete interface %s\n",
type->name, type->details.iface->inherit->name);
Nit: let's avoid overhangs, we're not Sylvester Stallone.
```suggestion:-2+0 error_at( &type->where, "interface %s can't inherit from incomplete interface %s\n", type->name, type->details.iface->inherit->name ); ```