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 */ | ||||
| #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) | ||||
|  |  | |||
							
								
								
									
										45
									
								
								tccgen.c
									
										
									
									
									
								
							
							
						
						
									
										45
									
								
								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 != ']') { | ||||
| 	        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…
	
	Add table
		
		Reference in a new issue