| author | |
| committer | |
| log | b7d5582dede8f4cae341365ac9c47c840bd80eff |
| tree | 76c5e13a11b133f44f096649be9d35ac2afe7f2a |
| parent | 10e11b60e56941cb664648dcebfd4db3d2efed30 |
| parent | c7884af063791211544c6595a4900bbfcd5d96b6 |
| signature |
Stage2 fixes35 files changed, 558 insertions(+), 255 deletions(-)
src/AstGen.zig+1-1| ... | ... | @@ -5127,7 +5127,7 @@ fn tryExpr( |
| 5127 | 5127 | else => .none, |
| 5128 | 5128 | }; |
| 5129 | 5129 | // This could be a pointer or value depending on the `rl` parameter. |
| 5130 | const operand = try expr(parent_gz, scope, operand_rl, operand_node); | |
| 5130 | const operand = try reachableExpr(parent_gz, scope, operand_rl, operand_node, node); | |
| 5131 | 5131 | const is_inline = parent_gz.force_comptime; |
| 5132 | 5132 | const is_inline_bit = @as(u2, @boolToInt(is_inline)); |
| 5133 | 5133 | const is_ptr_bit = @as(u2, @boolToInt(operand_rl == .ref)) << 1; |
src/Module.zig+1-1| ... | ... | @@ -4635,7 +4635,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4635 | 4635 | decl.analysis = .complete; |
| 4636 | 4636 | decl.generation = mod.generation; |
| 4637 | 4637 | |
| 4638 | const has_runtime_bits = try sema.fnHasRuntimeBits(&block_scope, ty_src, decl.ty); | |
| 4638 | const has_runtime_bits = try sema.fnHasRuntimeBits(decl.ty); | |
| 4639 | 4639 | |
| 4640 | 4640 | if (has_runtime_bits) { |
| 4641 | 4641 | // We don't fully codegen the decl until later, but we do need to reserve a global |
src/Sema.zig+125-62| ... | ... | @@ -2565,7 +2565,7 @@ fn zirEnumDecl( |
| 2565 | 2565 | } |
| 2566 | 2566 | } |
| 2567 | 2567 | |
| 2568 | if (small.nonexhaustive) { | |
| 2568 | if (small.nonexhaustive and enum_obj.tag_ty.zigTypeTag() != .ComptimeInt) { | |
| 2569 | 2569 | if (fields_len > 1 and std.math.log2_int(u64, fields_len) == enum_obj.tag_ty.bitSize(sema.mod.getTarget())) { |
| 2570 | 2570 | return sema.fail(block, src, "non-exhaustive enum specifies every value", .{}); |
| 2571 | 2571 | } |
| ... | ... | @@ -2586,6 +2586,7 @@ fn zirEnumDecl( |
| 2586 | 2586 | var cur_bit_bag: u32 = undefined; |
| 2587 | 2587 | var field_i: u32 = 0; |
| 2588 | 2588 | var last_tag_val: ?Value = null; |
| 2589 | var tag_val_buf: Value.Payload.U64 = undefined; | |
| 2589 | 2590 | while (field_i < fields_len) : (field_i += 1) { |
| 2590 | 2591 | if (field_i % 32 == 0) { |
| 2591 | 2592 | cur_bit_bag = sema.code.extra[bit_bag_index]; |
| ... | ... | @@ -2641,6 +2642,21 @@ fn zirEnumDecl( |
| 2641 | 2642 | .ty = enum_obj.tag_ty, |
| 2642 | 2643 | .mod = mod, |
| 2643 | 2644 | }); |
| 2645 | } else { | |
| 2646 | tag_val_buf = .{ | |
| 2647 | .base = .{ .tag = .int_u64 }, | |
| 2648 | .data = field_i, | |
| 2649 | }; | |
| 2650 | last_tag_val = Value.initPayload(&tag_val_buf.base); | |
| 2651 | } | |
| 2652 | ||
| 2653 | if (!(try sema.intFitsInType(block, src, last_tag_val.?, enum_obj.tag_ty, null))) { | |
| 2654 | const tree = try sema.getAstTree(block); | |
| 2655 | const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i); | |
| 2656 | const msg = try sema.errMsg(block, field_src, "enumeration value '{}' too large for type '{}'", .{ | |
| 2657 | last_tag_val.?.fmtValue(enum_obj.tag_ty, mod), enum_obj.tag_ty.fmt(mod), | |
| 2658 | }); | |
| 2659 | return sema.failWithOwnedErrorMsg(msg); | |
| 2644 | 2660 | } |
| 2645 | 2661 | } |
| 2646 | 2662 | return decl_val; |
| ... | ... | @@ -2849,7 +2865,7 @@ fn zirRetPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 2849 | 2865 | const inst_data = sema.code.instructions.items(.data)[inst].node; |
| 2850 | 2866 | const src = LazySrcLoc.nodeOffset(inst_data); |
| 2851 | 2867 | |
| 2852 | if (block.is_comptime or try sema.typeRequiresComptime(block, src, sema.fn_ret_ty)) { | |
| 2868 | if (block.is_comptime or try sema.typeRequiresComptime(sema.fn_ret_ty)) { | |
| 2853 | 2869 | const fn_ret_ty = try sema.resolveTypeFields(block, src, sema.fn_ret_ty); |
| 2854 | 2870 | return sema.analyzeComptimeAlloc(block, fn_ret_ty, 0, src); |
| 2855 | 2871 | } |
| ... | ... | @@ -5040,7 +5056,7 @@ pub fn analyzeExport( |
| 5040 | 5056 | try mod.ensureDeclAnalyzed(exported_decl_index); |
| 5041 | 5057 | const exported_decl = mod.declPtr(exported_decl_index); |
| 5042 | 5058 | |
| 5043 | if (!sema.validateExternType(exported_decl.ty, .other)) { | |
| 5059 | if (!try sema.validateExternType(block, src, exported_decl.ty, .other)) { | |
| 5044 | 5060 | const msg = msg: { |
| 5045 | 5061 | const msg = try sema.errMsg(block, src, "unable to export type '{}'", .{exported_decl.ty.fmt(sema.mod)}); |
| 5046 | 5062 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -5569,7 +5585,11 @@ fn zirCall( |
| 5569 | 5585 | const param_ty_inst = try sema.addType(param_ty); |
| 5570 | 5586 | try sema.inst_map.put(sema.gpa, inst, param_ty_inst); |
| 5571 | 5587 | |
| 5572 | resolved_args[arg_index] = try sema.resolveBody(block, args_body[arg_start..arg_end], inst); | |
| 5588 | const resolved = try sema.resolveBody(block, args_body[arg_start..arg_end], inst); | |
| 5589 | if (sema.typeOf(resolved).zigTypeTag() == .NoReturn) { | |
| 5590 | return resolved; | |
| 5591 | } | |
| 5592 | resolved_args[arg_index] = resolved; | |
| 5573 | 5593 | } |
| 5574 | 5594 | |
| 5575 | 5595 | return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src); |
| ... | ... | @@ -5768,7 +5788,7 @@ fn analyzeCall( |
| 5768 | 5788 | var is_comptime_call = block.is_comptime or modifier == .compile_time; |
| 5769 | 5789 | var comptime_only_ret_ty = false; |
| 5770 | 5790 | if (!is_comptime_call) { |
| 5771 | if (sema.typeRequiresComptime(block, func_src, func_ty_info.return_type)) |ct| { | |
| 5791 | if (sema.typeRequiresComptime(func_ty_info.return_type)) |ct| { | |
| 5772 | 5792 | is_comptime_call = ct; |
| 5773 | 5793 | comptime_only_ret_ty = ct; |
| 5774 | 5794 | } else |err| switch (err) { |
| ... | ... | @@ -6047,7 +6067,7 @@ fn analyzeCall( |
| 6047 | 6067 | break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges); |
| 6048 | 6068 | }; |
| 6049 | 6069 | |
| 6050 | if (!is_comptime_call) { | |
| 6070 | if (!is_comptime_call and sema.typeOf(result).zigTypeTag() != .NoReturn) { | |
| 6051 | 6071 | try sema.emitDbgInline( |
| 6052 | 6072 | block, |
| 6053 | 6073 | module_fn, |
| ... | ... | @@ -6206,7 +6226,7 @@ fn analyzeInlineCallArg( |
| 6206 | 6226 | const param_ty = try sema.analyzeAsType(param_block, param_src, param_ty_inst); |
| 6207 | 6227 | new_fn_info.param_types[arg_i.*] = param_ty; |
| 6208 | 6228 | const uncasted_arg = uncasted_args[arg_i.*]; |
| 6209 | if (try sema.typeRequiresComptime(arg_block, arg_src, param_ty)) { | |
| 6229 | if (try sema.typeRequiresComptime(param_ty)) { | |
| 6210 | 6230 | _ = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime only type must be comptime known") catch |err| { |
| 6211 | 6231 | if (err == error.AnalysisFail and sema.err != null) { |
| 6212 | 6232 | try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty); |
| ... | ... | @@ -6308,7 +6328,7 @@ fn analyzeGenericCallArg( |
| 6308 | 6328 | ) !void { |
| 6309 | 6329 | const is_runtime = comptime_arg.val.tag() == .generic_poison and |
| 6310 | 6330 | comptime_arg.ty.hasRuntimeBits() and |
| 6311 | !(try sema.typeRequiresComptime(block, arg_src, comptime_arg.ty)); | |
| 6331 | !(try sema.typeRequiresComptime(comptime_arg.ty)); | |
| 6312 | 6332 | if (is_runtime) { |
| 6313 | 6333 | const param_ty = new_fn_info.param_types[runtime_i.*]; |
| 6314 | 6334 | const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src); |
| ... | ... | @@ -6573,7 +6593,7 @@ fn instantiateGenericCall( |
| 6573 | 6593 | } |
| 6574 | 6594 | } else if (is_anytype) { |
| 6575 | 6595 | const arg_ty = sema.typeOf(arg); |
| 6576 | if (try sema.typeRequiresComptime(block, .unneeded, arg_ty)) { | |
| 6596 | if (try sema.typeRequiresComptime(arg_ty)) { | |
| 6577 | 6597 | const arg_val = try sema.resolveConstValue(block, .unneeded, arg, undefined); |
| 6578 | 6598 | const child_arg = try child_sema.addConstant(arg_ty, arg_val); |
| 6579 | 6599 | child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg); |
| ... | ... | @@ -6626,7 +6646,7 @@ fn instantiateGenericCall( |
| 6626 | 6646 | const arg = child_sema.inst_map.get(inst).?; |
| 6627 | 6647 | const copied_arg_ty = try child_sema.typeOf(arg).copy(new_decl_arena_allocator); |
| 6628 | 6648 | |
| 6629 | if (try sema.typeRequiresComptime(block, .unneeded, copied_arg_ty)) { | |
| 6649 | if (try sema.typeRequiresComptime(copied_arg_ty)) { | |
| 6630 | 6650 | is_comptime = true; |
| 6631 | 6651 | } |
| 6632 | 6652 | |
| ... | ... | @@ -6657,7 +6677,7 @@ fn instantiateGenericCall( |
| 6657 | 6677 | // If the call evaluated to a return type that requires comptime, never mind |
| 6658 | 6678 | // our generic instantiation. Instead we need to perform a comptime call. |
| 6659 | 6679 | const new_fn_info = new_decl.ty.fnInfo(); |
| 6660 | if (try sema.typeRequiresComptime(block, call_src, new_fn_info.return_type)) { | |
| 6680 | if (try sema.typeRequiresComptime(new_fn_info.return_type)) { | |
| 6661 | 6681 | return error.ComptimeReturn; |
| 6662 | 6682 | } |
| 6663 | 6683 | // Similarly, if the call evaluated to a generic type we need to instead |
| ... | ... | @@ -7838,7 +7858,7 @@ fn funcCommon( |
| 7838 | 7858 | } |
| 7839 | 7859 | |
| 7840 | 7860 | var ret_ty_requires_comptime = false; |
| 7841 | const ret_poison = if (sema.typeRequiresComptime(block, ret_ty_src, bare_return_type)) |ret_comptime| rp: { | |
| 7861 | const ret_poison = if (sema.typeRequiresComptime(bare_return_type)) |ret_comptime| rp: { | |
| 7842 | 7862 | ret_ty_requires_comptime = ret_comptime; |
| 7843 | 7863 | break :rp bare_return_type.tag() == .generic_poison; |
| 7844 | 7864 | } else |err| switch (err) { |
| ... | ... | @@ -7876,7 +7896,7 @@ fn funcCommon( |
| 7876 | 7896 | }; |
| 7877 | 7897 | return sema.failWithOwnedErrorMsg(msg); |
| 7878 | 7898 | } |
| 7879 | if (!Type.fnCallingConventionAllowsZigTypes(cc_workaround) and !sema.validateExternType(return_type, .ret_ty)) { | |
| 7899 | if (!Type.fnCallingConventionAllowsZigTypes(cc_workaround) and !try sema.validateExternType(block, ret_ty_src, return_type, .ret_ty)) { | |
| 7880 | 7900 | const msg = msg: { |
| 7881 | 7901 | const msg = try sema.errMsg(block, ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{ |
| 7882 | 7902 | return_type.fmt(sema.mod), @tagName(cc_workaround), |
| ... | ... | @@ -8072,7 +8092,7 @@ fn analyzeParameter( |
| 8072 | 8092 | cc: std.builtin.CallingConvention, |
| 8073 | 8093 | has_body: bool, |
| 8074 | 8094 | ) !void { |
| 8075 | const requires_comptime = try sema.typeRequiresComptime(block, param_src, param.ty); | |
| 8095 | const requires_comptime = try sema.typeRequiresComptime(param.ty); | |
| 8076 | 8096 | comptime_params[i] = param.is_comptime or requires_comptime; |
| 8077 | 8097 | const this_generic = param.ty.tag() == .generic_poison; |
| 8078 | 8098 | is_generic.* = is_generic.* or this_generic; |
| ... | ... | @@ -8095,7 +8115,7 @@ fn analyzeParameter( |
| 8095 | 8115 | }; |
| 8096 | 8116 | return sema.failWithOwnedErrorMsg(msg); |
| 8097 | 8117 | } |
| 8098 | if (!Type.fnCallingConventionAllowsZigTypes(cc) and !sema.validateExternType(param.ty, .param_ty)) { | |
| 8118 | if (!Type.fnCallingConventionAllowsZigTypes(cc) and !try sema.validateExternType(block, param_src, param.ty, .param_ty)) { | |
| 8099 | 8119 | const msg = msg: { |
| 8100 | 8120 | const msg = try sema.errMsg(block, param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{ |
| 8101 | 8121 | param.ty.fmt(sema.mod), @tagName(cc), |
| ... | ... | @@ -8177,7 +8197,7 @@ fn zirParam( |
| 8177 | 8197 | } |
| 8178 | 8198 | }; |
| 8179 | 8199 | const is_comptime = comptime_syntax or |
| 8180 | try sema.typeRequiresComptime(block, src, param_ty); | |
| 8200 | try sema.typeRequiresComptime(param_ty); | |
| 8181 | 8201 | if (sema.inst_map.get(inst)) |arg| { |
| 8182 | 8202 | if (is_comptime) { |
| 8183 | 8203 | // We have a comptime value for this parameter so it should be elided from the |
| ... | ... | @@ -8237,7 +8257,7 @@ fn zirParamAnytype( |
| 8237 | 8257 | |
| 8238 | 8258 | if (sema.inst_map.get(inst)) |air_ref| { |
| 8239 | 8259 | const param_ty = sema.typeOf(air_ref); |
| 8240 | if (comptime_syntax or try sema.typeRequiresComptime(block, src, param_ty)) { | |
| 8260 | if (comptime_syntax or try sema.typeRequiresComptime(param_ty)) { | |
| 8241 | 8261 | // We have a comptime value for this parameter so it should be elided from the |
| 8242 | 8262 | // function type of the function instruction in this block. |
| 8243 | 8263 | return; |
| ... | ... | @@ -15565,7 +15585,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 15565 | 15585 | } else if (inst_data.size == .Many and elem_ty.zigTypeTag() == .Opaque) { |
| 15566 | 15586 | return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{}); |
| 15567 | 15587 | } else if (inst_data.size == .C) { |
| 15568 | if (!sema.validateExternType(elem_ty, .other)) { | |
| 15588 | if (!try sema.validateExternType(block, elem_ty_src, elem_ty, .other)) { | |
| 15569 | 15589 | const msg = msg: { |
| 15570 | 15590 | const msg = try sema.errMsg(block, elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)}); |
| 15571 | 15591 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -16663,7 +16683,7 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in |
| 16663 | 16683 | } else if (ptr_size == .Many and elem_ty.zigTypeTag() == .Opaque) { |
| 16664 | 16684 | return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{}); |
| 16665 | 16685 | } else if (ptr_size == .C) { |
| 16666 | if (!sema.validateExternType(elem_ty, .other)) { | |
| 16686 | if (!try sema.validateExternType(block, src, elem_ty, .other)) { | |
| 16667 | 16687 | const msg = msg: { |
| 16668 | 16688 | const msg = try sema.errMsg(block, src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)}); |
| 16669 | 16689 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -17501,7 +17521,7 @@ fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 17501 | 17521 | |
| 17502 | 17522 | if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| { |
| 17503 | 17523 | const target = sema.mod.getTarget(); |
| 17504 | const result_val = try val.intToFloat(sema.arena, operand_ty, dest_ty, target); | |
| 17524 | const result_val = try val.intToFloatAdvanced(sema.arena, operand_ty, dest_ty, target, sema.kit(block, operand_src)); | |
| 17505 | 17525 | return sema.addConstant(dest_ty, result_val); |
| 17506 | 17526 | } else if (dest_ty.zigTypeTag() == .ComptimeFloat) { |
| 17507 | 17527 | return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_float' must be comptime known"); |
| ... | ... | @@ -20345,12 +20365,13 @@ fn validateRunTimeType( |
| 20345 | 20365 | .Int, |
| 20346 | 20366 | .Float, |
| 20347 | 20367 | .ErrorSet, |
| 20348 | .Enum, | |
| 20349 | 20368 | .Frame, |
| 20350 | 20369 | .AnyFrame, |
| 20351 | 20370 | .Void, |
| 20352 | 20371 | => return true, |
| 20353 | 20372 | |
| 20373 | .Enum => return !(try sema.typeRequiresComptime(ty)), | |
| 20374 | ||
| 20354 | 20375 | .BoundFn, |
| 20355 | 20376 | .ComptimeFloat, |
| 20356 | 20377 | .ComptimeInt, |
| ... | ... | @@ -20383,7 +20404,7 @@ fn validateRunTimeType( |
| 20383 | 20404 | |
| 20384 | 20405 | .Struct, .Union => { |
| 20385 | 20406 | const resolved_ty = try sema.resolveTypeFields(block, src, ty); |
| 20386 | const needs_comptime = try sema.typeRequiresComptime(block, src, resolved_ty); | |
| 20407 | const needs_comptime = try sema.typeRequiresComptime(resolved_ty); | |
| 20387 | 20408 | return !needs_comptime; |
| 20388 | 20409 | }, |
| 20389 | 20410 | }; |
| ... | ... | @@ -20491,7 +20512,7 @@ fn explainWhyTypeIsComptimeInner( |
| 20491 | 20512 | .range = .type, |
| 20492 | 20513 | }); |
| 20493 | 20514 | |
| 20494 | if (try sema.typeRequiresComptime(block, src, field.ty)) { | |
| 20515 | if (try sema.typeRequiresComptime(field.ty)) { | |
| 20495 | 20516 | try mod.errNoteNonLazy(field_src_loc, msg, "struct requires comptime because of this field", .{}); |
| 20496 | 20517 | try sema.explainWhyTypeIsComptimeInner(block, src, msg, field_src_loc, field.ty, type_set); |
| 20497 | 20518 | } |
| ... | ... | @@ -20511,7 +20532,7 @@ fn explainWhyTypeIsComptimeInner( |
| 20511 | 20532 | .range = .type, |
| 20512 | 20533 | }); |
| 20513 | 20534 | |
| 20514 | if (try sema.typeRequiresComptime(block, src, field.ty)) { | |
| 20535 | if (try sema.typeRequiresComptime(field.ty)) { | |
| 20515 | 20536 | try mod.errNoteNonLazy(field_src_loc, msg, "union requires comptime because of this field", .{}); |
| 20516 | 20537 | try sema.explainWhyTypeIsComptimeInner(block, src, msg, field_src_loc, field.ty, type_set); |
| 20517 | 20538 | } |
| ... | ... | @@ -20530,7 +20551,14 @@ const ExternPosition = enum { |
| 20530 | 20551 | |
| 20531 | 20552 | /// Returns true if `ty` is allowed in extern types. |
| 20532 | 20553 | /// Does *NOT* require `ty` to be resolved in any way. |
| 20533 | fn validateExternType(sema: *Sema, ty: Type, position: ExternPosition) bool { | |
| 20554 | /// Calls `resolveTypeLayout` for packed containers. | |
| 20555 | fn validateExternType( | |
| 20556 | sema: *Sema, | |
| 20557 | block: *Block, | |
| 20558 | src: LazySrcLoc, | |
| 20559 | ty: Type, | |
| 20560 | position: ExternPosition, | |
| 20561 | ) !bool { | |
| 20534 | 20562 | switch (ty.zigTypeTag()) { |
| 20535 | 20563 | .Type, |
| 20536 | 20564 | .ComptimeFloat, |
| ... | ... | @@ -20558,17 +20586,25 @@ fn validateExternType(sema: *Sema, ty: Type, position: ExternPosition) bool { |
| 20558 | 20586 | .Fn => return !Type.fnCallingConventionAllowsZigTypes(ty.fnCallingConvention()), |
| 20559 | 20587 | .Enum => { |
| 20560 | 20588 | var buf: Type.Payload.Bits = undefined; |
| 20561 | return sema.validateExternType(ty.intTagType(&buf), position); | |
| 20589 | return sema.validateExternType(block, src, ty.intTagType(&buf), position); | |
| 20562 | 20590 | }, |
| 20563 | 20591 | .Struct, .Union => switch (ty.containerLayout()) { |
| 20564 | .Extern, .Packed => return true, | |
| 20565 | else => return false, | |
| 20592 | .Extern => return true, | |
| 20593 | .Packed => { | |
| 20594 | const target = sema.mod.getTarget(); | |
| 20595 | const bit_size = try ty.bitSizeAdvanced(target, sema.kit(block, src)); | |
| 20596 | switch (bit_size) { | |
| 20597 | 8, 16, 32, 64, 128 => return true, | |
| 20598 | else => return false, | |
| 20599 | } | |
| 20600 | }, | |
| 20601 | .Auto => return false, | |
| 20566 | 20602 | }, |
| 20567 | 20603 | .Array => { |
| 20568 | 20604 | if (position == .ret_ty or position == .param_ty) return false; |
| 20569 | return sema.validateExternType(ty.elemType2(), .other); | |
| 20605 | return sema.validateExternType(block, src, ty.elemType2(), .other); | |
| 20570 | 20606 | }, |
| 20571 | .Vector => return sema.validateExternType(ty.elemType2(), .other), | |
| 20607 | .Vector => return sema.validateExternType(block, src, ty.elemType2(), .other), | |
| 20572 | 20608 | .Optional => return ty.isPtrLikeOptional(), |
| 20573 | 20609 | } |
| 20574 | 20610 | } |
| ... | ... | @@ -20620,8 +20656,8 @@ fn explainWhyTypeIsNotExtern( |
| 20620 | 20656 | try mod.errNoteNonLazy(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(sema.mod)}); |
| 20621 | 20657 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position); |
| 20622 | 20658 | }, |
| 20623 | .Struct => try mod.errNoteNonLazy(src_loc, msg, "only structs with packed or extern layout are extern compatible", .{}), | |
| 20624 | .Union => try mod.errNoteNonLazy(src_loc, msg, "only unions with packed or extern layout are extern compatible", .{}), | |
| 20659 | .Struct => try mod.errNoteNonLazy(src_loc, msg, "only extern structs and ABI sized packed structs are extern compatible", .{}), | |
| 20660 | .Union => try mod.errNoteNonLazy(src_loc, msg, "only extern unions and ABI sized packed unions are extern compatible", .{}), | |
| 20625 | 20661 | .Array => { |
| 20626 | 20662 | if (position == .ret_ty) { |
| 20627 | 20663 | return mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a return type", .{}); |
| ... | ... | @@ -23000,7 +23036,7 @@ fn coerceExtra( |
| 23000 | 23036 | } |
| 23001 | 23037 | break :int; |
| 23002 | 23038 | }; |
| 23003 | const result_val = try val.intToFloat(sema.arena, inst_ty, dest_ty, target); | |
| 23039 | const result_val = try val.intToFloatAdvanced(sema.arena, inst_ty, dest_ty, target, sema.kit(block, inst_src)); | |
| 23004 | 23040 | // TODO implement this compile error |
| 23005 | 23041 | //const int_again_val = try result_val.floatToInt(sema.arena, inst_ty); |
| 23006 | 23042 | //if (!int_again_val.eql(val, inst_ty, mod)) { |
| ... | ... | @@ -23424,8 +23460,11 @@ const InMemoryCoercionResult = union(enum) { |
| 23424 | 23460 | var index: u6 = 0; |
| 23425 | 23461 | var actual_noalias = false; |
| 23426 | 23462 | while (true) : (index += 1) { |
| 23427 | if (param.actual << index != param.wanted << index) { | |
| 23428 | actual_noalias = (param.actual << index) == (1 << 31); | |
| 23463 | const actual = @truncate(u1, param.actual >> index); | |
| 23464 | const wanted = @truncate(u1, param.wanted >> index); | |
| 23465 | if (actual != wanted) { | |
| 23466 | actual_noalias = actual == 1; | |
| 23467 | break; | |
| 23429 | 23468 | } |
| 23430 | 23469 | } |
| 23431 | 23470 | if (!actual_noalias) { |
| ... | ... | @@ -23919,7 +23958,7 @@ fn coerceInMemoryAllowedFns( |
| 23919 | 23958 | |
| 23920 | 23959 | if (dest_info.noalias_bits != src_info.noalias_bits) { |
| 23921 | 23960 | return InMemoryCoercionResult{ .fn_param_noalias = .{ |
| 23922 | .actual = dest_info.noalias_bits, | |
| 23961 | .actual = src_info.noalias_bits, | |
| 23923 | 23962 | .wanted = dest_info.noalias_bits, |
| 23924 | 23963 | } }; |
| 23925 | 23964 | } |
| ... | ... | @@ -24077,16 +24116,40 @@ fn coerceVarArgParam( |
| 24077 | 24116 | inst: Air.Inst.Ref, |
| 24078 | 24117 | inst_src: LazySrcLoc, |
| 24079 | 24118 | ) !Air.Inst.Ref { |
| 24080 | const inst_ty = sema.typeOf(inst); | |
| 24081 | 24119 | if (block.is_typeof) return inst; |
| 24082 | 24120 | |
| 24083 | switch (inst_ty.zigTypeTag()) { | |
| 24121 | const coerced = switch (sema.typeOf(inst).zigTypeTag()) { | |
| 24084 | 24122 | // TODO consider casting to c_int/f64 if they fit |
| 24085 | .ComptimeInt, .ComptimeFloat => return sema.fail(block, inst_src, "integer and float literals in var args function must be casted", .{}), | |
| 24086 | else => {}, | |
| 24123 | .ComptimeInt, .ComptimeFloat => return sema.fail( | |
| 24124 | block, | |
| 24125 | inst_src, | |
| 24126 | "integer and float literals passed variadic function must be casted to a fixed-size number type", | |
| 24127 | .{}, | |
| 24128 | ), | |
| 24129 | .Fn => blk: { | |
| 24130 | const fn_val = try sema.resolveConstValue(block, .unneeded, inst, undefined); | |
| 24131 | const fn_decl = fn_val.pointerDecl().?; | |
| 24132 | break :blk try sema.analyzeDeclRef(fn_decl); | |
| 24133 | }, | |
| 24134 | .Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}), | |
| 24135 | else => inst, | |
| 24136 | }; | |
| 24137 | ||
| 24138 | const coerced_ty = sema.typeOf(coerced); | |
| 24139 | if (!try sema.validateExternType(block, inst_src, coerced_ty, .other)) { | |
| 24140 | const msg = msg: { | |
| 24141 | const msg = try sema.errMsg(block, inst_src, "cannot pass '{}' to variadic function", .{coerced_ty.fmt(sema.mod)}); | |
| 24142 | errdefer msg.destroy(sema.gpa); | |
| 24143 | ||
| 24144 | const src_decl = sema.mod.declPtr(block.src_decl); | |
| 24145 | try sema.explainWhyTypeIsNotExtern(msg, inst_src.toSrcLoc(src_decl), coerced_ty, .other); | |
| 24146 | ||
| 24147 | try sema.addDeclaredHereNote(msg, coerced_ty); | |
| 24148 | break :msg msg; | |
| 24149 | }; | |
| 24150 | return sema.failWithOwnedErrorMsg(msg); | |
| 24087 | 24151 | } |
| 24088 | // TODO implement more of this function. | |
| 24089 | return inst; | |
| 24152 | return coerced; | |
| 24090 | 24153 | } |
| 24091 | 24154 | |
| 24092 | 24155 | // TODO migrate callsites to use storePtr2 instead. |
| ... | ... | @@ -27581,7 +27644,7 @@ pub fn resolveTypeLayout( |
| 27581 | 27644 | // In case of querying the ABI alignment of this optional, we will ask |
| 27582 | 27645 | // for hasRuntimeBits() of the payload type, so we need "requires comptime" |
| 27583 | 27646 | // to be known already before this function returns. |
| 27584 | _ = try sema.typeRequiresComptime(block, src, payload_ty); | |
| 27647 | _ = try sema.typeRequiresComptime(payload_ty); | |
| 27585 | 27648 | return sema.resolveTypeLayout(block, src, payload_ty); |
| 27586 | 27649 | }, |
| 27587 | 27650 | .ErrorUnion => { |
| ... | ... | @@ -27636,7 +27699,7 @@ fn resolveStructLayout( |
| 27636 | 27699 | // for hasRuntimeBits() of each field, so we need "requires comptime" |
| 27637 | 27700 | // to be known already before this function returns. |
| 27638 | 27701 | for (struct_obj.fields.values()) |field, i| { |
| 27639 | _ = sema.typeRequiresComptime(block, src, field.ty) catch |err| switch (err) { | |
| 27702 | _ = sema.typeRequiresComptime(field.ty) catch |err| switch (err) { | |
| 27640 | 27703 | error.AnalysisFail => { |
| 27641 | 27704 | const msg = sema.err orelse return err; |
| 27642 | 27705 | try sema.addFieldErrNote(block, ty, i, msg, "while checking this field", .{}); |
| ... | ... | @@ -27868,7 +27931,7 @@ fn resolveStructFully( |
| 27868 | 27931 | } |
| 27869 | 27932 | |
| 27870 | 27933 | // And let's not forget comptime-only status. |
| 27871 | _ = try sema.typeRequiresComptime(block, src, ty); | |
| 27934 | _ = try sema.typeRequiresComptime(ty); | |
| 27872 | 27935 | } |
| 27873 | 27936 | |
| 27874 | 27937 | fn resolveUnionFully( |
| ... | ... | @@ -27901,7 +27964,7 @@ fn resolveUnionFully( |
| 27901 | 27964 | } |
| 27902 | 27965 | |
| 27903 | 27966 | // And let's not forget comptime-only status. |
| 27904 | _ = try sema.typeRequiresComptime(block, src, ty); | |
| 27967 | _ = try sema.typeRequiresComptime(ty); | |
| 27905 | 27968 | } |
| 27906 | 27969 | |
| 27907 | 27970 | pub fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type { |
| ... | ... | @@ -28275,7 +28338,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 28275 | 28338 | }; |
| 28276 | 28339 | return sema.failWithOwnedErrorMsg(msg); |
| 28277 | 28340 | } |
| 28278 | if (struct_obj.layout == .Extern and !sema.validateExternType(field.ty, .other)) { | |
| 28341 | if (struct_obj.layout == .Extern and !try sema.validateExternType(&block_scope, src, field.ty, .other)) { | |
| 28279 | 28342 | const msg = msg: { |
| 28280 | 28343 | const tree = try sema.getAstTree(&block_scope); |
| 28281 | 28344 | const fields_src = enumFieldSrcLoc(decl, tree.*, 0, i); |
| ... | ... | @@ -28612,7 +28675,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 28612 | 28675 | }; |
| 28613 | 28676 | return sema.failWithOwnedErrorMsg(msg); |
| 28614 | 28677 | } |
| 28615 | if (union_obj.layout == .Extern and !sema.validateExternType(field_ty, .union_field)) { | |
| 28678 | if (union_obj.layout == .Extern and !try sema.validateExternType(&block_scope, src, field_ty, .union_field)) { | |
| 28616 | 28679 | const msg = msg: { |
| 28617 | 28680 | const tree = try sema.getAstTree(&block_scope); |
| 28618 | 28681 | const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); |
| ... | ... | @@ -29004,7 +29067,7 @@ pub fn typeHasOnePossibleValue( |
| 29004 | 29067 | }, |
| 29005 | 29068 | .enum_nonexhaustive => { |
| 29006 | 29069 | const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty; |
| 29007 | if (!(try sema.typeHasRuntimeBits(block, src, tag_ty))) { | |
| 29070 | if (tag_ty.zigTypeTag() != .ComptimeInt and !(try sema.typeHasRuntimeBits(block, src, tag_ty))) { | |
| 29008 | 29071 | return Value.zero; |
| 29009 | 29072 | } else { |
| 29010 | 29073 | return null; |
| ... | ... | @@ -29536,7 +29599,7 @@ fn typePtrOrOptionalPtrTy( |
| 29536 | 29599 | /// TODO assert the return value matches `ty.comptimeOnly` |
| 29537 | 29600 | /// TODO merge these implementations together with the "advanced"/sema_kit pattern seen |
| 29538 | 29601 | /// elsewhere in value.zig |
| 29539 | pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool { | |
| 29602 | pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { | |
| 29540 | 29603 | return switch (ty.tag()) { |
| 29541 | 29604 | .u1, |
| 29542 | 29605 | .u8, |
| ... | ... | @@ -29627,7 +29690,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ |
| 29627 | 29690 | .array, |
| 29628 | 29691 | .array_sentinel, |
| 29629 | 29692 | .vector, |
| 29630 | => return sema.typeRequiresComptime(block, src, ty.childType()), | |
| 29693 | => return sema.typeRequiresComptime(ty.childType()), | |
| 29631 | 29694 | |
| 29632 | 29695 | .pointer, |
| 29633 | 29696 | .single_const_pointer, |
| ... | ... | @@ -29643,7 +29706,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ |
| 29643 | 29706 | if (child_ty.zigTypeTag() == .Fn) { |
| 29644 | 29707 | return child_ty.fnInfo().is_generic; |
| 29645 | 29708 | } else { |
| 29646 | return sema.typeRequiresComptime(block, src, child_ty); | |
| 29709 | return sema.typeRequiresComptime(child_ty); | |
| 29647 | 29710 | } |
| 29648 | 29711 | }, |
| 29649 | 29712 | |
| ... | ... | @@ -29652,14 +29715,14 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ |
| 29652 | 29715 | .optional_single_const_pointer, |
| 29653 | 29716 | => { |
| 29654 | 29717 | var buf: Type.Payload.ElemType = undefined; |
| 29655 | return sema.typeRequiresComptime(block, src, ty.optionalChild(&buf)); | |
| 29718 | return sema.typeRequiresComptime(ty.optionalChild(&buf)); | |
| 29656 | 29719 | }, |
| 29657 | 29720 | |
| 29658 | 29721 | .tuple, .anon_struct => { |
| 29659 | 29722 | const tuple = ty.tupleFields(); |
| 29660 | 29723 | for (tuple.types) |field_ty, i| { |
| 29661 | 29724 | const have_comptime_val = tuple.values[i].tag() != .unreachable_value; |
| 29662 | if (!have_comptime_val and try sema.typeRequiresComptime(block, src, field_ty)) { | |
| 29725 | if (!have_comptime_val and try sema.typeRequiresComptime(field_ty)) { | |
| 29663 | 29726 | return true; |
| 29664 | 29727 | } |
| 29665 | 29728 | } |
| ... | ... | @@ -29680,7 +29743,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ |
| 29680 | 29743 | struct_obj.requires_comptime = .wip; |
| 29681 | 29744 | for (struct_obj.fields.values()) |field| { |
| 29682 | 29745 | if (field.is_comptime) continue; |
| 29683 | if (try sema.typeRequiresComptime(block, src, field.ty)) { | |
| 29746 | if (try sema.typeRequiresComptime(field.ty)) { | |
| 29684 | 29747 | struct_obj.requires_comptime = .yes; |
| 29685 | 29748 | return true; |
| 29686 | 29749 | } |
| ... | ... | @@ -29704,7 +29767,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ |
| 29704 | 29767 | |
| 29705 | 29768 | union_obj.requires_comptime = .wip; |
| 29706 | 29769 | for (union_obj.fields.values()) |field| { |
| 29707 | if (try sema.typeRequiresComptime(block, src, field.ty)) { | |
| 29770 | if (try sema.typeRequiresComptime(field.ty)) { | |
| 29708 | 29771 | union_obj.requires_comptime = .yes; |
| 29709 | 29772 | return true; |
| 29710 | 29773 | } |
| ... | ... | @@ -29715,18 +29778,18 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ |
| 29715 | 29778 | } |
| 29716 | 29779 | }, |
| 29717 | 29780 | |
| 29718 | .error_union => return sema.typeRequiresComptime(block, src, ty.errorUnionPayload()), | |
| 29781 | .error_union => return sema.typeRequiresComptime(ty.errorUnionPayload()), | |
| 29719 | 29782 | .anyframe_T => { |
| 29720 | 29783 | const child_ty = ty.castTag(.anyframe_T).?.data; |
| 29721 | return sema.typeRequiresComptime(block, src, child_ty); | |
| 29784 | return sema.typeRequiresComptime(child_ty); | |
| 29722 | 29785 | }, |
| 29723 | 29786 | .enum_numbered => { |
| 29724 | 29787 | const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty; |
| 29725 | return sema.typeRequiresComptime(block, src, tag_ty); | |
| 29788 | return sema.typeRequiresComptime(tag_ty); | |
| 29726 | 29789 | }, |
| 29727 | 29790 | .enum_full, .enum_nonexhaustive => { |
| 29728 | 29791 | const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty; |
| 29729 | return sema.typeRequiresComptime(block, src, tag_ty); | |
| 29792 | return sema.typeRequiresComptime(tag_ty); | |
| 29730 | 29793 | }, |
| 29731 | 29794 | }; |
| 29732 | 29795 | } |
| ... | ... | @@ -29764,7 +29827,7 @@ fn unionFieldAlignment( |
| 29764 | 29827 | } |
| 29765 | 29828 | |
| 29766 | 29829 | /// Synchronize logic with `Type.isFnOrHasRuntimeBits`. |
| 29767 | pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool { | |
| 29830 | pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { | |
| 29768 | 29831 | const fn_info = ty.fnInfo(); |
| 29769 | 29832 | if (fn_info.is_generic) return false; |
| 29770 | 29833 | if (fn_info.is_var_args) return true; |
| ... | ... | @@ -29773,7 +29836,7 @@ pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) C |
| 29773 | 29836 | .Inline => return false, |
| 29774 | 29837 | else => {}, |
| 29775 | 29838 | } |
| 29776 | if (try sema.typeRequiresComptime(block, src, fn_info.return_type)) { | |
| 29839 | if (try sema.typeRequiresComptime(fn_info.return_type)) { | |
| 29777 | 29840 | return false; |
| 29778 | 29841 | } |
| 29779 | 29842 | return true; |
src/arch/wasm/abi.zig+8| ... | ... | @@ -23,6 +23,10 @@ pub fn classifyType(ty: Type, target: Target) [2]Class { |
| 23 | 23 | if (!ty.hasRuntimeBitsIgnoreComptime()) return none; |
| 24 | 24 | switch (ty.zigTypeTag()) { |
| 25 | 25 | .Struct => { |
| 26 | if (ty.containerLayout() == .Packed) { | |
| 27 | if (ty.bitSize(target) <= 64) return direct; | |
| 28 | return .{ .direct, .direct }; | |
| 29 | } | |
| 26 | 30 | // When the struct type is non-scalar |
| 27 | 31 | if (ty.structFieldCount() > 1) return memory; |
| 28 | 32 | // When the struct's alignment is non-natural |
| ... | ... | @@ -57,6 +61,10 @@ pub fn classifyType(ty: Type, target: Target) [2]Class { |
| 57 | 61 | return direct; |
| 58 | 62 | }, |
| 59 | 63 | .Union => { |
| 64 | if (ty.containerLayout() == .Packed) { | |
| 65 | if (ty.bitSize(target) <= 64) return direct; | |
| 66 | return .{ .direct, .direct }; | |
| 67 | } | |
| 60 | 68 | const layout = ty.unionGetLayout(target); |
| 61 | 69 | std.debug.assert(layout.tag_size == 0); |
| 62 | 70 | if (ty.unionFields().count() > 1) return memory; |
src/arch/x86_64/abi.zig+22-2| ... | ... | @@ -5,7 +5,7 @@ const assert = std.debug.assert; |
| 5 | 5 | const Register = @import("bits.zig").Register; |
| 6 | 6 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 7 | 7 | |
| 8 | pub const Class = enum { integer, sse, sseup, x87, x87up, complex_x87, memory, none }; | |
| 8 | pub const Class = enum { integer, sse, sseup, x87, x87up, complex_x87, memory, none, win_i128 }; | |
| 9 | 9 | |
| 10 | 10 | pub fn classifyWindows(ty: Type, target: Target) Class { |
| 11 | 11 | // https://docs.microsoft.com/en-gb/cpp/build/x64-calling-convention?view=vs-2017 |
| ... | ... | @@ -34,7 +34,15 @@ pub fn classifyWindows(ty: Type, target: Target) Class { |
| 34 | 34 | => switch (ty.abiSize(target)) { |
| 35 | 35 | 0 => unreachable, |
| 36 | 36 | 1, 2, 4, 8 => return .integer, |
| 37 | else => return .memory, | |
| 37 | else => switch (ty.zigTypeTag()) { | |
| 38 | .Int => return .win_i128, | |
| 39 | .Struct, .Union => if (ty.containerLayout() == .Packed) { | |
| 40 | return .win_i128; | |
| 41 | } else { | |
| 42 | return .memory; | |
| 43 | }, | |
| 44 | else => return .memory, | |
| 45 | }, | |
| 38 | 46 | }, |
| 39 | 47 | |
| 40 | 48 | .Float, .Vector => return .sse, |
| ... | ... | @@ -174,6 +182,12 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class { |
| 174 | 182 | // "If the size of the aggregate exceeds a single eightbyte, each is classified |
| 175 | 183 | // separately.". |
| 176 | 184 | const ty_size = ty.abiSize(target); |
| 185 | if (ty.containerLayout() == .Packed) { | |
| 186 | assert(ty_size <= 128); | |
| 187 | result[0] = .integer; | |
| 188 | if (ty_size > 64) result[1] = .integer; | |
| 189 | return result; | |
| 190 | } | |
| 177 | 191 | if (ty_size > 64) |
| 178 | 192 | return memory_class; |
| 179 | 193 | |
| ... | ... | @@ -284,6 +298,12 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class { |
| 284 | 298 | // "If the size of the aggregate exceeds a single eightbyte, each is classified |
| 285 | 299 | // separately.". |
| 286 | 300 | const ty_size = ty.abiSize(target); |
| 301 | if (ty.containerLayout() == .Packed) { | |
| 302 | assert(ty_size <= 128); | |
| 303 | result[0] = .integer; | |
| 304 | if (ty_size > 64) result[1] = .integer; | |
| 305 | return result; | |
| 306 | } | |
| 287 | 307 | if (ty_size > 64) |
| 288 | 308 | return memory_class; |
| 289 | 309 |
src/codegen/llvm.zig+35-39| ... | ... | @@ -9051,7 +9051,7 @@ pub const FuncGen = struct { |
| 9051 | 9051 | } |
| 9052 | 9052 | }, |
| 9053 | 9053 | }, |
| 9054 | .Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty, field_index), | |
| 9054 | .Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty), | |
| 9055 | 9055 | else => unreachable, |
| 9056 | 9056 | } |
| 9057 | 9057 | } |
| ... | ... | @@ -9061,16 +9061,13 @@ pub const FuncGen = struct { |
| 9061 | 9061 | inst: Air.Inst.Index, |
| 9062 | 9062 | union_ptr: *const llvm.Value, |
| 9063 | 9063 | union_ty: Type, |
| 9064 | field_index: c_uint, | |
| 9065 | 9064 | ) !?*const llvm.Value { |
| 9066 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | |
| 9067 | const field = &union_obj.fields.values()[field_index]; | |
| 9068 | 9065 | const result_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst)); |
| 9069 | if (!field.ty.hasRuntimeBitsIgnoreComptime()) { | |
| 9070 | return null; | |
| 9071 | } | |
| 9072 | 9066 | const target = self.dg.module.getTarget(); |
| 9073 | 9067 | const layout = union_ty.unionGetLayout(target); |
| 9068 | if (layout.payload_size == 0) { | |
| 9069 | return self.builder.buildBitCast(union_ptr, result_llvm_ty, ""); | |
| 9070 | } | |
| 9074 | 9071 | const payload_index = @boolToInt(layout.tag_align >= layout.payload_align); |
| 9075 | 9072 | const union_field_ptr = self.builder.buildStructGEP(union_ptr, payload_index, ""); |
| 9076 | 9073 | return self.builder.buildBitCast(union_field_ptr, result_llvm_ty, ""); |
| ... | ... | @@ -9677,22 +9674,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm. |
| 9677 | 9674 | } |
| 9678 | 9675 | }, |
| 9679 | 9676 | .C => { |
| 9680 | const is_scalar = switch (fn_info.return_type.zigTypeTag()) { | |
| 9681 | .Void, | |
| 9682 | .Bool, | |
| 9683 | .NoReturn, | |
| 9684 | .Int, | |
| 9685 | .Float, | |
| 9686 | .Pointer, | |
| 9687 | .Optional, | |
| 9688 | .ErrorSet, | |
| 9689 | .Enum, | |
| 9690 | .AnyFrame, | |
| 9691 | .Vector, | |
| 9692 | => true, | |
| 9693 | ||
| 9694 | else => false, | |
| 9695 | }; | |
| 9677 | const is_scalar = isScalar(fn_info.return_type); | |
| 9696 | 9678 | switch (target.cpu.arch) { |
| 9697 | 9679 | .mips, .mipsel => return dg.lowerType(fn_info.return_type), |
| 9698 | 9680 | .x86_64 => switch (target.os.tag) { |
| ... | ... | @@ -9705,6 +9687,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm. |
| 9705 | 9687 | return dg.context.intType(@intCast(c_uint, abi_size * 8)); |
| 9706 | 9688 | } |
| 9707 | 9689 | }, |
| 9690 | .win_i128 => return dg.context.intType(64).vectorType(2), | |
| 9708 | 9691 | .memory => return dg.context.voidType(), |
| 9709 | 9692 | .sse => return dg.lowerType(fn_info.return_type), |
| 9710 | 9693 | else => unreachable, |
| ... | ... | @@ -9745,6 +9728,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm. |
| 9745 | 9728 | @panic("TODO"); |
| 9746 | 9729 | }, |
| 9747 | 9730 | .memory => unreachable, // handled above |
| 9731 | .win_i128 => unreachable, // windows only | |
| 9748 | 9732 | .none => break, |
| 9749 | 9733 | } |
| 9750 | 9734 | } |
| ... | ... | @@ -9840,22 +9824,7 @@ const ParamTypeIterator = struct { |
| 9840 | 9824 | @panic("TODO implement async function lowering in the LLVM backend"); |
| 9841 | 9825 | }, |
| 9842 | 9826 | .C => { |
| 9843 | const is_scalar = switch (ty.zigTypeTag()) { | |
| 9844 | .Void, | |
| 9845 | .Bool, | |
| 9846 | .NoReturn, | |
| 9847 | .Int, | |
| 9848 | .Float, | |
| 9849 | .Pointer, | |
| 9850 | .Optional, | |
| 9851 | .ErrorSet, | |
| 9852 | .Enum, | |
| 9853 | .AnyFrame, | |
| 9854 | .Vector, | |
| 9855 | => true, | |
| 9856 | ||
| 9857 | else => false, | |
| 9858 | }; | |
| 9827 | const is_scalar = isScalar(ty); | |
| 9859 | 9828 | switch (it.target.cpu.arch) { |
| 9860 | 9829 | .riscv32, .riscv64 => { |
| 9861 | 9830 | it.zig_index += 1; |
| ... | ... | @@ -9884,6 +9853,11 @@ const ParamTypeIterator = struct { |
| 9884 | 9853 | return .abi_sized_int; |
| 9885 | 9854 | } |
| 9886 | 9855 | }, |
| 9856 | .win_i128 => { | |
| 9857 | it.zig_index += 1; | |
| 9858 | it.llvm_index += 1; | |
| 9859 | return .byref; | |
| 9860 | }, | |
| 9887 | 9861 | .memory => { |
| 9888 | 9862 | it.zig_index += 1; |
| 9889 | 9863 | it.llvm_index += 1; |
| ... | ... | @@ -9938,6 +9912,7 @@ const ParamTypeIterator = struct { |
| 9938 | 9912 | @panic("TODO"); |
| 9939 | 9913 | }, |
| 9940 | 9914 | .memory => unreachable, // handled above |
| 9915 | .win_i128 => unreachable, // windows only | |
| 9941 | 9916 | .none => break, |
| 9942 | 9917 | } |
| 9943 | 9918 | } |
| ... | ... | @@ -10109,6 +10084,27 @@ fn isByRef(ty: Type) bool { |
| 10109 | 10084 | } |
| 10110 | 10085 | } |
| 10111 | 10086 | |
| 10087 | fn isScalar(ty: Type) bool { | |
| 10088 | return switch (ty.zigTypeTag()) { | |
| 10089 | .Void, | |
| 10090 | .Bool, | |
| 10091 | .NoReturn, | |
| 10092 | .Int, | |
| 10093 | .Float, | |
| 10094 | .Pointer, | |
| 10095 | .Optional, | |
| 10096 | .ErrorSet, | |
| 10097 | .Enum, | |
| 10098 | .AnyFrame, | |
| 10099 | .Vector, | |
| 10100 | => true, | |
| 10101 | ||
| 10102 | .Struct => ty.containerLayout() == .Packed, | |
| 10103 | .Union => ty.containerLayout() == .Packed, | |
| 10104 | else => false, | |
| 10105 | }; | |
| 10106 | } | |
| 10107 | ||
| 10112 | 10108 | /// This function returns true if we expect LLVM to lower x86_fp80 correctly |
| 10113 | 10109 | /// and false if we expect LLVM to crash if it counters an x86_fp80 type. |
| 10114 | 10110 | fn backendSupportsF80(target: std.Target) bool { |
src/translate_c.zig+4| ... | ... | @@ -1166,6 +1166,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD |
| 1166 | 1166 | }); |
| 1167 | 1167 | } |
| 1168 | 1168 | |
| 1169 | if (!c.zig_is_stage1 and is_packed) { | |
| 1170 | return failDecl(c, record_loc, bare_name, "cannot translate packed record union", .{}); | |
| 1171 | } | |
| 1172 | ||
| 1169 | 1173 | const record_payload = try c.arena.create(ast.Payload.Record); |
| 1170 | 1174 | record_payload.* = .{ |
| 1171 | 1175 | .base = .{ .tag = ([2]Tag{ .@"struct", .@"union" })[@boolToInt(is_union)] }, |
src/type.zig+5-2| ... | ... | @@ -2042,6 +2042,9 @@ pub const Type = extern union { |
| 2042 | 2042 | try writer.writeAll("fn("); |
| 2043 | 2043 | for (fn_info.param_types) |param_ty, i| { |
| 2044 | 2044 | if (i != 0) try writer.writeAll(", "); |
| 2045 | if (std.math.cast(u5, i)) |index| if (@truncate(u1, fn_info.noalias_bits >> index) != 0) { | |
| 2046 | try writer.writeAll("noalias "); | |
| 2047 | }; | |
| 2045 | 2048 | if (param_ty.tag() == .generic_poison) { |
| 2046 | 2049 | try writer.writeAll("anytype"); |
| 2047 | 2050 | } else { |
| ... | ... | @@ -2398,7 +2401,7 @@ pub const Type = extern union { |
| 2398 | 2401 | } else if (ty.childType().zigTypeTag() == .Fn) { |
| 2399 | 2402 | return !ty.childType().fnInfo().is_generic; |
| 2400 | 2403 | } else if (sema_kit) |sk| { |
| 2401 | return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty)); | |
| 2404 | return !(try sk.sema.typeRequiresComptime(ty)); | |
| 2402 | 2405 | } else { |
| 2403 | 2406 | return !comptimeOnly(ty); |
| 2404 | 2407 | } |
| ... | ... | @@ -2437,7 +2440,7 @@ pub const Type = extern union { |
| 2437 | 2440 | if (ignore_comptime_only) { |
| 2438 | 2441 | return true; |
| 2439 | 2442 | } else if (sema_kit) |sk| { |
| 2440 | return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, child_ty)); | |
| 2443 | return !(try sk.sema.typeRequiresComptime(child_ty)); | |
| 2441 | 2444 | } else { |
| 2442 | 2445 | return !comptimeOnly(child_ty); |
| 2443 | 2446 | } |
src/value.zig+26-3| ... | ... | @@ -2940,17 +2940,24 @@ pub const Value = extern union { |
| 2940 | 2940 | } |
| 2941 | 2941 | |
| 2942 | 2942 | pub fn intToFloat(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, target: Target) !Value { |
| 2943 | return intToFloatAdvanced(val, arena, int_ty, float_ty, target, null) catch |err| switch (err) { | |
| 2944 | error.OutOfMemory => return error.OutOfMemory, | |
| 2945 | else => unreachable, | |
| 2946 | }; | |
| 2947 | } | |
| 2948 | ||
| 2949 | pub fn intToFloatAdvanced(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, target: Target, sema_kit: ?Module.WipAnalysis) !Value { | |
| 2943 | 2950 | if (int_ty.zigTypeTag() == .Vector) { |
| 2944 | 2951 | const result_data = try arena.alloc(Value, int_ty.vectorLen()); |
| 2945 | 2952 | for (result_data) |*scalar, i| { |
| 2946 | scalar.* = try intToFloatScalar(val.indexVectorlike(i), arena, float_ty.scalarType(), target); | |
| 2953 | scalar.* = try intToFloatScalar(val.indexVectorlike(i), arena, float_ty.scalarType(), target, sema_kit); | |
| 2947 | 2954 | } |
| 2948 | 2955 | return Value.Tag.aggregate.create(arena, result_data); |
| 2949 | 2956 | } |
| 2950 | return intToFloatScalar(val, arena, float_ty, target); | |
| 2957 | return intToFloatScalar(val, arena, float_ty, target, sema_kit); | |
| 2951 | 2958 | } |
| 2952 | 2959 | |
| 2953 | pub fn intToFloatScalar(val: Value, arena: Allocator, float_ty: Type, target: Target) !Value { | |
| 2960 | pub fn intToFloatScalar(val: Value, arena: Allocator, float_ty: Type, target: Target, sema_kit: ?Module.WipAnalysis) !Value { | |
| 2954 | 2961 | switch (val.tag()) { |
| 2955 | 2962 | .undef, .zero, .one => return val, |
| 2956 | 2963 | .the_only_possible_value => return Value.initTag(.zero), // for i0, u0 |
| ... | ... | @@ -2970,6 +2977,22 @@ pub const Value = extern union { |
| 2970 | 2977 | const float = bigIntToFloat(limbs, false); |
| 2971 | 2978 | return floatToValue(float, arena, float_ty, target); |
| 2972 | 2979 | }, |
| 2980 | .lazy_align => { | |
| 2981 | const ty = val.castTag(.lazy_align).?.data; | |
| 2982 | if (sema_kit) |sk| { | |
| 2983 | return intToFloatInner((try ty.abiAlignmentAdvanced(target, .{ .sema_kit = sk })).scalar, arena, float_ty, target); | |
| 2984 | } else { | |
| 2985 | return intToFloatInner(ty.abiAlignment(target), arena, float_ty, target); | |
| 2986 | } | |
| 2987 | }, | |
| 2988 | .lazy_size => { | |
| 2989 | const ty = val.castTag(.lazy_size).?.data; | |
| 2990 | if (sema_kit) |sk| { | |
| 2991 | return intToFloatInner((try ty.abiSizeAdvanced(target, .{ .sema_kit = sk })).scalar, arena, float_ty, target); | |
| 2992 | } else { | |
| 2993 | return intToFloatInner(ty.abiSize(target), arena, float_ty, target); | |
| 2994 | } | |
| 2995 | }, | |
| 2973 | 2996 | else => unreachable, |
| 2974 | 2997 | } |
| 2975 | 2998 | } |
test/behavior/enum.zig+7| ... | ... | @@ -1175,3 +1175,10 @@ test "Non-exhaustive enum with nonstandard int size behaves correctly" { |
| 1175 | 1175 | const E = enum(u15) { _ }; |
| 1176 | 1176 | try expect(@sizeOf(E) == @sizeOf(u15)); |
| 1177 | 1177 | } |
| 1178 | ||
| 1179 | test "Non-exhaustive enum backed by comptime_int" { | |
| 1180 | const E = enum(comptime_int) { a, b, c, _ }; | |
| 1181 | comptime var e: E = .a; | |
| 1182 | e = @intToEnum(E, 378089457309184723749); | |
| 1183 | try expect(@enumToInt(e) == 378089457309184723749); | |
| 1184 | } |
test/behavior/packed-struct.zig+26| ... | ... | @@ -579,3 +579,29 @@ test "runtime init of unnamed packed struct type" { |
| 579 | 579 | } |
| 580 | 580 | }{ .x = z }).m(); |
| 581 | 581 | } |
| 582 | ||
| 583 | test "packed struct passed to callconv(.C) function" { | |
| 584 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 585 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 586 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 587 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | |
| 588 | ||
| 589 | const S = struct { | |
| 590 | const Packed = packed struct { | |
| 591 | a: u16, | |
| 592 | b: bool = true, | |
| 593 | c: bool = true, | |
| 594 | d: u46 = 0, | |
| 595 | }; | |
| 596 | ||
| 597 | fn foo(p: Packed, a1: u64, a2: u64, a3: u64, a4: u64, a5: u64) callconv(.C) bool { | |
| 598 | return p.a == 12345 and p.b == true and p.c == true and p.d == 0 and a1 == 5 and a2 == 4 and a3 == 3 and a4 == 2 and a5 == 1; | |
| 599 | } | |
| 600 | }; | |
| 601 | const result = S.foo(S.Packed{ | |
| 602 | .a = 12345, | |
| 603 | .b = true, | |
| 604 | .c = true, | |
| 605 | }, 5, 4, 3, 2, 1); | |
| 606 | try expect(result); | |
| 607 | } |
test/behavior/sizeof_and_typeof.zig+11| ... | ... | @@ -301,3 +301,14 @@ test "array access of generic param in typeof expression" { |
| 301 | 301 | try expect(S.first("a") == 'a'); |
| 302 | 302 | comptime try expect(S.first("a") == 'a'); |
| 303 | 303 | } |
| 304 | ||
| 305 | test "lazy size cast to float" { | |
| 306 | { | |
| 307 | const S = struct { a: u8 }; | |
| 308 | try expect(@intToFloat(f32, @sizeOf(S)) == 1.0); | |
| 309 | } | |
| 310 | { | |
| 311 | const S = struct { a: u8 }; | |
| 312 | try expect(@as(f32, @sizeOf(S)) == 1.0); | |
| 313 | } | |
| 314 | } |
test/behavior/union.zig+29-1| ... | ... | @@ -690,7 +690,7 @@ test "union with only 1 field casted to its enum type which has enum value speci |
| 690 | 690 | |
| 691 | 691 | var e = Expr{ .Literal = Literal{ .Bool = true } }; |
| 692 | 692 | comptime try expect(Tag(ExprTag) == comptime_int); |
| 693 | var t = @as(ExprTag, e); | |
| 693 | comptime var t = @as(ExprTag, e); | |
| 694 | 694 | try expect(t == Expr.Literal); |
| 695 | 695 | try expect(@enumToInt(t) == 33); |
| 696 | 696 | comptime try expect(@enumToInt(t) == 33); |
| ... | ... | @@ -1352,3 +1352,31 @@ test "@unionInit uses tag value instead of field index" { |
| 1352 | 1352 | } |
| 1353 | 1353 | try expect(@enumToInt(u) == 255); |
| 1354 | 1354 | } |
| 1355 | ||
| 1356 | test "union field ptr - zero sized payload" { | |
| 1357 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 1358 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1359 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 1360 | ||
| 1361 | const U = union { | |
| 1362 | foo: void, | |
| 1363 | bar: void, | |
| 1364 | fn bar(_: *void) void {} | |
| 1365 | }; | |
| 1366 | var u: U = .{ .foo = {} }; | |
| 1367 | U.bar(&u.foo); | |
| 1368 | } | |
| 1369 | ||
| 1370 | test "union field ptr - zero sized field" { | |
| 1371 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 1372 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1373 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 1374 | ||
| 1375 | const U = union { | |
| 1376 | foo: void, | |
| 1377 | bar: u32, | |
| 1378 | fn bar(_: *void) void {} | |
| 1379 | }; | |
| 1380 | var u: U = .{ .foo = {} }; | |
| 1381 | U.bar(&u.foo); | |
| 1382 | } |
test/c_abi/cfuncs.c+29-49| ... | ... | @@ -86,24 +86,8 @@ struct MedStructMixed { |
| 86 | 86 | void zig_med_struct_mixed(struct MedStructMixed); |
| 87 | 87 | struct MedStructMixed zig_ret_med_struct_mixed(); |
| 88 | 88 | |
| 89 | struct SmallPackedStruct { | |
| 90 | uint8_t a: 2; | |
| 91 | uint8_t b: 2; | |
| 92 | uint8_t c: 2; | |
| 93 | uint8_t d: 2; | |
| 94 | uint8_t e: 1; | |
| 95 | }; | |
| 96 | ||
| 97 | struct BigPackedStruct { | |
| 98 | uint64_t a: 64; | |
| 99 | uint64_t b: 64; | |
| 100 | uint64_t c: 64; | |
| 101 | uint64_t d: 64; | |
| 102 | uint8_t e: 8; | |
| 103 | }; | |
| 104 | ||
| 105 | //void zig_small_packed_struct(struct SmallPackedStruct); // #1481 | |
| 106 | void zig_big_packed_struct(struct BigPackedStruct); | |
| 89 | void zig_small_packed_struct(uint8_t); | |
| 90 | void zig_big_packed_struct(__int128); | |
| 107 | 91 | |
| 108 | 92 | struct SplitStructInts { |
| 109 | 93 | uint64_t a; |
| ... | ... | @@ -176,13 +160,19 @@ void run_c_tests(void) { |
| 176 | 160 | } |
| 177 | 161 | |
| 178 | 162 | { |
| 179 | struct BigPackedStruct s = {1, 2, 3, 4, 5}; | |
| 163 | __int128 s = 0; | |
| 164 | s |= 1 << 0; | |
| 165 | s |= (__int128)2 << 64; | |
| 180 | 166 | zig_big_packed_struct(s); |
| 181 | 167 | } |
| 182 | 168 | |
| 183 | 169 | { |
| 184 | struct SmallPackedStruct s = {0, 1, 2, 3, 1}; | |
| 185 | //zig_small_packed_struct(s); | |
| 170 | uint8_t s = 0; | |
| 171 | s |= 0 << 0; | |
| 172 | s |= 1 << 2; | |
| 173 | s |= 2 << 4; | |
| 174 | s |= 3 << 6; | |
| 175 | zig_small_packed_struct(s); | |
| 186 | 176 | } |
| 187 | 177 | |
| 188 | 178 | { |
| ... | ... | @@ -378,42 +368,32 @@ void c_split_struct_mixed(struct SplitStructMixed x) { |
| 378 | 368 | assert_or_panic(y.c == 1337.0f); |
| 379 | 369 | } |
| 380 | 370 | |
| 381 | struct SmallPackedStruct c_ret_small_packed_struct() { | |
| 382 | struct SmallPackedStruct s = { | |
| 383 | .a = 0, | |
| 384 | .b = 1, | |
| 385 | .c = 2, | |
| 386 | .d = 3, | |
| 387 | .e = 1, | |
| 388 | }; | |
| 371 | uint8_t c_ret_small_packed_struct() { | |
| 372 | uint8_t s = 0; | |
| 373 | s |= 0 << 0; | |
| 374 | s |= 1 << 2; | |
| 375 | s |= 2 << 4; | |
| 376 | s |= 3 << 6; | |
| 389 | 377 | return s; |
| 390 | 378 | } |
| 391 | 379 | |
| 392 | void c_small_packed_struct(struct SmallPackedStruct x) { | |
| 393 | assert_or_panic(x.a == 0); | |
| 394 | assert_or_panic(x.a == 1); | |
| 395 | assert_or_panic(x.a == 2); | |
| 396 | assert_or_panic(x.a == 3); | |
| 397 | assert_or_panic(x.e == 1); | |
| 380 | void c_small_packed_struct(uint8_t x) { | |
| 381 | assert_or_panic(((x >> 0) & 0x3) == 0); | |
| 382 | assert_or_panic(((x >> 2) & 0x3) == 1); | |
| 383 | assert_or_panic(((x >> 4) & 0x3) == 2); | |
| 384 | assert_or_panic(((x >> 6) & 0x3) == 3); | |
| 398 | 385 | } |
| 399 | 386 | |
| 400 | struct BigPackedStruct c_ret_big_packed_struct() { | |
| 401 | struct BigPackedStruct s = { | |
| 402 | .a = 1, | |
| 403 | .b = 2, | |
| 404 | .c = 3, | |
| 405 | .d = 4, | |
| 406 | .e = 5, | |
| 407 | }; | |
| 387 | __int128 c_ret_big_packed_struct() { | |
| 388 | __int128 s = 0; | |
| 389 | s |= 1 << 0; | |
| 390 | s |= (__int128)2 << 64; | |
| 408 | 391 | return s; |
| 409 | 392 | } |
| 410 | 393 | |
| 411 | void c_big_packed_struct(struct BigPackedStruct x) { | |
| 412 | assert_or_panic(x.a == 1); | |
| 413 | assert_or_panic(x.b == 2); | |
| 414 | assert_or_panic(x.c == 3); | |
| 415 | assert_or_panic(x.d == 4); | |
| 416 | assert_or_panic(x.e == 5); | |
| 394 | void c_big_packed_struct(__int128 x) { | |
| 395 | assert_or_panic(((x >> 0) & 0xFFFFFFFFFFFFFFFF) == 1); | |
| 396 | assert_or_panic(((x >> 64) & 0xFFFFFFFFFFFFFFFF) == 2); | |
| 417 | 397 | } |
| 418 | 398 | |
| 419 | 399 | struct SplitStructMixed c_ret_split_struct_mixed() { |
test/c_abi/main.zig+10-23| ... | ... | @@ -263,37 +263,30 @@ const SmallPackedStruct = packed struct { |
| 263 | 263 | b: u2, |
| 264 | 264 | c: u2, |
| 265 | 265 | d: u2, |
| 266 | e: bool, | |
| 267 | 266 | }; |
| 268 | const c_small_packed_struct: fn (SmallPackedStruct) callconv(.C) void = @compileError("TODO: #1481"); | |
| 267 | extern fn c_small_packed_struct(SmallPackedStruct) void; | |
| 269 | 268 | extern fn c_ret_small_packed_struct() SmallPackedStruct; |
| 270 | 269 | |
| 271 | // waiting on #1481 | |
| 272 | //export fn zig_small_packed_struct(x: SmallPackedStruct) void { | |
| 273 | // expect(x.a == 0) catch @panic("test failure"); | |
| 274 | // expect(x.b == 1) catch @panic("test failure"); | |
| 275 | // expect(x.c == 2) catch @panic("test failure"); | |
| 276 | // expect(x.d == 3) catch @panic("test failure"); | |
| 277 | // expect(x.e) catch @panic("test failure"); | |
| 278 | //} | |
| 270 | export fn zig_small_packed_struct(x: SmallPackedStruct) void { | |
| 271 | expect(x.a == 0) catch @panic("test failure"); | |
| 272 | expect(x.b == 1) catch @panic("test failure"); | |
| 273 | expect(x.c == 2) catch @panic("test failure"); | |
| 274 | expect(x.d == 3) catch @panic("test failure"); | |
| 275 | } | |
| 279 | 276 | |
| 280 | 277 | test "C ABI small packed struct" { |
| 281 | var s = SmallPackedStruct{ .a = 0, .b = 1, .c = 2, .d = 3, .e = true }; | |
| 282 | _ = s; //c_small_packed_struct(s); // waiting on #1481 | |
| 278 | var s = SmallPackedStruct{ .a = 0, .b = 1, .c = 2, .d = 3 }; | |
| 279 | c_small_packed_struct(s); | |
| 283 | 280 | var s2 = c_ret_small_packed_struct(); |
| 284 | 281 | try expect(s2.a == 0); |
| 285 | 282 | try expect(s2.b == 1); |
| 286 | 283 | try expect(s2.c == 2); |
| 287 | 284 | try expect(s2.d == 3); |
| 288 | try expect(s2.e); | |
| 289 | 285 | } |
| 290 | 286 | |
| 291 | 287 | const BigPackedStruct = packed struct { |
| 292 | 288 | a: u64, |
| 293 | 289 | b: u64, |
| 294 | c: u64, | |
| 295 | d: u64, | |
| 296 | e: u8, | |
| 297 | 290 | }; |
| 298 | 291 | extern fn c_big_packed_struct(BigPackedStruct) void; |
| 299 | 292 | extern fn c_ret_big_packed_struct() BigPackedStruct; |
| ... | ... | @@ -301,20 +294,14 @@ extern fn c_ret_big_packed_struct() BigPackedStruct; |
| 301 | 294 | export fn zig_big_packed_struct(x: BigPackedStruct) void { |
| 302 | 295 | expect(x.a == 1) catch @panic("test failure"); |
| 303 | 296 | expect(x.b == 2) catch @panic("test failure"); |
| 304 | expect(x.c == 3) catch @panic("test failure"); | |
| 305 | expect(x.d == 4) catch @panic("test failure"); | |
| 306 | expect(x.e == 5) catch @panic("test failure"); | |
| 307 | 297 | } |
| 308 | 298 | |
| 309 | 299 | test "C ABI big packed struct" { |
| 310 | var s = BigPackedStruct{ .a = 1, .b = 2, .c = 3, .d = 4, .e = 5 }; | |
| 300 | var s = BigPackedStruct{ .a = 1, .b = 2 }; | |
| 311 | 301 | c_big_packed_struct(s); |
| 312 | 302 | var s2 = c_ret_big_packed_struct(); |
| 313 | 303 | try expect(s2.a == 1); |
| 314 | 304 | try expect(s2.b == 2); |
| 315 | try expect(s2.c == 3); | |
| 316 | try expect(s2.d == 4); | |
| 317 | try expect(s2.e == 5); | |
| 318 | 305 | } |
| 319 | 306 | |
| 320 | 307 | const SplitStructInt = extern struct { |
test/cases/compile_errors/C_pointer_pointing_to_non_C_ABI_compatible_type_or_has_align_attr.zig+1-1| ... | ... | @@ -10,5 +10,5 @@ export fn a() void { |
| 10 | 10 | // target=native |
| 11 | 11 | // |
| 12 | 12 | // :3:19: error: C pointers cannot point to non-C-ABI-compatible type 'tmp.Foo' |
| 13 | // :3:19: note: only structs with packed or extern layout are extern compatible | |
| 13 | // :3:19: note: only extern structs and ABI sized packed structs are extern compatible | |
| 14 | 14 | // :1:13: note: struct declared here |
test/cases/compile_errors/enum_backed_by_comptime_int_must_be_comptime.zig created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | pub export fn entry() void { | |
| 2 | const E = enum(comptime_int) { a, b, c, _ }; | |
| 3 | var e: E = .a; | |
| 4 | _ = e; | |
| 5 | } | |
| 6 | ||
| 7 | // error | |
| 8 | // backend=stage2 | |
| 9 | // target=native | |
| 10 | // | |
| 11 | // :3:12: error: variable of type 'tmp.entry.E' must be const or comptime |
test/cases/compile_errors/function_with_non-extern_non-packed_struct_parameter.zig+1-1| ... | ... | @@ -10,5 +10,5 @@ export fn entry(foo: Foo) void { _ = foo; } |
| 10 | 10 | // target=native |
| 11 | 11 | // |
| 12 | 12 | // :6:17: error: parameter of type 'tmp.Foo' not allowed in function with calling convention 'C' |
| 13 | // :6:17: note: only structs with packed or extern layout are extern compatible | |
| 13 | // :6:17: note: only extern structs and ABI sized packed structs are extern compatible | |
| 14 | 14 | // :1:13: note: struct declared here |
test/cases/compile_errors/function_with_non-extern_non-packed_union_parameter.zig+1-1| ... | ... | @@ -10,5 +10,5 @@ export fn entry(foo: Foo) void { _ = foo; } |
| 10 | 10 | // target=native |
| 11 | 11 | // |
| 12 | 12 | // :6:17: error: parameter of type 'tmp.Foo' not allowed in function with calling convention 'C' |
| 13 | // :6:17: note: only unions with packed or extern layout are extern compatible | |
| 13 | // :6:17: note: only extern unions and ABI sized packed unions are extern compatible | |
| 14 | 14 | // :1:13: note: union declared here |
test/cases/compile_errors/int_literal_passed_as_variadic_arg.zig deleted-11| ... | ... | @@ -1,11 +0,0 @@ |
| 1 | extern fn printf([*:0]const u8, ...) c_int; | |
| 2 | ||
| 3 | pub export fn entry() void { | |
| 4 | _ = printf("%d %d %d %d\n", 1, 2, 3, 4); | |
| 5 | } | |
| 6 | ||
| 7 | // error | |
| 8 | // backend=stage2 | |
| 9 | // target=native | |
| 10 | // | |
| 11 | // :4:33: error: integer and float literals in var args function must be casted |
test/cases/compile_errors/noalias_param_coersion.zig created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | pub export fn entry() void { | |
| 2 | comptime var x: fn (noalias *i32, noalias *i32) void = undefined; | |
| 3 | x = bar; | |
| 4 | } | |
| 5 | pub export fn entry1() void { | |
| 6 | comptime var x: fn (*i32, *i32) void = undefined; | |
| 7 | x = foo; | |
| 8 | } | |
| 9 | ||
| 10 | fn foo(noalias _: *i32, noalias _: *i32) void {} | |
| 11 | fn bar(noalias _: *i32, _: *i32) void {} | |
| 12 | ||
| 13 | // error | |
| 14 | // backend=stage2 | |
| 15 | // target=native | |
| 16 | // | |
| 17 | // :3:9: error: expected type 'fn(noalias *i32, noalias *i32) void', found 'fn(noalias *i32, *i32) void' | |
| 18 | // :3:9: note: regular parameter 1 cannot cast into a noalias parameter | |
| 19 | // :7:9: error: expected type 'fn(*i32, *i32) void', found 'fn(noalias *i32, noalias *i32) void' | |
| 20 | // :7:9: note: noalias parameter 0 cannot cast into a regular parameter |
test/cases/compile_errors/overflow_in_enum_value_allocation.zig created+14| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | const Moo = enum(u8) { | |
| 2 | Last = 255, | |
| 3 | Over, | |
| 4 | }; | |
| 5 | pub export fn entry() void { | |
| 6 | var y = Moo.Last; | |
| 7 | _ = y; | |
| 8 | } | |
| 9 | ||
| 10 | // error | |
| 11 | // backend=stage2 | |
| 12 | // target=native | |
| 13 | // | |
| 14 | // :3:5: error: enumeration value '256' too large for type 'u8' |
test/cases/compile_errors/specify_enum_tag_type_that_is_too_small.zig created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | const Small = enum (u2) { | |
| 2 | One, | |
| 3 | Two, | |
| 4 | Three, | |
| 5 | Four, | |
| 6 | Five, | |
| 7 | }; | |
| 8 | ||
| 9 | export fn entry() void { | |
| 10 | var x = Small.One; | |
| 11 | _ = x; | |
| 12 | } | |
| 13 | ||
| 14 | // error | |
| 15 | // backend=stage2 | |
| 16 | // target=native | |
| 17 | // | |
| 18 | // :6:5: error: enumeration value '4' too large for type 'u2' |
test/cases/compile_errors/stage1/obj/overflow_in_enum_value_allocation.zig deleted-14| ... | ... | @@ -1,14 +0,0 @@ |
| 1 | const Moo = enum(u8) { | |
| 2 | Last = 255, | |
| 3 | Over, | |
| 4 | }; | |
| 5 | pub fn main() void { | |
| 6 | var y = Moo.Last; | |
| 7 | _ = y; | |
| 8 | } | |
| 9 | ||
| 10 | // error | |
| 11 | // backend=stage1 | |
| 12 | // target=native | |
| 13 | // | |
| 14 | // tmp.zig:3:5: error: enumeration value 256 too large for type 'u8' |
test/cases/compile_errors/stage1/obj/specify_enum_tag_type_that_is_too_small.zig deleted-18| ... | ... | @@ -1,18 +0,0 @@ |
| 1 | const Small = enum (u2) { | |
| 2 | One, | |
| 3 | Two, | |
| 4 | Three, | |
| 5 | Four, | |
| 6 | Five, | |
| 7 | }; | |
| 8 | ||
| 9 | export fn entry() void { | |
| 10 | var x = Small.One; | |
| 11 | _ = x; | |
| 12 | } | |
| 13 | ||
| 14 | // error | |
| 15 | // backend=stage1 | |
| 16 | // target=native | |
| 17 | // | |
| 18 | // tmp.zig:6:5: error: enumeration value 4 too large for type 'u2' |
test/cases/compile_errors/try_return.zig created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | pub fn foo() !void { | |
| 2 | try return bar(); | |
| 3 | } | |
| 4 | pub fn bar() !void {} | |
| 5 | ||
| 6 | // error | |
| 7 | // backend=stage2 | |
| 8 | // target=native | |
| 9 | // | |
| 10 | // :2:5: error: unreachable code | |
| 11 | // :2:9: note: control flow is diverted here |
test/cases/compile_errors/variadic_arg_validation.zig created+29| ... | ... | @@ -0,0 +1,29 @@ |
| 1 | extern fn printf([*:0]const u8, ...) c_int; | |
| 2 | ||
| 3 | pub export fn entry() void { | |
| 4 | _ = printf("%d %d %d %d\n", 1, 2, 3, 4); | |
| 5 | } | |
| 6 | ||
| 7 | pub export fn entry1() void { | |
| 8 | var arr: [2]u8 = undefined; | |
| 9 | _ = printf("%d\n", arr); | |
| 10 | } | |
| 11 | ||
| 12 | pub export fn entry2() void { | |
| 13 | _ = printf("%d\n", @as(u48, 2)); | |
| 14 | } | |
| 15 | ||
| 16 | pub export fn entry3() void { | |
| 17 | _ = printf("%d\n", {}); | |
| 18 | } | |
| 19 | ||
| 20 | // error | |
| 21 | // backend=stage2 | |
| 22 | // target=native | |
| 23 | // | |
| 24 | // :4:33: error: integer and float literals passed variadic function must be casted to a fixed-size number type | |
| 25 | // :9:24: error: arrays must be passed by reference to variadic function | |
| 26 | // :13:24: error: cannot pass 'u48' to variadic function | |
| 27 | // :13:24: note: only integers with power of two bits are extern compatible | |
| 28 | // :17:24: error: cannot pass 'void' to variadic function | |
| 29 | // :17:24: note: 'void' is a zero bit type; for C 'void' use 'anyopaque' |
test/run_translated_c.zig+14-12| ... | ... | @@ -250,18 +250,20 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { |
| 250 | 250 | \\} |
| 251 | 251 | , ""); |
| 252 | 252 | |
| 253 | cases.add("struct initializer - packed", | |
| 254 | \\#define _NO_CRT_STDIO_INLINE 1 | |
| 255 | \\#include <stdint.h> | |
| 256 | \\#include <stdlib.h> | |
| 257 | \\struct s {uint8_t x,y; | |
| 258 | \\ uint32_t z;} __attribute__((packed)) s0 = {1, 2}; | |
| 259 | \\int main() { | |
| 260 | \\ /* sizeof nor offsetof currently supported */ | |
| 261 | \\ if (((intptr_t)&s0.z - (intptr_t)&s0.x) != 2) abort(); | |
| 262 | \\ return 0; | |
| 263 | \\} | |
| 264 | , ""); | |
| 253 | if (@import("builtin").zig_backend == .stage1) { | |
| 254 | cases.add("struct initializer - packed", | |
| 255 | \\#define _NO_CRT_STDIO_INLINE 1 | |
| 256 | \\#include <stdint.h> | |
| 257 | \\#include <stdlib.h> | |
| 258 | \\struct s {uint8_t x,y; | |
| 259 | \\ uint32_t z;} __attribute__((packed)) s0 = {1, 2}; | |
| 260 | \\int main() { | |
| 261 | \\ /* sizeof nor offsetof currently supported */ | |
| 262 | \\ if (((intptr_t)&s0.z - (intptr_t)&s0.x) != 2) abort(); | |
| 263 | \\ return 0; | |
| 264 | \\} | |
| 265 | , ""); | |
| 266 | } | |
| 265 | 267 | |
| 266 | 268 | cases.add("cast signed array index to unsigned", |
| 267 | 269 | \\#include <stdlib.h> |
test/standalone.zig+3| ... | ... | @@ -13,6 +13,8 @@ pub fn addCases(cases: *tests.StandaloneContext) void { |
| 13 | 13 | cases.add("test/standalone/guess_number/main.zig"); |
| 14 | 14 | cases.add("test/standalone/main_return_error/error_u8.zig"); |
| 15 | 15 | cases.add("test/standalone/main_return_error/error_u8_non_zero.zig"); |
| 16 | cases.add("test/standalone/noreturn_call/inline.zig"); | |
| 17 | cases.add("test/standalone/noreturn_call/as_arg.zig"); | |
| 16 | 18 | cases.addBuildFile("test/standalone/main_pkg_path/build.zig", .{}); |
| 17 | 19 | cases.addBuildFile("test/standalone/shared_library/build.zig", .{}); |
| 18 | 20 | cases.addBuildFile("test/standalone/mix_o_files/build.zig", .{}); |
| ... | ... | @@ -66,6 +68,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void { |
| 66 | 68 | if (builtin.os.tag == .linux) { |
| 67 | 69 | cases.addBuildFile("test/standalone/pie/build.zig", .{}); |
| 68 | 70 | } |
| 71 | cases.addBuildFile("test/standalone/issue_12706/build.zig", .{}); | |
| 69 | 72 | |
| 70 | 73 | // Ensure the development tools are buildable. |
| 71 | 74 |
test/standalone/issue_12706/build.zig created+39| ... | ... | @@ -0,0 +1,39 @@ |
| 1 | const std = @import("std"); | |
| 2 | const builtin = @import("builtin"); | |
| 3 | const Builder = std.build.Builder; | |
| 4 | const CrossTarget = std.zig.CrossTarget; | |
| 5 | ||
| 6 | // TODO integrate this with the std.build executor API | |
| 7 | fn isRunnableTarget(t: CrossTarget) bool { | |
| 8 | if (t.isNative()) return true; | |
| 9 | ||
| 10 | return (t.getOsTag() == builtin.os.tag and | |
| 11 | t.getCpuArch() == builtin.cpu.arch); | |
| 12 | } | |
| 13 | ||
| 14 | pub fn build(b: *Builder) void { | |
| 15 | const mode = b.standardReleaseOptions(); | |
| 16 | const target = b.standardTargetOptions(.{}); | |
| 17 | ||
| 18 | const exe = b.addExecutable("main", "main.zig"); | |
| 19 | exe.setBuildMode(mode); | |
| 20 | exe.install(); | |
| 21 | ||
| 22 | const c_sources = [_][]const u8{ | |
| 23 | "test.c", | |
| 24 | }; | |
| 25 | ||
| 26 | exe.addCSourceFiles(&c_sources, &.{}); | |
| 27 | exe.linkLibC(); | |
| 28 | ||
| 29 | exe.setTarget(target); | |
| 30 | b.default_step.dependOn(&exe.step); | |
| 31 | ||
| 32 | const test_step = b.step("test", "Test the program"); | |
| 33 | if (isRunnableTarget(target)) { | |
| 34 | const run_cmd = exe.run(); | |
| 35 | test_step.dependOn(&run_cmd.step); | |
| 36 | } else { | |
| 37 | test_step.dependOn(&exe.step); | |
| 38 | } | |
| 39 | } |
test/standalone/issue_12706/main.zig created+12| ... | ... | @@ -0,0 +1,12 @@ |
| 1 | const std = @import("std"); | |
| 2 | extern fn testFnPtr(n: c_int, ...) void; | |
| 3 | ||
| 4 | const val: c_int = 123; | |
| 5 | ||
| 6 | fn func(a: c_int) callconv(.C) void { | |
| 7 | std.debug.assert(a == val); | |
| 8 | } | |
| 9 | ||
| 10 | pub fn main() void { | |
| 11 | testFnPtr(2, func, val); | |
| 12 | } |
test/standalone/issue_12706/test.c created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | #include <stdarg.h> | |
| 2 | ||
| 3 | void testFnPtr(int n, ...) { | |
| 4 | va_list ap; | |
| 5 | va_start(ap, n); | |
| 6 | ||
| 7 | void (*fnPtr)(int) = va_arg(ap, void (*)(int)); | |
| 8 | int arg = va_arg(ap, int); | |
| 9 | fnPtr(arg); | |
| 10 | va_end(ap); | |
| 11 | } | |
| \ No newline at end of file |
test/standalone/noreturn_call/as_arg.zig created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | const std = @import("std"); | |
| 2 | fn foo() noreturn { | |
| 3 | std.process.exit(0); | |
| 4 | } | |
| 5 | fn bar(_: u8, _: u8) void {} | |
| 6 | pub fn main() void { | |
| 7 | bar(foo(), @compileError("bad")); | |
| 8 | } |
test/standalone/noreturn_call/inline.zig created+10| ... | ... | @@ -0,0 +1,10 @@ |
| 1 | pub fn main() void { | |
| 2 | _ = bar(); | |
| 3 | } | |
| 4 | inline fn bar() u8 { | |
| 5 | noret(); | |
| 6 | } | |
| 7 | const std = @import("std"); | |
| 8 | inline fn noret() noreturn { | |
| 9 | std.process.exit(0); | |
| 10 | } |
test/translate_c.zig+16-14| ... | ... | @@ -728,20 +728,22 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 728 | 728 | \\} |
| 729 | 729 | }); |
| 730 | 730 | |
| 731 | cases.add("struct initializer - packed", | |
| 732 | \\struct {int x,y,z;} __attribute__((packed)) s0 = {1, 2}; | |
| 733 | , &[_][]const u8{ | |
| 734 | \\const struct_unnamed_1 = packed struct { | |
| 735 | \\ x: c_int, | |
| 736 | \\ y: c_int, | |
| 737 | \\ z: c_int, | |
| 738 | \\}; | |
| 739 | \\pub export var s0: struct_unnamed_1 = struct_unnamed_1{ | |
| 740 | \\ .x = @as(c_int, 1), | |
| 741 | \\ .y = @as(c_int, 2), | |
| 742 | \\ .z = 0, | |
| 743 | \\}; | |
| 744 | }); | |
| 731 | if (builtin.zig_backend == .stage1) { | |
| 732 | cases.add("struct initializer - packed", | |
| 733 | \\struct {int x,y,z;} __attribute__((packed)) s0 = {1, 2}; | |
| 734 | , &[_][]const u8{ | |
| 735 | \\const struct_unnamed_1 = packed struct { | |
| 736 | \\ x: c_int, | |
| 737 | \\ y: c_int, | |
| 738 | \\ z: c_int, | |
| 739 | \\}; | |
| 740 | \\pub export var s0: struct_unnamed_1 = struct_unnamed_1{ | |
| 741 | \\ .x = @as(c_int, 1), | |
| 742 | \\ .y = @as(c_int, 2), | |
| 743 | \\ .z = 0, | |
| 744 | \\}; | |
| 745 | }); | |
| 746 | } | |
| 745 | 747 | |
| 746 | 748 | // Test case temporarily disabled: |
| 747 | 749 | // https://github.com/ziglang/zig/issues/12055 |