Skip to content

Commit 0f870c6

Browse files
speak-agentclaude
andcommitted
the [c-abi.absent] parser gets its own function, and the docs index is regenerated
Two CI reports, both from the first push. clang 20.1.7 on Windows crashed during LLVM IR generation of `parse_string` (exception 0xC0000005, the frame naming the `[c-abi.absent]` block's compound statement). Every other host compiled the same source. This codebase has met the shape before --- a construct that is fine in a function and not in a large one inside a module interface unit --- and the answer is the same: the block becomes `parse_c_abi_absent`, a free function, and the reason is written beside it so the next reader does not inline it back. `.agents/docs/README.md` regenerated, and the ecosystem design's front matter carries a `status` the structure check knows. Co-authored-by: Claude Code <noreply@anthropic.com>
1 parent cbb1a07 commit 0f870c6

3 files changed

Lines changed: 88 additions & 60 deletions

File tree

.agents/docs/2026-09-20-openkal-c-environment-ecosystem-design.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
subject: design
3-
status: draft-for-review
3+
status: active
44
---
55

66
# openkal 生态:能力的时刻模型,以及 C 环境方案空间的划分

.agents/docs/README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ superseded_by: 2026-09-07-....md # when status is superseded
1818
---
1919
```
2020

21-
296 records.
21+
300 records.
2222

2323
## By subject
2424

@@ -30,6 +30,8 @@ Records that declare one. Everything else is listed by date below.
3030

3131
### design
3232

33+
- [openkal 生态:能力的时刻模型,以及 C 环境方案空间的划分](2026-09-20-openkal-c-environment-ecosystem-design.md) — active
34+
- [#674:`presents = "posix"` 在 Windows 上兑现契约的下半段](2026-09-19-issue-674-cenv-posix-preinclude-design.md) — active
3335
- [The build database of #636, and two defects on the way to the latest xlings](2026-09-14-636-build-database-and-the-latest-xlings.md) — active
3436

3537
### docs
@@ -48,10 +50,18 @@ Records that declare one. Everything else is listed by date below.
4850

4951
- [Two answers and two silences: the scanner's second grammar, and the manifest keys nothing reads](2026-09-09-two-answers-and-two-silences.md) — active
5052

53+
### plan
54+
55+
- [C 环境生态方案:执行计划](2026-09-20-ecosystem-execution-plan.md) — active
56+
5157
### plugins
5258

5359
- [The category the plugin taxonomy does not name, and what a platform actually decomposes into](2026-09-11-distribution-plugins-and-platform-decomposition.md) — active
5460

61+
### review
62+
63+
- [#674 设计方案评审:`-include unistd.h` 在 Windows + `presents = "posix"` 上的可行性](2026-09-20-issue-674-design-review.md) — active
64+
5565
### targets
5666

5767
- [A verified Web run that asked the host for node](2026-09-12-a-verified-web-run-that-asked-the-host-for-node.md) — landed
@@ -81,6 +91,10 @@ Records that declare one. Everything else is listed by date below.
8191

8292
### 2026-09
8393

94+
- [openkal 生态:能力的时刻模型,以及 C 环境方案空间的划分](2026-09-20-openkal-c-environment-ecosystem-design.md) — active
95+
- [#674 设计方案评审:`-include unistd.h` 在 Windows + `presents = "posix"` 上的可行性](2026-09-20-issue-674-design-review.md) — active
96+
- [C 环境生态方案:执行计划](2026-09-20-ecosystem-execution-plan.md) — active
97+
- [#674:`presents = "posix"` 在 Windows 上兑现契约的下半段](2026-09-19-issue-674-cenv-posix-preinclude-design.md) — active
8498
- [运行时绑定方案 v3:让 mcpp 真正安装它所声明的运行时](2026-09-17-runtime-binding-multi-repo-plan.md) — landed
8599
- [#662:目标侧由依赖图提供时,编译器的隐式头文件搜索仍指向宿主](2026-09-17-issue-662-graph-target-header-isolation-plan.md) — active
86100
- [Issue #660 分析:`glibc@2.44` 绑定在 2.44.3 发布后解析失败](2026-09-17-issue-660-glibc-line-binding-analysis.md) — landed

modules/manifest/src/toml.cppm

Lines changed: 72 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,75 @@ std::optional<std::string> find_disallowed_array_of_tables(
561561

562562
} // namespace
563563

564+
// [c-abi.absent] — the facilities a C library does not supply (design
565+
// 2026-09-20 §5.7.5). The set of names it DOES supply is not enumerable in a
566+
// manifest; the exceptions are, and enumerating an exception is what lets a CI
567+
// run contradict it.
568+
//
569+
// [c-abi.absent]
570+
// fork = { form = "link" }
571+
// mprotect = { form = "enosys", note = "openkal has no operation upon a
572+
// mapping's protection" }
573+
//
574+
// `form` is required and closed: a facility absent in an unnamed shape is one
575+
// nobody can assert against. `link` is the shape openkal's own model requires
576+
// (SPEC 0.14 §6.1, which calls a run-time report of unsupportedness a defect);
577+
// the other two are departures from it, named so that a departure is something
578+
// that can be counted.
579+
//
580+
// A FREE FUNCTION AND NOT A BLOCK INSIDE `parse_string`, FOR A MEASURED
581+
// REASON. Written inline it crashed clang 20.1.7 on Windows during LLVM IR
582+
// generation of `parse_string` (exception 0xC0000005, the frame naming this
583+
// block's compound statement); every other host compiled it. This codebase has
584+
// met the shape before — a construct that is fine in a function and not in a
585+
// large one inside a module interface unit — and the answer is the same: give
586+
// it its own function.
587+
inline std::expected<std::vector<mcpp::targetside::CAbiAbsentEntry>, std::string>
588+
parse_c_abi_absent(const t::Value& v) {
589+
std::vector<mcpp::targetside::CAbiAbsentEntry> out;
590+
if (!v.is_table())
591+
return std::unexpected(std::string(
592+
"[c-abi.absent] must be a table of facility names, each with a "
593+
"`form`: fork = { form = \"link\" }"));
594+
for (auto const& kv : v.as_table()) {
595+
const std::string& name = kv.first;
596+
const t::Value& ent = kv.second;
597+
if (!ent.is_table())
598+
return std::unexpected(std::format(
599+
"[c-abi.absent].{} must be a table with a `form`: "
600+
"{} = {{ form = \"link\" }}", name, name));
601+
const auto& et = ent.as_table();
602+
for (auto const& m : et)
603+
if (m.first != "form" && m.first != "note")
604+
return std::unexpected(std::format(
605+
"[c-abi.absent].{} has no member '{}'; the members are: "
606+
"form, note", name, m.first));
607+
auto fit = et.find("form");
608+
if (fit == et.end() || !fit->second.is_string())
609+
return std::unexpected(std::format(
610+
"[c-abi.absent].{} is missing `form`. An absence with no "
611+
"named shape is one nothing can assert against; the shapes "
612+
"are \"link\" (the definition is absent), \"enosys\" (it "
613+
"exists and reports that it cannot act) and "
614+
"\"accepted-no-effect\" (the call succeeds and part of what "
615+
"it asked for is not done).", name));
616+
auto form = mcpp::targetside::parse_c_abi_absent_form(fit->second.as_string());
617+
if (!form)
618+
return std::unexpected(std::format(
619+
"[c-abi.absent].{}.form = \"{}\" names no known shape. The "
620+
"shapes are \"link\", \"enosys\" and \"accepted-no-effect\".",
621+
name, fit->second.as_string()));
622+
mcpp::targetside::CAbiAbsentEntry e;
623+
e.name = name;
624+
e.form = *form;
625+
if (auto nit = et.find("note"); nit != et.end() && nit->second.is_string())
626+
e.note = nit->second.as_string();
627+
out.push_back(std::move(e));
628+
}
629+
std::ranges::sort(out, {}, &mcpp::targetside::CAbiAbsentEntry::name);
630+
return out;
631+
}
632+
564633
std::expected<Manifest, ManifestError> parse_string(std::string_view content,
565634
const std::filesystem::path& origin,
566635
LoadContext ctx) {
@@ -1085,65 +1154,10 @@ std::expected<Manifest, ManifestError> parse_string(std::string_view content,
10851154
"[c-abi] has no member '{}'; the members are: absent, "
10861155
"builtins, data-model, presents, wchar", key)));
10871156
}
1088-
// [c-abi.absent] — the facilities this C library does not supply
1089-
// (design 2026-09-20 §5.7.5). The set of names it DOES supply is not
1090-
// enumerable in a manifest; the exceptions are, and enumerating an
1091-
// exception is what lets a CI run contradict it.
1092-
//
1093-
// [c-abi.absent]
1094-
// fork = { form = "link" }
1095-
// mprotect = { form = "enosys", note = "openkal has no operation
1096-
// upon a mapping's protection" }
1097-
//
1098-
// `form` is required and closed: a facility that is absent in an
1099-
// unnamed shape is one nobody can assert against. `link` is the shape
1100-
// openkal's own model requires (SPEC 0.14 §6.1, which calls a
1101-
// run-time report of unsupportedness a defect); the other two are
1102-
// departures from it, and they are named so that a departure is
1103-
// something somebody can count.
11041157
if (auto ait = ct->find("absent"); ait != ct->end()) {
1105-
if (!ait->second.is_table())
1106-
return std::unexpected(error(origin,
1107-
"[c-abi.absent] must be a table of facility names, each "
1108-
"with a `form`: fork = { form = \"link\" }"));
1109-
for (auto const& [name, entry] : ait->second.as_table()) {
1110-
if (!entry.is_table())
1111-
return std::unexpected(error(origin, std::format(
1112-
"[c-abi.absent].{} must be a table with a `form`: "
1113-
"{} = {{ form = \"link\" }}", name, name)));
1114-
mcpp::targetside::CAbiAbsentEntry e;
1115-
e.name = name;
1116-
auto const& et = entry.as_table();
1117-
for (auto const& [k, _] : et)
1118-
if (k != "form" && k != "note")
1119-
return std::unexpected(error(origin, std::format(
1120-
"[c-abi.absent].{} has no member '{}'; the "
1121-
"members are: form, note", name, k)));
1122-
auto fit = et.find("form");
1123-
if (fit == et.end() || !fit->second.is_string())
1124-
return std::unexpected(error(origin, std::format(
1125-
"[c-abi.absent].{} is missing `form`. An absence "
1126-
"with no named shape is one nothing can assert "
1127-
"against; the shapes are \"link\" (the definition is "
1128-
"absent), \"enosys\" (it exists and reports that it "
1129-
"cannot act) and \"accepted-no-effect\" (the call "
1130-
"succeeds and part of what it asked for is not "
1131-
"done).", name)));
1132-
auto form = mcpp::targetside::parse_c_abi_absent_form(
1133-
fit->second.as_string());
1134-
if (!form)
1135-
return std::unexpected(error(origin, std::format(
1136-
"[c-abi.absent].{}.form = \"{}\" names no known "
1137-
"shape. The shapes are \"link\", \"enosys\" and "
1138-
"\"accepted-no-effect\".",
1139-
name, fit->second.as_string())));
1140-
e.form = *form;
1141-
if (auto nit = et.find("note");
1142-
nit != et.end() && nit->second.is_string())
1143-
e.note = nit->second.as_string();
1144-
decl.absent.push_back(std::move(e));
1145-
}
1146-
std::ranges::sort(decl.absent, {}, &mcpp::targetside::CAbiAbsentEntry::name);
1158+
auto absent = parse_c_abi_absent(ait->second);
1159+
if (!absent) return std::unexpected(error(origin, absent.error()));
1160+
decl.absent = std::move(*absent);
11471161
}
11481162
if (auto pit = ct->find("presents"); pit != ct->end()) {
11491163
if (!pit->second.is_string())

0 commit comments

Comments
 (0)