diff --git a/astgen.c b/astgen.c index 7833a720c9..4dd5521c0c 100644 --- a/astgen.c +++ b/astgen.c @@ -552,6 +552,37 @@ static uint32_t firstToken(const Ast* tree, uint32_t node) { case AST_NODE_ARRAY_ACCESS: n = tree->nodes.datas[n].lhs; continue; + // Var decls: scan backwards for modifiers (Ast.zig:634-643). + case AST_NODE_GLOBAL_VAR_DECL: + case AST_NODE_LOCAL_VAR_DECL: + case AST_NODE_SIMPLE_VAR_DECL: + case AST_NODE_ALIGNED_VAR_DECL: { + uint32_t mt = tree->nodes.main_tokens[n]; + uint32_t i = mt; + while (i > 0) { + TokenizerTag tt = tree->tokens.tags[i - 1]; + if (tt == TOKEN_KEYWORD_EXTERN || tt == TOKEN_KEYWORD_EXPORT + || tt == TOKEN_KEYWORD_PUB + || tt == TOKEN_KEYWORD_THREADLOCAL + || tt == TOKEN_KEYWORD_COMPTIME + || tt == TOKEN_STRING_LITERAL) { + i--; + } else { + break; + } + } + return i; + } + // Container fields: check for preceding comptime (Ast.zig:646-648). + case AST_NODE_CONTAINER_FIELD_INIT: + case AST_NODE_CONTAINER_FIELD_ALIGN: + case AST_NODE_CONTAINER_FIELD: { + uint32_t mt = tree->nodes.main_tokens[n]; + if (mt > 0 + && tree->tokens.tags[mt - 1] == TOKEN_KEYWORD_COMPTIME) + return mt - 1; + return mt; + } // Everything else: main_token (Ast.zig:602-643). default: return tree->nodes.main_tokens[n]; @@ -890,6 +921,38 @@ static bool declIdHasName(DeclFlagsId id) { return id != DECL_ID_UNNAMED_TEST && id != DECL_ID_COMPTIME; } +// Does this Declaration.Flags.Id have a lib name? (Zir.zig:2771) +static bool declIdHasLibName(DeclFlagsId id) { + switch (id) { + case DECL_ID_EXTERN_CONST: + case DECL_ID_PUB_EXTERN_CONST: + case DECL_ID_EXTERN_VAR: + case DECL_ID_EXTERN_VAR_THREADLOCAL: + case DECL_ID_PUB_EXTERN_VAR: + case DECL_ID_PUB_EXTERN_VAR_THREADLOCAL: + return true; + default: + return false; + } +} + +// Does this Declaration.Flags.Id have a type body? (Zir.zig:2783) +static bool declIdHasTypeBody(DeclFlagsId id) { + switch (id) { + case DECL_ID_UNNAMED_TEST: + case DECL_ID_TEST: + case DECL_ID_DECLTEST: + case DECL_ID_COMPTIME: + case DECL_ID_CONST_SIMPLE: + case DECL_ID_PUB_CONST_SIMPLE: + case DECL_ID_VAR_SIMPLE: + case DECL_ID_PUB_VAR_SIMPLE: + return false; + default: + return true; + } +} + // Does this Declaration.Flags.Id have a value body? (Zir.zig:2800) static bool declIdHasValueBody(DeclFlagsId id) { switch (id) { @@ -907,20 +970,79 @@ static bool declIdHasValueBody(DeclFlagsId id) { } } -// Mirrors setDeclaration (AstGen.zig:13883). -// Simplified: no type/align/linksection/addrspace bodies. -static void setDeclaration(AstGenCtx* ag, uint32_t decl_inst, - uint32_t src_line, uint32_t src_column, DeclFlagsId id, - uint32_t name_string_index, const uint32_t* value_body, - uint32_t value_body_len) { - bool has_name = declIdHasName(id); - bool has_value_body = declIdHasValueBody(id); +// Does this Declaration.Flags.Id have special bodies? (Zir.zig:2815) +static bool declIdHasSpecialBodies(DeclFlagsId id) { + switch (id) { + case DECL_ID_UNNAMED_TEST: + case DECL_ID_TEST: + case DECL_ID_DECLTEST: + case DECL_ID_COMPTIME: + case DECL_ID_CONST_SIMPLE: + case DECL_ID_CONST_TYPED: + case DECL_ID_PUB_CONST_SIMPLE: + case DECL_ID_PUB_CONST_TYPED: + case DECL_ID_EXTERN_CONST_SIMPLE: + case DECL_ID_PUB_EXTERN_CONST_SIMPLE: + case DECL_ID_VAR_SIMPLE: + case DECL_ID_PUB_VAR_SIMPLE: + return false; + default: + return true; + } +} - uint32_t need = 6; // Declaration struct: src_hash[4] + flags[2] +// Mirrors setDeclaration (AstGen.zig:13883). +// Full version with type/align/linksection/addrspace/value bodies. +typedef struct { + uint32_t src_line; + uint32_t src_column; + DeclFlagsId id; + uint32_t name; // NullTerminatedString index + uint32_t lib_name; // NullTerminatedString index (UINT32_MAX=none) + const uint32_t* type_body; + uint32_t type_body_len; + const uint32_t* align_body; + uint32_t align_body_len; + const uint32_t* linksection_body; + uint32_t linksection_body_len; + const uint32_t* addrspace_body; + uint32_t addrspace_body_len; + const uint32_t* value_body; + uint32_t value_body_len; +} SetDeclArgs; + +static void setDeclaration(AstGenCtx* ag, uint32_t decl_inst, + SetDeclArgs args) { + DeclFlagsId id = args.id; + bool has_name = declIdHasName(id); + bool has_lib_name = declIdHasLibName(id); + bool has_type_body_field = declIdHasTypeBody(id); + bool has_special_bodies = declIdHasSpecialBodies(id); + bool has_value_body_field = declIdHasValueBody(id); + + uint32_t type_len + = countBodyLenAfterFixups(ag, args.type_body, args.type_body_len); + uint32_t align_len + = countBodyLenAfterFixups(ag, args.align_body, args.align_body_len); + uint32_t linksection_len = countBodyLenAfterFixups( + ag, args.linksection_body, args.linksection_body_len); + uint32_t addrspace_len = countBodyLenAfterFixups( + ag, args.addrspace_body, args.addrspace_body_len); + uint32_t value_len + = countBodyLenAfterFixups(ag, args.value_body, args.value_body_len); + + uint32_t need = 6; // src_hash[4] + flags[2] if (has_name) need++; - if (has_value_body) - need += 1 + value_body_len; + if (has_lib_name) + need++; + if (has_type_body_field) + need++; + if (has_special_bodies) + need += 3; + if (has_value_body_field) + need++; + need += type_len + align_len + linksection_len + addrspace_len + value_len; ensureExtraCapacity(ag, need); uint32_t payload_start = ag->extra_len; @@ -934,24 +1056,39 @@ static void setDeclaration(AstGenCtx* ag, uint32_t decl_inst, // Declaration.Flags: packed struct(u64) { src_line: u30, src_column: u29, // id: u5 } (Zir.zig:2719) uint64_t flags = 0; - flags |= (uint64_t)(src_line & 0x3FFFFFFFu); - flags |= (uint64_t)(src_column & 0x1FFFFFFFu) << 30; + flags |= (uint64_t)(args.src_line & 0x3FFFFFFFu); + flags |= (uint64_t)(args.src_column & 0x1FFFFFFFu) << 30; flags |= (uint64_t)((uint32_t)id & 0x1Fu) << 59; ag->extra[ag->extra_len++] = (uint32_t)(flags & 0xFFFFFFFFu); ag->extra[ag->extra_len++] = (uint32_t)(flags >> 32); - if (has_name) { - ag->extra[ag->extra_len++] = name_string_index; + if (has_name) + ag->extra[ag->extra_len++] = args.name; + if (has_lib_name) { + ag->extra[ag->extra_len++] + = (args.lib_name != UINT32_MAX) ? args.lib_name : 0; } - - if (has_value_body) { - ag->extra[ag->extra_len++] = value_body_len; - for (uint32_t i = 0; i < value_body_len; i++) { - ag->extra[ag->extra_len++] = value_body[i]; - } + if (has_type_body_field) + ag->extra[ag->extra_len++] = type_len; + if (has_special_bodies) { + ag->extra[ag->extra_len++] = align_len; + ag->extra[ag->extra_len++] = linksection_len; + ag->extra[ag->extra_len++] = addrspace_len; } + if (has_value_body_field) + ag->extra[ag->extra_len++] = value_len; + + for (uint32_t i = 0; i < args.type_body_len; i++) + appendPossiblyRefdBodyInst(ag, args.type_body[i]); + for (uint32_t i = 0; i < args.align_body_len; i++) + appendPossiblyRefdBodyInst(ag, args.align_body[i]); + for (uint32_t i = 0; i < args.linksection_body_len; i++) + appendPossiblyRefdBodyInst(ag, args.linksection_body[i]); + for (uint32_t i = 0; i < args.addrspace_body_len; i++) + appendPossiblyRefdBodyInst(ag, args.addrspace_body[i]); + for (uint32_t i = 0; i < args.value_body_len; i++) + appendPossiblyRefdBodyInst(ag, args.value_body[i]); - // Set the declaration instruction's payload_index. ag->inst_datas[decl_inst].declaration.payload_index = payload_start; } @@ -6673,8 +6810,11 @@ static void testDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, makeBreakInline(&decl_block, decl_inst, func_ref, AST_NODE_OFFSET_NONE); // setDeclaration (AstGen.zig:4903-4923). - setDeclaration(ag, decl_inst, decl_line, decl_column, decl_id, test_name, - gzInstructionsSlice(&decl_block), gzInstructionsLen(&decl_block)); + setDeclaration(ag, decl_inst, + (SetDeclArgs) { .src_line = decl_line, .src_column = decl_column, + .id = decl_id, .name = test_name, .lib_name = UINT32_MAX, + .value_body = gzInstructionsSlice(&decl_block), + .value_body_len = gzInstructionsLen(&decl_block) }); gzUnstack(&decl_block); (void)gz; @@ -7037,8 +7177,11 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, DeclFlagsId decl_id = is_pub ? DECL_ID_PUB_CONST_SIMPLE : DECL_ID_CONST_SIMPLE; uint32_t name_str = identAsString(ag, fn_name_token); - setDeclaration(ag, decl_inst, decl_line, decl_column, decl_id, name_str, - gzInstructionsSlice(&decl_gz), gzInstructionsLen(&decl_gz)); + setDeclaration(ag, decl_inst, + (SetDeclArgs) { .src_line = decl_line, .src_column = decl_column, + .id = decl_id, .name = name_str, .lib_name = UINT32_MAX, + .value_body = gzInstructionsSlice(&decl_gz), + .value_body_len = gzInstructionsLen(&decl_gz) }); gzUnstack(&decl_gz); (void)gz; @@ -7075,8 +7218,11 @@ static void comptimeDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, makeBreakInline( &value_gz, decl_inst, ZIR_REF_VOID_VALUE, AST_NODE_OFFSET_NONE); - setDeclaration(ag, decl_inst, decl_line, decl_column, DECL_ID_COMPTIME, 0, - gzInstructionsSlice(&value_gz), gzInstructionsLen(&value_gz)); + setDeclaration(ag, decl_inst, + (SetDeclArgs) { .src_line = decl_line, .src_column = decl_column, + .id = DECL_ID_COMPTIME, .name = 0, .lib_name = UINT32_MAX, + .value_body = gzInstructionsSlice(&value_gz), + .value_body_len = gzInstructionsLen(&value_gz) }); gzUnstack(&value_gz); (void)gz; @@ -7084,10 +7230,158 @@ static void comptimeDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, // --- globalVarDecl (AstGen.zig:4498) --- +// Extract VarDecl fields from an AST node (Ast.zig:1326-1380). +typedef struct { + uint32_t mut_token; + uint32_t type_node; // 0 = none + uint32_t align_node; // 0 = none + uint32_t addrspace_node; // 0 = none + uint32_t section_node; // 0 = none + uint32_t init_node; // UINT32_MAX = none + bool is_pub; + bool is_extern; + bool is_export; + bool is_mutable; + bool is_threadlocal; + uint32_t lib_name_token; // UINT32_MAX = none +} VarDeclInfo; + +static VarDeclInfo extractVarDecl(const Ast* tree, uint32_t node) { + AstNodeTag tag = tree->nodes.tags[node]; + AstData nd = tree->nodes.datas[node]; + uint32_t mut_token = tree->nodes.main_tokens[node]; + VarDeclInfo info; + memset(&info, 0, sizeof(info)); + info.mut_token = mut_token; + info.init_node = UINT32_MAX; + info.lib_name_token = UINT32_MAX; + + switch (tag) { + case AST_NODE_SIMPLE_VAR_DECL: + // lhs = type_node (optional), rhs = init_node (optional) + info.type_node = nd.lhs; + info.init_node = nd.rhs; + break; + case AST_NODE_ALIGNED_VAR_DECL: + // lhs = align_node, rhs = init_node (optional) + info.align_node = nd.lhs; + info.init_node = nd.rhs; + break; + case AST_NODE_GLOBAL_VAR_DECL: { + // lhs = extra_data index, rhs = init_node (optional) + uint32_t ei = nd.lhs; + info.type_node = tree->extra_data.arr[ei + 0]; + info.align_node = tree->extra_data.arr[ei + 1]; + info.addrspace_node = tree->extra_data.arr[ei + 2]; + info.section_node = tree->extra_data.arr[ei + 3]; + info.init_node = nd.rhs; + break; + } + case AST_NODE_LOCAL_VAR_DECL: { + // lhs = extra_data index, rhs = init_node (optional) + uint32_t ei = nd.lhs; + info.type_node = tree->extra_data.arr[ei + 0]; + info.align_node = tree->extra_data.arr[ei + 1]; + info.init_node = nd.rhs; + break; + } + default: + break; + } + + // Scan backwards from mut_token to find modifiers (Ast.zig:2003-2025). + info.is_mutable + = (tree->tokens.tags[mut_token] == TOKEN_KEYWORD_VAR); + for (uint32_t i = mut_token; i > 0;) { + i--; + TokenizerTag ttag = tree->tokens.tags[i]; + if (ttag == TOKEN_KEYWORD_EXTERN) + info.is_extern = true; + else if (ttag == TOKEN_KEYWORD_EXPORT) + info.is_export = true; + else if (ttag == TOKEN_KEYWORD_PUB) + info.is_pub = true; + else if (ttag == TOKEN_KEYWORD_THREADLOCAL) + info.is_threadlocal = true; + else if (ttag == TOKEN_STRING_LITERAL) + info.lib_name_token = i; + else + break; + } + return info; +} + +// Compute DeclFlagsId from VarDecl properties (AstGen.zig:13916-13972). +static DeclFlagsId computeVarDeclId(bool is_mutable, bool is_pub, + bool is_extern, bool is_export, bool is_threadlocal, bool has_type_body, + bool has_special_body, bool has_lib_name) { + if (!is_mutable) { + // const + if (is_extern) { + if (is_pub) { + if (has_lib_name || has_special_body) + return DECL_ID_PUB_EXTERN_CONST; + return DECL_ID_PUB_EXTERN_CONST_SIMPLE; + } + if (has_lib_name || has_special_body) + return DECL_ID_EXTERN_CONST; + return DECL_ID_EXTERN_CONST_SIMPLE; + } + if (is_export) + return is_pub ? DECL_ID_PUB_EXPORT_CONST : DECL_ID_EXPORT_CONST; + if (is_pub) { + if (has_special_body) + return DECL_ID_PUB_CONST; + if (has_type_body) + return DECL_ID_PUB_CONST_TYPED; + return DECL_ID_PUB_CONST_SIMPLE; + } + if (has_special_body) + return DECL_ID_CONST; + if (has_type_body) + return DECL_ID_CONST_TYPED; + return DECL_ID_CONST_SIMPLE; + } + // var + if (is_extern) { + if (is_pub) { + if (is_threadlocal) + return DECL_ID_PUB_EXTERN_VAR_THREADLOCAL; + return DECL_ID_PUB_EXTERN_VAR; + } + if (is_threadlocal) + return DECL_ID_EXTERN_VAR_THREADLOCAL; + return DECL_ID_EXTERN_VAR; + } + if (is_export) { + if (is_pub) { + if (is_threadlocal) + return DECL_ID_PUB_EXPORT_VAR_THREADLOCAL; + return DECL_ID_PUB_EXPORT_VAR; + } + if (is_threadlocal) + return DECL_ID_EXPORT_VAR_THREADLOCAL; + return DECL_ID_EXPORT_VAR; + } + if (is_pub) { + if (is_threadlocal) + return DECL_ID_PUB_VAR_THREADLOCAL; + if (has_special_body || has_type_body) + return DECL_ID_PUB_VAR; + return DECL_ID_PUB_VAR_SIMPLE; + } + if (is_threadlocal) + return DECL_ID_VAR_THREADLOCAL; + if (has_special_body || has_type_body) + return DECL_ID_VAR; + return DECL_ID_VAR_SIMPLE; +} + static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, uint32_t* decl_idx, uint32_t node) { - uint32_t mut_token = ag->tree->nodes.main_tokens[node]; - uint32_t name_token = mut_token + 1; + const Ast* tree = ag->tree; + VarDeclInfo vd = extractVarDecl(tree, node); + uint32_t name_token = vd.mut_token + 1; // advanceSourceCursorToNode before makeDeclaration (AstGen.zig:4542-4546). advanceSourceCursorToNode(ag, node); @@ -7097,42 +7391,135 @@ static void globalVarDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts, wip_decl_insts[*decl_idx] = decl_inst; (*decl_idx)++; - // Set up init sub-block (AstGen.zig:4610). - GenZir init_gz; - memset(&init_gz, 0, sizeof(init_gz)); - init_gz.base.tag = SCOPE_GEN_ZIR; - init_gz.parent = NULL; - init_gz.astgen = ag; - init_gz.decl_node_index = node; - init_gz.instructions_top = ag->scratch_inst_len; - init_gz.decl_line = ag->source_line; - init_gz.is_comptime = true; + // Set up type sub-block (AstGen.zig:4574-4582). + GenZir type_gz; + memset(&type_gz, 0, sizeof(type_gz)); + type_gz.base.tag = SCOPE_GEN_ZIR; + type_gz.astgen = ag; + type_gz.decl_node_index = node; + type_gz.instructions_top = ag->scratch_inst_len; + type_gz.decl_line = ag->source_line; + type_gz.is_comptime = true; - // Evaluate init expression. - // For simple_var_decl: data.rhs = init_node (optional). - AstData data = ag->tree->nodes.datas[node]; - uint32_t init_node = data.rhs; - uint32_t init_ref; - - if (init_node != UINT32_MAX) { - init_ref = expr(&init_gz, &init_gz.base, init_node); - } else { - // extern variable: no init. Not handled yet. - SET_ERROR(ag); - init_ref = ZIR_REF_VOID_VALUE; + if (vd.type_node != 0) { + uint32_t type_inst = typeExpr(&type_gz, &type_gz.base, vd.type_node); + makeBreakInline(&type_gz, decl_inst, type_inst, 0); } - // addBreakWithSrcNode(.break_inline, decl_inst, init_inst, node) - // nodeIndexToRelative: decl_node_index == node, so offset = 0. - // (AstGen.zig:4620) - makeBreakInline(&init_gz, decl_inst, init_ref, 0); + // Record type_gz boundary for slicing. + uint32_t type_top = ag->scratch_inst_len; + + // Align sub-block (AstGen.zig:4592-4596). + GenZir align_gz; + memset(&align_gz, 0, sizeof(align_gz)); + align_gz.base.tag = SCOPE_GEN_ZIR; + align_gz.astgen = ag; + align_gz.decl_node_index = node; + align_gz.instructions_top = type_top; + align_gz.decl_line = ag->source_line; + align_gz.is_comptime = true; + + if (vd.align_node != 0) { + uint32_t align_inst + = expr(&align_gz, &align_gz.base, vd.align_node); + makeBreakInline(&align_gz, decl_inst, align_inst, 0); + } + + uint32_t align_top = ag->scratch_inst_len; + + // Linksection sub-block (AstGen.zig:4598-4602). + GenZir linksection_gz; + memset(&linksection_gz, 0, sizeof(linksection_gz)); + linksection_gz.base.tag = SCOPE_GEN_ZIR; + linksection_gz.astgen = ag; + linksection_gz.decl_node_index = node; + linksection_gz.instructions_top = align_top; + linksection_gz.decl_line = ag->source_line; + linksection_gz.is_comptime = true; + + if (vd.section_node != 0) { + uint32_t ls_inst + = expr(&linksection_gz, &linksection_gz.base, vd.section_node); + makeBreakInline(&linksection_gz, decl_inst, ls_inst, 0); + } + + uint32_t linksection_top = ag->scratch_inst_len; + + // Addrspace sub-block (AstGen.zig:4604-4608). + GenZir addrspace_gz; + memset(&addrspace_gz, 0, sizeof(addrspace_gz)); + addrspace_gz.base.tag = SCOPE_GEN_ZIR; + addrspace_gz.astgen = ag; + addrspace_gz.decl_node_index = node; + addrspace_gz.instructions_top = linksection_top; + addrspace_gz.decl_line = ag->source_line; + addrspace_gz.is_comptime = true; + + if (vd.addrspace_node != 0) { + uint32_t as_inst + = expr(&addrspace_gz, &addrspace_gz.base, vd.addrspace_node); + makeBreakInline(&addrspace_gz, decl_inst, as_inst, 0); + } + + uint32_t addrspace_top = ag->scratch_inst_len; + + // Value sub-block (AstGen.zig:4610-4620). + GenZir value_gz; + memset(&value_gz, 0, sizeof(value_gz)); + value_gz.base.tag = SCOPE_GEN_ZIR; + value_gz.astgen = ag; + value_gz.decl_node_index = node; + value_gz.instructions_top = addrspace_top; + value_gz.decl_line = ag->source_line; + value_gz.is_comptime = true; + + if (vd.init_node != UINT32_MAX && vd.init_node != 0) { + uint32_t init_ref = expr(&value_gz, &value_gz.base, vd.init_node); + makeBreakInline(&value_gz, decl_inst, init_ref, 0); + } + + // Compute body slices (instructionsSliceUpto). + const uint32_t* type_body = ag->scratch_instructions + type_gz.instructions_top; + uint32_t type_body_len = type_top - type_gz.instructions_top; + const uint32_t* align_body = ag->scratch_instructions + align_gz.instructions_top; + uint32_t align_body_len = align_top - align_gz.instructions_top; + const uint32_t* ls_body = ag->scratch_instructions + linksection_gz.instructions_top; + uint32_t ls_body_len = linksection_top - linksection_gz.instructions_top; + const uint32_t* as_body = ag->scratch_instructions + addrspace_gz.instructions_top; + uint32_t as_body_len = addrspace_top - addrspace_gz.instructions_top; + const uint32_t* val_body = gzInstructionsSlice(&value_gz); + uint32_t val_body_len = gzInstructionsLen(&value_gz); + + bool has_type_body = (type_body_len > 0); + bool has_special_body + = (align_body_len > 0 || ls_body_len > 0 || as_body_len > 0); + bool has_lib_name = (vd.lib_name_token != UINT32_MAX); uint32_t name_str = identAsString(ag, name_token); - setDeclaration(ag, decl_inst, ag->source_line, decl_column, - DECL_ID_CONST_SIMPLE, name_str, gzInstructionsSlice(&init_gz), - gzInstructionsLen(&init_gz)); - gzUnstack(&init_gz); + DeclFlagsId decl_id = computeVarDeclId(vd.is_mutable, vd.is_pub, + vd.is_extern, vd.is_export, vd.is_threadlocal, has_type_body, + has_special_body, has_lib_name); + + // Compute lib_name string index. + uint32_t lib_name = UINT32_MAX; + if (has_lib_name) { + uint32_t li, ll; + strLitAsString(ag, vd.lib_name_token, &li, &ll); + lib_name = li; + } + + setDeclaration(ag, decl_inst, + (SetDeclArgs) { .src_line = ag->source_line, + .src_column = decl_column, .id = decl_id, .name = name_str, + .lib_name = lib_name, .type_body = type_body, + .type_body_len = type_body_len, .align_body = align_body, + .align_body_len = align_body_len, .linksection_body = ls_body, + .linksection_body_len = ls_body_len, .addrspace_body = as_body, + .addrspace_body_len = as_body_len, .value_body = val_body, + .value_body_len = val_body_len }); + + gzUnstack(&value_gz); (void)gz; } diff --git a/astgen_test.zig b/astgen_test.zig index 93213dfb3b..c810baee4d 100644 --- a/astgen_test.zig +++ b/astgen_test.zig @@ -934,6 +934,18 @@ test "astgen: error set with members" { try expectEqualZir(gpa, ref_zir, c_zir); } +test "astgen: extern var" { + const gpa = std.testing.allocator; + const source: [:0]const u8 = "extern var x: u32;"; + var ref_zir = try refZir(gpa, source); + defer ref_zir.deinit(gpa); + var c_ast = c.astParse(source.ptr, @intCast(source.len)); + defer c.astDeinit(&c_ast); + var c_zir = c.astGen(&c_ast); + defer c.zirDeinit(&c_zir); + try expectEqualZir(gpa, ref_zir, c_zir); +} + test "astgen: corpus test_all.zig" { const gpa = std.testing.allocator; try corpusCheck(gpa, "test_all.zig", @embedFile("test_all.zig"));