authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-05-29 05:07:17+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-05-29 23:06:08+01:00
log4976b58ab16069f8d3267b69ed030f29685c1abe
tree400f632d11eec4f3c330bee15d59f8fd6219c20f
parentb5fad3a40a86eb379903d6a803bdbe66dcaa5487
signature Commit is signed but in an unrecognized format.

Prevent analysis of functions only referenced at comptime

The idea here is that there are two ways we can reference a function at runtime: * Through a direct call, i.e. where the function is comptime-known * Through a function pointer This means we can easily perform a form of rudimentary escape analysis on functions. If we ever see a `decl_ref` or `ref` of a function, we have a function pointer, which could "leak" into runtime code, so we emit the function; but for a plain `decl_val`, there's no need to. This change means that `comptime { _ = f; }` no longer forces a function to be emitted, which was used for some things (mainly tests). These use sites have been replaced with `_ = &f;`, which still triggers analysis of the function body, since you're taking a pointer to the function. Resolves: #6256 Resolves: #15353

33 files changed, 149 insertions(+), 65 deletions(-)

lib/compiler_rt/clear_cache.zig+1-1
...@@ -12,7 +12,7 @@ pub const panic = @import("common.zig").panic;...@@ -12,7 +12,7 @@ pub const panic = @import("common.zig").panic;
12// specified range.12// specified range.
1313
14comptime {14comptime {
15 _ = clear_cache;15 _ = &clear_cache;
16}16}
1717
18fn clear_cache(start: usize, end: usize) callconv(.C) void {18fn clear_cache(start: usize, end: usize) callconv(.C) void {
lib/std/fmt.zig+1-1
...@@ -1959,7 +1959,7 @@ pub const parseFloat = @import("fmt/parse_float.zig").parseFloat;...@@ -1959,7 +1959,7 @@ pub const parseFloat = @import("fmt/parse_float.zig").parseFloat;
1959pub const ParseFloatError = @import("fmt/parse_float.zig").ParseFloatError;1959pub const ParseFloatError = @import("fmt/parse_float.zig").ParseFloatError;
19601960
1961test {1961test {
1962 _ = parseFloat;1962 _ = &parseFloat;
1963}1963}
19641964
1965pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {1965pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
lib/std/fs.zig+5-5
...@@ -3150,12 +3150,12 @@ fn copy_file(fd_in: os.fd_t, fd_out: os.fd_t, maybe_size: ?u64) CopyFileRawError...@@ -3150,12 +3150,12 @@ fn copy_file(fd_in: os.fd_t, fd_out: os.fd_t, maybe_size: ?u64) CopyFileRawError
31503150
3151test {3151test {
3152 if (builtin.os.tag != .wasi) {3152 if (builtin.os.tag != .wasi) {
3153 _ = makeDirAbsolute;3153 _ = &makeDirAbsolute;
3154 _ = makeDirAbsoluteZ;3154 _ = &makeDirAbsoluteZ;
3155 _ = copyFileAbsolute;3155 _ = &copyFileAbsolute;
3156 _ = updateFileAbsolute;3156 _ = &updateFileAbsolute;
3157 }3157 }
3158 _ = Dir.copyFile;3158 _ = &Dir.copyFile;
3159 _ = @import("fs/test.zig");3159 _ = @import("fs/test.zig");
3160 _ = @import("fs/path.zig");3160 _ = @import("fs/path.zig");
3161 _ = @import("fs/file.zig");3161 _ = @import("fs/file.zig");
lib/std/hash_map.zig+1-1
...@@ -1605,7 +1605,7 @@ pub fn HashMapUnmanaged(...@@ -1605,7 +1605,7 @@ pub fn HashMapUnmanaged(
16051605
1606 comptime {1606 comptime {
1607 if (builtin.mode == .Debug) {1607 if (builtin.mode == .Debug) {
1608 _ = dbHelper;1608 _ = &dbHelper;
1609 }1609 }
1610 }1610 }
1611 };1611 };
lib/std/multi_array_list.zig+2-2
...@@ -532,8 +532,8 @@ pub fn MultiArrayList(comptime T: type) type {...@@ -532,8 +532,8 @@ pub fn MultiArrayList(comptime T: type) type {
532532
533 comptime {533 comptime {
534 if (builtin.mode == .Debug) {534 if (builtin.mode == .Debug) {
535 _ = dbHelper;535 _ = &dbHelper;
536 _ = Slice.dbHelper;536 _ = &Slice.dbHelper;
537 }537 }
538 }538 }
539 };539 };
lib/std/os/test.zig+1-1
...@@ -704,7 +704,7 @@ test "signalfd" {...@@ -704,7 +704,7 @@ test "signalfd" {
704 .linux, .solaris => {},704 .linux, .solaris => {},
705 else => return error.SkipZigTest,705 else => return error.SkipZigTest,
706 }706 }
707 _ = os.signalfd;707 _ = &os.signalfd;
708}708}
709709
710test "sync" {710test "sync" {
lib/std/testing.zig+2-2
...@@ -1116,7 +1116,7 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime...@@ -1116,7 +1116,7 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime
1116pub fn refAllDecls(comptime T: type) void {1116pub fn refAllDecls(comptime T: type) void {
1117 if (!builtin.is_test) return;1117 if (!builtin.is_test) return;
1118 inline for (comptime std.meta.declarations(T)) |decl| {1118 inline for (comptime std.meta.declarations(T)) |decl| {
1119 if (decl.is_pub) _ = @field(T, decl.name);1119 if (decl.is_pub) _ = &@field(T, decl.name);
1120 }1120 }
1121}1121}
11221122
...@@ -1132,7 +1132,7 @@ pub fn refAllDeclsRecursive(comptime T: type) void {...@@ -1132,7 +1132,7 @@ pub fn refAllDeclsRecursive(comptime T: type) void {
1132 else => {},1132 else => {},
1133 }1133 }
1134 }1134 }
1135 _ = @field(T, decl.name);1135 _ = &@field(T, decl.name);
1136 }1136 }
1137 }1137 }
1138}1138}
src/Compilation.zig+7
...@@ -3193,6 +3193,13 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v...@@ -3193,6 +3193,13 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
3193 error.OutOfMemory => return error.OutOfMemory,3193 error.OutOfMemory => return error.OutOfMemory,
3194 error.AnalysisFail => return,3194 error.AnalysisFail => return,
3195 };3195 };
3196 const decl = module.declPtr(decl_index);
3197 if (decl.kind == .@"test" and comp.bin_file.options.is_test) {
3198 // Tests are always emitted in test binaries. The decl_refs are created by
3199 // Module.populateTestFunctions, but this will not queue body analysis, so do
3200 // that now.
3201 try module.ensureFuncBodyAnalysisQueued(decl.val.castTag(.function).?.data);
3202 }
3196 },3203 },
3197 .update_embed_file => |embed_file| {3204 .update_embed_file => |embed_file| {
3198 const named_frame = tracy.namedFrame("update_embed_file");3205 const named_frame = tracy.namedFrame("update_embed_file");
src/Module.zig+59-15
...@@ -1638,6 +1638,10 @@ pub const Fn = struct {...@@ -1638,6 +1638,10 @@ pub const Fn = struct {
1638 inferred_error_sets: InferredErrorSetList = .{},1638 inferred_error_sets: InferredErrorSetList = .{},
16391639
1640 pub const Analysis = enum {1640 pub const Analysis = enum {
1641 /// This function has not yet undergone analysis, because we have not
1642 /// seen a potential runtime call. It may be analyzed in future.
1643 none,
1644 /// Analysis for this function has been queued, but not yet completed.
1641 queued,1645 queued,
1642 /// This function intentionally only has ZIR generated because it is marked1646 /// This function intentionally only has ZIR generated because it is marked
1643 /// inline, which means no runtime version of the function will be generated.1647 /// inline, which means no runtime version of the function will be generated.
...@@ -4323,7 +4327,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void {...@@ -4323,7 +4327,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void {
4323 .complete, .codegen_failure_retryable => {4327 .complete, .codegen_failure_retryable => {
4324 switch (func.state) {4328 switch (func.state) {
4325 .sema_failure, .dependency_failure => return error.AnalysisFail,4329 .sema_failure, .dependency_failure => return error.AnalysisFail,
4326 .queued => {},4330 .none, .queued => {},
4327 .in_progress => unreachable,4331 .in_progress => unreachable,
4328 .inline_only => unreachable, // don't queue work for this4332 .inline_only => unreachable, // don't queue work for this
4329 .success => return,4333 .success => return,
...@@ -4426,6 +4430,60 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void {...@@ -4426,6 +4430,60 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void {
4426 }4430 }
4427}4431}
44284432
4433/// Ensure this function's body is or will be analyzed and emitted. This should
4434/// be called whenever a potential runtime call of a function is seen.
4435///
4436/// The caller is responsible for ensuring the function decl itself is already
4437/// analyzed, and for ensuring it can exist at runtime (see
4438/// `sema.fnHasRuntimeBits`). This function does *not* guarantee that the body
4439/// will be analyzed when it returns: for that, see `ensureFuncBodyAnalyzed`.
4440pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func: *Fn) !void {
4441 const decl_index = func.owner_decl;
4442 const decl = mod.declPtr(decl_index);
4443
4444 switch (decl.analysis) {
4445 .unreferenced => unreachable,
4446 .in_progress => unreachable,
4447 .outdated => unreachable,
4448
4449 .file_failure,
4450 .sema_failure,
4451 .liveness_failure,
4452 .codegen_failure,
4453 .dependency_failure,
4454 .sema_failure_retryable,
4455 .codegen_failure_retryable,
4456 // The function analysis failed, but we've already emitted an error for
4457 // that. The callee doesn't need the function to be analyzed right now,
4458 // so its analysis can safely continue.
4459 => return,
4460
4461 .complete => {},
4462 }
4463
4464 assert(decl.has_tv);
4465
4466 switch (func.state) {
4467 .none => {},
4468 .queued => return,
4469 // As above, we don't need to forward errors here.
4470 .sema_failure, .dependency_failure => return,
4471 .in_progress => return,
4472 .inline_only => unreachable, // don't queue work for this
4473 .success => return,
4474 }
4475
4476 // Decl itself is safely analyzed, and body analysis is not yet queued
4477
4478 try mod.comp.work_queue.writeItem(.{ .codegen_func = func });
4479 if (mod.emit_h != null) {
4480 // TODO: we ideally only want to do this if the function's type changed
4481 // since the last update
4482 try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl_index });
4483 }
4484 func.state = .queued;
4485}
4486
4429pub fn updateEmbedFile(mod: *Module, embed_file: *EmbedFile) SemaError!void {4487pub fn updateEmbedFile(mod: *Module, embed_file: *EmbedFile) SemaError!void {
4430 const tracy = trace(@src());4488 const tracy = trace(@src());
4431 defer tracy.end();4489 defer tracy.end();
...@@ -4733,20 +4791,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -4733,20 +4791,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
4733 decl.analysis = .complete;4791 decl.analysis = .complete;
4734 decl.generation = mod.generation;4792 decl.generation = mod.generation;
47354793
4736 const has_runtime_bits = try sema.fnHasRuntimeBits(decl.ty);
4737
4738 if (has_runtime_bits) {
4739 // We don't fully codegen the decl until later, but we do need to reserve a global
4740 // offset table index for it. This allows us to codegen decls out of dependency
4741 // order, increasing how many computations can be done in parallel.
4742 try mod.comp.work_queue.writeItem(.{ .codegen_func = func });
4743 if (type_changed and mod.emit_h != null) {
4744 try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl_index });
4745 }
4746 } else if (!prev_is_inline and prev_type_has_bits) {
4747 mod.comp.bin_file.freeDecl(decl_index);
4748 }
4749
4750 const is_inline = decl.ty.fnCallingConvention() == .Inline;4794 const is_inline = decl.ty.fnCallingConvention() == .Inline;
4751 if (decl.is_exported) {4795 if (decl.is_exported) {
4752 const export_src: LazySrcLoc = .{ .token_offset = @boolToInt(decl.is_pub) };4796 const export_src: LazySrcLoc = .{ .token_offset = @boolToInt(decl.is_pub) };
src/Sema.zig+36-5
...@@ -2452,6 +2452,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -2452,6 +2452,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
2452 .@"align" = iac.data.alignment,2452 .@"align" = iac.data.alignment,
2453 .@"addrspace" = addr_space,2453 .@"addrspace" = addr_space,
2454 });2454 });
2455 try sema.maybeQueueFuncBodyAnalysis(iac.data.decl_index);
2455 return sema.addConstant(2456 return sema.addConstant(
2456 ptr_ty,2457 ptr_ty,
2457 try Value.Tag.decl_ref_mut.create(sema.arena, .{2458 try Value.Tag.decl_ref_mut.create(sema.arena, .{
...@@ -3709,6 +3710,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -3709,6 +3710,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
3709 const final_ptr_ty_inst = try sema.addType(final_ptr_ty);3710 const final_ptr_ty_inst = try sema.addType(final_ptr_ty);
3710 sema.air_instructions.items(.data)[ptr_inst].ty_pl.ty = final_ptr_ty_inst;3711 sema.air_instructions.items(.data)[ptr_inst].ty_pl.ty = final_ptr_ty_inst;
37113712
3713 try sema.maybeQueueFuncBodyAnalysis(decl_index);
3712 if (var_is_mut) {3714 if (var_is_mut) {
3713 sema.air_values.items[value_index] = try Value.Tag.decl_ref_mut.create(sema.arena, .{3715 sema.air_values.items[value_index] = try Value.Tag.decl_ref_mut.create(sema.arena, .{
3714 .decl_index = decl_index,3716 .decl_index = decl_index,
...@@ -3809,6 +3811,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -3809,6 +3811,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
3809 // Even though we reuse the constant instruction, we still remove it from the3811 // Even though we reuse the constant instruction, we still remove it from the
3810 // block so that codegen does not see it.3812 // block so that codegen does not see it.
3811 block.instructions.shrinkRetainingCapacity(search_index);3813 block.instructions.shrinkRetainingCapacity(search_index);
3814 try sema.maybeQueueFuncBodyAnalysis(new_decl_index);
3812 sema.air_values.items[value_index] = try Value.Tag.decl_ref.create(sema.arena, new_decl_index);3815 sema.air_values.items[value_index] = try Value.Tag.decl_ref.create(sema.arena, new_decl_index);
3813 // if bitcast ty ref needs to be made const, make_ptr_const3816 // if bitcast ty ref needs to be made const, make_ptr_const
3814 // ZIR handles it later, so we can just use the ty ref here.3817 // ZIR handles it later, so we can just use the ty ref here.
...@@ -5747,6 +5750,7 @@ pub fn analyzeExport(...@@ -5747,6 +5750,7 @@ pub fn analyzeExport(
57475750
5748 // This decl is alive no matter what, since it's being exported5751 // This decl is alive no matter what, since it's being exported
5749 mod.markDeclAlive(exported_decl);5752 mod.markDeclAlive(exported_decl);
5753 try sema.maybeQueueFuncBodyAnalysis(exported_decl_index);
57505754
5751 const gpa = mod.gpa;5755 const gpa = mod.gpa;
57525756
...@@ -7068,6 +7072,12 @@ fn analyzeCall(...@@ -7068,6 +7072,12 @@ fn analyzeCall(
7068 sema.owner_func.?.calls_or_awaits_errorable_fn = true;7072 sema.owner_func.?.calls_or_awaits_errorable_fn = true;
7069 }7073 }
70707074
7075 if (try sema.resolveMaybeUndefVal(func)) |func_val| {
7076 if (func_val.castTag(.function)) |func_obj| {
7077 try sema.mod.ensureFuncBodyAnalysisQueued(func_obj.data);
7078 }
7079 }
7080
7071 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +7081 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
7072 args.len);7082 args.len);
7073 const func_inst = try block.addInst(.{7083 const func_inst = try block.addInst(.{
...@@ -7585,6 +7595,8 @@ fn instantiateGenericCall(...@@ -7585,6 +7595,8 @@ fn instantiateGenericCall(
7585 sema.owner_func.?.calls_or_awaits_errorable_fn = true;7595 sema.owner_func.?.calls_or_awaits_errorable_fn = true;
7586 }7596 }
75877597
7598 try sema.mod.ensureFuncBodyAnalysisQueued(callee);
7599
7588 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +7600 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +
7589 runtime_args_len);7601 runtime_args_len);
7590 const result = try block.addInst(.{7602 const result = try block.addInst(.{
...@@ -9143,7 +9155,7 @@ fn funcCommon(...@@ -9143,7 +9155,7 @@ fn funcCommon(
9143 }9155 }
91449156
9145 const is_inline = fn_ty.fnCallingConvention() == .Inline;9157 const is_inline = fn_ty.fnCallingConvention() == .Inline;
9146 const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .queued;9158 const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .none;
91479159
9148 const comptime_args: ?[*]TypedValue = if (sema.comptime_args_fn_inst == func_inst) blk: {9160 const comptime_args: ?[*]TypedValue = if (sema.comptime_args_fn_inst == func_inst) blk: {
9149 break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr;9161 break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr;
...@@ -24279,9 +24291,7 @@ fn fieldCallBind(...@@ -24279,9 +24291,7 @@ fn fieldCallBind(
24279 if (concrete_ty.getNamespace()) |namespace| {24291 if (concrete_ty.getNamespace()) |namespace| {
24280 if (try sema.namespaceLookup(block, src, namespace, field_name)) |decl_idx| {24292 if (try sema.namespaceLookup(block, src, namespace, field_name)) |decl_idx| {
24281 try sema.addReferencedBy(block, src, decl_idx);24293 try sema.addReferencedBy(block, src, decl_idx);
24282 const inst = try sema.analyzeDeclRef(decl_idx);24294 const decl_val = try sema.analyzeDeclVal(block, src, decl_idx);
24283
24284 const decl_val = try sema.analyzeLoad(block, src, inst, src);
24285 const decl_type = sema.typeOf(decl_val);24295 const decl_type = sema.typeOf(decl_val);
24286 if (decl_type.zigTypeTag() == .Fn and24296 if (decl_type.zigTypeTag() == .Fn and
24287 decl_type.fnParamLen() >= 1)24297 decl_type.fnParamLen() >= 1)
...@@ -28911,7 +28921,7 @@ fn analyzeDeclVal(...@@ -28911,7 +28921,7 @@ fn analyzeDeclVal(
28911 if (sema.decl_val_table.get(decl_index)) |result| {28921 if (sema.decl_val_table.get(decl_index)) |result| {
28912 return result;28922 return result;
28913 }28923 }
28914 const decl_ref = try sema.analyzeDeclRef(decl_index);28924 const decl_ref = try sema.analyzeDeclRefInner(decl_index, false);
28915 const result = try sema.analyzeLoad(block, src, decl_ref, src);28925 const result = try sema.analyzeLoad(block, src, decl_ref, src);
28916 if (Air.refToIndex(result)) |index| {28926 if (Air.refToIndex(result)) |index| {
28917 if (sema.air_instructions.items(.tag)[index] == .constant and !block.is_typeof) {28927 if (sema.air_instructions.items(.tag)[index] == .constant and !block.is_typeof) {
...@@ -28970,6 +28980,7 @@ fn refValue(sema: *Sema, block: *Block, ty: Type, val: Value) !Value {...@@ -28970,6 +28980,7 @@ fn refValue(sema: *Sema, block: *Block, ty: Type, val: Value) !Value {
28970 try val.copy(anon_decl.arena()),28980 try val.copy(anon_decl.arena()),
28971 0, // default alignment28981 0, // default alignment
28972 );28982 );
28983 try sema.maybeQueueFuncBodyAnalysis(decl);
28973 try sema.mod.declareDeclDependency(sema.owner_decl_index, decl);28984 try sema.mod.declareDeclDependency(sema.owner_decl_index, decl);
28974 return try Value.Tag.decl_ref.create(sema.arena, decl);28985 return try Value.Tag.decl_ref.create(sema.arena, decl);
28975}28986}
...@@ -28982,6 +28993,14 @@ fn optRefValue(sema: *Sema, block: *Block, ty: Type, opt_val: ?Value) !Value {...@@ -28982,6 +28993,14 @@ fn optRefValue(sema: *Sema, block: *Block, ty: Type, opt_val: ?Value) !Value {
28982}28993}
2898328994
28984fn analyzeDeclRef(sema: *Sema, decl_index: Decl.Index) CompileError!Air.Inst.Ref {28995fn analyzeDeclRef(sema: *Sema, decl_index: Decl.Index) CompileError!Air.Inst.Ref {
28996 return sema.analyzeDeclRefInner(decl_index, true);
28997}
28998
28999/// Analyze a reference to the decl at the given index. Ensures the underlying decl is analyzed, but
29000/// only triggers analysis for function bodies if `analyze_fn_body` is true. If it's possible for a
29001/// decl_ref to end up in runtime code, the function body must be analyzed: `analyzeDeclRef` wraps
29002/// this function with `analyze_fn_body` set to true.
29003fn analyzeDeclRefInner(sema: *Sema, decl_index: Decl.Index, analyze_fn_body: bool) CompileError!Air.Inst.Ref {
28985 try sema.mod.declareDeclDependency(sema.owner_decl_index, decl_index);29004 try sema.mod.declareDeclDependency(sema.owner_decl_index, decl_index);
28986 try sema.ensureDeclAnalyzed(decl_index);29005 try sema.ensureDeclAnalyzed(decl_index);
2898729006
...@@ -28997,6 +29016,9 @@ fn analyzeDeclRef(sema: *Sema, decl_index: Decl.Index) CompileError!Air.Inst.Ref...@@ -28997,6 +29016,9 @@ fn analyzeDeclRef(sema: *Sema, decl_index: Decl.Index) CompileError!Air.Inst.Ref
28997 });29016 });
28998 return sema.addConstant(ty, try Value.Tag.decl_ref.create(sema.arena, decl_index));29017 return sema.addConstant(ty, try Value.Tag.decl_ref.create(sema.arena, decl_index));
28999 }29018 }
29019 if (analyze_fn_body) {
29020 try sema.maybeQueueFuncBodyAnalysis(decl_index);
29021 }
29000 return sema.addConstant(29022 return sema.addConstant(
29001 try Type.ptr(sema.arena, sema.mod, .{29023 try Type.ptr(sema.arena, sema.mod, .{
29002 .pointee_type = decl_tv.ty,29024 .pointee_type = decl_tv.ty,
...@@ -29008,6 +29030,15 @@ fn analyzeDeclRef(sema: *Sema, decl_index: Decl.Index) CompileError!Air.Inst.Ref...@@ -29008,6 +29030,15 @@ fn analyzeDeclRef(sema: *Sema, decl_index: Decl.Index) CompileError!Air.Inst.Ref
29008 );29030 );
29009}29031}
2901029032
29033fn maybeQueueFuncBodyAnalysis(sema: *Sema, decl_index: Decl.Index) !void {
29034 const decl = sema.mod.declPtr(decl_index);
29035 const tv = try decl.typedValue();
29036 if (tv.ty.zigTypeTag() != .Fn) return;
29037 if (!try sema.fnHasRuntimeBits(tv.ty)) return;
29038 const func = tv.val.castTag(.function) orelse return; // undef or extern_fn
29039 try sema.mod.ensureFuncBodyAnalysisQueued(func.data);
29040}
29041
29011fn analyzeRef(29042fn analyzeRef(
29012 sema: *Sema,29043 sema: *Sema,
29013 block: *Block,29044 block: *Block,
src/type.zig+1-1
...@@ -6802,7 +6802,7 @@ pub const Type = extern union {...@@ -6802,7 +6802,7 @@ pub const Type = extern union {
68026802
6803 comptime {6803 comptime {
6804 if (builtin.mode == .Debug) {6804 if (builtin.mode == .Debug) {
6805 _ = dbHelper;6805 _ = &dbHelper;
6806 }6806 }
6807 }6807 }
6808};6808};
src/value.zig+1-1
...@@ -5709,7 +5709,7 @@ pub const Value = extern union {...@@ -5709,7 +5709,7 @@ pub const Value = extern union {
57095709
5710 comptime {5710 comptime {
5711 if (builtin.mode == .Debug) {5711 if (builtin.mode == .Debug) {
5712 _ = dbHelper;5712 _ = &dbHelper;
5713 }5713 }
5714 }5714 }
5715};5715};
test/behavior/sizeof_and_typeof.zig+1-1
...@@ -48,7 +48,7 @@ fn fn1(alpha: bool) void {...@@ -48,7 +48,7 @@ fn fn1(alpha: bool) void {
48}48}
4949
50test "lazy @sizeOf result is checked for definedness" {50test "lazy @sizeOf result is checked for definedness" {
51 _ = fn1;51 _ = &fn1;
52}52}
5353
54const A = struct {54const A = struct {
test/cases/compile_errors/closure_get_depends_on_failed_decl.zig+1-1
...@@ -3,7 +3,7 @@ pub inline fn instanceRequestAdapter() void {}...@@ -3,7 +3,7 @@ pub inline fn instanceRequestAdapter() void {}
3pub inline fn requestAdapter(3pub inline fn requestAdapter(
4 comptime callbackArg: fn () callconv(.Inline) void,4 comptime callbackArg: fn () callconv(.Inline) void,
5) void {5) void {
6 _ = (struct {6 _ = &(struct {
7 pub fn callback() callconv(.C) void {7 pub fn callback() callconv(.C) void {
8 callbackArg();8 callbackArg();
9 }9 }
test/cases/compile_errors/compileLog_of_tagged_enum_doesnt_crash_the_compiler.zig+3-2
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const Bar = union(enum(u32)) {1const Bar = union(enum(u32)) {
2 X: i32 = 12 X: i32 = 1,
3};3};
44
5fn testCompileLog(x: Bar) void {5fn testCompileLog(x: Bar) void {
...@@ -7,7 +7,8 @@ fn testCompileLog(x: Bar) void {...@@ -7,7 +7,8 @@ fn testCompileLog(x: Bar) void {
7}7}
88
9pub export fn entry() void {9pub export fn entry() void {
10 comptime testCompileLog(Bar{.X = 123});10 comptime testCompileLog(Bar{ .X = 123 });
11 _ = &testCompileLog;
11}12}
1213
13// error14// error
test/cases/compile_errors/compile_log.zig+6-5
...@@ -1,10 +1,11 @@...@@ -1,10 +1,11 @@
1export fn foo() void {1export fn foo() void {
2 comptime bar(12, "hi",);2 comptime bar(12, "hi");
3 _ = &bar;
3}4}
4fn bar(a: i32, b: []const u8) void {5fn bar(a: i32, b: []const u8) void {
5 @compileLog("begin",);6 @compileLog("begin");
6 @compileLog("a", a, "b", b);7 @compileLog("a", a, "b", b);
7 @compileLog("end",);8 @compileLog("end");
8}9}
9export fn baz() void {10export fn baz() void {
10 const S = struct { a: u32 };11 const S = struct { a: u32 };
...@@ -15,8 +16,8 @@ export fn baz() void {...@@ -15,8 +16,8 @@ export fn baz() void {
15// backend=llvm16// backend=llvm
16// target=native17// target=native
17//18//
18// :5:5: error: found compile log statement19// :6:5: error: found compile log statement
19// :11:5: note: also here20// :12:5: note: also here
20//21//
21// Compile Log Output:22// Compile Log Output:
22// @as(*const [5:0]u8, "begin")23// @as(*const [5:0]u8, "begin")
test/cases/compile_errors/dereference_slice.zig+1-1
...@@ -2,7 +2,7 @@ fn entry(x: []i32) i32 {...@@ -2,7 +2,7 @@ fn entry(x: []i32) i32 {
2 return x.*;2 return x.*;
3}3}
4comptime {4comptime {
5 _ = entry;5 _ = &entry;
6}6}
77
8// error8// error
test/cases/compile_errors/extern_function_with_comptime_parameter.zig+3-3
...@@ -4,9 +4,9 @@ fn f() i32 {...@@ -4,9 +4,9 @@ fn f() i32 {
4}4}
5pub extern fn entry1(b: u32, comptime a: [2]u8, c: i32) void;5pub extern fn entry1(b: u32, comptime a: [2]u8, c: i32) void;
6pub extern fn entry2(b: u32, noalias a: anytype, i43) void;6pub extern fn entry2(b: u32, noalias a: anytype, i43) void;
7comptime { _ = f; }7comptime { _ = &f; }
8comptime { _ = entry1; }8comptime { _ = &entry1; }
9comptime { _ = entry2; }9comptime { _ = &entry2; }
1010
11// error11// error
12// backend=stage212// backend=stage2
test/cases/compile_errors/invalid_address_space_coercion.zig+1-1
...@@ -2,7 +2,7 @@ fn entry(a: *addrspace(.gs) i32) *i32 {...@@ -2,7 +2,7 @@ fn entry(a: *addrspace(.gs) i32) *i32 {
2 return a;2 return a;
3}3}
4pub fn main() void {4pub fn main() void {
5 _ = entry;5 _ = &entry;
6}6}
77
8// error8// error
test/cases/compile_errors/invalid_pointer_keeps_address_space_when_taking_address_of_dereference.zig+1-1
...@@ -2,7 +2,7 @@ fn entry(a: *addrspace(.gs) i32) *i32 {...@@ -2,7 +2,7 @@ fn entry(a: *addrspace(.gs) i32) *i32 {
2 return &a.*;2 return &a.*;
3}3}
4pub fn main() void {4pub fn main() void {
5 _ = entry;5 _ = &entry;
6}6}
77
8// error8// error
test/cases/compile_errors/noalias_on_non_pointer_param.zig+2-2
...@@ -2,10 +2,10 @@ fn f(noalias x: i32) void { _ = x; }...@@ -2,10 +2,10 @@ fn f(noalias x: i32) void { _ = x; }
2export fn entry() void { f(1234); }2export fn entry() void { f(1234); }
33
4fn generic(comptime T: type, noalias _: [*]T, noalias _: [*]const T, _: usize) void {}4fn generic(comptime T: type, noalias _: [*]T, noalias _: [*]const T, _: usize) void {}
5comptime { _ = generic; }5comptime { _ = &generic; }
66
7fn slice(noalias _: []u8) void {}7fn slice(noalias _: []u8) void {}
8comptime { _ = slice; }8comptime { _ = &slice; }
99
10// error10// error
11// backend=stage211// backend=stage2
test/cases/compile_errors/pointer_with_different_address_spaces.zig+1-1
...@@ -2,7 +2,7 @@ fn entry(a: *addrspace(.gs) i32) *addrspace(.fs) i32 {...@@ -2,7 +2,7 @@ fn entry(a: *addrspace(.gs) i32) *addrspace(.fs) i32 {
2 return a;2 return a;
3}3}
4export fn entry2() void {4export fn entry2() void {
5 _ = entry;5 _ = &entry;
6}6}
77
8// error8// error
test/cases/compile_errors/pointers_with_different_address_spaces.zig+1-1
...@@ -2,7 +2,7 @@ fn entry(a: ?*addrspace(.gs) i32) *i32 {...@@ -2,7 +2,7 @@ fn entry(a: ?*addrspace(.gs) i32) *i32 {
2 return a.?;2 return a.?;
3}3}
4pub fn main() void {4pub fn main() void {
5 _ = entry;5 _ = &entry;
6}6}
77
8// error8// error
test/cases/compile_errors/slice_sentinel_mismatch-2.zig+1-1
...@@ -2,7 +2,7 @@ fn foo() [:0]u8 {...@@ -2,7 +2,7 @@ fn foo() [:0]u8 {
2 var x: []u8 = undefined;2 var x: []u8 = undefined;
3 return x;3 return x;
4}4}
5comptime { _ = foo; }5comptime { _ = &foo; }
66
7// error7// error
8// backend=stage28// backend=stage2
test/cases/llvm/address_space_pointer_access_chaining_pointer_to_optional_array.zig+1-1
...@@ -2,7 +2,7 @@ fn entry(a: *addrspace(.gs) ?[1]i32) *addrspace(.gs) i32 {...@@ -2,7 +2,7 @@ fn entry(a: *addrspace(.gs) ?[1]i32) *addrspace(.gs) i32 {
2 return &a.*.?[0];2 return &a.*.?[0];
3}3}
4pub fn main() void {4pub fn main() void {
5 _ = entry;5 _ = &entry;
6}6}
77
8// compile8// compile
test/cases/llvm/address_spaces_pointer_access_chaining_array_pointer.zig+1-1
...@@ -2,7 +2,7 @@ fn entry(a: *addrspace(.gs) [1]i32) *addrspace(.gs) i32 {...@@ -2,7 +2,7 @@ fn entry(a: *addrspace(.gs) [1]i32) *addrspace(.gs) i32 {
2 return &a[0];2 return &a[0];
3}3}
4pub fn main() void {4pub fn main() void {
5 _ = entry;5 _ = &entry;
6}6}
77
8// compile8// compile
test/cases/llvm/address_spaces_pointer_access_chaining_complex.zig+1-1
...@@ -3,7 +3,7 @@ fn entry(a: *addrspace(.gs) [1]A) *addrspace(.gs) i32 {...@@ -3,7 +3,7 @@ fn entry(a: *addrspace(.gs) [1]A) *addrspace(.gs) i32 {
3 return &a[0].a.?[0];3 return &a[0].a.?[0];
4}4}
5pub fn main() void {5pub fn main() void {
6 _ = entry;6 _ = &entry;
7}7}
88
9// compile9// compile
test/cases/llvm/address_spaces_pointer_access_chaining_struct_pointer.zig+1-1
...@@ -3,7 +3,7 @@ fn entry(a: *addrspace(.gs) A) *addrspace(.gs) i32 {...@@ -3,7 +3,7 @@ fn entry(a: *addrspace(.gs) A) *addrspace(.gs) i32 {
3 return &a.a;3 return &a.a;
4}4}
5pub fn main() void {5pub fn main() void {
6 _ = entry;6 _ = &entry;
7}7}
88
9// compile9// compile
test/cases/llvm/dereferencing_though_multiple_pointers_with_address_spaces.zig+1-1
...@@ -2,7 +2,7 @@ fn entry(a: *addrspace(.fs) *addrspace(.gs) *i32) *i32 {...@@ -2,7 +2,7 @@ fn entry(a: *addrspace(.fs) *addrspace(.gs) *i32) *i32 {
2 return a.*.*;2 return a.*.*;
3}3}
4pub fn main() void {4pub fn main() void {
5 _ = entry;5 _ = &entry;
6}6}
77
8// compile8// compile
test/cases/llvm/pointer_keeps_address_space.zig+1-1
...@@ -2,7 +2,7 @@ fn entry(a: *addrspace(.gs) i32) *addrspace(.gs) i32 {...@@ -2,7 +2,7 @@ fn entry(a: *addrspace(.gs) i32) *addrspace(.gs) i32 {
2 return a;2 return a;
3}3}
4pub fn main() void {4pub fn main() void {
5 _ = entry;5 _ = &entry;
6}6}
77
8// compile8// compile
test/cases/llvm/pointer_keeps_address_space_when_taking_address_of_dereference.zig+1-1
...@@ -2,7 +2,7 @@ fn entry(a: *addrspace(.gs) i32) *addrspace(.gs) i32 {...@@ -2,7 +2,7 @@ fn entry(a: *addrspace(.gs) i32) *addrspace(.gs) i32 {
2 return &a.*;2 return &a.*;
3}3}
4pub fn main() void {4pub fn main() void {
5 _ = entry;5 _ = &entry;
6}6}
77
8// compile8// compile
test/cases/llvm/pointer_to_explicit_generic_address_space_coerces_to_implicit_pointer.zig+1-1
...@@ -2,7 +2,7 @@ fn entry(a: *addrspace(.generic) i32) *i32 {...@@ -2,7 +2,7 @@ fn entry(a: *addrspace(.generic) i32) *i32 {
2 return a;2 return a;
3}3}
4pub fn main() void {4pub fn main() void {
5 _ = entry;5 _ = &entry;
6}6}
77
8// compile8// compile
test/link/wasm/type/build.zig+2-2
...@@ -26,10 +26,10 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize...@@ -26,10 +26,10 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
2626
27 const check_lib = lib.checkObject();27 const check_lib = lib.checkObject();
28 check_lib.checkStart("Section type");28 check_lib.checkStart("Section type");
29 // only 3 entries, although we have more functions.29 // only 2 entries, although we have more functions.
30 // This is to test functions with the same function signature30 // This is to test functions with the same function signature
31 // have their types deduplicated.31 // have their types deduplicated.
32 check_lib.checkNext("entries 3");32 check_lib.checkNext("entries 2");
33 check_lib.checkNext("params 1");33 check_lib.checkNext("params 1");
34 check_lib.checkNext("type i32");34 check_lib.checkNext("type i32");
35 check_lib.checkNext("returns 1");35 check_lib.checkNext("returns 1");