Skip to content

Commit ec2f9ef

Browse files
authored
Merge pull request #3114 from Tetralux/align-on-struct-fields
parsing and rendering of align(N) on struct fields
2 parents 9322eee + 43587af commit ec2f9ef

File tree

7 files changed

+54
-12
lines changed

7 files changed

+54
-12
lines changed

src/all_types.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,8 @@ struct AstNodeStructField {
849849
Buf *name;
850850
AstNode *type;
851851
AstNode *value;
852+
// populated if the "align(A)" is present
853+
AstNode *align_expr;
852854
};
853855

854856
struct AstNodeStringLiteral {

src/analyze.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2255,9 +2255,21 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
22552255
if (field->gen_index == SIZE_MAX)
22562256
continue;
22572257

2258-
size_t this_field_align;
2259-
if (packed) {
2258+
uint32_t this_field_align;
2259+
2260+
// TODO: Sets the field alignment in the type, but doesn't do anything
2261+
// to actually make that happen yet.
2262+
AstNode *align_expr = field->decl_node->data.struct_field.align_expr;
2263+
if (align_expr != nullptr) {
2264+
if (!analyze_const_align(g, &struct_type->data.structure.decls_scope->base, align_expr, &this_field_align)) {
2265+
field->type_entry = g->builtin_types.entry_invalid;
2266+
} else {
2267+
field->align = this_field_align;
2268+
}
2269+
} else if (packed) {
22602270
// TODO: https://github.com/ziglang/zig/issues/1512
2271+
// TODO: Validate requested alignment is possible, given packed,
2272+
// and given other field alignments.
22612273
this_field_align = 1;
22622274
// TODO If we have no type_entry for the field, we've already failed to
22632275
// compile the program correctly. This stage1 compiler needs a deeper

src/parser.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -782,24 +782,26 @@ static AstNode *ast_parse_var_decl(ParseContext *pc) {
782782
return res;
783783
}
784784

785-
// ContainerField <- IDENTIFIER (COLON TypeExpr)? (EQUAL Expr)?
785+
// ContainerField <- IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)?
786786
static AstNode *ast_parse_container_field(ParseContext *pc) {
787787
Token *identifier = eat_token_if(pc, TokenIdSymbol);
788788
if (identifier == nullptr)
789789
return nullptr;
790790

791791
AstNode *type_expr = nullptr;
792-
if (eat_token_if(pc, TokenIdColon) != nullptr)
792+
if (eat_token_if(pc, TokenIdColon) != nullptr) {
793793
type_expr = ast_expect(pc, ast_parse_type_expr);
794+
}
795+
AstNode *align_expr = ast_parse_byte_align(pc);
794796
AstNode *expr = nullptr;
795797
if (eat_token_if(pc, TokenIdEq) != nullptr)
796798
expr = ast_expect(pc, ast_parse_expr);
797799

798-
799800
AstNode *res = ast_create_node(pc, NodeTypeStructField, identifier);
800801
res->data.struct_field.name = token_buf(identifier);
801802
res->data.struct_field.type = type_expr;
802803
res->data.struct_field.value = expr;
804+
res->data.struct_field.align_expr = align_expr;
803805
return res;
804806
}
805807

std/zig/ast.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,7 @@ pub const Node = struct {
761761
name_token: TokenIndex,
762762
type_expr: ?*Node,
763763
value_expr: ?*Node,
764+
align_expr: ?*Node,
764765

765766
pub fn iterate(self: *ContainerField, index: usize) ?*Node {
766767
var i = index;

std/zig/parse.zig

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -380,16 +380,18 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
380380
return &node.base;
381381
}
382382

383-
/// ContainerField <- IDENTIFIER (COLON TypeExpr)? (EQUAL Expr)?
383+
/// ContainerField <- IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)?
384384
fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
385385
const name_token = eatToken(it, .Identifier) orelse return null;
386386

387-
const type_expr = if (eatToken(it, .Colon)) |_|
388-
try expectNode(arena, it, tree, parseTypeExpr, AstError{
387+
var align_expr: ?*Node = null;
388+
var type_expr: ?*Node = null;
389+
if (eatToken(it, .Colon)) |_| {
390+
type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{
389391
.ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index },
390-
})
391-
else
392-
null;
392+
});
393+
align_expr = try parseByteAlign(arena, it, tree);
394+
}
393395

394396
const value_expr = if (eatToken(it, .Equal)) |_|
395397
try expectNode(arena, it, tree, parseExpr, AstError{
@@ -406,6 +408,7 @@ fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
406408
.name_token = name_token,
407409
.type_expr = type_expr,
408410
.value_expr = value_expr,
411+
.align_expr = align_expr,
409412
};
410413
return &node.base;
411414
}

std/zig/parser_test.zig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,15 @@ test "zig fmt: doc comments on param decl" {
166166
);
167167
}
168168

169+
test "zig fmt: aligned struct field" {
170+
try testCanonical(
171+
\\pub const S = struct {
172+
\\ f: i32 align(32),
173+
\\};
174+
\\
175+
);
176+
}
177+
169178
test "zig fmt: preserve space between async fn definitions" {
170179
try testCanonical(
171180
\\async fn a() void {}

std/zig/render.zig

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,20 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i
206206
} else if (field.type_expr != null and field.value_expr == null) {
207207
try renderToken(tree, stream, field.name_token, indent, start_col, Space.None); // name
208208
try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // :
209-
return renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, Space.Comma); // type,
209+
210+
if (field.align_expr) |align_value_expr| {
211+
try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, Space.Space); // type
212+
const lparen_token = tree.prevToken(align_value_expr.firstToken());
213+
const align_kw = tree.prevToken(lparen_token);
214+
const rparen_token = tree.nextToken(align_value_expr.lastToken());
215+
try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align
216+
try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (
217+
try renderExpression(allocator, stream, tree, indent, start_col, align_value_expr, Space.None); // alignment
218+
try renderToken(tree, stream, rparen_token, indent, start_col, Space.Comma); // )
219+
} else {
220+
try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, Space.Comma); // type,
221+
}
222+
210223
} else if (field.type_expr == null and field.value_expr != null) {
211224
try renderToken(tree, stream, field.name_token, indent, start_col, Space.Space); // name
212225
try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // =

0 commit comments

Comments
 (0)