Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] implement a borrow checker? #252

Closed
pheonixfirewingz opened this issue Feb 8, 2023 · 9 comments
Closed

[Question] implement a borrow checker? #252

pheonixfirewingz opened this issue Feb 8, 2023 · 9 comments

Comments

@pheonixfirewingz
Copy link

In rust they implement a borrow checker to stop some undefined and stop buffer overflows would it be adventurous to have one in cpp2?

@pheonixfirewingz
Copy link
Author

This explains it better: https://rustc-dev-guide.rust-lang.org/borrow_check.html

@AbhinavK00
Copy link

I don't think it is feasible to implement a borrow checker at transpiler level, correct me if i'm wrong.
Personally, I think a borrow checker is too restrictive, maybe we can have a relaxed version of borrow checker if possible, would definitely like to see others' views on this topic.

@switch-blade-stuff
Copy link

Rust-style borrow checker is good for static analysis and whatnot, but it requires the language to be structured around it, which would require C++2 to have a native compiler and would most likely break interoperability with "classic" C++ code, or at least would require API shims.

That being said, having builtin facilities to enable static analysis (beyond local lifetime analysis) is a good idea.

@filipsajdak
Copy link
Contributor

From the page you mentioned:

tasked with enforcing a number of properties:

  1. That all variables are initialized before they are used.
  2. That you can't move the same value twice.
  3. That you can't move a value while it is borrowed.
  4. That you can't access a place while it is mutably borrowed (except through the reference).
  5. That you can't mutate a place while it is immutably borrowed.
  6. etc
  1. is already done by cppfront. The following code:
main: () -> int = {
    i : int;

    fun(i);
}

fun: (i : int) = {
    std::cout << i << std::endl;
}

ends with an error:

lifetimesafety.cpp2...
lifetimesafety.cpp2(4,9): error: local variable i is used before it was initialized
  ==> program violates initialization safety guarantee - see previous errors

Some points will be covered by P1179 R1 Lifetime safety (check: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1179r1.pdf).

@switch-blade-stuff
Copy link

Also to add, point 2 (and to extent, 3-5) does not apply to C++, since C++ move works differently from Rust's, as such move does not invalidate an object, so you can move as many times as you want.

@filipsajdak
Copy link
Contributor

The borrowing topic probably is related to an issue that was already identified in cppfront:

One way to suppress this could be to require a mutating argument to be qualified with inout, which I've thought of and @jbatez suggested in #198.

More here: #231 (comment)

@Cons-Cat
Copy link

Cons-Cat commented Feb 8, 2023

Also to add, point 2 (and to extent, 3-5) does not apply to C++, since C++ move works differently from Rust's, as such move does not invalidate an object, so you can move as many times as you want.

Would it be possible for a Rust-like move to be added in a C++ transpiler as sugar around scope_guard or similar move-only wrappers?

@AbhinavK00
Copy link

AbhinavK00 commented Feb 9, 2023

Having only one Mutable borrow in rust is what I think is too restrictive.
All about single-threaded programs from now on---
Having multiple mutating references/pointers is good as long as none of them invalidate the object(delete it or move or some other ways maybe). We need to have a clear distinction between invalidating and mutating functions which is hard (having rust-like move is the first step towards that i think). After that, we can have pointer-like contructs which can access and mutate the object but don't own it so they can't invalidate it and those contructs can only be passed to non-invalidating functions. That'll leave us with only having to make sure that there's no pointers to the object which outlive the owner itself. We can do this by freezing the owner itself (making it non-accessible) when there are any pointers to it and some lifetime analysis. The hardest is doing this in a way that does not make our compile times go through the roof, they're already not good when using templates and replacing preprocessor with reflection and generation is probably going to make it worse.

For multi-threaded programs, we can fall back to rust-like restrictions. Val's model of safety is similar to rust's which I think is equally restrictive but it is worth looking into val's projections and subscripts.

@hsutter
Copy link
Owner

hsutter commented Mar 1, 2023

@filipsajdak covered it... this is intended to be covered primarily by the above-linked Lifetime static analysis which is not yet implemented in cppfront (and secondarily by things like guaranteed initialization, that one is already implemented in cppfront).

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

No branches or pull requests

6 participants