Reorganize type parsing

Various corner cases for declarator parsing were incorrect.  This
reorganizes and fixes it, and somewhat simplifies it as well.
This commit is contained in:
Michael Matz 2017-03-06 03:25:33 +01:00
parent 5891fbc0c8
commit 182367e232
2 changed files with 91 additions and 64 deletions

121
tccgen.c
View File

@ -74,7 +74,7 @@ static void gen_cast(CType *type);
static inline CType *pointed_type(CType *type); static inline CType *pointed_type(CType *type);
static int is_compatible_types(CType *type1, CType *type2); static int is_compatible_types(CType *type1, CType *type2);
static int parse_btype(CType *type, AttributeDef *ad); 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 parse_expr_type(CType *type);
static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only); 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); 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; v = 0;
type1 = btype; type1 = btype;
if (tok != ':') { if (tok != ':') {
type_decl(&type1, &ad1, &v, TYPE_DIRECT | TYPE_ABSTRACT); if (tok != ';')
type_decl(&type1, &ad1, &v, TYPE_DIRECT);
if (v == 0) { if (v == 0) {
if ((type1.t & VT_BTYPE) != VT_STRUCT) if ((type1.t & VT_BTYPE) != VT_STRUCT)
expect("identifier"); expect("identifier");
@ -3964,7 +3965,7 @@ static int asm_label_instr(void)
return v; 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; int n, l, t1, arg_size, align;
Sym **plast, *s, *first; Sym **plast, *s, *first;
@ -3972,25 +3973,25 @@ static void post_type(CType *type, AttributeDef *ad, int storage)
CType pt; CType pt;
if (tok == '(') { if (tok == '(') {
/* function declaration */ /* function type, or recursive declarator (return if so) */
next(); 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; first = NULL;
plast = &first; plast = &first;
arg_size = 0; arg_size = 0;
if (tok != ')') { 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 (!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 == ')') 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);
@ -3998,7 +3999,6 @@ static void post_type(CType *type, AttributeDef *ad, int storage)
tcc_error("parameter declared as void"); tcc_error("parameter declared as void");
arg_size += (type_size(&pt, &align) + PTR_SIZE - 1) / PTR_SIZE; arg_size += (type_size(&pt, &align) + PTR_SIZE - 1) / PTR_SIZE;
} else { } else {
old_proto:
n = tok; n = tok;
if (n < TOK_UIDENT) if (n < TOK_UIDENT)
expect("identifier"); expect("identifier");
@ -4017,10 +4017,11 @@ static void post_type(CType *type, AttributeDef *ad, int storage)
next(); next();
break; break;
} }
if (l == FUNC_NEW && !parse_btype(&pt, &ad1))
tcc_error("invalid type");
} }
} } else
/* if no parameters, then old type prototype */ /* if no parameters, then old type prototype */
if (l == 0)
l = FUNC_OLD; l = FUNC_OLD;
skip(')'); skip(')');
/* NOTE: const is ignored in returned type as it has a special /* 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(']'); skip(']');
/* parse next post type */ /* parse next post type */
post_type(type, ad, storage); post_type(type, ad, storage, 0);
if (type->t == VT_FUNC) if (type->t == VT_FUNC)
tcc_error("declaration of an array of functions"); tcc_error("declaration of an array of functions");
t1 |= type->t & VT_VLA; 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->t = (t1 ? VT_VLA : VT_ARRAY) | VT_PTR;
type->ref = s; 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 in 'type'. 'td' is a bitmask indicating which kind of type decl is
expected. 'type' should contain the basic type. 'ad' is the expected. 'type' should contain the basic type. 'ad' is the
attribute definition of the basic type. It can be modified by attribute definition of the basic type. It can be modified by
type_decl(). type_decl(). If this (possibly abstract) declarator is a pointer chain
*/ it returns the innermost pointed to type (equals *type, but is a different
static void type_decl(CType *type, AttributeDef *ad, int *v, int td) 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 *post, *ret;
CType type1, *type2;
int qualifiers, storage; 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 == '*') { while (tok == '*') {
qualifiers = 0; qualifiers = 0;
redo: redo:
@ -4139,51 +4145,38 @@ static void type_decl(CType *type, AttributeDef *ad, int *v, int td)
} }
mk_pointer(type); mk_pointer(type);
type->t |= qualifiers; 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 == '(') { if (tok == '(') {
next(); /* This is possibly a parameter type list for abstract declarators
/* XXX: this is not correct to modify 'ad' at this point, but ('int ()'), use post_type for testing this. */
the syntax is not clear */ if (!post_type(type, ad, 0, td)) {
if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) /* It's not, so it's a nested declarator, and the post operations
parse_attribute(ad); apply to the innermost pointed to type (if any). */
type_decl(&type1, ad, v, td); /* XXX: this is not correct to modify 'ad' at this point, but
skip(')'); 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 { } else {
/* type identifier */ if (!(td & TYPE_ABSTRACT))
if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) { expect("identifier");
*v = tok; *v = 0;
next();
} else {
if (!(td & TYPE_ABSTRACT))
expect("identifier");
*v = 0;
}
} }
storage = type->t & VT_STORAGE; post_type(post, ad, storage, 0);
type->t &= ~VT_STORAGE;
post_type(type, ad, storage);
type->t |= storage;
if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2)
parse_attribute(ad); 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; type->t |= storage;
return ret;
} }
/* compute the lvalue VT_LVAL_xxx needed to match type t. */ /* 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 #if 0
{ {
char buf[500]; 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); printf("type = '%s'\n", buf);
} }
#endif #endif

View File

@ -6,4 +6,38 @@ enum E const *e2;
struct S *s; struct S *s;
const struct S *s1; const struct S *s1;
struct S const *s2; 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; } int main () { return 0; }