Skip to content

Commit

Permalink
fix Issue 22028 - importC: Parser accepts initializers for struct mem…
Browse files Browse the repository at this point in the history
…bers
  • Loading branch information
ibuclaw committed Jun 17, 2021
1 parent 52ee0a2 commit d36fab2
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 9 deletions.
155 changes: 154 additions & 1 deletion src/dmd/cparse.d
Expand Up @@ -1666,6 +1666,159 @@ final class CParser(AST) : Parser!AST
}
}

/*************************************
* C11 6.7.2
* member-declaration:
* specifier-qualifier-list member-declarator-list (opt) ;
* static_assert-declaration
*
* member-declarator-list:
* member-declarator
* member-declarator-list , member-declarator
*
* member-declarator:
* declarator
* declarator (opt) : constant-expression
*/
void cparseMemberDeclaration()
{
//printf("cparseMemberDeclaration()\n");
if (token.value == TOK._Static_assert)
{
auto s = cparseStaticAssert();
symbols.push(s);
return;
}

auto symbolsSave = symbols;
Specifier specifier;
auto tspec = cparseSpecifierQualifierList(LVL.member, specifier);

/* If a declarator does not follow, it is unnamed
*/
if (token.value == TOK.semicolon && tspec)
{
nextToken();
auto tt = tspec.isTypeTag();
if (!tt)
return; // legal but meaningless empty declaration

/* If anonymous struct declaration
* struct { ... members ... };
* C11 6.7.2.1-13
*/
if (!tt.id && tt.members)
{
/* members of anonymous struct are considered members of
* the containing struct
*/
// TODO: merge in specifier
auto ad = new AST.AnonDeclaration(tt.loc, tt.tok == TOK.union_, tt.members);
if (!symbols)
symbols = new AST.Dsymbols();
symbols.push(ad);
return;
}
if (!tt.id && !tt.members)
return; // already gave error in cparseStruct()

/* `struct tag;` and `struct tag { ... };`
* always result in a declaration in the current scope
*/
// TODO: merge in specifier
auto stag = (tt.tok == TOK.struct_)
? new AST.StructDeclaration(tt.loc, tt.id, false)
: new AST.UnionDeclaration(tt.loc, tt.id);
stag.members = tt.members;
if (!symbols)
symbols = new AST.Dsymbols();
symbols.push(stag);
return;
}

while (1)
{
Identifier id;
AST.Type dt;
if (token.value == TOK.colon)
{
// C11 6.7.2.1-12 unnamed bit-field
nextToken();
cparseConstantExp();
error("unnamed bit fields are not supported"); // TODO
dt = AST.Type.tuns32;
}
else
dt = cparseDeclarator(DTR.xdirect, tspec, id);
if (!dt)
{
panic();
nextToken();
break; // error recovery
}
if (id && token.value == TOK.colon)
{
// C11 6.7.2.1 bit-field
nextToken();
cparseConstantExp();
error("bit fields are not supported"); // TODO
}

if (specifier.mod & MOD.xconst)
dt = dt.addSTC(STC.const_);

/* GNU Extensions
* member-declarator:
* declarator gnu-attributes (opt)
* declarator (opt) : constant-expression gnu-attributes (opt)
*/
if (token.value == TOK.__attribute__)
cparseGnuAttributes();

AST.Dsymbol s = null;
symbols = symbolsSave;
if (!symbols)
symbols = new AST.Dsymbols; // lazilly create it

if (!tspec && !specifier.scw && !specifier.mod)
error("specifier-qualifier-list required");
else if (id)
{
if (dt.ty == AST.Tvoid)
error("`void` has no value");

// declare the symbol
// Give member variables an implicit void initializer
auto initializer = new AST.VoidInitializer(token.loc);
s = new AST.VarDeclaration(token.loc, dt, id, initializer, specifiersToSTC(LVL.member, specifier));
}
if (s !is null)
symbols.push(s);

switch (token.value)
{
case TOK.identifier:
error("missing comma");
goto default;

case TOK.semicolon:
nextToken();
return;

case TOK.comma:
nextToken();
break;

default:
error("`;` or `,` expected");
while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
nextToken();
nextToken();
return;
}
}
}

/***************************************
* C11 Function Definitions
* function-definition
Expand Down Expand Up @@ -2904,7 +3057,7 @@ final class CParser(AST) : Parser!AST
symbols = new AST.Dsymbols();
while (token.value != TOK.rightCurly)
{
cparseDeclaration(LVL.member);
cparseMemberDeclaration();

if (token.value == TOK.endOfFile)
break;
Expand Down
29 changes: 21 additions & 8 deletions test/compilable/imports/cstuff2.c
Expand Up @@ -42,33 +42,33 @@ int test21937c() __attribute__((nothrow , leaf)) __attribute__((noreturn));
__attribute__((noinline))
void test21937d()
{
typedef int attr_var_t;
attr_var_t attr_local __attribute__((unused));
typedef int attr_var_t;
attr_var_t attr_local __attribute__((unused));
}

__attribute__((aligned)) int test21937e;
int test21937f __attribute__((aligned));

struct __attribute__((packed)) S21937a
{
__attribute__((deprecated("msg"))) char c;
int i __attribute__((deprecated));
__attribute__((deprecated("msg"))) char c;
int i __attribute__((deprecated));
};

struct S21937b
{
__attribute__((deprecated("msg"))) char c;
int i __attribute__((deprecated));
__attribute__((deprecated("msg"))) char c;
int i __attribute__((deprecated));
} __attribute__((packed));

enum __attribute__((aligned)) E21937a
{
E21937a_A,
E21937a_A,
};

enum E21937b
{
E21937b_A,
E21937b_A,
} __attribute__((aligned));

typedef int T21937a __attribute__((unused));
Expand Down Expand Up @@ -153,3 +153,16 @@ struct S21973

struct S21982 { int field; };
struct S21982 test21982;

/***************************************************/
// https://issues.dlang.org/show_bug.cgi?id=22028

struct S22028
{
struct nested
{
int field;
};
const int cfield;
_Static_assert(1 == 1, "ok");
};
5 changes: 5 additions & 0 deletions test/fail_compilation/failcstuff1.d
Expand Up @@ -4,6 +4,11 @@
fail_compilation/imports/cstuff1.c(101): Error: attributes should be specified before the function definition
fail_compilation/imports/cstuff1.c(200): Error: no members for `enum E21962`
fail_compilation/imports/cstuff1.c(201): Error: no members for anonymous enum
fail_compilation/imports/cstuff1.c(252): Error: `;` or `,` expected
fail_compilation/imports/cstuff1.c(253): Error: `void` has no value
fail_compilation/imports/cstuff1.c(253): Error: missing comma
fail_compilation/imports/cstuff1.c(253): Error: `;` or `,` expected
fail_compilation/imports/cstuff1.c(254): Error: empty struct-declaration-list for `struct Anonymous`
fail_compilation/imports/cstuff1.c(303): Error: storage class not allowed in specifier-qualified-list
fail_compilation/imports/cstuff1.c(304): Error: storage class not allowed in specifier-qualified-list
fail_compilation/imports/cstuff1.c(305): Error: storage class not allowed in specifier-qualified-list
Expand Down
10 changes: 10 additions & 0 deletions test/fail_compilation/imports/cstuff1.c
Expand Up @@ -13,6 +13,16 @@ void test21962() __attribute__((noinline))
enum E21962 { };
enum { };

/********************************/
// https://issues.dlang.org/show_bug.cgi?id=22028
#line 250
struct S22028
{
int init = 1;
void vfield nocomma;
struct { };
};

/********************************/
// https://issues.dlang.org/show_bug.cgi?id=22029
#line 300
Expand Down

0 comments on commit d36fab2

Please sign in to comment.