diff --git a/tcc.h b/tcc.h index 7bfac8b9..196654a9 100644 --- a/tcc.h +++ b/tcc.h @@ -432,6 +432,7 @@ typedef struct TokenSym { struct Sym *sym_struct; /* direct pointer to structure */ struct Sym *sym_identifier; /* direct pointer to identifier */ int tok; /* token number */ + int cnt; int len; char str[1]; } TokenSym; diff --git a/tccgen.c b/tccgen.c index adb59e5f..566d5281 100644 --- a/tccgen.c +++ b/tccgen.c @@ -4321,6 +4321,41 @@ static Sym * find_field (CType *type, int v, int *cumofs) return s; } +/* + * c = 0: reset symbol counter + * c = 1: increment symbol counter + * c = 2: check symbol counter + */ + +static void check_fields (CType *type, int c) +{ + Sym *s = type->ref; + int v; + + while ((s = s->next) != NULL) { + if ((s->v & SYM_FIELD) && + (s->type.t & VT_BTYPE) == VT_STRUCT && + (s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) { + check_fields (&s->type, c); + } + v = s->v & ~SYM_FIELD; + if (v < tok_ident) + switch (c) { + case 0: + table_ident[v - TOK_IDENT]->cnt = 0; + break; + case 1: + table_ident[v - TOK_IDENT]->cnt++; + break; + case 2: + if (table_ident[v - TOK_IDENT]->cnt != 1) + tcc_error("duplicate member '%s'", + get_tok_str(v, NULL)); + break; + } + } +} + static void struct_layout(CType *type, AttributeDef *ad) { int size, align, maxalign, offset, c, bit_pos, bit_size; @@ -4774,6 +4809,9 @@ do_decl: if (ad.cleanup_func) { tcc_warning("attribute '__cleanup__' ignored on type"); } + check_fields(type, 0); + check_fields(type, 1); + check_fields(type, 2); struct_layout(type, &ad); } } diff --git a/tests/tests2/60_errors_and_warnings.c b/tests/tests2/60_errors_and_warnings.c index d6571e90..363469d5 100644 --- a/tests/tests2/60_errors_and_warnings.c +++ b/tests/tests2/60_errors_and_warnings.c @@ -366,4 +366,21 @@ n[sizeof({3;})]; // crashed in block() due to missing local scope f(){"12"3;} // second const token killed the value of the first /******************************************************************/ +#elif defined test_duplicate_member +struct S { + int a, a; +}; +#elif defined test_duplicate_member_anon +struct S1 { + int b; + struct { + int b; + } c; +}; +struct S2 { + int d; + struct { + int d; + }; +}; #endif diff --git a/tests/tests2/60_errors_and_warnings.expect b/tests/tests2/60_errors_and_warnings.expect index 24a5d5ea..fee50c42 100644 --- a/tests/tests2/60_errors_and_warnings.expect +++ b/tests/tests2/60_errors_and_warnings.expect @@ -174,3 +174,9 @@ bar : 3 ; 3 [test_invalid_tokckill] 60_errors_and_warnings.c:366: error: ';' expected (got "3") + +[test_duplicate_member] +60_errors_and_warnings.c:372: error: duplicate member 'a' + +[test_duplicate_member_anon] +60_errors_and_warnings.c:385: error: duplicate member 'd'