Commit dae22a0a1f
Changed files (3)
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);
}
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));
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