implement packed structs

closes #183
This commit is contained in:
Andrew Kelley 2017-02-03 11:39:24 -05:00
parent cd7713b178
commit 71d335e5cc
12 changed files with 163 additions and 120 deletions

View File

@ -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) "}"
```

View File

@ -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

View File

@ -621,11 +621,17 @@ enum ContainerKind {
ContainerKindUnion,
};
enum ContainerLayout {
ContainerLayoutAuto,
ContainerLayoutExtern,
ContainerLayoutPacked,
};
struct AstNodeContainerDecl {
ContainerKind kind;
ZigList<AstNode *> fields;
ZigList<AstNode *> 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;

View File

@ -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<ZigLLVMDIType*>(gen_field_count);

View File

@ -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);

View File

@ -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];

View File

@ -5283,8 +5283,9 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope,
TldContainer *tld_container = allocate<TldContainer>(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;

View File

@ -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);

View File

@ -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);

View File

@ -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";

View File

@ -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,
TokenIdArrow,
TokenIdFatArrow,
TokenIdDash,
TokenIdNumberSign,
TokenIdBoolOr,
TokenIdBoolAnd,
TokenIdBinOr,
TokenIdAmpersand,
TokenIdArrow,
TokenIdAtSign,
TokenIdBang,
TokenIdBinOr,
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,
TokenIdEllipsis,
TokenIdMaybe,
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,
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 {

View File

@ -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);
}