mirror of
https://github.com/mirror/tinycc.git
synced 2025-03-04 08:20:12 +08:00
tccgen: accept array-size expressions in function paramters
Modify function parameter parser such that symbols are put into token-table temporarily. Benefits are: - detects redefinitions, as with int foo(int a, int a); - detects reserved symbols, as with int foo(int if); - can parse expressions like int main(int argc, char *argv[argc + 1]); - doesn't fix this one int main(int argc, char *argv[++argc]); Also: fix unexpected "function might return no value" with statement expression int f() { ({ return 0; }); }
This commit is contained in:
parent
917aad3bcf
commit
ec5d94291c
1
tcc.h
1
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
|
||||
|
||||
|
2
tccelf.c
2
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)
|
||||
|
47
tccgen.c
47
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();
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
Loading…
Reference in New Issue
Block a user