authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-14 17:41:22-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-14 17:41:22-07:00
logb4692c9a7808caabdf474c2acc6d6d3754e5e2e4
treea824991e12daf2e96be411926b82a123ccb2672b
parent9958652d92ee074fbd71a5d75a56341518cc0f99

stage2: improve Decl dependency management

* Do not report export collision errors until the very end, because it is possible, during an update, for a new export to be added before an old one is semantically analyzed to be deleted. In such a case there should be no compile error. - Likewise we defer emitting exports until the end when we know for sure what will happen. * Sema: Fix not adding a Decl dependency on imported files. * Sema: Properly add Decl dependencies for all identifier and namespace lookups. * After semantic analysis for a Decl, if it is still marked as `in_progress`, change it to `dependency_failure` because if the Decl itself failed, it would have already been changed during the call to add the compile error.

5 files changed, 145 insertions(+), 129 deletions(-)

BRANCH_TODO+7-4
...@@ -1,8 +1,7 @@...@@ -1,8 +1,7 @@
1 * get stage2 tests passing1 * get stage2 tests passing
2 - after the error from an empty file, "has no member main" is invalidated2 - spu-ii test is saying "unimplemented" for some reason
3 but the comptime block incorrectly does not get re-run3 - compile log test has wrong source loc
4 - segfault in one of the tests4 - extern variable has no type: TODO implement generateSymbol for int type 'i32'
5 - memory leaks
6 * modify stage2 tests so that only 1 uses _start and the rest use5 * modify stage2 tests so that only 1 uses _start and the rest use
7 pub fn main6 pub fn main
8 * modify stage2 CBE tests so that only 1 uses pub export main and the7 * modify stage2 CBE tests so that only 1 uses pub export main and the
...@@ -71,3 +70,7 @@...@@ -71,3 +70,7 @@
71 It will be unloaded if using cached ZIR.70 It will be unloaded if using cached ZIR.
72 71
73 * make AstGen smart enough to omit elided store_to_block_ptr instructions72 * make AstGen smart enough to omit elided store_to_block_ptr instructions
73
74 * repl: if you try `run` with -ofmt=c you get an access denied error because it
75 tries to execute the .c file as a child process instead of executing `zig run`
76 on it.
src/Compilation.zig+2
...@@ -1622,6 +1622,8 @@ pub fn update(self: *Compilation) !void {...@@ -1622,6 +1622,8 @@ pub fn update(self: *Compilation) !void {
1622 assert(decl.dependants.count() == 0);1622 assert(decl.dependants.count() == 0);
1623 try module.deleteDecl(decl, null);1623 try module.deleteDecl(decl, null);
1624 }1624 }
1625
1626 try module.processExports();
1625 }1627 }
1626 }1628 }
16271629
src/Module.zig+82-102
...@@ -41,14 +41,11 @@ root_pkg: *Package,...@@ -41,14 +41,11 @@ root_pkg: *Package,
41global_zir_cache: Compilation.Directory,41global_zir_cache: Compilation.Directory,
42/// Used by AstGen worker to load and store ZIR cache.42/// Used by AstGen worker to load and store ZIR cache.
43local_zir_cache: Compilation.Directory,43local_zir_cache: Compilation.Directory,
44/// It's rare for a decl to be exported, so we save memory by having a sparse map of44/// It's rare for a decl to be exported, so we save memory by having a sparse
45/// Decl pointers to details about them being exported.45/// map of Decl pointers to details about them being exported.
46/// The Export memory is owned by the `export_owners` table; the slice itself is owned by this table.46/// The Export memory is owned by the `export_owners` table; the slice itself
47/// The slice is guaranteed to not be empty.47/// is owned by this table. The slice is guaranteed to not be empty.
48decl_exports: std.AutoArrayHashMapUnmanaged(*Decl, []*Export) = .{},48decl_exports: std.AutoArrayHashMapUnmanaged(*Decl, []*Export) = .{},
49/// We track which export is associated with the given symbol name for quick
50/// detection of symbol collisions.
51symbol_exports: std.StringArrayHashMapUnmanaged(*Export) = .{},
52/// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl49/// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl
53/// is modified. Note that the key of this table is not the Decl being exported, but the Decl that50/// is modified. Note that the key of this table is not the Decl being exported, but the Decl that
54/// is performing the export of another Decl.51/// is performing the export of another Decl.
...@@ -144,6 +141,14 @@ pub const Export = struct {...@@ -144,6 +141,14 @@ pub const Export = struct {
144 failed_retryable,141 failed_retryable,
145 complete,142 complete,
146 },143 },
144
145 pub fn getSrcLoc(exp: Export) SrcLoc {
146 return .{
147 .file_scope = exp.owner_decl.namespace.file_scope,
148 .parent_decl_node = exp.owner_decl.src_node,
149 .lazy = exp.src,
150 };
151 }
147};152};
148153
149/// When Module emit_h field is non-null, each Decl is allocated via this struct, so that154/// When Module emit_h field is non-null, each Decl is allocated via this struct, so that
...@@ -2184,8 +2189,6 @@ pub fn deinit(mod: *Module) void {...@@ -2184,8 +2189,6 @@ pub fn deinit(mod: *Module) void {
2184 }2189 }
2185 mod.export_owners.deinit(gpa);2190 mod.export_owners.deinit(gpa);
21862191
2187 mod.symbol_exports.deinit(gpa);
2188
2189 var it = mod.global_error_set.iterator();2192 var it = mod.global_error_set.iterator();
2190 while (it.next()) |entry| {2193 while (it.next()) |entry| {
2191 gpa.free(entry.key);2194 gpa.free(entry.key);
...@@ -2779,7 +2782,10 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {...@@ -2779,7 +2782,10 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {
2779 for (decl.dependencies.items()) |entry| {2782 for (decl.dependencies.items()) |entry| {
2780 const dep = entry.key;2783 const dep = entry.key;
2781 dep.removeDependant(decl);2784 dep.removeDependant(decl);
2782 if (dep.dependants.items().len == 0 and !dep.deletion_flag) {2785 if (dep.dependants.count() == 0 and !dep.deletion_flag) {
2786 log.debug("insert {*} ({s}) dependant {*} ({s}) into deletion set", .{
2787 decl, decl.name, dep, dep.name,
2788 });
2783 // We don't perform a deletion here, because this Decl or another one2789 // We don't perform a deletion here, because this Decl or another one
2784 // may end up referencing it before the update is complete.2790 // may end up referencing it before the update is complete.
2785 dep.deletion_flag = true;2791 dep.deletion_flag = true;
...@@ -2795,11 +2801,18 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {...@@ -2795,11 +2801,18 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {
2795 };2801 };
27962802
2797 const type_changed = mod.semaDecl(decl) catch |err| switch (err) {2803 const type_changed = mod.semaDecl(decl) catch |err| switch (err) {
2798 error.OutOfMemory => return error.OutOfMemory,2804 error.AnalysisFail => {
2799 error.AnalysisFail => return error.AnalysisFail,2805 if (decl.analysis == .in_progress) {
2806 // If this decl caused the compile error, the analysis field would
2807 // be changed to indicate it was this Decl's fault. Because this
2808 // did not happen, we infer here that it was a dependency failure.
2809 decl.analysis = .dependency_failure;
2810 }
2811 return error.AnalysisFail;
2812 },
2800 else => {2813 else => {
2801 decl.analysis = .sema_failure_retryable;2814 decl.analysis = .sema_failure_retryable;
2802 try mod.failed_decls.ensureCapacity(mod.gpa, mod.failed_decls.items().len + 1);2815 try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);
2803 mod.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(2816 mod.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
2804 mod.gpa,2817 mod.gpa,
2805 decl.srcLoc(),2818 decl.srcLoc(),
...@@ -2818,7 +2831,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {...@@ -2818,7 +2831,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {
2818 const dep = entry.key;2831 const dep = entry.key;
2819 switch (dep.analysis) {2832 switch (dep.analysis) {
2820 .unreferenced => unreachable,2833 .unreferenced => unreachable,
2821 .in_progress => unreachable,2834 .in_progress => continue, // already doing analysis, ok
2822 .outdated => continue, // already queued for update2835 .outdated => continue, // already queued for update
28232836
2824 .file_failure,2837 .file_failure,
...@@ -3115,8 +3128,14 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3115,8 +3128,14 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
31153128
3116/// Returns the depender's index of the dependee.3129/// Returns the depender's index of the dependee.
3117pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !void {3130pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !void {
3118 try depender.dependencies.ensureCapacity(mod.gpa, depender.dependencies.count() + 1);3131 if (depender == dependee) return;
3119 try dependee.dependants.ensureCapacity(mod.gpa, dependee.dependants.count() + 1);3132
3133 log.debug("{*} ({s}) depends on {*} ({s})", .{
3134 depender, depender.name, dependee, dependee.name,
3135 });
3136
3137 try depender.dependencies.ensureUnusedCapacity(mod.gpa, 1);
3138 try dependee.dependants.ensureUnusedCapacity(mod.gpa, 1);
31203139
3121 if (dependee.deletion_flag) {3140 if (dependee.deletion_flag) {
3122 dependee.deletion_flag = false;3141 dependee.deletion_flag = false;
...@@ -3513,7 +3532,6 @@ fn deleteDeclExports(mod: *Module, decl: *Decl) void {...@@ -3513,7 +3532,6 @@ fn deleteDeclExports(mod: *Module, decl: *Decl) void {
3513 if (mod.failed_exports.swapRemove(exp)) |entry| {3532 if (mod.failed_exports.swapRemove(exp)) |entry| {
3514 entry.value.destroy(mod.gpa);3533 entry.value.destroy(mod.gpa);
3515 }3534 }
3516 _ = mod.symbol_exports.swapRemove(exp.options.name);
3517 mod.gpa.free(exp.options.name);3535 mod.gpa.free(exp.options.name);
3518 mod.gpa.destroy(exp);3536 mod.gpa.destroy(exp);
3519 }3537 }
...@@ -3726,38 +3744,6 @@ pub fn analyzeExport(...@@ -3726,38 +3744,6 @@ pub fn analyzeExport(
3726 de_gop.entry.value = try mod.gpa.realloc(de_gop.entry.value, de_gop.entry.value.len + 1);3744 de_gop.entry.value = try mod.gpa.realloc(de_gop.entry.value, de_gop.entry.value.len + 1);
3727 de_gop.entry.value[de_gop.entry.value.len - 1] = new_export;3745 de_gop.entry.value[de_gop.entry.value.len - 1] = new_export;
3728 errdefer de_gop.entry.value = mod.gpa.shrink(de_gop.entry.value, de_gop.entry.value.len - 1);3746 errdefer de_gop.entry.value = mod.gpa.shrink(de_gop.entry.value, de_gop.entry.value.len - 1);
3729
3730 if (mod.symbol_exports.get(symbol_name)) |other_export| {
3731 new_export.status = .failed_retryable;
3732 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
3733 const msg = try mod.errMsg(
3734 scope,
3735 src,
3736 "exported symbol collision: {s}",
3737 .{symbol_name},
3738 );
3739 errdefer msg.destroy(mod.gpa);
3740 const other_src_loc: SrcLoc = .{
3741 .file_scope = other_export.owner_decl.namespace.file_scope,
3742 .parent_decl_node = other_export.owner_decl.src_node,
3743 .lazy = other_export.src,
3744 };
3745 try mod.errNoteNonLazy(other_src_loc, msg, "other symbol here", .{});
3746 mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
3747 new_export.status = .failed;
3748 return;
3749 }
3750
3751 try mod.symbol_exports.putNoClobber(mod.gpa, symbol_name, new_export);
3752 mod.comp.bin_file.updateDeclExports(mod, exported_decl, de_gop.entry.value) catch |err| switch (err) {
3753 error.OutOfMemory => return error.OutOfMemory,
3754 else => {
3755 new_export.status = .failed_retryable;
3756 try mod.failed_exports.ensureCapacity(mod.gpa, mod.failed_exports.items().len + 1);
3757 const msg = try mod.errMsg(scope, src, "unable to export: {s}", .{@errorName(err)});
3758 mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
3759 },
3760 };
3761}3747}
3762pub fn constInst(mod: *Module, arena: *Allocator, src: LazySrcLoc, typed_value: TypedValue) !*ir.Inst {3748pub fn constInst(mod: *Module, arena: *Allocator, src: LazySrcLoc, typed_value: TypedValue) !*ir.Inst {
3763 const const_inst = try arena.create(ir.Inst.Constant);3749 const const_inst = try arena.create(ir.Inst.Constant);
...@@ -3903,59 +3889,6 @@ pub fn getNextAnonNameIndex(mod: *Module) usize {...@@ -3903,59 +3889,6 @@ pub fn getNextAnonNameIndex(mod: *Module) usize {
3903 return @atomicRmw(usize, &mod.next_anon_name_index, .Add, 1, .Monotonic);3889 return @atomicRmw(usize, &mod.next_anon_name_index, .Add, 1, .Monotonic);
3904}3890}
39053891
3906/// This looks up a bare identifier in the given scope. This will walk up the tree of namespaces
3907/// in scope and check each one for the identifier.
3908/// TODO emit a compile error if more than one decl would be matched.
3909pub fn lookupIdentifier(
3910 mod: *Module,
3911 scope: *Scope,
3912 ident_name: []const u8,
3913) error{AnalysisFail}!?*Decl {
3914 var namespace = scope.namespace();
3915 while (true) {
3916 if (try mod.lookupInNamespace(namespace, ident_name, false)) |decl| {
3917 return decl;
3918 }
3919 namespace = namespace.parent orelse break;
3920 }
3921 return null;
3922}
3923
3924/// This looks up a member of a specific namespace. It is affected by `usingnamespace` but
3925/// only for ones in the specified namespace.
3926pub fn lookupInNamespace(
3927 mod: *Module,
3928 namespace: *Scope.Namespace,
3929 ident_name: []const u8,
3930 only_pub_usingnamespaces: bool,
3931) error{AnalysisFail}!?*Decl {
3932 const owner_decl = namespace.getDecl();
3933 if (owner_decl.analysis == .file_failure) {
3934 return error.AnalysisFail;
3935 }
3936
3937 // TODO the decl doing the looking up needs to create a decl dependency
3938 // TODO implement usingnamespace
3939 if (namespace.decls.get(ident_name)) |decl| {
3940 return decl;
3941 }
3942 return null;
3943 //// TODO handle decl collision with usingnamespace
3944 //// on each usingnamespace decl here.
3945 //{
3946 // var it = namespace.usingnamespace_set.iterator();
3947 // while (it.next()) |entry| {
3948 // const other_ns = entry.key;
3949 // const other_is_pub = entry.value;
3950 // if (only_pub_usingnamespaces and !other_is_pub) continue;
3951 // // TODO handle cycles
3952 // if (mod.lookupInNamespace(other_ns, ident_name, true)) |decl| {
3953 // return decl;
3954 // }
3955 // }
3956 //}
3957}
3958
3959pub fn makeIntType(arena: *Allocator, signedness: std.builtin.Signedness, bits: u16) !Type {3892pub fn makeIntType(arena: *Allocator, signedness: std.builtin.Signedness, bits: u16) !Type {
3960 const int_payload = try arena.create(Type.Payload.Bits);3893 const int_payload = try arena.create(Type.Payload.Bits);
3961 int_payload.* = .{3894 int_payload.* = .{
...@@ -4922,3 +4855,50 @@ pub fn processOutdatedAndDeletedDecls(mod: *Module) !void {...@@ -4922,3 +4855,50 @@ pub fn processOutdatedAndDeletedDecls(mod: *Module) !void {
4922 try mod.markOutdatedDecl(entry.key);4855 try mod.markOutdatedDecl(entry.key);
4923 }4856 }
4924}4857}
4858
4859/// Called from `Compilation.update`, after everything is done, just before
4860/// reporting compile errors. In this function we emit exported symbol collision
4861/// errors and communicate exported symbols to the linker backend.
4862pub fn processExports(mod: *Module) !void {
4863 const gpa = mod.gpa;
4864 // Map symbol names to `Export` for name collision detection.
4865 var symbol_exports: std.StringArrayHashMapUnmanaged(*Export) = .{};
4866 defer symbol_exports.deinit(gpa);
4867
4868 for (mod.decl_exports.items()) |entry| {
4869 const exported_decl = entry.key;
4870 const exports = entry.value;
4871 for (exports) |new_export| {
4872 const gop = try symbol_exports.getOrPut(gpa, new_export.options.name);
4873 if (gop.found_existing) {
4874 new_export.status = .failed_retryable;
4875 try mod.failed_exports.ensureUnusedCapacity(gpa, 1);
4876 const src_loc = new_export.getSrcLoc();
4877 const msg = try ErrorMsg.create(gpa, src_loc, "exported symbol collision: {s}", .{
4878 new_export.options.name,
4879 });
4880 errdefer msg.destroy(gpa);
4881 const other_export = gop.entry.value;
4882 const other_src_loc = other_export.getSrcLoc();
4883 try mod.errNoteNonLazy(other_src_loc, msg, "other symbol here", .{});
4884 mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
4885 new_export.status = .failed;
4886 } else {
4887 gop.entry.value = new_export;
4888 }
4889 }
4890 mod.comp.bin_file.updateDeclExports(mod, exported_decl, exports) catch |err| switch (err) {
4891 error.OutOfMemory => return error.OutOfMemory,
4892 else => {
4893 const new_export = exports[0];
4894 new_export.status = .failed_retryable;
4895 try mod.failed_exports.ensureUnusedCapacity(gpa, 1);
4896 const src_loc = new_export.getSrcLoc();
4897 const msg = try ErrorMsg.create(gpa, src_loc, "unable to export: {s}", .{
4898 @errorName(err),
4899 });
4900 mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
4901 },
4902 };
4903 }
4904}
src/Sema.zig+44-13
...@@ -2070,15 +2070,43 @@ fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError...@@ -2070,15 +2070,43 @@ fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError
2070}2070}
20712071
2072fn lookupIdentifier(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, name: []const u8) !*Decl {2072fn lookupIdentifier(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, name: []const u8) !*Decl {
2073 const mod = sema.mod;2073 // TODO emit a compile error if more than one decl would be matched.
2074 const decl = (try mod.lookupIdentifier(&sema.namespace.base, name)) orelse {2074 var namespace = sema.namespace;
2075 // TODO insert a "dependency on the non-existence of a decl" here to make this2075 while (true) {
2076 // compile error go away when the decl is introduced. This data should be in a global2076 if (try sema.lookupInNamespace(namespace, name)) |decl| {
2077 // sparse map since it is only relevant when a compile error occurs.2077 return decl;
2078 return mod.fail(&block.base, src, "use of undeclared identifier '{s}'", .{name});2078 }
2079 };2079 namespace = namespace.parent orelse break;
2080 _ = try mod.declareDeclDependency(sema.owner_decl, decl);2080 }
2081 return decl;2081 return sema.mod.fail(&block.base, src, "use of undeclared identifier '{s}'", .{name});
2082}
2083
2084/// This looks up a member of a specific namespace. It is affected by `usingnamespace` but
2085/// only for ones in the specified namespace.
2086fn lookupInNamespace(
2087 sema: *Sema,
2088 namespace: *Scope.Namespace,
2089 ident_name: []const u8,
2090) InnerError!?*Decl {
2091 const namespace_decl = namespace.getDecl();
2092 if (namespace_decl.analysis == .file_failure) {
2093 try sema.mod.declareDeclDependency(sema.owner_decl, namespace_decl);
2094 return error.AnalysisFail;
2095 }
2096
2097 // TODO implement usingnamespace
2098 if (namespace.decls.get(ident_name)) |decl| {
2099 try sema.mod.declareDeclDependency(sema.owner_decl, decl);
2100 return decl;
2101 }
2102 log.debug("{*} ({s}) depends on non-existence of '{s}' in {*} ({s})", .{
2103 sema.owner_decl, sema.owner_decl.name, ident_name, namespace_decl, namespace_decl.name,
2104 });
2105 // TODO This dependency is too strong. Really, it should only be a dependency
2106 // on the non-existence of `ident_name` in the namespace. We can lessen the number of
2107 // outdated declarations by making this dependency more sophisticated.
2108 try sema.mod.declareDeclDependency(sema.owner_decl, namespace_decl);
2109 return null;
2082}2110}
20832111
2084fn zirCall(2112fn zirCall(
...@@ -4395,7 +4423,7 @@ fn zirHasDecl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError...@@ -4395,7 +4423,7 @@ fn zirHasDecl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError
4395 "expected struct, enum, union, or opaque, found '{}'",4423 "expected struct, enum, union, or opaque, found '{}'",
4396 .{container_type},4424 .{container_type},
4397 );4425 );
4398 if (try mod.lookupInNamespace(namespace, decl_name, true)) |decl| {4426 if (try sema.lookupInNamespace(namespace, decl_name)) |decl| {
4399 if (decl.is_pub or decl.namespace.file_scope == block.base.namespace().file_scope) {4427 if (decl.is_pub or decl.namespace.file_scope == block.base.namespace().file_scope) {
4400 return mod.constBool(arena, src, true);4428 return mod.constBool(arena, src, true);
4401 }4429 }
...@@ -4423,7 +4451,9 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!...@@ -4423,7 +4451,9 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!
4423 },4451 },
4424 };4452 };
4425 try mod.semaFile(result.file);4453 try mod.semaFile(result.file);
4426 return mod.constType(sema.arena, src, result.file.root_decl.?.ty);4454 const file_root_decl = result.file.root_decl.?;
4455 try sema.mod.declareDeclDependency(sema.owner_decl, file_root_decl);
4456 return mod.constType(sema.arena, src, file_root_decl.ty);
4427}4457}
44284458
4429fn zirShl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {4459fn zirShl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
...@@ -6327,7 +6357,7 @@ fn analyzeNamespaceLookup(...@@ -6327,7 +6357,7 @@ fn analyzeNamespaceLookup(
6327) InnerError!?*Inst {6357) InnerError!?*Inst {
6328 const mod = sema.mod;6358 const mod = sema.mod;
6329 const gpa = sema.gpa;6359 const gpa = sema.gpa;
6330 if (try mod.lookupInNamespace(namespace, decl_name, true)) |decl| {6360 if (try sema.lookupInNamespace(namespace, decl_name)) |decl| {
6331 if (!decl.is_pub and decl.namespace.file_scope != block.getFileScope()) {6361 if (!decl.is_pub and decl.namespace.file_scope != block.getFileScope()) {
6332 const msg = msg: {6362 const msg = msg: {
6333 const msg = try mod.errMsg(&block.base, src, "'{s}' is not marked 'pub'", .{6363 const msg = try mod.errMsg(&block.base, src, "'{s}' is not marked 'pub'", .{
...@@ -6752,7 +6782,7 @@ fn analyzeDeclVal(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl...@@ -6752,7 +6782,7 @@ fn analyzeDeclVal(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl
6752}6782}
67536783
6754fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl) InnerError!*Inst {6784fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl) InnerError!*Inst {
6755 _ = try sema.mod.declareDeclDependency(sema.owner_decl, decl);6785 try sema.mod.declareDeclDependency(sema.owner_decl, decl);
6756 sema.mod.ensureDeclAnalyzed(decl) catch |err| {6786 sema.mod.ensureDeclAnalyzed(decl) catch |err| {
6757 if (sema.func) |func| {6787 if (sema.func) |func| {
6758 func.state = .dependency_failure;6788 func.state = .dependency_failure;
...@@ -7544,3 +7574,4 @@ fn enumFieldSrcLoc(...@@ -7544,3 +7574,4 @@ fn enumFieldSrcLoc(
7544 }7574 }
7545 } else unreachable;7575 } else unreachable;
7546}7576}
7577
test/stage2/cbe.zig+10-10
...@@ -676,7 +676,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -676,7 +676,7 @@ pub fn addCases(ctx: *TestContext) !void {
676676
677 case.addError(677 case.addError(
678 \\const E1 = enum { a, b, c, b, d };678 \\const E1 = enum { a, b, c, b, d };
679 \\export fn foo() void {679 \\pub export fn main() c_int {
680 \\ const x = E1.a;680 \\ const x = E1.a;
681 \\}681 \\}
682 , &.{682 , &.{
...@@ -685,7 +685,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -685,7 +685,7 @@ pub fn addCases(ctx: *TestContext) !void {
685 });685 });
686686
687 case.addError(687 case.addError(
688 \\export fn foo() void {688 \\pub export fn main() c_int {
689 \\ const a = true;689 \\ const a = true;
690 \\ const b = @enumToInt(a);690 \\ const b = @enumToInt(a);
691 \\}691 \\}
...@@ -694,7 +694,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -694,7 +694,7 @@ pub fn addCases(ctx: *TestContext) !void {
694 });694 });
695695
696 case.addError(696 case.addError(
697 \\export fn foo() void {697 \\pub export fn main() c_int {
698 \\ const a = 1;698 \\ const a = 1;
699 \\ const b = @intToEnum(bool, a);699 \\ const b = @intToEnum(bool, a);
700 \\}700 \\}
...@@ -704,7 +704,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -704,7 +704,7 @@ pub fn addCases(ctx: *TestContext) !void {
704704
705 case.addError(705 case.addError(
706 \\const E = enum { a, b, c };706 \\const E = enum { a, b, c };
707 \\export fn foo() void {707 \\pub export fn main() c_int {
708 \\ const b = @intToEnum(E, 3);708 \\ const b = @intToEnum(E, 3);
709 \\}709 \\}
710 , &.{710 , &.{
...@@ -714,7 +714,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -714,7 +714,7 @@ pub fn addCases(ctx: *TestContext) !void {
714714
715 case.addError(715 case.addError(
716 \\const E = enum { a, b, c };716 \\const E = enum { a, b, c };
717 \\export fn foo() void {717 \\pub export fn main() c_int {
718 \\ var x: E = .a;718 \\ var x: E = .a;
719 \\ switch (x) {719 \\ switch (x) {
720 \\ .a => {},720 \\ .a => {},
...@@ -729,7 +729,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -729,7 +729,7 @@ pub fn addCases(ctx: *TestContext) !void {
729729
730 case.addError(730 case.addError(
731 \\const E = enum { a, b, c };731 \\const E = enum { a, b, c };
732 \\export fn foo() void {732 \\pub export fn main() c_int {
733 \\ var x: E = .a;733 \\ var x: E = .a;
734 \\ switch (x) {734 \\ switch (x) {
735 \\ .a => {},735 \\ .a => {},
...@@ -745,7 +745,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -745,7 +745,7 @@ pub fn addCases(ctx: *TestContext) !void {
745745
746 case.addError(746 case.addError(
747 \\const E = enum { a, b, c };747 \\const E = enum { a, b, c };
748 \\export fn foo() void {748 \\pub export fn main() c_int {
749 \\ var x: E = .a;749 \\ var x: E = .a;
750 \\ switch (x) {750 \\ switch (x) {
751 \\ .a => {},751 \\ .a => {},
...@@ -760,7 +760,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -760,7 +760,7 @@ pub fn addCases(ctx: *TestContext) !void {
760760
761 case.addError(761 case.addError(
762 \\const E = enum { a, b, c };762 \\const E = enum { a, b, c };
763 \\export fn foo() void {763 \\pub export fn main() c_int {
764 \\ var x: E = .a;764 \\ var x: E = .a;
765 \\ switch (x) {765 \\ switch (x) {
766 \\ .a => {},766 \\ .a => {},
...@@ -775,7 +775,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -775,7 +775,7 @@ pub fn addCases(ctx: *TestContext) !void {
775775
776 case.addError(776 case.addError(
777 \\const E = enum { a, b, c };777 \\const E = enum { a, b, c };
778 \\export fn foo() void {778 \\pub export fn main() c_int {
779 \\ var x = E.d;779 \\ var x = E.d;
780 \\}780 \\}
781 , &.{781 , &.{
...@@ -785,7 +785,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -785,7 +785,7 @@ pub fn addCases(ctx: *TestContext) !void {
785785
786 case.addError(786 case.addError(
787 \\const E = enum { a, b, c };787 \\const E = enum { a, b, c };
788 \\export fn foo() void {788 \\pub export fn main() c_int {
789 \\ var x: E = .d;789 \\ var x: E = .d;
790 \\}790 \\}
791 , &.{791 , &.{