Skip to content

infer/aot: allow C++-keyword function names via AOT name-mangling#2655

Merged
borisbat merged 1 commit into
masterfrom
bbatkin/allow-cpp-keyword-function-names
May 14, 2026
Merged

infer/aot: allow C++-keyword function names via AOT name-mangling#2655
borisbat merged 1 commit into
masterfrom
bbatkin/allow-cpp-keyword-function-names

Conversation

@borisbat
Copy link
Copy Markdown
Collaborator

@borisbat borisbat commented May 14, 2026

Inspiration

struct Foo { a: float; }

def string(handle : Foo) : string { return "Foo {handle.a}"; }
def float(handle : Foo) : float { return handle.a; }
def float2(handle : Foo) : float2 { return float2(handle.a, handle.a); }

[export] def main() {}

Summary

def float(...), def int(...), def double(...), def do(...) were rejected with error[30163] invalid function name — a surprising asymmetry next to def string(...) and def float2(...), which always compiled fine. The parser accepts all of them (function_name → das_type_name in src/parser/ds2_parser.ypp:1316-1408); a post-parse lint guard at src/ast/ast_lint.cpp:867-884 was the actual gate, rejecting any function name in a hardcoded C++-keyword set. The asymmetry was just that set: float / int / double / do are C++ keywords, but float2 / string / int2 are daslang-specific identifiers that happen not to clash.

The lint guard existed because the AOT C++ emitter would otherwise generate a literal float(...) C++ function, which is invalid. But the emitter already has a name-rewriting helper (aotSuffixNameEx) used for operator overloads — it just didn't kick in for plain alphanumeric names. This PR has it kick in for C++-keyword names too, and drops the now-redundant function-name lint guard.

  • daslib/aot_cpp.dasaotSuffixNameEx seeds prefix = is_cpp_keyword(funcName) so C++-keyword names get the _Func prefix already used for operator overloads (def +_FuncAdd_<hash>). After this, def float emits as _Funcfloat_<hash>.
  • src/ast/ast_lint.cpp — drop isValidFunctionName and its callsite. The other 5 isCppKeyword callsites (module / enum / enum-value / struct / struct-field names) stay — those embed 1:1 into C++ and need the guard.
  • tests/language/failed_reserved_names.das — drop the def do case and 30163 from the expect line.
  • tests/aot/test_cpp_keyword_names.das (new) — positive test exercising def float / def int / def double / def do via interpreter + AOT + JIT round-trip.

Scope is function names only; struct/enum/module/etc. names still 1:1 into C++ identifiers and are correctly out of scope.

Generated C++ for the new test (excerpt) confirms the mangling fires:

inline int32_t _Funcfloat_a367204646d2e00e ( Context * __context__, struct Foo const & h );
inline float   _Funcint_cb77d1bb25db9a2c    ( Context * __context__, struct Foo const & h );
inline int32_t _Funcdouble_55b8b2d232dd0bd3 ( Context * __context__, struct Foo const & h );
inline int32_t _Funcdo_3886b04bf9d216e6     ( Context * __context__, struct Foo const & h );

Includes three mouse-data/docs/*.md blind-mouse cards capturing the diagnosis (parser vs lint asymmetry, AOT name mangler details, failed_* test-prefix convention) — personal Q&A cache, no behavior impact.

Test plan

  • examples/wip.das (the originally failing case from the report) now compiles clean
  • tests/language/failed_reserved_names.das still PASSes (matches new expect line — codes 30106:3, 30146, 30148, 30152, 30240, 30282)
  • tests/aot/test_cpp_keyword_names.das — interpreter: 5/5 PASS
  • tests/aot/test_cpp_keyword_names.das — AOT round-trip via test_aot dastest/dastest.das -use-aot -- --use-aot --run …: 5/5 PASS
  • tests/aot/test_cpp_keyword_names.das — JIT via daslang dastest/dastest.das -jit -- --run …: 5/5 PASS
  • Generated C++ inspected: _Funcfloat_<hash> / _Funcint_<hash> / _Funcdouble_<hash> / _Funcdo_<hash> present at def + call + wrapper sites
  • Full tests/language/ regression: 927/927 PASS
  • Full tests/aot/ regression: 69/69 PASS
  • Full tests/ interpreter regression: 8016/8022 PASS (6 environment-conditional skips, 0 failed, 0 errors)
  • mcp__daslang__lint on changed .das files: 0 issues
  • mcp__daslang__format_file on changed .das files: already formatted

🤖 Generated with Claude Code

`def float(...)`, `def int(...)`, `def double(...)`, `def do(...)` were
rejected with error[30163] "invalid function name" — surprising next to
`def string(...)` and `def float2(...)`, which compiled fine. The parser
accepts all of them (function_name → das_type_name); a post-parse lint
guard was the gate, rejecting any name in a hardcoded C++-keyword set.
The asymmetry was just that set: `float` / `int` / `double` are C++
keywords, but `float2` / `string` / `int2` aren't.

Drop the function-name guard and have the AOT emitter mangle keyword
names the same way it already mangles operator overloads.

- daslib/aot_cpp.das: aotSuffixNameEx now seeds prefix = is_cpp_keyword,
  so `def float` AOTs to `_Funcfloat_<hash>` (valid C++) instead of
  literal `float`.
- src/ast/ast_lint.cpp: remove isValidFunctionName + its callsite. The
  other 5 isCppKeyword guards (module/enum/enum-value/struct/field)
  stay — those embed 1:1 into C++ and need the guard.
- tests/language/failed_reserved_names.das: drop the `def do` case and
  30163 from the expect line.
- tests/aot/test_cpp_keyword_names.das: positive test exercising
  `def float`/`def int`/`def double`/`def do` via interpreter, AOT,
  and JIT.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 14, 2026 15:27
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Removes the post-parse lint guard that rejected daslang function names matching C++ keywords (float, int, double, do, …) and instead reuses the existing AOT name-mangler (aotSuffixNameEx) so those names emit as valid C++ identifiers (e.g. _Funcfloat_<hash>). Other identifier classes (module/enum/struct/field) that still embed 1:1 into C++ keep their guard.

Changes:

  • Seed aotSuffixNameEx's prefix flag with is_cpp_keyword(funcName) so keyword names get the _Func prefix already used for operator overloads.
  • Drop isValidFunctionName and its invocation from ast_lint.cpp.
  • Update failed_reserved_names.das (remove def do case and 30163 from expect) and add a positive AOT/JIT/interpreter test test_cpp_keyword_names.das.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
daslib/aot_cpp.das Seed mangler's prefix flag with is_cpp_keyword so keyword names get _Func prefix in AOT C++ output.
src/ast/ast_lint.cpp Remove obsolete function-name C++-keyword lint guard now that AOT mangling handles it.
tests/language/failed_reserved_names.das Drop the def do failing-case and 30163 from the expected error list.
tests/aot/test_cpp_keyword_names.das New positive test exercising def float/int/double/do for interpreter + AOT + JIT.
mouse-data/docs/*.md Three personal Q&A notes documenting the parser-vs-lint asymmetry, the AOT mangler, and the failed_* test convention; no behavior impact.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@borisbat borisbat merged commit 918edd8 into master May 14, 2026
32 checks passed
@borisbat borisbat deleted the bbatkin/allow-cpp-keyword-function-names branch May 14, 2026 15:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants