aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/c.zig
diff options
context:
space:
mode:
authormlugg <mlugg@mlugg.co.uk>2024-12-23 20:39:19 +0000
committermlugg <mlugg@mlugg.co.uk>2024-12-24 02:18:41 +0000
commit3afda4322c34dedc2319701fdfac3505c8d311e9 (patch)
tree467873c408750cb4223f3ccf31775e42ec9fbd5c /src/codegen/c.zig
parent40aafcd6a85d3c517f445f17149c17523c832420 (diff)
downloadzig-3afda4322c34dedc2319701fdfac3505c8d311e9.tar.gz
zig-3afda4322c34dedc2319701fdfac3505c8d311e9.zip
compiler: analyze type and value of global declaration separately
This commit separates semantic analysis of the annotated type vs value of a global declaration, therefore allowing recursive and mutually recursive values to be declared. Every `Nav` which undergoes analysis now has *two* corresponding `AnalUnit`s: `.{ .nav_val = n }` and `.{ .nav_ty = n }`. The `nav_val` unit is responsible for *fully resolving* the `Nav`: determining its value, linksection, addrspace, etc. The `nav_ty` unit, on the other hand, resolves only the information necessary to construct a *pointer* to the `Nav`: its type, addrspace, etc. (It does also analyze its linksection, but that could be moved to `nav_val` I think; it doesn't make any difference). Analyzing a `nav_ty` for a declaration with no type annotation will just mark a dependency on the `nav_val`, analyze it, and finish. Conversely, analyzing a `nav_val` for a declaration *with* a type annotation will first mark a dependency on the `nav_ty` and analyze it, using this as the result type when evaluating the value body. The `nav_val` and `nav_ty` units always have references to one another: so, if a `Nav`'s type is referenced, its value implicitly is too, and vice versa. However, these dependencies are trivial, so, to save memory, are only known implicitly by logic in `resolveReferences`. In general, analyzing ZIR `decl_val` will only analyze `nav_ty` of the corresponding `Nav`. There are two exceptions to this. If the declaration is an `extern` declaration, then we immediately ensure the `Nav` value is resolved (which doesn't actually require any more analysis, since such a declaration has no value body anyway). Additionally, if the resolved type has type tag `.@"fn"`, we again immediately resolve the `Nav` value. The latter restriction is in place for two reasons: * Functions are special, in that their externs are allowed to trivially alias; i.e. with a declaration `extern fn foo(...)`, you can write `const bar = foo;`. This is not allowed for non-function externs, and it means that function types are the only place where it is possible for a declaration `Nav` to have a `.@"extern"` value without actually being declared `extern`. We need to identify this situation immediately so that the `decl_ref` can create a pointer to the *real* extern `Nav`, not this alias. * In certain situations, such as taking a pointer to a `Nav`, Sema needs to queue analysis of a runtime function if the value is a function. To do this, the function value needs to be known, so we need to resolve the value immediately upon `&foo` where `foo` is a function. This restriction is simple to codify into the eventual language specification, and doesn't limit the utility of this feature in practice. A consequence of this commit is that codegen and linking logic needs to be more careful when looking at `Nav`s. In general: * When `updateNav` or `updateFunc` is called, it is safe to assume that the `Nav` being updated (the owner `Nav` for `updateFunc`) is fully resolved. * Any `Nav` whose value is/will be an `@"extern"` or a function is fully resolved; see `Nav.getExtern` for a helper for a common case here. * Any other `Nav` may only have its type resolved. This didn't seem to be too tricky to satisfy in any of the existing codegen/linker backends. Resolves: #131
Diffstat (limited to 'src/codegen/c.zig')
-rw-r--r--src/codegen/c.zig61
1 files changed, 32 insertions, 29 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index c3e3c7fbdc..2368f202da 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -770,11 +770,14 @@ pub const DeclGen = struct {
const ctype_pool = &dg.ctype_pool;
// Chase function values in order to be able to reference the original function.
- const owner_nav = switch (ip.indexToKey(zcu.navValue(nav_index).toIntern())) {
- .variable => |variable| variable.owner_nav,
- .func => |func| func.owner_nav,
- .@"extern" => |@"extern"| @"extern".owner_nav,
- else => nav_index,
+ const owner_nav = switch (ip.getNav(nav_index).status) {
+ .unresolved => unreachable,
+ .type_resolved => nav_index, // this can't be an extern or a function
+ .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
+ .func => |f| f.owner_nav,
+ .@"extern" => |e| e.owner_nav,
+ else => nav_index,
+ },
};
// Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
@@ -2237,7 +2240,7 @@ pub const DeclGen = struct {
Type.fromInterned(nav.typeOf(ip)),
.{ .nav = nav_index },
CQualifiers.init(.{ .@"const" = flags.is_const }),
- nav.status.resolved.alignment,
+ nav.getAlignment(),
.complete,
);
try fwd.writeAll(";\n");
@@ -2246,19 +2249,19 @@ pub const DeclGen = struct {
fn renderNavName(dg: *DeclGen, writer: anytype, nav_index: InternPool.Nav.Index) !void {
const zcu = dg.pt.zcu;
const ip = &zcu.intern_pool;
- switch (ip.indexToKey(zcu.navValue(nav_index).toIntern())) {
- .@"extern" => |@"extern"| try writer.print("{ }", .{
+ const nav = ip.getNav(nav_index);
+ if (nav.getExtern(ip)) |@"extern"| {
+ try writer.print("{ }", .{
fmtIdent(ip.getNav(@"extern".owner_nav).name.toSlice(ip)),
- }),
- else => {
- // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case),
- // expand to 3x the length of its input, but let's cut it off at a much shorter limit.
- const fqn_slice = ip.getNav(nav_index).fqn.toSlice(ip);
- try writer.print("{}__{d}", .{
- fmtIdent(fqn_slice[0..@min(fqn_slice.len, 100)]),
- @intFromEnum(nav_index),
- });
- },
+ });
+ } else {
+ // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case),
+ // expand to 3x the length of its input, but let's cut it off at a much shorter limit.
+ const fqn_slice = ip.getNav(nav_index).fqn.toSlice(ip);
+ try writer.print("{}__{d}", .{
+ fmtIdent(fqn_slice[0..@min(fqn_slice.len, 100)]),
+ @intFromEnum(nav_index),
+ });
}
}
@@ -2826,7 +2829,7 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
const fwd = o.dg.fwdDeclWriter();
try fwd.print("static zig_{s} ", .{@tagName(key)});
- try o.dg.renderFunctionSignature(fwd, fn_val, ip.getNav(fn_nav_index).status.resolved.alignment, .forward, .{
+ try o.dg.renderFunctionSignature(fwd, fn_val, ip.getNav(fn_nav_index).getAlignment(), .forward, .{
.fmt_ctype_pool_string = fn_name,
});
try fwd.writeAll(";\n");
@@ -2867,13 +2870,13 @@ pub fn genFunc(f: *Function) !void {
try o.dg.renderFunctionSignature(
fwd,
nav_val,
- nav.status.resolved.alignment,
+ nav.status.fully_resolved.alignment,
.forward,
.{ .nav = nav_index },
);
try fwd.writeAll(";\n");
- if (nav.status.resolved.@"linksection".toSlice(ip)) |s|
+ if (nav.status.fully_resolved.@"linksection".toSlice(ip)) |s|
try o.writer().print("zig_linksection_fn({s}) ", .{fmtStringLiteral(s, null)});
try o.dg.renderFunctionSignature(
o.writer(),
@@ -2952,7 +2955,7 @@ pub fn genDecl(o: *Object) !void {
const nav_ty = Type.fromInterned(nav.typeOf(ip));
if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return;
- switch (ip.indexToKey(nav.status.resolved.val)) {
+ switch (ip.indexToKey(nav.status.fully_resolved.val)) {
.@"extern" => |@"extern"| {
if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{
.is_extern = true,
@@ -2965,8 +2968,8 @@ pub fn genDecl(o: *Object) !void {
try fwd.writeAll("zig_extern ");
try o.dg.renderFunctionSignature(
fwd,
- Value.fromInterned(nav.status.resolved.val),
- nav.status.resolved.alignment,
+ Value.fromInterned(nav.status.fully_resolved.val),
+ nav.status.fully_resolved.alignment,
.forward,
.{ .@"export" = .{
.main_name = nav.name,
@@ -2985,14 +2988,14 @@ pub fn genDecl(o: *Object) !void {
const w = o.writer();
if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");
if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal ");
- if (nav.status.resolved.@"linksection".toSlice(&zcu.intern_pool)) |s|
+ if (nav.status.fully_resolved.@"linksection".toSlice(&zcu.intern_pool)) |s|
try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});
try o.dg.renderTypeAndName(
w,
nav_ty,
.{ .nav = o.dg.pass.nav },
.{},
- nav.status.resolved.alignment,
+ nav.status.fully_resolved.alignment,
.complete,
);
try w.writeAll(" = ");
@@ -3002,10 +3005,10 @@ pub fn genDecl(o: *Object) !void {
},
else => try genDeclValue(
o,
- Value.fromInterned(nav.status.resolved.val),
+ Value.fromInterned(nav.status.fully_resolved.val),
.{ .nav = o.dg.pass.nav },
- nav.status.resolved.alignment,
- nav.status.resolved.@"linksection",
+ nav.status.fully_resolved.alignment,
+ nav.status.fully_resolved.@"linksection",
),
}
}