self-referential c record imports

This commit is contained in:
2026-06-25 07:43:43 +02:00
parent 4cb0ad7f25
commit 9d1130b359
8 changed files with 65 additions and 8 deletions
+5
View File
@@ -415,6 +415,11 @@ populate_record :: proc(ctx: ^Context, index: u32, declaration: CXCursor) {
ctx.result.records[index].kind = .Union if ctx.api.get_cursor_kind(definition) == CXCursor_UnionDecl else .Struct
ctx.result.records[index].size = u64(size)
ctx.result.records[index].alignment = u32(alignment)
// Mark in-progress before visiting fields: a self-referential field (e.g. the
// `struct __sFILE *` inside FILE) re-enters populate_record for this same record;
// the top guard now short-circuits instead of recursing forever. The final line
// recomputes the real value from `reason`.
ctx.result.records[index].complete = true
field_ctx := Record_Field_Context{ctx=ctx, record=index}
_ = ctx.api.visit_children(definition, visit_record_field, &field_ctx)
ctx.result.records[index].complete = len(ctx.result.records[index].reason) == 0
+21 -6
View File
@@ -640,9 +640,23 @@ is_c_signature_type :: proc(value: Type, store: ^Store, allow_void := false) ->
(is_c_struct(value, store) && is_runtime_value(value, store))
}
contains_distinct :: proc(value: Type, store: ^Store, depth := 0) -> bool {
if depth > 256 {
return true
// contains_distinct reports whether a `distinct` type is reachable from `value`
// (by value, behind a pointer, through fields/params/children). A pointer to a
// distinct type still counts — distinct types do not cross the C ABI even behind
// indirection. The `seen` set makes the graph walk terminate on self-referential
// records (e.g. `?*mut Node` inside `Node`), which previously recursed until the
// depth cap and wrongly reported `true`.
contains_distinct :: proc(value: Type, store: ^Store) -> bool {
seen: [dynamic]Type
defer delete(seen)
return contains_distinct_seen(value, store, &seen)
}
contains_distinct_seen :: proc(value: Type, store: ^Store, seen: ^[dynamic]Type) -> bool {
for visited in seen {
if visited == value {
return false
}
}
item, ok := node(store, value)
if !ok {
@@ -651,21 +665,22 @@ contains_distinct :: proc(value: Type, store: ^Store, depth := 0) -> bool {
if item.kind == .Distinct {
return true
}
append(seen, value)
if item.kind == .Struct || item.kind == .Union {
for field in fields_for(store, value) {
if contains_distinct(field.type, store, depth+1) {
if contains_distinct_seen(field.type, store, seen) {
return true
}
}
}
if item.kind == .Function {
for param in params_for(store, value) {
if contains_distinct(param.type, store, depth+1) {
if contains_distinct_seen(param.type, store, seen) {
return true
}
}
}
return is_valid(item.child) && contains_distinct(item.child, store, depth+1)
return is_valid(item.child) && contains_distinct_seen(item.child, store, seen)
}
is_c_integer_promotion_candidate :: proc(value: Type) -> bool {