diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig index 0b98fcf2b92d6b3f80e187f54f8060343fd8e24e..6a6bd0ed217906f84cebe87c1d063fbf4f2d2db8 100644 --- a/lib/std/zig/AstGen.zig +++ b/lib/std/zig/AstGen.zig @@ -3135,6 +3135,11 @@ fn varDecl( return astgen.failTok(tree.nodeMainToken(section_node), "cannot set section of local variable '{s}'", .{ident_name_raw}); } + const type_inst: Zir.Inst.Ref = if (var_decl.ast.type_node.unwrap()) |type_node| + try typeExpr(gz, scope, type_node) + else + .none; + const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node.unwrap()) |align_node| try comptimeExpr(gz, scope, coerced_align_ri, align_node, .@"align") else @@ -3155,8 +3160,8 @@ fn varDecl( if (align_inst == .none and !astgen.nodes_need_rl.contains(node)) { - const result_info: ResultInfo = if (var_decl.ast.type_node.unwrap()) |type_node| .{ - .rl = .{ .ty = try typeExpr(gz, scope, type_node) }, + const result_info: ResultInfo = if (type_inst != .none) .{ + .rl = .{ .ty = type_inst }, .ctx = .const_init, } else .{ .rl = .none, .ctx = .const_init }; const init_inst: Zir.Inst.Ref = try nameStratExpr(gz, scope, result_info, init_node, .dbg_var) orelse @@ -3185,8 +3190,7 @@ fn varDecl( const is_comptime = gz.is_comptime or tree.nodeTag(init_node) == .@"comptime"; - const init_rl: ResultInfo.Loc = if (var_decl.ast.type_node.unwrap()) |type_node| init_rl: { - const type_inst = try typeExpr(gz, scope, type_node); + const init_rl: ResultInfo.Loc = if (type_inst != .none) init_rl: { if (align_inst == .none) { break :init_rl .{ .ptr = .{ .inst = try gz.addUnNode(.alloc, type_inst, node) } }; } else { @@ -3254,8 +3258,7 @@ fn varDecl( if (var_decl.comptime_token != null and gz.is_comptime) return astgen.failTok(var_decl.comptime_token.?, "'comptime var' is redundant in comptime scope", .{}); const is_comptime = var_decl.comptime_token != null or gz.is_comptime; - const alloc: Zir.Inst.Ref, const resolve_inferred: bool, const result_info: ResultInfo = if (var_decl.ast.type_node.unwrap()) |type_node| a: { - const type_inst = try typeExpr(gz, scope, type_node); + const alloc: Zir.Inst.Ref, const resolve_inferred: bool, const result_info: ResultInfo = if (type_inst != .none) a: { const alloc = alloc: { if (align_inst == .none) { const tag: Zir.Inst.Tag = if (is_comptime) @@ -3482,14 +3485,18 @@ fn assignDestructureMaybeDecls( // We also mark `const`s as comptime if the RHS is definitely comptime-known. const this_variable_comptime = is_comptime or (is_const and value_is_comptime); + const type_inst = if (full_var_decl.ast.type_node.unwrap()) |type_node| + try typeExpr(gz, scope, type_node) + else + .none; + const align_inst: Zir.Inst.Ref = if (full_var_decl.ast.align_node.unwrap()) |align_node| try comptimeExpr(gz, scope, coerced_align_ri, align_node, .@"align") else .none; - if (full_var_decl.ast.type_node.unwrap()) |type_node| { + if (type_inst != .none) { // Typed alloc - const type_inst = try typeExpr(gz, scope, type_node); const ptr = if (align_inst == .none) ptr: { const tag: Zir.Inst.Tag = if (this_variable_comptime) .alloc_comptime_mut @@ -4061,43 +4068,41 @@ fn fnDecl( // We include a function *type*, not a value. const type_inst = try fnProtoExprInner(&type_gz, &type_gz.base, .{ .rl = .none }, decl_node, fn_proto, true); _ = try type_gz.addBreakWithSrcNode(.break_inline, decl_inst, type_inst, decl_node); + astgen.restoreSourceCursor(saved_cursor); } var align_gz = type_gz.makeSubBlock(scope); defer align_gz.unstack(); if (fn_proto.ast.align_expr.unwrap()) |align_expr| { - astgen.restoreSourceCursor(saved_cursor); const inst = try expr(&align_gz, &align_gz.base, coerced_align_ri, align_expr); _ = try align_gz.addBreakWithSrcNode(.break_inline, decl_inst, inst, decl_node); } - var linksection_gz = align_gz.makeSubBlock(scope); - defer linksection_gz.unstack(); - - if (fn_proto.ast.section_expr.unwrap()) |section_expr| { - astgen.restoreSourceCursor(saved_cursor); - const inst = try expr(&linksection_gz, &linksection_gz.base, coerced_linksection_ri, section_expr); - _ = try linksection_gz.addBreakWithSrcNode(.break_inline, decl_inst, inst, decl_node); - } - - var addrspace_gz = linksection_gz.makeSubBlock(scope); + var addrspace_gz = align_gz.makeSubBlock(scope); defer addrspace_gz.unstack(); if (fn_proto.ast.addrspace_expr.unwrap()) |addrspace_expr| { - astgen.restoreSourceCursor(saved_cursor); const addrspace_ty = try addrspace_gz.addStdLangValue(addrspace_expr, .address_space); const inst = try expr(&addrspace_gz, &addrspace_gz.base, .{ .rl = .{ .coerced_ty = addrspace_ty } }, addrspace_expr); _ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, inst, decl_node); } - var value_gz = addrspace_gz.makeSubBlock(scope); + var linksection_gz = addrspace_gz.makeSubBlock(scope); + defer linksection_gz.unstack(); + + if (fn_proto.ast.section_expr.unwrap()) |section_expr| { + const inst = try expr(&linksection_gz, &linksection_gz.base, coerced_linksection_ri, section_expr); + _ = try linksection_gz.addBreakWithSrcNode(.break_inline, decl_inst, inst, decl_node); + } + + var value_gz = linksection_gz.makeSubBlock(scope); defer value_gz.unstack(); if (!is_extern) { // We include a function *value*, not a type. astgen.restoreSourceCursor(saved_cursor); - try astgen.fnDeclInner(&value_gz, &value_gz.base, saved_cursor, decl_inst, decl_node, body_node.unwrap().?, fn_proto); + try astgen.fnDeclInner(&value_gz, &value_gz.base, decl_inst, decl_node, body_node.unwrap().?, fn_proto); } // *Now* we can incorporate the full source code into the hasher. @@ -4119,8 +4124,8 @@ fn fnDecl( .type_gz = &type_gz, .align_gz = &align_gz, - .linksection_gz = &linksection_gz, .addrspace_gz = &addrspace_gz, + .linksection_gz = &linksection_gz, .value_gz = &value_gz, }); } @@ -4129,7 +4134,6 @@ fn fnDeclInner( astgen: *AstGen, decl_gz: *GenZir, scope: *Scope, - saved_cursor: SourceCursor, decl_inst: Zir.Inst.Index, decl_node: Ast.Node.Index, body_node: Ast.Node.Index, @@ -4266,6 +4270,31 @@ fn fnDeclInner( // instructions inside the expression blocks for cc and ret_ty to use the function // instruction as the body to break from. + var cc_gz = decl_gz.makeSubBlock(scope); + defer cc_gz.unstack(); + const cc_ref: Zir.Inst.Ref = blk: { + if (fn_proto.ast.callconv_expr.unwrap()) |callconv_expr| { + const inst = try expr( + &cc_gz, + scope, + .{ .rl = .{ .coerced_ty = try cc_gz.addStdLangValue(callconv_expr, .calling_convention) } }, + callconv_expr, + ); + if (cc_gz.instructionsSlice().len == 0) { + // In this case we will send a len=0 body which can be encoded more efficiently. + break :blk inst; + } + _ = try cc_gz.addBreak(.break_inline, @fromBackingInt(@intCast(0)), inst); + break :blk inst; + } else if (has_inline_keyword) { + const inst = try cc_gz.addStdLangValue(decl_node, .calling_convention_inline); + _ = try cc_gz.addBreak(.break_inline, @fromBackingInt(@intCast(0)), inst); + break :blk inst; + } else { + break :blk .none; + } + }; + var ret_gz = decl_gz.makeSubBlock(params_scope); defer ret_gz.unstack(); any_param_used = false; // we will check this later @@ -4284,34 +4313,6 @@ fn fnDeclInner( const ret_body_param_refs = try astgen.fetchRemoveRefEntries(param_insts.items); const ret_ty_is_generic = any_param_used; - // We're jumping back in source, so restore the cursor. - astgen.restoreSourceCursor(saved_cursor); - - var cc_gz = decl_gz.makeSubBlock(scope); - defer cc_gz.unstack(); - const cc_ref: Zir.Inst.Ref = blk: { - if (fn_proto.ast.callconv_expr.unwrap()) |callconv_expr| { - const inst = try expr( - &cc_gz, - scope, - .{ .rl = .{ .coerced_ty = try cc_gz.addStdLangValue(callconv_expr, .calling_convention) } }, - callconv_expr, - ); - if (cc_gz.instructionsSlice().len == 0) { - // In this case we will send a len=0 body which can be encoded more efficiently. - break :blk inst; - } - _ = try cc_gz.addBreak(.break_inline, @fromBackingInt(@intCast(0)), inst); - break :blk inst; - } else if (has_inline_keyword) { - const inst = try cc_gz.addStdLangValue(decl_node, .calling_convention_inline); - _ = try cc_gz.addBreak(.break_inline, @fromBackingInt(@intCast(0)), inst); - break :blk inst; - } else { - break :blk .none; - } - }; - var body_gz: GenZir = .{ .is_comptime = false, .src_baseline = fn_proto.ast.proto_node, @@ -4490,14 +4491,6 @@ fn globalVarDecl( _ = try align_gz.addBreakWithSrcNode(.break_inline, decl_inst, align_inst, node); } - var linksection_gz = type_gz.makeSubBlock(scope); - defer linksection_gz.unstack(); - - if (var_decl.ast.section_node.unwrap()) |section_node| { - const linksection_inst = try expr(&linksection_gz, &linksection_gz.base, coerced_linksection_ri, section_node); - _ = try linksection_gz.addBreakWithSrcNode(.break_inline, decl_inst, linksection_inst, node); - } - var addrspace_gz = type_gz.makeSubBlock(scope); defer addrspace_gz.unstack(); @@ -4507,6 +4500,14 @@ fn globalVarDecl( _ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, addrspace_inst, node); } + var linksection_gz = type_gz.makeSubBlock(scope); + defer linksection_gz.unstack(); + + if (var_decl.ast.section_node.unwrap()) |section_node| { + const linksection_inst = try expr(&linksection_gz, &linksection_gz.base, coerced_linksection_ri, section_node); + _ = try linksection_gz.addBreakWithSrcNode(.break_inline, decl_inst, linksection_inst, node); + } + var init_gz = type_gz.makeSubBlock(scope); defer init_gz.unstack(); @@ -4536,8 +4537,8 @@ fn globalVarDecl( .type_gz = &type_gz, .align_gz = &align_gz, - .linksection_gz = &linksection_gz, .addrspace_gz = &addrspace_gz, + .linksection_gz = &linksection_gz, .value_gz = &init_gz, }); } @@ -4599,8 +4600,8 @@ fn comptimeDecl( .linkage = .normal, .type_gz = &dummy_gz, .align_gz = &dummy_gz, - .linksection_gz = &dummy_gz, .addrspace_gz = &dummy_gz, + .linksection_gz = &dummy_gz, .value_gz = &comptime_gz, }); } @@ -11527,8 +11528,8 @@ const GenZir = struct { /// Must be called with the following stack set up: /// * gz (bottom) - /// * ret_gz /// * cc_gz + /// * ret_gz /// * body_gz (top) /// Unstacks all of those except for `gz`. fn addFunc( @@ -11575,16 +11576,16 @@ const GenZir = struct { stacked_gz = body_gz; break :body body; } else &.{}; - const cc_body: []const Zir.Inst.Index = if (args.cc_gz) |cc_gz| body: { - const cc_body = cc_gz.instructionsSliceUptoOpt(stacked_gz); - stacked_gz = cc_gz; - break :body cc_body; - } else &.{}; const ret_body: []const Zir.Inst.Index = if (args.ret_gz) |ret_gz| body: { const ret_body = ret_gz.instructionsSliceUptoOpt(stacked_gz); stacked_gz = ret_gz; break :body ret_body; } else &.{}; + const cc_body: []const Zir.Inst.Index = if (args.cc_gz) |cc_gz| body: { + const cc_body = cc_gz.instructionsSliceUptoOpt(stacked_gz); + stacked_gz = cc_gz; + break :body cc_body; + } else &.{}; break :bodies .{ body, cc_body, ret_body }; }; @@ -11725,8 +11726,8 @@ const GenZir = struct { // Order is important when unstacking. if (args.body_gz) |body_gz| body_gz.unstack(); - if (args.cc_gz) |cc_gz| cc_gz.unstack(); if (args.ret_gz) |ret_gz| ret_gz.unstack(); + if (args.cc_gz) |cc_gz| cc_gz.unstack(); astgen.instructions.appendAssumeCapacity(.{ .tag = tag, @@ -13502,10 +13503,10 @@ fn setDeclaration( /// Must be stacked on `type_gz`. align_gz: *GenZir, /// Must be stacked on `align_gz`. - linksection_gz: *GenZir, - /// Must be stacked on `linksection_gz`. addrspace_gz: *GenZir, - /// Must be stacked on `addrspace_gz` and have nothing stacked on top of it. + /// Must be stacked on `addrspace_gz`. + linksection_gz: *GenZir, + /// Must be stacked on `linksection_gz` and have nothing stacked on top of it. value_gz: *GenZir, }, ) !void { @@ -13513,9 +13514,9 @@ fn setDeclaration( const gpa = astgen.gpa; const type_body = args.type_gz.instructionsSliceUpto(args.align_gz); - const align_body = args.align_gz.instructionsSliceUpto(args.linksection_gz); - const linksection_body = args.linksection_gz.instructionsSliceUpto(args.addrspace_gz); - const addrspace_body = args.addrspace_gz.instructionsSliceUpto(args.value_gz); + const align_body = args.align_gz.instructionsSliceUpto(args.addrspace_gz); + const addrspace_body = args.addrspace_gz.instructionsSliceUpto(args.linksection_gz); + const linksection_body = args.linksection_gz.instructionsSliceUpto(args.value_gz); const value_body = args.value_gz.instructionsSlice(); const has_name = args.name != .empty; diff --git a/test/cases/decl_qualifier_cursor.zig b/test/cases/decl_qualifier_cursor.zig new file mode 100644 index 0000000000000000000000000000000000000000..c4add0b6f11aad4253f89d49253bb9187542d3ca --- /dev/null +++ b/test/cases/decl_qualifier_cursor.zig @@ -0,0 +1,45 @@ +const lang = @import("std").lang; + +fn al() comptime_int { + return 16; +} + +fn as() lang.AddressSpace { + return .generic; +} + +fn ls() []const u8 { + return "text"; +} + +fn cc() lang.CallingConvention { + return .c; +} + +fn rv() type { + return void; +} + +extern var a: u64 align(al()) addrspace(as()) linksection(ls()); +extern fn b() align(al()) addrspace(as()) linksection(ls()) callconv(cc()) rv(); +// Intentionally not `export` so it is never analyzed since the qualifiers are +// not valid for all targets. The main point of this test is checking that Zir +// generation is done correctly for these, so the above is not an issue. +fn c() align(al()) addrspace(as()) linksection(ls()) callconv(cc()) rv() { + const v: struct { + x: u32, + y: u32, + } align(al()) = undefined; + const ta: u64, const tb: struct { + x: u32, + y: u32, + } align(al()) = .{ 0, .{ .x = 10, .y = 20 } }; + _ = v; + _ = a; + _ = b; + _ = ta; + _ = tb; +} + +// compile +// output_mode=Obj