authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-15 18:34:06+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-07-15 18:34:06+00:00
log6b103324d2d935260138584877dbe1593790b953
tree3d1dc5c5378ac41ab5ca24f549721a882583454f
parenta7c3cec65f1639195e787b98900c3f126953f880
parentc5b7322319a9559423fcda5c20c3b2e22338b2b4
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #5872 from ziglang/ast-flatten-2

stage2: introduce the concept of "trailer flags" to the AST

9 files changed, 773 insertions(+), 421 deletions(-)

lib/std/meta.zig+1
......@@ -6,6 +6,7 @@ const math = std.math;
66const testing = std.testing;
77
88pub const trait = @import("meta/trait.zig");
9pub const TrailerFlags = @import("meta/trailer_flags.zig").TrailerFlags;
910
1011const TypeInfo = builtin.TypeInfo;
1112
lib/std/meta/trailer_flags.zig created+145
......@@ -0,0 +1,145 @@
1const std = @import("../std.zig");
2const meta = std.meta;
3const testing = std.testing;
4const mem = std.mem;
5const assert = std.debug.assert;
6
7/// This is useful for saving memory when allocating an object that has many
8/// optional components. The optional objects are allocated sequentially in
9/// memory, and a single integer is used to represent each optional object
10/// and whether it is present based on each corresponding bit.
11pub fn TrailerFlags(comptime Fields: type) type {
12 return struct {
13 bits: Int,
14
15 pub const Int = @Type(.{ .Int = .{ .bits = bit_count, .is_signed = false } });
16 pub const bit_count = @typeInfo(Fields).Struct.fields.len;
17
18 pub const Self = @This();
19
20 pub fn has(self: Self, comptime name: []const u8) bool {
21 const field_index = meta.fieldIndex(Fields, name).?;
22 return (self.bits & (1 << field_index)) != 0;
23 }
24
25 pub fn get(self: Self, p: [*]align(@alignOf(Fields)) const u8, comptime name: []const u8) ?Field(name) {
26 if (!self.has(name))
27 return null;
28 return self.ptrConst(p, name).*;
29 }
30
31 pub fn setFlag(self: *Self, comptime name: []const u8) void {
32 const field_index = meta.fieldIndex(Fields, name).?;
33 self.bits |= 1 << field_index;
34 }
35
36 /// `fields` is a struct with each field set to an optional value.
37 /// Missing fields are assumed to be `null`.
38 /// Only the non-null bits are observed and are used to set the flag bits.
39 pub fn init(fields: anytype) Self {
40 var self: Self = .{ .bits = 0 };
41 inline for (@typeInfo(@TypeOf(fields)).Struct.fields) |field| {
42 const opt: ?Field(field.name) = @field(fields, field.name);
43 const field_index = meta.fieldIndex(Fields, field.name).?;
44 self.bits |= @as(Int, @boolToInt(opt != null)) << field_index;
45 }
46 return self;
47 }
48
49 /// `fields` is a struct with each field set to an optional value (same as `init`).
50 /// Missing fields are assumed to be `null`.
51 pub fn setMany(self: Self, p: [*]align(@alignOf(Fields)) u8, fields: anytype) void {
52 inline for (@typeInfo(@TypeOf(fields)).Struct.fields) |field| {
53 const opt: ?Field(field.name) = @field(fields, field.name);
54 if (opt) |value| {
55 self.set(p, field.name, value);
56 }
57 }
58 }
59
60 pub fn set(
61 self: Self,
62 p: [*]align(@alignOf(Fields)) u8,
63 comptime name: []const u8,
64 value: Field(name),
65 ) void {
66 self.ptr(p, name).* = value;
67 }
68
69 pub fn ptr(self: Self, p: [*]align(@alignOf(Fields)) u8, comptime name: []const u8) *Field(name) {
70 if (@sizeOf(Field(name)) == 0)
71 return undefined;
72 const off = self.offset(p, name);
73 return @ptrCast(*Field(name), @alignCast(@alignOf(Field(name)), p + off));
74 }
75
76 pub fn ptrConst(self: Self, p: [*]align(@alignOf(Fields)) const u8, comptime name: []const u8) *const Field(name) {
77 if (@sizeOf(Field(name)) == 0)
78 return undefined;
79 const off = self.offset(p, name);
80 return @ptrCast(*const Field(name), @alignCast(@alignOf(Field(name)), p + off));
81 }
82
83 pub fn offset(self: Self, p: [*]align(@alignOf(Fields)) const u8, comptime name: []const u8) usize {
84 var off: usize = 0;
85 inline for (@typeInfo(Fields).Struct.fields) |field, i| {
86 const active = (self.bits & (1 << i)) != 0;
87 if (comptime mem.eql(u8, field.name, name)) {
88 assert(active);
89 return mem.alignForwardGeneric(usize, off, @alignOf(field.field_type));
90 } else if (active) {
91 off = mem.alignForwardGeneric(usize, off, @alignOf(field.field_type));
92 off += @sizeOf(field.field_type);
93 }
94 }
95 @compileError("no field named " ++ name ++ " in type " ++ @typeName(Fields));
96 }
97
98 pub fn Field(comptime name: []const u8) type {
99 return meta.fieldInfo(Fields, name).field_type;
100 }
101
102 pub fn sizeInBytes(self: Self) usize {
103 var off: usize = 0;
104 inline for (@typeInfo(Fields).Struct.fields) |field, i| {
105 if (@sizeOf(field.field_type) == 0)
106 continue;
107 if ((self.bits & (1 << i)) != 0) {
108 off = mem.alignForwardGeneric(usize, off, @alignOf(field.field_type));
109 off += @sizeOf(field.field_type);
110 }
111 }
112 return off;
113 }
114 };
115}
116
117test "TrailerFlags" {
118 const Flags = TrailerFlags(struct {
119 a: i32,
120 b: bool,
121 c: u64,
122 });
123 var flags = Flags.init(.{
124 .b = true,
125 .c = 1234,
126 });
127 const slice = try testing.allocator.allocAdvanced(u8, 8, flags.sizeInBytes(), .exact);
128 defer testing.allocator.free(slice);
129
130 flags.set(slice.ptr, "b", false);
131 flags.set(slice.ptr, "c", 12345678);
132
133 testing.expect(flags.get(slice.ptr, "a") == null);
134 testing.expect(!flags.get(slice.ptr, "b").?);
135 testing.expect(flags.get(slice.ptr, "c").? == 12345678);
136
137 flags.setMany(slice.ptr, .{
138 .b = true,
139 .c = 5678,
140 });
141
142 testing.expect(flags.get(slice.ptr, "a") == null);
143 testing.expect(flags.get(slice.ptr, "b").?);
144 testing.expect(flags.get(slice.ptr, "c").? == 5678);
145}
lib/std/zig/ast.zig+159-60
......@@ -675,42 +675,84 @@ pub const Node = struct {
675675 }
676676 };
677677
678 /// Trailed in memory by possibly many things, with each optional thing
679 /// determined by a bit in `trailer_flags`.
678680 pub const VarDecl = struct {
679681 base: Node = Node{ .id = .VarDecl },
680 doc_comments: ?*DocComment,
681 visib_token: ?TokenIndex,
682 thread_local_token: ?TokenIndex,
683 name_token: TokenIndex,
684 eq_token: ?TokenIndex,
682 trailer_flags: TrailerFlags,
685683 mut_token: TokenIndex,
686 comptime_token: ?TokenIndex,
687 extern_export_token: ?TokenIndex,
688 lib_name: ?*Node,
689 type_node: ?*Node,
690 align_node: ?*Node,
691 section_node: ?*Node,
692 init_node: ?*Node,
684 name_token: TokenIndex,
693685 semicolon_token: TokenIndex,
694686
687 pub const TrailerFlags = std.meta.TrailerFlags(struct {
688 doc_comments: *DocComment,
689 visib_token: TokenIndex,
690 thread_local_token: TokenIndex,
691 eq_token: TokenIndex,
692 comptime_token: TokenIndex,
693 extern_export_token: TokenIndex,
694 lib_name: *Node,
695 type_node: *Node,
696 align_node: *Node,
697 section_node: *Node,
698 init_node: *Node,
699 });
700
701 pub const RequiredFields = struct {
702 mut_token: TokenIndex,
703 name_token: TokenIndex,
704 semicolon_token: TokenIndex,
705 };
706
707 pub fn getTrailer(self: *const VarDecl, comptime name: []const u8) ?TrailerFlags.Field(name) {
708 const trailers_start = @ptrCast([*]const u8, self) + @sizeOf(VarDecl);
709 return self.trailer_flags.get(trailers_start, name);
710 }
711
712 pub fn setTrailer(self: *VarDecl, comptime name: []const u8, value: TrailerFlags.Field(name)) void {
713 const trailers_start = @ptrCast([*]u8, self) + @sizeOf(VarDecl);
714 self.trailer_flags.set(trailers_start, name, value);
715 }
716
717 pub fn create(allocator: *mem.Allocator, required: RequiredFields, trailers: anytype) !*VarDecl {
718 const trailer_flags = TrailerFlags.init(trailers);
719 const bytes = try allocator.alignedAlloc(u8, @alignOf(VarDecl), sizeInBytes(trailer_flags));
720 const var_decl = @ptrCast(*VarDecl, bytes.ptr);
721 var_decl.* = .{
722 .trailer_flags = trailer_flags,
723 .mut_token = required.mut_token,
724 .name_token = required.name_token,
725 .semicolon_token = required.semicolon_token,
726 };
727 const trailers_start = bytes.ptr + @sizeOf(VarDecl);
728 trailer_flags.setMany(trailers_start, trailers);
729 return var_decl;
730 }
731
732 pub fn destroy(self: *VarDecl, allocator: *mem.Allocator) void {
733 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.trailer_flags)];
734 allocator.free(bytes);
735 }
736
695737 pub fn iterate(self: *const VarDecl, index: usize) ?*Node {
696738 var i = index;
697739
698 if (self.type_node) |type_node| {
740 if (self.getTrailer("type_node")) |type_node| {
699741 if (i < 1) return type_node;
700742 i -= 1;
701743 }
702744
703 if (self.align_node) |align_node| {
745 if (self.getTrailer("align_node")) |align_node| {
704746 if (i < 1) return align_node;
705747 i -= 1;
706748 }
707749
708 if (self.section_node) |section_node| {
750 if (self.getTrailer("section_node")) |section_node| {
709751 if (i < 1) return section_node;
710752 i -= 1;
711753 }
712754
713 if (self.init_node) |init_node| {
755 if (self.getTrailer("init_node")) |init_node| {
714756 if (i < 1) return init_node;
715757 i -= 1;
716758 }
......@@ -719,17 +761,21 @@ pub const Node = struct {
719761 }
720762
721763 pub fn firstToken(self: *const VarDecl) TokenIndex {
722 if (self.visib_token) |visib_token| return visib_token;
723 if (self.thread_local_token) |thread_local_token| return thread_local_token;
724 if (self.comptime_token) |comptime_token| return comptime_token;
725 if (self.extern_export_token) |extern_export_token| return extern_export_token;
726 assert(self.lib_name == null);
764 if (self.getTrailer("visib_token")) |visib_token| return visib_token;
765 if (self.getTrailer("thread_local_token")) |thread_local_token| return thread_local_token;
766 if (self.getTrailer("comptime_token")) |comptime_token| return comptime_token;
767 if (self.getTrailer("extern_export_token")) |extern_export_token| return extern_export_token;
768 assert(self.getTrailer("lib_name") == null);
727769 return self.mut_token;
728770 }
729771
730772 pub fn lastToken(self: *const VarDecl) TokenIndex {
731773 return self.semicolon_token;
732774 }
775
776 fn sizeInBytes(trailer_flags: TrailerFlags) usize {
777 return @sizeOf(VarDecl) + trailer_flags.sizeInBytes();
778 }
733779 };
734780
735781 pub const Use = struct {
......@@ -972,25 +1018,34 @@ pub const Node = struct {
9721018 };
9731019
9741020 /// The params are directly after the FnProto in memory.
975 /// TODO have a flags field for the optional nodes, and have them appended
976 /// before or after the parameters in memory.
1021 /// Next, each optional thing determined by a bit in `trailer_flags`.
9771022 pub const FnProto = struct {
9781023 base: Node = Node{ .id = .FnProto },
979 doc_comments: ?*DocComment,
980 visib_token: ?TokenIndex,
1024 trailer_flags: TrailerFlags,
9811025 fn_token: TokenIndex,
982 name_token: ?TokenIndex,
9831026 params_len: NodeIndex,
9841027 return_type: ReturnType,
985 var_args_token: ?TokenIndex,
986 extern_export_inline_token: ?TokenIndex,
987 body_node: ?*Node,
988 lib_name: ?*Node, // populated if this is an extern declaration
989 align_expr: ?*Node, // populated if align(A) is present
990 section_expr: ?*Node, // populated if linksection(A) is present
991 callconv_expr: ?*Node, // populated if callconv(A) is present
992 is_extern_prototype: bool = false, // TODO: Remove once extern fn rewriting is
993 is_async: bool = false, // TODO: remove once async fn rewriting is
1028
1029 pub const TrailerFlags = std.meta.TrailerFlags(struct {
1030 doc_comments: *DocComment,
1031 body_node: *Node,
1032 lib_name: *Node, // populated if this is an extern declaration
1033 align_expr: *Node, // populated if align(A) is present
1034 section_expr: *Node, // populated if linksection(A) is present
1035 callconv_expr: *Node, // populated if callconv(A) is present
1036 visib_token: TokenIndex,
1037 name_token: TokenIndex,
1038 var_args_token: TokenIndex,
1039 extern_export_inline_token: TokenIndex,
1040 is_extern_prototype: void, // TODO: Remove once extern fn rewriting is
1041 is_async: void, // TODO: remove once async fn rewriting is
1042 });
1043
1044 pub const RequiredFields = struct {
1045 fn_token: TokenIndex,
1046 params_len: NodeIndex,
1047 return_type: ReturnType,
1048 };
9941049
9951050 pub const ReturnType = union(enum) {
9961051 Explicit: *Node,
......@@ -1007,7 +1062,6 @@ pub const Node = struct {
10071062
10081063 pub const ParamType = union(enum) {
10091064 any_type: *Node,
1010 var_args: TokenIndex,
10111065 type_expr: *Node,
10121066 };
10131067
......@@ -1016,7 +1070,6 @@ pub const Node = struct {
10161070
10171071 if (i < 1) {
10181072 switch (self.param_type) {
1019 .var_args => return null,
10201073 .any_type, .type_expr => |node| return node,
10211074 }
10221075 }
......@@ -1030,34 +1083,79 @@ pub const Node = struct {
10301083 if (self.noalias_token) |noalias_token| return noalias_token;
10311084 if (self.name_token) |name_token| return name_token;
10321085 switch (self.param_type) {
1033 .var_args => |tok| return tok,
10341086 .any_type, .type_expr => |node| return node.firstToken(),
10351087 }
10361088 }
10371089
10381090 pub fn lastToken(self: *const ParamDecl) TokenIndex {
10391091 switch (self.param_type) {
1040 .var_args => |tok| return tok,
10411092 .any_type, .type_expr => |node| return node.lastToken(),
10421093 }
10431094 }
10441095 };
10451096
1097 /// For debugging purposes.
1098 pub fn dump(self: *const FnProto) void {
1099 const trailers_start = @alignCast(
1100 @alignOf(ParamDecl),
1101 @ptrCast([*]const u8, self) + @sizeOf(FnProto) + @sizeOf(ParamDecl) * self.params_len,
1102 );
1103 std.debug.print("{*} flags: {b} name_token: {} {*} params_len: {}\n", .{
1104 self,
1105 self.trailer_flags.bits,
1106 self.getTrailer("name_token"),
1107 self.trailer_flags.ptrConst(trailers_start, "name_token"),
1108 self.params_len,
1109 });
1110 }
1111
1112 pub fn getTrailer(self: *const FnProto, comptime name: []const u8) ?TrailerFlags.Field(name) {
1113 const trailers_start = @alignCast(
1114 @alignOf(ParamDecl),
1115 @ptrCast([*]const u8, self) + @sizeOf(FnProto) + @sizeOf(ParamDecl) * self.params_len,
1116 );
1117 return self.trailer_flags.get(trailers_start, name);
1118 }
1119
1120 pub fn setTrailer(self: *FnProto, comptime name: []const u8, value: TrailerFlags.Field(name)) void {
1121 const trailers_start = @alignCast(
1122 @alignOf(ParamDecl),
1123 @ptrCast([*]u8, self) + @sizeOf(FnProto) + @sizeOf(ParamDecl) * self.params_len,
1124 );
1125 self.trailer_flags.set(trailers_start, name, value);
1126 }
1127
10461128 /// After this the caller must initialize the params list.
1047 pub fn alloc(allocator: *mem.Allocator, params_len: NodeIndex) !*FnProto {
1048 const bytes = try allocator.alignedAlloc(u8, @alignOf(FnProto), sizeInBytes(params_len));
1049 return @ptrCast(*FnProto, bytes.ptr);
1129 pub fn create(allocator: *mem.Allocator, required: RequiredFields, trailers: anytype) !*FnProto {
1130 const trailer_flags = TrailerFlags.init(trailers);
1131 const bytes = try allocator.alignedAlloc(u8, @alignOf(FnProto), sizeInBytes(
1132 required.params_len,
1133 trailer_flags,
1134 ));
1135 const fn_proto = @ptrCast(*FnProto, bytes.ptr);
1136 fn_proto.* = .{
1137 .trailer_flags = trailer_flags,
1138 .fn_token = required.fn_token,
1139 .params_len = required.params_len,
1140 .return_type = required.return_type,
1141 };
1142 const trailers_start = @alignCast(
1143 @alignOf(ParamDecl),
1144 bytes.ptr + @sizeOf(FnProto) + @sizeOf(ParamDecl) * required.params_len,
1145 );
1146 trailer_flags.setMany(trailers_start, trailers);
1147 return fn_proto;
10501148 }
10511149
1052 pub fn free(self: *FnProto, allocator: *mem.Allocator) void {
1053 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len)];
1150 pub fn destroy(self: *FnProto, allocator: *mem.Allocator) void {
1151 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len, self.trailer_flags)];
10541152 allocator.free(bytes);
10551153 }
10561154
10571155 pub fn iterate(self: *const FnProto, index: usize) ?*Node {
10581156 var i = index;
10591157
1060 if (self.lib_name) |lib_name| {
1158 if (self.getTrailer("lib_name")) |lib_name| {
10611159 if (i < 1) return lib_name;
10621160 i -= 1;
10631161 }
......@@ -1066,23 +1164,21 @@ pub const Node = struct {
10661164 0
10671165 else switch (self.paramsConst()[self.params_len - 1].param_type) {
10681166 .any_type, .type_expr => self.params_len,
1069 .var_args => self.params_len - 1,
10701167 };
10711168 if (i < params_len) {
10721169 switch (self.paramsConst()[i].param_type) {
10731170 .any_type => |n| return n,
1074 .var_args => unreachable,
10751171 .type_expr => |n| return n,
10761172 }
10771173 }
10781174 i -= params_len;
10791175
1080 if (self.align_expr) |align_expr| {
1176 if (self.getTrailer("align_expr")) |align_expr| {
10811177 if (i < 1) return align_expr;
10821178 i -= 1;
10831179 }
10841180
1085 if (self.section_expr) |section_expr| {
1181 if (self.getTrailer("section_expr")) |section_expr| {
10861182 if (i < 1) return section_expr;
10871183 i -= 1;
10881184 }
......@@ -1095,7 +1191,7 @@ pub const Node = struct {
10951191 .Invalid => {},
10961192 }
10971193
1098 if (self.body_node) |body_node| {
1194 if (self.getTrailer("body_node")) |body_node| {
10991195 if (i < 1) return body_node;
11001196 i -= 1;
11011197 }
......@@ -1104,14 +1200,14 @@ pub const Node = struct {
11041200 }
11051201
11061202 pub fn firstToken(self: *const FnProto) TokenIndex {
1107 if (self.visib_token) |visib_token| return visib_token;
1108 if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
1109 assert(self.lib_name == null);
1203 if (self.getTrailer("visib_token")) |visib_token| return visib_token;
1204 if (self.getTrailer("extern_export_inline_token")) |extern_export_inline_token| return extern_export_inline_token;
1205 assert(self.getTrailer("lib_name") == null);
11101206 return self.fn_token;
11111207 }
11121208
11131209 pub fn lastToken(self: *const FnProto) TokenIndex {
1114 if (self.body_node) |body_node| return body_node.lastToken();
1210 if (self.getTrailer("body_node")) |body_node| return body_node.lastToken();
11151211 switch (self.return_type) {
11161212 .Explicit, .InferErrorSet => |node| return node.lastToken(),
11171213 .Invalid => |tok| return tok,
......@@ -1119,17 +1215,17 @@ pub const Node = struct {
11191215 }
11201216
11211217 pub fn params(self: *FnProto) []ParamDecl {
1122 const decls_start = @ptrCast([*]u8, self) + @sizeOf(FnProto);
1123 return @ptrCast([*]ParamDecl, decls_start)[0..self.params_len];
1218 const params_start = @ptrCast([*]u8, self) + @sizeOf(FnProto);
1219 return @ptrCast([*]ParamDecl, params_start)[0..self.params_len];
11241220 }
11251221
11261222 pub fn paramsConst(self: *const FnProto) []const ParamDecl {
1127 const decls_start = @ptrCast([*]const u8, self) + @sizeOf(FnProto);
1128 return @ptrCast([*]const ParamDecl, decls_start)[0..self.params_len];
1223 const params_start = @ptrCast([*]const u8, self) + @sizeOf(FnProto);
1224 return @ptrCast([*]const ParamDecl, params_start)[0..self.params_len];
11291225 }
11301226
1131 fn sizeInBytes(params_len: NodeIndex) usize {
1132 return @sizeOf(FnProto) + @sizeOf(ParamDecl) * @as(usize, params_len);
1227 fn sizeInBytes(params_len: NodeIndex, trailer_flags: TrailerFlags) usize {
1228 return @sizeOf(FnProto) + @sizeOf(ParamDecl) * @as(usize, params_len) + trailer_flags.sizeInBytes();
11331229 }
11341230 };
11351231
......@@ -2829,6 +2925,9 @@ pub const Node = struct {
28292925 }
28302926 };
28312927
2928 /// TODO remove from the Node base struct
2929 /// TODO actually maybe remove entirely in favor of iterating backward from Node.firstToken()
2930 /// and forwards to find same-line doc comments.
28322931 pub const DocComment = struct {
28332932 base: Node = Node{ .id = .DocComment },
28342933 /// Points to the first doc comment token. API users are expected to iterate over the
lib/std/zig/parse.zig+92-100
......@@ -150,7 +150,7 @@ const Parser = struct {
150150
151151 const visib_token = p.eatToken(.Keyword_pub);
152152
153 if (p.parseTopLevelDecl() catch |err| switch (err) {
153 if (p.parseTopLevelDecl(doc_comments, visib_token) catch |err| switch (err) {
154154 error.OutOfMemory => return error.OutOfMemory,
155155 error.ParseError => {
156156 p.findNextContainerMember();
......@@ -160,30 +160,7 @@ const Parser = struct {
160160 if (field_state == .seen) {
161161 field_state = .{ .end = visib_token orelse node.firstToken() };
162162 }
163 switch (node.id) {
164 .FnProto => {
165 node.cast(Node.FnProto).?.doc_comments = doc_comments;
166 node.cast(Node.FnProto).?.visib_token = visib_token;
167 },
168 .VarDecl => {
169 node.cast(Node.VarDecl).?.doc_comments = doc_comments;
170 node.cast(Node.VarDecl).?.visib_token = visib_token;
171 },
172 .Use => {
173 node.cast(Node.Use).?.doc_comments = doc_comments;
174 node.cast(Node.Use).?.visib_token = visib_token;
175 },
176 else => unreachable,
177 }
178163 try list.append(node);
179 if (try p.parseAppendedDocComment(node.lastToken())) |appended_comment| {
180 switch (node.id) {
181 .FnProto => {},
182 .VarDecl => node.cast(Node.VarDecl).?.doc_comments = appended_comment,
183 .Use => node.cast(Node.Use).?.doc_comments = appended_comment,
184 else => unreachable,
185 }
186 }
187164 continue;
188165 }
189166
......@@ -417,7 +394,7 @@ const Parser = struct {
417394 /// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block)
418395 /// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl
419396 /// / KEYWORD_usingnamespace Expr SEMICOLON
420 fn parseTopLevelDecl(p: *Parser) !?*Node {
397 fn parseTopLevelDecl(p: *Parser, doc_comments: ?*Node.DocComment, visib_token: ?TokenIndex) !?*Node {
421398 var lib_name: ?*Node = null;
422399 const extern_export_inline_token = blk: {
423400 if (p.eatToken(.Keyword_export)) |token| break :blk token;
......@@ -430,20 +407,12 @@ const Parser = struct {
430407 break :blk null;
431408 };
432409
433 if (try p.parseFnProto()) |node| {
434 const fn_node = node.cast(Node.FnProto).?;
435 fn_node.*.extern_export_inline_token = extern_export_inline_token;
436 fn_node.*.lib_name = lib_name;
437 if (p.eatToken(.Semicolon)) |_| return node;
438
439 if (try p.expectNodeRecoverable(parseBlock, .{
440 // since parseBlock only return error.ParseError on
441 // a missing '}' we can assume this function was
442 // supposed to end here.
443 .ExpectedSemiOrLBrace = .{ .token = p.tok_i },
444 })) |body_node| {
445 fn_node.body_node = body_node;
446 }
410 if (try p.parseFnProto(.top_level, .{
411 .doc_comments = doc_comments,
412 .visib_token = visib_token,
413 .extern_export_inline_token = extern_export_inline_token,
414 .lib_name = lib_name,
415 })) |node| {
447416 return node;
448417 }
449418
......@@ -460,12 +429,13 @@ const Parser = struct {
460429
461430 const thread_local_token = p.eatToken(.Keyword_threadlocal);
462431
463 if (try p.parseVarDecl()) |node| {
464 var var_decl = node.cast(Node.VarDecl).?;
465 var_decl.*.thread_local_token = thread_local_token;
466 var_decl.*.comptime_token = null;
467 var_decl.*.extern_export_token = extern_export_inline_token;
468 var_decl.*.lib_name = lib_name;
432 if (try p.parseVarDecl(.{
433 .doc_comments = doc_comments,
434 .visib_token = visib_token,
435 .thread_local_token = thread_local_token,
436 .extern_export_token = extern_export_inline_token,
437 .lib_name = lib_name,
438 })) |node| {
469439 return node;
470440 }
471441
......@@ -485,21 +455,41 @@ const Parser = struct {
485455 return error.ParseError;
486456 }
487457
488 return p.parseUse();
458 const use_token = p.eatToken(.Keyword_usingnamespace) orelse return null;
459 const expr = try p.expectNode(parseExpr, .{
460 .ExpectedExpr = .{ .token = p.tok_i },
461 });
462 const semicolon_token = try p.expectToken(.Semicolon);
463
464 const node = try p.arena.allocator.create(Node.Use);
465 node.* = .{
466 .doc_comments = doc_comments orelse try p.parseAppendedDocComment(semicolon_token),
467 .visib_token = visib_token,
468 .use_token = use_token,
469 .expr = expr,
470 .semicolon_token = semicolon_token,
471 };
472
473 return &node.base;
489474 }
490475
491476 /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (Keyword_anytype / TypeExpr)
492 fn parseFnProto(p: *Parser) !?*Node {
477 fn parseFnProto(p: *Parser, level: enum { top_level, as_type }, fields: struct {
478 doc_comments: ?*Node.DocComment = null,
479 visib_token: ?TokenIndex = null,
480 extern_export_inline_token: ?TokenIndex = null,
481 lib_name: ?*Node = null,
482 }) !?*Node {
493483 // TODO: Remove once extern/async fn rewriting is
494 var is_async = false;
495 var is_extern = false;
484 var is_async: ?void = null;
485 var is_extern_prototype: ?void = null;
496486 const cc_token: ?TokenIndex = blk: {
497487 if (p.eatToken(.Keyword_extern)) |token| {
498 is_extern = true;
488 is_extern_prototype = {};
499489 break :blk token;
500490 }
501491 if (p.eatToken(.Keyword_async)) |token| {
502 is_async = true;
492 is_async = {};
503493 break :blk token;
504494 }
505495 break :blk null;
......@@ -513,6 +503,7 @@ const Parser = struct {
513503 const lparen = try p.expectToken(.LParen);
514504 const params = try p.parseParamDeclList();
515505 defer p.gpa.free(params);
506 const var_args_token = p.eatToken(.Ellipsis3);
516507 const rparen = try p.expectToken(.RParen);
517508 const align_expr = try p.parseByteAlign();
518509 const section_expr = try p.parseLinkSection();
......@@ -535,37 +526,53 @@ const Parser = struct {
535526 else
536527 R{ .Explicit = return_type_expr.? };
537528
538 const var_args_token = if (params.len > 0) blk: {
539 const param_type = params[params.len - 1].param_type;
540 break :blk if (param_type == .var_args) param_type.var_args else null;
541 } else
542 null;
529 const body_node: ?*Node = switch (level) {
530 .top_level => blk: {
531 if (p.eatToken(.Semicolon)) |_| {
532 break :blk null;
533 }
534 break :blk try p.expectNodeRecoverable(parseBlock, .{
535 // Since parseBlock only return error.ParseError on
536 // a missing '}' we can assume this function was
537 // supposed to end here.
538 .ExpectedSemiOrLBrace = .{ .token = p.tok_i },
539 });
540 },
541 .as_type => null,
542 };
543543
544 const fn_proto_node = try Node.FnProto.alloc(&p.arena.allocator, params.len);
545 fn_proto_node.* = .{
546 .doc_comments = null,
547 .visib_token = null,
548 .fn_token = fn_token,
549 .name_token = name_token,
544 const fn_proto_node = try Node.FnProto.create(&p.arena.allocator, .{
550545 .params_len = params.len,
546 .fn_token = fn_token,
551547 .return_type = return_type,
548 }, .{
549 .doc_comments = fields.doc_comments,
550 .visib_token = fields.visib_token,
551 .name_token = name_token,
552552 .var_args_token = var_args_token,
553 .extern_export_inline_token = null,
554 .body_node = null,
555 .lib_name = null,
553 .extern_export_inline_token = fields.extern_export_inline_token,
554 .body_node = body_node,
555 .lib_name = fields.lib_name,
556556 .align_expr = align_expr,
557557 .section_expr = section_expr,
558558 .callconv_expr = callconv_expr,
559 .is_extern_prototype = is_extern,
559 .is_extern_prototype = is_extern_prototype,
560560 .is_async = is_async,
561 };
561 });
562562 std.mem.copy(Node.FnProto.ParamDecl, fn_proto_node.params(), params);
563563
564564 return &fn_proto_node.base;
565565 }
566566
567567 /// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON
568 fn parseVarDecl(p: *Parser) !?*Node {
568 fn parseVarDecl(p: *Parser, fields: struct {
569 doc_comments: ?*Node.DocComment = null,
570 visib_token: ?TokenIndex = null,
571 thread_local_token: ?TokenIndex = null,
572 extern_export_token: ?TokenIndex = null,
573 lib_name: ?*Node = null,
574 comptime_token: ?TokenIndex = null,
575 }) !?*Node {
569576 const mut_token = p.eatToken(.Keyword_const) orelse
570577 p.eatToken(.Keyword_var) orelse
571578 return null;
......@@ -587,23 +594,25 @@ const Parser = struct {
587594 } else null;
588595 const semicolon_token = try p.expectToken(.Semicolon);
589596
590 const node = try p.arena.allocator.create(Node.VarDecl);
591 node.* = .{
592 .doc_comments = null,
593 .visib_token = null,
594 .thread_local_token = null,
597 const doc_comments = fields.doc_comments orelse try p.parseAppendedDocComment(semicolon_token);
598
599 const node = try Node.VarDecl.create(&p.arena.allocator, .{
600 .mut_token = mut_token,
595601 .name_token = name_token,
602 .semicolon_token = semicolon_token,
603 }, .{
604 .doc_comments = doc_comments,
605 .visib_token = fields.visib_token,
606 .thread_local_token = fields.thread_local_token,
596607 .eq_token = eq_token,
597 .mut_token = mut_token,
598 .comptime_token = null,
599 .extern_export_token = null,
600 .lib_name = null,
608 .comptime_token = fields.comptime_token,
609 .extern_export_token = fields.extern_export_token,
610 .lib_name = fields.lib_name,
601611 .type_node = type_node,
602612 .align_node = align_node,
603613 .section_node = section_node,
604614 .init_node = init_node,
605 .semicolon_token = semicolon_token,
606 };
615 });
607616 return &node.base;
608617 }
609618
......@@ -663,10 +672,9 @@ const Parser = struct {
663672 fn parseStatement(p: *Parser) Error!?*Node {
664673 const comptime_token = p.eatToken(.Keyword_comptime);
665674
666 const var_decl_node = try p.parseVarDecl();
667 if (var_decl_node) |node| {
668 const var_decl = node.cast(Node.VarDecl).?;
669 var_decl.comptime_token = comptime_token;
675 if (try p.parseVarDecl(.{
676 .comptime_token = comptime_token,
677 })) |node| {
670678 return node;
671679 }
672680
......@@ -1527,7 +1535,7 @@ const Parser = struct {
15271535 if (try p.parseAnonLiteral()) |node| return node;
15281536 if (try p.parseErrorSetDecl()) |node| return node;
15291537 if (try p.parseFloatLiteral()) |node| return node;
1530 if (try p.parseFnProto()) |node| return node;
1538 if (try p.parseFnProto(.as_type, .{})) |node| return node;
15311539 if (try p.parseGroupedExpr()) |node| return node;
15321540 if (try p.parseLabeledTypeExpr()) |node| return node;
15331541 if (try p.parseIdentifier()) |node| return node;
......@@ -2028,7 +2036,6 @@ const Parser = struct {
20282036 // TODO cast from tuple to error union is broken
20292037 const P = Node.FnProto.ParamDecl.ParamType;
20302038 if (try p.parseAnyType()) |node| return P{ .any_type = node };
2031 if (p.eatToken(.Ellipsis3)) |token| return P{ .var_args = token };
20322039 if (try p.parseTypeExpr()) |node| return P{ .type_expr = node };
20332040 return null;
20342041 }
......@@ -3149,21 +3156,6 @@ const Parser = struct {
31493156 return &node.base;
31503157 }
31513158
3152 fn parseUse(p: *Parser) !?*Node {
3153 const token = p.eatToken(.Keyword_usingnamespace) orelse return null;
3154 const node = try p.arena.allocator.create(Node.Use);
3155 node.* = .{
3156 .doc_comments = null,
3157 .visib_token = null,
3158 .use_token = token,
3159 .expr = try p.expectNode(parseExpr, .{
3160 .ExpectedExpr = .{ .token = p.tok_i },
3161 }),
3162 .semicolon_token = try p.expectToken(.Semicolon),
3163 };
3164 return &node.base;
3165 }
3166
31673159 /// IfPrefix Body (KEYWORD_else Payload? Body)?
31683160 fn parseIf(p: *Parser, bodyParseFn: NodeParseFn) !?*Node {
31693161 const node = (try p.parseIfPrefix()) orelse return null;
lib/std/zig/parser_test.zig+32-27
......@@ -1,4 +1,32 @@
1const builtin = @import("builtin");
1test "zig fmt: convert var to anytype" {
2 // TODO remove in next release cycle
3 try testTransform(
4 \\pub fn main(
5 \\ a: var,
6 \\ bar: var,
7 \\) void {}
8 ,
9 \\pub fn main(
10 \\ a: anytype,
11 \\ bar: anytype,
12 \\) void {}
13 \\
14 );
15}
16
17test "zig fmt: noasync to nosuspend" {
18 // TODO: remove this
19 try testTransform(
20 \\pub fn main() void {
21 \\ noasync call();
22 \\}
23 ,
24 \\pub fn main() void {
25 \\ nosuspend call();
26 \\}
27 \\
28 );
29}
230
331test "recovery: top level" {
432 try testError(
......@@ -3146,20 +3174,6 @@ test "zig fmt: hexadeciaml float literals with underscore separators" {
31463174 );
31473175}
31483176
3149test "zig fmt: noasync to nosuspend" {
3150 // TODO: remove this
3151 try testTransform(
3152 \\pub fn main() void {
3153 \\ noasync call();
3154 \\}
3155 ,
3156 \\pub fn main() void {
3157 \\ nosuspend call();
3158 \\}
3159 \\
3160 );
3161}
3162
31633177test "zig fmt: convert async fn into callconv(.Async)" {
31643178 try testTransform(
31653179 \\async fn foo() void {}
......@@ -3180,18 +3194,9 @@ test "zig fmt: convert extern fn proto into callconv(.C)" {
31803194 );
31813195}
31823196
3183test "zig fmt: convert var to anytype" {
3184 // TODO remove in next release cycle
3185 try testTransform(
3186 \\pub fn main(
3187 \\ a: var,
3188 \\ bar: var,
3189 \\) void {}
3190 ,
3191 \\pub fn main(
3192 \\ a: anytype,
3193 \\ bar: anytype,
3194 \\) void {}
3197test "zig fmt: C var args" {
3198 try testCanonical(
3199 \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
31953200 \\
31963201 );
31973202}
lib/std/zig/render.zig+52-40
......@@ -227,9 +227,9 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr
227227 .FnProto => {
228228 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
229229
230 try renderDocComments(tree, stream, fn_proto, indent, start_col);
230 try renderDocComments(tree, stream, fn_proto, fn_proto.getTrailer("doc_comments"), indent, start_col);
231231
232 if (fn_proto.body_node) |body_node| {
232 if (fn_proto.getTrailer("body_node")) |body_node| {
233233 try renderExpression(allocator, stream, tree, indent, start_col, decl, .Space);
234234 try renderExpression(allocator, stream, tree, indent, start_col, body_node, space);
235235 } else {
......@@ -252,14 +252,14 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr
252252 .VarDecl => {
253253 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
254254
255 try renderDocComments(tree, stream, var_decl, indent, start_col);
255 try renderDocComments(tree, stream, var_decl, var_decl.getTrailer("doc_comments"), indent, start_col);
256256 try renderVarDecl(allocator, stream, tree, indent, start_col, var_decl);
257257 },
258258
259259 .TestDecl => {
260260 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
261261
262 try renderDocComments(tree, stream, test_decl, indent, start_col);
262 try renderDocComments(tree, stream, test_decl, test_decl.doc_comments, indent, start_col);
263263 try renderToken(tree, stream, test_decl.test_token, indent, start_col, .Space);
264264 try renderExpression(allocator, stream, tree, indent, start_col, test_decl.name, .Space);
265265 try renderExpression(allocator, stream, tree, indent, start_col, test_decl.body_node, space);
......@@ -268,7 +268,7 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tr
268268 .ContainerField => {
269269 const field = @fieldParentPtr(ast.Node.ContainerField, "base", decl);
270270
271 try renderDocComments(tree, stream, field, indent, start_col);
271 try renderDocComments(tree, stream, field, field.doc_comments, indent, start_col);
272272 if (field.comptime_token) |t| {
273273 try renderToken(tree, stream, t, indent, start_col, .Space); // comptime
274274 }
......@@ -1409,7 +1409,7 @@ fn renderExpression(
14091409 .ErrorTag => {
14101410 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", base);
14111411
1412 try renderDocComments(tree, stream, tag, indent, start_col);
1412 try renderDocComments(tree, stream, tag, tag.doc_comments, indent, start_col);
14131413 return renderToken(tree, stream, tag.name_token, indent, start_col, space); // name
14141414 },
14151415
......@@ -1483,23 +1483,23 @@ fn renderExpression(
14831483 .FnProto => {
14841484 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
14851485
1486 if (fn_proto.visib_token) |visib_token_index| {
1486 if (fn_proto.getTrailer("visib_token")) |visib_token_index| {
14871487 const visib_token = tree.token_ids[visib_token_index];
14881488 assert(visib_token == .Keyword_pub or visib_token == .Keyword_export);
14891489
14901490 try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub
14911491 }
14921492
1493 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
1494 if (!fn_proto.is_extern_prototype)
1493 if (fn_proto.getTrailer("extern_export_inline_token")) |extern_export_inline_token| {
1494 if (fn_proto.getTrailer("is_extern_prototype") == null)
14951495 try renderToken(tree, stream, extern_export_inline_token, indent, start_col, Space.Space); // extern/export/inline
14961496 }
14971497
1498 if (fn_proto.lib_name) |lib_name| {
1498 if (fn_proto.getTrailer("lib_name")) |lib_name| {
14991499 try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space);
15001500 }
15011501
1502 const lparen = if (fn_proto.name_token) |name_token| blk: {
1502 const lparen = if (fn_proto.getTrailer("name_token")) |name_token| blk: {
15031503 try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn
15041504 try renderToken(tree, stream, name_token, indent, start_col, Space.None); // name
15051505 break :blk tree.nextToken(name_token);
......@@ -1512,11 +1512,11 @@ fn renderExpression(
15121512 const rparen = tree.prevToken(
15131513 // the first token for the annotation expressions is the left
15141514 // parenthesis, hence the need for two prevToken
1515 if (fn_proto.align_expr) |align_expr|
1515 if (fn_proto.getTrailer("align_expr")) |align_expr|
15161516 tree.prevToken(tree.prevToken(align_expr.firstToken()))
1517 else if (fn_proto.section_expr) |section_expr|
1517 else if (fn_proto.getTrailer("section_expr")) |section_expr|
15181518 tree.prevToken(tree.prevToken(section_expr.firstToken()))
1519 else if (fn_proto.callconv_expr) |callconv_expr|
1519 else if (fn_proto.getTrailer("callconv_expr")) |callconv_expr|
15201520 tree.prevToken(tree.prevToken(callconv_expr.firstToken()))
15211521 else switch (fn_proto.return_type) {
15221522 .Explicit => |node| node.firstToken(),
......@@ -1537,11 +1537,14 @@ fn renderExpression(
15371537 for (fn_proto.params()) |param_decl, i| {
15381538 try renderParamDecl(allocator, stream, tree, indent, start_col, param_decl, Space.None);
15391539
1540 if (i + 1 < fn_proto.params_len) {
1540 if (i + 1 < fn_proto.params_len or fn_proto.getTrailer("var_args_token") != null) {
15411541 const comma = tree.nextToken(param_decl.lastToken());
15421542 try renderToken(tree, stream, comma, indent, start_col, Space.Space); // ,
15431543 }
15441544 }
1545 if (fn_proto.getTrailer("var_args_token")) |var_args_token| {
1546 try renderToken(tree, stream, var_args_token, indent, start_col, Space.None);
1547 }
15451548 } else {
15461549 // one param per line
15471550 const new_indent = indent + indent_delta;
......@@ -1551,12 +1554,16 @@ fn renderExpression(
15511554 try stream.writeByteNTimes(' ', new_indent);
15521555 try renderParamDecl(allocator, stream, tree, new_indent, start_col, param_decl, Space.Comma);
15531556 }
1557 if (fn_proto.getTrailer("var_args_token")) |var_args_token| {
1558 try stream.writeByteNTimes(' ', new_indent);
1559 try renderToken(tree, stream, var_args_token, new_indent, start_col, Space.Comma);
1560 }
15541561 try stream.writeByteNTimes(' ', indent);
15551562 }
15561563
15571564 try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // )
15581565
1559 if (fn_proto.align_expr) |align_expr| {
1566 if (fn_proto.getTrailer("align_expr")) |align_expr| {
15601567 const align_rparen = tree.nextToken(align_expr.lastToken());
15611568 const align_lparen = tree.prevToken(align_expr.firstToken());
15621569 const align_kw = tree.prevToken(align_lparen);
......@@ -1567,7 +1574,7 @@ fn renderExpression(
15671574 try renderToken(tree, stream, align_rparen, indent, start_col, Space.Space); // )
15681575 }
15691576
1570 if (fn_proto.section_expr) |section_expr| {
1577 if (fn_proto.getTrailer("section_expr")) |section_expr| {
15711578 const section_rparen = tree.nextToken(section_expr.lastToken());
15721579 const section_lparen = tree.prevToken(section_expr.firstToken());
15731580 const section_kw = tree.prevToken(section_lparen);
......@@ -1578,7 +1585,7 @@ fn renderExpression(
15781585 try renderToken(tree, stream, section_rparen, indent, start_col, Space.Space); // )
15791586 }
15801587
1581 if (fn_proto.callconv_expr) |callconv_expr| {
1588 if (fn_proto.getTrailer("callconv_expr")) |callconv_expr| {
15821589 const callconv_rparen = tree.nextToken(callconv_expr.lastToken());
15831590 const callconv_lparen = tree.prevToken(callconv_expr.firstToken());
15841591 const callconv_kw = tree.prevToken(callconv_lparen);
......@@ -1587,9 +1594,9 @@ fn renderExpression(
15871594 try renderToken(tree, stream, callconv_lparen, indent, start_col, Space.None); // (
15881595 try renderExpression(allocator, stream, tree, indent, start_col, callconv_expr, Space.None);
15891596 try renderToken(tree, stream, callconv_rparen, indent, start_col, Space.Space); // )
1590 } else if (fn_proto.is_extern_prototype) {
1597 } else if (fn_proto.getTrailer("is_extern_prototype") != null) {
15911598 try stream.writeAll("callconv(.C) ");
1592 } else if (fn_proto.is_async) {
1599 } else if (fn_proto.getTrailer("is_async") != null) {
15931600 try stream.writeAll("callconv(.Async) ");
15941601 }
15951602
......@@ -2177,64 +2184,69 @@ fn renderVarDecl(
21772184 start_col: *usize,
21782185 var_decl: *ast.Node.VarDecl,
21792186) (@TypeOf(stream).Error || Error)!void {
2180 if (var_decl.visib_token) |visib_token| {
2187 if (var_decl.getTrailer("visib_token")) |visib_token| {
21812188 try renderToken(tree, stream, visib_token, indent, start_col, Space.Space); // pub
21822189 }
21832190
2184 if (var_decl.extern_export_token) |extern_export_token| {
2191 if (var_decl.getTrailer("extern_export_token")) |extern_export_token| {
21852192 try renderToken(tree, stream, extern_export_token, indent, start_col, Space.Space); // extern
21862193
2187 if (var_decl.lib_name) |lib_name| {
2194 if (var_decl.getTrailer("lib_name")) |lib_name| {
21882195 try renderExpression(allocator, stream, tree, indent, start_col, lib_name, Space.Space); // "lib"
21892196 }
21902197 }
21912198
2192 if (var_decl.comptime_token) |comptime_token| {
2199 if (var_decl.getTrailer("comptime_token")) |comptime_token| {
21932200 try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space); // comptime
21942201 }
21952202
2196 if (var_decl.thread_local_token) |thread_local_token| {
2203 if (var_decl.getTrailer("thread_local_token")) |thread_local_token| {
21972204 try renderToken(tree, stream, thread_local_token, indent, start_col, Space.Space); // threadlocal
21982205 }
21992206 try renderToken(tree, stream, var_decl.mut_token, indent, start_col, Space.Space); // var
22002207
2201 const name_space = if (var_decl.type_node == null and (var_decl.align_node != null or
2202 var_decl.section_node != null or var_decl.init_node != null)) Space.Space else Space.None;
2208 const name_space = if (var_decl.getTrailer("type_node") == null and
2209 (var_decl.getTrailer("align_node") != null or
2210 var_decl.getTrailer("section_node") != null or
2211 var_decl.getTrailer("init_node") != null))
2212 Space.Space
2213 else
2214 Space.None;
22032215 try renderToken(tree, stream, var_decl.name_token, indent, start_col, name_space);
22042216
2205 if (var_decl.type_node) |type_node| {
2217 if (var_decl.getTrailer("type_node")) |type_node| {
22062218 try renderToken(tree, stream, tree.nextToken(var_decl.name_token), indent, start_col, Space.Space);
2207 const s = if (var_decl.align_node != null or
2208 var_decl.section_node != null or
2209 var_decl.init_node != null) Space.Space else Space.None;
2219 const s = if (var_decl.getTrailer("align_node") != null or
2220 var_decl.getTrailer("section_node") != null or
2221 var_decl.getTrailer("init_node") != null) Space.Space else Space.None;
22102222 try renderExpression(allocator, stream, tree, indent, start_col, type_node, s);
22112223 }
22122224
2213 if (var_decl.align_node) |align_node| {
2225 if (var_decl.getTrailer("align_node")) |align_node| {
22142226 const lparen = tree.prevToken(align_node.firstToken());
22152227 const align_kw = tree.prevToken(lparen);
22162228 const rparen = tree.nextToken(align_node.lastToken());
22172229 try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align
22182230 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
22192231 try renderExpression(allocator, stream, tree, indent, start_col, align_node, Space.None);
2220 const s = if (var_decl.section_node != null or var_decl.init_node != null) Space.Space else Space.None;
2232 const s = if (var_decl.getTrailer("section_node") != null or var_decl.getTrailer("init_node") != null) Space.Space else Space.None;
22212233 try renderToken(tree, stream, rparen, indent, start_col, s); // )
22222234 }
22232235
2224 if (var_decl.section_node) |section_node| {
2236 if (var_decl.getTrailer("section_node")) |section_node| {
22252237 const lparen = tree.prevToken(section_node.firstToken());
22262238 const section_kw = tree.prevToken(lparen);
22272239 const rparen = tree.nextToken(section_node.lastToken());
22282240 try renderToken(tree, stream, section_kw, indent, start_col, Space.None); // linksection
22292241 try renderToken(tree, stream, lparen, indent, start_col, Space.None); // (
22302242 try renderExpression(allocator, stream, tree, indent, start_col, section_node, Space.None);
2231 const s = if (var_decl.init_node != null) Space.Space else Space.None;
2243 const s = if (var_decl.getTrailer("init_node") != null) Space.Space else Space.None;
22322244 try renderToken(tree, stream, rparen, indent, start_col, s); // )
22332245 }
22342246
2235 if (var_decl.init_node) |init_node| {
2247 if (var_decl.getTrailer("init_node")) |init_node| {
22362248 const s = if (init_node.id == .MultilineStringLiteral) Space.None else Space.Space;
2237 try renderToken(tree, stream, var_decl.eq_token.?, indent, start_col, s); // =
2249 try renderToken(tree, stream, var_decl.getTrailer("eq_token").?, indent, start_col, s); // =
22382250 try renderExpression(allocator, stream, tree, indent, start_col, init_node, Space.None);
22392251 }
22402252
......@@ -2250,7 +2262,7 @@ fn renderParamDecl(
22502262 param_decl: ast.Node.FnProto.ParamDecl,
22512263 space: Space,
22522264) (@TypeOf(stream).Error || Error)!void {
2253 try renderDocComments(tree, stream, param_decl, indent, start_col);
2265 try renderDocComments(tree, stream, param_decl, param_decl.doc_comments, indent, start_col);
22542266
22552267 if (param_decl.comptime_token) |comptime_token| {
22562268 try renderToken(tree, stream, comptime_token, indent, start_col, Space.Space);
......@@ -2263,7 +2275,6 @@ fn renderParamDecl(
22632275 try renderToken(tree, stream, tree.nextToken(name_token), indent, start_col, Space.Space); // :
22642276 }
22652277 switch (param_decl.param_type) {
2266 .var_args => |token| try renderToken(tree, stream, token, indent, start_col, space),
22672278 .any_type, .type_expr => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, space),
22682279 }
22692280}
......@@ -2519,10 +2530,11 @@ fn renderDocComments(
25192530 tree: *ast.Tree,
25202531 stream: anytype,
25212532 node: anytype,
2533 doc_comments: ?*ast.Node.DocComment,
25222534 indent: usize,
25232535 start_col: *usize,
25242536) (@TypeOf(stream).Error || Error)!void {
2525 const comment = node.doc_comments orelse return;
2537 const comment = doc_comments orelse return;
25262538 return renderDocCommentsToken(tree, stream, comment, node.firstToken(), indent, start_col);
25272539}
25282540
src-self-hosted/Module.zig+12-10
......@@ -1130,7 +1130,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
11301130 };
11311131 defer fn_type_scope.instructions.deinit(self.gpa);
11321132
1133 const body_node = fn_proto.body_node orelse
1133 const body_node = fn_proto.getTrailer("body_node") orelse
11341134 return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});
11351135
11361136 const param_decls = fn_proto.params();
......@@ -1138,21 +1138,23 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
11381138 for (param_decls) |param_decl, i| {
11391139 const param_type_node = switch (param_decl.param_type) {
11401140 .any_type => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement anytype parameter", .{}),
1141 .var_args => |tok| return self.failTok(&fn_type_scope.base, tok, "TODO implement var args", .{}),
11421141 .type_expr => |node| node,
11431142 };
11441143 param_types[i] = try self.astGenExpr(&fn_type_scope.base, param_type_node);
11451144 }
1146 if (fn_proto.lib_name) |lib_name| {
1145 if (fn_proto.getTrailer("var_args_token")) |var_args_token| {
1146 return self.failTok(&fn_type_scope.base, var_args_token, "TODO implement var args", .{});
1147 }
1148 if (fn_proto.getTrailer("lib_name")) |lib_name| {
11471149 return self.failNode(&fn_type_scope.base, lib_name, "TODO implement function library name", .{});
11481150 }
1149 if (fn_proto.align_expr) |align_expr| {
1151 if (fn_proto.getTrailer("align_expr")) |align_expr| {
11501152 return self.failNode(&fn_type_scope.base, align_expr, "TODO implement function align expression", .{});
11511153 }
1152 if (fn_proto.section_expr) |sect_expr| {
1154 if (fn_proto.getTrailer("section_expr")) |sect_expr| {
11531155 return self.failNode(&fn_type_scope.base, sect_expr, "TODO implement function section expression", .{});
11541156 }
1155 if (fn_proto.callconv_expr) |callconv_expr| {
1157 if (fn_proto.getTrailer("callconv_expr")) |callconv_expr| {
11561158 return self.failNode(
11571159 &fn_type_scope.base,
11581160 callconv_expr,
......@@ -1265,10 +1267,10 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
12651267 self.bin_file.freeDecl(decl);
12661268 }
12671269
1268 if (fn_proto.extern_export_inline_token) |maybe_export_token| {
1270 if (fn_proto.getTrailer("extern_export_inline_token")) |maybe_export_token| {
12691271 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
12701272 const export_src = tree.token_locs[maybe_export_token].start;
1271 const name_loc = tree.token_locs[fn_proto.name_token.?];
1273 const name_loc = tree.token_locs[fn_proto.getTrailer("name_token").?];
12721274 const name = tree.tokenSliceLoc(name_loc);
12731275 // The scope needs to have the decl in it.
12741276 try self.analyzeExport(&block_scope.base, export_src, name, decl);
......@@ -1867,7 +1869,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
18671869 for (decls) |src_decl, decl_i| {
18681870 if (src_decl.cast(ast.Node.FnProto)) |fn_proto| {
18691871 // We will create a Decl for it regardless of analysis status.
1870 const name_tok = fn_proto.name_token orelse {
1872 const name_tok = fn_proto.getTrailer("name_token") orelse {
18711873 @panic("TODO missing function name");
18721874 };
18731875
......@@ -1893,7 +1895,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
18931895 } else {
18941896 const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash);
18951897 root_scope.decls.appendAssumeCapacity(new_decl);
1896 if (fn_proto.extern_export_inline_token) |maybe_export_token| {
1898 if (fn_proto.getTrailer("extern_export_inline_token")) |maybe_export_token| {
18971899 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
18981900 self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
18991901 }
src-self-hosted/translate_c.zig+279-183
......@@ -586,11 +586,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
586586 for (proto_node.params()) |*param, i| {
587587 const param_name = if (param.name_token) |name_tok|
588588 tokenSlice(c, name_tok)
589 else if (param.param_type == .var_args) {
590 assert(i + 1 == proto_node.params_len);
591 proto_node.params_len -= 1;
592 break;
593 } else
589 else
594590 return failDecl(c, fn_decl_loc, fn_name, "function {} parameter has no name", .{fn_name});
595591
596592 const c_param = ZigClangFunctionDecl_getParamDecl(fn_decl, param_id);
......@@ -602,10 +598,20 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
602598 if (!is_const) {
603599 const bare_arg_name = try std.fmt.allocPrint(c.arena, "arg_{}", .{mangled_param_name});
604600 const arg_name = try block_scope.makeMangledName(c, bare_arg_name);
605 const node = try transCreateNodeVarDecl(c, false, false, mangled_param_name);
606 node.eq_token = try appendToken(c, .Equal, "=");
607 node.init_node = try transCreateNodeIdentifier(c, arg_name);
608 node.semicolon_token = try appendToken(c, .Semicolon, ";");
601
602 const mut_tok = try appendToken(c, .Keyword_var, "var");
603 const name_tok = try appendIdentifier(c, mangled_param_name);
604 const eq_token = try appendToken(c, .Equal, "=");
605 const init_node = try transCreateNodeIdentifier(c, arg_name);
606 const semicolon_token = try appendToken(c, .Semicolon, ";");
607 const node = try ast.Node.VarDecl.create(c.arena, .{
608 .mut_token = mut_tok,
609 .name_token = name_tok,
610 .semicolon_token = semicolon_token,
611 }, .{
612 .eq_token = eq_token,
613 .init_node = init_node,
614 });
609615 try block_scope.statements.append(&node.base);
610616 param.name_token = try appendIdentifier(c, arg_name);
611617 _ = try appendToken(c, .Colon, ":");
......@@ -622,7 +628,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
622628 => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}),
623629 };
624630 const body_node = try block_scope.complete(rp.c);
625 proto_node.body_node = &body_node.base;
631 proto_node.setTrailer("body_node", &body_node.base);
626632 return addTopLevelDecl(c, fn_name, &proto_node.base);
627633}
628634
......@@ -725,23 +731,20 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
725731 break :blk null;
726732 };
727733
728 const node = try c.arena.create(ast.Node.VarDecl);
729 node.* = .{
730 .doc_comments = null,
734 const node = try ast.Node.VarDecl.create(c.arena, .{
735 .name_token = name_tok,
736 .mut_token = mut_tok,
737 .semicolon_token = try appendToken(c, .Semicolon, ";"),
738 }, .{
731739 .visib_token = visib_tok,
732740 .thread_local_token = thread_local_token,
733 .name_token = name_tok,
734741 .eq_token = eq_tok,
735 .mut_token = mut_tok,
736 .comptime_token = null,
737742 .extern_export_token = extern_tok,
738 .lib_name = null,
739743 .type_node = type_node,
740744 .align_node = align_expr,
741745 .section_node = linksection_expr,
742746 .init_node = init_node,
743 .semicolon_token = try appendToken(c, .Semicolon, ";"),
744 };
747 });
745748 return addTopLevelDecl(c, checked_name, &node.base);
746749}
747750
......@@ -795,26 +798,41 @@ fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, top_l
795798
796799 _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), checked_name);
797800 const node = (try transCreateNodeTypedef(rp, typedef_decl, true, checked_name)) orelse return null;
798 try addTopLevelDecl(c, checked_name, &node.base);
801 try addTopLevelDecl(c, checked_name, node);
799802 return transCreateNodeIdentifier(c, checked_name);
800803}
801804
802fn transCreateNodeTypedef(rp: RestorePoint, typedef_decl: *const ZigClangTypedefNameDecl, toplevel: bool, checked_name: []const u8) Error!?*ast.Node.VarDecl {
803 const node = try transCreateNodeVarDecl(rp.c, toplevel, true, checked_name);
804 node.eq_token = try appendToken(rp.c, .Equal, "=");
805
805fn transCreateNodeTypedef(
806 rp: RestorePoint,
807 typedef_decl: *const ZigClangTypedefNameDecl,
808 toplevel: bool,
809 checked_name: []const u8,
810) Error!?*ast.Node {
811 const visib_tok = if (toplevel) try appendToken(rp.c, .Keyword_pub, "pub") else null;
812 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
813 const name_tok = try appendIdentifier(rp.c, checked_name);
814 const eq_token = try appendToken(rp.c, .Equal, "=");
806815 const child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl);
807816 const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl);
808 node.init_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) {
817 const init_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) {
809818 error.UnsupportedType => {
810819 try failDecl(rp.c, typedef_loc, checked_name, "unable to resolve typedef child type", .{});
811820 return null;
812821 },
813822 error.OutOfMemory => |e| return e,
814823 };
824 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
815825
816 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
817 return node;
826 const node = try ast.Node.VarDecl.create(rp.c.arena, .{
827 .name_token = name_tok,
828 .mut_token = mut_tok,
829 .semicolon_token = semicolon_token,
830 }, .{
831 .visib_token = visib_tok,
832 .eq_token = eq_token,
833 .init_node = init_node,
834 });
835 return &node.base;
818836}
819837
820838fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*ast.Node {
......@@ -847,12 +865,14 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
847865 const name = try std.fmt.allocPrint(c.arena, "{}_{}", .{ container_kind_name, bare_name });
848866 _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name);
849867
850 const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name);
868 const visib_tok = if (!is_unnamed) try appendToken(c, .Keyword_pub, "pub") else null;
869 const mut_tok = try appendToken(c, .Keyword_const, "const");
870 const name_tok = try appendIdentifier(c, name);
851871
852 node.eq_token = try appendToken(c, .Equal, "=");
872 const eq_token = try appendToken(c, .Equal, "=");
853873
854874 var semicolon: ast.TokenIndex = undefined;
855 node.init_node = blk: {
875 const init_node = blk: {
856876 const rp = makeRestorePoint(c);
857877 const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse {
858878 const opaque = try transCreateNodeOpaqueType(c);
......@@ -959,7 +979,16 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
959979 semicolon = try appendToken(c, .Semicolon, ";");
960980 break :blk &container_node.base;
961981 };
962 node.semicolon_token = semicolon;
982
983 const node = try ast.Node.VarDecl.create(c.arena, .{
984 .name_token = name_tok,
985 .mut_token = mut_tok,
986 .semicolon_token = semicolon,
987 }, .{
988 .visib_token = visib_tok,
989 .eq_token = eq_token,
990 .init_node = init_node,
991 });
963992
964993 try addTopLevelDecl(c, name, &node.base);
965994 if (!is_unnamed)
......@@ -982,10 +1011,13 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
9821011
9831012 const name = try std.fmt.allocPrint(c.arena, "enum_{}", .{bare_name});
9841013 _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name);
985 const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name);
986 node.eq_token = try appendToken(c, .Equal, "=");
9871014
988 node.init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: {
1015 const visib_tok = if (!is_unnamed) try appendToken(c, .Keyword_pub, "pub") else null;
1016 const mut_tok = try appendToken(c, .Keyword_const, "const");
1017 const name_tok = try appendIdentifier(c, name);
1018 const eq_token = try appendToken(c, .Equal, "=");
1019
1020 const init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: {
9891021 var pure_enum = true;
9901022 var it = ZigClangEnumDecl_enumerator_begin(enum_def);
9911023 var end_it = ZigClangEnumDecl_enumerator_end(enum_def);
......@@ -1063,8 +1095,10 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
10631095
10641096 // In C each enum value is in the global namespace. So we put them there too.
10651097 // At this point we can rely on the enum emitting successfully.
1066 const tld_node = try transCreateNodeVarDecl(c, true, true, enum_val_name);
1067 tld_node.eq_token = try appendToken(c, .Equal, "=");
1098 const tld_visib_tok = try appendToken(c, .Keyword_pub, "pub");
1099 const tld_mut_tok = try appendToken(c, .Keyword_const, "const");
1100 const tld_name_tok = try appendIdentifier(c, enum_val_name);
1101 const tld_eq_token = try appendToken(c, .Equal, "=");
10681102 const cast_node = try rp.c.createBuiltinCall("@enumToInt", 1);
10691103 const enum_ident = try transCreateNodeIdentifier(c, name);
10701104 const period_tok = try appendToken(c, .Period, ".");
......@@ -1078,8 +1112,17 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
10781112 };
10791113 cast_node.params()[0] = &field_access_node.base;
10801114 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1081 tld_node.init_node = &cast_node.base;
1082 tld_node.semicolon_token = try appendToken(c, .Semicolon, ";");
1115 const tld_init_node = &cast_node.base;
1116 const tld_semicolon_token = try appendToken(c, .Semicolon, ";");
1117 const tld_node = try ast.Node.VarDecl.create(c.arena, .{
1118 .name_token = tld_name_tok,
1119 .mut_token = tld_mut_tok,
1120 .semicolon_token = tld_semicolon_token,
1121 }, .{
1122 .visib_token = tld_visib_tok,
1123 .eq_token = tld_eq_token,
1124 .init_node = tld_init_node,
1125 });
10831126 try addTopLevelDecl(c, field_name, &tld_node.base);
10841127 }
10851128 // make non exhaustive
......@@ -1109,7 +1152,16 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
11091152 } else
11101153 try transCreateNodeOpaqueType(c);
11111154
1112 node.semicolon_token = try appendToken(c, .Semicolon, ";");
1155 const semicolon_token = try appendToken(c, .Semicolon, ";");
1156 const node = try ast.Node.VarDecl.create(c.arena, .{
1157 .name_token = name_tok,
1158 .mut_token = mut_tok,
1159 .semicolon_token = semicolon_token,
1160 }, .{
1161 .visib_token = visib_tok,
1162 .eq_token = eq_token,
1163 .init_node = init_node,
1164 });
11131165
11141166 try addTopLevelDecl(c, name, &node.base);
11151167 if (!is_unnamed)
......@@ -1118,10 +1170,22 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
11181170}
11191171
11201172fn createAlias(c: *Context, alias: anytype) !void {
1121 const node = try transCreateNodeVarDecl(c, true, true, alias.alias);
1122 node.eq_token = try appendToken(c, .Equal, "=");
1123 node.init_node = try transCreateNodeIdentifier(c, alias.name);
1124 node.semicolon_token = try appendToken(c, .Semicolon, ";");
1173 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
1174 const mut_tok = try appendToken(c, .Keyword_const, "const");
1175 const name_tok = try appendIdentifier(c, alias.alias);
1176 const eq_token = try appendToken(c, .Equal, "=");
1177 const init_node = try transCreateNodeIdentifier(c, alias.name);
1178 const semicolon_token = try appendToken(c, .Semicolon, ";");
1179
1180 const node = try ast.Node.VarDecl.create(c.arena, .{
1181 .name_token = name_tok,
1182 .mut_token = mut_tok,
1183 .semicolon_token = semicolon_token,
1184 }, .{
1185 .visib_token = visib_tok,
1186 .eq_token = eq_token,
1187 .init_node = init_node,
1188 });
11251189 return addTopLevelDecl(c, alias.alias, &node.base);
11261190}
11271191
......@@ -1461,13 +1525,17 @@ fn transDeclStmtOne(
14611525 @ptrCast(*const ZigClangNamedDecl, var_decl),
14621526 ));
14631527 const mangled_name = try block_scope.makeMangledName(c, name);
1464 const node = try transCreateNodeVarDecl(c, false, ZigClangQualType_isConstQualified(qual_type), mangled_name);
1528 const mut_tok = if (ZigClangQualType_isConstQualified(qual_type))
1529 try appendToken(c, .Keyword_const, "const")
1530 else
1531 try appendToken(c, .Keyword_var, "var");
1532 const name_tok = try appendIdentifier(c, mangled_name);
14651533
14661534 _ = try appendToken(c, .Colon, ":");
14671535 const loc = ZigClangDecl_getLocation(decl);
1468 node.type_node = try transQualType(rp, qual_type, loc);
1536 const type_node = try transQualType(rp, qual_type, loc);
14691537
1470 node.eq_token = try appendToken(c, .Equal, "=");
1538 const eq_token = try appendToken(c, .Equal, "=");
14711539 var init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
14721540 try transExprCoercing(rp, scope, expr, .used, .r_value)
14731541 else
......@@ -1478,8 +1546,17 @@ fn transDeclStmtOne(
14781546 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
14791547 init_node = &builtin_node.base;
14801548 }
1481 node.init_node = init_node;
1482 node.semicolon_token = try appendToken(c, .Semicolon, ";");
1549 const semicolon_token = try appendToken(c, .Semicolon, ";");
1550 const node = try ast.Node.VarDecl.create(c.arena, .{
1551 .name_token = name_tok,
1552 .mut_token = mut_tok,
1553 .semicolon_token = semicolon_token,
1554 }, .{
1555 .thread_local_token = thread_local_token,
1556 .eq_token = eq_token,
1557 .type_node = type_node,
1558 .init_node = init_node,
1559 });
14831560 return &node.base;
14841561 },
14851562 .Typedef => {
......@@ -1494,7 +1571,7 @@ fn transDeclStmtOne(
14941571 const mangled_name = try block_scope.makeMangledName(c, name);
14951572 const node = (try transCreateNodeTypedef(rp, typedef_decl, false, mangled_name)) orelse
14961573 return error.UnsupportedTranslation;
1497 return &node.base;
1574 return node;
14981575 },
14991576 else => |kind| return revertAndWarn(
15001577 rp,
......@@ -3105,12 +3182,21 @@ fn transCreatePreCrement(
31053182 defer block_scope.deinit();
31063183 const ref = try block_scope.makeMangledName(rp.c, "ref");
31073184
3108 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
3109 node.eq_token = try appendToken(rp.c, .Equal, "=");
3185 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3186 const name_tok = try appendIdentifier(rp.c, ref);
3187 const eq_token = try appendToken(rp.c, .Equal, "=");
31103188 const rhs_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
31113189 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3112 node.init_node = &rhs_node.base;
3113 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3190 const init_node = &rhs_node.base;
3191 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3192 const node = try ast.Node.VarDecl.create(rp.c.arena, .{
3193 .name_token = name_tok,
3194 .mut_token = mut_tok,
3195 .semicolon_token = semicolon_token,
3196 }, .{
3197 .eq_token = eq_token,
3198 .init_node = init_node,
3199 });
31143200 try block_scope.statements.append(&node.base);
31153201
31163202 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
......@@ -3171,12 +3257,21 @@ fn transCreatePostCrement(
31713257 defer block_scope.deinit();
31723258 const ref = try block_scope.makeMangledName(rp.c, "ref");
31733259
3174 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
3175 node.eq_token = try appendToken(rp.c, .Equal, "=");
3260 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3261 const name_tok = try appendIdentifier(rp.c, ref);
3262 const eq_token = try appendToken(rp.c, .Equal, "=");
31763263 const rhs_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
31773264 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3178 node.init_node = &rhs_node.base;
3179 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3265 const init_node = &rhs_node.base;
3266 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3267 const node = try ast.Node.VarDecl.create(rp.c.arena, .{
3268 .name_token = name_tok,
3269 .mut_token = mut_tok,
3270 .semicolon_token = semicolon_token,
3271 }, .{
3272 .eq_token = eq_token,
3273 .init_node = init_node,
3274 });
31803275 try block_scope.statements.append(&node.base);
31813276
31823277 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
......@@ -3184,10 +3279,19 @@ fn transCreatePostCrement(
31843279 _ = try appendToken(rp.c, .Semicolon, ";");
31853280
31863281 const tmp = try block_scope.makeMangledName(rp.c, "tmp");
3187 const tmp_node = try transCreateNodeVarDecl(rp.c, false, true, tmp);
3188 tmp_node.eq_token = try appendToken(rp.c, .Equal, "=");
3189 tmp_node.init_node = ref_node;
3190 tmp_node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3282 const tmp_mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3283 const tmp_name_tok = try appendIdentifier(rp.c, tmp);
3284 const tmp_eq_token = try appendToken(rp.c, .Equal, "=");
3285 const tmp_init_node = ref_node;
3286 const tmp_semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3287 const tmp_node = try ast.Node.VarDecl.create(rp.c.arena, .{
3288 .name_token = tmp_name_tok,
3289 .mut_token = tmp_mut_tok,
3290 .semicolon_token = semicolon_token,
3291 }, .{
3292 .eq_token = tmp_eq_token,
3293 .init_node = tmp_init_node,
3294 });
31913295 try block_scope.statements.append(&tmp_node.base);
31923296
31933297 const token = try appendToken(rp.c, op_tok_id, bytes);
......@@ -3325,12 +3429,21 @@ fn transCreateCompoundAssign(
33253429 defer block_scope.deinit();
33263430 const ref = try block_scope.makeMangledName(rp.c, "ref");
33273431
3328 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
3329 node.eq_token = try appendToken(rp.c, .Equal, "=");
3432 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3433 const name_tok = try appendIdentifier(rp.c, ref);
3434 const eq_token = try appendToken(rp.c, .Equal, "=");
33303435 const addr_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
33313436 addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value);
3332 node.init_node = &addr_node.base;
3333 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3437 const init_node = &addr_node.base;
3438 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3439 const node = try ast.Node.VarDecl.create(rp.c.arena, .{
3440 .name_token = name_tok,
3441 .mut_token = mut_tok,
3442 .semicolon_token = semicolon_token,
3443 }, .{
3444 .eq_token = eq_token,
3445 .init_node = init_node,
3446 });
33343447 try block_scope.statements.append(&node.base);
33353448
33363449 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
......@@ -3375,8 +3488,8 @@ fn transCreateCompoundAssign(
33753488 const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false);
33763489 _ = try appendToken(rp.c, .Semicolon, ";");
33773490
3378 const eq_token = try appendToken(rp.c, .Equal, "=");
3379 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, eq_token, rhs_bin, .used, false);
3491 const ass_eq_token = try appendToken(rp.c, .Equal, "=");
3492 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, ass_eq_token, rhs_bin, .used, false);
33803493 try block_scope.statements.append(assign);
33813494 }
33823495
......@@ -3494,10 +3607,19 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const
34943607 defer block_scope.deinit();
34953608
34963609 const mangled_name = try block_scope.makeMangledName(rp.c, "cond_temp");
3497 const tmp_var = try transCreateNodeVarDecl(rp.c, false, true, mangled_name);
3498 tmp_var.eq_token = try appendToken(rp.c, .Equal, "=");
3499 tmp_var.init_node = try transExpr(rp, &block_scope.base, cond_expr, .used, .r_value);
3500 tmp_var.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3610 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3611 const name_tok = try appendIdentifier(rp.c, mangled_name);
3612 const eq_token = try appendToken(rp.c, .Equal, "=");
3613 const init_node = try transExpr(rp, &block_scope.base, cond_expr, .used, .r_value);
3614 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3615 const tmp_var = try ast.Node.VarDecl.create(rp.c.arena, .{
3616 .name_token = name_tok,
3617 .mut_token = mut_tok,
3618 .semicolon_token = semicolon_token,
3619 }, .{
3620 .eq_token = eq_token,
3621 .init_node = init_node,
3622 });
35013623 try block_scope.statements.append(&tmp_var.base);
35023624
35033625 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);
......@@ -3932,9 +4054,9 @@ fn transCreateNodeAssign(
39324054 defer block_scope.deinit();
39334055
39344056 const tmp = try block_scope.makeMangledName(rp.c, "tmp");
3935
3936 const node = try transCreateNodeVarDecl(rp.c, false, true, tmp);
3937 node.eq_token = try appendToken(rp.c, .Equal, "=");
4057 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
4058 const name_tok = try appendIdentifier(rp.c, tmp);
4059 const eq_token = try appendToken(rp.c, .Equal, "=");
39384060 var rhs_node = try transExpr(rp, &block_scope.base, rhs, .used, .r_value);
39394061 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {
39404062 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
......@@ -3942,16 +4064,24 @@ fn transCreateNodeAssign(
39424064 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
39434065 rhs_node = &builtin_node.base;
39444066 }
3945 node.init_node = rhs_node;
3946 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
4067 const init_node = rhs_node;
4068 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
4069 const node = try ast.Node.VarDecl.create(rp.c.arena, .{
4070 .name_token = name_tok,
4071 .mut_token = mut_tok,
4072 .semicolon_token = semicolon_token,
4073 }, .{
4074 .eq_token = eq_token,
4075 .init_node = init_node,
4076 });
39474077 try block_scope.statements.append(&node.base);
39484078
39494079 const lhs_node = try transExpr(rp, &block_scope.base, lhs, .used, .l_value);
3950 const eq_token = try appendToken(rp.c, .Equal, "=");
4080 const lhs_eq_token = try appendToken(rp.c, .Equal, "=");
39514081 const ident = try transCreateNodeIdentifier(rp.c, tmp);
39524082 _ = try appendToken(rp.c, .Semicolon, ";");
39534083
3954 const assign = try transCreateNodeInfixOp(rp, &block_scope.base, lhs_node, .Assign, eq_token, ident, .used, false);
4084 const assign = try transCreateNodeInfixOp(rp, &block_scope.base, lhs_node, .Assign, lhs_eq_token, ident, .used, false);
39554085 try block_scope.statements.append(assign);
39564086
39574087 const break_node = try transCreateNodeBreak(rp.c, label_name);
......@@ -4232,28 +4362,10 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
42324362
42334363 _ = try appendToken(c, .RParen, ")");
42344364
4235 const fn_proto = try ast.Node.FnProto.alloc(c.arena, fn_params.items.len);
4236 fn_proto.* = .{
4237 .doc_comments = null,
4238 .visib_token = pub_tok,
4239 .fn_token = fn_tok,
4240 .name_token = name_tok,
4241 .params_len = fn_params.items.len,
4242 .return_type = proto_alias.return_type,
4243 .var_args_token = null,
4244 .extern_export_inline_token = inline_tok,
4245 .body_node = null,
4246 .lib_name = null,
4247 .align_expr = null,
4248 .section_expr = null,
4249 .callconv_expr = null,
4250 };
4251 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
4252
42534365 const block_lbrace = try appendToken(c, .LBrace, "{");
42544366
42554367 const return_expr = try transCreateNodeReturnExpr(c);
4256 const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.init_node.?);
4368 const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.getTrailer("init_node").?);
42574369
42584370 const call_expr = try c.createCall(unwrap_expr, fn_params.items.len);
42594371 const call_params = call_expr.params();
......@@ -4277,7 +4389,18 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
42774389 .rbrace = try appendToken(c, .RBrace, "}"),
42784390 };
42794391 block.statements()[0] = &return_expr.base;
4280 fn_proto.body_node = &block.base;
4392
4393 const fn_proto = try ast.Node.FnProto.create(c.arena, .{
4394 .params_len = fn_params.items.len,
4395 .fn_token = fn_tok,
4396 .return_type = proto_alias.return_type,
4397 }, .{
4398 .visib_token = pub_tok,
4399 .name_token = name_tok,
4400 .extern_export_inline_token = inline_tok,
4401 .body_node = &block.base,
4402 });
4403 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
42814404 return &fn_proto.base;
42824405}
42834406
......@@ -4356,31 +4479,6 @@ fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowE
43564479 return node;
43574480}
43584481
4359fn transCreateNodeVarDecl(c: *Context, is_pub: bool, is_const: bool, name: []const u8) !*ast.Node.VarDecl {
4360 const visib_tok = if (is_pub) try appendToken(c, .Keyword_pub, "pub") else null;
4361 const mut_tok = if (is_const) try appendToken(c, .Keyword_const, "const") else try appendToken(c, .Keyword_var, "var");
4362 const name_tok = try appendIdentifier(c, name);
4363
4364 const node = try c.arena.create(ast.Node.VarDecl);
4365 node.* = .{
4366 .doc_comments = null,
4367 .visib_token = visib_tok,
4368 .thread_local_token = null,
4369 .name_token = name_tok,
4370 .eq_token = undefined,
4371 .mut_token = mut_tok,
4372 .comptime_token = null,
4373 .extern_export_token = null,
4374 .lib_name = null,
4375 .type_node = null,
4376 .align_node = null,
4377 .section_node = null,
4378 .init_node = null,
4379 .semicolon_token = undefined,
4380 };
4381 return node;
4382}
4383
43844482fn transCreateNodeWhile(c: *Context) !*ast.Node.While {
43854483 const while_tok = try appendToken(c, .Keyword_while, "while");
43864484 _ = try appendToken(c, .LParen, "(");
......@@ -4782,19 +4880,12 @@ fn finishTransFnProto(
47824880 }
47834881 }
47844882
4785 if (is_var_args) {
4883 const var_args_token: ?ast.TokenIndex = if (is_var_args) blk: {
47864884 if (param_count > 0) {
47874885 _ = try appendToken(rp.c, .Comma, ",");
47884886 }
4789
4790 fn_params.addOneAssumeCapacity().* = .{
4791 .doc_comments = null,
4792 .comptime_token = null,
4793 .noalias_token = null,
4794 .name_token = null,
4795 .param_type = .{ .var_args = try appendToken(rp.c, .Ellipsis3, "...") },
4796 };
4797 }
4887 break :blk try appendToken(rp.c, .Ellipsis3, "...");
4888 } else null;
47984889
47994890 const rparen_tok = try appendToken(rp.c, .RParen, ")");
48004891
......@@ -4860,22 +4951,31 @@ fn finishTransFnProto(
48604951 }
48614952 };
48624953
4863 const fn_proto = try ast.Node.FnProto.alloc(rp.c.arena, fn_params.items.len);
4864 fn_proto.* = .{
4865 .doc_comments = null,
4866 .visib_token = pub_tok,
4867 .fn_token = fn_tok,
4868 .name_token = name_tok,
4954 // We need to reserve an undefined (but non-null) body node to set later.
4955 var body_node: ?*ast.Node = null;
4956 if (fn_decl_context) |ctx| {
4957 if (ctx.has_body) {
4958 // TODO: we should be able to use undefined here but
4959 // it causes a bug. This is undefined without zig language
4960 // being aware of it.
4961 body_node = @intToPtr(*ast.Node, 0x08);
4962 }
4963 }
4964
4965 const fn_proto = try ast.Node.FnProto.create(rp.c.arena, .{
48694966 .params_len = fn_params.items.len,
48704967 .return_type = .{ .Explicit = return_type_node },
4871 .var_args_token = null, // TODO this field is broken in the AST data model
4968 .fn_token = fn_tok,
4969 }, .{
4970 .visib_token = pub_tok,
4971 .name_token = name_tok,
48724972 .extern_export_inline_token = extern_export_inline_tok,
4873 .body_node = null,
4874 .lib_name = null,
48754973 .align_expr = align_expr,
48764974 .section_expr = linksection_expr,
48774975 .callconv_expr = callconv_expr,
4878 };
4976 .body_node = body_node,
4977 .var_args_token = var_args_token,
4978 });
48794979 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
48804980 return fn_proto;
48814981}
......@@ -4923,23 +5023,15 @@ pub fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comp
49235023 };
49245024 call_node.params()[0] = &msg_node.base;
49255025
4926 const var_decl_node = try c.arena.create(ast.Node.VarDecl);
4927 var_decl_node.* = .{
4928 .doc_comments = null,
4929 .visib_token = pub_tok,
4930 .thread_local_token = null,
5026 const var_decl_node = try ast.Node.VarDecl.create(c.arena, .{
49315027 .name_token = name_tok,
4932 .eq_token = eq_tok,
49335028 .mut_token = const_tok,
4934 .comptime_token = null,
4935 .extern_export_token = null,
4936 .lib_name = null,
4937 .type_node = null,
4938 .align_node = null,
4939 .section_node = null,
4940 .init_node = &call_node.base,
49415029 .semicolon_token = semi_tok,
4942 };
5030 }, .{
5031 .visib_token = pub_tok,
5032 .eq_token = eq_tok,
5033 .init_node = &call_node.base,
5034 });
49435035 try addTopLevelDecl(c, name, &var_decl_node.base);
49445036}
49455037
......@@ -5132,10 +5224,12 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
51325224fn transMacroDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void {
51335225 const scope = &c.global_scope.base;
51345226
5135 const node = try transCreateNodeVarDecl(c, true, true, name);
5136 node.eq_token = try appendToken(c, .Equal, "=");
5227 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
5228 const mut_tok = try appendToken(c, .Keyword_const, "const");
5229 const name_tok = try appendIdentifier(c, name);
5230 const eq_token = try appendToken(c, .Equal, "=");
51375231
5138 node.init_node = try parseCExpr(c, it, source, source_loc, scope);
5232 const init_node = try parseCExpr(c, it, source, source_loc, scope);
51395233 const last = it.next().?;
51405234 if (last.id != .Eof and last.id != .Nl)
51415235 return failDecl(
......@@ -5146,7 +5240,16 @@ fn transMacroDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, n
51465240 .{@tagName(last.id)},
51475241 );
51485242
5149 node.semicolon_token = try appendToken(c, .Semicolon, ";");
5243 const semicolon_token = try appendToken(c, .Semicolon, ";");
5244 const node = try ast.Node.VarDecl.create(c.arena, .{
5245 .name_token = name_tok,
5246 .mut_token = mut_tok,
5247 .semicolon_token = semicolon_token,
5248 }, .{
5249 .visib_token = visib_tok,
5250 .eq_token = eq_token,
5251 .init_node = init_node,
5252 });
51505253 _ = try c.global_scope.macro_table.put(name, &node.base);
51515254}
51525255
......@@ -5223,24 +5326,6 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
52235326
52245327 const type_of = try c.createBuiltinCall("@TypeOf", 1);
52255328
5226 const fn_proto = try ast.Node.FnProto.alloc(c.arena, fn_params.items.len);
5227 fn_proto.* = .{
5228 .visib_token = pub_tok,
5229 .extern_export_inline_token = inline_tok,
5230 .fn_token = fn_tok,
5231 .name_token = name_tok,
5232 .params_len = fn_params.items.len,
5233 .return_type = .{ .Explicit = &type_of.base },
5234 .doc_comments = null,
5235 .var_args_token = null,
5236 .body_node = null,
5237 .lib_name = null,
5238 .align_expr = null,
5239 .section_expr = null,
5240 .callconv_expr = null,
5241 };
5242 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
5243
52445329 const return_expr = try transCreateNodeReturnExpr(c);
52455330 const expr = try parseCExpr(c, it, source, source_loc, scope);
52465331 const last = it.next().?;
......@@ -5266,7 +5351,18 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
52665351
52675352 try block_scope.statements.append(&return_expr.base);
52685353 const block_node = try block_scope.complete(c);
5269 fn_proto.body_node = &block_node.base;
5354 const fn_proto = try ast.Node.FnProto.create(c.arena, .{
5355 .fn_token = fn_tok,
5356 .params_len = fn_params.items.len,
5357 .return_type = .{ .Explicit = &type_of.base },
5358 }, .{
5359 .visib_token = pub_tok,
5360 .extern_export_inline_token = inline_tok,
5361 .name_token = name_tok,
5362 .body_node = &block_node.base,
5363 });
5364 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
5365
52705366 _ = try c.global_scope.macro_table.put(name, &fn_proto.base);
52715367}
52725368
......@@ -6030,7 +6126,7 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
60306126 const ident = node.cast(ast.Node.Identifier).?;
60316127 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
60326128 if (value.cast(ast.Node.VarDecl)) |var_decl|
6033 return getContainer(c, var_decl.init_node.?);
6129 return getContainer(c, var_decl.getTrailer("init_node").?);
60346130 }
60356131 },
60366132
......@@ -6060,7 +6156,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
60606156 if (ref.cast(ast.Node.Identifier)) |ident| {
60616157 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
60626158 if (value.cast(ast.Node.VarDecl)) |var_decl| {
6063 if (var_decl.type_node) |ty|
6159 if (var_decl.getTrailer("type_node")) |ty|
60646160 return getContainer(c, ty);
60656161 }
60666162 }
......@@ -6084,7 +6180,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
60846180}
60856181
60866182fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto {
6087 const init = if (ref.cast(ast.Node.VarDecl)) |v| v.init_node.? else return null;
6183 const init = if (ref.cast(ast.Node.VarDecl)) |v| v.getTrailer("init_node").? else return null;
60886184 if (getContainerTypeOf(c, init)) |ty_node| {
60896185 if (ty_node.cast(ast.Node.OptionalType)) |prefix| {
60906186 if (prefix.rhs.cast(ast.Node.FnProto)) |fn_proto| {
test/translate_c.zig+1-1
......@@ -2797,7 +2797,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
27972797 \\pub fn a() callconv(.C) void {}
27982798 \\pub fn b() callconv(.C) void {}
27992799 \\pub export fn c() void {}
2800 \\pub fn foo() callconv(.C) void {}
2800 \\pub fn foo(...) callconv(.C) void {}
28012801 });
28022802
28032803 cases.add("casting away const and volatile",