diff --git a/parser.c b/parser.c index 41e4a9ef56..be950baa5a 100644 --- a/parser.c +++ b/parser.c @@ -897,7 +897,7 @@ static AstNodeIndex parsePtrModifiersAndType( }, }); } - if (addrspace_expr != 0) { + if (addrspace_expr != 0 || (sentinel != 0 && align_expr != 0)) { return addNode(&p->nodes, (AstNodeItem) { .tag = AST_NODE_PTR_TYPE, @@ -905,7 +905,7 @@ static AstNodeIndex parsePtrModifiersAndType( .data = { .lhs = addExtra(p, (AstNodeIndex[]) { OPT(sentinel), OPT(align_expr), - addrspace_expr }, + OPT(addrspace_expr) }, 3), .rhs = child_type, }, @@ -946,17 +946,74 @@ static AstNodeIndex parseTypeExpr(Parser* p) { return parsePtrModifiersAndType(p, asterisk); } case TOKEN_ASTERISK_ASTERISK: { - // ** is two nested pointer types sharing the same token + // ** is two nested pointer types sharing the same token. + // Inner pointer gets modifiers, outer wraps it with none. + // (Matches upstream Parse.zig asterisk_asterisk case) const AstTokenIndex asterisk = nextToken(p); - // Inner pointer: parse modifiers and child type - const AstNodeIndex inner_child = parseTypeExpr(p); - const AstNodeIndex inner = addNode(&p->nodes, - (AstNodeItem) { - .tag = AST_NODE_PTR_TYPE_ALIGNED, - .main_token = asterisk, - .data = { .lhs = 0, .rhs = inner_child }, - }); - // Outer pointer wraps the inner + + // Parse inner pointer modifiers (no sentinel for **) + while (p->token_tags[p->tok_i] == TOKEN_KEYWORD_CONST + || p->token_tags[p->tok_i] == TOKEN_KEYWORD_VOLATILE + || p->token_tags[p->tok_i] == TOKEN_KEYWORD_ALLOWZERO) + p->tok_i++; + AstNodeIndex align_expr = 0; + AstNodeIndex bit_range_start = 0; + AstNodeIndex bit_range_end = 0; + if (eatToken(p, TOKEN_KEYWORD_ALIGN) != null_token) { + expectToken(p, TOKEN_L_PAREN); + align_expr = expectExpr(p); + if (eatToken(p, TOKEN_COLON) != null_token) { + bit_range_start = expectExpr(p); + expectToken(p, TOKEN_COLON); + bit_range_end = expectExpr(p); + } + expectToken(p, TOKEN_R_PAREN); + } + const AstNodeIndex addrspace_expr = parseAddrSpace(p); + while (p->token_tags[p->tok_i] == TOKEN_KEYWORD_CONST + || p->token_tags[p->tok_i] == TOKEN_KEYWORD_VOLATILE + || p->token_tags[p->tok_i] == TOKEN_KEYWORD_ALLOWZERO) + p->tok_i++; + const AstNodeIndex elem_type = parseTypeExpr(p); + assert(elem_type != 0); + + AstNodeIndex inner; + if (bit_range_start != 0) { + inner = addNode(&p->nodes, + (AstNodeItem) { + .tag = AST_NODE_PTR_TYPE_BIT_RANGE, + .main_token = asterisk, + .data = { + .lhs = addExtra(p, + (AstNodeIndex[]) { OPT(0), align_expr, + OPT(addrspace_expr), bit_range_start, + bit_range_end }, + 5), + .rhs = elem_type, + }, + }); + } else if (addrspace_expr != 0) { + inner = addNode(&p->nodes, + (AstNodeItem) { + .tag = AST_NODE_PTR_TYPE, + .main_token = asterisk, + .data = { + .lhs = addExtra(p, + (AstNodeIndex[]) { OPT(0), OPT(align_expr), + addrspace_expr }, + 3), + .rhs = elem_type, + }, + }); + } else { + inner = addNode(&p->nodes, + (AstNodeItem) { + .tag = AST_NODE_PTR_TYPE_ALIGNED, + .main_token = asterisk, + .data = { .lhs = align_expr, .rhs = elem_type }, + }); + } + return addNode(&p->nodes, (AstNodeItem) { .tag = AST_NODE_PTR_TYPE_ALIGNED, @@ -1034,7 +1091,7 @@ static AstNodeIndex parseTypeExpr(Parser* p) { }, }); } - if (addrspace_expr != 0) { + if (addrspace_expr != 0 || (sentinel != 0 && align_expr != 0)) { return addNode(&p->nodes, (AstNodeItem) { .tag = AST_NODE_PTR_TYPE, @@ -1042,7 +1099,8 @@ static AstNodeIndex parseTypeExpr(Parser* p) { .data = { .lhs = addExtra(p, (AstNodeIndex[]) { OPT(sentinel), - OPT(align_expr), addrspace_expr }, + OPT(align_expr), + OPT(addrspace_expr) }, 3), .rhs = elem_type, }, @@ -1081,7 +1139,7 @@ static AstNodeIndex parseTypeExpr(Parser* p) { || p->token_tags[p->tok_i] == TOKEN_KEYWORD_ALLOWZERO) p->tok_i++; const AstNodeIndex elem_type = parseTypeExpr(p); - if (addrspace_expr != 0) { + if (addrspace_expr != 0 || (sentinel != 0 && align_expr != 0)) { return addNode(&p->nodes, (AstNodeItem) { .tag = AST_NODE_PTR_TYPE, @@ -1089,13 +1147,14 @@ static AstNodeIndex parseTypeExpr(Parser* p) { .data = { .lhs = addExtra(p, (AstNodeIndex[]) { OPT(sentinel), - OPT(align_expr), addrspace_expr }, + OPT(align_expr), + OPT(addrspace_expr) }, 3), .rhs = elem_type, }, }); } - if (sentinel != 0 && align_expr == 0) { + if (sentinel != 0) { return addNode(&p->nodes, (AstNodeItem) { .tag = AST_NODE_PTR_TYPE_SENTINEL, diff --git a/parser_test.zig b/parser_test.zig index ab26f4603c..13e18d2d4f 100644 --- a/parser_test.zig +++ b/parser_test.zig @@ -2850,6 +2850,28 @@ test "zig fmt: nested pointers with ** tokens" { ); } +test "zig fmt: pointer attributes" { + try testCanonical( + \\extern fn f1(s: *align(*u8) u8) c_int; + \\extern fn f2(s: **align(1) *const *volatile u8) c_int; + \\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int; + \\extern fn f4(s: *align(1) const volatile u8) c_int; + \\extern fn f5(s: [*:0]align(1) const volatile u8) c_int; + \\ + ); +} + +test "zig fmt: slice attributes" { + try testCanonical( + \\extern fn f1(s: []align(*u8) u8) c_int; + \\extern fn f2(s: []align(1) []const []volatile u8) c_int; + \\extern fn f3(s: []align(1) const [:0]align(1) volatile []const volatile u8) c_int; + \\extern fn f4(s: []align(1) const volatile u8) c_int; + \\extern fn f5(s: [:0]align(1) const volatile u8) c_int; + \\ + ); +} + test "zig fmt: test declaration" { try testCanonical( \\test "test name" { @@ -5550,5 +5572,3 @@ fn zigAst(gpa: Allocator, c_ast: c.Ast) !Ast { .errors = errors, }; } - -// copy-past from parser_test.zig