authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-11 14:17:52-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-11 14:17:52-07:00
logbcf15e39e2d4e2243f475852aca7749e40a70fbd
tree367c697ea25a0649a263d13131ffaf0ec3f82ad4
parentdae22a0a1f13cc963e96cd704941eed29b8dde27

stage2: add `owns_tv` flag to `Module.Decl`

Decl objects need to know whether they are the owner of the Type/Value associated with them, in order to decide whether to destroy the associated Namespace, Fn, or Var when cleaning up.

6 files changed, 128 insertions(+), 59 deletions(-)

BRANCH_TODO-10
...@@ -1,13 +1,3 @@...@@ -1,13 +1,3 @@
1 * The next problem is that when trying to deinitialize everything, when we
2 deinit a Decl that is the owner of a Namespace, there may still be other Decl
3 objects that reference that Namespace. They want to check if they are the owner
4 in order to find out if they should destroy it. But they can't check if they are
5 the owner because the owner_decl field is destroyed.
6 So there's a memory management problem to solve. We could easily solve this with
7 ref counting or whatever but the goal is to not introduce extra overhead / unnecessary
8 fields just to help figure out how to free stuff. So come up with some way to make
9 this sound, and easily debuggable when something goes wrong.
10
11 * get stage2 tests passing1 * get stage2 tests passing
12 * modify stage2 tests so that only 1 uses _start and the rest use2 * modify stage2 tests so that only 1 uses _start and the rest use
13 pub fn main3 pub fn main
src/Module.zig+57-29
...@@ -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 cleared234 /// 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 }
312315
...@@ -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 }
450453
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 }
460463
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 }
469472
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 }
476479
...@@ -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 decl498 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 },
506508
...@@ -554,7 +556,11 @@ pub const Decl = struct {...@@ -554,7 +556,11 @@ pub const Decl = struct {
554556
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;
28432850
...@@ -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);
29502957
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 }
30063012
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;
30163041
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 });
30263045
...@@ -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 }
30313050
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;
37843812
src/Sema.zig+1-1
...@@ -5867,7 +5867,7 @@ fn zirVarExtended(...@@ -5867,7 +5867,7 @@ fn zirVarExtended(
5867 extra_index += 1;5867 extra_index += 1;
5868 const init_tv = try sema.resolveInstConst(block, init_src, init_ref);5868 const init_tv = try sema.resolveInstConst(block, init_src, init_ref);
5869 break :blk init_tv.val;5869 break :blk init_tv.val;
5870 } else Value.initTag(.null_value);5870 } else Value.initTag(.unreachable_value);
58715871
5872 if (!var_ty.isValidVarType(small.is_extern)) {5872 if (!var_ty.isValidVarType(small.is_extern)) {
5873 return sema.mod.fail(&block.base, mut_src, "variable of type '{}' must be const", .{5873 return sema.mod.fail(&block.base, mut_src, "variable of type '{}' must be const", .{
src/codegen/c.zig+51-4
...@@ -30,6 +30,7 @@ pub const CValue = union(enum) {...@@ -30,6 +30,7 @@ pub const CValue = union(enum) {
30 arg: usize,30 arg: usize,
31 /// By-value31 /// By-value
32 decl: *Decl,32 decl: *Decl,
33 decl_ref: *Decl,
33};34};
3435
35pub const CValueMap = std.AutoHashMap(*Inst, CValue);36pub const CValueMap = std.AutoHashMap(*Inst, CValue);
...@@ -117,6 +118,7 @@ pub const Object = struct {...@@ -117,6 +118,7 @@ pub const Object = struct {
117 .constant => |inst| return o.dg.renderValue(w, inst.ty, inst.value().?),118 .constant => |inst| return o.dg.renderValue(w, inst.ty, inst.value().?),
118 .arg => |i| return w.print("a{d}", .{i}),119 .arg => |i| return w.print("a{d}", .{i}),
119 .decl => |decl| return w.writeAll(mem.span(decl.name)),120 .decl => |decl| return w.writeAll(mem.span(decl.name)),
121 .decl_ref => |decl| return w.print("&{s}", .{decl.name}),
120 }122 }
121 }123 }
122124
...@@ -528,13 +530,17 @@ pub const DeclGen = struct {...@@ -528,13 +530,17 @@ pub const DeclGen = struct {
528 }530 }
529 }531 }
530532
531 fn functionIsGlobal(dg: *DeclGen, tv: TypedValue) bool {533 fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool {
532 switch (tv.val.tag()) {534 switch (tv.val.tag()) {
533 .extern_fn => return true,535 .extern_fn => return true,
534 .function => {536 .function => {
535 const func = tv.val.castTag(.function).?.data;537 const func = tv.val.castTag(.function).?.data;
536 return dg.module.decl_exports.contains(func.owner_decl);538 return dg.module.decl_exports.contains(func.owner_decl);
537 },539 },
540 .variable => {
541 const variable = tv.val.castTag(.variable).?.data;
542 return dg.module.decl_exports.contains(variable.owner_decl);
543 },
538 else => unreachable,544 else => unreachable,
539 }545 }
540 }546 }
...@@ -549,7 +555,7 @@ pub fn genDecl(o: *Object) !void {...@@ -549,7 +555,7 @@ pub fn genDecl(o: *Object) !void {
549 .val = o.dg.decl.val,555 .val = o.dg.decl.val,
550 };556 };
551 if (tv.val.castTag(.function)) |func_payload| {557 if (tv.val.castTag(.function)) |func_payload| {
552 const is_global = o.dg.functionIsGlobal(tv);558 const is_global = o.dg.declIsGlobal(tv);
553 const fwd_decl_writer = o.dg.fwd_decl.writer();559 const fwd_decl_writer = o.dg.fwd_decl.writer();
554 if (is_global) {560 if (is_global) {
555 try fwd_decl_writer.writeAll("ZIG_EXTERN_C ");561 try fwd_decl_writer.writeAll("ZIG_EXTERN_C ");
...@@ -570,6 +576,30 @@ pub fn genDecl(o: *Object) !void {...@@ -570,6 +576,30 @@ pub fn genDecl(o: *Object) !void {
570 try writer.writeAll("ZIG_EXTERN_C ");576 try writer.writeAll("ZIG_EXTERN_C ");
571 try o.dg.renderFunctionSignature(writer, true);577 try o.dg.renderFunctionSignature(writer, true);
572 try writer.writeAll(";\n");578 try writer.writeAll(";\n");
579 } else if (tv.val.castTag(.variable)) |var_payload| {
580 const variable: *Module.Var = var_payload.data;
581 const is_global = o.dg.declIsGlobal(tv);
582 const fwd_decl_writer = o.dg.fwd_decl.writer();
583 if (is_global or variable.is_extern) {
584 try fwd_decl_writer.writeAll("ZIG_EXTERN_C ");
585 }
586 if (variable.is_threadlocal) {
587 try fwd_decl_writer.writeAll("zig_threadlocal ");
588 }
589 try o.dg.renderType(fwd_decl_writer, o.dg.decl.ty);
590 const decl_name = mem.span(o.dg.decl.name);
591 try fwd_decl_writer.print(" {s};\n", .{decl_name});
592
593 try o.indent_writer.insertNewline();
594 const w = o.writer();
595 try o.dg.renderType(w, o.dg.decl.ty);
596 try w.print(" {s} = ", .{decl_name});
597 if (variable.init.tag() != .unreachable_value) {
598 try o.dg.renderValue(w, tv.ty, variable.init);
599 }
600 try w.writeAll(";");
601 try o.indent_writer.insertNewline();
602
573 } else {603 } else {
574 const writer = o.writer();604 const writer = o.writer();
575 try writer.writeAll("static ");605 try writer.writeAll("static ");
...@@ -598,7 +628,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {...@@ -598,7 +628,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
598628
599 switch (tv.ty.zigTypeTag()) {629 switch (tv.ty.zigTypeTag()) {
600 .Fn => {630 .Fn => {
601 const is_global = dg.functionIsGlobal(tv);631 const is_global = dg.declIsGlobal(tv);
602 if (is_global) {632 if (is_global) {
603 try writer.writeAll("ZIG_EXTERN_C ");633 try writer.writeAll("ZIG_EXTERN_C ");
604 }634 }
...@@ -696,7 +726,7 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi...@@ -696,7 +726,7 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
696 .wrap_errunion_err => try genWrapErrUnionErr(o, inst.castTag(.wrap_errunion_err).?),726 .wrap_errunion_err => try genWrapErrUnionErr(o, inst.castTag(.wrap_errunion_err).?),
697 .br_block_flat => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for br_block_flat", .{}),727 .br_block_flat => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for br_block_flat", .{}),
698 .ptrtoint => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for ptrtoint", .{}),728 .ptrtoint => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for ptrtoint", .{}),
699 .varptr => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for varptr", .{}),729 .varptr => try genVarPtr(o, inst.castTag(.varptr).?),
700 .floatcast => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for floatcast", .{}),730 .floatcast => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for floatcast", .{}),
701 };731 };
702 switch (result_value) {732 switch (result_value) {
...@@ -709,6 +739,10 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi...@@ -709,6 +739,10 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
709 try writer.writeAll("}");739 try writer.writeAll("}");
710}740}
711741
742fn genVarPtr(o: *Object, inst: *Inst.VarPtr) !CValue {
743 return CValue{ .decl_ref = inst.variable.owner_decl };
744}
745
712fn genAlloc(o: *Object, alloc: *Inst.NoOp) !CValue {746fn genAlloc(o: *Object, alloc: *Inst.NoOp) !CValue {
713 const writer = o.writer();747 const writer = o.writer();
714748
...@@ -743,6 +777,12 @@ fn genLoad(o: *Object, inst: *Inst.UnOp) !CValue {...@@ -743,6 +777,12 @@ fn genLoad(o: *Object, inst: *Inst.UnOp) !CValue {
743 try o.writeCValue(writer, wrapped);777 try o.writeCValue(writer, wrapped);
744 try writer.writeAll(";\n");778 try writer.writeAll(";\n");
745 },779 },
780 .decl_ref => |decl| {
781 const wrapped: CValue = .{ .decl = decl };
782 try writer.writeAll(" = ");
783 try o.writeCValue(writer, wrapped);
784 try writer.writeAll(";\n");
785 },
746 else => {786 else => {
747 try writer.writeAll(" = *");787 try writer.writeAll(" = *");
748 try o.writeCValue(writer, operand);788 try o.writeCValue(writer, operand);
...@@ -791,6 +831,13 @@ fn genStore(o: *Object, inst: *Inst.BinOp) !CValue {...@@ -791,6 +831,13 @@ fn genStore(o: *Object, inst: *Inst.BinOp) !CValue {
791 try o.writeCValue(writer, src_val);831 try o.writeCValue(writer, src_val);
792 try writer.writeAll(";\n");832 try writer.writeAll(";\n");
793 },833 },
834 .decl_ref => |decl| {
835 const dest: CValue = .{ .decl = decl };
836 try o.writeCValue(writer, dest);
837 try writer.writeAll(" = ");
838 try o.writeCValue(writer, src_val);
839 try writer.writeAll(";\n");
840 },
794 else => {841 else => {
795 try writer.writeAll("*");842 try writer.writeAll("*");
796 try o.writeCValue(writer, dest_ptr);843 try o.writeCValue(writer, dest_ptr);
src/link/C/zig.h+18-14
...@@ -1,25 +1,15 @@...@@ -1,25 +1,15 @@
1#if __STDC_VERSION__ >= 199901L
2#include <stdbool.h>
3#else
4#define bool unsigned char
5#define true 1
6#define false 0
7#endif
8
9#if __STDC_VERSION__ >= 201112L1#if __STDC_VERSION__ >= 201112L
10#define zig_noreturn _Noreturn2#define zig_noreturn _Noreturn
3#define zig_threadlocal thread_local
11#elif __GNUC__4#elif __GNUC__
12#define zig_noreturn __attribute__ ((noreturn))5#define zig_noreturn __attribute__ ((noreturn))
6#define zig_threadlocal __thread
13#elif _MSC_VER7#elif _MSC_VER
14#define zig_noreturn __declspec(noreturn)8#define zig_noreturn __declspec(noreturn)
9#define zig_threadlocal __declspec(thread)
15#else10#else
16#define zig_noreturn11#define zig_noreturn
17#endif12#define zig_threadlocal zig_threadlocal_unavailable
18
19#if defined(__GNUC__)
20#define zig_unreachable() __builtin_unreachable()
21#else
22#define zig_unreachable()
23#endif13#endif
2414
25#if __STDC_VERSION__ >= 199901L15#if __STDC_VERSION__ >= 199901L
...@@ -30,6 +20,20 @@...@@ -30,6 +20,20 @@
30#define ZIG_RESTRICT20#define ZIG_RESTRICT
31#endif21#endif
3222
23#if __STDC_VERSION__ >= 199901L
24#include <stdbool.h>
25#else
26#define bool unsigned char
27#define true 1
28#define false 0
29#endif
30
31#if defined(__GNUC__)
32#define zig_unreachable() __builtin_unreachable()
33#else
34#define zig_unreachable()
35#endif
36
33#ifdef __cplusplus37#ifdef __cplusplus
34#define ZIG_EXTERN_C extern "C"38#define ZIG_EXTERN_C extern "C"
35#else39#else
test/stage2/cbe.zig+1-1
...@@ -517,7 +517,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -517,7 +517,7 @@ pub fn addCases(ctx: *TestContext) !void {
517 \\}517 \\}
518 , &.{518 , &.{
519 ":3:21: error: missing struct field: x",519 ":3:21: error: missing struct field: x",
520 ":1:15: note: struct 'Point' declared here",520 ":1:15: note: struct 'test_case.Point' declared here",
521 });521 });
522 case.addError(522 case.addError(
523 \\const Point = struct { x: i32, y: i32 };523 \\const Point = struct { x: i32, y: i32 };