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
5 changed files with 73 additions and 16 deletions
1
tcc.h
1
tcc.h
|
@ -643,6 +643,7 @@ typedef struct DLLReference {
|
||||||
/* type_decl() types */
|
/* type_decl() types */
|
||||||
#define TYPE_ABSTRACT 1 /* type without variable */
|
#define TYPE_ABSTRACT 1 /* type without variable */
|
||||||
#define TYPE_DIRECT 2 /* type with variable */
|
#define TYPE_DIRECT 2 /* type with variable */
|
||||||
|
#define TYPE_PARAM 4 /* type declares function parameter */
|
||||||
|
|
||||||
#define IO_BUF_SIZE 8192
|
#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);
|
unlink(filename);
|
||||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode);
|
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode);
|
||||||
if (fd < 0 || (f = fdopen(fd, "wb")) == NULL) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
if (s1->verbose)
|
if (s1->verbose)
|
||||||
|
|
45
tccgen.c
45
tccgen.c
|
@ -5351,40 +5351,44 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
|
||||||
if (tok == '(') {
|
if (tok == '(') {
|
||||||
/* function type, or recursive declarator (return if so) */
|
/* function type, or recursive declarator (return if so) */
|
||||||
next();
|
next();
|
||||||
if (td && !(td & TYPE_ABSTRACT))
|
if (TYPE_DIRECT == (td & (TYPE_DIRECT|TYPE_ABSTRACT)))
|
||||||
return 0;
|
return 0;
|
||||||
if (tok == ')')
|
if (tok == ')')
|
||||||
l = 0;
|
l = 0;
|
||||||
else if (parse_btype(&pt, &ad1))
|
else if (parse_btype(&pt, &ad1))
|
||||||
l = FUNC_NEW;
|
l = FUNC_NEW;
|
||||||
else if (td) {
|
else if (td & (TYPE_DIRECT|TYPE_ABSTRACT)) {
|
||||||
merge_attr (ad, &ad1);
|
merge_attr (ad, &ad1);
|
||||||
return 0;
|
return 0;
|
||||||
} else
|
} else
|
||||||
l = FUNC_OLD;
|
l = FUNC_OLD;
|
||||||
|
|
||||||
first = NULL;
|
first = NULL;
|
||||||
plast = &first;
|
plast = &first;
|
||||||
arg_size = 0;
|
arg_size = 0;
|
||||||
|
++local_scope;
|
||||||
if (l) {
|
if (l) {
|
||||||
for(;;) {
|
for(;;) {
|
||||||
/* read param name and compute offset */
|
/* read param name and compute offset */
|
||||||
if (l != FUNC_OLD) {
|
if (l != FUNC_OLD) {
|
||||||
if ((pt.t & VT_BTYPE) == VT_VOID && tok == ')')
|
if ((pt.t & VT_BTYPE) == VT_VOID && tok == ')')
|
||||||
break;
|
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)
|
if ((pt.t & VT_BTYPE) == VT_VOID)
|
||||||
tcc_error("parameter declared as void");
|
tcc_error("parameter declared as void");
|
||||||
|
if (n == 0)
|
||||||
|
n = SYM_FIELD;
|
||||||
} else {
|
} else {
|
||||||
n = tok;
|
n = tok;
|
||||||
if (n < TOK_UIDENT)
|
|
||||||
expect("identifier");
|
|
||||||
pt.t = VT_VOID; /* invalid type */
|
pt.t = VT_VOID; /* invalid type */
|
||||||
pt.ref = NULL;
|
pt.ref = NULL;
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
if (n < TOK_UIDENT)
|
||||||
|
expect("identifier");
|
||||||
convert_parameter_type(&pt);
|
convert_parameter_type(&pt);
|
||||||
arg_size += (type_size(&pt, &align) + PTR_SIZE - 1) / PTR_SIZE;
|
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;
|
||||||
plast = &s->next;
|
plast = &s->next;
|
||||||
if (tok == ')')
|
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 */
|
/* if no parameters, then old type prototype */
|
||||||
l = FUNC_OLD;
|
l = FUNC_OLD;
|
||||||
skip(')');
|
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
|
/* NOTE: const is ignored in returned type as it has a special
|
||||||
meaning in gcc / C++ */
|
meaning in gcc / C++ */
|
||||||
type->t &= ~VT_CONSTANT;
|
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;
|
int saved_nocode_wanted = nocode_wanted;
|
||||||
/* array definition */
|
/* array definition */
|
||||||
next();
|
next();
|
||||||
while (1) {
|
n = -1;
|
||||||
|
t1 = 0;
|
||||||
|
if (td & TYPE_PARAM) while (1) {
|
||||||
/* XXX The optional type-quals and static should only be accepted
|
/* XXX The optional type-quals and static should only be accepted
|
||||||
in parameter decls. The '*' as well, and then even only
|
in parameter decls. The '*' as well, and then even only
|
||||||
in prototypes (not function defs). */
|
in prototypes (not function defs). */
|
||||||
|
@ -5441,11 +5454,13 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
|
||||||
default:
|
default:
|
||||||
break;
|
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))
|
if (!local_stack || (storage & VT_STATIC))
|
||||||
vpushi(expr_const());
|
vpushi(expr_const());
|
||||||
else {
|
else {
|
||||||
|
@ -5469,7 +5484,7 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
|
||||||
}
|
}
|
||||||
skip(']');
|
skip(']');
|
||||||
/* parse next post type */
|
/* 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)
|
if ((type->t & VT_BTYPE) == VT_FUNC)
|
||||||
tcc_error("declaration of an array of functions");
|
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");
|
expect("identifier");
|
||||||
*v = 0;
|
*v = 0;
|
||||||
}
|
}
|
||||||
post_type(post, ad, storage, 0);
|
post_type(post, ad, storage, td & ~(TYPE_DIRECT|TYPE_ABSTRACT));
|
||||||
parse_attribute(ad);
|
parse_attribute(ad);
|
||||||
type->t |= storage;
|
type->t |= storage;
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -5973,7 +5988,9 @@ ST_FUNC void unary(void)
|
||||||
outside, so any reactivation of code emission (from labels
|
outside, so any reactivation of code emission (from labels
|
||||||
or loop heads) can be disabled again after the end of it. */
|
or loop heads) can be disabled again after the end of it. */
|
||||||
block(1);
|
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(')');
|
skip(')');
|
||||||
} else {
|
} else {
|
||||||
gexpr();
|
gexpr();
|
||||||
|
|
|
@ -416,4 +416,30 @@ void func()
|
||||||
fink();
|
fink();
|
||||||
}
|
}
|
||||||
__attribute__((stuff)) int fink() {return 0;}
|
__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
|
#endif
|
||||||
|
|
|
@ -203,3 +203,16 @@ bar : 3 ; 3
|
||||||
[test_switch_W4]
|
[test_switch_W4]
|
||||||
60_errors_and_warnings.c:416: warning: implicit declaration of function 'fink'
|
60_errors_and_warnings.c:416: warning: implicit declaration of function 'fink'
|
||||||
60_errors_and_warnings.c:418: error: 'stuff' attribute ignored
|
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 a new issue