};
static struct pending_param pending_params[MAX_PENDING_PARAMS];
+
static int pending_param_count = 0;
static int declarator_depth = 0;
+static int preserve_pending_params = 0;
static int local_symbol_exists_in_current_scope (const char *name, int start_count);
}
+static int find_pending_param_from (const char *name, int start) {
+
+ int i;
+
+ if (!name) {
+ return -1;
+ }
+
+ if (start < 0) {
+ start = 0;
+ }
+
+ for (i = start; i < pending_param_count; i++) {
+
+ if (pending_params[i].name && strcmp (pending_params[i].name, name) == 0) {
+ return i;
+ }
+
+ }
+
+ return -1;
+
+}
+
+static int find_pending_param (const char *name) {
+ return find_pending_param_from (name, 0);
+}
+
+static void update_pending_param (const char *name, int size, int align, int is_unsigned, int is_floating, int pointer_depth, int pointed_size) {
+
+ int i = find_pending_param (name);
+
+ if (i < 0) {
+ return;
+ }
+
+ if (pointer_depth > 0 && parsed_type_is_aggregate && parsed_type_size > (DATA_PTR & 0x1f) && pointed_size <= (DATA_PTR & 0x1f)) {
+ pointed_size = parsed_type_size;
+ }
+
+ if (size < 1) {
+ size = DATA_INT & 0x1f;
+ }
+
+ if (align < 1) {
+ align = type_alignment (size);
+ }
+
+ pending_params[i].size = size;
+ pending_params[i].align = align;
+ pending_params[i].is_unsigned = is_unsigned ? 1 : 0;
+ pending_params[i].is_floating = is_floating ? 1 : 0;
+ pending_params[i].pointer_depth = pointer_depth;
+ pending_params[i].pointed_size = pointed_size > 0 ? pointed_size : 0;
+
+ if (pending_params[i].pointed_tag_name) {
+
+ free (pending_params[i].pointed_tag_name);
+ pending_params[i].pointed_tag_name = 0;
+
+ }
+
+ if (pointer_depth > 0 && parsed_type_tag_name[0]) {
+ pending_params[i].pointed_tag_name = xstrdup (parsed_type_tag_name);
+ }
+
+}
+
+static void remove_duplicate_pending_params (void) {
+
+ int i;
+
+ for (i = 0; i < pending_param_count; i++) {
+
+ int j;
+
+ if (!pending_params[i].name) {
+ continue;
+ }
+
+ j = i + 1;
+
+ while (j < pending_param_count) {
+
+ if (pending_params[j].name && strcmp (pending_params[i].name, pending_params[j].name) == 0) {
+
+ int k;
+
+ if (pending_params[j].name) {
+ free (pending_params[j].name);
+ }
+
+ if (pending_params[j].pointed_tag_name) {
+ free (pending_params[j].pointed_tag_name);
+ }
+
+ for (k = j; k + 1 < pending_param_count; k++) {
+ pending_params[k] = pending_params[k + 1];
+ }
+
+ pending_param_count--;
+
+ pending_params[pending_param_count].name = 0;
+ pending_params[pending_param_count].size = 0;
+ pending_params[pending_param_count].align = 0;
+ pending_params[pending_param_count].is_unsigned = 0;
+ pending_params[pending_param_count].is_floating = 0;
+ pending_params[pending_param_count].pointer_depth = 0;
+ pending_params[pending_param_count].pointed_size = 0;
+ pending_params[pending_param_count].pointed_tag_name = 0;
+
+ continue;
+
+ }
+
+ j++;
+
+ }
+
+ }
+
+}
+
static void copy_pending_params_to_global_symbol (const char *name) {
int i = find_global_symbol (name);
if (_accept (TOK_LPAREN)) {
+ int old_style_param_start = pending_param_count;
declarator_has_function = 1;
if (tok.kind != TOK_RPAREN) {
get_token ();
if (declarator_depth == 1) {
- add_pending_param (param_name, param_size, type_alignment (param_size), 0, 0, unknown_typedef_pointer ? 1 : 0, DATA_INT & 0x1f);
+
+ if (find_pending_param_from (param_name, old_style_param_start) >= 0) {
+ report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate parameter '%s'", param_name);
+ } else {
+ add_pending_param (param_name, param_size, type_alignment (param_size), 0, 0, unknown_typedef_pointer ? 1 : 0, DATA_INT & 0x1f);
+ }
+
}
free (param_name);
}
if (!consumed_as_prototype_param) {
+
+ if (declarator_depth == 1) {
+
+ if (find_pending_param_from (maybe_type_name, old_style_param_start) >= 0) {
+ report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate parameter '%s'", maybe_type_name);
+ } else {
+ add_pending_param (maybe_type_name, DATA_INT & 0x1f, type_alignment (DATA_INT & 0x1f), 0, 0, 0, 0);
+ }
+
+ }
+
declarator_function_param_count++;
+
}
if (maybe_type_name) {
if (top_level) {
- clear_pending_params ();
+ if (!preserve_pending_params) {
+ clear_pending_params ();
+ }
capture_declarator_name_location = 1;
+
captured_declarator_name_location = 0;
captured_declarator_name_start = 0;
captured_declarator_name_caret = 0;
while (is_type_start (tok.kind)) {
+ int param_base_size;
+
parse_type_spec ();
+ param_base_size = parsed_type_size;
for (;;) {
char *name = 0;
+
+ int param_size;
+ int param_pointer_depth;
+
+ preserve_pending_params++;
parse_declarator (&name);
+ preserve_pending_params--;
if (name) {
+
+ param_size = (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef) ? DATA_PTR : declarator_object_size (param_base_size);
+ param_pointer_depth = declarator_pointer_depth;
+
+ if ((declarator_has_array || declarator_has_function || parsed_type_is_array_typedef) && param_pointer_depth < 1) {
+ param_pointer_depth = 1;
+ }
+
+ update_pending_param (name, param_size, type_alignment (param_size),
+ (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef ? 0 : parsed_type_is_unsigned),
+ (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef ? 0 : parsed_type_is_floating),
+ param_pointer_depth, parsed_type_is_aggregate ? parsed_type_size : (parsed_type_size & 0x1f));
+
free (name);
+
}
if (_accept (TOK_ASSIGN)) {
set_global_symbol_returns_void (name, return_is_void);
set_global_symbol_param_count (name, saved_declarator_function_param_count, saved_declarator_function_has_prototype || saved_declarator_function_param_count > 0, saved_declarator_function_is_variadic);
- copy_pending_params_to_global_symbol (name);
-
if (is_inline) {
remember_inline_function_signature (name, saved_declarator_function_param_count, saved_declarator_function_has_prototype || saved_declarator_function_param_count > 0,
current_function_returns_aggregate = (!return_is_void && !return_is_floating && return_size > (DATA_LLONG & 0x1f));
current_function_has_return_statement = 0;
+ parse_old_style_param_decls ();
+ remove_duplicate_pending_params ();
+
+ /*
+ * Old-style definitions start with an identifier list, so the first
+ * function-symbol install only knows the default int-sized parameter
+ * placeholders. The declaration list between ')' and '{' is what gives
+ * those parameters their real types. Refresh the saved call signature
+ * after that list has been parsed, otherwise later calls in the same
+ * translation unit pass 64-bit parameters as single words.
+ */
+ if (emit_body && should_emit) {
+ copy_pending_params_to_global_symbol (name);
+ }
+
reset_local_symbols ();
reset_goto_labels ();
emit_function_start (name, !emit_public);
- parse_old_style_param_decls ();
parse_block ();
check_goto_labels ();
}
+ clear_pending_params ();
+
+ declarator_function_param_count = 0;
+ declarator_function_has_prototype = 0;
+ declarator_function_is_variadic = 0;
+
if (tok.kind != TOK_RPAREN) {
- for (;;) {
+ int old_style_param_start = pending_param_count;
- if (token_is_ident ()) {
+ for (;;) {
+
+ if (tok.kind == TOK_ELLIPSIS) {
- add_pending_param (tok.ident, DATA_INT & 0x1f, type_alignment (DATA_INT & 0x1f), 0, 0, 0, 0);
+ declarator_function_is_variadic = 1;
+ declarator_function_has_prototype = 1;
+
+ get_token ();
+
+ } else if (is_type_start (tok.kind)) {
+
+ int param_base_size;
+ int param_size;
+ int param_pointer_depth;
+ int saved_function_param_count;
+
+ int count_this_param = 0;
+ int saw_void_param_list = 0;
+
+ char *param_name = 0;
+
+ parse_type_spec ();
+ param_base_size = parsed_type_size;
+
+ preserve_pending_params++;
+
+ declarator_is_pointer = 0;
+ declarator_pointer_depth = 0;
+ declarator_has_array = 0;
+ declarator_has_function = 0;
+ declarator_function_is_pointer = 0;
+ declarator_array_unsized = 0;
+ declarator_array_count = 1;
+ declarator_last_array_count = 1;
+
+ if (parsed_type_only_qualifiers && token_is_ident ()) {
+ get_token ();
+ }
+
+ saved_function_param_count = declarator_function_param_count;
+
+ if (tok.kind != TOK_COMMA && tok.kind != TOK_RPAREN) {
+ parse_declarator (¶m_name);
+ }
+
+ preserve_pending_params--;
+
+ if (!parsed_type_is_void || declarator_is_pointer || declarator_has_array || declarator_has_function || param_name) {
+
+ count_this_param = 1;
+
+ param_size = (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef) ? DATA_PTR : declarator_object_size (param_base_size);
+ param_pointer_depth = declarator_pointer_depth;
+
+ if ((declarator_has_array || declarator_has_function || parsed_type_is_array_typedef) && param_pointer_depth < 1) {
+ param_pointer_depth = 1;
+ }
+
+ if (param_name && find_pending_param_from (param_name, old_style_param_start) >= 0) {
+ report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate parameter '%s'", param_name);
+ } else {
+
+ add_pending_param (param_name, param_size, type_alignment (param_size),
+ (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef ? 0 : parsed_type_is_unsigned),
+ (declarator_is_pointer || declarator_has_array || declarator_has_function || parsed_type_is_array_typedef ? 0 : parsed_type_is_floating),
+ param_pointer_depth, parsed_type_is_aggregate ? parsed_type_size : (parsed_type_size & 0x1f));
+
+ }
+
+ } else {
+ saw_void_param_list = 1;
+ }
+
+ if (param_name) {
+ free (param_name);
+ }
+
+ declarator_function_param_count = saved_function_param_count + (count_this_param ? 1 : 0);
+ declarator_function_has_prototype = declarator_function_has_prototype || count_this_param || saw_void_param_list;
+
+ } else if (token_is_ident ()) {
+
+ if (find_pending_param_from (tok.ident, old_style_param_start) >= 0) {
+ report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.start, tok.caret, "duplicate parameter '%s'", tok.ident);
+ } else {
+
+ add_pending_param (tok.ident, DATA_INT & 0x1f, type_alignment (DATA_INT & 0x1f), 0, 0, 0, 0);
+ declarator_function_param_count++;
+
+ }
+
get_token ();
} else {
}
- if (name && tok.kind == TOK_LBRACE) {
+ if (name && declarator_has_function && (tok.kind == TOK_LBRACE || is_type_start (tok.kind))) {
if (parsed_dllexport) {