From dae22a0a1f13cc963e96cd704941eed29b8dde27 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 May 2021 22:50:00 -0700 Subject: [PATCH] stage2: struct, union, enum, opaque, error sets get better names This commit takes advantage of the new "NameStrategy" that is exposed in the ZIR in order to name Decls after their parent when asked to. This makes the next failing test case pass. --- BRANCH_TODO | 12 ++++++++++-- src/Module.zig | 27 +++++++++++++++++++-------- src/Sema.zig | 46 ++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 67 insertions(+), 18 deletions(-) diff --git a/BRANCH_TODO b/BRANCH_TODO index 76b4f7e1aac70b52344bd41e72c7c2edec03e021..4df72d831545f8ab7e3f6d1451281c9e48aa3790 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,5 +1,13 @@ - * structs, unions, enums, etc get weird names such as "Point__anon_22" rather - than "Point". + * The next problem is that when trying to deinitialize everything, when we + deinit a Decl that is the owner of a Namespace, there may still be other Decl + objects that reference that Namespace. They want to check if they are the owner + in order to find out if they should destroy it. But they can't check if they are + the owner because the owner_decl field is destroyed. + So there's a memory management problem to solve. We could easily solve this with + ref counting or whatever but the goal is to not introduce extra overhead / unnecessary + fields just to help figure out how to free stuff. So come up with some way to make + this sound, and easily debuggable when something goes wrong. + * get stage2 tests passing * modify stage2 tests so that only 1 uses _start and the rest use pub fn main diff --git a/src/Module.zig b/src/Module.zig index 434e74ca2faba9323240ef35a0aa6cbfbb932bb8..7860f9141c587150a686c30f5fbb98499fc1485a 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -3759,17 +3759,19 @@ pub fn constIntBig(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type, b } } -pub fn createAnonymousDecl(mod: *Module, scope: *Scope, typed_value: TypedValue) !*Decl { +/// Takes ownership of `name` even if it returns an error. +pub fn createAnonymousDeclNamed( + mod: *Module, + scope: *Scope, + typed_value: TypedValue, + name: [:0]u8, +) !*Decl { + errdefer mod.gpa.free(name); + const scope_decl = scope.ownerDecl().?; const namespace = scope_decl.namespace; try namespace.anon_decls.ensureUnusedCapacity(mod.gpa, 1); - const name_index = mod.getNextAnonNameIndex(); - const name = try std.fmt.allocPrintZ(mod.gpa, "{s}__anon_{d}", .{ - scope_decl.name, name_index, - }); - errdefer mod.gpa.free(name); - const new_decl = try mod.allocateNewDecl(namespace, scope_decl.src_node); new_decl.name = name; @@ -3793,7 +3795,16 @@ pub fn createAnonymousDecl(mod: *Module, scope: *Scope, typed_value: TypedValue) return new_decl; } -fn getNextAnonNameIndex(mod: *Module) usize { +pub fn createAnonymousDecl(mod: *Module, scope: *Scope, typed_value: TypedValue) !*Decl { + const scope_decl = scope.ownerDecl().?; + const name_index = mod.getNextAnonNameIndex(); + const name = try std.fmt.allocPrintZ(mod.gpa, "{s}__anon_{d}", .{ + scope_decl.name, name_index, + }); + return mod.createAnonymousDeclNamed(scope, typed_value, name); +} + +pub fn getNextAnonNameIndex(mod: *Module) usize { return @atomicRmw(usize, &mod.next_anon_name_index, .Add, 1, .Monotonic); } diff --git a/src/Sema.zig b/src/Sema.zig index 07fb4b4cd30a7cd14547d16ec1d3d27df708b664..35248d8f8b16b0a9371fa15fe2f9dcba3f232686 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -719,10 +719,11 @@ fn zirStructDecl( const struct_obj = try new_decl_arena.allocator.create(Module.Struct); const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj); const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty); - const new_decl = try sema.mod.createAnonymousDecl(&block.base, .{ + const type_name = try sema.createTypeName(block, small.name_strategy); + const new_decl = try sema.mod.createAnonymousDeclNamed(&block.base, .{ .ty = Type.initTag(.type), .val = struct_val, - }); + }, type_name); struct_obj.* = .{ .owner_decl = new_decl, .fields = .{}, @@ -744,6 +745,32 @@ fn zirStructDecl( return sema.analyzeDeclVal(block, src, new_decl); } +fn createTypeName(sema: *Sema, block: *Scope.Block, name_strategy: Zir.Inst.NameStrategy) ![:0]u8 { + switch (name_strategy) { + .anon => { + // It would be neat to have "struct:line:column" but this name has + // to survive incremental updates, where it may have been shifted down + // or up to a different line, but unchanged, and thus not unnecessarily + // semantically analyzed. + const name_index = sema.mod.getNextAnonNameIndex(); + return std.fmt.allocPrintZ(sema.gpa, "{s}__anon_{d}", .{ + sema.owner_decl.name, name_index, + }); + }, + .parent => return sema.gpa.dupeZ(u8, mem.spanZ(sema.owner_decl.name)), + .func => { + const name_index = sema.mod.getNextAnonNameIndex(); + const name = try std.fmt.allocPrintZ(sema.gpa, "{s}__anon_{d}", .{ + sema.owner_decl.name, name_index, + }); + log.warn("TODO: handle NameStrategy.func correctly instead of using anon name '{s}'", .{ + name, + }); + return name; + }, + } +} + fn zirEnumDecl( sema: *Sema, block: *Scope.Block, @@ -807,10 +834,11 @@ fn zirEnumDecl( }; const enum_ty = Type.initPayload(&enum_ty_payload.base); const enum_val = try Value.Tag.ty.create(&new_decl_arena.allocator, enum_ty); - const new_decl = try sema.mod.createAnonymousDecl(&block.base, .{ + const type_name = try sema.createTypeName(block, small.name_strategy); + const new_decl = try sema.mod.createAnonymousDeclNamed(&block.base, .{ .ty = Type.initTag(.type), .val = enum_val, - }); + }, type_name); enum_obj.* = .{ .owner_decl = new_decl, .tag_ty = tag_ty, @@ -957,10 +985,11 @@ fn zirUnionDecl( const union_obj = try new_decl_arena.allocator.create(Module.Union); const union_ty = try Type.Tag.@"union".create(&new_decl_arena.allocator, union_obj); const union_val = try Value.Tag.ty.create(&new_decl_arena.allocator, union_ty); - const new_decl = try sema.mod.createAnonymousDecl(&block.base, .{ + const type_name = try sema.createTypeName(block, small.name_strategy); + const new_decl = try sema.mod.createAnonymousDeclNamed(&block.base, .{ .ty = Type.initTag(.type), .val = union_val, - }); + }, type_name); union_obj.* = .{ .owner_decl = new_decl, .tag_ty = Type.initTag(.@"null"), @@ -1021,10 +1050,11 @@ fn zirErrorSetDecl( const error_set = try new_decl_arena.allocator.create(Module.ErrorSet); const error_set_ty = try Type.Tag.error_set.create(&new_decl_arena.allocator, error_set); const error_set_val = try Value.Tag.ty.create(&new_decl_arena.allocator, error_set_ty); - const new_decl = try sema.mod.createAnonymousDecl(&block.base, .{ + const type_name = try sema.createTypeName(block, name_strategy); + const new_decl = try sema.mod.createAnonymousDeclNamed(&block.base, .{ .ty = Type.initTag(.type), .val = error_set_val, - }); + }, type_name); const names = try new_decl_arena.allocator.alloc([]const u8, fields.len); for (fields) |str_index, i| { names[i] = try new_decl_arena.allocator.dupe(u8, sema.code.nullTerminatedString(str_index)); -- 2.54.0