Commit ccc7f9987d

Robin Voetter <robin@voetter.nl>
2021-09-02 14:45:00
Address spaces: addrspace(A) parsing
The grammar for function prototypes, (global) variable declarations, and pointer types now accepts an optional addrspace(A) modifier.
1 parent 9fa723e
Changed files (4)
lib
src
translate_c
lib/std/zig/Ast.zig
@@ -262,6 +262,9 @@ pub fn renderError(tree: Tree, parse_error: Error, stream: anytype) !void {
                 token_tags[parse_error.token].symbol(),
             });
         },
+        .extra_addrspace_qualifier => {
+            return stream.writeAll("extra addrspace qualifier");
+        },
         .extra_align_qualifier => {
             return stream.writeAll("extra align qualifier");
         },
@@ -1021,7 +1024,7 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex {
         },
         .fn_proto_one => {
             const extra = tree.extraData(datas[n].lhs, Node.FnProtoOne);
-            // linksection, callconv, align can appear in any order, so we
+            // addrspace, linksection, callconv, align can appear in any order, so we
             // find the last one here.
             var max_node: Node.Index = datas[n].rhs;
             var max_start = token_starts[main_tokens[max_node]];
@@ -1034,6 +1037,14 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex {
                     max_offset = 1; // for the rparen
                 }
             }
+            if (extra.addrspace_expr != 0) {
+                const start = token_starts[main_tokens[extra.addrspace_expr]];
+                if (start > max_start) {
+                    max_node = extra.addrspace_expr;
+                    max_start = start;
+                    max_offset = 1; // for the rparen
+                }
+            }
             if (extra.section_expr != 0) {
                 const start = token_starts[main_tokens[extra.section_expr]];
                 if (start > max_start) {
@@ -1055,7 +1066,7 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex {
         },
         .fn_proto => {
             const extra = tree.extraData(datas[n].lhs, Node.FnProto);
-            // linksection, callconv, align can appear in any order, so we
+            // addrspace, linksection, callconv, align can appear in any order, so we
             // find the last one here.
             var max_node: Node.Index = datas[n].rhs;
             var max_start = token_starts[main_tokens[max_node]];
@@ -1068,6 +1079,14 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex {
                     max_offset = 1; // for the rparen
                 }
             }
+            if (extra.addrspace_expr != 0) {
+                const start = token_starts[main_tokens[extra.addrspace_expr]];
+                if (start > max_start) {
+                    max_node = extra.addrspace_expr;
+                    max_start = start;
+                    max_offset = 1; // for the rparen
+                }
+            }
             if (extra.section_expr != 0) {
                 const start = token_starts[main_tokens[extra.section_expr]];
                 if (start > max_start) {
@@ -1138,6 +1157,7 @@ pub fn globalVarDecl(tree: Tree, node: Node.Index) full.VarDecl {
     return tree.fullVarDecl(.{
         .type_node = extra.type_node,
         .align_node = extra.align_node,
+        .addrspace_node = extra.addrspace_node,
         .section_node = extra.section_node,
         .init_node = data.rhs,
         .mut_token = tree.nodes.items(.main_token)[node],
@@ -1151,6 +1171,7 @@ pub fn localVarDecl(tree: Tree, node: Node.Index) full.VarDecl {
     return tree.fullVarDecl(.{
         .type_node = extra.type_node,
         .align_node = extra.align_node,
+        .addrspace_node = 0,
         .section_node = 0,
         .init_node = data.rhs,
         .mut_token = tree.nodes.items(.main_token)[node],
@@ -1163,6 +1184,7 @@ pub fn simpleVarDecl(tree: Tree, node: Node.Index) full.VarDecl {
     return tree.fullVarDecl(.{
         .type_node = data.lhs,
         .align_node = 0,
+        .addrspace_node = 0,
         .section_node = 0,
         .init_node = data.rhs,
         .mut_token = tree.nodes.items(.main_token)[node],
@@ -1175,6 +1197,7 @@ pub fn alignedVarDecl(tree: Tree, node: Node.Index) full.VarDecl {
     return tree.fullVarDecl(.{
         .type_node = 0,
         .align_node = data.lhs,
+        .addrspace_node = 0,
         .section_node = 0,
         .init_node = data.rhs,
         .mut_token = tree.nodes.items(.main_token)[node],
@@ -1249,6 +1272,7 @@ pub fn fnProtoSimple(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.
         .return_type = data.rhs,
         .params = params,
         .align_expr = 0,
+        .addrspace_expr = 0,
         .section_expr = 0,
         .callconv_expr = 0,
     });
@@ -1265,6 +1289,7 @@ pub fn fnProtoMulti(tree: Tree, node: Node.Index) full.FnProto {
         .return_type = data.rhs,
         .params = params,
         .align_expr = 0,
+        .addrspace_expr = 0,
         .section_expr = 0,
         .callconv_expr = 0,
     });
@@ -1282,6 +1307,7 @@ pub fn fnProtoOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.FnP
         .return_type = data.rhs,
         .params = params,
         .align_expr = extra.align_expr,
+        .addrspace_expr = extra.addrspace_expr,
         .section_expr = extra.section_expr,
         .callconv_expr = extra.callconv_expr,
     });
@@ -1298,6 +1324,7 @@ pub fn fnProto(tree: Tree, node: Node.Index) full.FnProto {
         .return_type = data.rhs,
         .params = params,
         .align_expr = extra.align_expr,
+        .addrspace_expr = extra.addrspace_expr,
         .section_expr = extra.section_expr,
         .callconv_expr = extra.callconv_expr,
     });
@@ -1453,6 +1480,7 @@ pub fn ptrTypeAligned(tree: Tree, node: Node.Index) full.PtrType {
     return tree.fullPtrType(.{
         .main_token = tree.nodes.items(.main_token)[node],
         .align_node = data.lhs,
+        .addrspace_node = 0,
         .sentinel = 0,
         .bit_range_start = 0,
         .bit_range_end = 0,
@@ -1466,6 +1494,7 @@ pub fn ptrTypeSentinel(tree: Tree, node: Node.Index) full.PtrType {
     return tree.fullPtrType(.{
         .main_token = tree.nodes.items(.main_token)[node],
         .align_node = 0,
+        .addrspace_node = 0,
         .sentinel = data.lhs,
         .bit_range_start = 0,
         .bit_range_end = 0,
@@ -1480,6 +1509,7 @@ pub fn ptrType(tree: Tree, node: Node.Index) full.PtrType {
     return tree.fullPtrType(.{
         .main_token = tree.nodes.items(.main_token)[node],
         .align_node = extra.align_node,
+        .addrspace_node = extra.addrspace_node,
         .sentinel = extra.sentinel,
         .bit_range_start = 0,
         .bit_range_end = 0,
@@ -1494,6 +1524,7 @@ pub fn ptrTypeBitRange(tree: Tree, node: Node.Index) full.PtrType {
     return tree.fullPtrType(.{
         .main_token = tree.nodes.items(.main_token)[node],
         .align_node = extra.align_node,
+        .addrspace_node = extra.addrspace_node,
         .sentinel = extra.sentinel,
         .bit_range_start = extra.bit_range_start,
         .bit_range_end = extra.bit_range_end,
@@ -2063,6 +2094,7 @@ pub const full = struct {
             mut_token: TokenIndex,
             type_node: Node.Index,
             align_node: Node.Index,
+            addrspace_node: Node.Index,
             section_node: Node.Index,
             init_node: Node.Index,
         };
@@ -2130,6 +2162,7 @@ pub const full = struct {
             return_type: Node.Index,
             params: []const Node.Index,
             align_expr: Node.Index,
+            addrspace_expr: Node.Index,
             section_expr: Node.Index,
             callconv_expr: Node.Index,
         };
@@ -2288,6 +2321,7 @@ pub const full = struct {
         pub const Components = struct {
             main_token: TokenIndex,
             align_node: Node.Index,
+            addrspace_node: Node.Index,
             sentinel: Node.Index,
             bit_range_start: Node.Index,
             bit_range_end: Node.Index,
@@ -2397,6 +2431,7 @@ pub const Error = struct {
         expected_var_decl_or_fn,
         expected_loop_payload,
         expected_container,
+        extra_addrspace_qualifier,
         extra_align_qualifier,
         extra_allowzero_qualifier,
         extra_const_qualifier,
@@ -2723,13 +2758,13 @@ pub const Node = struct {
         /// main_token is the `fn` keyword.
         /// extern function declarations use this tag.
         fn_proto_multi,
-        /// `fn(a: b) rhs linksection(e) callconv(f)`. `FnProtoOne[lhs]`.
+        /// `fn(a: b) rhs addrspace(e) linksection(f) callconv(g)`. `FnProtoOne[lhs]`.
         /// zero or one parameters.
         /// anytype and ... parameters are omitted from the AST tree.
         /// main_token is the `fn` keyword.
         /// extern function declarations use this tag.
         fn_proto_one,
-        /// `fn(a: b, c: d) rhs linksection(e) callconv(f)`. `FnProto[lhs]`.
+        /// `fn(a: b, c: d) rhs addrspace(e) linksection(f) callconv(g)`. `FnProto[lhs]`.
         /// anytype and ... parameters are omitted from the AST tree.
         /// main_token is the `fn` keyword.
         /// extern function declarations use this tag.
@@ -2893,11 +2928,13 @@ pub const Node = struct {
     pub const PtrType = struct {
         sentinel: Index,
         align_node: Index,
+        addrspace_node: Index,
     };
 
     pub const PtrTypeBitRange = struct {
         sentinel: Index,
         align_node: Index,
+        addrspace_node: Index,
         bit_range_start: Index,
         bit_range_end: Index,
     };
@@ -2920,8 +2957,13 @@ pub const Node = struct {
     };
 
     pub const GlobalVarDecl = struct {
+        /// Populated if there is an explicit type ascription.
         type_node: Index,
+        /// Populated if align(A) is present.
         align_node: Index,
+        /// Populated if linksection(A) is present.
+        addrspace_node: Index,
+        /// Populated if addrspace(A) is present.
         section_node: Index,
     };
 
@@ -2954,6 +2996,8 @@ pub const Node = struct {
         /// Populated if align(A) is present.
         align_expr: Index,
         /// Populated if linksection(A) is present.
+        addrspace_expr: Index,
+        /// Populated if addrspace(A) is present.
         section_expr: Index,
         /// Populated if callconv(A) is present.
         callconv_expr: Index,
@@ -2964,6 +3008,8 @@ pub const Node = struct {
         params_end: Index,
         /// Populated if align(A) is present.
         align_expr: Index,
+        /// Populated if addrspace(A) is present.
+        addrspace_expr: Index,
         /// Populated if linksection(A) is present.
         section_expr: Index,
         /// Populated if callconv(A) is present.
lib/std/zig/parse.zig
@@ -629,7 +629,7 @@ const Parser = struct {
         };
     }
 
-    /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr
+    /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr
     fn parseFnProto(p: *Parser) !Node.Index {
         const fn_token = p.eatToken(.keyword_fn) orelse return null_node;
 
@@ -639,6 +639,7 @@ const Parser = struct {
         _ = p.eatToken(.identifier);
         const params = try p.parseParamDeclList();
         const align_expr = try p.parseByteAlign();
+        const addrspace_expr = try p.parseAddrSpace();
         const section_expr = try p.parseLinkSection();
         const callconv_expr = try p.parseCallconv();
         _ = p.eatToken(.bang);
@@ -650,7 +651,7 @@ const Parser = struct {
             try p.warn(.expected_return_type);
         }
 
-        if (align_expr == 0 and section_expr == 0 and callconv_expr == 0) {
+        if (align_expr == 0 and section_expr == 0 and callconv_expr == 0 and addrspace_expr == 0) {
             switch (params) {
                 .zero_or_one => |param| return p.setNode(fn_proto_index, .{
                     .tag = .fn_proto_simple,
@@ -683,6 +684,7 @@ const Parser = struct {
                     .lhs = try p.addExtra(Node.FnProtoOne{
                         .param = param,
                         .align_expr = align_expr,
+                        .addrspace_expr = addrspace_expr,
                         .section_expr = section_expr,
                         .callconv_expr = callconv_expr,
                     }),
@@ -698,6 +700,7 @@ const Parser = struct {
                             .params_start = span.start,
                             .params_end = span.end,
                             .align_expr = align_expr,
+                            .addrspace_expr = addrspace_expr,
                             .section_expr = section_expr,
                             .callconv_expr = callconv_expr,
                         }),
@@ -708,7 +711,7 @@ const Parser = struct {
         }
     }
 
-    /// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON
+    /// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection? (EQUAL Expr)? SEMICOLON
     fn parseVarDecl(p: *Parser) !Node.Index {
         const mut_token = p.eatToken(.keyword_const) orelse
             p.eatToken(.keyword_var) orelse
@@ -717,9 +720,10 @@ const Parser = struct {
         _ = try p.expectToken(.identifier);
         const type_node: Node.Index = if (p.eatToken(.colon) == null) 0 else try p.expectTypeExpr();
         const align_node = try p.parseByteAlign();
+        const addrspace_node = try p.parseAddrSpace();
         const section_node = try p.parseLinkSection();
         const init_node: Node.Index = if (p.eatToken(.equal) == null) 0 else try p.expectExpr();
-        if (section_node == 0) {
+        if (section_node == 0 and addrspace_node == 0) {
             if (align_node == 0) {
                 return p.addNode(.{
                     .tag = .simple_var_decl,
@@ -759,6 +763,7 @@ const Parser = struct {
                     .lhs = try p.addExtra(Node.GlobalVarDecl{
                         .type_node = type_node,
                         .align_node = align_node,
+                        .addrspace_node = addrspace_node,
                         .section_node = section_node,
                     }),
                     .rhs = init_node,
@@ -1440,8 +1445,8 @@ const Parser = struct {
     /// PrefixTypeOp
     ///     <- QUESTIONMARK
     ///      / KEYWORD_anyframe MINUSRARROW
-    ///      / SliceTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
-    ///      / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
+    ///      / SliceTypeStart (ByteAlign / AddrSpace / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
+    ///      / PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
     ///      / ArrayTypeStart
     /// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET
     /// PtrTypeStart
@@ -1474,29 +1479,43 @@ const Parser = struct {
                 const asterisk = p.nextToken();
                 const mods = try p.parsePtrModifiers();
                 const elem_type = try p.expectTypeExpr();
-                if (mods.bit_range_start == 0) {
+                if (mods.bit_range_start != 0) {
                     return p.addNode(.{
-                        .tag = .ptr_type_aligned,
+                        .tag = .ptr_type_bit_range,
                         .main_token = asterisk,
                         .data = .{
-                            .lhs = mods.align_node,
+                            .lhs = try p.addExtra(Node.PtrTypeBitRange{
+                                .sentinel = 0,
+                                .align_node = mods.align_node,
+                                .addrspace_node = mods.addrspace_node,
+                                .bit_range_start = mods.bit_range_start,
+                                .bit_range_end = mods.bit_range_end,
+                            }),
                             .rhs = elem_type,
                         },
                     });
-                } else {
+                } else if (mods.addrspace_node != 0) {
                     return p.addNode(.{
-                        .tag = .ptr_type_bit_range,
+                        .tag = .ptr_type,
                         .main_token = asterisk,
                         .data = .{
-                            .lhs = try p.addExtra(Node.PtrTypeBitRange{
+                            .lhs = try p.addExtra(Node.PtrType{
                                 .sentinel = 0,
                                 .align_node = mods.align_node,
-                                .bit_range_start = mods.bit_range_start,
-                                .bit_range_end = mods.bit_range_end,
+                                .addrspace_node = mods.addrspace_node,
                             }),
                             .rhs = elem_type,
                         },
                     });
+                } else {
+                    return p.addNode(.{
+                        .tag = .ptr_type_aligned,
+                        .main_token = asterisk,
+                        .data = .{
+                            .lhs = mods.align_node,
+                            .rhs = elem_type,
+                        },
+                    });
                 }
             },
             .asterisk_asterisk => {
@@ -1504,29 +1523,43 @@ const Parser = struct {
                 const mods = try p.parsePtrModifiers();
                 const elem_type = try p.expectTypeExpr();
                 const inner: Node.Index = inner: {
-                    if (mods.bit_range_start == 0) {
+                    if (mods.bit_range_start != 0) {
                         break :inner try p.addNode(.{
-                            .tag = .ptr_type_aligned,
+                            .tag = .ptr_type_bit_range,
                             .main_token = asterisk,
                             .data = .{
-                                .lhs = mods.align_node,
+                                .lhs = try p.addExtra(Node.PtrTypeBitRange{
+                                    .sentinel = 0,
+                                    .align_node = mods.align_node,
+                                    .addrspace_node = mods.addrspace_node,
+                                    .bit_range_start = mods.bit_range_start,
+                                    .bit_range_end = mods.bit_range_end,
+                                }),
                                 .rhs = elem_type,
                             },
                         });
-                    } else {
+                    } else if (mods.addrspace_node != 0) {
                         break :inner try p.addNode(.{
-                            .tag = .ptr_type_bit_range,
+                            .tag = .ptr_type,
                             .main_token = asterisk,
                             .data = .{
-                                .lhs = try p.addExtra(Node.PtrTypeBitRange{
+                                .lhs = try p.addExtra(Node.PtrType{
                                     .sentinel = 0,
                                     .align_node = mods.align_node,
-                                    .bit_range_start = mods.bit_range_start,
-                                    .bit_range_end = mods.bit_range_end,
+                                    .addrspace_node = mods.addrspace_node,
                                 }),
                                 .rhs = elem_type,
                             },
                         });
+                    } else {
+                        break :inner try p.addNode(.{
+                            .tag = .ptr_type_aligned,
+                            .main_token = asterisk,
+                            .data = .{
+                                .lhs = mods.align_node,
+                                .rhs = elem_type,
+                            },
+                        });
                     }
                 };
                 return p.addNode(.{
@@ -1560,7 +1593,7 @@ const Parser = struct {
                     const mods = try p.parsePtrModifiers();
                     const elem_type = try p.expectTypeExpr();
                     if (mods.bit_range_start == 0) {
-                        if (sentinel == 0) {
+                        if (sentinel == 0 and mods.addrspace_node == 0) {
                             return p.addNode(.{
                                 .tag = .ptr_type_aligned,
                                 .main_token = asterisk,
@@ -1569,7 +1602,7 @@ const Parser = struct {
                                     .rhs = elem_type,
                                 },
                             });
-                        } else if (mods.align_node == 0) {
+                        } else if (mods.align_node == 0 and mods.addrspace_node == 0) {
                             return p.addNode(.{
                                 .tag = .ptr_type_sentinel,
                                 .main_token = asterisk,
@@ -1586,6 +1619,7 @@ const Parser = struct {
                                     .lhs = try p.addExtra(Node.PtrType{
                                         .sentinel = sentinel,
                                         .align_node = mods.align_node,
+                                        .addrspace_node = mods.addrspace_node,
                                     }),
                                     .rhs = elem_type,
                                 },
@@ -1599,6 +1633,7 @@ const Parser = struct {
                                 .lhs = try p.addExtra(Node.PtrTypeBitRange{
                                     .sentinel = sentinel,
                                     .align_node = mods.align_node,
+                                    .addrspace_node = mods.addrspace_node,
                                     .bit_range_start = mods.bit_range_start,
                                     .bit_range_end = mods.bit_range_end,
                                 }),
@@ -1624,7 +1659,7 @@ const Parser = struct {
                                 .token = p.nodes.items(.main_token)[mods.bit_range_start],
                             });
                         }
-                        if (sentinel == 0) {
+                        if (sentinel == 0 and mods.addrspace_node == 0) {
                             return p.addNode(.{
                                 .tag = .ptr_type_aligned,
                                 .main_token = lbracket,
@@ -1633,7 +1668,7 @@ const Parser = struct {
                                     .rhs = elem_type,
                                 },
                             });
-                        } else if (mods.align_node == 0) {
+                        } else if (mods.align_node == 0 and mods.addrspace_node == 0) {
                             return p.addNode(.{
                                 .tag = .ptr_type_sentinel,
                                 .main_token = lbracket,
@@ -1650,6 +1685,7 @@ const Parser = struct {
                                     .lhs = try p.addExtra(Node.PtrType{
                                         .sentinel = sentinel,
                                         .align_node = mods.align_node,
+                                        .addrspace_node = mods.addrspace_node,
                                     }),
                                     .rhs = elem_type,
                                 },
@@ -1661,6 +1697,7 @@ const Parser = struct {
                             .keyword_const,
                             .keyword_volatile,
                             .keyword_allowzero,
+                            .keyword_addrspace,
                             => return p.fail(.ptr_mod_on_array_child_type),
                             else => {},
                         }
@@ -2879,6 +2916,15 @@ const Parser = struct {
         return expr_node;
     }
 
+    /// AddrSpace <- KEYWORD_addrspace LPAREN Expr RPAREN
+    fn parseAddrSpace(p: *Parser) !Node.Index {
+        _ = p.eatToken(.keyword_addrspace) orelse return null_node;
+        _ = try p.expectToken(.l_paren);
+        const expr_node = try p.expectExpr();
+        _ = try p.expectToken(.r_paren);
+        return expr_node;
+    }
+
     /// ParamDecl
     ///     <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
     ///     / DOT3
@@ -3011,6 +3057,7 @@ const Parser = struct {
 
     const PtrModifiers = struct {
         align_node: Node.Index,
+        addrspace_node: Node.Index,
         bit_range_start: Node.Index,
         bit_range_end: Node.Index,
     };
@@ -3018,12 +3065,14 @@ const Parser = struct {
     fn parsePtrModifiers(p: *Parser) !PtrModifiers {
         var result: PtrModifiers = .{
             .align_node = 0,
+            .addrspace_node = 0,
             .bit_range_start = 0,
             .bit_range_end = 0,
         };
         var saw_const = false;
         var saw_volatile = false;
         var saw_allowzero = false;
+        var saw_addrspace = false;
         while (true) {
             switch (p.token_tags[p.tok_i]) {
                 .keyword_align => {
@@ -3063,6 +3112,12 @@ const Parser = struct {
                     p.tok_i += 1;
                     saw_allowzero = true;
                 },
+                .keyword_addrspace => {
+                    if (saw_addrspace) {
+                        try p.warn(.extra_addrspace_qualifier);
+                    }
+                    result.addrspace_node = try p.parseAddrSpace();
+                },
                 else => return result,
             }
         }
lib/std/zig/tokenizer.zig
@@ -11,6 +11,7 @@ pub const Token = struct {
     };
 
     pub const keywords = std.ComptimeStringMap(Tag, .{
+        .{ "addrspace", .keyword_addrspace },
         .{ "align", .keyword_align },
         .{ "allowzero", .keyword_allowzero },
         .{ "and", .keyword_and },
@@ -132,6 +133,7 @@ pub const Token = struct {
         float_literal,
         doc_comment,
         container_doc_comment,
+        keyword_addrspace,
         keyword_align,
         keyword_allowzero,
         keyword_and,
@@ -251,6 +253,7 @@ pub const Token = struct {
                 .angle_bracket_angle_bracket_right => ">>",
                 .angle_bracket_angle_bracket_right_equal => ">>=",
                 .tilde => "~",
+                .keyword_addrspace => "addrspace",
                 .keyword_align => "align",
                 .keyword_allowzero => "allowzero",
                 .keyword_and => "and",
src/translate_c/ast.zig
@@ -2614,6 +2614,7 @@ fn renderVar(c: *Context, node: Node) !NodeIndex {
                     .type_node = type_node,
                     .align_node = align_node,
                     .section_node = section_node,
+                    .addrspace_node = 0,
                 }),
                 .rhs = init_node,
             },