mirror of
https://github.com/ziglang/zig.git
synced 2025-12-15 18:53:07 +00:00
Merge pull request #3114 from Tetralux/align-on-struct-fields
parsing and rendering of align(N) on struct fields
This commit is contained in:
commit
ec2f9ef4e8
@ -849,6 +849,8 @@ struct AstNodeStructField {
|
||||
Buf *name;
|
||||
AstNode *type;
|
||||
AstNode *value;
|
||||
// populated if the "align(A)" is present
|
||||
AstNode *align_expr;
|
||||
};
|
||||
|
||||
struct AstNodeStringLiteral {
|
||||
|
||||
@ -2255,9 +2255,21 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
|
||||
if (field->gen_index == SIZE_MAX)
|
||||
continue;
|
||||
|
||||
size_t this_field_align;
|
||||
if (packed) {
|
||||
uint32_t this_field_align;
|
||||
|
||||
// TODO: Sets the field alignment in the type, but doesn't do anything
|
||||
// to actually make that happen yet.
|
||||
AstNode *align_expr = field->decl_node->data.struct_field.align_expr;
|
||||
if (align_expr != nullptr) {
|
||||
if (!analyze_const_align(g, &struct_type->data.structure.decls_scope->base, align_expr, &this_field_align)) {
|
||||
field->type_entry = g->builtin_types.entry_invalid;
|
||||
} else {
|
||||
field->align = this_field_align;
|
||||
}
|
||||
} else if (packed) {
|
||||
// TODO: https://github.com/ziglang/zig/issues/1512
|
||||
// TODO: Validate requested alignment is possible, given packed,
|
||||
// and given other field alignments.
|
||||
this_field_align = 1;
|
||||
// TODO If we have no type_entry for the field, we've already failed to
|
||||
// compile the program correctly. This stage1 compiler needs a deeper
|
||||
|
||||
@ -782,24 +782,26 @@ static AstNode *ast_parse_var_decl(ParseContext *pc) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// ContainerField <- IDENTIFIER (COLON TypeExpr)? (EQUAL Expr)?
|
||||
// ContainerField <- IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)?
|
||||
static AstNode *ast_parse_container_field(ParseContext *pc) {
|
||||
Token *identifier = eat_token_if(pc, TokenIdSymbol);
|
||||
if (identifier == nullptr)
|
||||
return nullptr;
|
||||
|
||||
AstNode *type_expr = nullptr;
|
||||
if (eat_token_if(pc, TokenIdColon) != nullptr)
|
||||
if (eat_token_if(pc, TokenIdColon) != nullptr) {
|
||||
type_expr = ast_expect(pc, ast_parse_type_expr);
|
||||
}
|
||||
AstNode *align_expr = ast_parse_byte_align(pc);
|
||||
AstNode *expr = nullptr;
|
||||
if (eat_token_if(pc, TokenIdEq) != nullptr)
|
||||
expr = ast_expect(pc, ast_parse_expr);
|
||||
|
||||
|
||||
AstNode *res = ast_create_node(pc, NodeTypeStructField, identifier);
|
||||
res->data.struct_field.name = token_buf(identifier);
|
||||
res->data.struct_field.type = type_expr;
|
||||
res->data.struct_field.value = expr;
|
||||
res->data.struct_field.align_expr = align_expr;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@ -761,6 +761,7 @@ pub const Node = struct {
|
||||
name_token: TokenIndex,
|
||||
type_expr: ?*Node,
|
||||
value_expr: ?*Node,
|
||||
align_expr: ?*Node,
|
||||
|
||||
pub fn iterate(self: *ContainerField, index: usize) ?*Node {
|
||||
var i = index;
|
||||
|
||||
@ -380,16 +380,18 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
return &node.base;
|
||||
}
|
||||
|
||||
/// ContainerField <- IDENTIFIER (COLON TypeExpr)? (EQUAL Expr)?
|
||||
/// ContainerField <- IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)?
|
||||
fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
const name_token = eatToken(it, .Identifier) orelse return null;
|
||||
|
||||
const type_expr = if (eatToken(it, .Colon)) |_|
|
||||
try expectNode(arena, it, tree, parseTypeExpr, AstError{
|
||||
var align_expr: ?*Node = null;
|
||||
var type_expr: ?*Node = null;
|
||||
if (eatToken(it, .Colon)) |_| {
|
||||
type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{
|
||||
.ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index },
|
||||
})
|
||||
else
|
||||
null;
|
||||
});
|
||||
align_expr = try parseByteAlign(arena, it, tree);
|
||||
}
|
||||
|
||||
const value_expr = if (eatToken(it, .Equal)) |_|
|
||||
try expectNode(arena, it, tree, parseExpr, AstError{
|
||||
@ -406,6 +408,7 @@ fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
|
||||
.name_token = name_token,
|
||||
.type_expr = type_expr,
|
||||
.value_expr = value_expr,
|
||||
.align_expr = align_expr,
|
||||
};
|
||||
return &node.base;
|
||||
}
|
||||
|
||||
@ -166,6 +166,15 @@ test "zig fmt: doc comments on param decl" {
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: aligned struct field" {
|
||||
try testCanonical(
|
||||
\\pub const S = struct {
|
||||
\\ f: i32 align(32),
|
||||
\\};
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: preserve space between async fn definitions" {
|
||||
try testCanonical(
|
||||
\\async fn a() void {}
|
||||
|
||||
@ -206,7 +206,20 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i
|
||||
} else if (field.type_expr != null and field.value_expr == null) {
|
||||
try renderToken(tree, stream, field.name_token, indent, start_col, Space.None); // name
|
||||
try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // :
|
||||
return renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, Space.Comma); // type,
|
||||
|
||||
if (field.align_expr) |align_value_expr| {
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, Space.Space); // type
|
||||
const lparen_token = tree.prevToken(align_value_expr.firstToken());
|
||||
const align_kw = tree.prevToken(lparen_token);
|
||||
const rparen_token = tree.nextToken(align_value_expr.lastToken());
|
||||
try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align
|
||||
try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // (
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, align_value_expr, Space.None); // alignment
|
||||
try renderToken(tree, stream, rparen_token, indent, start_col, Space.Comma); // )
|
||||
} else {
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, Space.Comma); // type,
|
||||
}
|
||||
|
||||
} else if (field.type_expr == null and field.value_expr != null) {
|
||||
try renderToken(tree, stream, field.name_token, indent, start_col, Space.Space); // name
|
||||
try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // =
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user