authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-21 00:01:30-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-09-21 00:01:30-04:00
log5269cbea202c6a81108390f4c47bc8a04fc6d1ff
treea95896bf83bb427953a6a33d037698e30c05d8f8
parent1ad905c71e0896295d4781853cd577bbe1b4111a
parent0c74ce1156d6a967cd089cd4657575a3e22bb782
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #9797 from Vexu/stage2

stage2: implement cImport

11 files changed, 550 insertions(+), 267 deletions(-)

src/AstGen.zig+8-3
...@@ -7082,7 +7082,7 @@ fn builtinCall(...@@ -7082,7 +7082,7 @@ fn builtinCall(
7082 .bit_cast => return bitCast( gz, scope, rl, node, params[0], params[1]),7082 .bit_cast => return bitCast( gz, scope, rl, node, params[0], params[1]),
7083 .TypeOf => return typeOf( gz, scope, rl, node, params),7083 .TypeOf => return typeOf( gz, scope, rl, node, params),
7084 .union_init => return unionInit(gz, scope, rl, node, params),7084 .union_init => return unionInit(gz, scope, rl, node, params),
7085 .c_import => return cImport( gz, scope, rl, node, params[0]),7085 .c_import => return cImport( gz, scope, node, params[0]),
70867086
7087 .@"export" => {7087 .@"export" => {
7088 const node_tags = tree.nodes.items(.tag);7088 const node_tags = tree.nodes.items(.tag);
...@@ -7269,6 +7269,7 @@ fn builtinCall(...@@ -7269,6 +7269,7 @@ fn builtinCall(
7269 return rvalue(gz, rl, result, node);7269 return rvalue(gz, rl, result, node);
7270 },7270 },
7271 .c_define => {7271 .c_define => {
7272 if (!gz.c_import) return gz.astgen.failNode(node, "C define valid only inside C import block", .{});
7272 const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[0]);7273 const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[0]);
7273 const value = try comptimeExpr(gz, scope, .none, params[1]);7274 const value = try comptimeExpr(gz, scope, .none, params[1]);
7274 const result = try gz.addExtendedPayload(.c_define, Zir.Inst.BinNode{7275 const result = try gz.addExtendedPayload(.c_define, Zir.Inst.BinNode{
...@@ -7641,6 +7642,8 @@ fn simpleCBuiltin(...@@ -7641,6 +7642,8 @@ fn simpleCBuiltin(
7641 operand_node: Ast.Node.Index,7642 operand_node: Ast.Node.Index,
7642 tag: Zir.Inst.Extended,7643 tag: Zir.Inst.Extended,
7643) InnerError!Zir.Inst.Ref {7644) InnerError!Zir.Inst.Ref {
7645 const name: []const u8 = if (tag == .c_undef) "C undef" else "C include";
7646 if (!gz.c_import) return gz.astgen.failNode(node, "{s} valid only inside C import block", .{name});
7644 const operand = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, operand_node);7647 const operand = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, operand_node);
7645 _ = try gz.addExtendedPayload(tag, Zir.Inst.UnNode{7648 _ = try gz.addExtendedPayload(tag, Zir.Inst.UnNode{
7646 .node = gz.nodeIndexToRelative(node),7649 .node = gz.nodeIndexToRelative(node),
...@@ -7689,7 +7692,6 @@ fn shiftOp(...@@ -7689,7 +7692,6 @@ fn shiftOp(
7689fn cImport(7692fn cImport(
7690 gz: *GenZir,7693 gz: *GenZir,
7691 scope: *Scope,7694 scope: *Scope,
7692 rl: ResultLoc,
7693 node: Ast.Node.Index,7695 node: Ast.Node.Index,
7694 body_node: Ast.Node.Index,7696 body_node: Ast.Node.Index,
7695) InnerError!Zir.Inst.Ref {7697) InnerError!Zir.Inst.Ref {
...@@ -7698,6 +7700,7 @@ fn cImport(...@@ -7698,6 +7700,7 @@ fn cImport(
76987700
7699 var block_scope = gz.makeSubBlock(scope);7701 var block_scope = gz.makeSubBlock(scope);
7700 block_scope.force_comptime = true;7702 block_scope.force_comptime = true;
7703 block_scope.c_import = true;
7701 defer block_scope.instructions.deinit(gpa);7704 defer block_scope.instructions.deinit(gpa);
77027705
7703 const block_inst = try gz.addBlock(.c_import, node);7706 const block_inst = try gz.addBlock(.c_import, node);
...@@ -7708,7 +7711,7 @@ fn cImport(...@@ -7708,7 +7711,7 @@ fn cImport(
7708 try block_scope.setBlockBody(block_inst);7711 try block_scope.setBlockBody(block_inst);
7709 try gz.instructions.append(gpa, block_inst);7712 try gz.instructions.append(gpa, block_inst);
77107713
7711 return rvalue(gz, rl, .void_value, node);7714 return indexToRef(block_inst);
7712}7715}
77137716
7714fn overflowArithmetic(7717fn overflowArithmetic(
...@@ -9025,6 +9028,7 @@ const GenZir = struct {...@@ -9025,6 +9028,7 @@ const GenZir = struct {
9025 base: Scope = Scope{ .tag = base_tag },9028 base: Scope = Scope{ .tag = base_tag },
9026 force_comptime: bool,9029 force_comptime: bool,
9027 in_defer: bool,9030 in_defer: bool,
9031 c_import: bool = false,
9028 /// How decls created in this scope should be named.9032 /// How decls created in this scope should be named.
9029 anon_name_strategy: Zir.Inst.NameStrategy = .anon,9033 anon_name_strategy: Zir.Inst.NameStrategy = .anon,
9030 /// The containing decl AST node.9034 /// The containing decl AST node.
...@@ -9070,6 +9074,7 @@ const GenZir = struct {...@@ -9070,6 +9074,7 @@ const GenZir = struct {
9070 return .{9074 return .{
9071 .force_comptime = gz.force_comptime,9075 .force_comptime = gz.force_comptime,
9072 .in_defer = gz.in_defer,9076 .in_defer = gz.in_defer,
9077 .c_import = gz.c_import,
9073 .decl_node_index = gz.decl_node_index,9078 .decl_node_index = gz.decl_node_index,
9074 .decl_line = gz.decl_line,9079 .decl_line = gz.decl_line,
9075 .parent = scope,9080 .parent = scope,
src/Compilation.zig+1-1
...@@ -2644,7 +2644,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {...@@ -2644,7 +2644,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
26442644
2645 const dep_basename = std.fs.path.basename(out_dep_path);2645 const dep_basename = std.fs.path.basename(out_dep_path);
2646 try man.addDepFilePost(zig_cache_tmp_dir, dep_basename);2646 try man.addDepFilePost(zig_cache_tmp_dir, dep_basename);
2647 try comp.stage1_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename);2647 if (build_options.is_stage1 and comp.bin_file.options.use_stage1) try comp.stage1_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename);
26482648
2649 const digest = man.final();2649 const digest = man.final();
2650 const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });2650 const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
src/Module.zig+3
...@@ -1325,6 +1325,8 @@ pub const Scope = struct {...@@ -1325,6 +1325,8 @@ pub const Scope = struct {
1325 /// when null, it is determined by build mode, changed by @setRuntimeSafety1325 /// when null, it is determined by build mode, changed by @setRuntimeSafety
1326 want_safety: ?bool = null,1326 want_safety: ?bool = null,
13271327
1328 c_import_buf: ?*std.ArrayList(u8) = null,
1329
1328 const Param = struct {1330 const Param = struct {
1329 /// `noreturn` means `anytype`.1331 /// `noreturn` means `anytype`.
1330 ty: Type,1332 ty: Type,
...@@ -1377,6 +1379,7 @@ pub const Scope = struct {...@@ -1377,6 +1379,7 @@ pub const Scope = struct {
1377 .runtime_loop = parent.runtime_loop,1379 .runtime_loop = parent.runtime_loop,
1378 .runtime_index = parent.runtime_index,1380 .runtime_index = parent.runtime_index,
1379 .want_safety = parent.want_safety,1381 .want_safety = parent.want_safety,
1382 .c_import_buf = parent.c_import_buf,
1380 };1383 };
1381 }1384 }
13821385
src/Sema.zig+274-21
...@@ -83,6 +83,7 @@ const Decl = Module.Decl;...@@ -83,6 +83,7 @@ const Decl = Module.Decl;
83const LazySrcLoc = Module.LazySrcLoc;83const LazySrcLoc = Module.LazySrcLoc;
84const RangeSet = @import("RangeSet.zig");84const RangeSet = @import("RangeSet.zig");
85const target_util = @import("target.zig");85const target_util = @import("target.zig");
86const Package = @import("Package.zig");
8687
87pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref);88pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref);
8889
...@@ -2138,10 +2139,77 @@ fn zirCImport(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) Com...@@ -2138,10 +2139,77 @@ fn zirCImport(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) Com
2138 const tracy = trace(@src());2139 const tracy = trace(@src());
2139 defer tracy.end();2140 defer tracy.end();
21402141
2141 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;2142 const pl_node = sema.code.instructions.items(.data)[inst].pl_node;
2142 const src = inst_data.src();2143 const src = pl_node.src();
2144 const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index);
2145 const body = sema.code.extra[extra.end..][0..extra.data.body_len];
2146
2147 // we check this here to avoid undefined symbols
2148 if (!@import("build_options").have_llvm)
2149 return sema.mod.fail(&parent_block.base, src, "cannot do C import on Zig compiler not built with LLVM-extension", .{});
2150
2151 var c_import_buf = std.ArrayList(u8).init(sema.gpa);
2152 defer c_import_buf.deinit();
2153
2154 var child_block: Scope.Block = .{
2155 .parent = parent_block,
2156 .sema = sema,
2157 .src_decl = parent_block.src_decl,
2158 .instructions = .{},
2159 .inlining = parent_block.inlining,
2160 .is_comptime = parent_block.is_comptime,
2161 .c_import_buf = &c_import_buf,
2162 };
2163 defer child_block.instructions.deinit(sema.gpa);
2164
2165 _ = try sema.analyzeBody(&child_block, body);
2166
2167 const c_import_res = sema.mod.comp.cImport(c_import_buf.items) catch |err|
2168 return sema.mod.fail(&child_block.base, src, "C import failed: {s}", .{@errorName(err)});
2169
2170 if (c_import_res.errors.len != 0) {
2171 const msg = msg: {
2172 const msg = try sema.mod.errMsg(&child_block.base, src, "C import failed", .{});
2173 errdefer msg.destroy(sema.gpa);
2174
2175 if (!sema.mod.comp.bin_file.options.link_libc)
2176 try sema.mod.errNote(&child_block.base, src, msg, "libc headers not available; compilation does not link against libc", .{});
2177
2178 for (c_import_res.errors) |_| {
2179 // TODO integrate with LazySrcLoc
2180 // try sema.mod.errNoteNonLazy(.{}, msg, "{s}", .{clang_err.msg_ptr[0..clang_err.msg_len]});
2181 // if (clang_err.filename_ptr) |p| p[0..clang_err.filename_len] else "(no file)",
2182 // clang_err.line + 1,
2183 // clang_err.column + 1,
2184 }
2185 @import("clang.zig").Stage2ErrorMsg.delete(c_import_res.errors.ptr, c_import_res.errors.len);
2186 break :msg msg;
2187 };
2188 return sema.mod.failWithOwnedErrorMsg(&child_block.base, msg);
2189 }
2190 const c_import_pkg = Package.create(
2191 sema.gpa,
2192 null,
2193 c_import_res.out_zig_path,
2194 ) catch |err| switch (err) {
2195 error.OutOfMemory => return error.OutOfMemory,
2196 else => unreachable, // we pass null for root_src_dir_path
2197 };
2198 const std_pkg = sema.mod.main_pkg.table.get("std").?;
2199 const builtin_pkg = sema.mod.main_pkg.table.get("builtin").?;
2200 try c_import_pkg.add(sema.gpa, "builtin", builtin_pkg);
2201 try c_import_pkg.add(sema.gpa, "std", std_pkg);
2202
2203 const result = sema.mod.importPkg(c_import_pkg) catch |err|
2204 return sema.mod.fail(&child_block.base, src, "C import failed: {s}", .{@errorName(err)});
2205
2206 sema.mod.astGenFile(result.file) catch |err|
2207 return sema.mod.fail(&child_block.base, src, "C import failed: {s}", .{@errorName(err)});
21432208
2144 return sema.mod.fail(&parent_block.base, src, "TODO: implement Sema.zirCImport", .{});2209 try sema.mod.semaFile(result.file);
2210 const file_root_decl = result.file.root_decl.?;
2211 try sema.mod.declareDeclDependency(sema.owner_decl, file_root_decl);
2212 return sema.addType(file_root_decl.ty);
2145}2213}
21462214
2147fn zirSuspendBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {2215fn zirSuspendBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -6405,10 +6473,41 @@ fn runtimeBoolCmp(...@@ -6405,10 +6473,41 @@ fn runtimeBoolCmp(
64056473
6406fn zirSizeOf(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {6474fn zirSizeOf(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
6407 const inst_data = sema.code.instructions.items(.data)[inst].un_node;6475 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
6476 const src = inst_data.src();
6408 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };6477 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
6409 const operand_ty = try sema.resolveType(block, operand_src, inst_data.operand);6478 const operand_ty = try sema.resolveType(block, operand_src, inst_data.operand);
6410 const target = sema.mod.getTarget();6479 const target = sema.mod.getTarget();
6411 const abi_size = operand_ty.abiSize(target);6480 const abi_size = switch (operand_ty.zigTypeTag()) {
6481 .Fn => unreachable,
6482 .NoReturn,
6483 .Undefined,
6484 .Null,
6485 .BoundFn,
6486 .Opaque,
6487 => return sema.mod.fail(&block.base, src, "no size available for type '{}'", .{operand_ty}),
6488 .Type,
6489 .EnumLiteral,
6490 .ComptimeFloat,
6491 .ComptimeInt,
6492 .Void,
6493 => 0,
6494
6495 .Bool,
6496 .Int,
6497 .Float,
6498 .Pointer,
6499 .Array,
6500 .Struct,
6501 .Optional,
6502 .ErrorUnion,
6503 .ErrorSet,
6504 .Enum,
6505 .Union,
6506 .Vector,
6507 .Frame,
6508 .AnyFrame,
6509 => operand_ty.abiSize(target),
6510 };
6412 return sema.addIntUnsigned(Type.initTag(.comptime_int), abi_size);6511 return sema.addIntUnsigned(Type.initTag(.comptime_int), abi_size);
6413}6512}
64146513
...@@ -6456,19 +6555,80 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr...@@ -6456,19 +6555,80 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
6456 const target = sema.mod.getTarget();6555 const target = sema.mod.getTarget();
64576556
6458 switch (ty.zigTypeTag()) {6557 switch (ty.zigTypeTag()) {
6558 .Type => return sema.addConstant(
6559 type_info_ty,
6560 try Value.Tag.@"union".create(sema.arena, .{
6561 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Type)),
6562 .val = Value.initTag(.unreachable_value),
6563 }),
6564 ),
6565 .Void => return sema.addConstant(
6566 type_info_ty,
6567 try Value.Tag.@"union".create(sema.arena, .{
6568 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Void)),
6569 .val = Value.initTag(.unreachable_value),
6570 }),
6571 ),
6572 .Bool => return sema.addConstant(
6573 type_info_ty,
6574 try Value.Tag.@"union".create(sema.arena, .{
6575 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Bool)),
6576 .val = Value.initTag(.unreachable_value),
6577 }),
6578 ),
6579 .NoReturn => return sema.addConstant(
6580 type_info_ty,
6581 try Value.Tag.@"union".create(sema.arena, .{
6582 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.NoReturn)),
6583 .val = Value.initTag(.unreachable_value),
6584 }),
6585 ),
6586 .ComptimeFloat => return sema.addConstant(
6587 type_info_ty,
6588 try Value.Tag.@"union".create(sema.arena, .{
6589 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ComptimeFloat)),
6590 .val = Value.initTag(.unreachable_value),
6591 }),
6592 ),
6593 .ComptimeInt => return sema.addConstant(
6594 type_info_ty,
6595 try Value.Tag.@"union".create(sema.arena, .{
6596 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ComptimeInt)),
6597 .val = Value.initTag(.unreachable_value),
6598 }),
6599 ),
6600 .Undefined => return sema.addConstant(
6601 type_info_ty,
6602 try Value.Tag.@"union".create(sema.arena, .{
6603 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Undefined)),
6604 .val = Value.initTag(.unreachable_value),
6605 }),
6606 ),
6607 .Null => return sema.addConstant(
6608 type_info_ty,
6609 try Value.Tag.@"union".create(sema.arena, .{
6610 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Null)),
6611 .val = Value.initTag(.unreachable_value),
6612 }),
6613 ),
6614 .EnumLiteral => return sema.addConstant(
6615 type_info_ty,
6616 try Value.Tag.@"union".create(sema.arena, .{
6617 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.EnumLiteral)),
6618 .val = Value.initTag(.unreachable_value),
6619 }),
6620 ),
6459 .Fn => {6621 .Fn => {
6622 const info = ty.fnInfo();
6460 const field_values = try sema.arena.alloc(Value, 6);6623 const field_values = try sema.arena.alloc(Value, 6);
6461 // calling_convention: CallingConvention,6624 // calling_convention: CallingConvention,
6462 field_values[0] = try Value.Tag.enum_field_index.create(6625 field_values[0] = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.cc));
6463 sema.arena,
6464 @enumToInt(ty.fnCallingConvention()),
6465 );
6466 // alignment: comptime_int,6626 // alignment: comptime_int,
6467 field_values[1] = try Value.Tag.int_u64.create(sema.arena, ty.abiAlignment(target));6627 field_values[1] = try Value.Tag.int_u64.create(sema.arena, ty.abiAlignment(target));
6468 // is_generic: bool,6628 // is_generic: bool,
6469 field_values[2] = Value.initTag(.bool_false); // TODO6629 field_values[2] = if (info.is_generic) Value.initTag(.bool_true) else Value.initTag(.bool_false);
6470 // is_var_args: bool,6630 // is_var_args: bool,
6471 field_values[3] = Value.initTag(.bool_false); // TODO6631 field_values[3] = if (info.is_var_args) Value.initTag(.bool_true) else Value.initTag(.bool_false);
6472 // return_type: ?type,6632 // return_type: ?type,
6473 field_values[4] = try Value.Tag.ty.create(sema.arena, ty.fnReturnType());6633 field_values[4] = try Value.Tag.ty.create(sema.arena, ty.fnReturnType());
6474 // args: []const FnArg,6634 // args: []const FnArg,
...@@ -6477,10 +6637,7 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr...@@ -6477,10 +6637,7 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
6477 return sema.addConstant(6637 return sema.addConstant(
6478 type_info_ty,6638 type_info_ty,
6479 try Value.Tag.@"union".create(sema.arena, .{6639 try Value.Tag.@"union".create(sema.arena, .{
6480 .tag = try Value.Tag.enum_field_index.create(6640 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Fn)),
6481 sema.arena,
6482 @enumToInt(@typeInfo(std.builtin.TypeInfo).Union.tag_type.?.Fn),
6483 ),
6484 .val = try Value.Tag.@"struct".create(sema.arena, field_values),6641 .val = try Value.Tag.@"struct".create(sema.arena, field_values),
6485 }),6642 }),
6486 );6643 );
...@@ -6499,10 +6656,92 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr...@@ -6499,10 +6656,92 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
6499 return sema.addConstant(6656 return sema.addConstant(
6500 type_info_ty,6657 type_info_ty,
6501 try Value.Tag.@"union".create(sema.arena, .{6658 try Value.Tag.@"union".create(sema.arena, .{
6502 .tag = try Value.Tag.enum_field_index.create(6659 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Int)),
6503 sema.arena,6660 .val = try Value.Tag.@"struct".create(sema.arena, field_values),
6504 @enumToInt(@typeInfo(std.builtin.TypeInfo).Union.tag_type.?.Int),6661 }),
6505 ),6662 );
6663 },
6664 .Float => {
6665 const field_values = try sema.arena.alloc(Value, 1);
6666 // bits: comptime_int,
6667 field_values[0] = try Value.Tag.int_u64.create(sema.arena, ty.bitSize(target));
6668
6669 return sema.addConstant(
6670 type_info_ty,
6671 try Value.Tag.@"union".create(sema.arena, .{
6672 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Float)),
6673 .val = try Value.Tag.@"struct".create(sema.arena, field_values),
6674 }),
6675 );
6676 },
6677 .Pointer => {
6678 const info = ty.ptrInfo().data;
6679 const field_values = try sema.arena.alloc(Value, 7);
6680 // size: Size,
6681 field_values[0] = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.size));
6682 // is_const: bool,
6683 field_values[1] = if (!info.mutable) Value.initTag(.bool_true) else Value.initTag(.bool_false);
6684 // is_volatile: bool,
6685 field_values[2] = if (info.@"volatile") Value.initTag(.bool_true) else Value.initTag(.bool_false);
6686 // alignment: comptime_int,
6687 field_values[3] = try Value.Tag.int_u64.create(sema.arena, info.@"align");
6688 // child: type,
6689 field_values[4] = try Value.Tag.ty.create(sema.arena, info.pointee_type);
6690 // is_allowzero: bool,
6691 field_values[5] = if (info.@"allowzero") Value.initTag(.bool_true) else Value.initTag(.bool_false);
6692 // sentinel: anytype,
6693 field_values[6] = if (info.sentinel) |some| try Value.Tag.opt_payload.create(sema.arena, some) else Value.initTag(.null_value);
6694
6695 return sema.addConstant(
6696 type_info_ty,
6697 try Value.Tag.@"union".create(sema.arena, .{
6698 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Pointer)),
6699 .val = try Value.Tag.@"struct".create(sema.arena, field_values),
6700 }),
6701 );
6702 },
6703 .Array => {
6704 const info = ty.arrayInfo();
6705 const field_values = try sema.arena.alloc(Value, 3);
6706 // len: comptime_int,
6707 field_values[0] = try Value.Tag.int_u64.create(sema.arena, info.len);
6708 // child: type,
6709 field_values[1] = try Value.Tag.ty.create(sema.arena, info.elem_type);
6710 // sentinel: anytype,
6711 field_values[2] = if (info.sentinel) |some| try Value.Tag.opt_payload.create(sema.arena, some) else Value.initTag(.null_value);
6712
6713 return sema.addConstant(
6714 type_info_ty,
6715 try Value.Tag.@"union".create(sema.arena, .{
6716 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Array)),
6717 .val = try Value.Tag.@"struct".create(sema.arena, field_values),
6718 }),
6719 );
6720 },
6721 .Optional => {
6722 const field_values = try sema.arena.alloc(Value, 1);
6723 // child: type,
6724 field_values[0] = try Value.Tag.ty.create(sema.arena, try ty.optionalChildAlloc(sema.arena));
6725
6726 return sema.addConstant(
6727 type_info_ty,
6728 try Value.Tag.@"union".create(sema.arena, .{
6729 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Optional)),
6730 .val = try Value.Tag.@"struct".create(sema.arena, field_values),
6731 }),
6732 );
6733 },
6734 .ErrorUnion => {
6735 const field_values = try sema.arena.alloc(Value, 2);
6736 // error_set: type,
6737 field_values[0] = try Value.Tag.ty.create(sema.arena, ty.errorUnionSet());
6738 // payload: type,
6739 field_values[1] = try Value.Tag.ty.create(sema.arena, ty.errorUnionPayload());
6740
6741 return sema.addConstant(
6742 type_info_ty,
6743 try Value.Tag.@"union".create(sema.arena, .{
6744 .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ErrorUnion)),
6506 .val = try Value.Tag.@"struct".create(sema.arena, field_values),6745 .val = try Value.Tag.@"struct".create(sema.arena, field_values),
6507 }),6746 }),
6508 );6747 );
...@@ -8226,7 +8465,10 @@ fn zirCUndef(...@@ -8226,7 +8465,10 @@ fn zirCUndef(
8226) CompileError!Air.Inst.Ref {8465) CompileError!Air.Inst.Ref {
8227 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;8466 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
8228 const src: LazySrcLoc = .{ .node_offset = extra.node };8467 const src: LazySrcLoc = .{ .node_offset = extra.node };
8229 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirCUndef", .{});8468
8469 const name = try sema.resolveConstString(block, src, extra.operand);
8470 try block.c_import_buf.?.writer().print("#undefine {s}\n", .{name});
8471 return Air.Inst.Ref.void_value;
8230}8472}
82318473
8232fn zirCInclude(8474fn zirCInclude(
...@@ -8236,7 +8478,10 @@ fn zirCInclude(...@@ -8236,7 +8478,10 @@ fn zirCInclude(
8236) CompileError!Air.Inst.Ref {8478) CompileError!Air.Inst.Ref {
8237 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;8479 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
8238 const src: LazySrcLoc = .{ .node_offset = extra.node };8480 const src: LazySrcLoc = .{ .node_offset = extra.node };
8239 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirCInclude", .{});8481
8482 const name = try sema.resolveConstString(block, src, extra.operand);
8483 try block.c_import_buf.?.writer().print("#include <{s}>\n", .{name});
8484 return Air.Inst.Ref.void_value;
8240}8485}
82418486
8242fn zirCDefine(8487fn zirCDefine(
...@@ -8246,7 +8491,15 @@ fn zirCDefine(...@@ -8246,7 +8491,15 @@ fn zirCDefine(
8246) CompileError!Air.Inst.Ref {8491) CompileError!Air.Inst.Ref {
8247 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;8492 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
8248 const src: LazySrcLoc = .{ .node_offset = extra.node };8493 const src: LazySrcLoc = .{ .node_offset = extra.node };
8249 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirCDefine", .{});8494
8495 const name = try sema.resolveConstString(block, src, extra.lhs);
8496 if (sema.typeOf(extra.rhs).zigTypeTag() != .Void) {
8497 const value = try sema.resolveConstString(block, src, extra.rhs);
8498 try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value });
8499 } else {
8500 try block.c_import_buf.?.writer().print("#define {s}\n", .{name});
8501 }
8502 return Air.Inst.Ref.void_value;
8250}8503}
82518504
8252fn zirWasmMemorySize(8505fn zirWasmMemorySize(
src/print_zir.zig+15-3
...@@ -407,15 +407,27 @@ const Writer = struct {...@@ -407,15 +407,27 @@ const Writer = struct {
407 .mul_with_saturation,407 .mul_with_saturation,
408 .shl_with_saturation,408 .shl_with_saturation,
409 => try self.writeSaturatingArithmetic(stream, extended),409 => try self.writeSaturatingArithmetic(stream, extended),
410
410 .struct_decl => try self.writeStructDecl(stream, extended),411 .struct_decl => try self.writeStructDecl(stream, extended),
411 .union_decl => try self.writeUnionDecl(stream, extended),412 .union_decl => try self.writeUnionDecl(stream, extended),
412 .enum_decl => try self.writeEnumDecl(stream, extended),413 .enum_decl => try self.writeEnumDecl(stream, extended),
413414
415 .c_undef, .c_include => {
416 const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
417 try self.writeInstRef(stream, inst_data.operand);
418 try stream.writeAll(") ");
419 },
420
421 .c_define => {
422 const inst_data = self.code.extraData(Zir.Inst.BinNode, extended.operand).data;
423 try self.writeInstRef(stream, inst_data.lhs);
424 try stream.writeAll(", ");
425 try self.writeInstRef(stream, inst_data.rhs);
426 try stream.writeByte(')');
427 },
428
414 .alloc,429 .alloc,
415 .builtin_extern,430 .builtin_extern,
416 .c_undef,
417 .c_include,
418 .c_define,
419 .wasm_memory_size,431 .wasm_memory_size,
420 .wasm_memory_grow,432 .wasm_memory_grow,
421 => try stream.writeAll("TODO))"),433 => try stream.writeAll("TODO))"),
src/type.zig+1-1
...@@ -602,8 +602,8 @@ pub const Type = extern union {...@@ -602,8 +602,8 @@ pub const Type = extern union {
602 }602 }
603 return false;603 return false;
604 },604 },
605 .Float => return a.tag() == b.tag(),
605 .Opaque,606 .Opaque,
606 .Float,
607 .BoundFn,607 .BoundFn,
608 .Frame,608 .Frame,
609 => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),609 => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),
test/behavior.zig+4-2
...@@ -11,6 +11,8 @@ test {...@@ -11,6 +11,8 @@ test {
11 _ = @import("behavior/array.zig");11 _ = @import("behavior/array.zig");
12 _ = @import("behavior/usingnamespace.zig");12 _ = @import("behavior/usingnamespace.zig");
13 _ = @import("behavior/atomics.zig");13 _ = @import("behavior/atomics.zig");
14 _ = @import("behavior/sizeof_and_typeof.zig");
15 _ = @import("behavior/translate_c_macros.zig");
1416
15 if (builtin.zig_is_stage2) {17 if (builtin.zig_is_stage2) {
16 // When all comptime_memory.zig tests pass, #9646 can be closed.18 // When all comptime_memory.zig tests pass, #9646 can be closed.
...@@ -128,7 +130,7 @@ test {...@@ -128,7 +130,7 @@ test {
128 _ = @import("behavior/saturating_arithmetic.zig");130 _ = @import("behavior/saturating_arithmetic.zig");
129 _ = @import("behavior/shuffle.zig");131 _ = @import("behavior/shuffle.zig");
130 _ = @import("behavior/select.zig");132 _ = @import("behavior/select.zig");
131 _ = @import("behavior/sizeof_and_typeof.zig");133 _ = @import("behavior/sizeof_and_typeof_stage1.zig");
132 _ = @import("behavior/slice.zig");134 _ = @import("behavior/slice.zig");
133 _ = @import("behavior/slice_sentinel_comptime.zig");135 _ = @import("behavior/slice_sentinel_comptime.zig");
134 _ = @import("behavior/struct.zig");136 _ = @import("behavior/struct.zig");
...@@ -157,6 +159,6 @@ test {...@@ -157,6 +159,6 @@ test {
157 _ = @import("behavior/while.zig");159 _ = @import("behavior/while.zig");
158 _ = @import("behavior/widening.zig");160 _ = @import("behavior/widening.zig");
159 _ = @import("behavior/src.zig");161 _ = @import("behavior/src.zig");
160 _ = @import("behavior/translate_c_macros.zig");162 _ = @import("behavior/translate_c_macros_stage1.zig");
161 }163 }
162}164}
test/behavior/sizeof_and_typeof.zig-214
...@@ -10,118 +10,6 @@ test "@sizeOf and @TypeOf" {...@@ -10,118 +10,6 @@ test "@sizeOf and @TypeOf" {
10const x: u16 = 13;10const x: u16 = 13;
11const z: @TypeOf(x) = 19;11const z: @TypeOf(x) = 19;
1212
13const A = struct {
14 a: u8,
15 b: u32,
16 c: u8,
17 d: u3,
18 e: u5,
19 f: u16,
20 g: u16,
21 h: u9,
22 i: u7,
23};
24
25const P = packed struct {
26 a: u8,
27 b: u32,
28 c: u8,
29 d: u3,
30 e: u5,
31 f: u16,
32 g: u16,
33 h: u9,
34 i: u7,
35};
36
37test "@offsetOf" {
38 // Packed structs have fixed memory layout
39 try expect(@offsetOf(P, "a") == 0);
40 try expect(@offsetOf(P, "b") == 1);
41 try expect(@offsetOf(P, "c") == 5);
42 try expect(@offsetOf(P, "d") == 6);
43 try expect(@offsetOf(P, "e") == 6);
44 try expect(@offsetOf(P, "f") == 7);
45 try expect(@offsetOf(P, "g") == 9);
46 try expect(@offsetOf(P, "h") == 11);
47 try expect(@offsetOf(P, "i") == 12);
48
49 // Normal struct fields can be moved/padded
50 var a: A = undefined;
51 try expect(@ptrToInt(&a.a) - @ptrToInt(&a) == @offsetOf(A, "a"));
52 try expect(@ptrToInt(&a.b) - @ptrToInt(&a) == @offsetOf(A, "b"));
53 try expect(@ptrToInt(&a.c) - @ptrToInt(&a) == @offsetOf(A, "c"));
54 try expect(@ptrToInt(&a.d) - @ptrToInt(&a) == @offsetOf(A, "d"));
55 try expect(@ptrToInt(&a.e) - @ptrToInt(&a) == @offsetOf(A, "e"));
56 try expect(@ptrToInt(&a.f) - @ptrToInt(&a) == @offsetOf(A, "f"));
57 try expect(@ptrToInt(&a.g) - @ptrToInt(&a) == @offsetOf(A, "g"));
58 try expect(@ptrToInt(&a.h) - @ptrToInt(&a) == @offsetOf(A, "h"));
59 try expect(@ptrToInt(&a.i) - @ptrToInt(&a) == @offsetOf(A, "i"));
60}
61
62test "@offsetOf packed struct, array length not power of 2 or multiple of native pointer width in bytes" {
63 const p3a_len = 3;
64 const P3 = packed struct {
65 a: [p3a_len]u8,
66 b: usize,
67 };
68 try std.testing.expectEqual(0, @offsetOf(P3, "a"));
69 try std.testing.expectEqual(p3a_len, @offsetOf(P3, "b"));
70
71 const p5a_len = 5;
72 const P5 = packed struct {
73 a: [p5a_len]u8,
74 b: usize,
75 };
76 try std.testing.expectEqual(0, @offsetOf(P5, "a"));
77 try std.testing.expectEqual(p5a_len, @offsetOf(P5, "b"));
78
79 const p6a_len = 6;
80 const P6 = packed struct {
81 a: [p6a_len]u8,
82 b: usize,
83 };
84 try std.testing.expectEqual(0, @offsetOf(P6, "a"));
85 try std.testing.expectEqual(p6a_len, @offsetOf(P6, "b"));
86
87 const p7a_len = 7;
88 const P7 = packed struct {
89 a: [p7a_len]u8,
90 b: usize,
91 };
92 try std.testing.expectEqual(0, @offsetOf(P7, "a"));
93 try std.testing.expectEqual(p7a_len, @offsetOf(P7, "b"));
94
95 const p9a_len = 9;
96 const P9 = packed struct {
97 a: [p9a_len]u8,
98 b: usize,
99 };
100 try std.testing.expectEqual(0, @offsetOf(P9, "a"));
101 try std.testing.expectEqual(p9a_len, @offsetOf(P9, "b"));
102
103 // 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 25 etc. are further cases
104}
105
106test "@bitOffsetOf" {
107 // Packed structs have fixed memory layout
108 try expect(@bitOffsetOf(P, "a") == 0);
109 try expect(@bitOffsetOf(P, "b") == 8);
110 try expect(@bitOffsetOf(P, "c") == 40);
111 try expect(@bitOffsetOf(P, "d") == 48);
112 try expect(@bitOffsetOf(P, "e") == 51);
113 try expect(@bitOffsetOf(P, "f") == 56);
114 try expect(@bitOffsetOf(P, "g") == 72);
115
116 try expect(@offsetOf(A, "a") * 8 == @bitOffsetOf(A, "a"));
117 try expect(@offsetOf(A, "b") * 8 == @bitOffsetOf(A, "b"));
118 try expect(@offsetOf(A, "c") * 8 == @bitOffsetOf(A, "c"));
119 try expect(@offsetOf(A, "d") * 8 == @bitOffsetOf(A, "d"));
120 try expect(@offsetOf(A, "e") * 8 == @bitOffsetOf(A, "e"));
121 try expect(@offsetOf(A, "f") * 8 == @bitOffsetOf(A, "f"));
122 try expect(@offsetOf(A, "g") * 8 == @bitOffsetOf(A, "g"));
123}
124
125test "@sizeOf on compile-time types" {13test "@sizeOf on compile-time types" {
126 try expect(@sizeOf(comptime_int) == 0);14 try expect(@sizeOf(comptime_int) == 0);
127 try expect(@sizeOf(comptime_float) == 0);15 try expect(@sizeOf(comptime_float) == 0);
...@@ -129,34 +17,6 @@ test "@sizeOf on compile-time types" {...@@ -129,34 +17,6 @@ test "@sizeOf on compile-time types" {
129 try expect(@sizeOf(@TypeOf(type)) == 0);17 try expect(@sizeOf(@TypeOf(type)) == 0);
130}18}
13119
132test "@sizeOf(T) == 0 doesn't force resolving struct size" {
133 const S = struct {
134 const Foo = struct {
135 y: if (@sizeOf(Foo) == 0) u64 else u32,
136 };
137 const Bar = struct {
138 x: i32,
139 y: if (0 == @sizeOf(Bar)) u64 else u32,
140 };
141 };
142
143 try expect(@sizeOf(S.Foo) == 4);
144 try expect(@sizeOf(S.Bar) == 8);
145}
146
147test "@TypeOf() has no runtime side effects" {
148 const S = struct {
149 fn foo(comptime T: type, ptr: *T) T {
150 ptr.* += 1;
151 return ptr.*;
152 }
153 };
154 var data: i32 = 0;
155 const T = @TypeOf(S.foo(i32, &data));
156 comptime try expect(T == i32);
157 try expect(data == 0);
158}
159
160test "@TypeOf() with multiple arguments" {20test "@TypeOf() with multiple arguments" {
161 {21 {
162 var var_1: u32 = undefined;22 var var_1: u32 = undefined;
...@@ -180,19 +40,6 @@ test "@TypeOf() with multiple arguments" {...@@ -180,19 +40,6 @@ test "@TypeOf() with multiple arguments" {
180 }40 }
181}41}
18242
183test "branching logic inside @TypeOf" {
184 const S = struct {
185 var data: i32 = 0;
186 fn foo() anyerror!i32 {
187 data += 1;
188 return undefined;
189 }
190 };
191 const T = @TypeOf(S.foo() catch undefined);
192 comptime try expect(T == i32);
193 try expect(S.data == 0);
194}
195
196fn fn1(alpha: bool) void {43fn fn1(alpha: bool) void {
197 const n: usize = 7;44 const n: usize = 7;
198 _ = if (alpha) n else @sizeOf(usize);45 _ = if (alpha) n else @sizeOf(usize);
...@@ -201,64 +48,3 @@ fn fn1(alpha: bool) void {...@@ -201,64 +48,3 @@ fn fn1(alpha: bool) void {
201test "lazy @sizeOf result is checked for definedness" {48test "lazy @sizeOf result is checked for definedness" {
202 _ = fn1;49 _ = fn1;
203}50}
204
205test "@bitSizeOf" {
206 try expect(@bitSizeOf(u2) == 2);
207 try expect(@bitSizeOf(u8) == @sizeOf(u8) * 8);
208 try expect(@bitSizeOf(struct {
209 a: u2,
210 }) == 8);
211 try expect(@bitSizeOf(packed struct {
212 a: u2,
213 }) == 2);
214}
215
216test "@sizeOf comparison against zero" {
217 const S0 = struct {
218 f: *@This(),
219 };
220 const U0 = union {
221 f: *@This(),
222 };
223 const S1 = struct {
224 fn H(comptime T: type) type {
225 return struct {
226 x: T,
227 };
228 }
229 f0: H(*@This()),
230 f1: H(**@This()),
231 f2: H(***@This()),
232 };
233 const U1 = union {
234 fn H(comptime T: type) type {
235 return struct {
236 x: T,
237 };
238 }
239 f0: H(*@This()),
240 f1: H(**@This()),
241 f2: H(***@This()),
242 };
243 const S = struct {
244 fn doTheTest(comptime T: type, comptime result: bool) !void {
245 try expectEqual(result, @sizeOf(T) > 0);
246 }
247 };
248 // Zero-sized type
249 try S.doTheTest(u0, false);
250 try S.doTheTest(*u0, false);
251 // Non byte-sized type
252 try S.doTheTest(u1, true);
253 try S.doTheTest(*u1, true);
254 // Regular type
255 try S.doTheTest(u8, true);
256 try S.doTheTest(*u8, true);
257 try S.doTheTest(f32, true);
258 try S.doTheTest(*f32, true);
259 // Container with ptr pointing to themselves
260 try S.doTheTest(S0, true);
261 try S.doTheTest(U0, true);
262 try S.doTheTest(S1, true);
263 try S.doTheTest(U1, true);
264}
test/behavior/sizeof_and_typeof_stage1.zig created+218
...@@ -0,0 +1,218 @@
1const std = @import("std");
2const builtin = std.builtin;
3const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;
5
6const A = struct {
7 a: u8,
8 b: u32,
9 c: u8,
10 d: u3,
11 e: u5,
12 f: u16,
13 g: u16,
14 h: u9,
15 i: u7,
16};
17
18const P = packed struct {
19 a: u8,
20 b: u32,
21 c: u8,
22 d: u3,
23 e: u5,
24 f: u16,
25 g: u16,
26 h: u9,
27 i: u7,
28};
29
30test "@offsetOf" {
31 // Packed structs have fixed memory layout
32 try expect(@offsetOf(P, "a") == 0);
33 try expect(@offsetOf(P, "b") == 1);
34 try expect(@offsetOf(P, "c") == 5);
35 try expect(@offsetOf(P, "d") == 6);
36 try expect(@offsetOf(P, "e") == 6);
37 try expect(@offsetOf(P, "f") == 7);
38 try expect(@offsetOf(P, "g") == 9);
39 try expect(@offsetOf(P, "h") == 11);
40 try expect(@offsetOf(P, "i") == 12);
41
42 // Normal struct fields can be moved/padded
43 var a: A = undefined;
44 try expect(@ptrToInt(&a.a) - @ptrToInt(&a) == @offsetOf(A, "a"));
45 try expect(@ptrToInt(&a.b) - @ptrToInt(&a) == @offsetOf(A, "b"));
46 try expect(@ptrToInt(&a.c) - @ptrToInt(&a) == @offsetOf(A, "c"));
47 try expect(@ptrToInt(&a.d) - @ptrToInt(&a) == @offsetOf(A, "d"));
48 try expect(@ptrToInt(&a.e) - @ptrToInt(&a) == @offsetOf(A, "e"));
49 try expect(@ptrToInt(&a.f) - @ptrToInt(&a) == @offsetOf(A, "f"));
50 try expect(@ptrToInt(&a.g) - @ptrToInt(&a) == @offsetOf(A, "g"));
51 try expect(@ptrToInt(&a.h) - @ptrToInt(&a) == @offsetOf(A, "h"));
52 try expect(@ptrToInt(&a.i) - @ptrToInt(&a) == @offsetOf(A, "i"));
53}
54
55test "@offsetOf packed struct, array length not power of 2 or multiple of native pointer width in bytes" {
56 const p3a_len = 3;
57 const P3 = packed struct {
58 a: [p3a_len]u8,
59 b: usize,
60 };
61 try std.testing.expectEqual(0, @offsetOf(P3, "a"));
62 try std.testing.expectEqual(p3a_len, @offsetOf(P3, "b"));
63
64 const p5a_len = 5;
65 const P5 = packed struct {
66 a: [p5a_len]u8,
67 b: usize,
68 };
69 try std.testing.expectEqual(0, @offsetOf(P5, "a"));
70 try std.testing.expectEqual(p5a_len, @offsetOf(P5, "b"));
71
72 const p6a_len = 6;
73 const P6 = packed struct {
74 a: [p6a_len]u8,
75 b: usize,
76 };
77 try std.testing.expectEqual(0, @offsetOf(P6, "a"));
78 try std.testing.expectEqual(p6a_len, @offsetOf(P6, "b"));
79
80 const p7a_len = 7;
81 const P7 = packed struct {
82 a: [p7a_len]u8,
83 b: usize,
84 };
85 try std.testing.expectEqual(0, @offsetOf(P7, "a"));
86 try std.testing.expectEqual(p7a_len, @offsetOf(P7, "b"));
87
88 const p9a_len = 9;
89 const P9 = packed struct {
90 a: [p9a_len]u8,
91 b: usize,
92 };
93 try std.testing.expectEqual(0, @offsetOf(P9, "a"));
94 try std.testing.expectEqual(p9a_len, @offsetOf(P9, "b"));
95
96 // 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 25 etc. are further cases
97}
98
99test "@bitOffsetOf" {
100 // Packed structs have fixed memory layout
101 try expect(@bitOffsetOf(P, "a") == 0);
102 try expect(@bitOffsetOf(P, "b") == 8);
103 try expect(@bitOffsetOf(P, "c") == 40);
104 try expect(@bitOffsetOf(P, "d") == 48);
105 try expect(@bitOffsetOf(P, "e") == 51);
106 try expect(@bitOffsetOf(P, "f") == 56);
107 try expect(@bitOffsetOf(P, "g") == 72);
108
109 try expect(@offsetOf(A, "a") * 8 == @bitOffsetOf(A, "a"));
110 try expect(@offsetOf(A, "b") * 8 == @bitOffsetOf(A, "b"));
111 try expect(@offsetOf(A, "c") * 8 == @bitOffsetOf(A, "c"));
112 try expect(@offsetOf(A, "d") * 8 == @bitOffsetOf(A, "d"));
113 try expect(@offsetOf(A, "e") * 8 == @bitOffsetOf(A, "e"));
114 try expect(@offsetOf(A, "f") * 8 == @bitOffsetOf(A, "f"));
115 try expect(@offsetOf(A, "g") * 8 == @bitOffsetOf(A, "g"));
116}
117
118test "@sizeOf(T) == 0 doesn't force resolving struct size" {
119 const S = struct {
120 const Foo = struct {
121 y: if (@sizeOf(Foo) == 0) u64 else u32,
122 };
123 const Bar = struct {
124 x: i32,
125 y: if (0 == @sizeOf(Bar)) u64 else u32,
126 };
127 };
128
129 try expect(@sizeOf(S.Foo) == 4);
130 try expect(@sizeOf(S.Bar) == 8);
131}
132
133test "@TypeOf() has no runtime side effects" {
134 const S = struct {
135 fn foo(comptime T: type, ptr: *T) T {
136 ptr.* += 1;
137 return ptr.*;
138 }
139 };
140 var data: i32 = 0;
141 const T = @TypeOf(S.foo(i32, &data));
142 comptime try expect(T == i32);
143 try expect(data == 0);
144}
145
146test "branching logic inside @TypeOf" {
147 const S = struct {
148 var data: i32 = 0;
149 fn foo() anyerror!i32 {
150 data += 1;
151 return undefined;
152 }
153 };
154 const T = @TypeOf(S.foo() catch undefined);
155 comptime try expect(T == i32);
156 try expect(S.data == 0);
157}
158
159test "@bitSizeOf" {
160 try expect(@bitSizeOf(u2) == 2);
161 try expect(@bitSizeOf(u8) == @sizeOf(u8) * 8);
162 try expect(@bitSizeOf(struct {
163 a: u2,
164 }) == 8);
165 try expect(@bitSizeOf(packed struct {
166 a: u2,
167 }) == 2);
168}
169
170test "@sizeOf comparison against zero" {
171 const S0 = struct {
172 f: *@This(),
173 };
174 const U0 = union {
175 f: *@This(),
176 };
177 const S1 = struct {
178 fn H(comptime T: type) type {
179 return struct {
180 x: T,
181 };
182 }
183 f0: H(*@This()),
184 f1: H(**@This()),
185 f2: H(***@This()),
186 };
187 const U1 = union {
188 fn H(comptime T: type) type {
189 return struct {
190 x: T,
191 };
192 }
193 f0: H(*@This()),
194 f1: H(**@This()),
195 f2: H(***@This()),
196 };
197 const S = struct {
198 fn doTheTest(comptime T: type, comptime result: bool) !void {
199 try expectEqual(result, @sizeOf(T) > 0);
200 }
201 };
202 // Zero-sized type
203 try S.doTheTest(u0, false);
204 try S.doTheTest(*u0, false);
205 // Non byte-sized type
206 try S.doTheTest(u1, true);
207 try S.doTheTest(*u1, true);
208 // Regular type
209 try S.doTheTest(u8, true);
210 try S.doTheTest(*u8, true);
211 try S.doTheTest(f32, true);
212 try S.doTheTest(*f32, true);
213 // Container with ptr pointing to themselves
214 try S.doTheTest(S0, true);
215 try S.doTheTest(U0, true);
216 try S.doTheTest(S1, true);
217 try S.doTheTest(U1, true);
218}
test/behavior/translate_c_macros.zig-22
...@@ -3,28 +3,6 @@ const expectEqual = @import("std").testing.expectEqual;...@@ -3,28 +3,6 @@ const expectEqual = @import("std").testing.expectEqual;
33
4const h = @cImport(@cInclude("behavior/translate_c_macros.h"));4const h = @cImport(@cInclude("behavior/translate_c_macros.h"));
55
6test "initializer list expression" {
7 try expectEqual(h.Color{
8 .r = 200,
9 .g = 200,
10 .b = 200,
11 .a = 255,
12 }, h.LIGHTGRAY);
13}
14
15test "sizeof in macros" {
16 try expectEqual(@as(c_int, @sizeOf(u32)), h.MY_SIZEOF(u32));
17 try expectEqual(@as(c_int, @sizeOf(u32)), h.MY_SIZEOF2(u32));
18}
19
20test "reference to a struct type" {
21 try expectEqual(@sizeOf(h.struct_Foo), h.SIZE_OF_FOO);
22}
23
24test "cast negative integer to pointer" {
25 try expectEqual(@intToPtr(?*c_void, @bitCast(usize, @as(isize, -1))), h.MAP_FAILED);
26}
27
28test "casting to void with a macro" {6test "casting to void with a macro" {
29 h.IGNORE_ME_1(42);7 h.IGNORE_ME_1(42);
30 h.IGNORE_ME_2(42);8 h.IGNORE_ME_2(42);
test/behavior/translate_c_macros_stage1.zig created+26
...@@ -0,0 +1,26 @@
1const expect = @import("std").testing.expect;
2const expectEqual = @import("std").testing.expectEqual;
3
4const h = @cImport(@cInclude("behavior/translate_c_macros.h"));
5
6test "initializer list expression" {
7 try expectEqual(h.Color{
8 .r = 200,
9 .g = 200,
10 .b = 200,
11 .a = 255,
12 }, h.LIGHTGRAY);
13}
14
15test "sizeof in macros" {
16 try expectEqual(@as(c_int, @sizeOf(u32)), h.MY_SIZEOF(u32));
17 try expectEqual(@as(c_int, @sizeOf(u32)), h.MY_SIZEOF2(u32));
18}
19
20test "reference to a struct type" {
21 try expectEqual(@sizeOf(h.struct_Foo), h.SIZE_OF_FOO);
22}
23
24test "cast negative integer to pointer" {
25 try expectEqual(@intToPtr(?*c_void, @bitCast(usize, @as(isize, -1))), h.MAP_FAILED);
26}