@@ -131,6 +131,15 @@ pub const CallingConvention = enum {
|
||||
AAPCSVFP,
|
||||
};
|
||||
|
||||
/// This data structure is used by the Zig language code generation and
|
||||
/// therefore must be kept in sync with the compiler implementation.
|
||||
pub const SourceLocation = struct {
|
||||
file: []const u8,
|
||||
fn_name: []const u8,
|
||||
line: u32,
|
||||
column: u32,
|
||||
};
|
||||
|
||||
pub const TypeId = @TagType(TypeInfo);
|
||||
|
||||
/// This data structure is used by the Zig language code generation and
|
||||
|
||||
@@ -1827,6 +1827,7 @@ enum BuiltinFnId {
|
||||
BuiltinFnIdBitSizeof,
|
||||
BuiltinFnIdWasmMemorySize,
|
||||
BuiltinFnIdWasmMemoryGrow,
|
||||
BuiltinFnIdSrc,
|
||||
};
|
||||
|
||||
struct BuiltinFnEntry {
|
||||
@@ -2754,6 +2755,7 @@ enum IrInstSrcId {
|
||||
IrInstSrcIdSpillEnd,
|
||||
IrInstSrcIdWasmMemorySize,
|
||||
IrInstSrcIdWasmMemoryGrow,
|
||||
IrInstSrcIdSrc,
|
||||
};
|
||||
|
||||
// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR.
|
||||
@@ -3761,6 +3763,10 @@ struct IrInstGenWasmMemoryGrow {
|
||||
IrInstGen *delta;
|
||||
};
|
||||
|
||||
struct IrInstSrcSrc {
|
||||
IrInstSrc base;
|
||||
};
|
||||
|
||||
struct IrInstSrcSlice {
|
||||
IrInstSrc base;
|
||||
|
||||
|
||||
@@ -8714,6 +8714,7 @@ static void define_builtin_fns(CodeGen *g) {
|
||||
create_builtin_fn(g, BuiltinFnIdBitSizeof, "bitSizeOf", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdWasmMemorySize, "wasmMemorySize", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdWasmMemoryGrow, "wasmMemoryGrow", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdSrc, "src", 0);
|
||||
}
|
||||
|
||||
static const char *bool_to_str(bool b) {
|
||||
|
||||
76
src/ir.cpp
76
src/ir.cpp
@@ -561,6 +561,8 @@ static void destroy_instruction_src(IrInstSrc *inst) {
|
||||
return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcWasmMemorySize *>(inst));
|
||||
case IrInstSrcIdWasmMemoryGrow:
|
||||
return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcWasmMemoryGrow *>(inst));
|
||||
case IrInstSrcIdSrc:
|
||||
return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSrc *>(inst));
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@@ -1627,6 +1629,9 @@ static constexpr IrInstSrcId ir_inst_id(IrInstSrcWasmMemoryGrow *) {
|
||||
return IrInstSrcIdWasmMemoryGrow;
|
||||
}
|
||||
|
||||
static constexpr IrInstSrcId ir_inst_id(IrInstSrcSrc *) {
|
||||
return IrInstSrcIdSrc;
|
||||
}
|
||||
|
||||
static constexpr IrInstGenId ir_inst_id(IrInstGenDeclVar *) {
|
||||
return IrInstGenIdDeclVar;
|
||||
@@ -5030,6 +5035,11 @@ static IrInstGen *ir_build_wasm_memory_grow_gen(IrAnalyze *ira, IrInst *source_i
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstSrc *ir_build_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) {
|
||||
IrInstSrcSrc *instruction = ir_build_instruction<IrInstSrcSrc>(irb, scope, source_node);
|
||||
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static void ir_count_defers(IrBuilderSrc *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
|
||||
results[ReturnKindUnconditional] = 0;
|
||||
@@ -7450,6 +7460,11 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod
|
||||
return ir_gen_union_init_expr(irb, scope, node, union_type_inst, name_inst, init_node,
|
||||
lval, result_loc);
|
||||
}
|
||||
case BuiltinFnIdSrc:
|
||||
{
|
||||
IrInstSrc *src_inst = ir_build_src(irb, scope, node);
|
||||
return ir_lval_wrap(irb, scope, src_inst, lval, result_loc);
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@@ -30859,6 +30874,64 @@ static IrInstGen *ir_analyze_instruction_spill_end(IrAnalyze *ira, IrInstSrcSpil
|
||||
return ir_build_spill_end_gen(ira, &instruction->base.base, begin, operand->value->type);
|
||||
}
|
||||
|
||||
static IrInstGen *ir_analyze_instruction_src(IrAnalyze *ira, IrInstSrcSrc *instruction) {
|
||||
ZigFn *fn_entry = scope_fn_entry(instruction->base.base.scope);
|
||||
if (fn_entry == nullptr) {
|
||||
ir_add_error(ira, &instruction->base.base, buf_sprintf("@src outside function"));
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
||||
ZigType *u8_ptr = get_pointer_to_type_extra(
|
||||
ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
true, false, PtrLenUnknown,
|
||||
0, 0, 0, false);
|
||||
ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr);
|
||||
|
||||
ZigType *source_location_type = get_builtin_type(ira->codegen, "SourceLocation");
|
||||
if (type_resolve(ira->codegen, source_location_type, ResolveStatusSizeKnown)) {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
ZigValue *result = ira->codegen->pass1_arena->create<ZigValue>();
|
||||
result->special = ConstValSpecialStatic;
|
||||
result->type = source_location_type;
|
||||
|
||||
ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 4);
|
||||
result->data.x_struct.fields = fields;
|
||||
|
||||
// file: []const u8
|
||||
ensure_field_index(source_location_type, "file", 0);
|
||||
fields[0]->special = ConstValSpecialStatic;
|
||||
fields[0]->type = u8_slice;
|
||||
|
||||
ZigType *import = instruction->base.base.source_node->owner;
|
||||
Buf *path = import->data.structure.root_struct->path;
|
||||
ZigValue *file_name = create_const_str_lit(ira->codegen, path)->data.x_ptr.data.ref.pointee;
|
||||
init_const_slice(ira->codegen, fields[0], file_name, 0, buf_len(path), true);
|
||||
|
||||
// fn_name: []const u8
|
||||
ensure_field_index(source_location_type, "fn_name", 1);
|
||||
fields[1]->special = ConstValSpecialStatic;
|
||||
fields[1]->type = u8_slice;
|
||||
|
||||
ZigValue *fn_name = create_const_str_lit(ira->codegen, &fn_entry->symbol_name)->data.x_ptr.data.ref.pointee;
|
||||
init_const_slice(ira->codegen, fields[1], fn_name, 0, buf_len(&fn_entry->symbol_name), true);
|
||||
|
||||
// line: u32
|
||||
ensure_field_index(source_location_type, "line", 2);
|
||||
fields[2]->special = ConstValSpecialStatic;
|
||||
fields[2]->type = ira->codegen->builtin_types.entry_u32;
|
||||
bigint_init_unsigned(&fields[2]->data.x_bigint, instruction->base.base.source_node->line + 1);
|
||||
|
||||
// column: u32
|
||||
ensure_field_index(source_location_type, "column", 3);
|
||||
fields[3]->special = ConstValSpecialStatic;
|
||||
fields[3]->type = ira->codegen->builtin_types.entry_u32;
|
||||
bigint_init_unsigned(&fields[3]->data.x_bigint, instruction->base.base.source_node->column + 1);
|
||||
|
||||
return ir_const_move(ira, &instruction->base.base, result);
|
||||
}
|
||||
|
||||
static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruction) {
|
||||
switch (instruction->id) {
|
||||
case IrInstSrcIdInvalid:
|
||||
@@ -31130,6 +31203,8 @@ static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruc
|
||||
return ir_analyze_instruction_wasm_memory_size(ira, (IrInstSrcWasmMemorySize *)instruction);
|
||||
case IrInstSrcIdWasmMemoryGrow:
|
||||
return ir_analyze_instruction_wasm_memory_grow(ira, (IrInstSrcWasmMemoryGrow *)instruction);
|
||||
case IrInstSrcIdSrc:
|
||||
return ir_analyze_instruction_src(ira, (IrInstSrcSrc *)instruction);
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@@ -31525,6 +31600,7 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) {
|
||||
case IrInstSrcIdAlloca:
|
||||
case IrInstSrcIdSpillEnd:
|
||||
case IrInstSrcIdWasmMemorySize:
|
||||
case IrInstSrcIdSrc:
|
||||
return false;
|
||||
|
||||
case IrInstSrcIdAsm:
|
||||
|
||||
@@ -325,6 +325,8 @@ const char* ir_inst_src_type_str(IrInstSrcId id) {
|
||||
return "SrcWasmMemorySize";
|
||||
case IrInstSrcIdWasmMemoryGrow:
|
||||
return "SrcWasmMemoryGrow";
|
||||
case IrInstSrcIdSrc:
|
||||
return "SrcSrc";
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@@ -1744,6 +1746,10 @@ static void ir_print_wasm_memory_grow(IrPrintGen *irp, IrInstGenWasmMemoryGrow *
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_builtin_src(IrPrintSrc *irp, IrInstSrcSrc *instruction) {
|
||||
fprintf(irp->f, "@src()");
|
||||
}
|
||||
|
||||
static void ir_print_memset(IrPrintSrc *irp, IrInstSrcMemset *instruction) {
|
||||
fprintf(irp->f, "@memset(");
|
||||
ir_print_other_inst_src(irp, instruction->dest_ptr);
|
||||
@@ -2994,6 +3000,9 @@ static void ir_print_inst_src(IrPrintSrc *irp, IrInstSrc *instruction, bool trai
|
||||
case IrInstSrcIdWasmMemoryGrow:
|
||||
ir_print_wasm_memory_grow(irp, (IrInstSrcWasmMemoryGrow *)instruction);
|
||||
break;
|
||||
case IrInstSrcIdSrc:
|
||||
ir_print_builtin_src(irp, (IrInstSrcSrc *)instruction);
|
||||
break;
|
||||
}
|
||||
fprintf(irp->f, "\n");
|
||||
}
|
||||
|
||||
@@ -2,6 +2,14 @@ const tests = @import("tests.zig");
|
||||
const std = @import("std");
|
||||
|
||||
pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
cases.add("@src outside function",
|
||||
\\comptime {
|
||||
\\ @src();
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
"tmp.zig:2:5: error: @src outside function",
|
||||
});
|
||||
|
||||
cases.add("call assigned to constant",
|
||||
\\const Foo = struct {
|
||||
\\ x: i32,
|
||||
|
||||
@@ -131,4 +131,5 @@ comptime {
|
||||
}
|
||||
_ = @import("behavior/while.zig");
|
||||
_ = @import("behavior/widening.zig");
|
||||
_ = @import("behavior/src.zig");
|
||||
}
|
||||
|
||||
15
test/stage1/behavior/src.zig
Normal file
15
test/stage1/behavior/src.zig
Normal file
@@ -0,0 +1,15 @@
|
||||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
|
||||
test "@src" {
|
||||
doTheTest();
|
||||
}
|
||||
|
||||
fn doTheTest() void {
|
||||
const src = @src();
|
||||
|
||||
expect(src.line == 9);
|
||||
expect(src.column == 17);
|
||||
expect(std.mem.endsWith(u8, src.fn_name, "doTheTest"));
|
||||
expect(std.mem.endsWith(u8, src.file, "src.zig"));
|
||||
}
|
||||
Reference in New Issue
Block a user