authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-05 14:27:20-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-06 22:40:57-07:00
log9afc4fe0e2114ae0ed53d48d98f5e12b6a269339
tree4324713009e22c6401d73def7fcc574336fb7ab0
parentdf38dfa4d1c9028453f90c7e37dd6c06f829a995

Sema: solve a false positive "depends on itself"

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(
8282 allocator: Allocator,
8383 ctx: Context,
8484
85 comptime {
86 std.hash_map.verifyContext(Context, K, K, u32, true);
87 }
88
8985 /// The ArrayHashMapUnmanaged type using the same settings as this managed map.
9086 pub const Unmanaged = ArrayHashMapUnmanaged(K, V, Context, store_hash);
9187
src/Sema.zig+1
......@@ -18073,6 +18073,7 @@ fn elemValSlice(
1807318073 const is_in_bounds = try block.addBinOp(cmp_op, elem_index, len_inst);
1807418074 try sema.addSafetyCheck(block, is_in_bounds, .index_out_of_bounds);
1807518075 }
18076 try sema.queueFullTypeResolution(sema.typeOf(slice));
1807618077 return block.addBinOp(.slice_elem_val, slice, elem_index);
1807718078}
1807818079
src/link/MachO.zig-3
......@@ -1322,9 +1322,6 @@ pub fn parseDylib(self: *MachO, path: []const u8, opts: DylibCreateOpts) ParseDy
13221322 error.EndOfStream, error.NotDylib => {
13231323 try file.seekTo(0);
13241324
1325 // TODO https://github.com/ziglang/zig/issues/11367
1326 if (@import("builtin").zig_backend != .stage1) return error.Unexpected;
1327
13281325 var lib_stub = LibStub.loadFromFile(self.base.allocator, file) catch {
13291326 dylib.deinit(self.base.allocator);
13301327 return false;
src/link/MachO/Dylib.zig+4-4
......@@ -242,20 +242,20 @@ fn addObjCClassSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8)
242242
243243 for (expanded) |sym| {
244244 if (self.symbols.contains(sym)) continue;
245 try self.symbols.putNoClobber(allocator, sym, .{});
245 try self.symbols.putNoClobber(allocator, sym, {});
246246 }
247247}
248248
249249fn addObjCIVarSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8) !void {
250250 const expanded = try std.fmt.allocPrint(allocator, "_OBJC_IVAR_$_{s}", .{sym_name});
251251 if (self.symbols.contains(expanded)) return;
252 try self.symbols.putNoClobber(allocator, expanded, .{});
252 try self.symbols.putNoClobber(allocator, expanded, {});
253253}
254254
255255fn addObjCEhTypeSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8) !void {
256256 const expanded = try std.fmt.allocPrint(allocator, "_OBJC_EHTYPE_$_{s}", .{sym_name});
257257 if (self.symbols.contains(expanded)) return;
258 try self.symbols.putNoClobber(allocator, expanded, .{});
258 try self.symbols.putNoClobber(allocator, expanded, {});
259259}
260260
261261fn addSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8) !void {
......@@ -373,7 +373,7 @@ pub fn parseFromStub(
373373 // TODO I thought that we could switch on presence of `parent-umbrella` map;
374374 // however, turns out `libsystem_notify.dylib` is fully reexported by `libSystem.dylib`
375375 // 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(), {});
377377 }
378378
379379 switch (elem) {
src/link/tapi/yaml.zig+1-1
......@@ -153,7 +153,7 @@ pub const Value = union(ValueType) {
153153 if (node.cast(Node.Doc)) |doc| {
154154 const inner = doc.value orelse {
155155 // empty doc
156 return Value{ .empty = .{} };
156 return Value{ .empty = {} };
157157 };
158158 return Value.fromNode(arena, tree, inner, null);
159159 } else if (node.cast(Node.Map)) |map| {
src/type.zig+91-38
......@@ -2394,11 +2394,15 @@ pub const Type = extern union {
23942394 _ = try sk.sema.typeRequiresComptime(sk.block, sk.src, ty);
23952395 }
23962396 switch (struct_obj.requires_comptime) {
2397 .wip => unreachable,
23982397 .yes => return false,
2399 .no => if (struct_obj.known_non_opv) return true,
2398 .wip, .no => if (struct_obj.known_non_opv) return true,
24002399 .unknown => {},
24012400 }
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 }
24022406 if (sema_kit) |sk| {
24032407 _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);
24042408 }
......@@ -2735,6 +2739,12 @@ pub const Type = extern union {
27352739 val: Value,
27362740 };
27372741
2742 const AbiAlignmentAdvancedStrat = union(enum) {
2743 eager,
2744 lazy: Allocator,
2745 sema_kit: Module.WipAnalysis,
2746 };
2747
27382748 /// If you pass `eager` you will get back `scalar` and assert the type is resolved.
27392749 /// In this case there will be no error, guaranteed.
27402750 /// If you pass `lazy` you may get back `scalar` or `val`.
......@@ -2744,11 +2754,7 @@ pub const Type = extern union {
27442754 pub fn abiAlignmentAdvanced(
27452755 ty: Type,
27462756 target: Target,
2747 strat: union(enum) {
2748 eager,
2749 lazy: Allocator,
2750 sema_kit: Module.WipAnalysis,
2751 },
2757 strat: AbiAlignmentAdvancedStrat,
27522758 ) Module.CompileError!AbiAlignmentAdvanced {
27532759 const sema_kit = switch (strat) {
27542760 .sema_kit => |sk| sk,
......@@ -2928,21 +2934,24 @@ pub const Type = extern union {
29282934 },
29292935
29302936 .@"struct" => {
2937 const struct_obj = ty.castTag(.@"struct").?.data;
29312938 if (sema_kit) |sk| {
2932 try sk.sema.resolveTypeLayout(sk.block, sk.src, ty);
2933 }
2934 if (ty.castTag(.@"struct")) |payload| {
2935 const struct_obj = payload.data;
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) };
2939 if (struct_obj.status == .field_types_wip) {
2940 // We'll guess "pointer-aligned" and if we guess wrong, emit
2941 // a compile error later.
2942 return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) };
29452943 }
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) };
29462955 }
29472956
29482957 const fields = ty.structFields();
......@@ -2950,7 +2959,16 @@ pub const Type = extern union {
29502959 for (fields.values()) |field| {
29512960 if (!(try field.ty.hasRuntimeBitsAdvanced(false, sema_kit))) continue;
29522961
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 };
29542972 big_align = @maximum(big_align, field_align);
29552973 }
29562974 return AbiAlignmentAdvanced{ .scalar = big_align };
......@@ -2980,24 +2998,14 @@ pub const Type = extern union {
29802998 const int_tag_ty = ty.intTagType(&buffer);
29812999 return AbiAlignmentAdvanced{ .scalar = int_tag_ty.abiAlignment(target) };
29823000 },
2983 .@"union" => switch (strat) {
2984 .eager, .sema_kit => {
2985 if (sema_kit) |sk| {
2986 try sk.sema.resolveTypeLayout(sk.block, sk.src, ty);
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) },
3001 .@"union" => {
3002 const union_obj = ty.castTag(.@"union").?.data;
3003 // TODO pass `true` for have_tag when unions have a safety tag
3004 return abiAlignmentAdvancedUnion(ty, target, strat, union_obj, false);
29923005 },
2993 .union_tagged => switch (strat) {
2994 .eager, .sema_kit => {
2995 if (sema_kit) |sk| {
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) },
3006 .union_tagged => {
3007 const union_obj = ty.castTag(.union_tagged).?.data;
3008 return abiAlignmentAdvancedUnion(ty, target, strat, union_obj, true);
30013009 },
30023010
30033011 .empty_struct,
......@@ -3023,6 +3031,51 @@ pub const Type = extern union {
30233031 };
30243032 }
30253033
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
30263079 /// Asserts the type has the ABI size already resolved.
30273080 /// Types that return false for hasRuntimeBits() return 0.
30283081 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
999999 try S.doTheTest('b');
10001000 comptime try S.doTheTest('b');
10011001}
1002
1003test "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
1040test "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
1077test "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}