Rust does, successfully, guarantee the lack of data races. It also guarantees the lack of memory-unsafety resulting from race conditions in general (which to be fair largely just means "it guarantees a lack of data races", though it does also include things like "race conditions won't result in a use after free or an out of bounds memory access").
If by address it you mean "show how C/C++ does this"... they don't and this is well known.
If by address it you mean "prove that rust doesn't do what it says it does"... as that point you're inviting someone to teach you the details of how rust works down to the nitty gritty in an HN comment. You'd be much better off finding and reading the relevant materials on the internet than someones off hand attempt at recreating them on HN.
Sadly, I don't know rustlang, so I can't tell if the inability to describe its features in more commonly used terms is due to incompetence or the features being irrelevant to this discussion (see the title of the thread).
As near as I can tell to give you the answer you're looking for I'd have to explain the majority of rust to you. How traits work, and auto traits, and unsafe trait impls, and ownership, and the borrow checker, and for it to make sense as a practical thing interior mutability, and then I could point you at the standard library concepts of Send and Sync which someone mentioned above and they would actually make sense, and then I could give some examples of how everything comes together to enable memory safe, efficient, and ergonomic, threading primitives.
But this would no longer be a discussion about a rust language feature, but a tutorial on rust in general. Because to properly understand how the primitives that allow rust to build safe abstractions work, you need to understand most of rust.
Send and Sync (mentioned up thread) while being useful search terms, are some of the last things in a reasonable rust curriculum, not the first. I could quickly explain them to someone who already knew rust, and hadn't used them (or threads) at all, because they're simple once you have the foundation of "how the rest of rust works". Skipping the foundation doesn't make sense.
† "Memory safety" was admittedly possibly popularized by rust, but is equivalent to "the absence of undefined behaviour" which should be understandable to any C programmer.
Well, yes, but that's the whole value of Rust: you don't need to use these overly-cautious defensive constructs, (at least not to prevent data races), because the language prevents them for you automatically.
Yes
> I.e. it assumes that all other code is Rust for the purpose of those checks?
Not exactly, it merely assumes that you upheld the documented invariants when you wrote code to call/be-called-from other languages. For example that if I have a `extern "C" fn foo(x: &mut i32)` that
- x points to a properly aligned properly allocated i32 (not to null, not to the middle of un-unallocated page somewhere)
- The only way that memory will be accessed for the duration of the call to `foo` is via `x`. Which is to say that other parts of the system won't be writing to `x` or making assumptions about what value is stored in its memory until the function call returns (rust is, in principle, permitted to store some temporary value in `x`s memory even if the code never touches x beyond being passed it. So long as when `foo` returns the memory contains what it is supposed to). Note that this implies that a pointer to the same memory isn't also being passed to rust some other way (e.g. through a static which doesn't have a locked lock around it)
- foo will be called via the standard "C" calling convention (on x86_64 linux this for instance means that the stack pointer must be 2-byte aligned. Which is the type of constraint that is very easy to violate from assembly and next to impossible to violate from C code).
That it's up to the programmer to verify the invariants is why FFI code is considered "unsafe" in rust - programmer error can result in unsoundness. But if you, the programmer, are confident you have upheld the invariants you still get the guarantees about the broader system.
Rust is generally all about local reasoning. It doesn't actually care very much what the rest of the system is, so long as it called us following the agreed upon contract. It just has a much more explicit definition of what that contract is then C.
This is fairly narrow, often C functions for example aren't actually safe, for example they take a pointer and it must be valid, that's not inherently safe, or they have requirements about the relative values of parameters or the state of the wider system which can't be checked by the Rust, again unsafe. But there are cases where this affordance is a nice improvement.
I like the term "checked" and "unchecked" better but not enough to actually lobby to change them, and as a term of art they're fine.
As far as I can tell, ANY guarantee provided by ANY language is "just a language construct" that fails if we assume there is other code executing which is ill-behaved.
The point is rather that it’s not. The “trait send sync things” specify whether a value of the type is allowed to be respectively move or borrowed across thread boundaries.
It won't prevent all races, but it might help avoid mistakes in a few of em. And concurrency is such a pain; any such machine-checked guarantees are probably nice to have to those dealing with em - caveat being that I'm not such a person.