| author | |
| committer | |
| log | 5269cbea202c6a81108390f4c47bc8a04fc6d1ff |
| tree | a95896bf83bb427953a6a33d037698e30c05d8f8 |
| parent | 1ad905c71e0896295d4781853cd577bbe1b4111a |
| parent | 0c74ce1156d6a967cd089cd4657575a3e22bb782 |
| signature |
stage2: implement cImport11 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]), |
| 7086 | 7086 | ||
| 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( |
| 7689 | fn cImport( | 7692 | fn 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( |
| 7698 | 7700 | ||
| 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); |
| 7702 | 7705 | ||
| 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); |
| 7710 | 7713 | ||
| 7711 | return rvalue(gz, rl, .void_value, node); | 7714 | return indexToRef(block_inst); |
| 7712 | } | 7715 | } |
| 7713 | 7716 | ||
| 7714 | fn overflowArithmetic( | 7717 | fn 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 { |
| 2644 | 2644 | ||
| 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); |
| 2648 | 2648 | ||
| 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 @setRuntimeSafety | 1325 | /// when null, it is determined by build mode, changed by @setRuntimeSafety |
| 1326 | want_safety: ?bool = null, | 1326 | want_safety: ?bool = null, |
| 1327 | 1327 | ||
| 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 | } |
| 1382 | 1385 |
src/Sema.zig+274-21| ... | @@ -83,6 +83,7 @@ const Decl = Module.Decl; | ... | @@ -83,6 +83,7 @@ const Decl = Module.Decl; |
| 83 | const LazySrcLoc = Module.LazySrcLoc; | 83 | const LazySrcLoc = Module.LazySrcLoc; |
| 84 | const RangeSet = @import("RangeSet.zig"); | 84 | const RangeSet = @import("RangeSet.zig"); |
| 85 | const target_util = @import("target.zig"); | 85 | const target_util = @import("target.zig"); |
| 86 | const Package = @import("Package.zig"); | ||
| 86 | 87 | ||
| 87 | pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref); | 88 | pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref); |
| 88 | 89 | ||
| ... | @@ -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(); |
| 2140 | 2141 | ||
| 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)}); | ||
| 2143 | 2208 | ||
| 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 | } |
| 2146 | 2214 | ||
| 2147 | fn zirSuspendBlock(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 2215 | fn 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( |
| 6405 | 6473 | ||
| 6406 | fn zirSizeOf(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 6474 | fn 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 | } |
| 6414 | 6513 | ||
| ... | @@ -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(); |
| 6457 | 6556 | ||
| 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); // TODO | 6629 | 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); // TODO | 6631 | 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 | } |
| 8231 | 8473 | ||
| 8232 | fn zirCInclude( | 8474 | fn 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 | } |
| 8241 | 8486 | ||
| 8242 | fn zirCDefine( | 8487 | fn 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 | } |
| 8251 | 8504 | ||
| 8252 | fn zirWasmMemorySize( | 8505 | fn 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), |
| 413 | 414 | ||
| 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"); | ||
| 14 | 16 | ||
| 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" { |
| 10 | const x: u16 = 13; | 10 | const x: u16 = 13; |
| 11 | const z: @TypeOf(x) = 19; | 11 | const z: @TypeOf(x) = 19; |
| 12 | 12 | ||
| 13 | const 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 | |||
| 25 | const 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 | |||
| 37 | test "@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 | |||
| 62 | test "@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 | |||
| 106 | test "@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 | |||
| 125 | test "@sizeOf on compile-time types" { | 13 | test "@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 | } |
| 131 | 19 | ||
| 132 | test "@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 | |||
| 147 | test "@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 | |||
| 160 | test "@TypeOf() with multiple arguments" { | 20 | test "@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 | } |
| 182 | 42 | ||
| 183 | test "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 | |||
| 196 | fn fn1(alpha: bool) void { | 43 | fn 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 { |
| 201 | test "lazy @sizeOf result is checked for definedness" { | 48 | test "lazy @sizeOf result is checked for definedness" { |
| 202 | _ = fn1; | 49 | _ = fn1; |
| 203 | } | 50 | } |
| 204 | |||
| 205 | test "@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 | |||
| 216 | test "@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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = std.builtin; | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | const expectEqual = std.testing.expectEqual; | ||
| 5 | |||
| 6 | const 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 | |||
| 18 | const 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 | |||
| 30 | test "@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 | |||
| 55 | test "@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 | |||
| 99 | test "@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 | |||
| 118 | test "@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 | |||
| 133 | test "@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 | |||
| 146 | test "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 | |||
| 159 | test "@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 | |||
| 170 | test "@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; |
| 3 | 3 | ||
| 4 | const h = @cImport(@cInclude("behavior/translate_c_macros.h")); | 4 | const h = @cImport(@cInclude("behavior/translate_c_macros.h")); |
| 5 | 5 | ||
| 6 | test "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 | |||
| 15 | test "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 | |||
| 20 | test "reference to a struct type" { | ||
| 21 | try expectEqual(@sizeOf(h.struct_Foo), h.SIZE_OF_FOO); | ||
| 22 | } | ||
| 23 | |||
| 24 | test "cast negative integer to pointer" { | ||
| 25 | try expectEqual(@intToPtr(?*c_void, @bitCast(usize, @as(isize, -1))), h.MAP_FAILED); | ||
| 26 | } | ||
| 27 | |||
| 28 | test "casting to void with a macro" { | 6 | test "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 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | const expectEqual = @import("std").testing.expectEqual; | ||
| 3 | |||
| 4 | const h = @cImport(@cInclude("behavior/translate_c_macros.h")); | ||
| 5 | |||
| 6 | test "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 | |||
| 15 | test "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 | |||
| 20 | test "reference to a struct type" { | ||
| 21 | try expectEqual(@sizeOf(h.struct_Foo), h.SIZE_OF_FOO); | ||
| 22 | } | ||
| 23 | |||
| 24 | test "cast negative integer to pointer" { | ||
| 25 | try expectEqual(@intToPtr(?*c_void, @bitCast(usize, @as(isize, -1))), h.MAP_FAILED); | ||
| 26 | } | ||