Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/std/zig/AstRlAnnotate.zig
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,7 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
},
// These builtins take no args and do not consume the result pointer.
.src,
.caller_src,
.This,
.return_address,
.error_return_trace,
Expand Down
9 changes: 9 additions & 0 deletions lib/std/zig/BuiltinFn.zig
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ pub const Tag = enum {
splat,
reduce,
src,
caller_src,
sqrt,
sin,
cos,
Expand Down Expand Up @@ -822,6 +823,14 @@ pub const list = list: {
.illegal_outside_function = true,
},
},
.{
"@callerSrc",
.{
.tag = .caller_src,
.param_count = 0,
.illegal_outside_function = true,
},
},
.{
"@sqrt",
.{
Expand Down
1 change: 1 addition & 0 deletions src/AstGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -8486,6 +8486,7 @@ fn builtinCall(
.frame_address => return rvalue(gz, ri, try gz.addNodeExtended(.frame_address, node), node),
.breakpoint => return rvalue(gz, ri, try gz.addNodeExtended(.breakpoint, node), node),
.in_comptime => return rvalue(gz, ri, try gz.addNodeExtended(.in_comptime, node), node),
.caller_src => return rvalue(gz, ri, try gz.addNodeExtended(.builtin_caller_src, node), node),

.type_info => return simpleUnOpType(gz, scope, ri, node, params[0], .type_info),
.size_of => return simpleUnOpType(gz, scope, ri, node, params[0], .size_of),
Expand Down
114 changes: 114 additions & 0 deletions src/Sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1230,6 +1230,7 @@ fn analyzeBodyInner(
.this => try sema.zirThis( block, extended),
.ret_addr => try sema.zirRetAddr( block, extended),
.builtin_src => try sema.zirBuiltinSrc( block, extended),
.builtin_caller_src => try sema.zirBuiltinCallerSrc( block, extended),
.error_return_trace => try sema.zirErrorReturnTrace( block),
.frame => try sema.zirFrame( block, extended),
.frame_address => try sema.zirFrameAddress( block, extended),
Expand Down Expand Up @@ -16876,6 +16877,119 @@ fn zirBuiltinSrc(
} })));
}

fn zirBuiltinCallerSrc(
sema: *Sema,
block: *Block,
extended: Zir.Inst.Extended.InstData,
) CompileError!Air.Inst.Ref {
_ = extended;
_ = block;

const mod = sema.mod;
const ip = &mod.intern_pool;
const gpa = sema.gpa;

// Declare default values for the case where we are not able to retrieve caller location.
var filename: []const u8 = "<unknown>";
var function_name: []const u8 = "<unknown>";
var line: usize = 0;
var column: usize = 0;

const referenced_by = if (sema.owner_func_index != .none)
mod.funcOwnerDeclIndex(sema.owner_func_index)
else
sema.owner_decl_index;

// Try to get our caller block.
if (mod.reference_table.get(referenced_by)) |caller| ref: {
// Retrieve the assocaited declaration.
const decl = mod.declPtr(caller.referencer);

// Get the function name
// NOTE(Corentin,@Hack): This might not be a function but SourceLocation is expecting a function name.
function_name = try sema.arena.dupe(u8, ip.stringToSlice(decl.name));

// Get the file name
const file_scope = decl.getFileScope(mod);
filename = try file_scope.fullPathZ(sema.arena);

// Load or get the file source.
const file_source = file_scope.getSource(gpa) catch break :ref;

// Retrieve the location of the Decl as a Span.
const source_loc = caller.src.toSrcLoc(decl, mod);
const source_span = source_loc.span(gpa) catch break :ref;

// Compute the associated line and columm.
const reference_location = std.zig.findLineColumn(file_source.bytes, source_span.main);

// Update the line and column values.
line = reference_location.line + 1;
column = reference_location.column + 1;
}

// Produce the SourceLocation
const func_name_val = v: {
// This dupe prevents InternPool string pool memory from being reallocated
// while a reference exists.
const bytes = function_name;
const array_ty = try ip.get(gpa, .{ .array_type = .{
.len = bytes.len,
.sentinel = .zero_u8,
.child = .u8_type,
} });
break :v try ip.get(gpa, .{ .ptr = .{
.ty = .slice_const_u8_sentinel_0_type,
.len = (try mod.intValue(Type.usize, bytes.len)).toIntern(),
.addr = .{ .anon_decl = .{
.orig_ty = .slice_const_u8_sentinel_0_type,
.val = try ip.get(gpa, .{ .aggregate = .{
.ty = array_ty,
.storage = .{ .bytes = bytes },
} }),
} },
} });
};

const file_name_val = v: {
// The compiler must not call realpath anywhere.
const bytes = filename;
const array_ty = try ip.get(gpa, .{ .array_type = .{
.len = bytes.len,
.sentinel = .zero_u8,
.child = .u8_type,
} });
break :v try ip.get(gpa, .{ .ptr = .{
.ty = .slice_const_u8_sentinel_0_type,
.len = (try mod.intValue(Type.usize, bytes.len)).toIntern(),
.addr = .{ .anon_decl = .{
.orig_ty = .slice_const_u8_sentinel_0_type,
.val = try ip.get(gpa, .{ .aggregate = .{
.ty = array_ty,
.storage = .{ .bytes = bytes },
} }),
} },
} });
};

const src_loc_ty = try sema.getBuiltinType("SourceLocation");
const fields = .{
// file: [:0]const u8,
file_name_val,
// fn_name: [:0]const u8,
func_name_val,
// line: u32,
(try mod.intValue(Type.u32, line)).toIntern(),
// column: u32,
(try mod.intValue(Type.u32, column)).toIntern(),
};

return Air.internedToRef((try mod.intern(.{ .aggregate = .{
.ty = src_loc_ty.toIntern(),
.storage = .{ .elems = &fields },
} })));
}

fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const mod = sema.mod;
const gpa = sema.gpa;
Expand Down
3 changes: 3 additions & 0 deletions src/Zir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1920,6 +1920,9 @@ pub const Inst = struct {
/// Implements the `@src` builtin.
/// `operand` is payload index to `LineColumn`.
builtin_src,
/// Implements the `@callerSrc` builtin.
/// `operand` is `src_node: i32`.
builtin_caller_src,
/// Implements the `@errorReturnTrace` builtin.
/// `operand` is `src_node: i32`.
error_return_trace,
Expand Down
1 change: 1 addition & 0 deletions src/print_zir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,7 @@ const Writer = struct {
.c_va_start,
.in_comptime,
.value_placeholder,
.builtin_caller_src,
=> try self.writeExtNode(stream, extended),

.builtin_src => {
Expand Down
14 changes: 14 additions & 0 deletions test/behavior/caller_src.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const std = @import("std");

fn callerSrcReporter() std.builtin.SourceLocation {
const caller = @callerSrc();
return caller;
}

test "@callerSrc() behavior" {
const loc = callerSrcReporter();

try std.testing.expectEqual(@as(usize, 9), loc.line);
try std.testing.expectEqual(@as(usize, 17), loc.column);
try std.testing.expectEqualStrings("test.@callerSrc() behavior", loc.fn_name);
}