| author | |
| committer | |
| log | ec2f9ef4e8be5995ab652dde59b12ee340a9e28d |
| tree | 1f91f64575dcf8e9184f74d804021d0fadcb8a24 |
| parent | 9322eee80aadd6d9f80ebc11d29d09898237a14a |
| parent | 43587af01acba98d9c09c4e0cf20343be8d7c81b |
| signature |
parsing and rendering of align(N) on struct fields7 files changed, 54 insertions(+), 12 deletions(-)
src/all_types.hpp+2| ... | ... | @@ -849,6 +849,8 @@ struct AstNodeStructField { |
| 849 | 849 | Buf *name; |
| 850 | 850 | AstNode *type; |
| 851 | 851 | AstNode *value; |
| 852 | // populated if the "align(A)" is present | |
| 853 | AstNode *align_expr; | |
| 852 | 854 | }; |
| 853 | 855 | |
| 854 | 856 | struct AstNodeStringLiteral { |
src/analyze.cpp+14-2| ... | ... | @@ -2255,9 +2255,21 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { |
| 2255 | 2255 | if (field->gen_index == SIZE_MAX) |
| 2256 | 2256 | continue; |
| 2257 | 2257 | |
| 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) { | |
| 2260 | 2270 | // TODO: https://github.com/ziglang/zig/issues/1512 |
| 2271 | // TODO: Validate requested alignment is possible, given packed, | |
| 2272 | // and given other field alignments. | |
| 2261 | 2273 | this_field_align = 1; |
| 2262 | 2274 | // TODO If we have no type_entry for the field, we've already failed to |
| 2263 | 2275 | // compile the program correctly. This stage1 compiler needs a deeper |
src/parser.cpp+5-3| ... | ... | @@ -782,24 +782,26 @@ static AstNode *ast_parse_var_decl(ParseContext *pc) { |
| 782 | 782 | return res; |
| 783 | 783 | } |
| 784 | 784 | |
| 785 | // ContainerField <- IDENTIFIER (COLON TypeExpr)? (EQUAL Expr)? | |
| 785 | // ContainerField <- IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)? | |
| 786 | 786 | static AstNode *ast_parse_container_field(ParseContext *pc) { |
| 787 | 787 | Token *identifier = eat_token_if(pc, TokenIdSymbol); |
| 788 | 788 | if (identifier == nullptr) |
| 789 | 789 | return nullptr; |
| 790 | 790 | |
| 791 | 791 | AstNode *type_expr = nullptr; |
| 792 | if (eat_token_if(pc, TokenIdColon) != nullptr) | |
| 792 | if (eat_token_if(pc, TokenIdColon) != nullptr) { | |
| 793 | 793 | type_expr = ast_expect(pc, ast_parse_type_expr); |
| 794 | } | |
| 795 | AstNode *align_expr = ast_parse_byte_align(pc); | |
| 794 | 796 | AstNode *expr = nullptr; |
| 795 | 797 | if (eat_token_if(pc, TokenIdEq) != nullptr) |
| 796 | 798 | expr = ast_expect(pc, ast_parse_expr); |
| 797 | 799 | |
| 798 | ||
| 799 | 800 | AstNode *res = ast_create_node(pc, NodeTypeStructField, identifier); |
| 800 | 801 | res->data.struct_field.name = token_buf(identifier); |
| 801 | 802 | res->data.struct_field.type = type_expr; |
| 802 | 803 | res->data.struct_field.value = expr; |
| 804 | res->data.struct_field.align_expr = align_expr; | |
| 803 | 805 | return res; |
| 804 | 806 | } |
| 805 | 807 |
std/zig/ast.zig+1| ... | ... | @@ -761,6 +761,7 @@ pub const Node = struct { |
| 761 | 761 | name_token: TokenIndex, |
| 762 | 762 | type_expr: ?*Node, |
| 763 | 763 | value_expr: ?*Node, |
| 764 | align_expr: ?*Node, | |
| 764 | 765 | |
| 765 | 766 | pub fn iterate(self: *ContainerField, index: usize) ?*Node { |
| 766 | 767 | var i = index; |
std/zig/parse.zig+9-6| ... | ... | @@ -380,16 +380,18 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 380 | 380 | return &node.base; |
| 381 | 381 | } |
| 382 | 382 | |
| 383 | /// ContainerField <- IDENTIFIER (COLON TypeExpr)? (EQUAL Expr)? | |
| 383 | /// ContainerField <- IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)? | |
| 384 | 384 | fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 385 | 385 | const name_token = eatToken(it, .Identifier) orelse return null; |
| 386 | 386 | |
| 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{ | |
| 389 | 391 | .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, |
| 390 | }) | |
| 391 | else | |
| 392 | null; | |
| 392 | }); | |
| 393 | align_expr = try parseByteAlign(arena, it, tree); | |
| 394 | } | |
| 393 | 395 | |
| 394 | 396 | const value_expr = if (eatToken(it, .Equal)) |_| |
| 395 | 397 | try expectNode(arena, it, tree, parseExpr, AstError{ |
| ... | ... | @@ -406,6 +408,7 @@ fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 406 | 408 | .name_token = name_token, |
| 407 | 409 | .type_expr = type_expr, |
| 408 | 410 | .value_expr = value_expr, |
| 411 | .align_expr = align_expr, | |
| 409 | 412 | }; |
| 410 | 413 | return &node.base; |
| 411 | 414 | } |
std/zig/parser_test.zig+9| ... | ... | @@ -166,6 +166,15 @@ test "zig fmt: doc comments on param decl" { |
| 166 | 166 | ); |
| 167 | 167 | } |
| 168 | 168 | |
| 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 | ||
| 169 | 178 | test "zig fmt: preserve space between async fn definitions" { |
| 170 | 179 | try testCanonical( |
| 171 | 180 | \\async fn a() void {} |
std/zig/render.zig+14-1| ... | ... | @@ -206,7 +206,20 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i |
| 206 | 206 | } else if (field.type_expr != null and field.value_expr == null) { |
| 207 | 207 | try renderToken(tree, stream, field.name_token, indent, start_col, Space.None); // name |
| 208 | 208 | 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 | ||
| 210 | 223 | } else if (field.type_expr == null and field.value_expr != null) { |
| 211 | 224 | try renderToken(tree, stream, field.name_token, indent, start_col, Space.Space); // name |
| 212 | 225 | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // = |