commit aaf3e90b91d0938e78ff4af28c7fdc52f12bc3c4
parent 4ee57ded3d787ea29d4fa7528ae452c9a2ddc814
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Wed, 10 Jun 2026 07:31:49 -0700
fix(deps): T1.12 — report resolved-dir system flag, not include spelling
kit_dep_iter_next reported from_system_path from the <...>-vs-"..."
spelling bit, so a <foo.h> resolved via a plain -I dir was wrongly flagged
system (and dropped by cc -MM/-MMD). Thread the resolved include dir's
system flag (pp->inc_dirs[i].system) from find_and_open_include through a
new SourceInclude.resolved_system field, kit_source_add_include, and into
the dep edge. bracketed now carries the spelling; from_system_path carries
the resolved-dir flag (GCC -MM semantics).
Verified: <h> via -I now appears in cc -MM; via -isystem it is skipped;
-M shows it either way. test-pp, test-parse (3880+128), test-cg-api (211)
green. Updated the stale cc -MM/-MMD doc comment.
Diffstat:
9 files changed, 50 insertions(+), 40 deletions(-)
diff --git a/doc/plan/TODO.md b/doc/plan/TODO.md
@@ -73,17 +73,6 @@ Add new deferred fixes below as they are discovered.
which programs compile vs panic, so it must be a reviewed change, NOT folded into
a dedup. Unblocks A.2 (below).
-- **`kit_dep_iter` system-path conflation (T1.12).** `kit_dep_iter_next`
- (`src/api/compile.c:654-655`) reports both `from_system_path` and `bracketed`
- from the single `<>`-vs-`""` spelling bit, so a `<...>` include resolved via a
- plain `-I` dir falsely reports `from_system_path=1`. The accurate signal (the
- resolved dir's system flag) is discarded at resolution. A correct fix needs a
- cross-file change: widen `SourceInclude` (`src/core/core.h`) with a resolved-system
- bit and thread it through `lang/cpp/pp/pp_directive.c` (`find_and_open_include` →
- `do_include`), `pp.{c,h}`, `include/kit/source.h`, `src/api/source.c`,
- `src/core/source.c`. Currently documented at the assignment site; value is
- identical to before.
-
## Design-needed (not a quick fix)
- **c_target data relocations (T1.3 / D.5).** `c_emit_data_symbol`
diff --git a/driver/cmd/cc.c b/driver/cmd/cc.c
@@ -46,10 +46,12 @@
/* Header-dependency emission mode (subset of GCC's -M family).
* M — print all deps; do not compile.
- * MM — like M but skip <bracketed> includes.
+ * MM — like M but skip headers resolved via system (-isystem) dirs.
* MD — compile normally AND write all deps to a file.
- * MMD — like MD but skip <bracketed> includes.
- * MD/MMD currently require -c (single-source compile_obj_emit path). */
+ * MMD — like MD but skip headers resolved via system (-isystem) dirs.
+ * The MM/MMD filter keys on the resolved include directory (GCC semantics),
+ * not the <...>-vs-"..." spelling, so a <foo.h> found via a plain -I dir is
+ * still reported. MD/MMD currently require -c (single-source path). */
typedef enum CcDepMode {
CC_DEP_NONE = 0,
CC_DEP_M,
diff --git a/include/kit/source.h b/include/kit/source.h
@@ -17,10 +17,15 @@ KIT_API KitStatus kit_source_add_memory(KitCompiler*, KitSlice name,
uint32_t* file_id_out);
KIT_API KitStatus kit_source_add_builtin(KitCompiler*, KitSlice name,
uint32_t* file_id_out);
+/* `system` is the spelling form (<...> vs "..."); `resolved_system` records
+ * whether the header was actually resolved through a system (-isystem) include
+ * directory. The two differ when a <...> include is satisfied by a plain -I
+ * dir; dependency reporting wants the resolved flag, not the spelling. */
KIT_API KitStatus kit_source_add_include(KitCompiler*,
uint32_t includer_file_id,
uint32_t included_file_id,
- KitSrcLoc loc, int system);
+ KitSrcLoc loc, int system,
+ int resolved_system);
typedef struct KitSourceFile {
uint32_t id;
diff --git a/lang/cpp/pp/pp.c b/lang/cpp/pp/pp.c
@@ -871,5 +871,8 @@ uint32_t pp_pack_alignment(const Pp* pp) { return pp ? pp->pack_align : 0; }
void pp_add_include_edge(Pp* pp, u32 includer, u32 included, SrcLoc include_loc,
int system) {
- kit_source_add_include(pp->c, includer, included, include_loc, system);
+ /* This generic edge-recording entry point has no resolved-dir context, so it
+ * can only fall back to the spelling form for the resolved-system flag. */
+ kit_source_add_include(pp->c, includer, included, include_loc, system,
+ system);
}
diff --git a/lang/cpp/pp/pp_directive.c b/lang/cpp/pp/pp_directive.c
@@ -662,11 +662,16 @@ static int includer_dir(Pp* pp, SrcLoc loc, char* dir_out, size_t cap) {
* Both forms then walk the configured -I / -isystem dirs in order. */
static int find_and_open_include(Pp* pp, const char* path, int system,
SrcLoc loc, const u8** data, size_t* size,
- char* resolved, size_t resolved_cap) {
+ char* resolved, size_t resolved_cap,
+ int* resolved_system_out) {
char buf[4096];
u32 i;
size_t plen = kit_slice_cstr(path).len;
+ /* Absolute paths and the includer-relative ("...") step are not system
+ * search dirs; only a configured -isystem dir flips this to 1 below. */
+ *resolved_system_out = 0;
+
if (plen > 0 && path[0] == '/') {
if (try_open_include(pp, path, data, size)) {
if (plen + 1 > resolved_cap) return 0;
@@ -704,6 +709,7 @@ static int find_and_open_include(Pp* pp, const char* path, int system,
if (try_open_include(pp, buf, data, size)) {
if (dlen + 1 + plen + 1 > resolved_cap) return 0;
memcpy(resolved, buf, dlen + 1 + plen + 1);
+ *resolved_system_out = pp->inc_dirs[i].system ? 1 : 0;
return 1;
}
}
@@ -801,6 +807,7 @@ static void do_include(Pp* pp, const Tok* line, u32 n, SrcLoc loc) {
char path[4096];
char resolved[4096];
int system_form = 0;
+ int resolved_system = 0;
const u8* data;
size_t size;
Lexer* lex;
@@ -812,7 +819,7 @@ static void do_include(Pp* pp, const Tok* line, u32 n, SrcLoc loc) {
parse_include_path(pp, line, n, loc, path, sizeof(path), &system_form);
if (!find_and_open_include(pp, path, system_form, loc, &data, &size, resolved,
- sizeof(resolved))) {
+ sizeof(resolved), &resolved_system)) {
compiler_panic(pp->c, loc, "#include: file not found: %.*s",
KIT_SLICE_ARG(kit_slice_cstr(path)));
}
@@ -834,7 +841,8 @@ static void do_include(Pp* pp, const Tok* line, u32 n, SrcLoc loc) {
s.lex = lex;
src_push(pp, s);
- kit_source_add_include(pp->c, includer_id, included_id, loc, system_form);
+ kit_source_add_include(pp->c, includer_id, included_id, loc, system_form,
+ resolved_system);
}
/* ============================================================
@@ -1242,10 +1250,16 @@ static void do_embed(Pp* pp, const Tok* line, u32 n, SrcLoc loc) {
compiler_panic(pp->c, loc, "#embed: unexpected token in parameter list");
}
- if (!find_and_open_include(pp, path, system_form, loc, &data, &size, resolved,
- sizeof(resolved))) {
- compiler_panic(pp->c, loc, "#embed: file not found: %.*s",
- KIT_SLICE_ARG(kit_slice_cstr(path)));
+ {
+ /* #embed does not record a dependency edge, so the resolved-dir system
+ * flag is not consumed here. */
+ int embed_resolved_system = 0;
+ if (!find_and_open_include(pp, path, system_form, loc, &data, &size,
+ resolved, sizeof(resolved),
+ &embed_resolved_system)) {
+ compiler_panic(pp->c, loc, "#embed: file not found: %.*s",
+ KIT_SLICE_ARG(kit_slice_cstr(path)));
+ }
}
/* Apply limit(). */
diff --git a/src/api/compile.c b/src/api/compile.c
@@ -651,18 +651,12 @@ KitIterResult kit_dep_iter_next(KitDepIter* it, KitDepEdge* out) {
out->included_name =
included ? pool_slice(it->c->global, included->name) : KIT_SLICE_NULL;
out->include_loc = edge->include_loc;
- /* SourceInclude.system records only the spelling form (<...> vs "..."), not
- * which configured directory ultimately resolved the header: the resolved-dir
- * system flag (pp->inc_dirs[i].system in lang/cpp/pp/pp_directive.c) is never
- * threaded onto the dep edge — find_and_open_include / source_add_include
- * drop it. So a true from_system_path (e.g. "<...>" or "..." satisfied by an
- * -isystem dir, vs. a plain -I dir) is not derivable here without widening
- * the SourceInclude record + its producers. Until that plumbing exists, both
- * fields carry the same spelling bit: `bracketed` is its accurate meaning,
- * and `from_system_path` is reported as the spelling bit too (an
- * approximation that over-reports <...> via plain -I as system). */
+ /* `bracketed` is the spelling form (<...> vs "..."); `from_system_path` is the
+ * resolved-dir system flag (whether an -isystem dir satisfied the header),
+ * threaded from find_and_open_include through SourceInclude.resolved_system.
+ * They differ when a <...> include is resolved via a plain -I dir. */
out->bracketed = (uint8_t)(edge->system ? 1 : 0);
- out->from_system_path = out->bracketed;
+ out->from_system_path = (uint8_t)(edge->resolved_system ? 1 : 0);
out->pad[0] = 0;
out->pad[1] = 0;
return KIT_ITER_ITEM;
diff --git a/src/api/source.c b/src/api/source.c
@@ -26,10 +26,10 @@ KitStatus kit_source_add_builtin(KitCompiler* c, KitSlice name,
KitStatus kit_source_add_include(KitCompiler* c, uint32_t includer_file_id,
uint32_t included_file_id, KitSrcLoc loc,
- int system) {
+ int system, int resolved_system) {
if (!c) return KIT_INVALID;
return source_add_include(c->sources, includer_file_id, included_file_id, loc,
- system);
+ system, resolved_system);
}
KitStatus kit_source_file(KitCompiler* c, uint32_t file_id,
diff --git a/src/core/core.h b/src/core/core.h
@@ -82,8 +82,9 @@ typedef struct SourceInclude {
u32 includer_file_id;
u32 included_file_id;
SrcLoc include_loc;
- u8 system;
- u8 pad[3];
+ u8 system; /* spelling form: <...> (1) vs "..." (0) */
+ u8 resolved_system; /* resolved via a system (-isystem) include dir */
+ u8 pad[2];
} SourceInclude;
typedef struct SourceExpansion {
@@ -103,7 +104,7 @@ KitStatus source_add_memory(SourceManager*, KitSlice name, u32* id_out);
KitStatus source_add_builtin(SourceManager*, KitSlice name, u32* id_out);
KitStatus source_add_include(SourceManager*, u32 includer_file_id,
u32 included_file_id, SrcLoc include_loc,
- int system);
+ int system, int resolved_system);
KitStatus source_add_macro_expansion(SourceManager*, Sym macro_name,
SrcLoc spelling_loc, SrcLoc expansion_loc,
u32* id_out);
diff --git a/src/core/source.c b/src/core/source.c
@@ -125,12 +125,14 @@ KitStatus source_add_builtin(SourceManager* sm, KitSlice name, u32* id_out) {
KitStatus source_add_include(SourceManager* sm, u32 includer_file_id,
u32 included_file_id, SrcLoc include_loc,
- int system) {
+ int system, int resolved_system) {
if (includes_grow(sm)) return KIT_NOMEM;
sm->includes[sm->nincludes].info.includer_file_id = includer_file_id;
sm->includes[sm->nincludes].info.included_file_id = included_file_id;
sm->includes[sm->nincludes].info.include_loc = include_loc;
sm->includes[sm->nincludes].info.system = (u8)(system ? 1 : 0);
+ sm->includes[sm->nincludes].info.resolved_system =
+ (u8)(resolved_system ? 1 : 0);
sm->nincludes++;
return KIT_OK;
}