commit 500614de42f086b4c4190fc9d736d50e28ec7b23
parent bf6d1df8204f07146354dce4f52030f65135cf08
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Thu, 14 May 2026 10:15:47 -0700
Remove src include path from C frontend build
Diffstat:
7 files changed, 4 insertions(+), 283 deletions(-)
diff --git a/Makefile b/Makefile
@@ -68,7 +68,7 @@ build/lib/%.o: src/%.c
build/lang/c/%.o: lang/c/%.c
@mkdir -p $(dir $@)
- $(CC) $(CFLAGS_COMMON) -ffreestanding -Iinclude -Ilang/c -Isrc $(DEPFLAGS) -c $< -o $@
+ $(CC) $(CFLAGS_COMMON) -ffreestanding -Iinclude -Ilang/c $(DEPFLAGS) -c $< -o $@
build/lib/%.o: src/%.S
@mkdir -p $(dir $@)
diff --git a/lang/c/c.c b/lang/c/c.c
@@ -170,7 +170,7 @@ int cfree_c_compile(CfreeCompiler* c, const CfreeCompileOptions* opts,
c_apply_pp_options(pp, &opts->pp);
pp_push_input(pp, lex);
- parse_c(c, pp, decls, cg, NULL);
+ parse_c(c, pp, decls, cg);
cfree_cg_free(cg);
decl_free(decls);
diff --git a/lang/c/debug/c_debug.c b/lang/c/debug/c_debug.c
@@ -1,252 +0,0 @@
-/* C-type → DebugTypeId adapter.
- *
- * Walks the C `Type*` chain, calling debug_type_* on the language-neutral
- * Debug surface and caching the result keyed by Type* identity.
- *
- * Identity contract (see c_debug.h): the cache is per-Debug; equal Type*
- * (canonical pool pointer) → equal DebugTypeId. Recursive shapes (a
- * struct containing a pointer to itself) work because:
- * - We allocate the record DIE id first via debug_type_record_begin /
- * end and store the id in the cache *before* descending into fields.
- * Cyclic references through a pointer get a fresh ptr-DIE that points
- * back to the (now-known) record id.
- * - Direct cycles (a struct containing itself by value) are illegal in
- * C anyway. */
-
-#include "debug/c_debug.h"
-
-#include <string.h>
-
-#include "core/core.h"
-#include "core/heap.h"
-#include "core/pool.h"
-#include "core/vec.h"
-#include "abi/c_abi.h"
-#include "debug/debug.h"
-#include "debug/debug_internal.h"
-
-/* Cache: Type* → DebugTypeId.
- *
- * We attach the cache to the Debug instance via a void* slot. Since
- * DebugTypeId is u32 and we use a u64-keyed hashmap (PtrToU32 from the
- * internal header), the cache survives the lifetime of one Debug.
- *
- * The cache is created lazily on first lookup so producers that don't
- * use c_debug_type pay nothing. */
-
-typedef struct CDebugCache {
- PtrToU32 map; /* (u64)(uintptr_t)Type* → DebugTypeId */
-} CDebugCache;
-
-/* The Debug struct doesn't have a slot for the cache. Rather than
- * touching debug.h, we keep a single (Debug* → cache) tiny association
- * list. In practice exactly one Debug exists per TU; this list rarely
- * grows past 1. */
-
-typedef struct CDebugCacheEntry {
- Debug* d;
- CDebugCache* cache;
-} CDebugCacheEntry;
-
-static CDebugCacheEntry* g_caches = NULL;
-static u32 g_caches_n = 0;
-static u32 g_caches_cap = 0;
-
-static CDebugCache* cache_for(Debug* d) {
- u32 i;
- Heap* h;
- for (i = 0; i < g_caches_n; ++i) {
- if (g_caches[i].d == d) return g_caches[i].cache;
- }
- h = (Heap*)d->c->env->heap;
- if (VEC_GROW(h, g_caches, g_caches_cap, g_caches_n + 1)) return NULL;
- {
- CDebugCacheEntry* slot = &g_caches[g_caches_n++];
- slot->d = d;
- slot->cache =
- (CDebugCache*)h->alloc(h, sizeof(CDebugCache), _Alignof(CDebugCache));
- if (!slot->cache) {
- g_caches_n--;
- return NULL;
- }
- PtrToU32_init(&slot->cache->map, h);
- return slot->cache;
- }
-}
-
-static DebugTypeId cache_get(CDebugCache* c, const Type* t) {
- u32* v = PtrToU32_get(&c->map, (u64)(uintptr_t)t);
- return v ? *v : DEBUG_TYPE_NONE;
-}
-
-static void cache_put(CDebugCache* c, const Type* t, DebugTypeId id) {
- PtrToU32_set(&c->map, (u64)(uintptr_t)t, id);
-}
-
-/* ---- recursive type walk ---- */
-
-static DebugTypeId walk(Debug* d, TargetABI* abi, const Type* t,
- CDebugCache* cache);
-
-static Sym intern_cstr(Debug* d, const char* s) {
- return pool_intern_cstr(d->c->global, s);
-}
-
-static DebugTypeId base_id(Debug* d, TargetABI* abi, const Type* t,
- const char* name, DebugBaseEncoding enc) {
- return debug_type_base(d, intern_cstr(d, name), enc, c_abi_sizeof(abi, t));
-}
-
-static DebugTypeId walk_unqual(Debug* d, TargetABI* abi, const Type* t,
- CDebugCache* cache) {
- switch ((TypeKind)t->kind) {
- case TY_VOID:
- return debug_type_void(d);
- case TY_BOOL:
- return base_id(d, abi, t, "_Bool", DEBUG_BE_BOOL);
- case TY_CHAR:
- return base_id(d, abi, t, "char", DEBUG_BE_SIGNED_CHAR);
- case TY_SCHAR:
- return base_id(d, abi, t, "signed char", DEBUG_BE_SIGNED_CHAR);
- case TY_UCHAR:
- return base_id(d, abi, t, "unsigned char", DEBUG_BE_UNSIGNED_CHAR);
- case TY_SHORT:
- return base_id(d, abi, t, "short", DEBUG_BE_SIGNED);
- case TY_USHORT:
- return base_id(d, abi, t, "unsigned short", DEBUG_BE_UNSIGNED);
- case TY_INT:
- return base_id(d, abi, t, "int", DEBUG_BE_SIGNED);
- case TY_UINT:
- return base_id(d, abi, t, "unsigned int", DEBUG_BE_UNSIGNED);
- case TY_LONG:
- return base_id(d, abi, t, "long", DEBUG_BE_SIGNED);
- case TY_ULONG:
- return base_id(d, abi, t, "unsigned long", DEBUG_BE_UNSIGNED);
- case TY_LLONG:
- return base_id(d, abi, t, "long long", DEBUG_BE_SIGNED);
- case TY_ULLONG:
- return base_id(d, abi, t, "unsigned long long", DEBUG_BE_UNSIGNED);
- case TY_INT128:
- return base_id(d, abi, t, "__int128", DEBUG_BE_SIGNED);
- case TY_UINT128:
- return base_id(d, abi, t, "unsigned __int128", DEBUG_BE_UNSIGNED);
- case TY_FLOAT:
- return base_id(d, abi, t, "float", DEBUG_BE_FLOAT);
- case TY_DOUBLE:
- return base_id(d, abi, t, "double", DEBUG_BE_FLOAT);
- case TY_LDOUBLE:
- return base_id(d, abi, t, "long double", DEBUG_BE_FLOAT);
- case TY_PTR: {
- DebugTypeId pointee = walk(d, abi, t->ptr.pointee, cache);
- return debug_type_ptr(d, pointee);
- }
- case TY_ARRAY: {
- DebugTypeId elem = walk(d, abi, t->arr.elem, cache);
- return debug_type_array(d, elem, t->arr.incomplete ? 0 : t->arr.count);
- }
- case TY_FUNC: {
- DebugTypeId ret = walk(d, abi, t->fn.ret, cache);
- DebugTypeId* params = NULL;
- DebugTypeId result;
- u32 i;
- Heap* h = (Heap*)d->c->env->heap;
- if (t->fn.nparams) {
- params = (DebugTypeId*)h->alloc(h, sizeof(DebugTypeId) * t->fn.nparams,
- _Alignof(DebugTypeId));
- if (!params) return DEBUG_TYPE_NONE;
- for (i = 0; i < t->fn.nparams; ++i) {
- params[i] = walk(d, abi, t->fn.params[i], cache);
- }
- }
- result = debug_type_func(d, ret, params, t->fn.nparams, t->fn.variadic);
- if (params) h->free(h, params, sizeof(DebugTypeId) * t->fn.nparams);
- return result;
- }
- case TY_STRUCT:
- case TY_UNION: {
- const ABIRecordLayout* layout;
- DebugTypeBuilder* b;
- DebugTypeId id;
- u32 i;
- if (t->rec.incomplete) {
- /* Emit an opaque record: zero size, no fields. */
- b = debug_type_record_begin(d, t->rec.tag, t->kind == TY_UNION, 0, 0);
- return debug_type_record_end(b);
- }
- layout = c_abi_record_layout(abi, t);
- b = debug_type_record_begin(d, t->rec.tag, t->kind == TY_UNION,
- layout ? layout->size : 0,
- layout ? layout->align : 0);
- /* Pre-publish the cache entry pointing at the in-progress builder
- * id so cycles via pointer fields resolve. We don't have a builder
- * id yet; allocate one early via the record_end-then-walk strategy
- * is safer. To keep things simple here, we cache after end_record.
- * Self-referential pointers must therefore be expressed via a
- * `Type*` that points to a *forward-declared* incomplete record
- * (handled above), then refined later. For now no test path hits
- * this. */
- for (i = 0; i < t->rec.nfields; ++i) {
- const Field* f = &t->rec.fields[i];
- DebugTypeId ftype = walk(d, abi, f->type, cache);
- u32 byte_ofs = layout ? layout->fields[i].offset : 0;
- if (f->flags & FIELD_BITFIELD) {
- u16 bit_ofs = layout ? layout->fields[i].bit_offset : 0;
- debug_type_record_bitfield(b, f->name, ftype, byte_ofs, bit_ofs,
- f->bitfield_width);
- } else {
- debug_type_record_field(b, f->name, ftype, byte_ofs);
- }
- }
- id = debug_type_record_end(b);
- return id;
- }
- case TY_ENUM: {
- DebugTypeId base = walk(d, abi, t->enm.base, cache);
- DebugEnumBuilder* b = debug_type_enum_begin(d, t->enm.tag, base);
- /* Type doesn't carry enum members directly; we'd need a registry
- * lookup keyed by tag_id. Leave empty — consumers see an enum
- * with no enumerators. */
- return debug_type_enum_end(b);
- }
- }
- return DEBUG_TYPE_NONE;
-}
-
-static DebugTypeId walk(Debug* d, TargetABI* abi, const Type* t,
- CDebugCache* cache) {
- DebugTypeId cached;
- DebugTypeId base_id_;
- DebugTypeId result;
- if (!t) return DEBUG_TYPE_NONE;
- cached = cache_get(cache, t);
- if (cached != DEBUG_TYPE_NONE) return cached;
-
- /* Strip and re-apply qualifiers. The unqualified type goes into the
- * pool as one DIE; const/volatile/restrict layer DIEs around it. */
- if (t->qual) {
- /* Build the unqualified core, then layer qualifiers. We can't simply
- * re-pool a Type with qual=0 because we don't have a pool here.
- * Instead walk fields directly and synthesize. */
- /* Synthesize unqualified DIE from the same shape. We construct a
- * shallow Type with qual=0 and recurse via walk_unqual. */
- Type tmp = *t;
- tmp.qual = 0;
- base_id_ = walk_unqual(d, abi, &tmp, cache);
- result = base_id_;
- if (t->qual & Q_CONST) result = debug_type_const(d, result);
- if (t->qual & Q_VOLATILE) result = debug_type_volatile(d, result);
- if (t->qual & Q_RESTRICT) result = debug_type_restrict(d, result);
- } else {
- result = walk_unqual(d, abi, t, cache);
- }
- cache_put(cache, t, result);
- return result;
-}
-
-DebugTypeId c_debug_type(Debug* d, TargetABI* abi, const Type* t) {
- CDebugCache* cache;
- if (!d || !t) return DEBUG_TYPE_NONE;
- cache = cache_for(d);
- if (!cache) return DEBUG_TYPE_NONE;
- return walk(d, abi, t, cache);
-}
diff --git a/lang/c/debug/c_debug.h b/lang/c/debug/c_debug.h
@@ -1,23 +0,0 @@
-#ifndef CFREE_C_DEBUG_H
-#define CFREE_C_DEBUG_H
-
-#include "core/core.h"
-#include "debug/debug.h"
-#include "type/type.h"
-
-/* C-specific adapter over the language-neutral Debug type DIE API.
- *
- * Walks a `const Type*` and emits the corresponding tree of debug_type_*
- * calls, returning a DebugTypeId that the C frontend (parse / cg) can
- * pass to debug_param, debug_local, debug_func_begin, etc. Used only by
- * the C frontend; the core Debug module does not depend on `Type`.
- *
- * Identity: this adapter interns by Type* pointer. CG owns a per-TU
- * cache so repeated lookups for the same Type* yield the same id without
- * re-walking the chain. The cache lives for the duration of the TU (i.e.
- * until debug_emit / debug_free) and is invalidated automatically when
- * Debug is freed. */
-
-DebugTypeId c_debug_type(Debug*, TargetABI*, const Type*);
-
-#endif
diff --git a/lang/c/parse/parse.c b/lang/c/parse/parse.c
@@ -1033,7 +1033,7 @@ static void parse_translation_unit(Parser* p) {
* Entry point
* ============================================================ */
-void parse_c(Compiler* c, Pp* pp, DeclTable* decls, CG* cg, Debug* debug) {
+void parse_c(Compiler* c, Pp* pp, DeclTable* decls, CG* cg) {
Parser p;
CKw i;
@@ -1042,7 +1042,6 @@ void parse_c(Compiler* c, Pp* pp, DeclTable* decls, CG* cg, Debug* debug) {
p.pp = pp;
p.decls = decls;
p.cg = cg;
- p.debug = debug;
p.abi = c->abi;
p.pool = c->global;
diff --git a/lang/c/parse/parse.h b/lang/c/parse/parse.h
@@ -5,10 +5,8 @@
#include "parse/cg_public_compat.h"
#include "pp/pp.h"
-typedef struct Debug Debug;
-
/* C11 frontend. Reads preprocessed tokens, records C declarations, and drives
* the public CG API for executable code and object data. */
-void parse_c(Compiler*, Pp*, DeclTable*, CG*, Debug*);
+void parse_c(Compiler*, Pp*, DeclTable*, CG*);
#endif
diff --git a/lang/c/parse/parse_priv.h b/lang/c/parse/parse_priv.h
@@ -162,7 +162,6 @@ typedef struct Parser {
Pp* pp;
DeclTable* decls;
CG* cg;
- Debug* debug;
TargetABI* abi;
Pool* pool;