Skip to content

Replace one of the examples of the aliasing rule #2715

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

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 23 additions & 8 deletions src/borrowing/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,36 @@ fn main() {
}
```

Similarly, consider the case of iterator invalidation:
We can also look at a case where these rules prevent incorrect optimizations:

```rust,editable,compile_fail
fn sum_and_zero(a: &mut i32, b: &mut i32) {
*a = *a + *b;
*b = 0;
}

fn main() {
let mut vec = vec![1, 2, 3, 4, 5];
for elem in &vec {
vec.push(elem * 2);
}
let mut x = 5;
sum_and_zero(&mut x, &mut x);
}
```

<details>

- In both of these cases, modifying the collection by pushing new elements into
it can potentially invalidate existing references to the collection's elements
if the collection has to reallocate.
- In the first case, modifying the collection by pushing new elements into it
can potentially invalidate existing references to the collection's elements if
the collection has to reallocate.

- In the second case, the aliasing rule prevents mis-compilation: The output of
`sum_and_zero` depends on the ordering of the two operations, which means if
the compiler swaps the order of these operations (which it's allowed to do) it
changes the result.

- The equivalent code in C exhibits undefined behavior, which may result in
mis-compilation and unexpected behavior, even if it doesn't cause a crash.
Copy link
Collaborator

Choose a reason for hiding this comment

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

What is the basis for this assertion? I was under the impression that C assumed everything aliased and therefore could not re-order operations very aggressively.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Pointers would need to be tagged with restrict to allow this reordering in C.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I've gone back and reworked the example to better demonstrate UB in the C version. The C version now uses the restrict keyword and demonstrates a change in behavior when optimizations are enabled. I have also included links to Godbolt so that it's easy to demonstrate this for students. Let me know if this seems like a better option.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think it makes sense to say that the Rust function would be miscompiled if not for the aliasing rule. If Rust semantics were different, it would change how Rust is optimized--in every language optimizations must be semantics-preserving.

We could say that the Rust rules enable more optimizations than C compilers can perform (in general, e.g. without restrict), which is true, but in my opinion not really the strongest reason behind why Rust does things this way.


- Rust's aliasing rules provide strong guarantees about how references can
alias, allowing the compiler to apply optimizations without breaking the
semantics of your program.

</details>