fix(C4): collectCImportSources recurses into nested namespaces
A named #import c unit declared inside an aliased module sits two namespace levels deep in the merged tree; the one-level walk (the extractLibraries/0130 pattern in c_import form) never collected it, so the unit silently never compiled and its symbols resolved from whatever process image carried the same names — surfaced by C4's sqlite migration, where only the version pin could tell the OS copy from the vendored one.
This commit is contained in:
@@ -627,44 +627,41 @@ pub fn collectCImportSources(allocator: std.mem.Allocator, root: *const Node) ![
|
||||
var seen = std.AutoHashMap([*]const []const u8, void).init(allocator);
|
||||
defer seen.deinit();
|
||||
|
||||
for (root.data.root.decls) |decl| {
|
||||
switch (decl.data) {
|
||||
.c_import_decl => |ci| {
|
||||
if (ci.sources.len > 0) {
|
||||
const key = ci.sources.ptr;
|
||||
if (!seen.contains(key)) {
|
||||
try seen.put(key, {});
|
||||
try infos.append(allocator, .{
|
||||
.sources = ci.sources,
|
||||
.includes = ci.includes,
|
||||
.defines = ci.defines,
|
||||
.flags = ci.flags,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
.namespace_decl => |ns| {
|
||||
for (ns.decls) |nd| {
|
||||
if (nd.data == .c_import_decl) {
|
||||
const nci = nd.data.c_import_decl;
|
||||
if (nci.sources.len > 0) {
|
||||
const key = nci.sources.ptr;
|
||||
if (!seen.contains(key)) {
|
||||
try seen.put(key, {});
|
||||
try infos.append(allocator, .{
|
||||
.sources = nci.sources,
|
||||
.includes = nci.includes,
|
||||
.defines = nci.defines,
|
||||
.flags = nci.flags,
|
||||
// Aliased imports lower to namespace_decl nodes and NEST when a
|
||||
// namespaced module declares its own named unit — recurse, or a
|
||||
// unit two aliases deep is silently never compiled and its symbols
|
||||
// resolve from whatever process image carries the same names (the
|
||||
// extractLibraries depth bug, issue 0130, in c_import form).
|
||||
const walker = struct {
|
||||
fn walk(
|
||||
infos_: *std.ArrayList(CImportInfo),
|
||||
seen_: *std.AutoHashMap([*]const []const u8, void),
|
||||
alloc: std.mem.Allocator,
|
||||
decls: []const *Node,
|
||||
) !void {
|
||||
for (decls) |d| {
|
||||
switch (d.data) {
|
||||
.c_import_decl => |ci| {
|
||||
if (ci.sources.len > 0) {
|
||||
const key = ci.sources.ptr;
|
||||
if (!seen_.contains(key)) {
|
||||
try seen_.put(key, {});
|
||||
try infos_.append(alloc, .{
|
||||
.sources = ci.sources,
|
||||
.includes = ci.includes,
|
||||
.defines = ci.defines,
|
||||
.flags = ci.flags,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
.namespace_decl => |ns| try walk(infos_, seen_, alloc, ns.decls),
|
||||
else => {},
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
try walker.walk(&infos, &seen, allocator, root.data.root.decls);
|
||||
|
||||
return try infos.toOwnedSlice(allocator);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user