| author | |
| committer | |
| log | b83c037f9ffd7a4285de41c95827615fcbdbbf2f |
| tree | 25b6f3ce249c9b77603a47647fc9d658980da08a |
| parent | 6aee07c1446f3ce98d326998c887fbca3b7fd945 |
9 files changed, 116 insertions(+), 125 deletions(-)
src/Sema.zig+31-16| ... | @@ -5056,7 +5056,7 @@ pub fn analyzeExport( | ... | @@ -5056,7 +5056,7 @@ pub fn analyzeExport( |
| 5056 | try mod.ensureDeclAnalyzed(exported_decl_index); | 5056 | try mod.ensureDeclAnalyzed(exported_decl_index); |
| 5057 | const exported_decl = mod.declPtr(exported_decl_index); | 5057 | const exported_decl = mod.declPtr(exported_decl_index); |
| 5058 | 5058 | ||
| 5059 | if (!sema.validateExternType(exported_decl.ty, .other)) { | 5059 | if (!try sema.validateExternType(block, src, exported_decl.ty, .other)) { |
| 5060 | const msg = msg: { | 5060 | const msg = msg: { |
| 5061 | const msg = try sema.errMsg(block, src, "unable to export type '{}'", .{exported_decl.ty.fmt(sema.mod)}); | 5061 | const msg = try sema.errMsg(block, src, "unable to export type '{}'", .{exported_decl.ty.fmt(sema.mod)}); |
| 5062 | errdefer msg.destroy(sema.gpa); | 5062 | errdefer msg.destroy(sema.gpa); |
| ... | @@ -7896,7 +7896,7 @@ fn funcCommon( | ... | @@ -7896,7 +7896,7 @@ fn funcCommon( |
| 7896 | }; | 7896 | }; |
| 7897 | return sema.failWithOwnedErrorMsg(msg); | 7897 | return sema.failWithOwnedErrorMsg(msg); |
| 7898 | } | 7898 | } |
| 7899 | 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)) { |
| 7900 | const msg = msg: { | 7900 | const msg = msg: { |
| 7901 | const msg = try sema.errMsg(block, ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{ | 7901 | const msg = try sema.errMsg(block, ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{ |
| 7902 | return_type.fmt(sema.mod), @tagName(cc_workaround), | 7902 | return_type.fmt(sema.mod), @tagName(cc_workaround), |
| ... | @@ -8115,7 +8115,7 @@ fn analyzeParameter( | ... | @@ -8115,7 +8115,7 @@ fn analyzeParameter( |
| 8115 | }; | 8115 | }; |
| 8116 | return sema.failWithOwnedErrorMsg(msg); | 8116 | return sema.failWithOwnedErrorMsg(msg); |
| 8117 | } | 8117 | } |
| 8118 | 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)) { |
| 8119 | const msg = msg: { | 8119 | const msg = msg: { |
| 8120 | const msg = try sema.errMsg(block, param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{ | 8120 | const msg = try sema.errMsg(block, param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{ |
| 8121 | param.ty.fmt(sema.mod), @tagName(cc), | 8121 | param.ty.fmt(sema.mod), @tagName(cc), |
| ... | @@ -15583,7 +15583,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -15583,7 +15583,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 15583 | } else if (inst_data.size == .Many and elem_ty.zigTypeTag() == .Opaque) { | 15583 | } else if (inst_data.size == .Many and elem_ty.zigTypeTag() == .Opaque) { |
| 15584 | return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{}); | 15584 | return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{}); |
| 15585 | } else if (inst_data.size == .C) { | 15585 | } else if (inst_data.size == .C) { |
| 15586 | if (!sema.validateExternType(elem_ty, .other)) { | 15586 | if (!try sema.validateExternType(block, elem_ty_src, elem_ty, .other)) { |
| 15587 | const msg = msg: { | 15587 | const msg = msg: { |
| 15588 | const msg = try sema.errMsg(block, elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)}); | 15588 | const msg = try sema.errMsg(block, elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)}); |
| 15589 | errdefer msg.destroy(sema.gpa); | 15589 | errdefer msg.destroy(sema.gpa); |
| ... | @@ -16681,7 +16681,7 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in | ... | @@ -16681,7 +16681,7 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in |
| 16681 | } else if (ptr_size == .Many and elem_ty.zigTypeTag() == .Opaque) { | 16681 | } else if (ptr_size == .Many and elem_ty.zigTypeTag() == .Opaque) { |
| 16682 | return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{}); | 16682 | return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{}); |
| 16683 | } else if (ptr_size == .C) { | 16683 | } else if (ptr_size == .C) { |
| 16684 | if (!sema.validateExternType(elem_ty, .other)) { | 16684 | if (!try sema.validateExternType(block, src, elem_ty, .other)) { |
| 16685 | const msg = msg: { | 16685 | const msg = msg: { |
| 16686 | const msg = try sema.errMsg(block, src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)}); | 16686 | const msg = try sema.errMsg(block, src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)}); |
| 16687 | errdefer msg.destroy(sema.gpa); | 16687 | errdefer msg.destroy(sema.gpa); |
| ... | @@ -20549,7 +20549,14 @@ const ExternPosition = enum { | ... | @@ -20549,7 +20549,14 @@ const ExternPosition = enum { |
| 20549 | 20549 | ||
| 20550 | /// Returns true if `ty` is allowed in extern types. | 20550 | /// Returns true if `ty` is allowed in extern types. |
| 20551 | /// Does *NOT* require `ty` to be resolved in any way. | 20551 | /// Does *NOT* require `ty` to be resolved in any way. |
| 20552 | fn validateExternType(sema: *Sema, ty: Type, position: ExternPosition) bool { | 20552 | /// Calls `resolveTypeLayout` for packed containers. |
| 20553 | fn validateExternType( | ||
| 20554 | sema: *Sema, | ||
| 20555 | block: *Block, | ||
| 20556 | src: LazySrcLoc, | ||
| 20557 | ty: Type, | ||
| 20558 | position: ExternPosition, | ||
| 20559 | ) !bool { | ||
| 20553 | switch (ty.zigTypeTag()) { | 20560 | switch (ty.zigTypeTag()) { |
| 20554 | .Type, | 20561 | .Type, |
| 20555 | .ComptimeFloat, | 20562 | .ComptimeFloat, |
| ... | @@ -20577,17 +20584,25 @@ fn validateExternType(sema: *Sema, ty: Type, position: ExternPosition) bool { | ... | @@ -20577,17 +20584,25 @@ fn validateExternType(sema: *Sema, ty: Type, position: ExternPosition) bool { |
| 20577 | .Fn => return !Type.fnCallingConventionAllowsZigTypes(ty.fnCallingConvention()), | 20584 | .Fn => return !Type.fnCallingConventionAllowsZigTypes(ty.fnCallingConvention()), |
| 20578 | .Enum => { | 20585 | .Enum => { |
| 20579 | var buf: Type.Payload.Bits = undefined; | 20586 | var buf: Type.Payload.Bits = undefined; |
| 20580 | return sema.validateExternType(ty.intTagType(&buf), position); | 20587 | return sema.validateExternType(block, src, ty.intTagType(&buf), position); |
| 20581 | }, | 20588 | }, |
| 20582 | .Struct, .Union => switch (ty.containerLayout()) { | 20589 | .Struct, .Union => switch (ty.containerLayout()) { |
| 20583 | .Extern, .Packed => return true, | 20590 | .Extern => return true, |
| 20584 | else => return false, | 20591 | .Packed => { |
| 20592 | const target = sema.mod.getTarget(); | ||
| 20593 | const bit_size = try ty.bitSizeAdvanced(target, sema.kit(block, src)); | ||
| 20594 | switch (bit_size) { | ||
| 20595 | 8, 16, 32, 64, 128 => return true, | ||
| 20596 | else => return false, | ||
| 20597 | } | ||
| 20598 | }, | ||
| 20599 | .Auto => return false, | ||
| 20585 | }, | 20600 | }, |
| 20586 | .Array => { | 20601 | .Array => { |
| 20587 | if (position == .ret_ty or position == .param_ty) return false; | 20602 | if (position == .ret_ty or position == .param_ty) return false; |
| 20588 | return sema.validateExternType(ty.elemType2(), .other); | 20603 | return sema.validateExternType(block, src, ty.elemType2(), .other); |
| 20589 | }, | 20604 | }, |
| 20590 | .Vector => return sema.validateExternType(ty.elemType2(), .other), | 20605 | .Vector => return sema.validateExternType(block, src, ty.elemType2(), .other), |
| 20591 | .Optional => return ty.isPtrLikeOptional(), | 20606 | .Optional => return ty.isPtrLikeOptional(), |
| 20592 | } | 20607 | } |
| 20593 | } | 20608 | } |
| ... | @@ -20639,8 +20654,8 @@ fn explainWhyTypeIsNotExtern( | ... | @@ -20639,8 +20654,8 @@ fn explainWhyTypeIsNotExtern( |
| 20639 | try mod.errNoteNonLazy(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(sema.mod)}); | 20654 | try mod.errNoteNonLazy(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(sema.mod)}); |
| 20640 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position); | 20655 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position); |
| 20641 | }, | 20656 | }, |
| 20642 | .Struct => try mod.errNoteNonLazy(src_loc, msg, "only structs with packed or extern layout are extern compatible", .{}), | 20657 | .Struct => try mod.errNoteNonLazy(src_loc, msg, "only extern structs and ABI sized packed structs are extern compatible", .{}), |
| 20643 | .Union => try mod.errNoteNonLazy(src_loc, msg, "only unions with packed or extern layout are extern compatible", .{}), | 20658 | .Union => try mod.errNoteNonLazy(src_loc, msg, "only extern unions and ABI sized packed unions are extern compatible", .{}), |
| 20644 | .Array => { | 20659 | .Array => { |
| 20645 | if (position == .ret_ty) { | 20660 | if (position == .ret_ty) { |
| 20646 | return mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a return type", .{}); | 20661 | return mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a return type", .{}); |
| ... | @@ -24119,7 +24134,7 @@ fn coerceVarArgParam( | ... | @@ -24119,7 +24134,7 @@ fn coerceVarArgParam( |
| 24119 | }; | 24134 | }; |
| 24120 | 24135 | ||
| 24121 | const coerced_ty = sema.typeOf(coerced); | 24136 | const coerced_ty = sema.typeOf(coerced); |
| 24122 | if (!sema.validateExternType(coerced_ty, .other)) { | 24137 | if (!try sema.validateExternType(block, inst_src, coerced_ty, .other)) { |
| 24123 | const msg = msg: { | 24138 | const msg = msg: { |
| 24124 | const msg = try sema.errMsg(block, inst_src, "cannot pass '{}' to variadic function", .{coerced_ty.fmt(sema.mod)}); | 24139 | const msg = try sema.errMsg(block, inst_src, "cannot pass '{}' to variadic function", .{coerced_ty.fmt(sema.mod)}); |
| 24125 | errdefer msg.destroy(sema.gpa); | 24140 | errdefer msg.destroy(sema.gpa); |
| ... | @@ -28321,7 +28336,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -28321,7 +28336,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 28321 | }; | 28336 | }; |
| 28322 | return sema.failWithOwnedErrorMsg(msg); | 28337 | return sema.failWithOwnedErrorMsg(msg); |
| 28323 | } | 28338 | } |
| 28324 | if (struct_obj.layout == .Extern and !sema.validateExternType(field.ty, .other)) { | 28339 | if (struct_obj.layout == .Extern and !try sema.validateExternType(&block_scope, src, field.ty, .other)) { |
| 28325 | const msg = msg: { | 28340 | const msg = msg: { |
| 28326 | const tree = try sema.getAstTree(&block_scope); | 28341 | const tree = try sema.getAstTree(&block_scope); |
| 28327 | const fields_src = enumFieldSrcLoc(decl, tree.*, 0, i); | 28342 | const fields_src = enumFieldSrcLoc(decl, tree.*, 0, i); |
| ... | @@ -28658,7 +28673,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -28658,7 +28673,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 28658 | }; | 28673 | }; |
| 28659 | return sema.failWithOwnedErrorMsg(msg); | 28674 | return sema.failWithOwnedErrorMsg(msg); |
| 28660 | } | 28675 | } |
| 28661 | if (union_obj.layout == .Extern and !sema.validateExternType(field_ty, .union_field)) { | 28676 | if (union_obj.layout == .Extern and !try sema.validateExternType(&block_scope, src, field_ty, .union_field)) { |
| 28662 | const msg = msg: { | 28677 | const msg = msg: { |
| 28663 | const tree = try sema.getAstTree(&block_scope); | 28678 | const tree = try sema.getAstTree(&block_scope); |
| 28664 | const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); | 28679 | const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); |
src/arch/wasm/abi.zig+8| ... | @@ -23,6 +23,10 @@ pub fn classifyType(ty: Type, target: Target) [2]Class { | ... | @@ -23,6 +23,10 @@ pub fn classifyType(ty: Type, target: Target) [2]Class { |
| 23 | if (!ty.hasRuntimeBitsIgnoreComptime()) return none; | 23 | if (!ty.hasRuntimeBitsIgnoreComptime()) return none; |
| 24 | switch (ty.zigTypeTag()) { | 24 | switch (ty.zigTypeTag()) { |
| 25 | .Struct => { | 25 | .Struct => { |
| 26 | if (ty.containerLayout() == .Packed) { | ||
| 27 | if (ty.bitSize(target) <= 64) return direct; | ||
| 28 | return .{ .direct, .direct }; | ||
| 29 | } | ||
| 26 | // When the struct type is non-scalar | 30 | // When the struct type is non-scalar |
| 27 | if (ty.structFieldCount() > 1) return memory; | 31 | if (ty.structFieldCount() > 1) return memory; |
| 28 | // When the struct's alignment is non-natural | 32 | // When the struct's alignment is non-natural |
| ... | @@ -57,6 +61,10 @@ pub fn classifyType(ty: Type, target: Target) [2]Class { | ... | @@ -57,6 +61,10 @@ pub fn classifyType(ty: Type, target: Target) [2]Class { |
| 57 | return direct; | 61 | return direct; |
| 58 | }, | 62 | }, |
| 59 | .Union => { | 63 | .Union => { |
| 64 | if (ty.containerLayout() == .Packed) { | ||
| 65 | if (ty.bitSize(target) <= 64) return direct; | ||
| 66 | return .{ .direct, .direct }; | ||
| 67 | } | ||
| 60 | const layout = ty.unionGetLayout(target); | 68 | const layout = ty.unionGetLayout(target); |
| 61 | std.debug.assert(layout.tag_size == 0); | 69 | std.debug.assert(layout.tag_size == 0); |
| 62 | if (ty.unionFields().count() > 1) return memory; | 70 | if (ty.unionFields().count() > 1) return memory; |
src/arch/x86_64/abi.zig+12| ... | @@ -174,6 +174,12 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class { | ... | @@ -174,6 +174,12 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class { |
| 174 | // "If the size of the aggregate exceeds a single eightbyte, each is classified | 174 | // "If the size of the aggregate exceeds a single eightbyte, each is classified |
| 175 | // separately.". | 175 | // separately.". |
| 176 | const ty_size = ty.abiSize(target); | 176 | const ty_size = ty.abiSize(target); |
| 177 | if (ty.containerLayout() == .Packed) { | ||
| 178 | assert(ty_size <= 128); | ||
| 179 | result[0] = .integer; | ||
| 180 | if (ty_size > 64) result[1] = .integer; | ||
| 181 | return result; | ||
| 182 | } | ||
| 177 | if (ty_size > 64) | 183 | if (ty_size > 64) |
| 178 | return memory_class; | 184 | return memory_class; |
| 179 | 185 | ||
| ... | @@ -284,6 +290,12 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class { | ... | @@ -284,6 +290,12 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class { |
| 284 | // "If the size of the aggregate exceeds a single eightbyte, each is classified | 290 | // "If the size of the aggregate exceeds a single eightbyte, each is classified |
| 285 | // separately.". | 291 | // separately.". |
| 286 | const ty_size = ty.abiSize(target); | 292 | const ty_size = ty.abiSize(target); |
| 293 | if (ty.containerLayout() == .Packed) { | ||
| 294 | assert(ty_size <= 128); | ||
| 295 | result[0] = .integer; | ||
| 296 | if (ty_size > 64) result[1] = .integer; | ||
| 297 | return result; | ||
| 298 | } | ||
| 287 | if (ty_size > 64) | 299 | if (ty_size > 64) |
| 288 | return memory_class; | 300 | return memory_class; |
| 289 | 301 |
src/codegen/llvm.zig+23-34| ... | @@ -9674,22 +9674,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm. | ... | @@ -9674,22 +9674,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm. |
| 9674 | } | 9674 | } |
| 9675 | }, | 9675 | }, |
| 9676 | .C => { | 9676 | .C => { |
| 9677 | const is_scalar = switch (fn_info.return_type.zigTypeTag()) { | 9677 | const is_scalar = isScalar(fn_info.return_type); |
| 9678 | .Void, | ||
| 9679 | .Bool, | ||
| 9680 | .NoReturn, | ||
| 9681 | .Int, | ||
| 9682 | .Float, | ||
| 9683 | .Pointer, | ||
| 9684 | .Optional, | ||
| 9685 | .ErrorSet, | ||
| 9686 | .Enum, | ||
| 9687 | .AnyFrame, | ||
| 9688 | .Vector, | ||
| 9689 | => true, | ||
| 9690 | |||
| 9691 | else => false, | ||
| 9692 | }; | ||
| 9693 | switch (target.cpu.arch) { | 9678 | switch (target.cpu.arch) { |
| 9694 | .mips, .mipsel => return dg.lowerType(fn_info.return_type), | 9679 | .mips, .mipsel => return dg.lowerType(fn_info.return_type), |
| 9695 | .x86_64 => switch (target.os.tag) { | 9680 | .x86_64 => switch (target.os.tag) { |
| ... | @@ -9837,24 +9822,7 @@ const ParamTypeIterator = struct { | ... | @@ -9837,24 +9822,7 @@ const ParamTypeIterator = struct { |
| 9837 | @panic("TODO implement async function lowering in the LLVM backend"); | 9822 | @panic("TODO implement async function lowering in the LLVM backend"); |
| 9838 | }, | 9823 | }, |
| 9839 | .C => { | 9824 | .C => { |
| 9840 | const is_scalar = switch (ty.zigTypeTag()) { | 9825 | const is_scalar = isScalar(ty); |
| 9841 | .Void, | ||
| 9842 | .Bool, | ||
| 9843 | .NoReturn, | ||
| 9844 | .Int, | ||
| 9845 | .Float, | ||
| 9846 | .Pointer, | ||
| 9847 | .Optional, | ||
| 9848 | .ErrorSet, | ||
| 9849 | .Enum, | ||
| 9850 | .AnyFrame, | ||
| 9851 | .Vector, | ||
| 9852 | => true, | ||
| 9853 | .Struct => ty.containerLayout() == .Packed, | ||
| 9854 | .Union => ty.containerLayout() == .Packed, | ||
| 9855 | |||
| 9856 | else => false, | ||
| 9857 | }; | ||
| 9858 | switch (it.target.cpu.arch) { | 9826 | switch (it.target.cpu.arch) { |
| 9859 | .riscv32, .riscv64 => { | 9827 | .riscv32, .riscv64 => { |
| 9860 | it.zig_index += 1; | 9828 | it.zig_index += 1; |
| ... | @@ -10108,6 +10076,27 @@ fn isByRef(ty: Type) bool { | ... | @@ -10108,6 +10076,27 @@ fn isByRef(ty: Type) bool { |
| 10108 | } | 10076 | } |
| 10109 | } | 10077 | } |
| 10110 | 10078 | ||
| 10079 | fn isScalar(ty: Type) bool { | ||
| 10080 | return switch (ty.zigTypeTag()) { | ||
| 10081 | .Void, | ||
| 10082 | .Bool, | ||
| 10083 | .NoReturn, | ||
| 10084 | .Int, | ||
| 10085 | .Float, | ||
| 10086 | .Pointer, | ||
| 10087 | .Optional, | ||
| 10088 | .ErrorSet, | ||
| 10089 | .Enum, | ||
| 10090 | .AnyFrame, | ||
| 10091 | .Vector, | ||
| 10092 | => true, | ||
| 10093 | |||
| 10094 | .Struct => ty.containerLayout() == .Packed, | ||
| 10095 | .Union => ty.containerLayout() == .Packed, | ||
| 10096 | else => false, | ||
| 10097 | }; | ||
| 10098 | } | ||
| 10099 | |||
| 10111 | /// This function returns true if we expect LLVM to lower x86_fp80 correctly | 10100 | /// This function returns true if we expect LLVM to lower x86_fp80 correctly |
| 10112 | /// and false if we expect LLVM to crash if it counters an x86_fp80 type. | 10101 | /// and false if we expect LLVM to crash if it counters an x86_fp80 type. |
| 10113 | fn backendSupportsF80(target: std.Target) bool { | 10102 | fn backendSupportsF80(target: std.Target) bool { |
test/c_abi/cfuncs.c+29-49| ... | @@ -86,24 +86,8 @@ struct MedStructMixed { | ... | @@ -86,24 +86,8 @@ struct MedStructMixed { |
| 86 | void zig_med_struct_mixed(struct MedStructMixed); | 86 | void zig_med_struct_mixed(struct MedStructMixed); |
| 87 | struct MedStructMixed zig_ret_med_struct_mixed(); | 87 | struct MedStructMixed zig_ret_med_struct_mixed(); |
| 88 | 88 | ||
| 89 | struct SmallPackedStruct { | 89 | void zig_small_packed_struct(uint8_t); |
| 90 | uint8_t a: 2; | 90 | void zig_big_packed_struct(__int128); |
| 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); | ||
| 107 | 91 | ||
| 108 | struct SplitStructInts { | 92 | struct SplitStructInts { |
| 109 | uint64_t a; | 93 | uint64_t a; |
| ... | @@ -176,13 +160,19 @@ void run_c_tests(void) { | ... | @@ -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 | zig_big_packed_struct(s); | 166 | zig_big_packed_struct(s); |
| 181 | } | 167 | } |
| 182 | 168 | ||
| 183 | { | 169 | { |
| 184 | struct SmallPackedStruct s = {0, 1, 2, 3, 1}; | 170 | uint8_t s = 0; |
| 185 | //zig_small_packed_struct(s); | 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,42 +368,32 @@ void c_split_struct_mixed(struct SplitStructMixed x) { |
| 378 | assert_or_panic(y.c == 1337.0f); | 368 | assert_or_panic(y.c == 1337.0f); |
| 379 | } | 369 | } |
| 380 | 370 | ||
| 381 | struct SmallPackedStruct c_ret_small_packed_struct() { | 371 | uint8_t c_ret_small_packed_struct() { |
| 382 | struct SmallPackedStruct s = { | 372 | uint8_t s = 0; |
| 383 | .a = 0, | 373 | s |= 0 << 0; |
| 384 | .b = 1, | 374 | s |= 1 << 2; |
| 385 | .c = 2, | 375 | s |= 2 << 4; |
| 386 | .d = 3, | 376 | s |= 3 << 6; |
| 387 | .e = 1, | ||
| 388 | }; | ||
| 389 | return s; | 377 | return s; |
| 390 | } | 378 | } |
| 391 | 379 | ||
| 392 | void c_small_packed_struct(struct SmallPackedStruct x) { | 380 | void c_small_packed_struct(uint8_t x) { |
| 393 | assert_or_panic(x.a == 0); | 381 | assert_or_panic(((x >> 0) & 0x3) == 0); |
| 394 | assert_or_panic(x.a == 1); | 382 | assert_or_panic(((x >> 2) & 0x3) == 1); |
| 395 | assert_or_panic(x.a == 2); | 383 | assert_or_panic(((x >> 4) & 0x3) == 2); |
| 396 | assert_or_panic(x.a == 3); | 384 | assert_or_panic(((x >> 6) & 0x3) == 3); |
| 397 | assert_or_panic(x.e == 1); | ||
| 398 | } | 385 | } |
| 399 | 386 | ||
| 400 | struct BigPackedStruct c_ret_big_packed_struct() { | 387 | __int128 c_ret_big_packed_struct() { |
| 401 | struct BigPackedStruct s = { | 388 | __int128 s = 0; |
| 402 | .a = 1, | 389 | s |= 1 << 0; |
| 403 | .b = 2, | 390 | s |= (__int128)2 << 64; |
| 404 | .c = 3, | ||
| 405 | .d = 4, | ||
| 406 | .e = 5, | ||
| 407 | }; | ||
| 408 | return s; | 391 | return s; |
| 409 | } | 392 | } |
| 410 | 393 | ||
| 411 | void c_big_packed_struct(struct BigPackedStruct x) { | 394 | void c_big_packed_struct(__int128 x) { |
| 412 | assert_or_panic(x.a == 1); | 395 | assert_or_panic(((x >> 0) & 0xFFFFFFFFFFFFFFFF) == 1); |
| 413 | assert_or_panic(x.b == 2); | 396 | assert_or_panic(((x >> 64) & 0xFFFFFFFFFFFFFFFF) == 2); |
| 414 | assert_or_panic(x.c == 3); | ||
| 415 | assert_or_panic(x.d == 4); | ||
| 416 | assert_or_panic(x.e == 5); | ||
| 417 | } | 397 | } |
| 418 | 398 | ||
| 419 | struct SplitStructMixed c_ret_split_struct_mixed() { | 399 | struct SplitStructMixed c_ret_split_struct_mixed() { |
test/c_abi/main.zig+10-23| ... | @@ -263,37 +263,30 @@ const SmallPackedStruct = packed struct { | ... | @@ -263,37 +263,30 @@ const SmallPackedStruct = packed struct { |
| 263 | b: u2, | 263 | b: u2, |
| 264 | c: u2, | 264 | c: u2, |
| 265 | d: u2, | 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 | extern fn c_ret_small_packed_struct() SmallPackedStruct; | 268 | extern fn c_ret_small_packed_struct() SmallPackedStruct; |
| 270 | 269 | ||
| 271 | // waiting on #1481 | 270 | export fn zig_small_packed_struct(x: SmallPackedStruct) void { |
| 272 | //export fn zig_small_packed_struct(x: SmallPackedStruct) void { | 271 | expect(x.a == 0) catch @panic("test failure"); |
| 273 | // expect(x.a == 0) catch @panic("test failure"); | 272 | expect(x.b == 1) catch @panic("test failure"); |
| 274 | // expect(x.b == 1) catch @panic("test failure"); | 273 | expect(x.c == 2) catch @panic("test failure"); |
| 275 | // expect(x.c == 2) catch @panic("test failure"); | 274 | expect(x.d == 3) catch @panic("test failure"); |
| 276 | // expect(x.d == 3) catch @panic("test failure"); | 275 | } |
| 277 | // expect(x.e) catch @panic("test failure"); | ||
| 278 | //} | ||
| 279 | 276 | ||
| 280 | test "C ABI small packed struct" { | 277 | test "C ABI small packed struct" { |
| 281 | var s = SmallPackedStruct{ .a = 0, .b = 1, .c = 2, .d = 3, .e = true }; | 278 | var s = SmallPackedStruct{ .a = 0, .b = 1, .c = 2, .d = 3 }; |
| 282 | _ = s; //c_small_packed_struct(s); // waiting on #1481 | 279 | c_small_packed_struct(s); |
| 283 | var s2 = c_ret_small_packed_struct(); | 280 | var s2 = c_ret_small_packed_struct(); |
| 284 | try expect(s2.a == 0); | 281 | try expect(s2.a == 0); |
| 285 | try expect(s2.b == 1); | 282 | try expect(s2.b == 1); |
| 286 | try expect(s2.c == 2); | 283 | try expect(s2.c == 2); |
| 287 | try expect(s2.d == 3); | 284 | try expect(s2.d == 3); |
| 288 | try expect(s2.e); | ||
| 289 | } | 285 | } |
| 290 | 286 | ||
| 291 | const BigPackedStruct = packed struct { | 287 | const BigPackedStruct = packed struct { |
| 292 | a: u64, | 288 | a: u64, |
| 293 | b: u64, | 289 | b: u64, |
| 294 | c: u64, | ||
| 295 | d: u64, | ||
| 296 | e: u8, | ||
| 297 | }; | 290 | }; |
| 298 | extern fn c_big_packed_struct(BigPackedStruct) void; | 291 | extern fn c_big_packed_struct(BigPackedStruct) void; |
| 299 | extern fn c_ret_big_packed_struct() BigPackedStruct; | 292 | extern fn c_ret_big_packed_struct() BigPackedStruct; |
| ... | @@ -301,20 +294,14 @@ extern fn c_ret_big_packed_struct() BigPackedStruct; | ... | @@ -301,20 +294,14 @@ extern fn c_ret_big_packed_struct() BigPackedStruct; |
| 301 | export fn zig_big_packed_struct(x: BigPackedStruct) void { | 294 | export fn zig_big_packed_struct(x: BigPackedStruct) void { |
| 302 | expect(x.a == 1) catch @panic("test failure"); | 295 | expect(x.a == 1) catch @panic("test failure"); |
| 303 | expect(x.b == 2) catch @panic("test failure"); | 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 | test "C ABI big packed struct" { | 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 | c_big_packed_struct(s); | 301 | c_big_packed_struct(s); |
| 312 | var s2 = c_ret_big_packed_struct(); | 302 | var s2 = c_ret_big_packed_struct(); |
| 313 | try expect(s2.a == 1); | 303 | try expect(s2.a == 1); |
| 314 | try expect(s2.b == 2); | 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 | const SplitStructInt = extern struct { | 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,5 +10,5 @@ export fn a() void { |
| 10 | // target=native | 10 | // target=native |
| 11 | // | 11 | // |
| 12 | // :3:19: error: C pointers cannot point to non-C-ABI-compatible type 'tmp.Foo' | 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 | // :1:13: note: struct declared here | 14 | // :1:13: note: struct declared here |
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,5 +10,5 @@ export fn entry(foo: Foo) void { _ = foo; } |
| 10 | // target=native | 10 | // target=native |
| 11 | // | 11 | // |
| 12 | // :6:17: error: parameter of type 'tmp.Foo' not allowed in function with calling convention 'C' | 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 | // :1:13: note: struct declared here | 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,5 +10,5 @@ export fn entry(foo: Foo) void { _ = foo; } |
| 10 | // target=native | 10 | // target=native |
| 11 | // | 11 | // |
| 12 | // :6:17: error: parameter of type 'tmp.Foo' not allowed in function with calling convention 'C' | 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 | // :1:13: note: union declared here | 14 | // :1:13: note: union declared here |