authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-23 11:19:27-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-08-23 11:19:27-04:00
logec2f9ef4e8be5995ab652dde59b12ee340a9e28d
tree1f91f64575dcf8e9184f74d804021d0fadcb8a24
parent9322eee80aadd6d9f80ebc11d29d09898237a14a
parent43587af01acba98d9c09c4e0cf20343be8d7c81b
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #3114 from Tetralux/align-on-struct-fields

parsing and rendering of align(N) on struct fields

7 files changed, 54 insertions(+), 12 deletions(-)

src/all_types.hpp+2
......@@ -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
854856struct AstNodeStringLiteral {
src/analyze.cpp+14-2
......@@ -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+5-3
......@@ -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)?
786786static 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+1
......@@ -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+9-6
......@@ -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)?
384384fn 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+9
......@@ -166,6 +166,15 @@ test "zig fmt: doc comments on param decl" {
166166 );
167167}
168168
169test "zig fmt: aligned struct field" {
170 try testCanonical(
171 \\pub const S = struct {
172 \\ f: i32 align(32),
173 \\};
174 \\
175 );
176}
177
169178test "zig fmt: preserve space between async fn definitions" {
170179 try testCanonical(
171180 \\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
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); // =