diff --git a/doc/langref.md b/doc/langref.md index 78904d8325705f397a4ab6d75941ba031d19332c..e49dd66ff67e859f9931b73b3c2f6eda6cce82cc 100644 --- a/doc/langref.md +++ b/doc/langref.md @@ -17,9 +17,9 @@ GlobalVarDecl = VariableDeclaration ";" VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" TypeExpr) "=" Expression -StructMember = (StructField | FnDef | GlobalVarDecl) +ContainerMember = (ContainerField | FnDef | GlobalVarDecl) -StructField = Symbol option(":" Expression) ",") +ContainerField = Symbol option(":" Expression) ",") UseDecl = "use" Expression ";" @@ -155,7 +155,7 @@ GroupedExpression = "(" Expression ")" KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type" | "this" -ContainerDecl = option("extern") ("struct" | "enum" | "union") "{" many(StructMember) "}" +ContainerDecl = option("extern" | "packed") ("struct" | "enum" | "union") "{" many(ContainerMember) "}" ``` diff --git a/doc/vim/syntax/zig.vim b/doc/vim/syntax/zig.vim index ccae0a6f142d04307d62d27fe0a3d01d50bfc09b..aa97b7b460a8aec031c4499008aa8a4c613099f8 100644 --- a/doc/vim/syntax/zig.vim +++ b/doc/vim/syntax/zig.vim @@ -8,15 +8,15 @@ if exists("b:current_syntax") endif let b:current_syntax = "zig" -syn keyword zigStorage const var extern export pub noalias inline comptime nakedcc coldcc +syn keyword zigStorage const var extern packed export pub noalias inline comptime nakedcc coldcc volatile syn keyword zigStructure struct enum union -syn keyword zigStatement goto break return continue asm defer +syn keyword zigStatement goto break return continue asm defer unreachable syn keyword zigConditional if else switch try syn keyword zigRepeat while for syn keyword zigConstant null undefined zeroes this syn keyword zigKeyword fn use -syn keyword zigType bool f32 f64 void unreachable type error +syn keyword zigType bool f32 f64 void Unreachable type error syn keyword zigType i8 u8 i16 u16 i32 u32 i64 u64 isize usize syn keyword zigType c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong c_long_double diff --git a/src/all_types.hpp b/src/all_types.hpp index 7eaca8c45a813c1d3d059bf2ddd9e5141b57c0a3..4b971ea552aa986f99c83dbee53c36094bdc3a24 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -621,11 +621,17 @@ enum ContainerKind { ContainerKindUnion, }; +enum ContainerLayout { + ContainerLayoutAuto, + ContainerLayoutExtern, + ContainerLayoutPacked, +}; + struct AstNodeContainerDecl { ContainerKind kind; ZigList fields; ZigList decls; - bool is_extern; + ContainerLayout layout; }; struct AstNodeStructField { @@ -820,7 +826,7 @@ struct TypeStructField { }; struct TypeTableEntryStruct { AstNode *decl_node; - bool is_extern; + ContainerLayout layout; bool is_packed; uint32_t src_field_count; uint32_t gen_field_count; @@ -850,7 +856,7 @@ struct TypeTableEntryError { struct TypeTableEntryEnum { AstNode *decl_node; - bool is_extern; + ContainerLayout layout; uint32_t src_field_count; uint32_t gen_field_count; TypeEnumField *fields; @@ -877,7 +883,7 @@ struct TypeTableEntryEnumTag { struct TypeTableEntryUnion { AstNode *decl_node; - bool is_extern; + ContainerLayout layout; uint32_t src_field_count; uint32_t gen_field_count; TypeStructField *fields; diff --git a/src/analyze.cpp b/src/analyze.cpp index 506d5e1db3ea083fabe2ebc98b5336e8cc6609d0..280fc94214ae3cc97f2df1b0847d59671e657ac8 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -823,22 +823,24 @@ static TypeTableEntryId container_to_type(ContainerKind kind) { zig_unreachable(); } -TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind, AstNode *decl_node, const char *name, bool is_extern) { +TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind, + AstNode *decl_node, const char *name, ContainerLayout layout) +{ TypeTableEntryId type_id = container_to_type(kind); TypeTableEntry *entry = new_container_type_entry(type_id, decl_node, scope); switch (kind) { case ContainerKindStruct: entry->data.structure.decl_node = decl_node; - entry->data.structure.is_extern = is_extern; + entry->data.structure.layout = layout; break; case ContainerKindEnum: entry->data.enumeration.decl_node = decl_node; - entry->data.enumeration.is_extern = is_extern; + entry->data.enumeration.layout = layout; break; case ContainerKindUnion: entry->data.unionation.decl_node = decl_node; - entry->data.unionation.is_extern = is_extern; + entry->data.unionation.layout = layout; break; } @@ -1328,7 +1330,8 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { } assert(struct_type->di_type); - LLVMStructSetBody(struct_type->type_ref, element_types, gen_field_count, false); + bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked); + LLVMStructSetBody(struct_type->type_ref, element_types, gen_field_count, packed); assert(LLVMStoreSizeOfType(g->target_data_ref, struct_type->type_ref) > 0); ZigLLVMDIType **di_element_types = allocate(gen_field_count); diff --git a/src/analyze.hpp b/src/analyze.hpp index 7c83030c51fb3e8707c5994e273de66ffb74056b..fdbc6e74c82a74aab6cb00062ac8d0c73aee81f0 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -26,7 +26,8 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id); TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type); TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size); TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); -TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind, AstNode *decl_node, const char *name, bool is_extern); +TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind, + AstNode *decl_node, const char *name, ContainerLayout layout); TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x); TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type); TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry); diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 4689f723ee8bc4c8bace04a17fedddd2e6607d80..1c82ef972e7eea09c6676d3422961ce0b144b0b1 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -104,6 +104,15 @@ static const char *defer_string(ReturnKind kind) { zig_unreachable(); } +static const char *layout_string(ContainerLayout layout) { + switch (layout) { + case ContainerLayoutAuto: return ""; + case ContainerLayoutExtern: return "extern "; + case ContainerLayoutPacked: return "packed "; + } + zig_unreachable(); +} + static const char *extern_string(bool is_extern) { return is_extern ? "extern " : ""; } @@ -970,8 +979,8 @@ static void ast_render_tld_var(AstRender *ar, Buf *name, TldVar *tld_var) { { TypeTableEntry *type_entry = var->value.data.x_type; if (type_entry->id == TypeTableEntryIdStruct) { - const char *extern_str = extern_string(type_entry->data.structure.is_extern); - fprintf(ar->f, "%sstruct {\n", extern_str); + const char *layout_str = layout_string(type_entry->data.structure.layout); + fprintf(ar->f, "%sstruct {\n", layout_str); if (type_entry->data.structure.complete) { for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { TypeStructField *field = &type_entry->data.structure.fields[i]; @@ -982,8 +991,8 @@ static void ast_render_tld_var(AstRender *ar, Buf *name, TldVar *tld_var) { } fprintf(ar->f, "}"); } else if (type_entry->id == TypeTableEntryIdEnum) { - const char *extern_str = extern_string(type_entry->data.enumeration.is_extern); - fprintf(ar->f, "%senum {\n", extern_str); + const char *layout_str = layout_string(type_entry->data.enumeration.layout); + fprintf(ar->f, "%senum {\n", layout_str); if (type_entry->data.enumeration.complete) { for (size_t i = 0; i < type_entry->data.enumeration.src_field_count; i += 1) { TypeEnumField *field = &type_entry->data.enumeration.fields[i]; diff --git a/src/ir.cpp b/src/ir.cpp index bf85a20f7a60d2f55d5eedb7762fb3783610e131..573e4cefad957ea565b200ffe9b8fcee9d050579 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5283,8 +5283,9 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope, TldContainer *tld_container = allocate(1); init_tld(&tld_container->base, TldIdContainer, name, visib_mod, node, parent_scope); - TypeTableEntry *container_type = get_partial_container_type(irb->codegen, parent_scope, kind, node, buf_ptr(name), - node->data.container_decl.is_extern); + ContainerLayout layout = node->data.container_decl.layout; + TypeTableEntry *container_type = get_partial_container_type(irb->codegen, parent_scope, + kind, node, buf_ptr(name), layout); ScopeDecls *child_scope = get_container_scope(container_type); tld_container->type_entry = container_type; diff --git a/src/parseh.cpp b/src/parseh.cpp index 94f430cdfa988700c6d3552bc6cc7cf7cda8a548..9a83e0d6b1c92dbc487db2369131267faabe1161 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -720,7 +720,7 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) const EnumDecl *enum_def = enum_decl->getDefinition(); if (!enum_def) { TypeTableEntry *enum_type = get_partial_container_type(c->codegen, &c->import->decls_scope->base, - ContainerKindEnum, c->source_node, buf_ptr(full_type_name), true); + ContainerKindEnum, c->source_node, buf_ptr(full_type_name), ContainerLayoutExtern); enum_type->data.enumeration.zero_bits_known = true; c->enum_type_table.put(bare_name, enum_type); c->decl_table.put(enum_decl, enum_type); @@ -745,7 +745,7 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) if (pure_enum) { TypeTableEntry *enum_type = get_partial_container_type(c->codegen, &c->import->decls_scope->base, - ContainerKindEnum, c->source_node, buf_ptr(full_type_name), true); + ContainerKindEnum, c->source_node, buf_ptr(full_type_name), ContainerLayoutExtern); c->enum_type_table.put(bare_name, enum_type); c->decl_table.put(enum_decl, enum_type); @@ -885,7 +885,7 @@ static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_ TypeTableEntry *struct_type = get_partial_container_type(c->codegen, &c->import->decls_scope->base, - ContainerKindStruct, c->source_node, buf_ptr(full_type_name), true); + ContainerKindStruct, c->source_node, buf_ptr(full_type_name), ContainerLayoutExtern); struct_type->data.structure.zero_bits_known = true; c->struct_type_table.put(bare_name, struct_type); diff --git a/src/parser.cpp b/src/parser.cpp index 54081d91a77c0be5e1c2337050fdbcca9d943365..7b7126ca40bc46bccfc68074cc4e8116664c8b38 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2275,21 +2275,24 @@ static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index, VisibMod vi } /* -ContainerDecl = option("extern") ("struct" | "enum" | "union") "{" many(StructMember) "}" -StructMember = (StructField | FnDef | GlobalVarDecl) -StructField = Symbol option(":" Expression) ",") +ContainerDecl = option("extern" | "packed") ("struct" | "enum" | "union") "{" many(ContainerMember) "}" +ContainerMember = (ContainerField | FnDef | GlobalVarDecl) +ContainerField = Symbol option(":" Expression) ",") */ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory) { Token *first_token = &pc->tokens->at(*token_index); Token *container_kind_token; - bool is_extern; + ContainerLayout layout; if (first_token->id == TokenIdKeywordExtern) { container_kind_token = &pc->tokens->at(*token_index + 1); - is_extern = true; + layout = ContainerLayoutExtern; + } else if (first_token->id == TokenIdKeywordPacked) { + container_kind_token = &pc->tokens->at(*token_index + 1); + layout = ContainerLayoutPacked; } else { container_kind_token = first_token; - is_extern = false; + layout = ContainerLayoutAuto; } ContainerKind kind; @@ -2304,10 +2307,10 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, } else { return nullptr; } - *token_index += is_extern ? 2 : 1; + *token_index += (layout == ContainerLayoutAuto) ? 1 : 2; AstNode *node = ast_create_node(pc, NodeTypeContainerDecl, first_token); - node->data.container_decl.is_extern = is_extern; + node->data.container_decl.layout = layout; node->data.container_decl.kind = kind; ast_eat_token(pc, token_index, TokenIdLBrace); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 769e8c9d8de7f91c5bf48137865b676e642153e6..6adb7dd8636444c7081dd1c5f54a8ac01b051557 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -128,6 +128,7 @@ static const struct ZigKeyword zig_keywords[] = { {"nakedcc", TokenIdKeywordNakedCC}, {"noalias", TokenIdKeywordNoAlias}, {"null", TokenIdKeywordNull}, + {"packed", TokenIdKeywordPacked}, {"pub", TokenIdKeywordPub}, {"return", TokenIdKeywordReturn}, {"struct", TokenIdKeywordStruct}, @@ -1502,6 +1503,7 @@ const char * token_name(TokenId id) { case TokenIdKeywordNakedCC: return "nakedcc"; case TokenIdKeywordNoAlias: return "noalias"; case TokenIdKeywordNull: return "null"; + case TokenIdKeywordPacked: return "packed"; case TokenIdKeywordPub: return "pub"; case TokenIdKeywordReturn: return "return"; case TokenIdKeywordStruct: return "struct"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index d004ad4241ca57270fb8ed1595244dcbbdb780b0..a5cbe4cdea231f4f16103501a95c70edd4eb8c7a 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -12,109 +12,110 @@ #include "bignum.hpp" enum TokenId { - TokenIdEof, - TokenIdSymbol, - TokenIdKeywordFn, - TokenIdKeywordReturn, - TokenIdKeywordVar, - TokenIdKeywordConst, - TokenIdKeywordExtern, - TokenIdKeywordPub, - TokenIdKeywordUse, - TokenIdKeywordExport, - TokenIdKeywordTrue, - TokenIdKeywordFalse, - TokenIdKeywordIf, - TokenIdKeywordTry, - TokenIdKeywordElse, - TokenIdKeywordGoto, - TokenIdKeywordAsm, - TokenIdKeywordVolatile, - TokenIdKeywordStruct, - TokenIdKeywordEnum, - TokenIdKeywordUnion, - TokenIdKeywordWhile, - TokenIdKeywordFor, - TokenIdKeywordContinue, - TokenIdKeywordBreak, - TokenIdKeywordNull, - TokenIdKeywordNoAlias, - TokenIdKeywordSwitch, - TokenIdKeywordUndefined, - TokenIdKeywordError, - TokenIdKeywordType, - TokenIdKeywordInline, - TokenIdKeywordCompTime, - TokenIdKeywordDefer, - TokenIdKeywordThis, - TokenIdKeywordColdCC, - TokenIdKeywordNakedCC, - TokenIdLParen, - TokenIdRParen, - TokenIdComma, - TokenIdStar, - TokenIdStarStar, - TokenIdLBrace, - TokenIdRBrace, - TokenIdLBracket, - TokenIdRBracket, - TokenIdStringLiteral, - TokenIdCharLiteral, - TokenIdSemicolon, - TokenIdNumberLiteral, - TokenIdPlus, - TokenIdPlusPlus, - TokenIdColon, + TokenIdAmpersand, TokenIdArrow, - TokenIdFatArrow, - TokenIdDash, - TokenIdNumberSign, - TokenIdBoolOr, - TokenIdBoolAnd, + TokenIdAtSign, + TokenIdBang, TokenIdBinOr, - TokenIdAmpersand, TokenIdBinXor, - TokenIdEq, - TokenIdTimesEq, - TokenIdTimesPercent, - TokenIdTimesPercentEq, - TokenIdDivEq, - TokenIdModEq, - TokenIdPlusEq, - TokenIdPlusPercent, - TokenIdPlusPercentEq, - TokenIdMinusEq, - TokenIdMinusPercent, - TokenIdMinusPercentEq, + TokenIdBitAndEq, + TokenIdBitOrEq, + TokenIdBitShiftLeft, TokenIdBitShiftLeftEq, TokenIdBitShiftLeftPercent, TokenIdBitShiftLeftPercentEq, + TokenIdBitShiftRight, TokenIdBitShiftRightEq, - TokenIdBitAndEq, TokenIdBitXorEq, - TokenIdBitOrEq, + TokenIdBoolAnd, TokenIdBoolAndEq, + TokenIdBoolOr, TokenIdBoolOrEq, + TokenIdCharLiteral, TokenIdCmpEq, - TokenIdBang, - TokenIdTilde, - TokenIdCmpNotEq, - TokenIdCmpLessThan, + TokenIdCmpGreaterOrEq, TokenIdCmpGreaterThan, TokenIdCmpLessOrEq, - TokenIdCmpGreaterOrEq, - TokenIdBitShiftLeft, - TokenIdBitShiftRight, - TokenIdSlash, - TokenIdPercent, - TokenIdPercentPercent, + TokenIdCmpLessThan, + TokenIdCmpNotEq, + TokenIdColon, + TokenIdComma, + TokenIdDash, + TokenIdDivEq, TokenIdDot, + TokenIdDoubleQuestion, TokenIdEllipsis, + TokenIdEof, + TokenIdEq, + TokenIdFatArrow, + TokenIdKeywordAsm, + TokenIdKeywordBreak, + TokenIdKeywordColdCC, + TokenIdKeywordCompTime, + TokenIdKeywordConst, + TokenIdKeywordContinue, + TokenIdKeywordDefer, + TokenIdKeywordElse, + TokenIdKeywordEnum, + TokenIdKeywordError, + TokenIdKeywordExport, + TokenIdKeywordExtern, + TokenIdKeywordFalse, + TokenIdKeywordFn, + TokenIdKeywordFor, + TokenIdKeywordGoto, + TokenIdKeywordIf, + TokenIdKeywordInline, + TokenIdKeywordNakedCC, + TokenIdKeywordNoAlias, + TokenIdKeywordNull, + TokenIdKeywordPacked, + TokenIdKeywordPub, + TokenIdKeywordReturn, + TokenIdKeywordStruct, + TokenIdKeywordSwitch, + TokenIdKeywordThis, + TokenIdKeywordTrue, + TokenIdKeywordTry, + TokenIdKeywordType, + TokenIdKeywordUndefined, + TokenIdKeywordUnion, + TokenIdKeywordUse, + TokenIdKeywordVar, + TokenIdKeywordVolatile, + TokenIdKeywordWhile, + TokenIdLBrace, + TokenIdLBracket, + TokenIdLParen, TokenIdMaybe, - TokenIdDoubleQuestion, TokenIdMaybeAssign, - TokenIdAtSign, + TokenIdMinusEq, + TokenIdMinusPercent, + TokenIdMinusPercentEq, + TokenIdModEq, + TokenIdNumberLiteral, + TokenIdNumberSign, + TokenIdPercent, TokenIdPercentDot, + TokenIdPercentPercent, + TokenIdPlus, + TokenIdPlusEq, + TokenIdPlusPercent, + TokenIdPlusPercentEq, + TokenIdPlusPlus, + TokenIdRBrace, + TokenIdRBracket, + TokenIdRParen, + TokenIdSemicolon, + TokenIdSlash, + TokenIdStar, + TokenIdStarStar, + TokenIdStringLiteral, + TokenIdSymbol, + TokenIdTilde, + TokenIdTimesEq, + TokenIdTimesPercent, + TokenIdTimesPercentEq, }; struct TokenNumLit { diff --git a/test/cases/struct.zig b/test/cases/struct.zig index 930aa79db184a6e91d802f84550539b9a404a533..09312990a2e0ebf440ada937a48ededdab031c57 100644 --- a/test/cases/struct.zig +++ b/test/cases/struct.zig @@ -208,3 +208,20 @@ fn passSliceOfEmptyStructToFn() { fn testPassSliceOfEmptyStructToFn(slice: []EmptyStruct2) -> usize { slice.len } + +const APackedStruct = packed struct { + x: u8, + y: u8, +}; + +fn packedStruct() { + @setFnTest(this); + + var foo = APackedStruct { + .x = 1, + .y = 2, + }; + foo.y += 1; + const four = foo.x + foo.y; + assert(four == 4); +}