aboutsummaryrefslogtreecommitdiff
path: root/src/Module.zig
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2021-09-13 23:12:19 +0200
committerJakub Konka <kubkon@jakubkonka.com>2021-09-13 23:40:38 +0200
commita38b636045c0384faad1565d47dfbf774821021e (patch)
treea78193473fd5b725feaf2762b10cfc189a26a325 /src/Module.zig
parent760241ce50eaa9031339f6b591358b53f5797486 (diff)
parentf011f13933b72f4d63a5f635c7646b68beee726e (diff)
downloadzig-a38b636045c0384faad1565d47dfbf774821021e.tar.gz
zig-a38b636045c0384faad1565d47dfbf774821021e.zip
Merge remote-tracking branch 'origin/master' into zld-incr
Diffstat (limited to 'src/Module.zig')
-rw-r--r--src/Module.zig115
1 files changed, 78 insertions, 37 deletions
diff --git a/src/Module.zig b/src/Module.zig
index 4ed39c9954..07b86c0d51 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -11,7 +11,7 @@ const log = std.log.scoped(.module);
const BigIntConst = std.math.big.int.Const;
const BigIntMutable = std.math.big.int.Mutable;
const Target = std.Target;
-const ast = std.zig.ast;
+const Ast = std.zig.Ast;
const Module = @This();
const Compilation = @import("Compilation.zig");
@@ -291,7 +291,7 @@ pub const Decl = struct {
generation: u32,
/// The AST node index of this declaration.
/// Must be recomputed when the corresponding source file is modified.
- src_node: ast.Node.Index,
+ src_node: Ast.Node.Index,
/// Line number corresponding to `src_node`. Stored separately so that source files
/// do not need to be loaded into memory in order to compute debug line numbers.
src_line: u32,
@@ -365,6 +365,8 @@ pub const Decl = struct {
/// Decl is marked alive, then it sends the Decl to the linker. Otherwise it
/// deletes the Decl on the spot.
alive: bool,
+ /// Whether the Decl is a `usingnamespace` declaration.
+ is_usingnamespace: bool,
/// Represents the position of the code in the output file.
/// This is populated regardless of semantic analysis and code generation.
@@ -497,19 +499,19 @@ pub const Decl = struct {
return decl.src_line + offset;
}
- pub fn relativeToNodeIndex(decl: Decl, offset: i32) ast.Node.Index {
- return @bitCast(ast.Node.Index, offset + @bitCast(i32, decl.src_node));
+ pub fn relativeToNodeIndex(decl: Decl, offset: i32) Ast.Node.Index {
+ return @bitCast(Ast.Node.Index, offset + @bitCast(i32, decl.src_node));
}
- pub fn nodeIndexToRelative(decl: Decl, node_index: ast.Node.Index) i32 {
+ pub fn nodeIndexToRelative(decl: Decl, node_index: Ast.Node.Index) i32 {
return @bitCast(i32, node_index) - @bitCast(i32, decl.src_node);
}
- pub fn tokSrcLoc(decl: Decl, token_index: ast.TokenIndex) LazySrcLoc {
+ pub fn tokSrcLoc(decl: Decl, token_index: Ast.TokenIndex) LazySrcLoc {
return .{ .token_offset = token_index - decl.srcToken() };
}
- pub fn nodeSrcLoc(decl: Decl, node_index: ast.Node.Index) LazySrcLoc {
+ pub fn nodeSrcLoc(decl: Decl, node_index: Ast.Node.Index) LazySrcLoc {
return .{ .node_offset = decl.nodeIndexToRelative(node_index) };
}
@@ -525,7 +527,7 @@ pub const Decl = struct {
};
}
- pub fn srcToken(decl: Decl) ast.TokenIndex {
+ pub fn srcToken(decl: Decl) Ast.TokenIndex {
const tree = &decl.namespace.file_scope.tree;
return tree.firstToken(decl.src_node);
}
@@ -1008,6 +1010,11 @@ pub const Scope = struct {
anon_decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},
+ /// Key is usingnamespace Decl itself. To find the namespace being included,
+ /// the Decl Value has to be resolved as a Type which has a Namespace.
+ /// Value is whether the usingnamespace decl is marked `pub`.
+ usingnamespace_set: std.AutoHashMapUnmanaged(*Decl, bool) = .{},
+
pub fn deinit(ns: *Namespace, mod: *Module) void {
ns.destroyDecls(mod);
ns.* = undefined;
@@ -1114,7 +1121,7 @@ pub const Scope = struct {
/// Whether this is populated depends on `status`.
stat_mtime: i128,
/// Whether this is populated or not depends on `tree_loaded`.
- tree: ast.Tree,
+ tree: Ast,
/// Whether this is populated or not depends on `zir_loaded`.
zir: Zir,
/// Package that this file is a part of, managed externally.
@@ -1213,7 +1220,7 @@ pub const Scope = struct {
return source;
}
- pub fn getTree(file: *File, gpa: *Allocator) !*const ast.Tree {
+ pub fn getTree(file: *File, gpa: *Allocator) !*const Ast {
if (file.tree_loaded) return &file.tree;
const source = try file.getSource(gpa);
@@ -1558,17 +1565,17 @@ pub const ErrorMsg = struct {
pub const SrcLoc = struct {
file_scope: *Scope.File,
/// Might be 0 depending on tag of `lazy`.
- parent_decl_node: ast.Node.Index,
+ parent_decl_node: Ast.Node.Index,
/// Relative to `parent_decl_node`.
lazy: LazySrcLoc,
- pub fn declSrcToken(src_loc: SrcLoc) ast.TokenIndex {
+ pub fn declSrcToken(src_loc: SrcLoc) Ast.TokenIndex {
const tree = src_loc.file_scope.tree;
return tree.firstToken(src_loc.parent_decl_node);
}
- pub fn declRelativeToNodeIndex(src_loc: SrcLoc, offset: i32) ast.TokenIndex {
- return @bitCast(ast.Node.Index, offset + @bitCast(i32, src_loc.parent_decl_node));
+ pub fn declRelativeToNodeIndex(src_loc: SrcLoc, offset: i32) Ast.TokenIndex {
+ return @bitCast(Ast.Node.Index, offset + @bitCast(i32, src_loc.parent_decl_node));
}
pub fn byteOffset(src_loc: SrcLoc, gpa: *Allocator) !u32 {
@@ -1694,7 +1701,7 @@ pub const SrcLoc = struct {
const tree = try src_loc.file_scope.getTree(gpa);
const node_tags = tree.nodes.items(.tag);
const node = src_loc.declRelativeToNodeIndex(node_off);
- var params: [1]ast.Node.Index = undefined;
+ var params: [1]Ast.Node.Index = undefined;
const full = switch (node_tags[node]) {
.call_one,
.call_one_comma,
@@ -1824,7 +1831,7 @@ pub const SrcLoc = struct {
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const main_tokens = tree.nodes.items(.main_token);
- const extra = tree.extraData(node_datas[switch_node].rhs, ast.Node.SubRange);
+ const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange);
const case_nodes = tree.extra_data[extra.start..extra.end];
for (case_nodes) |case_node| {
const case = switch (node_tags[case_node]) {
@@ -1850,7 +1857,7 @@ pub const SrcLoc = struct {
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const main_tokens = tree.nodes.items(.main_token);
- const extra = tree.extraData(node_datas[switch_node].rhs, ast.Node.SubRange);
+ const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange);
const case_nodes = tree.extra_data[extra.start..extra.end];
for (case_nodes) |case_node| {
const case = switch (node_tags[case_node]) {
@@ -1879,7 +1886,7 @@ pub const SrcLoc = struct {
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const node = src_loc.declRelativeToNodeIndex(node_off);
- var params: [1]ast.Node.Index = undefined;
+ var params: [1]Ast.Node.Index = undefined;
const full = switch (node_tags[node]) {
.fn_proto_simple => tree.fnProtoSimple(&params, node),
.fn_proto_multi => tree.fnProtoMulti(node),
@@ -1904,7 +1911,7 @@ pub const SrcLoc = struct {
const tree = try src_loc.file_scope.getTree(gpa);
const node_tags = tree.nodes.items(.tag);
const node = src_loc.declRelativeToNodeIndex(node_off);
- var params: [1]ast.Node.Index = undefined;
+ var params: [1]Ast.Node.Index = undefined;
const full = switch (node_tags[node]) {
.fn_proto_simple => tree.fnProtoSimple(&params, node),
.fn_proto_multi => tree.fnProtoMulti(node),
@@ -1934,7 +1941,7 @@ pub const SrcLoc = struct {
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const parent_node = src_loc.declRelativeToNodeIndex(node_off);
- var params: [1]ast.Node.Index = undefined;
+ var params: [1]Ast.Node.Index = undefined;
const full = switch (node_tags[parent_node]) {
.fn_proto_simple => tree.fnProtoSimple(&params, parent_node),
.fn_proto_multi => tree.fnProtoMulti(parent_node),
@@ -2648,7 +2655,10 @@ pub fn astGenFile(mod: *Module, file: *Scope.File) !void {
undefined;
defer if (data_has_safety_tag) gpa.free(safety_buffer);
const data_ptr = if (data_has_safety_tag)
- @ptrCast([*]const u8, safety_buffer.ptr)
+ if (file.zir.instructions.len == 0)
+ @as([*]const u8, undefined)
+ else
+ @ptrCast([*]const u8, safety_buffer.ptr)
else
@ptrCast([*]const u8, file.zir.instructions.items(.data).ptr);
if (data_has_safety_tag) {
@@ -3171,6 +3181,31 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
errdefer decl_arena.deinit();
const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
+ if (decl.is_usingnamespace) {
+ const ty_ty = Type.initTag(.type);
+ if (!decl_tv.ty.eql(ty_ty)) {
+ return mod.fail(&block_scope.base, src, "expected type, found {}", .{decl_tv.ty});
+ }
+ var buffer: Value.ToTypeBuffer = undefined;
+ const ty = decl_tv.val.toType(&buffer);
+ if (ty.getNamespace() == null) {
+ return mod.fail(&block_scope.base, src, "type {} has no namespace", .{ty});
+ }
+
+ decl.ty = ty_ty;
+ decl.val = try Value.Tag.ty.create(&decl_arena.allocator, ty);
+ decl.align_val = Value.initTag(.null_value);
+ decl.linksection_val = Value.initTag(.null_value);
+ decl.has_tv = true;
+ decl.owns_tv = false;
+ decl_arena_state.* = decl_arena.state;
+ decl.value_arena = decl_arena_state;
+ decl.analysis = .complete;
+ decl.generation = mod.generation;
+
+ return true;
+ }
+
if (decl_tv.val.castTag(.function)) |fn_payload| {
const func = fn_payload.data;
const owns_tv = func.owner_decl == decl;
@@ -3266,16 +3301,13 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
if (type_changed and mod.emit_h != null) {
try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl });
}
- } else if (decl_tv.ty.zigTypeTag() == .Type) {
- // In case this Decl is a struct or union, we need to resolve the fields
- // while we still have the `Sema` in scope, so that the field type expressions
- // can use the resolved AIR instructions that they possibly reference.
- // We do this after the decl is populated and set to `complete` so that a `Decl`
- // may reference itself.
- var buffer: Value.ToTypeBuffer = undefined;
- const ty = decl.val.toType(&buffer);
- try sema.resolveDeclFields(&block_scope, src, ty);
}
+ // In case this Decl is a struct or union, we need to resolve the fields
+ // while we still have the `Sema` in scope, so that the field type expressions
+ // can use the resolved AIR instructions that they possibly reference.
+ // We do this after the decl is populated and set to `complete` so that a `Decl`
+ // may reference itself.
+ try sema.resolvePendingTypes(&block_scope);
if (decl.is_exported) {
const export_src = src; // TODO point to the export token
@@ -3491,7 +3523,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi
// zig fmt: off
const is_pub = (flags & 0b0001) != 0;
- const is_exported = (flags & 0b0010) != 0;
+ const export_bit = (flags & 0b0010) != 0;
const has_align = (flags & 0b0100) != 0;
const has_linksection = (flags & 0b1000) != 0;
// zig fmt: on
@@ -3506,7 +3538,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi
var is_named_test = false;
const decl_name: [:0]const u8 = switch (decl_name_index) {
0 => name: {
- if (is_exported) {
+ if (export_bit) {
const i = iter.usingnamespace_index;
iter.usingnamespace_index += 1;
break :name try std.fmt.allocPrintZ(gpa, "usingnamespace_{d}", .{i});
@@ -3532,11 +3564,17 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi
}
},
};
+ const is_exported = export_bit and decl_name_index != 0;
+ const is_usingnamespace = export_bit and decl_name_index == 0;
+ if (is_usingnamespace) try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1);
// We create a Decl for it regardless of analysis status.
const gop = try namespace.decls.getOrPut(gpa, decl_name);
if (!gop.found_existing) {
const new_decl = try mod.allocateNewDecl(namespace, decl_node);
+ if (is_usingnamespace) {
+ namespace.usingnamespace_set.putAssumeCapacity(new_decl, is_pub);
+ }
log.debug("scan new {*} ({s}) into {*}", .{ new_decl, decl_name, namespace });
new_decl.src_line = line;
new_decl.name = decl_name;
@@ -3545,7 +3583,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi
// test decls if in test mode, get analyzed.
const decl_pkg = namespace.file_scope.pkg;
const want_analysis = is_exported or switch (decl_name_index) {
- 0 => true, // comptime decl
+ 0 => true, // comptime or usingnamespace decl
1 => blk: {
// test decl with no name. Skip the part where we check against
// the test name filter.
@@ -3568,6 +3606,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi
}
new_decl.is_pub = is_pub;
new_decl.is_exported = is_exported;
+ new_decl.is_usingnamespace = is_usingnamespace;
new_decl.has_align = has_align;
new_decl.has_linksection = has_linksection;
new_decl.zir_decl_index = @intCast(u32, decl_sub_index);
@@ -3584,6 +3623,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi
decl.is_pub = is_pub;
decl.is_exported = is_exported;
+ decl.is_usingnamespace = is_usingnamespace;
decl.has_align = has_align;
decl.has_linksection = has_linksection;
decl.zir_decl_index = @intCast(u32, decl_sub_index);
@@ -3927,7 +3967,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void {
decl.analysis = .outdated;
}
-pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node.Index) !*Decl {
+pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast.Node.Index) !*Decl {
// If we have emit-h then we must allocate a bigger structure to store the emit-h state.
const new_decl: *Decl = if (mod.emit_h != null) blk: {
const parent_struct = try mod.gpa.create(DeclPlusEmitH);
@@ -3976,6 +4016,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.
.has_linksection = false,
.has_align = false,
.alive = false,
+ .is_usingnamespace = false,
};
return new_decl;
}
@@ -4196,7 +4237,7 @@ pub fn fail(
pub fn failTok(
mod: *Module,
scope: *Scope,
- token_index: ast.TokenIndex,
+ token_index: Ast.TokenIndex,
comptime format: []const u8,
args: anytype,
) CompileError {
@@ -4209,7 +4250,7 @@ pub fn failTok(
pub fn failNode(
mod: *Module,
scope: *Scope,
- node_index: ast.Node.Index,
+ node_index: Ast.Node.Index,
comptime format: []const u8,
args: anytype,
) CompileError {
@@ -4414,7 +4455,7 @@ pub const SwitchProngSrc = union(enum) {
const main_tokens = tree.nodes.items(.main_token);
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
- const extra = tree.extraData(node_datas[switch_node].rhs, ast.Node.SubRange);
+ const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange);
const case_nodes = tree.extra_data[extra.start..extra.end];
var multi_i: u32 = 0;