diff --git a/tools/widl/header.c b/tools/widl/header.c index 5bf5d09ef14..dd1186845bf 100644 --- a/tools/widl/header.c +++ b/tools/widl/header.c @@ -285,16 +285,31 @@ int needs_space_after(type_t *t) (!is_ptr(t) && (!is_array(t) || !type_array_is_decl_as_ptr(t) || t->name))); } +int decl_needs_parens(const type_t *t) +{ + if (type_is_alias(t)) + return FALSE; + if (is_array(t) && !type_array_is_decl_as_ptr(t)) + return TRUE; + return is_func(t); +} + static void write_pointer_left(FILE *h, type_t *ref) { if (needs_space_after(ref)) fprintf(h, " "); - if (!type_is_alias(ref) && is_array(ref) && !type_array_is_decl_as_ptr(ref)) + if (decl_needs_parens(ref)) fprintf(h, "("); + if (type_get_type_detect_alias(ref) == TYPE_FUNCTION) + { + const char *callconv = get_attrp(ref->attrs, ATTR_CALLCONV); + if (!callconv && is_object_interface) callconv = "STDMETHODCALLTYPE"; + if (callconv) fprintf(h, "%s ", callconv); + } fprintf(h, "*"); } -void write_type_left(FILE *h, const decl_spec_t *ds, enum name_type name_type, int declonly) +void write_type_left(FILE *h, const decl_spec_t *ds, enum name_type name_type, int declonly, int write_callconv) { type_t *t = ds->type; const char *name; @@ -352,7 +367,7 @@ void write_type_left(FILE *h, const decl_spec_t *ds, enum name_type name_type, i break; case TYPE_POINTER: { - write_type_left(h, type_pointer_get_ref(t), name_type, declonly); + write_type_left(h, type_pointer_get_ref(t), name_type, declonly, FALSE); write_pointer_left(h, type_pointer_get_ref_type(t)); if (is_attr(t->attrs, ATTR_CONST)) fprintf(h, "const "); break; @@ -362,11 +377,28 @@ void write_type_left(FILE *h, const decl_spec_t *ds, enum name_type name_type, i fprintf(h, "%s", t->name); else { - write_type_left(h, type_array_get_element(t), name_type, declonly); + write_type_left(h, type_array_get_element(t), name_type, declonly, !type_array_is_decl_as_ptr(t)); if (type_array_is_decl_as_ptr(t)) write_pointer_left(h, type_array_get_element_type(t)); } break; + case TYPE_FUNCTION: + { + if (is_attr(t->attrs, ATTR_INLINE)) fprintf(h, "inline "); + write_type_left(h, type_function_get_ret(t), name_type, declonly, TRUE); + + /* A pointer to a function has to write the calling convention inside + * the parentheses. There's no way to handle that here, so we have to + * use an extra parameter to tell us whether to write the calling + * convention or not. */ + if (write_callconv) + { + const char *callconv = get_attrp(t->attrs, ATTR_CALLCONV); + if (!callconv && is_object_interface) callconv = "STDMETHODCALLTYPE"; + if (callconv) fprintf(h, " %s ", callconv); + } + break; + } case TYPE_BASIC: if (type_basic_get_type(t) != TYPE_BASIC_INT32 && type_basic_get_type(t) != TYPE_BASIC_INT64 && @@ -426,11 +458,10 @@ void write_type_left(FILE *h, const decl_spec_t *ds, enum name_type name_type, i case TYPE_BITFIELD: { const decl_spec_t ds = {.type = type_bitfield_get_field(t)}; - write_type_left(h, &ds, name_type, declonly); + write_type_left(h, &ds, name_type, declonly, TRUE); break; } case TYPE_ALIAS: - case TYPE_FUNCTION: /* handled elsewhere */ assert(0); break; @@ -450,7 +481,7 @@ void write_type_right(FILE *h, type_t *t, int is_field) type_t *elem = type_array_get_element_type(t); if (type_array_is_decl_as_ptr(t)) { - if (!type_is_alias(elem) && is_array(elem) && !type_array_is_decl_as_ptr(elem)) + if (decl_needs_parens(elem)) fprintf(h, ")"); } else @@ -463,10 +494,22 @@ void write_type_right(FILE *h, type_t *t, int is_field) write_type_right(h, elem, FALSE); break; } + case TYPE_FUNCTION: + { + const var_list_t *args = type_function_get_args(t); + fputc('(', h); + if (args) + write_args(h, args, NULL, 0, FALSE); + else + fprintf(h, "void"); + fputc(')', h); + write_type_right(h, type_function_get_rettype(t), FALSE); + break; + } case TYPE_POINTER: { type_t *ref = type_pointer_get_ref_type(t); - if (!type_is_alias(ref) && is_array(ref) && !type_array_is_decl_as_ptr(ref)) + if (decl_needs_parens(ref)) fprintf(h, ")"); write_type_right(h, ref, FALSE); break; @@ -483,7 +526,6 @@ void write_type_right(FILE *h, type_t *t, int is_field) case TYPE_ALIAS: case TYPE_MODULE: case TYPE_COCLASS: - case TYPE_FUNCTION: case TYPE_INTERFACE: break; } @@ -491,46 +533,17 @@ void write_type_right(FILE *h, type_t *t, int is_field) static void write_type_v(FILE *h, const decl_spec_t *ds, int is_field, int declonly, const char *name) { - type_t *t = ds->type, *pt = NULL; - int ptr_level = 0; + type_t *t = ds->type; - if (!h) return; + if (!h) return; - if (t) { - for (pt = t; is_ptr(pt); pt = type_pointer_get_ref_type(pt), ptr_level++) - ; + if (t) + write_type_left(h, ds, NAME_DEFAULT, declonly, TRUE); - if (type_get_type_detect_alias(pt) == TYPE_FUNCTION) { - int i; - const char *callconv = get_attrp(pt->attrs, ATTR_CALLCONV); - if (!callconv && is_object_interface) callconv = "STDMETHODCALLTYPE"; - if (is_attr(pt->attrs, ATTR_INLINE)) fprintf(h, "inline "); - write_type_left(h, type_function_get_ret(pt), NAME_DEFAULT, declonly); - fputc(' ', h); - if (ptr_level) fputc('(', h); - if (callconv) fprintf(h, "%s ", callconv); - for (i = 0; i < ptr_level; i++) - fputc('*', h); - } else - write_type_left(h, ds, NAME_DEFAULT, declonly); - } + if (name) fprintf(h, "%s%s", !t || needs_space_after(t) ? " " : "", name ); - if (name) fprintf(h, "%s%s", !t || needs_space_after(t) ? " " : "", name ); - - if (t) { - if (type_get_type_detect_alias(pt) == TYPE_FUNCTION) { - const var_list_t *args = type_function_get_args(pt); - - if (ptr_level) fputc(')', h); - fputc('(', h); - if (args) - write_args(h, args, NULL, 0, FALSE); - else - fprintf(h, "void"); - fputc(')', h); - } else - write_type_right(h, t, is_field); - } + if (t) + write_type_right(h, t, is_field); } static void write_type_def_or_decl(FILE *f, const decl_spec_t *t, int field, const char *name) @@ -550,14 +563,14 @@ static void write_type_definition(FILE *f, type_t *t) write_namespace_start(f, t->namespace); } indent(f, 0); - write_type_left(f, &ds, NAME_DEFAULT, FALSE); + write_type_left(f, &ds, NAME_DEFAULT, FALSE, TRUE); 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, &ds, NAME_C, FALSE); + write_type_left(f, &ds, NAME_C, FALSE, TRUE); fprintf(f, ";\n"); fprintf(f, "#endif\n\n"); } @@ -570,7 +583,7 @@ void write_type_decl(FILE *f, const decl_spec_t *t, const char *name) void write_type_decl_left(FILE *f, const decl_spec_t *ds) { - write_type_left(f, ds, NAME_DEFAULT, TRUE); + write_type_left(f, ds, NAME_DEFAULT, TRUE, TRUE); } static int user_type_registered(const char *name) diff --git a/tools/widl/header.h b/tools/widl/header.h index e047e4e2e4b..cebfd83fe4c 100644 --- a/tools/widl/header.h +++ b/tools/widl/header.h @@ -29,7 +29,7 @@ extern int is_attr(const attr_list_t *list, enum attr_type t); extern void *get_attrp(const attr_list_t *list, enum attr_type t); extern unsigned int get_attrv(const attr_list_t *list, enum attr_type t); extern const char* get_name(const var_t *v); -extern void write_type_left(FILE *h, const decl_spec_t *ds, enum name_type name_type, int declonly); +extern void write_type_left(FILE *h, const decl_spec_t *ds, enum name_type name_type, int declonly, int write_callconv); extern void write_type_right(FILE *h, type_t *t, int is_field); extern void write_type_decl(FILE *f, const decl_spec_t *t, const char *name); extern void write_type_decl_left(FILE *f, const decl_spec_t *ds); @@ -66,6 +66,11 @@ static inline int is_array(const type_t *t) return type_get_type(t) == TYPE_ARRAY; } +static inline int is_func(const type_t *t) +{ + return type_get_type(t) == TYPE_FUNCTION; +} + static inline int is_void(const type_t *t) { return type_get_type(t) == TYPE_VOID; diff --git a/tools/widl/parser.y b/tools/widl/parser.y index 038b40725c0..9cfcd7f30f9 100644 --- a/tools/widl/parser.y +++ b/tools/widl/parser.y @@ -75,6 +75,7 @@ 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_chain_type(type_t *chain, type_t *type); +static void append_chain_callconv(type_t *chain, char *callconv); 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); @@ -975,8 +976,7 @@ decl_spec_no_type: declarator: '*' m_type_qual_list declarator %prec PPTR { $$ = $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)); } + | callconv declarator { $$ = $2; append_chain_callconv($$->type, $1); } | direct_declarator ; @@ -984,18 +984,14 @@ direct_declarator: ident { $$ = make_declarator($1); } | '(' declarator ')' { $$ = $2; } | direct_declarator array { $$ = $1; $$->type = append_array($$->type, $2); } - | direct_declarator '(' m_args ')' { $$ = $1; - $$->func_type = append_chain_type($$->type, type_new_function($3)); - $$->type = NULL; - } + | direct_declarator '(' m_args ')' { $$ = $1; $$->type = append_chain_type($$->type, type_new_function($3)); } ; /* abstract declarator */ abstract_declarator: '*' m_type_qual_list m_abstract_declarator %prec PPTR { $$ = $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)); } + | callconv m_abstract_declarator { $$ = $2; append_chain_callconv($$->type, $1); } | abstract_direct_declarator ; @@ -1003,8 +999,7 @@ abstract_declarator: abstract_declarator_no_direct: '*' m_type_qual_list m_any_declarator %prec PPTR { $$ = $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)); } + | callconv m_any_declarator { $$ = $2; append_chain_callconv($$->type, $1); } ; /* abstract declarator or empty */ @@ -1019,13 +1014,11 @@ abstract_direct_declarator: | array { $$ = make_declarator(NULL); $$->type = append_array($$->type, $1); } | '(' m_args ')' { $$ = make_declarator(NULL); - $$->func_type = append_chain_type($$->type, type_new_function($2)); - $$->type = NULL; + $$->type = append_chain_type($$->type, type_new_function($2)); } | abstract_direct_declarator '(' m_args ')' { $$ = $1; - $$->func_type = append_chain_type($$->type, type_new_function($3)); - $$->type = NULL; + $$->type = append_chain_type($$->type, type_new_function($3)); } ; @@ -1033,7 +1026,7 @@ abstract_direct_declarator: any_declarator: '*' m_type_qual_list m_any_declarator %prec PPTR { $$ = $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)); } + | callconv m_any_declarator { $$ = $2; append_chain_callconv($$->type, $1); } | any_direct_declarator ; @@ -1041,7 +1034,7 @@ any_declarator: any_declarator_no_direct: '*' m_type_qual_list m_any_declarator %prec PPTR { $$ = $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)); } + | callconv m_any_declarator { $$ = $2; append_chain_callconv($$->type, $1); } ; /* abstract or non-abstract declarator or empty */ @@ -1059,13 +1052,11 @@ any_direct_declarator: | array { $$ = make_declarator(NULL); $$->type = append_array($$->type, $1); } | '(' m_args ')' { $$ = make_declarator(NULL); - $$->func_type = append_chain_type($$->type, type_new_function($2)); - $$->type = NULL; + $$->type = append_chain_type($$->type, type_new_function($2)); } | any_direct_declarator '(' m_args ')' { $$ = $1; - $$->func_type = append_chain_type($$->type, type_new_function($3)); - $$->type = NULL; + $$->type = append_chain_type($$->type, type_new_function($3)); } ; @@ -1463,34 +1454,58 @@ static int is_allowed_range_type(const type_t *type) } } -static type_t *get_array_or_ptr_ref(type_t *type) +static type_t *get_chain_ref(type_t *type) { if (is_ptr(type)) return type_pointer_get_ref_type(type); else if (is_array(type)) return type_array_get_element_type(type); + else if (is_func(type)) + return type_function_get_rettype(type); return NULL; } +static type_t *get_chain_end(type_t *type) +{ + type_t *inner; + while ((inner = get_chain_ref(type))) + type = inner; + return type; +} + 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)) - ; + chain_type = get_chain_end(chain); if (is_ptr(chain_type)) chain_type->details.pointer.ref.type = type; else if (is_array(chain_type)) chain_type->details.array.elem.type = type; + else if (is_func(chain_type)) + chain_type->details.function->retval->declspec.type = type; else assert(0); + if (!is_func(chain_type)) + type->attrs = move_attr(type->attrs, chain_type->attrs, ATTR_CALLCONV); + return chain; } +static void append_chain_callconv(type_t *chain, char *callconv) +{ + type_t *chain_end; + + if (chain && (chain_end = get_chain_end(chain))) + chain_end->attrs = append_attr(chain_end->attrs, make_attrp(ATTR_CALLCONV, callconv)); + else + error_loc("calling convention applied to non-function type\n"); +} + static warning_list_t *append_warning(warning_list_t *list, int num) { warning_t *entry; @@ -1514,21 +1529,14 @@ static var_t *declare_var(attr_list_t *attrs, decl_spec_t *decl_spec, const decl expr_list_t *lengs = get_attrp(attrs, ATTR_LENGTHIS); expr_t *dim; type_t **ptype; - type_t *func_type = decl ? decl->func_type : NULL; type_t *type = decl_spec->type; if (is_attr(type->attrs, ATTR_INLINE)) { - if (!func_type) + if (!decl || !is_func(decl->type)) error_loc("inline attribute applied to non-function type\n"); else - { - type_t *t; - /* move inline attribute from return type node to function node */ - for (t = func_type; is_ptr(t); t = type_pointer_get_ref_type(t)) - ; - t->attrs = move_attr(t->attrs, type->attrs, ATTR_INLINE); - } + decl->type->attrs = move_attr(decl->type->attrs, type->attrs, ATTR_INLINE); } /* add type onto the end of the pointers in pident->type */ @@ -1536,16 +1544,16 @@ static var_t *declare_var(attr_list_t *attrs, decl_spec_t *decl_spec, const decl v->declspec.stgclass = decl_spec->stgclass; v->attrs = attrs; + if (is_attr(type->attrs, ATTR_CALLCONV) && !is_func(type)) + error_loc("calling convention applied to non-function type\n"); + /* check for pointer attribute being applied to non-pointer, non-array * type */ if (!is_array(v->declspec.type)) { int ptr_attr = get_attrv(v->attrs, ATTR_POINTERTYPE); const type_t *ptr = NULL; - /* pointer attributes on the left side of the type belong to the function - * pointer, if one is being declared */ - type_t **pt = func_type ? &func_type : &v->declspec.type; - for (ptr = *pt; ptr && !ptr_attr; ) + for (ptr = v->declspec.type; ptr && !ptr_attr; ) { ptr_attr = get_attrv(ptr->attrs, ATTR_POINTERTYPE); if (!ptr_attr && type_is_alias(ptr)) @@ -1560,13 +1568,13 @@ static var_t *declare_var(attr_list_t *attrs, decl_spec_t *decl_spec, const decl warning_loc_info(&v->loc_info, "%s: pointer attribute applied to interface " "pointer type has no effect\n", v->name); - if (!ptr_attr && top && type_pointer_get_default_fc(*pt) != FC_RP) + if (!ptr_attr && top && type_pointer_get_default_fc(v->declspec.type) != 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 * two typeformat strings may be written depending on whether the * pointer is a toplevel parameter or not */ - *pt = duptype(*pt, 1); + v->declspec.type = duptype(v->declspec.type, 1); } } else if (ptr_attr) @@ -1667,32 +1675,6 @@ static var_t *declare_var(attr_list_t *attrs, decl_spec_t *decl_spec, const decl error_loc("%s: too many expressions in length_is attribute\n", v->name); } - /* v->type is currently pointing to the type on the left-side of the - * declaration, so we need to fix this up so that it is the return type of the - * function and make v->type point to the function side of the declaration */ - if (func_type) - { - type_t *ft, *t; - type_t *return_type = v->declspec.type; - v->declspec.type = func_type; - for (ft = v->declspec.type; is_ptr(ft); ft = type_pointer_get_ref_type(ft)) - ; - assert(type_get_type_detect_alias(ft) == TYPE_FUNCTION); - ft->details.function->retval = make_var(xstrdup("_RetVal")); - ft->details.function->retval->declspec.type = return_type; - /* move calling convention attribute, if present, from pointer nodes to - * function node */ - for (t = v->declspec.type; is_ptr(t); t = type_pointer_get_ref_type(t)) - ft->attrs = move_attr(ft->attrs, t->attrs, ATTR_CALLCONV); - } - else - { - type_t *t; - for (t = v->declspec.type; is_ptr(t); t = type_pointer_get_ref_type(t)) - if (is_attr(t->attrs, ATTR_CALLCONV)) - error_loc("calling convention applied to non-function-pointer type\n"); - } - if (decl->bits) v->declspec.type = type_new_bitfield(v->declspec.type, decl->bits); @@ -1796,7 +1778,6 @@ static declarator_t *make_declarator(var_t *var) declarator_t *d = xmalloc(sizeof(*d)); d->var = var ? var : make_var(NULL); d->type = NULL; - d->func_type = NULL; d->bits = NULL; return d; } diff --git a/tools/widl/typegen.c b/tools/widl/typegen.c index 55abd0a40cb..2e4045154fb 100644 --- a/tools/widl/typegen.c +++ b/tools/widl/typegen.c @@ -4805,7 +4805,7 @@ void write_func_param_struct( FILE *file, const type_t *iface, const type_t *fun if (args) LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry ) { print_file(file, 2, "%s", ""); - write_type_left( file, &arg->declspec, NAME_DEFAULT, TRUE ); + write_type_left( file, &arg->declspec, NAME_DEFAULT, TRUE, TRUE ); if (needs_space_after( arg->declspec.type )) fputc( ' ', file ); if (is_array( arg->declspec.type ) && !type_array_is_decl_as_ptr( arg->declspec.type )) fputc( '*', file ); @@ -4871,9 +4871,9 @@ int write_expr_eval_routines(FILE *file, const char *iface) { decl_spec_t ds = {.type = (type_t *)eval->cont_type}; print_file(file, 1, "%s", ""); - write_type_left(file, &ds, NAME_DEFAULT, TRUE); + write_type_left(file, &ds, NAME_DEFAULT, TRUE, TRUE); fprintf(file, " *%s = (", var_name); - write_type_left(file, &ds, NAME_DEFAULT, TRUE); + write_type_left(file, &ds, NAME_DEFAULT, TRUE, TRUE); fprintf(file, " *)(pStubMsg->StackTop - %u);\n", eval->baseoff); } print_file(file, 1, "pStubMsg->Offset = 0;\n"); /* FIXME */ diff --git a/tools/widl/typetree.c b/tools/widl/typetree.c index ef9a6699b20..615a758f4dc 100644 --- a/tools/widl/typetree.c +++ b/tools/widl/typetree.c @@ -172,6 +172,7 @@ type_t *type_new_function(var_list_t *args) t = make_type(TYPE_FUNCTION); t->details.function = xmalloc(sizeof(*t->details.function)); t->details.function->args = args; + t->details.function->retval = make_var(xstrdup("_RetVal")); return t; } diff --git a/tools/widl/widltypes.h b/tools/widl/widltypes.h index 3f2a719f2de..3f92192ceee 100644 --- a/tools/widl/widltypes.h +++ b/tools/widl/widltypes.h @@ -478,7 +478,6 @@ struct _var_t { struct _declarator_t { var_t *var; type_t *type; - type_t *func_type; expr_t *bits; /* parser-internal */