schemagen _CPP_KEYWORDS list is missing C++ keywords (mutable, wchar_t, char8_t, char16_t, char32_t, noexcept, typeid, *_cast, ...) — generated code does not compile #62

Open
opened 2026-08-23 15:28:20 +00:00 by weaselbot · 0 comments
Member

Summary

contrib/schemagen/weaseljson_schemagen.py generates a C++ struct member whose name is a C++ keyword when a JSON Schema property key is one of several keywords that are absent from the _CPP_KEYWORDS allow-list. The generated header then fails to compile. This happens for perfectly valid JSON Schemas — JSON object keys may be any string, including ordinary words like "mutable" or type names like "wchar_t"/"char8_t".

This is distinct from the closed issue #18, which only added the C++20 keywords (concept, consteval, constinit, co_await, co_return, co_yield, requires, module, import). Many older C++ keywords were never added to the list and are still missing. It is also distinct from the open issues #59 (digit-leading names) and #60 (non-identifier characters).

Root cause

contrib/schemagen/weaseljson_schemagen.py, _CPP_KEYWORDS set (line 160) and sanitize() (line 111):

def sanitize(name, fallback="x"):
    ...
    if keyword.iskeyword(s) or s in _CPP_KEYWORDS:
        s = s + "_"
    return s

sanitize() only suffixes a name when it is a Python keyword or in _CPP_KEYWORDS. keyword.iskeyword only knows Python keywords, so C++-only keywords must be listed in _CPP_KEYWORDS. That set is missing many C++ keywords, including at least:

mutable, wchar_t, char8_t, char16_t, char32_t, noexcept, typeid, static_cast, dynamic_cast, reinterpret_cast, const_cast, static_assert, thread_local, and_eq, or_eq, xor, xor_eq, not_eq, bitand, bitor, compl

(not_eq is missing even though not is present; static_assert is missing even though static is present; static_cast is missing even though static is present.)

Reproduction

Minimal schema (schema.json):

{"type":"object","additionalProperties":false,"properties":{"mutable":{"type":"string"}},"required":["mutable"]}
python3 contrib/schemagen/weaseljson_schemagen.py schema.json -o gen.h --namespace ts

schemagen exits 0 and emits (note std::string mutable; and &o->mutable;):

struct Root1 {
  std::string mutable;  // "mutable"
};
...
      case 0: return &o->mutable;
...
      if (key == "mutable") return 0;

Compiling any TU that includes the header fails (GCC 16, -std=c++20):

gen.h:20:15: error: declaration does not declare anything [-fpermissive]
   20 |   std::string mutable;  // "mutable"
      |               ^~~~~~~
gen.h:397:26: error: expected unqualified-id before 'mutable'
  397 |       case 0: return &o->mutable;

The same failure occurs for wchar_t, char8_t, char16_t, char32_t, noexcept, typeid, static_cast, xor, and_eq, compl, etc. (verified by generating a schema with each as the sole property key and running c++ -std=c++20 -fsyntax-only).

Expected behavior

sanitize() should append _ (e.g. mutable_) for every C++ keyword, the same way it already does for class, int, concept, etc., so the generated code compiles. Key matching (matchKey) compares against the original JSON key, so renaming only the C++ member is safe.

Impact

Schemas that use common words such as "mutable", or type-ish names such as "wchar_t"/"char8_t", as JSON property keys cannot be turned into compilable C++ structs. The failure is at C++ compile time of the generated header, after schemagen itself reported success (exit 0).

## Summary `contrib/schemagen/weaseljson_schemagen.py` generates a C++ struct member whose name is a **C++ keyword** when a JSON Schema property key is one of several keywords that are absent from the `_CPP_KEYWORDS` allow-list. The generated header then fails to compile. This happens for perfectly valid JSON Schemas — JSON object keys may be any string, including ordinary words like `"mutable"` or type names like `"wchar_t"`/`"char8_t"`. This is distinct from the closed issue #18, which only added the **C++20** keywords (`concept`, `consteval`, `constinit`, `co_await`, `co_return`, `co_yield`, `requires`, `module`, `import`). Many older C++ keywords were never added to the list and are still missing. It is also distinct from the open issues #59 (digit-leading names) and #60 (non-identifier characters). ## Root cause `contrib/schemagen/weaseljson_schemagen.py`, `_CPP_KEYWORDS` set (line 160) and `sanitize()` (line 111): ```python def sanitize(name, fallback="x"): ... if keyword.iskeyword(s) or s in _CPP_KEYWORDS: s = s + "_" return s ``` `sanitize()` only suffixes a name when it is a Python keyword **or** in `_CPP_KEYWORDS`. `keyword.iskeyword` only knows Python keywords, so C++-only keywords must be listed in `_CPP_KEYWORDS`. That set is missing many C++ keywords, including at least: `mutable`, `wchar_t`, `char8_t`, `char16_t`, `char32_t`, `noexcept`, `typeid`, `static_cast`, `dynamic_cast`, `reinterpret_cast`, `const_cast`, `static_assert`, `thread_local`, `and_eq`, `or_eq`, `xor`, `xor_eq`, `not_eq`, `bitand`, `bitor`, `compl` (`not_eq` is missing even though `not` is present; `static_assert` is missing even though `static` is present; `static_cast` is missing even though `static` is present.) ## Reproduction Minimal schema (`schema.json`): ```json {"type":"object","additionalProperties":false,"properties":{"mutable":{"type":"string"}},"required":["mutable"]} ``` ```sh python3 contrib/schemagen/weaseljson_schemagen.py schema.json -o gen.h --namespace ts ``` schemagen exits 0 and emits (note `std::string mutable;` and `&o->mutable;`): ```cpp struct Root1 { std::string mutable; // "mutable" }; ... case 0: return &o->mutable; ... if (key == "mutable") return 0; ``` Compiling any TU that includes the header fails (GCC 16, `-std=c++20`): ``` gen.h:20:15: error: declaration does not declare anything [-fpermissive] 20 | std::string mutable; // "mutable" | ^~~~~~~ gen.h:397:26: error: expected unqualified-id before 'mutable' 397 | case 0: return &o->mutable; ``` The same failure occurs for `wchar_t`, `char8_t`, `char16_t`, `char32_t`, `noexcept`, `typeid`, `static_cast`, `xor`, `and_eq`, `compl`, etc. (verified by generating a schema with each as the sole property key and running `c++ -std=c++20 -fsyntax-only`). ## Expected behavior `sanitize()` should append `_` (e.g. `mutable_`) for every C++ keyword, the same way it already does for `class`, `int`, `concept`, etc., so the generated code compiles. Key matching (`matchKey`) compares against the original JSON key, so renaming only the C++ member is safe. ## Impact Schemas that use common words such as `"mutable"`, or type-ish names such as `"wchar_t"`/`"char8_t"`, as JSON property keys cannot be turned into compilable C++ structs. The failure is at C++ compile time of the generated header, after schemagen itself reported success (exit 0).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: weaselab/weaseljson#62