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) | ||||||
|  |  | ||||||
							
								
								
									
										47
									
								
								tccgen.c
									
										
									
									
									
								
							
							
						
						
									
										47
									
								
								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; |             if (tok != ']') { | ||||||
| 	} | 	        nocode_wanted = 1; | ||||||
|         n = -1; | 	        gexpr(), vpop(); | ||||||
|         t1 = 0; |             } | ||||||
|         if (tok != ']') { |             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…
	
	Add table
		
		Reference in a new issue