From 182367e232e92861be2e4734a6bf496c63389f45 Mon Sep 17 00:00:00 2001 From: Michael Matz Date: Mon, 6 Mar 2017 03:25:33 +0100 Subject: [PATCH] Reorganize type parsing Various corner cases for declarator parsing were incorrect. This reorganizes and fixes it, and somewhat simplifies it as well. --- tccgen.c | 121 +++++++++++++++++++--------------------- tests/tests2/81_types.c | 34 +++++++++++ 2 files changed, 91 insertions(+), 64 deletions(-) diff --git a/tccgen.c b/tccgen.c index 7ab69400..88a2bcec 100644 --- a/tccgen.c +++ b/tccgen.c @@ -74,7 +74,7 @@ static void gen_cast(CType *type); static inline CType *pointed_type(CType *type); static int is_compatible_types(CType *type1, CType *type2); static int parse_btype(CType *type, AttributeDef *ad); -static void type_decl(CType *type, AttributeDef *ad, int *v, int td); +static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td); static void parse_expr_type(CType *type); static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only); static void block(int *bsym, int *csym, int is_expr); @@ -3586,7 +3586,8 @@ static void struct_decl(CType *type, AttributeDef *ad, int u) v = 0; type1 = btype; if (tok != ':') { - type_decl(&type1, &ad1, &v, TYPE_DIRECT | TYPE_ABSTRACT); + if (tok != ';') + type_decl(&type1, &ad1, &v, TYPE_DIRECT); if (v == 0) { if ((type1.t & VT_BTYPE) != VT_STRUCT) expect("identifier"); @@ -3964,7 +3965,7 @@ static int asm_label_instr(void) return v; } -static void post_type(CType *type, AttributeDef *ad, int storage) +static int post_type(CType *type, AttributeDef *ad, int storage, int td) { int n, l, t1, arg_size, align; Sym **plast, *s, *first; @@ -3972,25 +3973,25 @@ static void post_type(CType *type, AttributeDef *ad, int storage) CType pt; if (tok == '(') { - /* function declaration */ + /* function type, or recursive declarator (return if so) */ next(); - l = 0; + if (td && !(td & TYPE_ABSTRACT)) + return 0; + if (tok == ')') + l = 0; + else if (parse_btype(&pt, &ad1)) + l = FUNC_NEW; + else if (td) + return 0; + else + l = FUNC_OLD; first = NULL; plast = &first; arg_size = 0; - if (tok != ')') { + if (l) { for(;;) { /* read param name and compute offset */ if (l != FUNC_OLD) { - if (!parse_btype(&pt, &ad1)) { - if (l) { - tcc_error("invalid type"); - } else { - l = FUNC_OLD; - goto old_proto; - } - } - l = FUNC_NEW; if ((pt.t & VT_BTYPE) == VT_VOID && tok == ')') break; type_decl(&pt, &ad1, &n, TYPE_DIRECT | TYPE_ABSTRACT); @@ -3998,7 +3999,6 @@ static void post_type(CType *type, AttributeDef *ad, int storage) tcc_error("parameter declared as void"); arg_size += (type_size(&pt, &align) + PTR_SIZE - 1) / PTR_SIZE; } else { - old_proto: n = tok; if (n < TOK_UIDENT) expect("identifier"); @@ -4017,10 +4017,11 @@ static void post_type(CType *type, AttributeDef *ad, int storage) next(); break; } + if (l == FUNC_NEW && !parse_btype(&pt, &ad1)) + tcc_error("invalid type"); } - } - /* if no parameters, then old type prototype */ - if (l == 0) + } else + /* if no parameters, then old type prototype */ l = FUNC_OLD; skip(')'); /* NOTE: const is ignored in returned type as it has a special @@ -4072,7 +4073,7 @@ static void post_type(CType *type, AttributeDef *ad, int storage) } skip(']'); /* parse next post type */ - post_type(type, ad, storage); + post_type(type, ad, storage, 0); if (type->t == VT_FUNC) tcc_error("declaration of an array of functions"); t1 |= type->t & VT_VLA; @@ -4098,20 +4099,25 @@ static void post_type(CType *type, AttributeDef *ad, int storage) type->t = (t1 ? VT_VLA : VT_ARRAY) | VT_PTR; type->ref = s; } + return 1; } -/* Parse a type declaration (except basic type), and return the type +/* Parse a type declarator (except basic type), and return the type in 'type'. 'td' is a bitmask indicating which kind of type decl is expected. 'type' should contain the basic type. 'ad' is the attribute definition of the basic type. It can be modified by - type_decl(). - */ -static void type_decl(CType *type, AttributeDef *ad, int *v, int td) + type_decl(). If this (possibly abstract) declarator is a pointer chain + it returns the innermost pointed to type (equals *type, but is a different + pointer), otherwise returns type itself, that's used for recursive calls. */ +static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td) { - Sym *s; - CType type1, *type2; + CType *post, *ret; int qualifiers, storage; + /* recursive type, remove storage bits first, apply them later again */ + storage = type->t & VT_STORAGE; + type->t &= ~VT_STORAGE; + post = ret = type; while (tok == '*') { qualifiers = 0; redo: @@ -4139,51 +4145,38 @@ static void type_decl(CType *type, AttributeDef *ad, int *v, int td) } mk_pointer(type); type->t |= qualifiers; + if (ret == type) + /* innermost pointed to type is the one for the first derivation */ + ret = pointed_type(type); } - /* recursive type */ - /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */ - type1.t = 0; /* XXX: same as int */ if (tok == '(') { - next(); - /* XXX: this is not correct to modify 'ad' at this point, but - the syntax is not clear */ - if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) - parse_attribute(ad); - type_decl(&type1, ad, v, td); - skip(')'); + /* This is possibly a parameter type list for abstract declarators + ('int ()'), use post_type for testing this. */ + if (!post_type(type, ad, 0, td)) { + /* It's not, so it's a nested declarator, and the post operations + apply to the innermost pointed to type (if any). */ + /* XXX: this is not correct to modify 'ad' at this point, but + the syntax is not clear */ + if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) + parse_attribute(ad); + post = type_decl(type, ad, v, td); + skip(')'); + } + } else if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) { + /* type identifier */ + *v = tok; + next(); } else { - /* type identifier */ - if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) { - *v = tok; - next(); - } else { - if (!(td & TYPE_ABSTRACT)) - expect("identifier"); - *v = 0; - } + if (!(td & TYPE_ABSTRACT)) + expect("identifier"); + *v = 0; } - storage = type->t & VT_STORAGE; - type->t &= ~VT_STORAGE; - post_type(type, ad, storage); - type->t |= storage; + post_type(post, ad, storage, 0); if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) parse_attribute(ad); - - if (!type1.t) - return; - /* append type at the end of type1 */ - type2 = &type1; - for(;;) { - s = type2->ref; - type2 = &s->type; - if (!type2->t) { - *type2 = *type; - break; - } - } - *type = type1; type->t |= storage; + return ret; } /* compute the lvalue VT_LVAL_xxx needed to match type t. */ @@ -6924,7 +6917,7 @@ static int decl0(int l, int is_for_loop_init) #if 0 { char buf[500]; - type_to_str(buf, sizeof(buf), t, get_tok_str(v, NULL)); + type_to_str(buf, sizeof(buf), &type, get_tok_str(v, NULL)); printf("type = '%s'\n", buf); } #endif diff --git a/tests/tests2/81_types.c b/tests/tests2/81_types.c index 542d0663..fd6d71b0 100644 --- a/tests/tests2/81_types.c +++ b/tests/tests2/81_types.c @@ -6,4 +6,38 @@ enum E const *e2; struct S *s; const struct S *s1; struct S const *s2; + +/* Various strangely looking declarators, which are all valid + and have to map to the same numbered typedefs. */ +typedef int (*fptr1)(); +int f1 (int (), int); +typedef int (*fptr2)(int x); +int f2 (int (int x), int); +typedef int (*fptr3)(int); +int f3 (int (int), int); +typedef int (*fptr4[4])(int); +int f4 (int (*[4])(int), int); +typedef int (*fptr5)(fptr1); +int f5 (int (int()), fptr1); +int f1 (fptr1 fp, int i) +{ + return (*fp)(i); +} +int f2 (fptr2 fp, int i) +{ + return (*fp)(i); +} +int f3 (fptr3 fp, int i) +{ + return (*fp)(i); +} +int f4 (fptr4 fp, int i) +{ + return (*fp[i])(i); +} +int f5 (fptr5 fp, fptr1 i) +{ + return fp(i); +} +int f8 (int ([4]), int); int main () { return 0; }