{"id":24772510,"url":"https://github.com/san7o/cchecker","last_synced_at":"2025-09-13T05:46:36.436Z","repository":{"id":274057706,"uuid":"921772655","full_name":"San7o/cchecker","owner":"San7o","description":"Borrow checker in C++","archived":false,"fork":false,"pushed_at":"2025-01-24T16:11:03.000Z","size":11,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-21T23:06:18.097Z","etag":null,"topics":["borrow-checker","cpp"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/San7o.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-01-24T15:34:42.000Z","updated_at":"2025-02-13T17:03:01.000Z","dependencies_parsed_at":"2025-01-24T16:42:31.485Z","dependency_job_id":null,"html_url":"https://github.com/San7o/cchecker","commit_stats":null,"previous_names":["san7o/cchecker"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/San7o/cchecker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/San7o%2Fcchecker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/San7o%2Fcchecker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/San7o%2Fcchecker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/San7o%2Fcchecker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/San7o","download_url":"https://codeload.github.com/San7o/cchecker/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/San7o%2Fcchecker/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261206111,"owners_count":23124838,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["borrow-checker","cpp"],"created_at":"2025-01-29T04:23:12.426Z","updated_at":"2025-06-21T23:06:20.409Z","avatar_url":"https://github.com/San7o.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# cchecker\n\n## TLDR\n\nThis [header only](./cchecker.hpp) library is a little run-time borrow\nchecker implemented in C++. It doesn't use any recent features other\nthan templates so It is quite portable, the only header included\nis `\u003ccassert\u003e` to panic when the borrow rules are not met.\n\n## Writeup\n\nI wanted to implement a borrow checker in C, It seemed like a cool\nproject for an afternoon. A borrow checker (at least, my borrow checker)\nis a system that imposes the following rules:\n- There can be infinite (many) immutable references to a value\n- There can be only one mutable referene to a value\n- The two rules above cannot happen togheter\n- The lifetime of a value is boud to the owner's scope (so references\n  must be invalidated if the owner goes out of scope)\n  \nIf any of the aforementioned rules does not hold, the code panics (an\nassertion fails). Languages like Rust have this incorporated in the\ncompiler, but for all the other folks this needs to be implemented\nmanually. While creating a compile-time borrow checker is not trivial\nat all, the C++ committee is pushing more and more safety features into\nthe language. A [famous proposal](https://safecpp.org/draft.html#introduction)\nfor a full-fledged C++ borrow cheker was\nmade but the context was quite... controversial. From my understanding,\nsome safety features were already discussed and \"almost\" ready to be\nimplemented, we know that the C++ standard moves very slow and features\ntake years or decades to be implemented. This proposal came out of nowere\nwith a full implementation (lots of hours of work) but was \"never\"\nproperly discussed with the community, so the future of this proposal is\nquite uncertain.\n\nWell, enought talking, let's get into business.\nI am not building one of that (but maybe I will eventually), right\nnow I just want to create a run-time borrow checker that panics when\nthe rules are not met. While this is not as powerful as a compile time\none, It follows the principle of \"fail early\": if we made some \"unsafe\"\nvariable declarations we should be punished as soon as possible when we\nreach that code.\n\nNow. I tried to write everything in C, trust me, but It wasn't quite..\nlet's say, _ergonomic_. C does not have the concept of constructors\nand destructors bound to the scope of a variable, and I needed them\nsince I need to know when a reference to a variable goes out of scope,\namong many other things. I tried creating a sort of constructor-desctructor\nwith macros but It was _very_ ugly. Something like this:\n```cpp\n#define CHECK(NAME, ...) { \\\n  constructor_ ##Check(\u0026 NAME); \\\n  __VA_ARGS__ \\\n  dtor_ ##Check(\u0026 NAME); \\\n} (void)0\n\n...\n\nint x, y, z;\nCHECK(x,\n  CHECK(y,\n    CHECK(z,\n\t  z = x + y;\n    );\n  );\n);\n```\n\nCool, not practical. So I moved to C++ and everything was much easier.\nThe owner of a value wraps the value in an inner context, and the\nreferences hold a pointer to this context. It is very similar to\nsmart pointer: the context contains a counter for mutable and\nimmutable references that gets incremented when a new reference gets\ncreated and removed when a reference goes out of scope. If the owner's\ndestructor gets called and the counters are not 0, that means that\nthe references are not valid anymore so It panics. In particular, I\ncreated the following calsses:\n- `Val\u003cT\u003e`: An immutable value of type `T`\n- `ValMut\u003cT\u003e`: A mutable value of type `T`\n- `ValRef\u003cT\u003e`: An immutable reference to a value (that It can be both\n  mutable or immutable) of type `T`\n- `ValMutRef\u003cT\u003e`: A mutable reference to a mutable value of type `T`\n\nYou use `getRef()` or `getRefMut()` to get the reference types.\n\nFor example, you can have multiple immutable references of a mutable\nvalue:\n\n```cpp\ncheck::Val\u003cint\u003e x = 1;\ncheck::ValRef\u003cint\u003e a = x.getRef();   // OK\ncheck::ValRef\u003cint\u003e a2 = x.getRef();  // OK\nassert(a.get() == 1);\nassert(a2.get() == 1);\n```\n\nBut you cannot have multiple mutable references or both mutable and\nimmutable references:\n\n```cpp\ncheck::ValRef\u003cint\u003e b = y.getRef();\ncheck::ValRef\u003cint\u003e b2 = y.getRef();\nassert(b.get() == 3);\nassert(b2.get() == 3);\n//check::ValMutRef\u003cint\u003e b3 = y.getMutRef(); // FAIL!\n\n```\n\nWhen you create a mutable reference, you cannot use the owner to access\nthe value until all the references to that owner go out of scope:\n\n```cpp\ncheck::ValMut\u003cint\u003e c = 10;\ncheck::ValMutRef\u003cint\u003e d = c.getMutRef();\n// assert(c.get() == 10); // FAIL!\nassert(d.get() == 10);\n```\n\nOverall I had great fun with this little project, I will probably add\nthis to my own [standard library](https://github.com/San7o/tenno-tl)\nso I can reuse It easily.\n\nIts already time for the next project lol. Bye.\n\nNote: I did not use any form of AI neither I looked at other's work.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsan7o%2Fcchecker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsan7o%2Fcchecker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsan7o%2Fcchecker/lists"}