aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-09-06 19:06:09 -0700
committerAndrew Kelley <andrew@ziglang.org>2022-09-06 19:45:02 -0700
commitb7900de1684021ff86c67105e14e34968821ea02 (patch)
treeb881a288071705ffb8cd65ede5f8e7a1452b6dce /src
parent20145016ac0d098e8e63d5107a05eca376d1e7bb (diff)
parente2bb92b2e27dc54852a0227345e294ae383358fd (diff)
downloadzig-b7900de1684021ff86c67105e14e34968821ea02.tar.gz
zig-b7900de1684021ff86c67105e14e34968821ea02.zip
Merge remote-tracking branch 'origin/master' into llvm15
Diffstat (limited to 'src')
-rw-r--r--src/AstGen.zig2
-rw-r--r--src/Autodoc.zig614
-rw-r--r--src/Module.zig2
-rw-r--r--src/Sema.zig191
-rw-r--r--src/arch/aarch64/abi.zig63
-rw-r--r--src/arch/wasm/CodeGen.zig2
-rw-r--r--src/arch/wasm/abi.zig8
-rw-r--r--src/arch/x86_64/abi.zig24
-rw-r--r--src/autodoc/render_source.zig15
-rw-r--r--src/codegen/llvm.zig192
-rw-r--r--src/link/Coff.zig148
-rw-r--r--src/link/Coff/Atom.zig14
-rw-r--r--src/link/Wasm.zig45
-rw-r--r--src/link/Wasm/Atom.zig14
-rw-r--r--src/link/Wasm/Symbol.zig2
-rw-r--r--src/main.zig14
-rw-r--r--src/translate_c.zig4
-rw-r--r--src/type.zig7
-rw-r--r--src/value.zig29
19 files changed, 1006 insertions, 384 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig
index 79e5ad963e..1502b97017 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -5127,7 +5127,7 @@ fn tryExpr(
else => .none,
};
// This could be a pointer or value depending on the `rl` parameter.
- const operand = try expr(parent_gz, scope, operand_rl, operand_node);
+ const operand = try reachableExpr(parent_gz, scope, operand_rl, operand_node, node);
const is_inline = parent_gz.force_comptime;
const is_inline_bit = @as(u2, @boolToInt(is_inline));
const is_ptr_bit = @as(u2, @boolToInt(operand_rl == .ref)) << 1;
diff --git a/src/Autodoc.zig b/src/Autodoc.zig
index 0e056c093f..e6e025b5b4 100644
--- a/src/Autodoc.zig
+++ b/src/Autodoc.zig
@@ -1,6 +1,7 @@
const builtin = @import("builtin");
const std = @import("std");
const build_options = @import("build_options");
+const Ast = std.zig.Ast;
const Autodoc = @This();
const Compilation = @import("Compilation.zig");
const Module = @import("Module.zig");
@@ -47,6 +48,19 @@ const RefPathResumeInfo = struct {
ref_path: []DocData.Expr,
};
+/// Used to accumulate src_node offsets.
+/// In ZIR, all ast node indices are relative to the parent decl.
+/// More concretely, `union_decl`, `struct_decl`, `enum_decl` and `opaque_decl`
+/// and the value of each of their decls participate in the relative offset
+/// counting, and nothing else.
+/// We keep track of the line and byte values for these instructions in order
+/// to avoid tokenizing every file (on new lines) from the start every time.
+const SrcLocInfo = struct {
+ bytes: u32 = 0,
+ line: usize = 0,
+ src_node: u32 = 0,
+};
+
var arena_allocator: std.heap.ArenaAllocator = undefined;
pub fn init(m: *Module, doc_location: Compilation.EmitLoc) Autodoc {
arena_allocator = std.heap.ArenaAllocator.init(m.gpa);
@@ -202,7 +216,7 @@ pub fn generateZirData(self: *Autodoc) !void {
try self.ast_nodes.append(self.arena, .{ .name = "(root)" });
try self.files.put(self.arena, file, main_type_index);
- _ = try self.walkInstruction(file, &root_scope, 1, Zir.main_struct_inst, false);
+ _ = try self.walkInstruction(file, &root_scope, .{}, Zir.main_struct_inst, false);
if (self.ref_paths_pending_on_decls.count() > 0) {
@panic("some decl paths were never fully analized (pending on decls)");
@@ -467,6 +481,7 @@ const DocData = struct {
line: usize = 0,
col: usize = 0,
name: ?[]const u8 = null,
+ code: ?[]const u8 = null,
docs: ?[]const u8 = null,
fields: ?[]usize = null, // index into astNodes
@"comptime": bool = false,
@@ -562,7 +577,13 @@ const DocData = struct {
is_extern: bool = false,
},
BoundFn: struct { name: []const u8 },
- Opaque: struct { name: []const u8 },
+ Opaque: struct {
+ name: []const u8,
+ src: usize, // index into astNodes
+ privDecls: []usize = &.{}, // index into decls
+ pubDecls: []usize = &.{}, // index into decls
+ ast: usize,
+ },
Frame: struct { name: []const u8 },
AnyFrame: struct { name: []const u8 },
Vector: struct { name: []const u8 },
@@ -625,7 +646,7 @@ const DocData = struct {
negated: bool = false,
},
int_big: struct {
- value: []const u8, // direct value
+ value: []const u8, // string representation
negated: bool = false,
},
float: f64, // direct value
@@ -712,12 +733,6 @@ const DocData = struct {
if (self.int.negated) try w.writeAll("-");
try jsw.emitNumber(self.int.value);
},
- .int_big => {
-
- //@panic("TODO: json serialization of big ints!");
- //if (v.negated) try w.writeAll("-");
- //try jsw.emitNumber(v.value);
- },
.builtinField => {
try jsw.emitString(@tagName(self.builtinField));
},
@@ -758,8 +773,8 @@ const DocData = struct {
const AutodocErrors = error{
OutOfMemory,
CurrentWorkingDirectoryUnlinked,
- Unexpected,
-};
+ UnexpectedEndOfFile,
+} || std.fs.File.OpenError || std.fs.File.ReadError;
/// Called when we need to analyze a Zir instruction.
/// For example it gets called by `generateZirData` on instruction 0,
@@ -773,7 +788,7 @@ fn walkInstruction(
self: *Autodoc,
file: *File,
parent_scope: *Scope,
- parent_line: usize,
+ parent_src: SrcLocInfo,
inst_index: usize,
need_type: bool, // true if the caller needs us to provide also a typeRef
) AutodocErrors!DocData.WalkResult {
@@ -865,7 +880,7 @@ fn walkInstruction(
return self.walkInstruction(
new_file,
&root_scope,
- 1,
+ .{},
Zir.main_struct_inst,
false,
);
@@ -890,14 +905,14 @@ fn walkInstruction(
return self.walkInstruction(
new_file.file,
&new_scope,
- 1,
+ .{},
Zir.main_struct_inst,
need_type,
);
},
.ret_node => {
const un_node = data[inst_index].un_node;
- return self.walkRef(file, parent_scope, parent_line, un_node.operand, false);
+ return self.walkRef(file, parent_scope, parent_src, un_node.operand, false);
},
.ret_load => {
const un_node = data[inst_index].un_node;
@@ -928,7 +943,7 @@ fn walkInstruction(
}
if (result_ref) |rr| {
- return self.walkRef(file, parent_scope, parent_line, rr, need_type);
+ return self.walkRef(file, parent_scope, parent_src, rr, need_type);
}
return DocData.WalkResult{
@@ -937,11 +952,11 @@ fn walkInstruction(
},
.closure_get => {
const inst_node = data[inst_index].inst_node;
- return try self.walkInstruction(file, parent_scope, parent_line, inst_node.inst, need_type);
+ return try self.walkInstruction(file, parent_scope, parent_src, inst_node.inst, need_type);
},
.closure_capture => {
const un_tok = data[inst_index].un_tok;
- return try self.walkRef(file, parent_scope, parent_line, un_tok.operand, need_type);
+ return try self.walkRef(file, parent_scope, parent_src, un_tok.operand, need_type);
},
.cmpxchg_strong, .cmpxchg_weak => {
const pl_node = data[inst_index].pl_node;
@@ -956,7 +971,7 @@ fn walkInstruction(
var ptr: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.ptr,
false,
);
@@ -966,7 +981,7 @@ fn walkInstruction(
var expected_value: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.expected_value,
false,
);
@@ -976,7 +991,7 @@ fn walkInstruction(
var new_value: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.new_value,
false,
);
@@ -986,7 +1001,7 @@ fn walkInstruction(
var success_order: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.success_order,
false,
);
@@ -996,7 +1011,7 @@ fn walkInstruction(
var failure_order: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.failure_order,
false,
);
@@ -1047,10 +1062,11 @@ fn walkInstruction(
},
.compile_error => {
const un_node = data[inst_index].un_node;
+
var operand: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
un_node.operand,
false,
);
@@ -1084,15 +1100,24 @@ fn walkInstruction(
},
.int_big => {
// @check
- const str = data[inst_index].str.get(file.zir);
- _ = str;
- printWithContext(
- file,
- inst_index,
- "TODO: implement `{s}` for walkInstruction\n\n",
- .{@tagName(tags[inst_index])},
- );
- return self.cteTodo(@tagName(tags[inst_index]));
+ const str = data[inst_index].str; //.get(file.zir);
+ const byte_count = str.len * @sizeOf(std.math.big.Limb);
+ const limb_bytes = file.zir.string_bytes[str.start..][0..byte_count];
+
+ var limbs = try self.arena.alloc(std.math.big.Limb, str.len);
+ std.mem.copy(u8, std.mem.sliceAsBytes(limbs), limb_bytes);
+
+ const big_int = std.math.big.int.Const{
+ .limbs = limbs,
+ .positive = true,
+ };
+
+ const as_string = try big_int.toStringAlloc(self.arena, 10, .lower);
+
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
+ .expr = .{ .int_big = .{ .value = as_string } },
+ };
},
.slice_start => {
@@ -1105,14 +1130,14 @@ fn walkInstruction(
var lhs: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.lhs,
false,
);
var start: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.start,
false,
);
@@ -1138,21 +1163,21 @@ fn walkInstruction(
var lhs: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.lhs,
false,
);
var start: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.start,
false,
);
var end: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.end,
false,
);
@@ -1180,28 +1205,28 @@ fn walkInstruction(
var lhs: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.lhs,
false,
);
var start: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.start,
false,
);
var end: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.end,
false,
);
var sentinel: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.sentinel,
false,
);
@@ -1251,14 +1276,14 @@ fn walkInstruction(
var lhs: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.lhs,
false,
);
var rhs: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.rhs,
false,
);
@@ -1278,6 +1303,50 @@ fn walkInstruction(
.expr = .{ .binOpIndex = binop_index },
};
},
+ // compare operators
+ .cmp_eq,
+ .cmp_neq,
+ .cmp_gt,
+ .cmp_gte,
+ .cmp_lt,
+ .cmp_lte,
+ => {
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
+
+ const binop_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, .{ .binOp = .{ .lhs = 0, .rhs = 0 } });
+
+ var lhs: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ parent_src,
+ extra.data.lhs,
+ false,
+ );
+ var rhs: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ parent_src,
+ extra.data.rhs,
+ false,
+ );
+
+ const lhs_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, lhs.expr);
+ const rhs_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, rhs.expr);
+ self.exprs.items[binop_index] = .{ .binOp = .{
+ .name = @tagName(tags[inst_index]),
+ .lhs = lhs_index,
+ .rhs = rhs_index,
+ } };
+
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.bool_type) },
+ .expr = .{ .binOpIndex = binop_index },
+ };
+ },
// builtin functions
.align_of,
@@ -1319,7 +1388,7 @@ fn walkInstruction(
const un_node = data[inst_index].un_node;
const bin_index = self.exprs.items.len;
try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } });
- const param = try self.walkRef(file, parent_scope, parent_line, un_node.operand, false);
+ const param = try self.walkRef(file, parent_scope, parent_src, un_node.operand, false);
const param_index = self.exprs.items.len;
try self.exprs.append(self.arena, param.expr);
@@ -1368,14 +1437,14 @@ fn walkInstruction(
var lhs: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.lhs,
false,
);
var rhs: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.rhs,
false,
);
@@ -1398,14 +1467,14 @@ fn walkInstruction(
var lhs: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.lhs,
false,
);
var rhs: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.rhs,
false,
);
@@ -1428,14 +1497,14 @@ fn walkInstruction(
var lhs: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.lhs,
false,
);
var rhs: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.rhs,
false,
);
@@ -1455,7 +1524,7 @@ fn walkInstruction(
// var operand: DocData.WalkResult = try self.walkRef(
// file,
- // parent_scope, parent_line,
+ // parent_scope, parent_src,
// un_node.operand,
// false,
// );
@@ -1464,7 +1533,8 @@ fn walkInstruction(
// },
.overflow_arithmetic_ptr => {
const un_node = data[inst_index].un_node;
- const elem_type_ref = try self.walkRef(file, parent_scope, parent_line, un_node.operand, false);
+
+ const elem_type_ref = try self.walkRef(file, parent_scope, parent_src, un_node.operand, false);
const type_slot_index = self.types.items.len;
try self.types.append(self.arena, .{
.Pointer = .{
@@ -1489,7 +1559,7 @@ fn walkInstruction(
const elem_type_ref = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.elem_type,
false,
);
@@ -1499,7 +1569,7 @@ fn walkInstruction(
var sentinel: ?DocData.Expr = null;
if (ptr.flags.has_sentinel) {
const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
- const ref_result = try self.walkRef(file, parent_scope, parent_line, ref, false);
+ const ref_result = try self.walkRef(file, parent_scope, parent_src, ref, false);
sentinel = ref_result.expr;
extra_index += 1;
}
@@ -1507,21 +1577,21 @@ fn walkInstruction(
var @"align": ?DocData.Expr = null;
if (ptr.flags.has_align) {
const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
- const ref_result = try self.walkRef(file, parent_scope, parent_line, ref, false);
+ const ref_result = try self.walkRef(file, parent_scope, parent_src, ref, false);
@"align" = ref_result.expr;
extra_index += 1;
}
var address_space: ?DocData.Expr = null;
if (ptr.flags.has_addrspace) {
const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
- const ref_result = try self.walkRef(file, parent_scope, parent_line, ref, false);
+ const ref_result = try self.walkRef(file, parent_scope, parent_src, ref, false);
address_space = ref_result.expr;
extra_index += 1;
}
var bit_start: ?DocData.Expr = null;
if (ptr.flags.has_bit_range) {
const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
- const ref_result = try self.walkRef(file, parent_scope, parent_line, ref, false);
+ const ref_result = try self.walkRef(file, parent_scope, parent_src, ref, false);
address_space = ref_result.expr;
extra_index += 1;
}
@@ -1529,7 +1599,7 @@ fn walkInstruction(
var host_size: ?DocData.Expr = null;
if (ptr.flags.has_bit_range) {
const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
- const ref_result = try self.walkRef(file, parent_scope, parent_line, ref, false);
+ const ref_result = try self.walkRef(file, parent_scope, parent_src, ref, false);
host_size = ref_result.expr;
}
@@ -1558,9 +1628,10 @@ fn walkInstruction(
},
.array_type => {
const pl_node = data[inst_index].pl_node;
+
const bin = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index).data;
- const len = try self.walkRef(file, parent_scope, parent_line, bin.lhs, false);
- const child = try self.walkRef(file, parent_scope, parent_line, bin.rhs, false);
+ const len = try self.walkRef(file, parent_scope, parent_src, bin.lhs, false);
+ const child = try self.walkRef(file, parent_scope, parent_src, bin.rhs, false);
const type_slot_index = self.types.items.len;
try self.types.append(self.arena, .{
@@ -1578,9 +1649,9 @@ fn walkInstruction(
.array_type_sentinel => {
const pl_node = data[inst_index].pl_node;
const extra = file.zir.extraData(Zir.Inst.ArrayTypeSentinel, pl_node.payload_index);
- const len = try self.walkRef(file, parent_scope, parent_line, extra.data.len, false);
- const sentinel = try self.walkRef(file, parent_scope, parent_line, extra.data.sentinel, false);
- const elem_type = try self.walkRef(file, parent_scope, parent_line, extra.data.elem_type, false);
+ const len = try self.walkRef(file, parent_scope, parent_src, extra.data.len, false);
+ const sentinel = try self.walkRef(file, parent_scope, parent_src, extra.data.sentinel, false);
+ const elem_type = try self.walkRef(file, parent_scope, parent_src, extra.data.elem_type, false);
const type_slot_index = self.types.items.len;
try self.types.append(self.arena, .{
@@ -1602,10 +1673,10 @@ fn walkInstruction(
const array_data = try self.arena.alloc(usize, operands.len - 1);
std.debug.assert(operands.len > 0);
- var array_type = try self.walkRef(file, parent_scope, parent_line, operands[0], false);
+ var array_type = try self.walkRef(file, parent_scope, parent_src, operands[0], false);
for (operands[1..]) |op, idx| {
- const wr = try self.walkRef(file, parent_scope, parent_line, op, false);
+ const wr = try self.walkRef(file, parent_scope, parent_src, op, false);
const expr_index = self.exprs.items.len;
try self.exprs.append(self.arena, wr.expr);
array_data[idx] = expr_index;
@@ -1623,7 +1694,7 @@ fn walkInstruction(
const array_data = try self.arena.alloc(usize, operands.len);
for (operands) |op, idx| {
- const wr = try self.walkRef(file, parent_scope, parent_line, op, false);
+ const wr = try self.walkRef(file, parent_scope, parent_src, op, false);
const expr_index = self.exprs.items.len;
try self.exprs.append(self.arena, wr.expr);
array_data[idx] = expr_index;
@@ -1641,10 +1712,10 @@ fn walkInstruction(
const array_data = try self.arena.alloc(usize, operands.len - 1);
std.debug.assert(operands.len > 0);
- var array_type = try self.walkRef(file, parent_scope, parent_line, operands[0], false);
+ var array_type = try self.walkRef(file, parent_scope, parent_src, operands[0], false);
for (operands[1..]) |op, idx| {
- const wr = try self.walkRef(file, parent_scope, parent_line, op, false);
+ const wr = try self.walkRef(file, parent_scope, parent_src, op, false);
const expr_index = self.exprs.items.len;
try self.exprs.append(self.arena, wr.expr);
array_data[idx] = expr_index;
@@ -1673,7 +1744,7 @@ fn walkInstruction(
const array_data = try self.arena.alloc(usize, operands.len);
for (operands) |op, idx| {
- const wr = try self.walkRef(file, parent_scope, parent_line, op, false);
+ const wr = try self.walkRef(file, parent_scope, parent_src, op, false);
const expr_index = self.exprs.items.len;
try self.exprs.append(self.arena, wr.expr);
array_data[idx] = expr_index;
@@ -1705,15 +1776,17 @@ fn walkInstruction(
},
.negate => {
const un_node = data[inst_index].un_node;
+
var operand: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
un_node.operand,
need_type,
);
switch (operand.expr) {
.int => |*int| int.negated = true,
+ .int_big => |*int_big| int_big.negated = true,
else => {
printWithContext(
file,
@@ -1727,10 +1800,11 @@ fn walkInstruction(
},
.size_of => {
const un_node = data[inst_index].un_node;
+
const operand = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
un_node.operand,
false,
);
@@ -1744,10 +1818,11 @@ fn walkInstruction(
.bit_size_of => {
// not working correctly with `align()`
const un_node = data[inst_index].un_node;
+
const operand = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
un_node.operand,
need_type,
);
@@ -1765,7 +1840,7 @@ fn walkInstruction(
const operand = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
un_node.operand,
false,
);
@@ -1782,7 +1857,8 @@ fn walkInstruction(
const pl_node = data[inst_index].pl_node;
const extra = file.zir.extraData(Zir.Inst.SwitchBlock, pl_node.payload_index);
const cond_index = self.exprs.items.len;
- _ = try self.walkRef(file, parent_scope, parent_line, extra.data.operand, false);
+
+ _ = try self.walkRef(file, parent_scope, parent_src, extra.data.operand, false);
const ast_index = self.ast_nodes.items.len;
const type_index = self.types.items.len - 1;
@@ -1810,7 +1886,7 @@ fn walkInstruction(
const operand = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
un_node.operand,
need_type,
);
@@ -1833,10 +1909,11 @@ fn walkInstruction(
.typeof => {
const un_node = data[inst_index].un_node;
+
const operand = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
un_node.operand,
need_type,
);
@@ -1852,11 +1929,10 @@ fn walkInstruction(
const pl_node = data[inst_index].pl_node;
const extra = file.zir.extraData(Zir.Inst.Block, pl_node.payload_index);
const body = file.zir.extra[extra.end..][extra.data.body_len - 1];
-
var operand: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
data[body].@"break".operand,
false,
);
@@ -1872,10 +1948,11 @@ fn walkInstruction(
.type_info => {
// @check
const un_node = data[inst_index].un_node;
+
const operand = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
un_node.operand,
need_type,
);
@@ -1894,7 +1971,7 @@ fn walkInstruction(
const dest_type_walk = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.dest_type,
false,
);
@@ -1902,7 +1979,7 @@ fn walkInstruction(
const operand = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
extra.data.operand,
false,
);
@@ -1927,10 +2004,11 @@ fn walkInstruction(
},
.optional_type => {
const un_node = data[inst_index].un_node;
+
const operand: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
un_node.operand,
false,
);
@@ -2014,7 +2092,7 @@ fn walkInstruction(
}
}
- break :blk try self.walkRef(file, parent_scope, parent_line, lhs_ref, false);
+ break :blk try self.walkRef(file, parent_scope, parent_src, lhs_ref, false);
};
try path.append(self.arena, wr.expr);
@@ -2065,7 +2143,7 @@ fn walkInstruction(
return self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
getBlockInlineBreak(file.zir, inst_index),
need_type,
);
@@ -2092,13 +2170,18 @@ fn walkInstruction(
Zir.Inst.FieldType,
field_pl_node.payload_index,
);
+ const field_src = try self.srcLocInfo(
+ file,
+ field_pl_node.src_node,
+ parent_src,
+ );
// On first iteration use field info to find out the struct type
if (idx == extra.end) {
const wr = try self.walkRef(
file,
parent_scope,
- parent_line,
+ field_src,
field_extra.data.container_type,
false,
);
@@ -2109,7 +2192,7 @@ fn walkInstruction(
const value = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
init_extra.data.init,
need_type,
);
@@ -2123,10 +2206,11 @@ fn walkInstruction(
},
.struct_init_empty => {
const un_node = data[inst_index].un_node;
+
var operand: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
un_node.operand,
false,
);
@@ -2159,7 +2243,7 @@ fn walkInstruction(
const value = try self.walkRef(
file,
parent_scope,
- parent_line,
+ parent_src,
init_extra.data.init,
need_type,
);
@@ -2235,7 +2319,7 @@ fn walkInstruction(
const pl_node = data[inst_index].pl_node;
const extra = file.zir.extraData(Zir.Inst.Call, pl_node.payload_index);
- const callee = try self.walkRef(file, parent_scope, parent_line, extra.data.callee, need_type);
+ const callee = try self.walkRef(file, parent_scope, parent_src, extra.data.callee, need_type);
const args_len = extra.data.flags.args_len;
var args = try self.arena.alloc(DocData.Expr, args_len);
@@ -2250,7 +2334,7 @@ fn walkInstruction(
// to show discrepancies between the types of provided
// arguments and the types declared in the function
// signature for its parameters.
- const wr = try self.walkRef(file, parent_scope, parent_line, ref, false);
+ const wr = try self.walkRef(file, parent_scope, parent_src, ref, false);
args[i] = wr.expr;
}
@@ -2281,7 +2365,7 @@ fn walkInstruction(
const result = self.analyzeFunction(
file,
parent_scope,
- parent_line,
+ parent_src,
inst_index,
self_ast_node_index,
type_slot_index,
@@ -2297,7 +2381,7 @@ fn walkInstruction(
const result = self.analyzeFancyFunction(
file,
parent_scope,
- parent_line,
+ parent_src,
inst_index,
self_ast_node_index,
type_slot_index,
@@ -2325,7 +2409,7 @@ fn walkInstruction(
var array_type: ?DocData.Expr = null;
for (args) |arg, idx| {
- const wr = try self.walkRef(file, parent_scope, parent_line, arg, idx == 0);
+ const wr = try self.walkRef(file, parent_scope, parent_src, arg, idx == 0);
if (idx == 0) {
array_type = wr.typeRef;
}
@@ -2355,36 +2439,91 @@ fn walkInstruction(
return result;
},
.opaque_decl => {
+ const type_slot_index = self.types.items.len;
+ try self.types.append(self.arena, .{ .Unanalyzed = .{} });
+
+ var scope: Scope = .{
+ .parent = parent_scope,
+ .enclosing_type = type_slot_index,
+ };
+
const small = @bitCast(Zir.Inst.OpaqueDecl.Small, extended.small);
var extra_index: usize = extended.operand;
+
const src_node: ?i32 = if (small.has_src_node) blk: {
const src_node = @bitCast(i32, file.zir.extra[extra_index]);
extra_index += 1;
break :blk src_node;
} else null;
- _ = src_node;
+
+ const src_info = if (src_node) |sn|
+ try self.srcLocInfo(file, sn, parent_src)
+ else
+ parent_src;
+ _ = src_info;
const decls_len = if (small.has_decls_len) blk: {
const decls_len = file.zir.extra[extra_index];
extra_index += 1;
break :blk decls_len;
} else 0;
- _ = decls_len;
-
- const decls_bits = file.zir.extra[extra_index];
- _ = decls_bits;
-
- // const sep = "=" ** 200;
- // log.debug("{s}", .{sep});
- // log.debug("small = {any}", .{small});
- // log.debug("src_node = {}", .{src_node});
- // log.debug("decls_len = {}", .{decls_len});
- // log.debug("decls_bit = {}", .{decls_bits});
- // log.debug("{s}", .{sep});
- const type_slot_index = self.types.items.len - 1;
- try self.types.append(self.arena, .{ .Opaque = .{ .name = "TODO" } });
+
+ var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
+ var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
+
+ const decls_first_index = self.decls.items.len;
+ // Decl name lookahead for reserving slots in `scope` (and `decls`).
+ // Done to make sure that all decl refs can be resolved correctly,
+ // even if we haven't fully analyzed the decl yet.
+ {
+ var it = file.zir.declIterator(@intCast(u32, inst_index));
+ try self.decls.resize(self.arena, decls_first_index + it.decls_len);
+ for (self.decls.items[decls_first_index..]) |*slot| {
+ slot._analyzed = false;
+ }
+ var decls_slot_index = decls_first_index;
+ while (it.next()) |d| : (decls_slot_index += 1) {
+ const decl_name_index = file.zir.extra[d.sub_index + 5];
+ try scope.insertDeclRef(self.arena, decl_name_index, decls_slot_index);
+ }
+ }
+
+ extra_index = try self.walkDecls(
+ file,
+ &scope,
+ src_info,
+ decls_first_index,
+ decls_len,
+ &decl_indexes,
+ &priv_decl_indexes,
+ extra_index,
+ );
+
+ self.types.items[type_slot_index] = .{
+ .Opaque = .{
+ .name = "todo_name",
+ .src = self_ast_node_index,
+ .privDecls = priv_decl_indexes.items,
+ .pubDecls = decl_indexes.items,
+ .ast = self_ast_node_index,
+ },
+ };
+ if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
+ for (paths.items) |resume_info| {
+ try self.tryResolveRefPath(
+ resume_info.file,
+ inst_index,
+ resume_info.ref_path,
+ );
+ }
+
+ _ = self.ref_paths_pending_on_types.remove(type_slot_index);
+ // TODO: we should deallocate the arraylist that holds all the
+ // decl paths. not doing it now since it's arena-allocated
+ // anyway, but maybe we should put it elsewhere.
+ }
return DocData.WalkResult{
- .typeRef = .{ .type = @enumToInt(Ref.anyopaque_type) },
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
.expr = .{ .type = type_slot_index },
};
},
@@ -2419,7 +2558,11 @@ fn walkInstruction(
extra_index += 1;
break :blk src_node;
} else null;
- _ = src_node;
+
+ const src_info = if (src_node) |sn|
+ try self.srcLocInfo(file, sn, parent_src)
+ else
+ parent_src;
const tag_type: ?Ref = if (small.has_tag_type) blk: {
const tag_type = file.zir.extra[extra_index];
@@ -2470,7 +2613,7 @@ fn walkInstruction(
extra_index = try self.walkDecls(
file,
&scope,
- parent_line,
+ src_info,
decls_first_index,
decls_len,
&decl_indexes,
@@ -2491,7 +2634,7 @@ fn walkInstruction(
try self.collectUnionFieldInfo(
file,
&scope,
- parent_line,
+ src_info,
fields_len,
&field_type_refs,
&field_name_indexes,
@@ -2541,7 +2684,11 @@ fn walkInstruction(
extra_index += 1;
break :blk src_node;
} else null;
- _ = src_node;
+
+ const src_info = if (src_node) |sn|
+ try self.srcLocInfo(file, sn, parent_src)
+ else
+ parent_src;
const tag_type: ?Ref = if (small.has_tag_type) blk: {
const tag_type = file.zir.extra[extra_index];
@@ -2592,7 +2739,7 @@ fn walkInstruction(
extra_index = try self.walkDecls(
file,
&scope,
- parent_line,
+ src_info,
decls_first_index,
decls_len,
&decl_indexes,
@@ -2687,7 +2834,11 @@ fn walkInstruction(
extra_index += 1;
break :blk src_node;
} else null;
- _ = src_node;
+
+ const src_info = if (src_node) |sn|
+ try self.srcLocInfo(file, sn, parent_src)
+ else
+ parent_src;
const fields_len = if (small.has_fields_len) blk: {
const fields_len = file.zir.extra[extra_index];
@@ -2736,7 +2887,7 @@ fn walkInstruction(
extra_index = try self.walkDecls(
file,
&scope,
- parent_line,
+ src_info,
decls_first_index,
decls_len,
&decl_indexes,
@@ -2749,7 +2900,7 @@ fn walkInstruction(
try self.collectStructFieldInfo(
file,
&scope,
- parent_line,
+ src_info,
fields_len,
&field_type_refs,
&field_name_indexes,
@@ -2793,7 +2944,7 @@ fn walkInstruction(
const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data;
const bin_index = self.exprs.items.len;
try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } });
- const param = try self.walkRef(file, parent_scope, parent_line, extra.operand, false);
+ const param = try self.walkRef(file, parent_scope, parent_src, extra.operand, false);
const param_index = self.exprs.items.len;
try self.exprs.append(self.arena, param.expr);
@@ -2821,13 +2972,14 @@ fn walkDecls(
self: *Autodoc,
file: *File,
scope: *Scope,
- parent_line: usize,
+ parent_src: SrcLocInfo,
decls_first_index: usize,
decls_len: u32,
decl_indexes: *std.ArrayListUnmanaged(usize),
priv_decl_indexes: *std.ArrayListUnmanaged(usize),
extra_start: usize,
) AutodocErrors!usize {
+ const data = file.zir.instructions.items(.data);
const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable;
var extra_index = extra_start + bit_bags_count;
var bit_bag_index: usize = extra_start;
@@ -2854,7 +3006,8 @@ fn walkDecls(
// const hash_u32s = file.zir.extra[extra_index..][0..4];
extra_index += 4;
- const line = parent_line + file.zir.extra[extra_index];
+
+ // const line = file.zir.extra[extra_index];
extra_index += 1;
const decl_name_index = file.zir.extra[extra_index];
extra_index += 1;
@@ -2884,10 +3037,11 @@ fn walkDecls(
};
_ = addrspace_inst;
- // const pub_str = if (is_pub) "pub " else "";
- // const hash_bytes = @bitCast([16]u8, hash_u32s.*);
+ // This is known to work because decl values are always block_inlines
+ const value_pl_node = data[value_index].pl_node;
+ const decl_src = try self.srcLocInfo(file, value_pl_node.src_node, parent_src);
- var is_test = false; // we discover if it's a test by lookin at its name
+ var is_test = false; // we discover if it's a test by looking at its name
const name: []const u8 = blk: {
if (decl_name_index == 0) {
break :blk if (is_exported) "usingnamespace" else "comptime";
@@ -2895,84 +3049,32 @@ fn walkDecls(
is_test = true;
break :blk "test";
} else if (decl_name_index == 2) {
- is_test = true;
- // TODO: remove temporary hack
- break :blk "test";
- // // it is a decltest
- // const decl_being_tested = scope.resolveDeclName(doc_comment_index);
- // const ast_node_index = idx: {
- // const idx = self.ast_nodes.items.len;
- // const file_source = file.getSource(self.module.gpa) catch unreachable; // TODO fix this
- // const source_of_decltest_function = srcloc: {
- // const func_index = getBlockInlineBreak(file.zir, value_index);
- // // a decltest is always a function
- // const tag = file.zir.instructions.items(.tag)[Zir.refToIndex(func_index).?];
- // std.debug.assert(tag == .func_extended);
-
- // const pl_node = file.zir.instructions.items(.data)[Zir.refToIndex(func_index).?].pl_node;
- // const extra = file.zir.extraData(Zir.Inst.ExtendedFunc, pl_node.payload_index);
- // const bits = @bitCast(Zir.Inst.ExtendedFunc.Bits, extra.data.bits);
-
- // var extra_index_for_this_func: usize = extra.end;
- // if (bits.has_lib_name) extra_index_for_this_func += 1;
- // if (bits.has_cc) extra_index_for_this_func += 1;
- // if (bits.has_align) extra_index_for_this_func += 1;
-
- // const ret_ty_body = file.zir.extra[extra_index_for_this_func..][0..extra.data.ret_body_len];
- // extra_index_for_this_func += ret_ty_body.len;
-
- // const body = file.zir.extra[extra_index_for_this_func..][0..extra.data.body_len];
- // extra_index_for_this_func += body.len;
-
- // var src_locs: Zir.Inst.Func.SrcLocs = undefined;
- // if (body.len != 0) {
- // src_locs = file.zir.extraData(Zir.Inst.Func.SrcLocs, extra_index_for_this_func).data;
- // } else {
- // src_locs = .{
- // .lbrace_line = line,
- // .rbrace_line = line,
- // .columns = 0, // TODO get columns when body.len == 0
- // };
- // }
- // break :srcloc src_locs;
- // };
- // const source_slice = slice: {
- // var start_byte_offset: u32 = 0;
- // var end_byte_offset: u32 = 0;
- // const rbrace_col = @truncate(u16, source_of_decltest_function.columns >> 16);
- // var lines: u32 = 0;
- // for (file_source.bytes) |b, i| {
- // if (b == '\n') {
- // lines += 1;
- // }
- // if (lines == source_of_decltest_function.lbrace_line) {
- // start_byte_offset = @intCast(u32, i);
- // }
- // if (lines == source_of_decltest_function.rbrace_line) {
- // end_byte_offset = @intCast(u32, i) + rbrace_col;
- // break;
- // }
- // }
- // break :slice file_source.bytes[start_byte_offset..end_byte_offset];
- // };
- // try self.ast_nodes.append(self.arena, .{
- // .file = 0,
- // .line = line,
- // .col = 0,
- // .name = try self.arena.dupe(u8, source_slice),
- // });
- // break :idx idx;
- // };
- // self.decls.items[decl_being_tested].decltest = ast_node_index;
- // self.decls.items[decls_slot_index] = .{
- // ._analyzed = true,
- // .name = "test",
- // .isTest = true,
- // .src = ast_node_index,
- // .value = .{ .expr = .{ .type = 0 } },
- // .kind = "const",
- // };
- // continue;
+ // it is a decltest
+ const decl_being_tested = scope.resolveDeclName(doc_comment_index);
+ const func_index = getBlockInlineBreak(file.zir, value_index);
+
+ const pl_node = data[Zir.refToIndex(func_index).?].pl_node;
+ const fn_src = try self.srcLocInfo(file, pl_node.src_node, decl_src);
+ const tree = try file.getTree(self.module.gpa);
+ const test_source_code = tree.getNodeSource(fn_src.src_node);
+
+ const ast_node_index = self.ast_nodes.items.len;
+ try self.ast_nodes.append(self.arena, .{
+ .file = 0,
+ .line = 0,
+ .col = 0,
+ .code = test_source_code,
+ });
+ self.decls.items[decl_being_tested].decltest = ast_node_index;
+ self.decls.items[decls_slot_index] = .{
+ ._analyzed = true,
+ .name = "test",
+ .isTest = true,
+ .src = ast_node_index,
+ .value = .{ .expr = .{ .type = 0 } },
+ .kind = "const",
+ };
+ continue;
} else {
const raw_decl_name = file.zir.nullTerminatedString(decl_name_index);
if (raw_decl_name.len == 0) {
@@ -2993,8 +3095,8 @@ fn walkDecls(
const ast_node_index = idx: {
const idx = self.ast_nodes.items.len;
try self.ast_nodes.append(self.arena, .{
- .file = self.files.getIndex(file) orelse unreachable,
- .line = line,
+ .file = self.files.getIndex(file).?,
+ .line = decl_src.line,
.col = 0,
.docs = doc_comment,
.fields = null, // walkInstruction will fill `fields` if necessary
@@ -3005,7 +3107,7 @@ fn walkDecls(
const walk_result = if (is_test) // TODO: decide if tests should show up at all
DocData.WalkResult{ .expr = .{ .void = .{} } }
else
- try self.walkInstruction(file, scope, line, value_index, true);
+ try self.walkInstruction(file, scope, decl_src, value_index, true);
if (is_pub) {
try decl_indexes.append(self.arena, decls_slot_index);
@@ -3381,6 +3483,37 @@ fn tryResolveRefPath(
path[i + 1] = (try self.cteTodo(child_string)).expr;
continue :outer;
},
+ .Opaque => |t_opaque| {
+ for (t_opaque.pubDecls) |d| {
+ // TODO: this could be improved a lot
+ // by having our own string table!
+ const decl = self.decls.items[d];
+ if (std.mem.eql(u8, decl.name, child_string)) {
+ path[i + 1] = .{ .declRef = d };
+ continue :outer;
+ }
+ }
+ for (t_opaque.privDecls) |d| {
+ // TODO: this could be improved a lot
+ // by having our own string table!
+ const decl = self.decls.items[d];
+ if (std.mem.eql(u8, decl.name, child_string)) {
+ path[i + 1] = .{ .declRef = d };
+ continue :outer;
+ }
+ }
+
+ // if we got here, our search failed
+ printWithContext(
+ file,
+ inst_index,
+ "failed to match `{s}` in opaque",
+ .{child_string},
+ );
+
+ path[i + 1] = (try self.cteTodo("match failure")).expr;
+ continue :outer;
+ },
},
}
}
@@ -3401,7 +3534,7 @@ fn analyzeFancyFunction(
self: *Autodoc,
file: *File,
scope: *Scope,
- parent_line: usize,
+ parent_src: SrcLocInfo,
inst_index: usize,
self_ast_node_index: usize,
type_slot_index: usize,
@@ -3466,7 +3599,7 @@ fn analyzeFancyFunction(
const break_index = file.zir.extra[extra.end..][extra.data.body_len - 1];
const break_operand = data[break_index].@"break".operand;
- const param_type_ref = try self.walkRef(file, scope, parent_line, break_operand, false);
+ const param_type_ref = try self.walkRef(file, scope, parent_src, break_operand, false);
param_type_refs.appendAssumeCapacity(param_type_ref.expr);
},
@@ -3475,8 +3608,8 @@ fn analyzeFancyFunction(
self.ast_nodes.items[self_ast_node_index].fields = param_ast_indexes.items;
- const inst_data = data[inst_index].pl_node;
- const extra = file.zir.extraData(Zir.Inst.FuncFancy, inst_data.payload_index);
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.FuncFancy, pl_node.payload_index);
var extra_index: usize = extra.end;
@@ -3490,7 +3623,7 @@ fn analyzeFancyFunction(
if (extra.data.bits.has_align_ref) {
const align_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
align_index = self.exprs.items.len;
- _ = try self.walkRef(file, scope, parent_line, align_ref, false);
+ _ = try self.walkRef(file, scope, parent_src, align_ref, false);
extra_index += 1;
} else if (extra.data.bits.has_align_body) {
const align_body_len = file.zir.extra[extra_index];
@@ -3507,7 +3640,7 @@ fn analyzeFancyFunction(
if (extra.data.bits.has_addrspace_ref) {
const addrspace_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
addrspace_index = self.exprs.items.len;
- _ = try self.walkRef(file, scope, parent_line, addrspace_ref, false);
+ _ = try self.walkRef(file, scope, parent_src, addrspace_ref, false);
extra_index += 1;
} else if (extra.data.bits.has_addrspace_body) {
const addrspace_body_len = file.zir.extra[extra_index];
@@ -3524,7 +3657,7 @@ fn analyzeFancyFunction(
if (extra.data.bits.has_section_ref) {
const section_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
section_index = self.exprs.items.len;
- _ = try self.walkRef(file, scope, parent_line, section_ref, false);
+ _ = try self.walkRef(file, scope, parent_src, section_ref, false);
extra_index += 1;
} else if (extra.data.bits.has_section_body) {
const section_body_len = file.zir.extra[extra_index];
@@ -3541,7 +3674,7 @@ fn analyzeFancyFunction(
if (extra.data.bits.has_cc_ref) {
const cc_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
cc_index = self.exprs.items.len;
- _ = try self.walkRef(file, scope, parent_line, cc_ref, false);
+ _ = try self.walkRef(file, scope, parent_src, cc_ref, false);
extra_index += 1;
} else if (extra.data.bits.has_cc_body) {
const cc_body_len = file.zir.extra[extra_index];
@@ -3560,14 +3693,14 @@ fn analyzeFancyFunction(
.none => DocData.Expr{ .void = .{} },
else => blk: {
const ref = fn_info.ret_ty_ref;
- const wr = try self.walkRef(file, scope, parent_line, ref, false);
+ const wr = try self.walkRef(file, scope, parent_src, ref, false);
break :blk wr.expr;
},
},
else => blk: {
const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1];
const break_operand = data[last_instr_index].@"break".operand;
- const wr = try self.walkRef(file, scope, parent_line, break_operand, false);
+ const wr = try self.walkRef(file, scope, parent_src, break_operand, false);
break :blk wr.expr;
},
};
@@ -3582,7 +3715,7 @@ fn analyzeFancyFunction(
break :blk try self.getGenericReturnType(
file,
scope,
- parent_line,
+ parent_src,
fn_info.body[fn_info.body.len - 1],
);
} else {
@@ -3619,7 +3752,7 @@ fn analyzeFunction(
self: *Autodoc,
file: *File,
scope: *Scope,
- parent_line: usize,
+ parent_src: SrcLocInfo,
inst_index: usize,
self_ast_node_index: usize,
type_slot_index: usize,
@@ -3685,7 +3818,7 @@ fn analyzeFunction(
const break_index = file.zir.extra[extra.end..][extra.data.body_len - 1];
const break_operand = data[break_index].@"break".operand;
- const param_type_ref = try self.walkRef(file, scope, parent_line, break_operand, false);
+ const param_type_ref = try self.walkRef(file, scope, parent_src, break_operand, false);
param_type_refs.appendAssumeCapacity(param_type_ref.expr);
},
@@ -3698,14 +3831,14 @@ fn analyzeFunction(
.none => DocData.Expr{ .void = .{} },
else => blk: {
const ref = fn_info.ret_ty_ref;
- const wr = try self.walkRef(file, scope, parent_line, ref, false);
+ const wr = try self.walkRef(file, scope, parent_src, ref, false);
break :blk wr.expr;
},
},
else => blk: {
const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1];
const break_operand = data[last_instr_index].@"break".operand;
- const wr = try self.walkRef(file, scope, parent_line, break_operand, false);
+ const wr = try self.walkRef(file, scope, parent_src, break_operand, false);
break :blk wr.expr;
},
};
@@ -3720,7 +3853,7 @@ fn analyzeFunction(
break :blk try self.getGenericReturnType(
file,
scope,
- parent_line,
+ parent_src,
fn_info.body[fn_info.body.len - 1],
);
} else {
@@ -3761,11 +3894,11 @@ fn getGenericReturnType(
self: *Autodoc,
file: *File,
scope: *Scope,
- parent_line: usize, // function decl line
+ parent_src: SrcLocInfo, // function decl line
body_end: usize,
) !DocData.Expr {
// TODO: compute the correct line offset
- const wr = try self.walkInstruction(file, scope, parent_line, body_end, false);
+ const wr = try self.walkInstruction(file, scope, parent_src, body_end, false);
return wr.expr;
}
@@ -3773,7 +3906,7 @@ fn collectUnionFieldInfo(
self: *Autodoc,
file: *File,
scope: *Scope,
- parent_line: usize,
+ parent_src: SrcLocInfo,
fields_len: usize,
field_type_refs: *std.ArrayListUnmanaged(DocData.Expr),
field_name_indexes: *std.ArrayListUnmanaged(usize),
@@ -3820,7 +3953,7 @@ fn collectUnionFieldInfo(
// type
{
- const walk_result = try self.walkRef(file, scope, parent_line, field_type, false);
+ const walk_result = try self.walkRef(file, scope, parent_src, field_type, false);
try field_type_refs.append(self.arena, walk_result.expr);
}
@@ -3843,7 +3976,7 @@ fn collectStructFieldInfo(
self: *Autodoc,
file: *File,
scope: *Scope,
- parent_line: usize,
+ parent_src: SrcLocInfo,
fields_len: usize,
field_type_refs: *std.ArrayListUnmanaged(DocData.Expr),
field_name_indexes: *std.ArrayListUnmanaged(usize),
@@ -3917,7 +4050,7 @@ fn collectStructFieldInfo(
for (fields) |field| {
const type_expr = expr: {
if (field.type_ref != .none) {
- const walk_result = try self.walkRef(file, scope, parent_line, field.type_ref, false);
+ const walk_result = try self.walkRef(file, scope, parent_src, field.type_ref, false);
break :expr walk_result.expr;
}
@@ -3927,7 +4060,7 @@ fn collectStructFieldInfo(
const break_inst = body[body.len - 1];
const operand = data[break_inst].@"break".operand;
- const walk_result = try self.walkRef(file, scope, parent_line, operand, false);
+ const walk_result = try self.walkRef(file, scope, parent_src, operand, false);
break :expr walk_result.expr;
};
@@ -3957,7 +4090,7 @@ fn walkRef(
self: *Autodoc,
file: *File,
parent_scope: *Scope,
- parent_line: usize,
+ parent_src: SrcLocInfo,
ref: Ref,
need_type: bool, // true when the caller needs also a typeRef for the return value
) AutodocErrors!DocData.WalkResult {
@@ -4069,7 +4202,7 @@ fn walkRef(
}
} else {
const zir_index = enum_value - Ref.typed_value_map.len;
- return self.walkInstruction(file, parent_scope, parent_line, zir_index, need_type);
+ return self.walkInstruction(file, parent_scope, parent_src, zir_index, need_type);
}
}
@@ -4122,3 +4255,24 @@ fn writePackageTableToJson(
}
try jsw.endObject();
}
+
+fn srcLocInfo(
+ self: Autodoc,
+ file: *File,
+ src_node: i32,
+ parent_src: SrcLocInfo,
+) !SrcLocInfo {
+ const sn = @intCast(u32, @intCast(i32, parent_src.src_node) + src_node);
+ const tree = try file.getTree(self.module.gpa);
+ const node_idx = @bitCast(Ast.Node.Index, sn);
+ const tokens = tree.nodes.items(.main_token);
+
+ const tok_idx = tokens[node_idx];
+ const start = tree.tokens.items(.start)[tok_idx];
+ const loc = tree.tokenLocation(parent_src.bytes, tok_idx);
+ return SrcLocInfo{
+ .line = parent_src.line + loc.line,
+ .bytes = start,
+ .src_node = sn,
+ };
+}
diff --git a/src/Module.zig b/src/Module.zig
index 9410c4ea4a..c63fe43158 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -4635,7 +4635,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
decl.analysis = .complete;
decl.generation = mod.generation;
- const has_runtime_bits = try sema.fnHasRuntimeBits(&block_scope, ty_src, decl.ty);
+ const has_runtime_bits = try sema.fnHasRuntimeBits(decl.ty);
if (has_runtime_bits) {
// We don't fully codegen the decl until later, but we do need to reserve a global
diff --git a/src/Sema.zig b/src/Sema.zig
index 7a96fd51cd..fb1638bc2a 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -2565,7 +2565,7 @@ fn zirEnumDecl(
}
}
- if (small.nonexhaustive) {
+ if (small.nonexhaustive and enum_obj.tag_ty.zigTypeTag() != .ComptimeInt) {
if (fields_len > 1 and std.math.log2_int(u64, fields_len) == enum_obj.tag_ty.bitSize(sema.mod.getTarget())) {
return sema.fail(block, src, "non-exhaustive enum specifies every value", .{});
}
@@ -2586,6 +2586,7 @@ fn zirEnumDecl(
var cur_bit_bag: u32 = undefined;
var field_i: u32 = 0;
var last_tag_val: ?Value = null;
+ var tag_val_buf: Value.Payload.U64 = undefined;
while (field_i < fields_len) : (field_i += 1) {
if (field_i % 32 == 0) {
cur_bit_bag = sema.code.extra[bit_bag_index];
@@ -2641,6 +2642,21 @@ fn zirEnumDecl(
.ty = enum_obj.tag_ty,
.mod = mod,
});
+ } else {
+ tag_val_buf = .{
+ .base = .{ .tag = .int_u64 },
+ .data = field_i,
+ };
+ last_tag_val = Value.initPayload(&tag_val_buf.base);
+ }
+
+ if (!(try sema.intFitsInType(block, src, last_tag_val.?, enum_obj.tag_ty, null))) {
+ const tree = try sema.getAstTree(block);
+ const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i);
+ const msg = try sema.errMsg(block, field_src, "enumeration value '{}' too large for type '{}'", .{
+ last_tag_val.?.fmtValue(enum_obj.tag_ty, mod), enum_obj.tag_ty.fmt(mod),
+ });
+ return sema.failWithOwnedErrorMsg(msg);
}
}
return decl_val;
@@ -2849,7 +2865,7 @@ fn zirRetPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const inst_data = sema.code.instructions.items(.data)[inst].node;
const src = LazySrcLoc.nodeOffset(inst_data);
- if (block.is_comptime or try sema.typeRequiresComptime(block, src, sema.fn_ret_ty)) {
+ if (block.is_comptime or try sema.typeRequiresComptime(sema.fn_ret_ty)) {
const fn_ret_ty = try sema.resolveTypeFields(block, src, sema.fn_ret_ty);
return sema.analyzeComptimeAlloc(block, fn_ret_ty, 0, src);
}
@@ -5040,7 +5056,7 @@ pub fn analyzeExport(
try mod.ensureDeclAnalyzed(exported_decl_index);
const exported_decl = mod.declPtr(exported_decl_index);
- if (!sema.validateExternType(exported_decl.ty, .other)) {
+ if (!try sema.validateExternType(block, src, exported_decl.ty, .other)) {
const msg = msg: {
const msg = try sema.errMsg(block, src, "unable to export type '{}'", .{exported_decl.ty.fmt(sema.mod)});
errdefer msg.destroy(sema.gpa);
@@ -5569,7 +5585,11 @@ fn zirCall(
const param_ty_inst = try sema.addType(param_ty);
try sema.inst_map.put(sema.gpa, inst, param_ty_inst);
- resolved_args[arg_index] = try sema.resolveBody(block, args_body[arg_start..arg_end], inst);
+ const resolved = try sema.resolveBody(block, args_body[arg_start..arg_end], inst);
+ if (sema.typeOf(resolved).zigTypeTag() == .NoReturn) {
+ return resolved;
+ }
+ resolved_args[arg_index] = resolved;
}
return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src);
@@ -5768,7 +5788,7 @@ fn analyzeCall(
var is_comptime_call = block.is_comptime or modifier == .compile_time;
var comptime_only_ret_ty = false;
if (!is_comptime_call) {
- if (sema.typeRequiresComptime(block, func_src, func_ty_info.return_type)) |ct| {
+ if (sema.typeRequiresComptime(func_ty_info.return_type)) |ct| {
is_comptime_call = ct;
comptime_only_ret_ty = ct;
} else |err| switch (err) {
@@ -6047,7 +6067,7 @@ fn analyzeCall(
break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges);
};
- if (!is_comptime_call) {
+ if (!is_comptime_call and sema.typeOf(result).zigTypeTag() != .NoReturn) {
try sema.emitDbgInline(
block,
module_fn,
@@ -6206,7 +6226,7 @@ fn analyzeInlineCallArg(
const param_ty = try sema.analyzeAsType(param_block, param_src, param_ty_inst);
new_fn_info.param_types[arg_i.*] = param_ty;
const uncasted_arg = uncasted_args[arg_i.*];
- if (try sema.typeRequiresComptime(arg_block, arg_src, param_ty)) {
+ if (try sema.typeRequiresComptime(param_ty)) {
_ = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime only type must be comptime known") catch |err| {
if (err == error.AnalysisFail and sema.err != null) {
try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
@@ -6308,7 +6328,7 @@ fn analyzeGenericCallArg(
) !void {
const is_runtime = comptime_arg.val.tag() == .generic_poison and
comptime_arg.ty.hasRuntimeBits() and
- !(try sema.typeRequiresComptime(block, arg_src, comptime_arg.ty));
+ !(try sema.typeRequiresComptime(comptime_arg.ty));
if (is_runtime) {
const param_ty = new_fn_info.param_types[runtime_i.*];
const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
@@ -6573,7 +6593,7 @@ fn instantiateGenericCall(
}
} else if (is_anytype) {
const arg_ty = sema.typeOf(arg);
- if (try sema.typeRequiresComptime(block, .unneeded, arg_ty)) {
+ if (try sema.typeRequiresComptime(arg_ty)) {
const arg_val = try sema.resolveConstValue(block, .unneeded, arg, undefined);
const child_arg = try child_sema.addConstant(arg_ty, arg_val);
child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
@@ -6626,7 +6646,7 @@ fn instantiateGenericCall(
const arg = child_sema.inst_map.get(inst).?;
const copied_arg_ty = try child_sema.typeOf(arg).copy(new_decl_arena_allocator);
- if (try sema.typeRequiresComptime(block, .unneeded, copied_arg_ty)) {
+ if (try sema.typeRequiresComptime(copied_arg_ty)) {
is_comptime = true;
}
@@ -6657,7 +6677,7 @@ fn instantiateGenericCall(
// If the call evaluated to a return type that requires comptime, never mind
// our generic instantiation. Instead we need to perform a comptime call.
const new_fn_info = new_decl.ty.fnInfo();
- if (try sema.typeRequiresComptime(block, call_src, new_fn_info.return_type)) {
+ if (try sema.typeRequiresComptime(new_fn_info.return_type)) {
return error.ComptimeReturn;
}
// Similarly, if the call evaluated to a generic type we need to instead
@@ -7838,7 +7858,7 @@ fn funcCommon(
}
var ret_ty_requires_comptime = false;
- const ret_poison = if (sema.typeRequiresComptime(block, ret_ty_src, bare_return_type)) |ret_comptime| rp: {
+ const ret_poison = if (sema.typeRequiresComptime(bare_return_type)) |ret_comptime| rp: {
ret_ty_requires_comptime = ret_comptime;
break :rp bare_return_type.tag() == .generic_poison;
} else |err| switch (err) {
@@ -7876,7 +7896,7 @@ fn funcCommon(
};
return sema.failWithOwnedErrorMsg(msg);
}
- if (!Type.fnCallingConventionAllowsZigTypes(cc_workaround) and !sema.validateExternType(return_type, .ret_ty)) {
+ if (!Type.fnCallingConventionAllowsZigTypes(cc_workaround) and !try sema.validateExternType(block, ret_ty_src, return_type, .ret_ty)) {
const msg = msg: {
const msg = try sema.errMsg(block, ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{
return_type.fmt(sema.mod), @tagName(cc_workaround),
@@ -8072,7 +8092,7 @@ fn analyzeParameter(
cc: std.builtin.CallingConvention,
has_body: bool,
) !void {
- const requires_comptime = try sema.typeRequiresComptime(block, param_src, param.ty);
+ const requires_comptime = try sema.typeRequiresComptime(param.ty);
comptime_params[i] = param.is_comptime or requires_comptime;
const this_generic = param.ty.tag() == .generic_poison;
is_generic.* = is_generic.* or this_generic;
@@ -8095,7 +8115,7 @@ fn analyzeParameter(
};
return sema.failWithOwnedErrorMsg(msg);
}
- if (!Type.fnCallingConventionAllowsZigTypes(cc) and !sema.validateExternType(param.ty, .param_ty)) {
+ if (!Type.fnCallingConventionAllowsZigTypes(cc) and !try sema.validateExternType(block, param_src, param.ty, .param_ty)) {
const msg = msg: {
const msg = try sema.errMsg(block, param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{
param.ty.fmt(sema.mod), @tagName(cc),
@@ -8177,7 +8197,7 @@ fn zirParam(
}
};
const is_comptime = comptime_syntax or
- try sema.typeRequiresComptime(block, src, param_ty);
+ try sema.typeRequiresComptime(param_ty);
if (sema.inst_map.get(inst)) |arg| {
if (is_comptime) {
// We have a comptime value for this parameter so it should be elided from the
@@ -8237,7 +8257,7 @@ fn zirParamAnytype(
if (sema.inst_map.get(inst)) |air_ref| {
const param_ty = sema.typeOf(air_ref);
- if (comptime_syntax or try sema.typeRequiresComptime(block, src, param_ty)) {
+ if (comptime_syntax or try sema.typeRequiresComptime(param_ty)) {
// We have a comptime value for this parameter so it should be elided from the
// function type of the function instruction in this block.
return;
@@ -10379,7 +10399,9 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
}
}
unreachable;
- } else unreachable;
+ } else {
+ return sema.fail(block, operand_src, "no package named '{s}' available", .{operand});
+ };
return sema.fail(block, operand_src, "no package named '{s}' available within package '{s}'", .{ operand, parent });
},
else => {
@@ -15563,7 +15585,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
} else if (inst_data.size == .Many and elem_ty.zigTypeTag() == .Opaque) {
return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{});
} else if (inst_data.size == .C) {
- if (!sema.validateExternType(elem_ty, .other)) {
+ if (!try sema.validateExternType(block, elem_ty_src, elem_ty, .other)) {
const msg = msg: {
const msg = try sema.errMsg(block, elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)});
errdefer msg.destroy(sema.gpa);
@@ -16661,7 +16683,7 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
} else if (ptr_size == .Many and elem_ty.zigTypeTag() == .Opaque) {
return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{});
} else if (ptr_size == .C) {
- if (!sema.validateExternType(elem_ty, .other)) {
+ if (!try sema.validateExternType(block, src, elem_ty, .other)) {
const msg = msg: {
const msg = try sema.errMsg(block, src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)});
errdefer msg.destroy(sema.gpa);
@@ -17499,7 +17521,7 @@ fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
const target = sema.mod.getTarget();
- const result_val = try val.intToFloat(sema.arena, operand_ty, dest_ty, target);
+ const result_val = try val.intToFloatAdvanced(sema.arena, operand_ty, dest_ty, target, sema.kit(block, operand_src));
return sema.addConstant(dest_ty, result_val);
} else if (dest_ty.zigTypeTag() == .ComptimeFloat) {
return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_float' must be comptime known");
@@ -20343,12 +20365,13 @@ fn validateRunTimeType(
.Int,
.Float,
.ErrorSet,
- .Enum,
.Frame,
.AnyFrame,
.Void,
=> return true,
+ .Enum => return !(try sema.typeRequiresComptime(ty)),
+
.BoundFn,
.ComptimeFloat,
.ComptimeInt,
@@ -20381,7 +20404,7 @@ fn validateRunTimeType(
.Struct, .Union => {
const resolved_ty = try sema.resolveTypeFields(block, src, ty);
- const needs_comptime = try sema.typeRequiresComptime(block, src, resolved_ty);
+ const needs_comptime = try sema.typeRequiresComptime(resolved_ty);
return !needs_comptime;
},
};
@@ -20489,7 +20512,7 @@ fn explainWhyTypeIsComptimeInner(
.range = .type,
});
- if (try sema.typeRequiresComptime(block, src, field.ty)) {
+ if (try sema.typeRequiresComptime(field.ty)) {
try mod.errNoteNonLazy(field_src_loc, msg, "struct requires comptime because of this field", .{});
try sema.explainWhyTypeIsComptimeInner(block, src, msg, field_src_loc, field.ty, type_set);
}
@@ -20509,7 +20532,7 @@ fn explainWhyTypeIsComptimeInner(
.range = .type,
});
- if (try sema.typeRequiresComptime(block, src, field.ty)) {
+ if (try sema.typeRequiresComptime(field.ty)) {
try mod.errNoteNonLazy(field_src_loc, msg, "union requires comptime because of this field", .{});
try sema.explainWhyTypeIsComptimeInner(block, src, msg, field_src_loc, field.ty, type_set);
}
@@ -20528,7 +20551,14 @@ const ExternPosition = enum {
/// Returns true if `ty` is allowed in extern types.
/// Does *NOT* require `ty` to be resolved in any way.
-fn validateExternType(sema: *Sema, ty: Type, position: ExternPosition) bool {
+/// Calls `resolveTypeLayout` for packed containers.
+fn validateExternType(
+ sema: *Sema,
+ block: *Block,
+ src: LazySrcLoc,
+ ty: Type,
+ position: ExternPosition,
+) !bool {
switch (ty.zigTypeTag()) {
.Type,
.ComptimeFloat,
@@ -20556,17 +20586,25 @@ fn validateExternType(sema: *Sema, ty: Type, position: ExternPosition) bool {
.Fn => return !Type.fnCallingConventionAllowsZigTypes(ty.fnCallingConvention()),
.Enum => {
var buf: Type.Payload.Bits = undefined;
- return sema.validateExternType(ty.intTagType(&buf), position);
+ return sema.validateExternType(block, src, ty.intTagType(&buf), position);
},
.Struct, .Union => switch (ty.containerLayout()) {
- .Extern, .Packed => return true,
- else => return false,
+ .Extern => return true,
+ .Packed => {
+ const target = sema.mod.getTarget();
+ const bit_size = try ty.bitSizeAdvanced(target, sema.kit(block, src));
+ switch (bit_size) {
+ 8, 16, 32, 64, 128 => return true,
+ else => return false,
+ }
+ },
+ .Auto => return false,
},
.Array => {
if (position == .ret_ty or position == .param_ty) return false;
- return sema.validateExternType(ty.elemType2(), .other);
+ return sema.validateExternType(block, src, ty.elemType2(), .other);
},
- .Vector => return sema.validateExternType(ty.elemType2(), .other),
+ .Vector => return sema.validateExternType(block, src, ty.elemType2(), .other),
.Optional => return ty.isPtrLikeOptional(),
}
}
@@ -20618,8 +20656,8 @@ fn explainWhyTypeIsNotExtern(
try mod.errNoteNonLazy(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(sema.mod)});
try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position);
},
- .Struct => try mod.errNoteNonLazy(src_loc, msg, "only structs with packed or extern layout are extern compatible", .{}),
- .Union => try mod.errNoteNonLazy(src_loc, msg, "only unions with packed or extern layout are extern compatible", .{}),
+ .Struct => try mod.errNoteNonLazy(src_loc, msg, "only extern structs and ABI sized packed structs are extern compatible", .{}),
+ .Union => try mod.errNoteNonLazy(src_loc, msg, "only extern unions and ABI sized packed unions are extern compatible", .{}),
.Array => {
if (position == .ret_ty) {
return mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a return type", .{});
@@ -22998,7 +23036,7 @@ fn coerceExtra(
}
break :int;
};
- const result_val = try val.intToFloat(sema.arena, inst_ty, dest_ty, target);
+ const result_val = try val.intToFloatAdvanced(sema.arena, inst_ty, dest_ty, target, sema.kit(block, inst_src));
// TODO implement this compile error
//const int_again_val = try result_val.floatToInt(sema.arena, inst_ty);
//if (!int_again_val.eql(val, inst_ty, mod)) {
@@ -23422,8 +23460,11 @@ const InMemoryCoercionResult = union(enum) {
var index: u6 = 0;
var actual_noalias = false;
while (true) : (index += 1) {
- if (param.actual << index != param.wanted << index) {
- actual_noalias = (param.actual << index) == (1 << 31);
+ const actual = @truncate(u1, param.actual >> index);
+ const wanted = @truncate(u1, param.wanted >> index);
+ if (actual != wanted) {
+ actual_noalias = actual == 1;
+ break;
}
}
if (!actual_noalias) {
@@ -23917,7 +23958,7 @@ fn coerceInMemoryAllowedFns(
if (dest_info.noalias_bits != src_info.noalias_bits) {
return InMemoryCoercionResult{ .fn_param_noalias = .{
- .actual = dest_info.noalias_bits,
+ .actual = src_info.noalias_bits,
.wanted = dest_info.noalias_bits,
} };
}
@@ -24075,16 +24116,40 @@ fn coerceVarArgParam(
inst: Air.Inst.Ref,
inst_src: LazySrcLoc,
) !Air.Inst.Ref {
- const inst_ty = sema.typeOf(inst);
if (block.is_typeof) return inst;
- switch (inst_ty.zigTypeTag()) {
+ const coerced = switch (sema.typeOf(inst).zigTypeTag()) {
// TODO consider casting to c_int/f64 if they fit
- .ComptimeInt, .ComptimeFloat => return sema.fail(block, inst_src, "integer and float literals in var args function must be casted", .{}),
- else => {},
+ .ComptimeInt, .ComptimeFloat => return sema.fail(
+ block,
+ inst_src,
+ "integer and float literals passed variadic function must be casted to a fixed-size number type",
+ .{},
+ ),
+ .Fn => blk: {
+ const fn_val = try sema.resolveConstValue(block, .unneeded, inst, undefined);
+ const fn_decl = fn_val.pointerDecl().?;
+ break :blk try sema.analyzeDeclRef(fn_decl);
+ },
+ .Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}),
+ else => inst,
+ };
+
+ const coerced_ty = sema.typeOf(coerced);
+ if (!try sema.validateExternType(block, inst_src, coerced_ty, .other)) {
+ const msg = msg: {
+ const msg = try sema.errMsg(block, inst_src, "cannot pass '{}' to variadic function", .{coerced_ty.fmt(sema.mod)});
+ errdefer msg.destroy(sema.gpa);
+
+ const src_decl = sema.mod.declPtr(block.src_decl);
+ try sema.explainWhyTypeIsNotExtern(msg, inst_src.toSrcLoc(src_decl), coerced_ty, .other);
+
+ try sema.addDeclaredHereNote(msg, coerced_ty);
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
}
- // TODO implement more of this function.
- return inst;
+ return coerced;
}
// TODO migrate callsites to use storePtr2 instead.
@@ -27579,7 +27644,7 @@ pub fn resolveTypeLayout(
// In case of querying the ABI alignment of this optional, we will ask
// for hasRuntimeBits() of the payload type, so we need "requires comptime"
// to be known already before this function returns.
- _ = try sema.typeRequiresComptime(block, src, payload_ty);
+ _ = try sema.typeRequiresComptime(payload_ty);
return sema.resolveTypeLayout(block, src, payload_ty);
},
.ErrorUnion => {
@@ -27634,7 +27699,7 @@ fn resolveStructLayout(
// for hasRuntimeBits() of each field, so we need "requires comptime"
// to be known already before this function returns.
for (struct_obj.fields.values()) |field, i| {
- _ = sema.typeRequiresComptime(block, src, field.ty) catch |err| switch (err) {
+ _ = sema.typeRequiresComptime(field.ty) catch |err| switch (err) {
error.AnalysisFail => {
const msg = sema.err orelse return err;
try sema.addFieldErrNote(block, ty, i, msg, "while checking this field", .{});
@@ -27866,7 +27931,7 @@ fn resolveStructFully(
}
// And let's not forget comptime-only status.
- _ = try sema.typeRequiresComptime(block, src, ty);
+ _ = try sema.typeRequiresComptime(ty);
}
fn resolveUnionFully(
@@ -27899,7 +27964,7 @@ fn resolveUnionFully(
}
// And let's not forget comptime-only status.
- _ = try sema.typeRequiresComptime(block, src, ty);
+ _ = try sema.typeRequiresComptime(ty);
}
pub fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type {
@@ -28273,7 +28338,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
};
return sema.failWithOwnedErrorMsg(msg);
}
- if (struct_obj.layout == .Extern and !sema.validateExternType(field.ty, .other)) {
+ if (struct_obj.layout == .Extern and !try sema.validateExternType(&block_scope, src, field.ty, .other)) {
const msg = msg: {
const tree = try sema.getAstTree(&block_scope);
const fields_src = enumFieldSrcLoc(decl, tree.*, 0, i);
@@ -28610,7 +28675,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
};
return sema.failWithOwnedErrorMsg(msg);
}
- if (union_obj.layout == .Extern and !sema.validateExternType(field_ty, .union_field)) {
+ if (union_obj.layout == .Extern and !try sema.validateExternType(&block_scope, src, field_ty, .union_field)) {
const msg = msg: {
const tree = try sema.getAstTree(&block_scope);
const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i);
@@ -29002,7 +29067,7 @@ pub fn typeHasOnePossibleValue(
},
.enum_nonexhaustive => {
const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty;
- if (!(try sema.typeHasRuntimeBits(block, src, tag_ty))) {
+ if (tag_ty.zigTypeTag() != .ComptimeInt and !(try sema.typeHasRuntimeBits(block, src, tag_ty))) {
return Value.zero;
} else {
return null;
@@ -29534,7 +29599,7 @@ fn typePtrOrOptionalPtrTy(
/// TODO assert the return value matches `ty.comptimeOnly`
/// TODO merge these implementations together with the "advanced"/sema_kit pattern seen
/// elsewhere in value.zig
-pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
+pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
return switch (ty.tag()) {
.u1,
.u8,
@@ -29625,7 +29690,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
.array,
.array_sentinel,
.vector,
- => return sema.typeRequiresComptime(block, src, ty.childType()),
+ => return sema.typeRequiresComptime(ty.childType()),
.pointer,
.single_const_pointer,
@@ -29641,7 +29706,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
if (child_ty.zigTypeTag() == .Fn) {
return child_ty.fnInfo().is_generic;
} else {
- return sema.typeRequiresComptime(block, src, child_ty);
+ return sema.typeRequiresComptime(child_ty);
}
},
@@ -29650,14 +29715,14 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
.optional_single_const_pointer,
=> {
var buf: Type.Payload.ElemType = undefined;
- return sema.typeRequiresComptime(block, src, ty.optionalChild(&buf));
+ return sema.typeRequiresComptime(ty.optionalChild(&buf));
},
.tuple, .anon_struct => {
const tuple = ty.tupleFields();
for (tuple.types) |field_ty, i| {
const have_comptime_val = tuple.values[i].tag() != .unreachable_value;
- if (!have_comptime_val and try sema.typeRequiresComptime(block, src, field_ty)) {
+ if (!have_comptime_val and try sema.typeRequiresComptime(field_ty)) {
return true;
}
}
@@ -29678,7 +29743,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
struct_obj.requires_comptime = .wip;
for (struct_obj.fields.values()) |field| {
if (field.is_comptime) continue;
- if (try sema.typeRequiresComptime(block, src, field.ty)) {
+ if (try sema.typeRequiresComptime(field.ty)) {
struct_obj.requires_comptime = .yes;
return true;
}
@@ -29702,7 +29767,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
union_obj.requires_comptime = .wip;
for (union_obj.fields.values()) |field| {
- if (try sema.typeRequiresComptime(block, src, field.ty)) {
+ if (try sema.typeRequiresComptime(field.ty)) {
union_obj.requires_comptime = .yes;
return true;
}
@@ -29713,18 +29778,18 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
}
},
- .error_union => return sema.typeRequiresComptime(block, src, ty.errorUnionPayload()),
+ .error_union => return sema.typeRequiresComptime(ty.errorUnionPayload()),
.anyframe_T => {
const child_ty = ty.castTag(.anyframe_T).?.data;
- return sema.typeRequiresComptime(block, src, child_ty);
+ return sema.typeRequiresComptime(child_ty);
},
.enum_numbered => {
const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty;
- return sema.typeRequiresComptime(block, src, tag_ty);
+ return sema.typeRequiresComptime(tag_ty);
},
.enum_full, .enum_nonexhaustive => {
const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty;
- return sema.typeRequiresComptime(block, src, tag_ty);
+ return sema.typeRequiresComptime(tag_ty);
},
};
}
@@ -29762,7 +29827,7 @@ fn unionFieldAlignment(
}
/// Synchronize logic with `Type.isFnOrHasRuntimeBits`.
-pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
+pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
const fn_info = ty.fnInfo();
if (fn_info.is_generic) return false;
if (fn_info.is_var_args) return true;
@@ -29771,7 +29836,7 @@ pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) C
.Inline => return false,
else => {},
}
- if (try sema.typeRequiresComptime(block, src, fn_info.return_type)) {
+ if (try sema.typeRequiresComptime(fn_info.return_type)) {
return false;
}
return true;
diff --git a/src/arch/aarch64/abi.zig b/src/arch/aarch64/abi.zig
index cb28b1fffa..f26a9a8a8a 100644
--- a/src/arch/aarch64/abi.zig
+++ b/src/arch/aarch64/abi.zig
@@ -3,6 +3,69 @@ const builtin = @import("builtin");
const bits = @import("bits.zig");
const Register = bits.Register;
const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
+const Type = @import("../../type.zig").Type;
+
+pub const Class = enum { memory, integer, none, float_array };
+
+pub fn classifyType(ty: Type, target: std.Target) [2]Class {
+ if (!ty.hasRuntimeBitsIgnoreComptime()) return .{ .none, .none };
+ switch (ty.zigTypeTag()) {
+ .Struct => {
+ if (ty.containerLayout() == .Packed) return .{ .integer, .none };
+
+ if (ty.structFieldCount() <= 4) {
+ const fields = ty.structFields();
+ var float_size: ?u64 = null;
+ for (fields.values()) |field| {
+ if (field.ty.zigTypeTag() != .Float) break;
+ const field_size = field.ty.bitSize(target);
+ const prev_size = float_size orelse {
+ float_size = field_size;
+ continue;
+ };
+ if (field_size != prev_size) break;
+ } else {
+ return .{ .float_array, .none };
+ }
+ }
+ const bit_size = ty.bitSize(target);
+ if (bit_size > 128) return .{ .memory, .none };
+ if (bit_size > 64) return .{ .integer, .integer };
+ return .{ .integer, .none };
+ },
+ .Union => {
+ const bit_size = ty.bitSize(target);
+ if (bit_size > 128) return .{ .memory, .none };
+ if (bit_size > 64) return .{ .integer, .integer };
+ return .{ .integer, .none };
+ },
+ .Int, .Enum, .ErrorSet, .Vector, .Float, .Bool => return .{ .integer, .none },
+ .Array => return .{ .memory, .none },
+ .Optional => {
+ std.debug.assert(ty.isPtrLikeOptional());
+ return .{ .integer, .none };
+ },
+ .Pointer => {
+ std.debug.assert(!ty.isSlice());
+ return .{ .integer, .none };
+ },
+ .ErrorUnion,
+ .Frame,
+ .AnyFrame,
+ .NoReturn,
+ .Void,
+ .Type,
+ .ComptimeFloat,
+ .ComptimeInt,
+ .Undefined,
+ .Null,
+ .BoundFn,
+ .Fn,
+ .Opaque,
+ .EnumLiteral,
+ => unreachable,
+ }
+}
const callee_preserved_regs_impl = if (builtin.os.tag.isDarwin()) struct {
pub const callee_preserved_regs = [_]Register{
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig
index 95a0a8e4aa..b9637bf8e3 100644
--- a/src/arch/wasm/CodeGen.zig
+++ b/src/arch/wasm/CodeGen.zig
@@ -2394,9 +2394,7 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
const decl_index = decl_ref_mut.data.decl_index;
return self.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl_index);
}
-
const target = self.target;
-
switch (ty.zigTypeTag()) {
.Void => return WValue{ .none = {} },
.Int => {
diff --git a/src/arch/wasm/abi.zig b/src/arch/wasm/abi.zig
index b1e99f4f92..d54965a50c 100644
--- a/src/arch/wasm/abi.zig
+++ b/src/arch/wasm/abi.zig
@@ -23,6 +23,10 @@ pub fn classifyType(ty: Type, target: Target) [2]Class {
if (!ty.hasRuntimeBitsIgnoreComptime()) return none;
switch (ty.zigTypeTag()) {
.Struct => {
+ if (ty.containerLayout() == .Packed) {
+ if (ty.bitSize(target) <= 64) return direct;
+ return .{ .direct, .direct };
+ }
// When the struct type is non-scalar
if (ty.structFieldCount() > 1) return memory;
// When the struct's alignment is non-natural
@@ -57,6 +61,10 @@ pub fn classifyType(ty: Type, target: Target) [2]Class {
return direct;
},
.Union => {
+ if (ty.containerLayout() == .Packed) {
+ if (ty.bitSize(target) <= 64) return direct;
+ return .{ .direct, .direct };
+ }
const layout = ty.unionGetLayout(target);
std.debug.assert(layout.tag_size == 0);
if (ty.unionFields().count() > 1) return memory;
diff --git a/src/arch/x86_64/abi.zig b/src/arch/x86_64/abi.zig
index 7e2025a23d..344fe235f3 100644
--- a/src/arch/x86_64/abi.zig
+++ b/src/arch/x86_64/abi.zig
@@ -5,7 +5,7 @@ const assert = std.debug.assert;
const Register = @import("bits.zig").Register;
const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
-pub const Class = enum { integer, sse, sseup, x87, x87up, complex_x87, memory, none };
+pub const Class = enum { integer, sse, sseup, x87, x87up, complex_x87, memory, none, win_i128 };
pub fn classifyWindows(ty: Type, target: Target) Class {
// https://docs.microsoft.com/en-gb/cpp/build/x64-calling-convention?view=vs-2017
@@ -34,7 +34,15 @@ pub fn classifyWindows(ty: Type, target: Target) Class {
=> switch (ty.abiSize(target)) {
0 => unreachable,
1, 2, 4, 8 => return .integer,
- else => return .memory,
+ else => switch (ty.zigTypeTag()) {
+ .Int => return .win_i128,
+ .Struct, .Union => if (ty.containerLayout() == .Packed) {
+ return .win_i128;
+ } else {
+ return .memory;
+ },
+ else => return .memory,
+ },
},
.Float, .Vector => return .sse,
@@ -174,6 +182,12 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class {
// "If the size of the aggregate exceeds a single eightbyte, each is classified
// separately.".
const ty_size = ty.abiSize(target);
+ if (ty.containerLayout() == .Packed) {
+ assert(ty_size <= 128);
+ result[0] = .integer;
+ if (ty_size > 64) result[1] = .integer;
+ return result;
+ }
if (ty_size > 64)
return memory_class;
@@ -284,6 +298,12 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class {
// "If the size of the aggregate exceeds a single eightbyte, each is classified
// separately.".
const ty_size = ty.abiSize(target);
+ if (ty.containerLayout() == .Packed) {
+ assert(ty_size <= 128);
+ result[0] = .integer;
+ if (ty_size > 64) result[1] = .integer;
+ return result;
+ }
if (ty_size > 64)
return memory_class;
diff --git a/src/autodoc/render_source.zig b/src/autodoc/render_source.zig
index cafed8d526..ceba230276 100644
--- a/src/autodoc/render_source.zig
+++ b/src/autodoc/render_source.zig
@@ -79,6 +79,16 @@ pub fn genHtml(
\\ text-align: right;
\\ color: #999;
\\ }
+ \\
+ \\ .line {
+ \\ width: 100%;
+ \\ display: inline-block;
+ \\ }
+ \\ .line:target {
+ \\ border-top: 1px solid #ccc;
+ \\ border-bottom: 1px solid #ccc;
+ \\ background: #fafafa;
+ \\ }
\\
\\ @media (prefers-color-scheme: dark) {
\\ body{
@@ -90,6 +100,11 @@ pub fn genHtml(
\\ background: #222;
\\ border: unset;
\\ }
+ \\ .line:target {
+ \\ border-top: 1px solid #444;
+ \\ border-bottom: 1px solid #444;
+ \\ background: #333;
+ \\ }
\\ .tok-kw {
\\ color: #eee;
\\ }
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index badf0721c7..dc43548b80 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -23,6 +23,7 @@ const LazySrcLoc = Module.LazySrcLoc;
const CType = @import("../type.zig").CType;
const x86_64_abi = @import("../arch/x86_64/abi.zig");
const wasm_c_abi = @import("../arch/wasm/abi.zig");
+const aarch64_c_abi = @import("../arch/aarch64/abi.zig");
const Error = error{ OutOfMemory, CodegenFail };
@@ -314,6 +315,15 @@ pub fn supportsTailCall(target: std.Target) bool {
}
}
+/// TODO can this be done with simpler logic / different API binding?
+fn deleteLlvmGlobal(llvm_global: *const llvm.Value) void {
+ if (llvm_global.globalGetValueType().getTypeKind() == .Function) {
+ llvm_global.deleteFunction();
+ return;
+ }
+ return llvm_global.deleteGlobal();
+}
+
pub const Object = struct {
gpa: Allocator,
module: *Module,
@@ -667,7 +677,7 @@ pub const Object = struct {
const new_global_ptr = other_global.constBitCast(llvm_global.typeOf());
llvm_global.replaceAllUsesWith(new_global_ptr);
- object.deleteLlvmGlobal(llvm_global);
+ deleteLlvmGlobal(llvm_global);
entry.value_ptr.* = new_global_ptr;
}
object.extern_collisions.clearRetainingCapacity();
@@ -693,7 +703,7 @@ pub const Object = struct {
const new_global_ptr = llvm_global.constBitCast(other_global.typeOf());
other_global.replaceAllUsesWith(new_global_ptr);
llvm_global.takeName(other_global);
- other_global.deleteGlobal();
+ deleteLlvmGlobal(other_global);
// Problem: now we need to replace in the decl_map that
// the extern decl index points to this new global. However we don't
// know the decl index.
@@ -1084,6 +1094,26 @@ pub const Object = struct {
try args.ensureUnusedCapacity(1);
args.appendAssumeCapacity(casted);
},
+ .float_array => {
+ const param_ty = fn_info.param_types[it.zig_index - 1];
+ const param_llvm_ty = try dg.lowerType(param_ty);
+ const param = llvm_func.getParam(llvm_arg_i);
+ llvm_arg_i += 1;
+
+ const alignment = param_ty.abiAlignment(target);
+ const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);
+ arg_ptr.setAlignment(alignment);
+ const casted_ptr = builder.buildBitCast(arg_ptr, param.typeOf().pointerType(0), "");
+ _ = builder.buildStore(param, casted_ptr);
+
+ if (isByRef(param_ty)) {
+ try args.append(arg_ptr);
+ } else {
+ const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");
+ load_inst.setAlignment(alignment);
+ try args.append(load_inst);
+ }
+ },
};
}
@@ -1191,15 +1221,6 @@ pub const Object = struct {
return null;
}
- /// TODO can this be done with simpler logic / different API binding?
- fn deleteLlvmGlobal(o: Object, llvm_global: *const llvm.Value) void {
- if (o.llvm_module.getNamedFunction(llvm_global.getValueName()) != null) {
- llvm_global.deleteFunction();
- return;
- }
- return llvm_global.deleteGlobal();
- }
-
pub fn updateDeclExports(
self: *Object,
module: *Module,
@@ -1294,7 +1315,7 @@ pub const Object = struct {
alias.setAliasee(llvm_global);
} else {
_ = self.llvm_module.addAlias(
- llvm_global.typeOf(),
+ llvm_global.globalGetValueType(),
0,
llvm_global,
exp_name_z,
@@ -2527,6 +2548,7 @@ pub const DeclGen = struct {
.multiple_llvm_ints,
.multiple_llvm_float,
.as_u16,
+ .float_array,
=> continue,
.slice => unreachable, // extern functions do not support slice types.
@@ -3093,6 +3115,13 @@ pub const DeclGen = struct {
.as_u16 => {
try llvm_params.append(dg.context.intType(16));
},
+ .float_array => {
+ const param_ty = fn_info.param_types[it.zig_index - 1];
+ const float_ty = try dg.lowerType(param_ty.structFieldType(0));
+ const field_count = @intCast(c_uint, param_ty.structFieldCount());
+ const arr_ty = float_ty.arrayType(field_count);
+ try llvm_params.append(arr_ty);
+ },
};
return llvm.functionType(
@@ -4719,6 +4748,27 @@ pub const FuncGen = struct {
const casted = self.builder.buildBitCast(llvm_arg, self.dg.context.intType(16), "");
try llvm_args.append(casted);
},
+ .float_array => {
+ const arg = args[it.zig_index - 1];
+ const arg_ty = self.air.typeOf(arg);
+ var llvm_arg = try self.resolveInst(arg);
+ if (!isByRef(arg_ty)) {
+ const p = self.buildAlloca(llvm_arg.typeOf());
+ const store_inst = self.builder.buildStore(llvm_arg, p);
+ store_inst.setAlignment(arg_ty.abiAlignment(target));
+ llvm_arg = store_inst;
+ }
+
+ const float_ty = try self.dg.lowerType(arg_ty.structFieldType(0));
+ const field_count = @intCast(u32, arg_ty.structFieldCount());
+ const array_llvm_ty = float_ty.arrayType(field_count);
+
+ const casted = self.builder.buildBitCast(llvm_arg, array_llvm_ty.pointerType(0), "");
+ const alignment = arg_ty.abiAlignment(target);
+ const load_inst = self.builder.buildLoad(array_llvm_ty, casted, "");
+ load_inst.setAlignment(alignment);
+ try llvm_args.append(load_inst);
+ },
};
const call = self.builder.buildCall(
@@ -9240,7 +9290,7 @@ pub const FuncGen = struct {
}
},
},
- .Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty, field_index),
+ .Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty),
else => unreachable,
}
}
@@ -9250,19 +9300,16 @@ pub const FuncGen = struct {
inst: Air.Inst.Index,
union_ptr: *const llvm.Value,
union_ty: Type,
- field_index: c_uint,
) !?*const llvm.Value {
- const union_obj = union_ty.cast(Type.Payload.Union).?.data;
- const field = &union_obj.fields.values()[field_index];
- if (!field.ty.hasRuntimeBitsIgnoreComptime()) {
- return null;
- }
const target = self.dg.module.getTarget();
const layout = union_ty.unionGetLayout(target);
+ const result_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
+ if (layout.payload_size == 0) {
+ return self.builder.buildBitCast(union_ptr, result_llvm_ty, "");
+ }
const payload_index = @boolToInt(layout.tag_align >= layout.payload_align);
const union_llvm_ty = try self.dg.lowerType(union_ty);
const union_field_ptr = self.builder.buildStructGEP(union_llvm_ty, union_ptr, payload_index, "");
- const result_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
return self.builder.buildBitCast(union_field_ptr, result_llvm_ty, "");
}
@@ -9832,6 +9879,7 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool
else => return x86_64_abi.classifySystemV(fn_info.return_type, target)[0] == .memory,
},
.wasm32 => return wasm_c_abi.classifyType(fn_info.return_type, target)[0] == .indirect,
+ .aarch64, .aarch64_be => return aarch64_c_abi.classifyType(fn_info.return_type, target)[0] == .memory,
else => return false, // TODO investigate C ABI for other architectures
},
else => return false,
@@ -9862,22 +9910,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.
}
},
.C => {
- const is_scalar = switch (fn_info.return_type.zigTypeTag()) {
- .Void,
- .Bool,
- .NoReturn,
- .Int,
- .Float,
- .Pointer,
- .Optional,
- .ErrorSet,
- .Enum,
- .AnyFrame,
- .Vector,
- => true,
-
- else => false,
- };
+ const is_scalar = isScalar(fn_info.return_type);
switch (target.cpu.arch) {
.mips, .mipsel => return dg.lowerType(fn_info.return_type),
.x86_64 => switch (target.os.tag) {
@@ -9890,6 +9923,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.
return dg.context.intType(@intCast(c_uint, abi_size * 8));
}
},
+ .win_i128 => return dg.context.intType(64).vectorType(2),
.memory => return dg.context.voidType(),
.sse => return dg.lowerType(fn_info.return_type),
else => unreachable,
@@ -9930,6 +9964,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.
@panic("TODO");
},
.memory => unreachable, // handled above
+ .win_i128 => unreachable, // windows only
.none => break,
}
}
@@ -9954,6 +9989,24 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.
const abi_size = scalar_type.abiSize(target);
return dg.context.intType(@intCast(c_uint, abi_size * 8));
},
+ .aarch64, .aarch64_be => {
+ if (is_scalar) {
+ return dg.lowerType(fn_info.return_type);
+ }
+ const classes = aarch64_c_abi.classifyType(fn_info.return_type, target);
+ if (classes[0] == .memory or classes[0] == .none) {
+ return dg.context.voidType();
+ }
+ if (classes[0] == .float_array) {
+ return dg.lowerType(fn_info.return_type);
+ }
+ if (classes[1] == .none) {
+ const bit_size = fn_info.return_type.bitSize(target);
+ return dg.context.intType(@intCast(c_uint, bit_size));
+ }
+
+ return dg.context.intType(64).arrayType(2);
+ },
// TODO investigate C ABI for other architectures
else => return dg.lowerType(fn_info.return_type),
}
@@ -9981,6 +10034,7 @@ const ParamTypeIterator = struct {
multiple_llvm_float,
slice,
as_u16,
+ float_array,
};
pub fn next(it: *ParamTypeIterator) ?Lowering {
@@ -10025,22 +10079,7 @@ const ParamTypeIterator = struct {
@panic("TODO implement async function lowering in the LLVM backend");
},
.C => {
- const is_scalar = switch (ty.zigTypeTag()) {
- .Void,
- .Bool,
- .NoReturn,
- .Int,
- .Float,
- .Pointer,
- .Optional,
- .ErrorSet,
- .Enum,
- .AnyFrame,
- .Vector,
- => true,
-
- else => false,
- };
+ const is_scalar = isScalar(ty);
switch (it.target.cpu.arch) {
.riscv32, .riscv64 => {
it.zig_index += 1;
@@ -10069,6 +10108,11 @@ const ParamTypeIterator = struct {
return .abi_sized_int;
}
},
+ .win_i128 => {
+ it.zig_index += 1;
+ it.llvm_index += 1;
+ return .byref;
+ },
.memory => {
it.zig_index += 1;
it.llvm_index += 1;
@@ -10123,6 +10167,7 @@ const ParamTypeIterator = struct {
@panic("TODO");
},
.memory => unreachable, // handled above
+ .win_i128 => unreachable, // windows only
.none => break,
}
}
@@ -10155,6 +10200,28 @@ const ParamTypeIterator = struct {
}
return .abi_sized_int;
},
+ .aarch64, .aarch64_be => {
+ it.zig_index += 1;
+ it.llvm_index += 1;
+ if (is_scalar) {
+ return .byval;
+ }
+ const classes = aarch64_c_abi.classifyType(ty, it.target);
+ if (classes[0] == .memory) {
+ return .byref;
+ }
+ if (classes[0] == .float_array) {
+ return .float_array;
+ }
+ if (classes[1] == .none) {
+ it.llvm_types_len = 1;
+ } else {
+ it.llvm_types_len = 2;
+ }
+ it.llvm_types_buffer[0] = 64;
+ it.llvm_types_buffer[1] = 64;
+ return .multiple_llvm_ints;
+ },
// TODO investigate C ABI for other architectures
else => {
it.zig_index += 1;
@@ -10294,6 +10361,27 @@ fn isByRef(ty: Type) bool {
}
}
+fn isScalar(ty: Type) bool {
+ return switch (ty.zigTypeTag()) {
+ .Void,
+ .Bool,
+ .NoReturn,
+ .Int,
+ .Float,
+ .Pointer,
+ .Optional,
+ .ErrorSet,
+ .Enum,
+ .AnyFrame,
+ .Vector,
+ => true,
+
+ .Struct => ty.containerLayout() == .Packed,
+ .Union => ty.containerLayout() == .Packed,
+ else => false,
+ };
+}
+
/// This function returns true if we expect LLVM to lower x86_fp80 correctly
/// and false if we expect LLVM to crash if it counters an x86_fp80 type.
fn backendSupportsF80(target: std.Target) bool {
diff --git a/src/link/Coff.zig b/src/link/Coff.zig
index 36ddfc4e2a..e302571671 100644
--- a/src/link/Coff.zig
+++ b/src/link/Coff.zig
@@ -50,6 +50,7 @@ text_section_index: ?u16 = null,
got_section_index: ?u16 = null,
rdata_section_index: ?u16 = null,
data_section_index: ?u16 = null,
+reloc_section_index: ?u16 = null,
locals: std.ArrayListUnmanaged(coff.Symbol) = .{},
globals: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{},
@@ -98,11 +99,16 @@ atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{},
/// with `Decl` `main`, and lives as long as that `Decl`.
unnamed_const_atoms: UnnamedConstTable = .{},
-/// A table of relocations indexed by the owning them `TextBlock`.
-/// Note that once we refactor `TextBlock`'s lifetime and ownership rules,
+/// A table of relocations indexed by the owning them `Atom`.
+/// Note that once we refactor `Atom`'s lifetime and ownership rules,
/// this will be a table indexed by index into the list of Atoms.
relocs: RelocTable = .{},
+/// A table of base relocations indexed by the owning them `Atom`.
+/// Note that once we refactor `Atom`'s lifetime and ownership rules,
+/// this will be a table indexed by index into the list of Atoms.
+base_relocs: BaseRelocationTable = .{},
+
pub const Reloc = struct {
@"type": enum {
got,
@@ -117,6 +123,7 @@ pub const Reloc = struct {
};
const RelocTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Reloc));
+const BaseRelocationTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(u32));
const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom));
const default_file_alignment: u16 = 0x200;
@@ -150,7 +157,17 @@ const Section = struct {
free_list: std.ArrayListUnmanaged(*Atom) = .{},
};
-pub const PtrWidth = enum { p32, p64 };
+pub const PtrWidth = enum {
+ p32,
+ p64,
+
+ fn abiSize(pw: PtrWidth) u4 {
+ return switch (pw) {
+ .p32 => 4,
+ .p64 => 8,
+ };
+ }
+};
pub const SrcFn = void;
pub const Export = struct {
@@ -274,6 +291,14 @@ pub fn deinit(self: *Coff) void {
}
self.relocs.deinit(gpa);
}
+
+ {
+ var it = self.base_relocs.valueIterator();
+ while (it.next()) |relocs| {
+ relocs.deinit(gpa);
+ }
+ self.base_relocs.deinit(gpa);
+ }
}
fn populateMissingMetadata(self: *Coff) !void {
@@ -307,7 +332,7 @@ fn populateMissingMetadata(self: *Coff) !void {
if (self.got_section_index == null) {
self.got_section_index = @intCast(u16, self.sections.slice().len);
- const file_size = @intCast(u32, self.base.options.symbol_count_hint);
+ const file_size = @intCast(u32, self.base.options.symbol_count_hint) * self.ptr_width.abiSize();
const off = self.findFreeSpace(file_size, self.page_size);
log.debug("found .got free space 0x{x} to 0x{x}", .{ off, off + file_size });
var header = coff.SectionHeader{
@@ -378,6 +403,31 @@ fn populateMissingMetadata(self: *Coff) !void {
try self.sections.append(gpa, .{ .header = header });
}
+ if (self.reloc_section_index == null) {
+ self.reloc_section_index = @intCast(u16, self.sections.slice().len);
+ const file_size = @intCast(u32, self.base.options.symbol_count_hint) * @sizeOf(coff.BaseRelocation);
+ const off = self.findFreeSpace(file_size, self.page_size);
+ log.debug("found .reloc free space 0x{x} to 0x{x}", .{ off, off + file_size });
+ var header = coff.SectionHeader{
+ .name = undefined,
+ .virtual_size = file_size,
+ .virtual_address = off,
+ .size_of_raw_data = file_size,
+ .pointer_to_raw_data = off,
+ .pointer_to_relocations = 0,
+ .pointer_to_linenumbers = 0,
+ .number_of_relocations = 0,
+ .number_of_linenumbers = 0,
+ .flags = .{
+ .CNT_INITIALIZED_DATA = 1,
+ .MEM_PURGEABLE = 1,
+ .MEM_READ = 1,
+ },
+ };
+ try self.setSectionName(&header, ".reloc");
+ try self.sections.append(gpa, .{ .header = header });
+ }
+
if (self.strtab_offset == null) {
try self.strtab.buffer.append(gpa, 0);
self.strtab_offset = self.findFreeSpace(@intCast(u32, self.strtab.len()), 1);
@@ -605,6 +655,14 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {
.prev_vaddr = sym.value,
});
+ const target_sym = self.getSymbol(target);
+ switch (target_sym.section_number) {
+ .UNDEFINED => @panic("TODO generate a binding for undefined GOT target"),
+ .ABSOLUTE => {},
+ .DEBUG => unreachable, // not possible
+ else => try atom.addBaseRelocation(self, 0),
+ }
+
return atom;
}
@@ -1179,6 +1237,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
try self.resolveRelocs(atom.*);
}
}
+ try self.writeBaseRelocations();
if (self.getEntryPoint()) |entry_sym_loc| {
self.entry_addr = self.getSymbol(entry_sym_loc).value;
@@ -1216,6 +1275,83 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v
log.debug("TODO implement updateDeclLineNumber", .{});
}
+/// TODO: note if we need to rewrite base relocations by dirtying any of the entries in the global table
+/// TODO: note that .ABSOLUTE is used as padding within each block; we could use this fact to do
+/// incremental updates and writes into the table instead of doing it all at once
+fn writeBaseRelocations(self: *Coff) !void {
+ const gpa = self.base.allocator;
+
+ var pages = std.AutoHashMap(u32, std.ArrayList(coff.BaseRelocation)).init(gpa);
+ defer {
+ var it = pages.valueIterator();
+ while (it.next()) |inner| {
+ inner.deinit();
+ }
+ pages.deinit();
+ }
+
+ var it = self.base_relocs.iterator();
+ while (it.next()) |entry| {
+ const atom = entry.key_ptr.*;
+ const offsets = entry.value_ptr.*;
+
+ for (offsets.items) |offset| {
+ const sym = atom.getSymbol(self);
+ const rva = sym.value + offset;
+ const page = mem.alignBackwardGeneric(u32, rva, self.page_size);
+ const gop = try pages.getOrPut(page);
+ if (!gop.found_existing) {
+ gop.value_ptr.* = std.ArrayList(coff.BaseRelocation).init(gpa);
+ }
+ try gop.value_ptr.append(.{
+ .offset = @intCast(u12, rva - page),
+ .@"type" = .DIR64,
+ });
+ }
+ }
+
+ var buffer = std.ArrayList(u8).init(gpa);
+ defer buffer.deinit();
+
+ var pages_it = pages.iterator();
+ while (pages_it.next()) |entry| {
+ // Pad to required 4byte alignment
+ if (!mem.isAlignedGeneric(
+ usize,
+ entry.value_ptr.items.len * @sizeOf(coff.BaseRelocation),
+ @sizeOf(u32),
+ )) {
+ try entry.value_ptr.append(.{
+ .offset = 0,
+ .@"type" = .ABSOLUTE,
+ });
+ }
+
+ const block_size = @intCast(
+ u32,
+ entry.value_ptr.items.len * @sizeOf(coff.BaseRelocation) + @sizeOf(coff.BaseRelocationDirectoryEntry),
+ );
+ try buffer.ensureUnusedCapacity(block_size);
+ buffer.appendSliceAssumeCapacity(mem.asBytes(&coff.BaseRelocationDirectoryEntry{
+ .page_rva = entry.key_ptr.*,
+ .block_size = block_size,
+ }));
+ buffer.appendSliceAssumeCapacity(mem.sliceAsBytes(entry.value_ptr.items));
+ }
+
+ const header = &self.sections.items(.header)[self.reloc_section_index.?];
+ const sect_capacity = self.allocatedSize(header.pointer_to_raw_data);
+ const needed_size = @intCast(u32, buffer.items.len);
+ assert(needed_size < sect_capacity); // TODO expand .reloc section
+
+ try self.base.file.?.pwriteAll(buffer.items, header.pointer_to_raw_data);
+
+ self.data_directories[@enumToInt(coff.DirectoryEntry.BASERELOC)] = .{
+ .virtual_address = header.virtual_address,
+ .size = needed_size,
+ };
+}
+
fn writeStrtab(self: *Coff) !void {
const allocated_size = self.allocatedSize(self.strtab_offset.?);
const needed_size = @intCast(u32, self.strtab.len());
@@ -1277,8 +1413,8 @@ fn writeHeader(self: *Coff) !void {
writer.writeAll(mem.asBytes(&coff_header)) catch unreachable;
const dll_flags: coff.DllFlags = .{
- .HIGH_ENTROPY_VA = 0, //@boolToInt(self.base.options.pie),
- .DYNAMIC_BASE = 0,
+ .HIGH_ENTROPY_VA = 1, // TODO do we want to permit non-PIE builds at all?
+ .DYNAMIC_BASE = 1,
.TERMINAL_SERVER_AWARE = 1, // We are not a legacy app
.NX_COMPAT = 1, // We are compatible with Data Execution Prevention
};
diff --git a/src/link/Coff/Atom.zig b/src/link/Coff/Atom.zig
index 6c085a8f58..a7608d9a34 100644
--- a/src/link/Coff/Atom.zig
+++ b/src/link/Coff/Atom.zig
@@ -2,6 +2,7 @@ const Atom = @This();
const std = @import("std");
const coff = std.coff;
+const log = std.log.scoped(.link);
const Allocator = std.mem.Allocator;
@@ -100,11 +101,20 @@ pub fn freeListEligible(self: Atom, coff_file: *const Coff) bool {
pub fn addRelocation(self: *Atom, coff_file: *Coff, reloc: Reloc) !void {
const gpa = coff_file.base.allocator;
- // TODO causes a segfault on Windows
- // log.debug("adding reloc of type {s} to target %{d}", .{ @tagName(reloc.@"type"), reloc.target.sym_index });
+ log.debug(" (adding reloc of type {s} to target %{d})", .{ @tagName(reloc.@"type"), reloc.target.sym_index });
const gop = try coff_file.relocs.getOrPut(gpa, self);
if (!gop.found_existing) {
gop.value_ptr.* = .{};
}
try gop.value_ptr.append(gpa, reloc);
}
+
+pub fn addBaseRelocation(self: *Atom, coff_file: *Coff, offset: u32) !void {
+ const gpa = coff_file.base.allocator;
+ log.debug(" (adding base relocation at offset 0x{x} in %{d})", .{ offset, self.sym_index });
+ const gop = try coff_file.base_relocs.getOrPut(gpa, self);
+ if (!gop.found_existing) {
+ gop.value_ptr.* = .{};
+ }
+ try gop.value_ptr.append(gpa, offset);
+}
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index 51ede6f699..68eb3b0aee 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -607,6 +607,24 @@ fn resolveSymbolsInArchives(self: *Wasm) !void {
}
}
+fn checkUndefinedSymbols(self: *const Wasm) !void {
+ var found_undefined_symbols = false;
+ for (self.undefs.values()) |undef| {
+ const symbol = undef.getSymbol(self);
+ if (symbol.tag == .data) {
+ found_undefined_symbols = true;
+ const file_name = if (undef.file) |file_index| name: {
+ break :name self.objects.items[file_index].name;
+ } else self.name;
+ log.err("could not resolve undefined symbol '{s}'", .{undef.getName(self)});
+ log.err(" defined in '{s}'", .{file_name});
+ }
+ }
+ if (found_undefined_symbols) {
+ return error.UndefinedSymbol;
+ }
+}
+
pub fn deinit(self: *Wasm) void {
const gpa = self.base.allocator;
if (build_options.have_llvm) {
@@ -783,15 +801,17 @@ pub fn updateDecl(self: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi
decl.link.wasm.clear();
- if (decl.isExtern()) {
- return;
- }
-
if (decl.val.castTag(.function)) |_| {
return;
} else if (decl.val.castTag(.extern_fn)) |_| {
return;
}
+
+ if (decl.isExtern()) {
+ const variable = decl.getVariable().?;
+ const name = mem.sliceTo(decl.name, 0);
+ return self.addOrUpdateImport(name, decl.link.wasm.sym_index, variable.lib_name, null);
+ }
const val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
var code_writer = std.ArrayList(u8).init(self.base.allocator);
@@ -834,19 +854,18 @@ pub fn updateDeclLineNumber(self: *Wasm, mod: *Module, decl: *const Module.Decl)
}
fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void {
- if (code.len == 0) return;
const mod = self.base.options.module.?;
const atom: *Atom = &decl.link.wasm;
- atom.size = @intCast(u32, code.len);
- atom.alignment = decl.ty.abiAlignment(self.base.options.target);
const symbol = &self.symbols.items[atom.sym_index];
-
const full_name = try decl.getFullyQualifiedName(mod);
defer self.base.allocator.free(full_name);
symbol.name = try self.string_table.put(self.base.allocator, full_name);
try atom.code.appendSlice(self.base.allocator, code);
-
try self.resolved_symbols.put(self.base.allocator, atom.symbolLoc(), {});
+
+ if (code.len == 0) return;
+ atom.size = @intCast(u32, code.len);
+ atom.alignment = decl.ty.abiAlignment(self.base.options.target);
}
/// From a given symbol location, returns its `wasm.GlobalType`.
@@ -1235,7 +1254,10 @@ pub fn addOrUpdateImport(
.kind = .{ .function = ty_index },
};
}
- } else @panic("TODO: Implement undefined symbols for non-function declarations");
+ } else {
+ symbol.tag = .data;
+ return; // non-functions will not be imported from the runtime, but only resolved during link-time
+ }
}
/// Kind represents the type of an Atom, which is only
@@ -1438,7 +1460,7 @@ fn setupImports(self: *Wasm) !void {
if (std.mem.eql(u8, symbol_loc.getName(self), "__indirect_function_table")) {
continue;
}
- if (symbol.tag == .data or !symbol.requiresImport()) {
+ if (!symbol.requiresImport()) {
continue;
}
@@ -2007,6 +2029,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
}
try self.resolveSymbolsInArchives();
+ try self.checkUndefinedSymbols();
// When we finish/error we reset the state of the linker
// So we can rebuild the binary file on each incremental update
diff --git a/src/link/Wasm/Atom.zig b/src/link/Wasm/Atom.zig
index d5bb4509f6..9e7f7a5a76 100644
--- a/src/link/Wasm/Atom.zig
+++ b/src/link/Wasm/Atom.zig
@@ -172,18 +172,16 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa
.R_WASM_MEMORY_ADDR_SLEB,
.R_WASM_MEMORY_ADDR_SLEB64,
=> {
- if (symbol.isUndefined() and symbol.isWeak()) {
- return 0;
- }
- std.debug.assert(symbol.tag == .data);
+ std.debug.assert(symbol.tag == .data and !symbol.isUndefined());
const merge_segment = wasm_bin.base.options.output_mode != .Obj;
- const segment_info = if (self.file) |object_index| blk: {
+ const target_atom_loc = wasm_bin.discarded.get(target_loc) orelse target_loc;
+ const target_atom = wasm_bin.symbol_atom.get(target_atom_loc).?;
+ const segment_info = if (target_atom.file) |object_index| blk: {
break :blk wasm_bin.objects.items[object_index].segment_info;
} else wasm_bin.segment_info.items;
const segment_name = segment_info[symbol.index].outputName(merge_segment);
- const atom_index = wasm_bin.data_segments.get(segment_name).?;
- const target_atom = wasm_bin.symbol_atom.get(target_loc).?;
- const segment = wasm_bin.segments.items[atom_index];
+ const segment_index = wasm_bin.data_segments.get(segment_name).?;
+ const segment = wasm_bin.segments.items[segment_index];
return target_atom.offset + segment.offset + (relocation.addend orelse 0);
},
.R_WASM_EVENT_INDEX_LEB => return symbol.index,
diff --git a/src/link/Wasm/Symbol.zig b/src/link/Wasm/Symbol.zig
index fa6ea89d69..5e13456605 100644
--- a/src/link/Wasm/Symbol.zig
+++ b/src/link/Wasm/Symbol.zig
@@ -79,9 +79,9 @@ pub const Flag = enum(u32) {
/// Verifies if the given symbol should be imported from the
/// host environment or not
pub fn requiresImport(self: Symbol) bool {
+ if (self.tag == .data) return false;
if (!self.isUndefined()) return false;
if (self.isWeak()) return false;
- if (self.tag == .data) return false;
// if (self.isDefined() and self.isWeak()) return true; //TODO: Only when building shared lib
return true;
diff --git a/src/main.zig b/src/main.zig
index e8a16e194a..6263a6a402 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -2750,8 +2750,22 @@ fn buildOutputType(
// Transfer packages added with --pkg-begin/--pkg-end to the root package
if (main_pkg) |pkg| {
+ var it = pkg_tree_root.table.valueIterator();
+ while (it.next()) |p| {
+ if (p.*.parent == &pkg_tree_root) {
+ p.*.parent = pkg;
+ }
+ }
pkg.table = pkg_tree_root.table;
pkg_tree_root.table = .{};
+ } else {
+ // Remove any dangling pointers just in case.
+ var it = pkg_tree_root.table.valueIterator();
+ while (it.next()) |p| {
+ if (p.*.parent == &pkg_tree_root) {
+ p.*.parent = null;
+ }
+ }
}
const self_exe_path = try introspect.findZigExePath(arena);
diff --git a/src/translate_c.zig b/src/translate_c.zig
index b0fae81475..faa8a456f5 100644
--- a/src/translate_c.zig
+++ b/src/translate_c.zig
@@ -1166,6 +1166,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
});
}
+ if (!c.zig_is_stage1 and is_packed) {
+ return failDecl(c, record_loc, bare_name, "cannot translate packed record union", .{});
+ }
+
const record_payload = try c.arena.create(ast.Payload.Record);
record_payload.* = .{
.base = .{ .tag = ([2]Tag{ .@"struct", .@"union" })[@boolToInt(is_union)] },
diff --git a/src/type.zig b/src/type.zig
index 5c9d3f60fc..c4f1782954 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -2042,6 +2042,9 @@ pub const Type = extern union {
try writer.writeAll("fn(");
for (fn_info.param_types) |param_ty, i| {
if (i != 0) try writer.writeAll(", ");
+ if (std.math.cast(u5, i)) |index| if (@truncate(u1, fn_info.noalias_bits >> index) != 0) {
+ try writer.writeAll("noalias ");
+ };
if (param_ty.tag() == .generic_poison) {
try writer.writeAll("anytype");
} else {
@@ -2398,7 +2401,7 @@ pub const Type = extern union {
} else if (ty.childType().zigTypeTag() == .Fn) {
return !ty.childType().fnInfo().is_generic;
} else if (sema_kit) |sk| {
- return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty));
+ return !(try sk.sema.typeRequiresComptime(ty));
} else {
return !comptimeOnly(ty);
}
@@ -2437,7 +2440,7 @@ pub const Type = extern union {
if (ignore_comptime_only) {
return true;
} else if (sema_kit) |sk| {
- return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, child_ty));
+ return !(try sk.sema.typeRequiresComptime(child_ty));
} else {
return !comptimeOnly(child_ty);
}
diff --git a/src/value.zig b/src/value.zig
index a1961b40f7..50f86c7e79 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -2940,17 +2940,24 @@ pub const Value = extern union {
}
pub fn intToFloat(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, target: Target) !Value {
+ return intToFloatAdvanced(val, arena, int_ty, float_ty, target, null) catch |err| switch (err) {
+ error.OutOfMemory => return error.OutOfMemory,
+ else => unreachable,
+ };
+ }
+
+ pub fn intToFloatAdvanced(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, target: Target, sema_kit: ?Module.WipAnalysis) !Value {
if (int_ty.zigTypeTag() == .Vector) {
const result_data = try arena.alloc(Value, int_ty.vectorLen());
for (result_data) |*scalar, i| {
- scalar.* = try intToFloatScalar(val.indexVectorlike(i), arena, float_ty.scalarType(), target);
+ scalar.* = try intToFloatScalar(val.indexVectorlike(i), arena, float_ty.scalarType(), target, sema_kit);
}
return Value.Tag.aggregate.create(arena, result_data);
}
- return intToFloatScalar(val, arena, float_ty, target);
+ return intToFloatScalar(val, arena, float_ty, target, sema_kit);
}
- pub fn intToFloatScalar(val: Value, arena: Allocator, float_ty: Type, target: Target) !Value {
+ pub fn intToFloatScalar(val: Value, arena: Allocator, float_ty: Type, target: Target, sema_kit: ?Module.WipAnalysis) !Value {
switch (val.tag()) {
.undef, .zero, .one => return val,
.the_only_possible_value => return Value.initTag(.zero), // for i0, u0
@@ -2970,6 +2977,22 @@ pub const Value = extern union {
const float = bigIntToFloat(limbs, false);
return floatToValue(float, arena, float_ty, target);
},
+ .lazy_align => {
+ const ty = val.castTag(.lazy_align).?.data;
+ if (sema_kit) |sk| {
+ return intToFloatInner((try ty.abiAlignmentAdvanced(target, .{ .sema_kit = sk })).scalar, arena, float_ty, target);
+ } else {
+ return intToFloatInner(ty.abiAlignment(target), arena, float_ty, target);
+ }
+ },
+ .lazy_size => {
+ const ty = val.castTag(.lazy_size).?.data;
+ if (sema_kit) |sk| {
+ return intToFloatInner((try ty.abiSizeAdvanced(target, .{ .sema_kit = sk })).scalar, arena, float_ty, target);
+ } else {
+ return intToFloatInner(ty.abiSize(target), arena, float_ty, target);
+ }
+ },
else => unreachable,
}
}