| author | |
| committer | |
| log | 9afc4fe0e2114ae0ed53d48d98f5e12b6a269339 |
| tree | 4324713009e22c6401d73def7fcc574336fb7ab0 |
| parent | df38dfa4d1c9028453f90c7e37dd6c06f829a995 |
This improves the ABI alignment resolution code.
This commit fully enables the MachO linker code in stage3. Note,
however, that there are still miscompilations in stage3.7 files changed, 208 insertions(+), 50 deletions(-)
lib/std/array_hash_map.zig-4| ... | @@ -82,10 +82,6 @@ pub fn ArrayHashMap( | ... | @@ -82,10 +82,6 @@ pub fn ArrayHashMap( |
| 82 | allocator: Allocator, | 82 | allocator: Allocator, |
| 83 | ctx: Context, | 83 | ctx: Context, |
| 84 | 84 | ||
| 85 | comptime { | ||
| 86 | std.hash_map.verifyContext(Context, K, K, u32, true); | ||
| 87 | } | ||
| 88 | |||
| 89 | /// The ArrayHashMapUnmanaged type using the same settings as this managed map. | 85 | /// The ArrayHashMapUnmanaged type using the same settings as this managed map. |
| 90 | pub const Unmanaged = ArrayHashMapUnmanaged(K, V, Context, store_hash); | 86 | pub const Unmanaged = ArrayHashMapUnmanaged(K, V, Context, store_hash); |
| 91 | 87 |
src/Sema.zig+1| ... | @@ -18073,6 +18073,7 @@ fn elemValSlice( | ... | @@ -18073,6 +18073,7 @@ fn elemValSlice( |
| 18073 | const is_in_bounds = try block.addBinOp(cmp_op, elem_index, len_inst); | 18073 | const is_in_bounds = try block.addBinOp(cmp_op, elem_index, len_inst); |
| 18074 | try sema.addSafetyCheck(block, is_in_bounds, .index_out_of_bounds); | 18074 | try sema.addSafetyCheck(block, is_in_bounds, .index_out_of_bounds); |
| 18075 | } | 18075 | } |
| 18076 | try sema.queueFullTypeResolution(sema.typeOf(slice)); | ||
| 18076 | return block.addBinOp(.slice_elem_val, slice, elem_index); | 18077 | return block.addBinOp(.slice_elem_val, slice, elem_index); |
| 18077 | } | 18078 | } |
| 18078 | 18079 |
src/link/MachO.zig-3| ... | @@ -1322,9 +1322,6 @@ pub fn parseDylib(self: *MachO, path: []const u8, opts: DylibCreateOpts) ParseDy | ... | @@ -1322,9 +1322,6 @@ pub fn parseDylib(self: *MachO, path: []const u8, opts: DylibCreateOpts) ParseDy |
| 1322 | error.EndOfStream, error.NotDylib => { | 1322 | error.EndOfStream, error.NotDylib => { |
| 1323 | try file.seekTo(0); | 1323 | try file.seekTo(0); |
| 1324 | 1324 | ||
| 1325 | // TODO https://github.com/ziglang/zig/issues/11367 | ||
| 1326 | if (@import("builtin").zig_backend != .stage1) return error.Unexpected; | ||
| 1327 | |||
| 1328 | var lib_stub = LibStub.loadFromFile(self.base.allocator, file) catch { | 1325 | var lib_stub = LibStub.loadFromFile(self.base.allocator, file) catch { |
| 1329 | dylib.deinit(self.base.allocator); | 1326 | dylib.deinit(self.base.allocator); |
| 1330 | return false; | 1327 | return false; |
src/link/MachO/Dylib.zig+4-4| ... | @@ -242,20 +242,20 @@ fn addObjCClassSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8) | ... | @@ -242,20 +242,20 @@ fn addObjCClassSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8) |
| 242 | 242 | ||
| 243 | for (expanded) |sym| { | 243 | for (expanded) |sym| { |
| 244 | if (self.symbols.contains(sym)) continue; | 244 | if (self.symbols.contains(sym)) continue; |
| 245 | try self.symbols.putNoClobber(allocator, sym, .{}); | 245 | try self.symbols.putNoClobber(allocator, sym, {}); |
| 246 | } | 246 | } |
| 247 | } | 247 | } |
| 248 | 248 | ||
| 249 | fn addObjCIVarSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8) !void { | 249 | fn addObjCIVarSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8) !void { |
| 250 | const expanded = try std.fmt.allocPrint(allocator, "_OBJC_IVAR_$_{s}", .{sym_name}); | 250 | const expanded = try std.fmt.allocPrint(allocator, "_OBJC_IVAR_$_{s}", .{sym_name}); |
| 251 | if (self.symbols.contains(expanded)) return; | 251 | if (self.symbols.contains(expanded)) return; |
| 252 | try self.symbols.putNoClobber(allocator, expanded, .{}); | 252 | try self.symbols.putNoClobber(allocator, expanded, {}); |
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | fn addObjCEhTypeSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8) !void { | 255 | fn addObjCEhTypeSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8) !void { |
| 256 | const expanded = try std.fmt.allocPrint(allocator, "_OBJC_EHTYPE_$_{s}", .{sym_name}); | 256 | const expanded = try std.fmt.allocPrint(allocator, "_OBJC_EHTYPE_$_{s}", .{sym_name}); |
| 257 | if (self.symbols.contains(expanded)) return; | 257 | if (self.symbols.contains(expanded)) return; |
| 258 | try self.symbols.putNoClobber(allocator, expanded, .{}); | 258 | try self.symbols.putNoClobber(allocator, expanded, {}); |
| 259 | } | 259 | } |
| 260 | 260 | ||
| 261 | fn addSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8) !void { | 261 | fn addSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8) !void { |
| ... | @@ -373,7 +373,7 @@ pub fn parseFromStub( | ... | @@ -373,7 +373,7 @@ pub fn parseFromStub( |
| 373 | // TODO I thought that we could switch on presence of `parent-umbrella` map; | 373 | // TODO I thought that we could switch on presence of `parent-umbrella` map; |
| 374 | // however, turns out `libsystem_notify.dylib` is fully reexported by `libSystem.dylib` | 374 | // however, turns out `libsystem_notify.dylib` is fully reexported by `libSystem.dylib` |
| 375 | // BUT does not feature a `parent-umbrella` map as the only sublib. Apple's bug perhaps? | 375 | // BUT does not feature a `parent-umbrella` map as the only sublib. Apple's bug perhaps? |
| 376 | try umbrella_libs.put(elem.installName(), .{}); | 376 | try umbrella_libs.put(elem.installName(), {}); |
| 377 | } | 377 | } |
| 378 | 378 | ||
| 379 | switch (elem) { | 379 | switch (elem) { |
src/link/tapi/yaml.zig+1-1| ... | @@ -153,7 +153,7 @@ pub const Value = union(ValueType) { | ... | @@ -153,7 +153,7 @@ pub const Value = union(ValueType) { |
| 153 | if (node.cast(Node.Doc)) |doc| { | 153 | if (node.cast(Node.Doc)) |doc| { |
| 154 | const inner = doc.value orelse { | 154 | const inner = doc.value orelse { |
| 155 | // empty doc | 155 | // empty doc |
| 156 | return Value{ .empty = .{} }; | 156 | return Value{ .empty = {} }; |
| 157 | }; | 157 | }; |
| 158 | return Value.fromNode(arena, tree, inner, null); | 158 | return Value.fromNode(arena, tree, inner, null); |
| 159 | } else if (node.cast(Node.Map)) |map| { | 159 | } else if (node.cast(Node.Map)) |map| { |
src/type.zig+91-38| ... | @@ -2394,11 +2394,15 @@ pub const Type = extern union { | ... | @@ -2394,11 +2394,15 @@ pub const Type = extern union { |
| 2394 | _ = try sk.sema.typeRequiresComptime(sk.block, sk.src, ty); | 2394 | _ = try sk.sema.typeRequiresComptime(sk.block, sk.src, ty); |
| 2395 | } | 2395 | } |
| 2396 | switch (struct_obj.requires_comptime) { | 2396 | switch (struct_obj.requires_comptime) { |
| 2397 | .wip => unreachable, | ||
| 2398 | .yes => return false, | 2397 | .yes => return false, |
| 2399 | .no => if (struct_obj.known_non_opv) return true, | 2398 | .wip, .no => if (struct_obj.known_non_opv) return true, |
| 2400 | .unknown => {}, | 2399 | .unknown => {}, |
| 2401 | } | 2400 | } |
| 2401 | if (struct_obj.status == .field_types_wip) { | ||
| 2402 | // In this case, we guess that hasRuntimeBits() for this type is true, | ||
| 2403 | // and then later if our guess was incorrect, we emit a compile error. | ||
| 2404 | return true; | ||
| 2405 | } | ||
| 2402 | if (sema_kit) |sk| { | 2406 | if (sema_kit) |sk| { |
| 2403 | _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty); | 2407 | _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty); |
| 2404 | } | 2408 | } |
| ... | @@ -2735,6 +2739,12 @@ pub const Type = extern union { | ... | @@ -2735,6 +2739,12 @@ pub const Type = extern union { |
| 2735 | val: Value, | 2739 | val: Value, |
| 2736 | }; | 2740 | }; |
| 2737 | 2741 | ||
| 2742 | const AbiAlignmentAdvancedStrat = union(enum) { | ||
| 2743 | eager, | ||
| 2744 | lazy: Allocator, | ||
| 2745 | sema_kit: Module.WipAnalysis, | ||
| 2746 | }; | ||
| 2747 | |||
| 2738 | /// If you pass `eager` you will get back `scalar` and assert the type is resolved. | 2748 | /// If you pass `eager` you will get back `scalar` and assert the type is resolved. |
| 2739 | /// In this case there will be no error, guaranteed. | 2749 | /// In this case there will be no error, guaranteed. |
| 2740 | /// If you pass `lazy` you may get back `scalar` or `val`. | 2750 | /// If you pass `lazy` you may get back `scalar` or `val`. |
| ... | @@ -2744,11 +2754,7 @@ pub const Type = extern union { | ... | @@ -2744,11 +2754,7 @@ pub const Type = extern union { |
| 2744 | pub fn abiAlignmentAdvanced( | 2754 | pub fn abiAlignmentAdvanced( |
| 2745 | ty: Type, | 2755 | ty: Type, |
| 2746 | target: Target, | 2756 | target: Target, |
| 2747 | strat: union(enum) { | 2757 | strat: AbiAlignmentAdvancedStrat, |
| 2748 | eager, | ||
| 2749 | lazy: Allocator, | ||
| 2750 | sema_kit: Module.WipAnalysis, | ||
| 2751 | }, | ||
| 2752 | ) Module.CompileError!AbiAlignmentAdvanced { | 2758 | ) Module.CompileError!AbiAlignmentAdvanced { |
| 2753 | const sema_kit = switch (strat) { | 2759 | const sema_kit = switch (strat) { |
| 2754 | .sema_kit => |sk| sk, | 2760 | .sema_kit => |sk| sk, |
| ... | @@ -2928,21 +2934,24 @@ pub const Type = extern union { | ... | @@ -2928,21 +2934,24 @@ pub const Type = extern union { |
| 2928 | }, | 2934 | }, |
| 2929 | 2935 | ||
| 2930 | .@"struct" => { | 2936 | .@"struct" => { |
| 2937 | const struct_obj = ty.castTag(.@"struct").?.data; | ||
| 2931 | if (sema_kit) |sk| { | 2938 | if (sema_kit) |sk| { |
| 2932 | try sk.sema.resolveTypeLayout(sk.block, sk.src, ty); | 2939 | if (struct_obj.status == .field_types_wip) { |
| 2933 | } | 2940 | // We'll guess "pointer-aligned" and if we guess wrong, emit |
| 2934 | if (ty.castTag(.@"struct")) |payload| { | 2941 | // a compile error later. |
| 2935 | const struct_obj = payload.data; | 2942 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) }; |
| 2936 | if (!struct_obj.haveLayout()) switch (strat) { | ||
| 2937 | .eager => unreachable, // struct layout not resolved | ||
| 2938 | .sema_kit => unreachable, // handled above | ||
| 2939 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | ||
| 2940 | }; | ||
| 2941 | if (struct_obj.layout == .Packed) { | ||
| 2942 | var buf: Type.Payload.Bits = undefined; | ||
| 2943 | const int_ty = struct_obj.packedIntegerType(target, &buf); | ||
| 2944 | return AbiAlignmentAdvanced{ .scalar = int_ty.abiAlignment(target) }; | ||
| 2945 | } | 2943 | } |
| 2944 | _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty); | ||
| 2945 | } | ||
| 2946 | if (!struct_obj.haveFieldTypes()) switch (strat) { | ||
| 2947 | .eager => unreachable, // struct layout not resolved | ||
| 2948 | .sema_kit => unreachable, // handled above | ||
| 2949 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | ||
| 2950 | }; | ||
| 2951 | if (struct_obj.layout == .Packed) { | ||
| 2952 | var buf: Type.Payload.Bits = undefined; | ||
| 2953 | const int_ty = struct_obj.packedIntegerType(target, &buf); | ||
| 2954 | return AbiAlignmentAdvanced{ .scalar = int_ty.abiAlignment(target) }; | ||
| 2946 | } | 2955 | } |
| 2947 | 2956 | ||
| 2948 | const fields = ty.structFields(); | 2957 | const fields = ty.structFields(); |
| ... | @@ -2950,7 +2959,16 @@ pub const Type = extern union { | ... | @@ -2950,7 +2959,16 @@ pub const Type = extern union { |
| 2950 | for (fields.values()) |field| { | 2959 | for (fields.values()) |field| { |
| 2951 | if (!(try field.ty.hasRuntimeBitsAdvanced(false, sema_kit))) continue; | 2960 | if (!(try field.ty.hasRuntimeBitsAdvanced(false, sema_kit))) continue; |
| 2952 | 2961 | ||
| 2953 | const field_align = field.normalAlignment(target); | 2962 | const field_align = if (field.abi_align != 0) |
| 2963 | field.abi_align | ||
| 2964 | else switch (try field.ty.abiAlignmentAdvanced(target, strat)) { | ||
| 2965 | .scalar => |a| a, | ||
| 2966 | .val => switch (strat) { | ||
| 2967 | .eager => unreachable, // struct layout not resolved | ||
| 2968 | .sema_kit => unreachable, // handled above | ||
| 2969 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | ||
| 2970 | }, | ||
| 2971 | }; | ||
| 2954 | big_align = @maximum(big_align, field_align); | 2972 | big_align = @maximum(big_align, field_align); |
| 2955 | } | 2973 | } |
| 2956 | return AbiAlignmentAdvanced{ .scalar = big_align }; | 2974 | return AbiAlignmentAdvanced{ .scalar = big_align }; |
| ... | @@ -2980,24 +2998,14 @@ pub const Type = extern union { | ... | @@ -2980,24 +2998,14 @@ pub const Type = extern union { |
| 2980 | const int_tag_ty = ty.intTagType(&buffer); | 2998 | const int_tag_ty = ty.intTagType(&buffer); |
| 2981 | return AbiAlignmentAdvanced{ .scalar = int_tag_ty.abiAlignment(target) }; | 2999 | return AbiAlignmentAdvanced{ .scalar = int_tag_ty.abiAlignment(target) }; |
| 2982 | }, | 3000 | }, |
| 2983 | .@"union" => switch (strat) { | 3001 | .@"union" => { |
| 2984 | .eager, .sema_kit => { | 3002 | const union_obj = ty.castTag(.@"union").?.data; |
| 2985 | if (sema_kit) |sk| { | 3003 | // TODO pass `true` for have_tag when unions have a safety tag |
| 2986 | try sk.sema.resolveTypeLayout(sk.block, sk.src, ty); | 3004 | return abiAlignmentAdvancedUnion(ty, target, strat, union_obj, false); |
| 2987 | } | ||
| 2988 | // TODO pass `true` for have_tag when unions have a safety tag | ||
| 2989 | return AbiAlignmentAdvanced{ .scalar = ty.castTag(.@"union").?.data.abiAlignment(target, false) }; | ||
| 2990 | }, | ||
| 2991 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | ||
| 2992 | }, | 3005 | }, |
| 2993 | .union_tagged => switch (strat) { | 3006 | .union_tagged => { |
| 2994 | .eager, .sema_kit => { | 3007 | const union_obj = ty.castTag(.union_tagged).?.data; |
| 2995 | if (sema_kit) |sk| { | 3008 | return abiAlignmentAdvancedUnion(ty, target, strat, union_obj, true); |
| 2996 | try sk.sema.resolveTypeLayout(sk.block, sk.src, ty); | ||
| 2997 | } | ||
| 2998 | return AbiAlignmentAdvanced{ .scalar = ty.castTag(.union_tagged).?.data.abiAlignment(target, true) }; | ||
| 2999 | }, | ||
| 3000 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | ||
| 3001 | }, | 3009 | }, |
| 3002 | 3010 | ||
| 3003 | .empty_struct, | 3011 | .empty_struct, |
| ... | @@ -3023,6 +3031,51 @@ pub const Type = extern union { | ... | @@ -3023,6 +3031,51 @@ pub const Type = extern union { |
| 3023 | }; | 3031 | }; |
| 3024 | } | 3032 | } |
| 3025 | 3033 | ||
| 3034 | pub fn abiAlignmentAdvancedUnion( | ||
| 3035 | ty: Type, | ||
| 3036 | target: Target, | ||
| 3037 | strat: AbiAlignmentAdvancedStrat, | ||
| 3038 | union_obj: *Module.Union, | ||
| 3039 | have_tag: bool, | ||
| 3040 | ) Module.CompileError!AbiAlignmentAdvanced { | ||
| 3041 | const sema_kit = switch (strat) { | ||
| 3042 | .sema_kit => |sk| sk, | ||
| 3043 | else => null, | ||
| 3044 | }; | ||
| 3045 | if (sema_kit) |sk| { | ||
| 3046 | if (union_obj.status == .field_types_wip) { | ||
| 3047 | // We'll guess "pointer-aligned" and if we guess wrong, emit | ||
| 3048 | // a compile error later. | ||
| 3049 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) }; | ||
| 3050 | } | ||
| 3051 | _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty); | ||
| 3052 | } | ||
| 3053 | if (!union_obj.haveFieldTypes()) switch (strat) { | ||
| 3054 | .eager => unreachable, // union layout not resolved | ||
| 3055 | .sema_kit => unreachable, // handled above | ||
| 3056 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | ||
| 3057 | }; | ||
| 3058 | |||
| 3059 | var max_align: u32 = 0; | ||
| 3060 | if (have_tag) max_align = union_obj.tag_ty.abiAlignment(target); | ||
| 3061 | for (union_obj.fields.values()) |field| { | ||
| 3062 | if (!(try field.ty.hasRuntimeBitsAdvanced(false, sema_kit))) continue; | ||
| 3063 | |||
| 3064 | const field_align = if (field.abi_align != 0) | ||
| 3065 | field.abi_align | ||
| 3066 | else switch (try field.ty.abiAlignmentAdvanced(target, strat)) { | ||
| 3067 | .scalar => |a| a, | ||
| 3068 | .val => switch (strat) { | ||
| 3069 | .eager => unreachable, // struct layout not resolved | ||
| 3070 | .sema_kit => unreachable, // handled above | ||
| 3071 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | ||
| 3072 | }, | ||
| 3073 | }; | ||
| 3074 | max_align = @maximum(max_align, field_align); | ||
| 3075 | } | ||
| 3076 | return AbiAlignmentAdvanced{ .scalar = max_align }; | ||
| 3077 | } | ||
| 3078 | |||
| 3026 | /// Asserts the type has the ABI size already resolved. | 3079 | /// Asserts the type has the ABI size already resolved. |
| 3027 | /// Types that return false for hasRuntimeBits() return 0. | 3080 | /// Types that return false for hasRuntimeBits() return 0. |
| 3028 | pub fn abiSize(self: Type, target: Target) u64 { | 3081 | pub fn abiSize(self: Type, target: Target) u64 { |
test/behavior/eval.zig+111| ... | @@ -999,3 +999,114 @@ test "comptime break operand passing through runtime switch converted to runtime | ... | @@ -999,3 +999,114 @@ test "comptime break operand passing through runtime switch converted to runtime |
| 999 | try S.doTheTest('b'); | 999 | try S.doTheTest('b'); |
| 1000 | comptime try S.doTheTest('b'); | 1000 | comptime try S.doTheTest('b'); |
| 1001 | } | 1001 | } |
| 1002 | |||
| 1003 | test "no dependency loop for alignment of self struct" { | ||
| 1004 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 1005 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 1006 | |||
| 1007 | const S = struct { | ||
| 1008 | fn doTheTest() !void { | ||
| 1009 | var a: namespace.A = undefined; | ||
| 1010 | a.d = .{ .g = &buf }; | ||
| 1011 | a.d.g[3] = 42; | ||
| 1012 | a.d.g[3] += 1; | ||
| 1013 | try expect(a.d.g[3] == 43); | ||
| 1014 | } | ||
| 1015 | |||
| 1016 | var buf: [10]u8 align(@alignOf([*]u8)) = undefined; | ||
| 1017 | |||
| 1018 | const namespace = struct { | ||
| 1019 | const B = struct { a: A }; | ||
| 1020 | const A = C(B); | ||
| 1021 | }; | ||
| 1022 | |||
| 1023 | pub fn C(comptime B: type) type { | ||
| 1024 | return struct { | ||
| 1025 | d: D(F) = .{}, | ||
| 1026 | |||
| 1027 | const F = struct { b: B }; | ||
| 1028 | }; | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | pub fn D(comptime F: type) type { | ||
| 1032 | return struct { | ||
| 1033 | g: [*]align(@alignOf(F)) u8 = undefined, | ||
| 1034 | }; | ||
| 1035 | } | ||
| 1036 | }; | ||
| 1037 | try S.doTheTest(); | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | test "no dependency loop for alignment of self bare union" { | ||
| 1041 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 1042 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 1043 | |||
| 1044 | const S = struct { | ||
| 1045 | fn doTheTest() !void { | ||
| 1046 | var a: namespace.A = undefined; | ||
| 1047 | a.d = .{ .g = &buf }; | ||
| 1048 | a.d.g[3] = 42; | ||
| 1049 | a.d.g[3] += 1; | ||
| 1050 | try expect(a.d.g[3] == 43); | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | var buf: [10]u8 align(@alignOf([*]u8)) = undefined; | ||
| 1054 | |||
| 1055 | const namespace = struct { | ||
| 1056 | const B = union { a: A, b: void }; | ||
| 1057 | const A = C(B); | ||
| 1058 | }; | ||
| 1059 | |||
| 1060 | pub fn C(comptime B: type) type { | ||
| 1061 | return struct { | ||
| 1062 | d: D(F) = .{}, | ||
| 1063 | |||
| 1064 | const F = struct { b: B }; | ||
| 1065 | }; | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | pub fn D(comptime F: type) type { | ||
| 1069 | return struct { | ||
| 1070 | g: [*]align(@alignOf(F)) u8 = undefined, | ||
| 1071 | }; | ||
| 1072 | } | ||
| 1073 | }; | ||
| 1074 | try S.doTheTest(); | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | test "no dependency loop for alignment of self tagged union" { | ||
| 1078 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 1079 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 1080 | |||
| 1081 | const S = struct { | ||
| 1082 | fn doTheTest() !void { | ||
| 1083 | var a: namespace.A = undefined; | ||
| 1084 | a.d = .{ .g = &buf }; | ||
| 1085 | a.d.g[3] = 42; | ||
| 1086 | a.d.g[3] += 1; | ||
| 1087 | try expect(a.d.g[3] == 43); | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | var buf: [10]u8 align(@alignOf([*]u8)) = undefined; | ||
| 1091 | |||
| 1092 | const namespace = struct { | ||
| 1093 | const B = union(enum) { a: A, b: void }; | ||
| 1094 | const A = C(B); | ||
| 1095 | }; | ||
| 1096 | |||
| 1097 | pub fn C(comptime B: type) type { | ||
| 1098 | return struct { | ||
| 1099 | d: D(F) = .{}, | ||
| 1100 | |||
| 1101 | const F = struct { b: B }; | ||
| 1102 | }; | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | pub fn D(comptime F: type) type { | ||
| 1106 | return struct { | ||
| 1107 | g: [*]align(@alignOf(F)) u8 = undefined, | ||
| 1108 | }; | ||
| 1109 | } | ||
| 1110 | }; | ||
| 1111 | try S.doTheTest(); | ||
| 1112 | } |