| ... | @@ -227,6 +227,10 @@ pub const Decl = struct { | ... | @@ -227,6 +227,10 @@ pub const Decl = struct { |
| 227 | }, | 227 | }, |
| 228 | /// Whether `typed_value`, `align_val`, and `linksection_val` are populated. | 228 | /// Whether `typed_value`, `align_val`, and `linksection_val` are populated. |
| 229 | has_tv: bool, | 229 | has_tv: bool, |
| | 230 | /// If `true` it means the `Decl` is the resource owner of the type/value associated |
| | 231 | /// with it. That means when `Decl` is destroyed, the cleanup code should additionally |
| | 232 | /// check if the value owns a `Namespace`, and destroy that too. |
| | 233 | owns_tv: bool, |
| 230 | /// This flag is set when this Decl is added to `Module.deletion_set`, and cleared | 234 | /// This flag is set when this Decl is added to `Module.deletion_set`, and cleared |
| 231 | /// when removed. | 235 | /// when removed. |
| 232 | deletion_flag: bool, | 236 | deletion_flag: bool, |
| ... | @@ -278,9 +282,7 @@ pub const Decl = struct { | ... | @@ -278,9 +282,7 @@ pub const Decl = struct { |
| 278 | decl.clearName(gpa); | 282 | decl.clearName(gpa); |
| 279 | if (decl.has_tv) { | 283 | if (decl.has_tv) { |
| 280 | if (decl.getInnerNamespace()) |namespace| { | 284 | if (decl.getInnerNamespace()) |namespace| { |
| 281 | if (namespace.getDecl() == decl) { | 285 | namespace.clearDecls(module); |
| 282 | namespace.clearDecls(module); | | |
| 283 | } | | |
| 284 | } | 286 | } |
| 285 | decl.clearValues(gpa); | 287 | decl.clearValues(gpa); |
| 286 | } | 288 | } |
| ... | @@ -307,6 +309,7 @@ pub const Decl = struct { | ... | @@ -307,6 +309,7 @@ pub const Decl = struct { |
| 307 | arena_state.promote(gpa).deinit(); | 309 | arena_state.promote(gpa).deinit(); |
| 308 | decl.value_arena = null; | 310 | decl.value_arena = null; |
| 309 | decl.has_tv = false; | 311 | decl.has_tv = false; |
| | 312 | decl.owns_tv = false; |
| 310 | } | 313 | } |
| 311 | } | 314 | } |
| 312 | | 315 | |
| ... | @@ -441,36 +444,36 @@ pub const Decl = struct { | ... | @@ -441,36 +444,36 @@ pub const Decl = struct { |
| 441 | /// If the Decl has a value and it is a struct, return it, | 444 | /// If the Decl has a value and it is a struct, return it, |
| 442 | /// otherwise null. | 445 | /// otherwise null. |
| 443 | pub fn getStruct(decl: *Decl) ?*Struct { | 446 | pub fn getStruct(decl: *Decl) ?*Struct { |
| 444 | if (!decl.has_tv) return null; | 447 | if (!decl.owns_tv) return null; |
| 445 | const ty = (decl.val.castTag(.ty) orelse return null).data; | 448 | const ty = (decl.val.castTag(.ty) orelse return null).data; |
| 446 | const struct_obj = (ty.castTag(.@"struct") orelse return null).data; | 449 | const struct_obj = (ty.castTag(.@"struct") orelse return null).data; |
| 447 | if (struct_obj.owner_decl != decl) return null; | 450 | assert(struct_obj.owner_decl == decl); |
| 448 | return struct_obj; | 451 | return struct_obj; |
| 449 | } | 452 | } |
| 450 | | 453 | |
| 451 | /// If the Decl has a value and it is a union, return it, | 454 | /// If the Decl has a value and it is a union, return it, |
| 452 | /// otherwise null. | 455 | /// otherwise null. |
| 453 | pub fn getUnion(decl: *Decl) ?*Union { | 456 | pub fn getUnion(decl: *Decl) ?*Union { |
| 454 | if (!decl.has_tv) return null; | 457 | if (!decl.owns_tv) return null; |
| 455 | const ty = (decl.val.castTag(.ty) orelse return null).data; | 458 | const ty = (decl.val.castTag(.ty) orelse return null).data; |
| 456 | const union_obj = (ty.cast(Type.Payload.Union) orelse return null).data; | 459 | const union_obj = (ty.cast(Type.Payload.Union) orelse return null).data; |
| 457 | if (union_obj.owner_decl != decl) return null; | 460 | assert(union_obj.owner_decl == decl); |
| 458 | return union_obj; | 461 | return union_obj; |
| 459 | } | 462 | } |
| 460 | | 463 | |
| 461 | /// If the Decl has a value and it is a function, return it, | 464 | /// If the Decl has a value and it is a function, return it, |
| 462 | /// otherwise null. | 465 | /// otherwise null. |
| 463 | pub fn getFunction(decl: *Decl) ?*Fn { | 466 | pub fn getFunction(decl: *Decl) ?*Fn { |
| 464 | if (!decl.has_tv) return null; | 467 | if (!decl.owns_tv) return null; |
| 465 | const func = (decl.val.castTag(.function) orelse return null).data; | 468 | const func = (decl.val.castTag(.function) orelse return null).data; |
| 466 | if (func.owner_decl != decl) return null; | 469 | assert(func.owner_decl == decl); |
| 467 | return func; | 470 | return func; |
| 468 | } | 471 | } |
| 469 | | 472 | |
| 470 | pub fn getVariable(decl: *Decl) ?*Var { | 473 | pub fn getVariable(decl: *Decl) ?*Var { |
| 471 | if (!decl.has_tv) return null; | 474 | if (!decl.owns_tv) return null; |
| 472 | const variable = (decl.val.castTag(.variable) orelse return null).data; | 475 | const variable = (decl.val.castTag(.variable) orelse return null).data; |
| 473 | if (variable.owner_decl != decl) return null; | 476 | assert(variable.owner_decl == decl); |
| 474 | return variable; | 477 | return variable; |
| 475 | } | 478 | } |
| 476 | | 479 | |
| ... | @@ -478,29 +481,28 @@ pub const Decl = struct { | ... | @@ -478,29 +481,28 @@ pub const Decl = struct { |
| 478 | /// enum, or opaque. | 481 | /// enum, or opaque. |
| 479 | /// Only returns it if the Decl is the owner. | 482 | /// Only returns it if the Decl is the owner. |
| 480 | pub fn getInnerNamespace(decl: *Decl) ?*Scope.Namespace { | 483 | pub fn getInnerNamespace(decl: *Decl) ?*Scope.Namespace { |
| 481 | if (!decl.has_tv) return null; | 484 | if (!decl.owns_tv) return null; |
| 482 | const ty = (decl.val.castTag(.ty) orelse return null).data; | 485 | const ty = (decl.val.castTag(.ty) orelse return null).data; |
| 483 | switch (ty.tag()) { | 486 | switch (ty.tag()) { |
| 484 | .@"struct" => { | 487 | .@"struct" => { |
| 485 | const struct_obj = ty.castTag(.@"struct").?.data; | 488 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 486 | if (struct_obj.owner_decl != decl) return null; | 489 | assert(struct_obj.owner_decl == decl); |
| 487 | return &struct_obj.namespace; | 490 | return &struct_obj.namespace; |
| 488 | }, | 491 | }, |
| 489 | .enum_full => { | 492 | .enum_full => { |
| 490 | const enum_obj = ty.castTag(.enum_full).?.data; | 493 | const enum_obj = ty.castTag(.enum_full).?.data; |
| 491 | if (enum_obj.owner_decl != decl) return null; | 494 | assert(enum_obj.owner_decl == decl); |
| 492 | return &enum_obj.namespace; | 495 | return &enum_obj.namespace; |
| 493 | }, | 496 | }, |
| 494 | .empty_struct => { | 497 | .empty_struct => { |
| 495 | // design flaw, can't verify the owner is this decl | 498 | return ty.castTag(.empty_struct).?.data; |
| 496 | @panic("TODO can't implement getInnerNamespace for this type"); | | |
| 497 | }, | 499 | }, |
| 498 | .@"opaque" => { | 500 | .@"opaque" => { |
| 499 | @panic("TODO opaque types"); | 501 | @panic("TODO opaque types"); |
| 500 | }, | 502 | }, |
| 501 | .@"union", .union_tagged => { | 503 | .@"union", .union_tagged => { |
| 502 | const union_obj = ty.cast(Type.Payload.Union).?.data; | 504 | const union_obj = ty.cast(Type.Payload.Union).?.data; |
| 503 | if (union_obj.owner_decl != decl) return null; | 505 | assert(union_obj.owner_decl == decl); |
| 504 | return &union_obj.namespace; | 506 | return &union_obj.namespace; |
| 505 | }, | 507 | }, |
| 506 | | 508 | |
| ... | @@ -554,7 +556,11 @@ pub const Decl = struct { | ... | @@ -554,7 +556,11 @@ pub const Decl = struct { |
| 554 | | 556 | |
| 555 | .complete, | 557 | .complete, |
| 556 | .outdated, | 558 | .outdated, |
| 557 | => true, | 559 | => { |
| | 560 | if (!decl.owns_tv) |
| | 561 | return false; |
| | 562 | return decl.ty.hasCodeGenBits(); |
| | 563 | }, |
| 558 | }; | 564 | }; |
| 559 | } | 565 | } |
| 560 | }; | 566 | }; |
| ... | @@ -2838,6 +2844,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void { | ... | @@ -2838,6 +2844,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) InnerError!void { |
| 2838 | new_decl.ty = struct_ty; | 2844 | new_decl.ty = struct_ty; |
| 2839 | new_decl.val = struct_val; | 2845 | new_decl.val = struct_val; |
| 2840 | new_decl.has_tv = true; | 2846 | new_decl.has_tv = true; |
| | 2847 | new_decl.owns_tv = true; |
| 2841 | new_decl.analysis = .complete; | 2848 | new_decl.analysis = .complete; |
| 2842 | new_decl.generation = mod.generation; | 2849 | new_decl.generation = mod.generation; |
| 2843 | | 2850 | |
| ... | @@ -2948,7 +2955,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { | ... | @@ -2948,7 +2955,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { |
| 2948 | errdefer decl_arena.deinit(); | 2955 | errdefer decl_arena.deinit(); |
| 2949 | const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State); | 2956 | const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State); |
| 2950 | | 2957 | |
| 2951 | if (decl_tv.val.tag() == .function) { | 2958 | if (decl_tv.val.castTag(.function)) |fn_payload| { |
| 2952 | var prev_type_has_bits = false; | 2959 | var prev_type_has_bits = false; |
| 2953 | var prev_is_inline = false; | 2960 | var prev_is_inline = false; |
| 2954 | var type_changed = true; | 2961 | var type_changed = true; |
| ... | @@ -2956,10 +2963,8 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { | ... | @@ -2956,10 +2963,8 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { |
| 2956 | if (decl.has_tv) { | 2963 | if (decl.has_tv) { |
| 2957 | prev_type_has_bits = decl.ty.hasCodeGenBits(); | 2964 | prev_type_has_bits = decl.ty.hasCodeGenBits(); |
| 2958 | type_changed = !decl.ty.eql(decl_tv.ty); | 2965 | type_changed = !decl.ty.eql(decl_tv.ty); |
| 2959 | if (decl.val.castTag(.function)) |payload| { | 2966 | if (decl.getFunction()) |prev_func| { |
| 2960 | const prev_func = payload.data; | | |
| 2961 | prev_is_inline = prev_func.state == .inline_only; | 2967 | prev_is_inline = prev_func.state == .inline_only; |
| 2962 | prev_func.deinit(gpa); | | |
| 2963 | } | 2968 | } |
| 2964 | decl.clearValues(gpa); | 2969 | decl.clearValues(gpa); |
| 2965 | } | 2970 | } |
| ... | @@ -2969,6 +2974,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { | ... | @@ -2969,6 +2974,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { |
| 2969 | decl.align_val = try align_val.copy(&decl_arena.allocator); | 2974 | decl.align_val = try align_val.copy(&decl_arena.allocator); |
| 2970 | decl.linksection_val = try linksection_val.copy(&decl_arena.allocator); | 2975 | decl.linksection_val = try linksection_val.copy(&decl_arena.allocator); |
| 2971 | decl.has_tv = true; | 2976 | decl.has_tv = true; |
| | 2977 | decl.owns_tv = fn_payload.data.owner_decl == decl; |
| 2972 | decl_arena_state.* = decl_arena.state; | 2978 | decl_arena_state.* = decl_arena.state; |
| 2973 | decl.value_arena = decl_arena_state; | 2979 | decl.value_arena = decl_arena_state; |
| 2974 | decl.analysis = .complete; | 2980 | decl.analysis = .complete; |
| ... | @@ -3004,6 +3010,25 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { | ... | @@ -3004,6 +3010,25 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { |
| 3004 | decl.clearValues(gpa); | 3010 | decl.clearValues(gpa); |
| 3005 | } | 3011 | } |
| 3006 | | 3012 | |
| | 3013 | decl.owns_tv = false; |
| | 3014 | var queue_linker_work = false; |
| | 3015 | if (decl_tv.val.castTag(.variable)) |payload| { |
| | 3016 | const variable = payload.data; |
| | 3017 | if (variable.owner_decl == decl) { |
| | 3018 | decl.owns_tv = true; |
| | 3019 | queue_linker_work = true; |
| | 3020 | |
| | 3021 | const copied_init = try variable.init.copy(&decl_arena.allocator); |
| | 3022 | variable.init = copied_init; |
| | 3023 | } |
| | 3024 | } else if (decl_tv.val.castTag(.extern_fn)) |payload| { |
| | 3025 | const owner_decl = payload.data; |
| | 3026 | if (decl == owner_decl) { |
| | 3027 | decl.owns_tv = true; |
| | 3028 | queue_linker_work = true; |
| | 3029 | } |
| | 3030 | } |
| | 3031 | |
| 3007 | decl.ty = try decl_tv.ty.copy(&decl_arena.allocator); | 3032 | decl.ty = try decl_tv.ty.copy(&decl_arena.allocator); |
| 3008 | decl.val = try decl_tv.val.copy(&decl_arena.allocator); | 3033 | decl.val = try decl_tv.val.copy(&decl_arena.allocator); |
| 3009 | decl.align_val = try align_val.copy(&decl_arena.allocator); | 3034 | decl.align_val = try align_val.copy(&decl_arena.allocator); |
| ... | @@ -3014,13 +3039,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { | ... | @@ -3014,13 +3039,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { |
| 3014 | decl.analysis = .complete; | 3039 | decl.analysis = .complete; |
| 3015 | decl.generation = mod.generation; | 3040 | decl.generation = mod.generation; |
| 3016 | | 3041 | |
| 3017 | if (decl.is_exported) { | 3042 | if (queue_linker_work and decl.ty.hasCodeGenBits()) { |
| 3018 | const export_src = src; // TODO point to the export token | | |
| 3019 | // The scope needs to have the decl in it. | | |
| 3020 | try mod.analyzeExport(&block_scope.base, export_src, mem.spanZ(decl.name), decl); | | |
| 3021 | } | | |
| 3022 | | | |
| 3023 | if (decl.val.tag() == .extern_fn) { | | |
| 3024 | try mod.comp.bin_file.allocateDeclIndexes(decl); | 3043 | try mod.comp.bin_file.allocateDeclIndexes(decl); |
| 3025 | try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl }); | 3044 | try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl }); |
| 3026 | | 3045 | |
| ... | @@ -3029,6 +3048,13 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { | ... | @@ -3029,6 +3048,13 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { |
| 3029 | } | 3048 | } |
| 3030 | } | 3049 | } |
| 3031 | | 3050 | |
| | 3051 | if (decl.is_exported) { |
| | 3052 | const export_src = src; // TODO point to the export token |
| | 3053 | // The scope needs to have the decl in it. |
| | 3054 | try mod.analyzeExport(&block_scope.base, export_src, mem.spanZ(decl.name), decl); |
| | 3055 | } |
| | 3056 | |
| | 3057 | |
| 3032 | return type_changed; | 3058 | return type_changed; |
| 3033 | } | 3059 | } |
| 3034 | } | 3060 | } |
| ... | @@ -3531,6 +3557,7 @@ fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node | ... | @@ -3531,6 +3557,7 @@ fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node |
| 3531 | .src_node = src_node, | 3557 | .src_node = src_node, |
| 3532 | .src_line = undefined, | 3558 | .src_line = undefined, |
| 3533 | .has_tv = false, | 3559 | .has_tv = false, |
| | 3560 | .owns_tv = false, |
| 3534 | .ty = undefined, | 3561 | .ty = undefined, |
| 3535 | .val = undefined, | 3562 | .val = undefined, |
| 3536 | .align_val = undefined, | 3563 | .align_val = undefined, |
| ... | @@ -3779,6 +3806,7 @@ pub fn createAnonymousDeclNamed( | ... | @@ -3779,6 +3806,7 @@ pub fn createAnonymousDeclNamed( |
| 3779 | new_decl.ty = typed_value.ty; | 3806 | new_decl.ty = typed_value.ty; |
| 3780 | new_decl.val = typed_value.val; | 3807 | new_decl.val = typed_value.val; |
| 3781 | new_decl.has_tv = true; | 3808 | new_decl.has_tv = true; |
| | 3809 | new_decl.owns_tv = true; |
| 3782 | new_decl.analysis = .complete; | 3810 | new_decl.analysis = .complete; |
| 3783 | new_decl.generation = mod.generation; | 3811 | new_decl.generation = mod.generation; |
| 3784 | | 3812 | |