diff --git a/src/dmd/cparse.d b/src/dmd/cparse.d index 99620100a1b0..febc139c34f7 100644 --- a/src/dmd/cparse.d +++ b/src/dmd/cparse.d @@ -1671,6 +1671,167 @@ 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 && tspec.isTypeTag()) + { + /* If anonymous struct declaration + * struct { ... members ... }; + * C11 6.7.2.1-13 + */ + nextToken(); + auto tt = tspec.isTypeTag(); + 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(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_); + + if (!id) // no identifier + { + if (dt !is tspec) + { + error("identifier or `(` expected"); // ) + panic(); + break; + } + } + + /* 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 @@ -2903,7 +3064,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;