diff --git a/tcc.h b/tcc.h index ef69ef59..04e68049 100644 --- a/tcc.h +++ b/tcc.h @@ -643,6 +643,7 @@ typedef struct DLLReference { /* type_decl() types */ #define TYPE_ABSTRACT 1 /* type without variable */ #define TYPE_DIRECT 2 /* type with variable */ +#define TYPE_PARAM 4 /* type declares function parameter */ #define IO_BUF_SIZE 8192 diff --git a/tccelf.c b/tccelf.c index 69176749..83146fdd 100644 --- a/tccelf.c +++ b/tccelf.c @@ -2424,7 +2424,7 @@ static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum, unlink(filename); fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); if (fd < 0 || (f = fdopen(fd, "wb")) == NULL) { - tcc_error_noabort("could not write or fdopen '%s'", filename); + tcc_error_noabort("could not write '%s: %s'", filename, strerror(errno)); return -1; } if (s1->verbose) diff --git a/tccgen.c b/tccgen.c index 67e205b2..f4dc0fc2 100644 --- a/tccgen.c +++ b/tccgen.c @@ -5351,40 +5351,44 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td) if (tok == '(') { /* function type, or recursive declarator (return if so) */ next(); - if (td && !(td & TYPE_ABSTRACT)) + if (TYPE_DIRECT == (td & (TYPE_DIRECT|TYPE_ABSTRACT))) return 0; if (tok == ')') l = 0; else if (parse_btype(&pt, &ad1)) l = FUNC_NEW; - else if (td) { + else if (td & (TYPE_DIRECT|TYPE_ABSTRACT)) { merge_attr (ad, &ad1); return 0; } else l = FUNC_OLD; + first = NULL; plast = &first; arg_size = 0; + ++local_scope; if (l) { for(;;) { /* read param name and compute offset */ if (l != FUNC_OLD) { if ((pt.t & VT_BTYPE) == VT_VOID && tok == ')') break; - type_decl(&pt, &ad1, &n, TYPE_DIRECT | TYPE_ABSTRACT); + type_decl(&pt, &ad1, &n, TYPE_DIRECT | TYPE_ABSTRACT | TYPE_PARAM); if ((pt.t & VT_BTYPE) == VT_VOID) tcc_error("parameter declared as void"); + if (n == 0) + n = SYM_FIELD; } else { n = tok; - if (n < TOK_UIDENT) - expect("identifier"); pt.t = VT_VOID; /* invalid type */ pt.ref = NULL; next(); } + if (n < TOK_UIDENT) + expect("identifier"); convert_parameter_type(&pt); arg_size += (type_size(&pt, &align) + PTR_SIZE - 1) / PTR_SIZE; - s = sym_push(n | SYM_FIELD, &pt, 0, 0); + s = sym_push(n, &pt, 0, 0); *plast = s; plast = &s->next; if (tok == ')') @@ -5402,6 +5406,13 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td) /* if no parameters, then old type prototype */ l = FUNC_OLD; skip(')'); + /* remove parameter symbols from token table, keep on stack */ + if (first) { + sym_pop(local_stack ? &local_stack : &global_stack, first->prev, 1); + for (s = first; s; s = s->next) + s->v |= SYM_FIELD; + } + --local_scope; /* NOTE: const is ignored in returned type as it has a special meaning in gcc / C++ */ type->t &= ~VT_CONSTANT; @@ -5426,7 +5437,9 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td) int saved_nocode_wanted = nocode_wanted; /* array definition */ next(); - while (1) { + n = -1; + t1 = 0; + if (td & TYPE_PARAM) while (1) { /* XXX The optional type-quals and static should only be accepted in parameter decls. The '*' as well, and then even only in prototypes (not function defs). */ @@ -5441,11 +5454,13 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td) default: break; } - break; - } - n = -1; - t1 = 0; - if (tok != ']') { + if (tok != ']') { + nocode_wanted = 1; + gexpr(), vpop(); + } + break; + + } else if (tok != ']') { if (!local_stack || (storage & VT_STATIC)) vpushi(expr_const()); else { @@ -5469,7 +5484,7 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td) } skip(']'); /* parse next post type */ - post_type(type, ad, storage, 0); + post_type(type, ad, storage, td & ~(TYPE_DIRECT|TYPE_ABSTRACT)); if ((type->t & VT_BTYPE) == VT_FUNC) tcc_error("declaration of an array of functions"); @@ -5580,7 +5595,7 @@ static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td) expect("identifier"); *v = 0; } - post_type(post, ad, storage, 0); + post_type(post, ad, storage, td & ~(TYPE_DIRECT|TYPE_ABSTRACT)); parse_attribute(ad); type->t |= storage; return ret; @@ -5973,7 +5988,9 @@ ST_FUNC void unary(void) outside, so any reactivation of code emission (from labels or loop heads) can be disabled again after the end of it. */ block(1); - nocode_wanted = saved_nocode_wanted; + /* or'ing to keep however possible CODE_OFF() from e.g. "return 0;" + in the statement expression */ + nocode_wanted |= saved_nocode_wanted; skip(')'); } else { gexpr(); diff --git a/tests/tests2/60_errors_and_warnings.c b/tests/tests2/60_errors_and_warnings.c index 8a91512a..9cede328 100644 --- a/tests/tests2/60_errors_and_warnings.c +++ b/tests/tests2/60_errors_and_warnings.c @@ -416,4 +416,30 @@ void func() fink(); } __attribute__((stuff)) int fink() {return 0;} + +#elif defined test_invalid_funcparam_1 +void func(int a, int b, int a); + +#elif defined test_invalid_funcparam_2 +void func(int a, int if); + +#elif defined test_array_funcparam +int amain(int argc, char *argv[static argc + 1]) +{ + int i; + int printf(const char*, ...); + for (i = 0; i < argc; ++i) + printf("arg[%d] = \"%s\"\n", i, argv[i]); + return 0; +} +int main() +{ + return amain(2, (char *[]){ "X", "Y", 0 }); +} + +#elif defined test_return_from_statement_expr +int f() { ({ return 78; }); } +int main() { return f(); } + +/******************************************************************/ #endif diff --git a/tests/tests2/60_errors_and_warnings.expect b/tests/tests2/60_errors_and_warnings.expect index a9dfa2d1..ac8a9653 100644 --- a/tests/tests2/60_errors_and_warnings.expect +++ b/tests/tests2/60_errors_and_warnings.expect @@ -203,3 +203,16 @@ bar : 3 ; 3 [test_switch_W4] 60_errors_and_warnings.c:416: warning: implicit declaration of function 'fink' 60_errors_and_warnings.c:418: error: 'stuff' attribute ignored + +[test_invalid_funcparam_1] +60_errors_and_warnings.c:421: error: redeclaration of 'a' + +[test_invalid_funcparam_2] +60_errors_and_warnings.c:424: error: identifier expected + +[test_array_funcparam] +arg[0] = "X" +arg[1] = "Y" + +[test_return_from_statement_expr] +[returns 78]