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

Adjust Vec to build on stable Rust #223

Merged
merged 3 commits into from
May 2, 2021
Merged

Conversation

blkerby
Copy link
Contributor

@blkerby blkerby commented Jun 19, 2020

Hi, first time contributing to the Nomicon here. I'm aware this is a somewhat large proposed change (larger than I anticipated it being when I began) but I hope it will be useful.

The chapter on implementing Vec was written to build on nightly Rust. From the discussion in 9.1 (Layout), the primary motivation for this was to get an optimized non-nullable pointer type. Since std::ptr::NonNull is now stable, this can achieved on stable Rust. This pull request makes the changes throughout the chapter necessary to implement Vec using std::ptr::NonNull instead of the unstable Unique.

Currently much of the code in the main body of the chapter does not compile on the latest nightly Rust because it relies on unstable APIs which have changed (for instance, std::alloc::oom, alloc::heap::{allocate, reallocate, deallocate} are gone, and Unique no longer implements Deref). The final code in the last section of the chapter compiles, because it has been updated to use current unstable APIs such as std::alloc::Global. This pull request updates the main body of the chapter as well as the final code so that they are consistent with each other, both now using the stable allocation functions in std::alloc (while mentioning the new unstable type std::alloc::Global in the text).

Instead of incorporating NonNull directly into Vec, RawVec, etc. as this pull request does, one alternative would be to implement a stable version of Unique using NonNull internally, and then include this Unique in Vec, RawVec, etc. I briefly started going down that pathway before concluding that for this to be convenient quite a few methods would need to be implemented for this new Unique, which would seem to create a distraction from the main goal and add an unnecessary layer of abstraction. But this would be another option if there's a preference for going that way.

Fixes #5, fixes #70, fixes #83, fixes #160

@blkerby
Copy link
Contributor Author

blkerby commented Jun 19, 2020

FYI, after finishing the changes, I made a pass through the chapter and tested the cumulative code at each step, confirming that it compiles successfully on stable Rust.

@skade
Copy link
Contributor

skade commented Mar 8, 2021

I want to register interest in getting this PR rebased and merged.

@blkerby
Copy link
Contributor Author

blkerby commented Apr 3, 2021

I wouldn't mind rebasing and making the needed changes to get this ready again; could we get a reviewer/assignee first so we can know if the maintainers are interested in getting it merged? @JohnTitor, would you be interested in reviewing, or helping us find someone?

@JohnTitor
Copy link
Member

Hey sorry for the delay! I'll try to find some time to review in a few days and it'd be great if you could rebase meanwhile.

@blkerby
Copy link
Contributor Author

blkerby commented Apr 6, 2021

@JohnTitor I resolved the conflicts and rebased, so it should be ready for review whenever you're able!

Copy link
Member

@JohnTitor JohnTitor left a comment

Choose a reason for hiding this comment

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

Sorry for the delay! Just read and the implementation itself looks good to me, just left suggestions for the style issues.

src/vec.md Outdated Show resolved Hide resolved
src/vec-layout.md Outdated Show resolved Hide resolved
src/vec-layout.md Outdated Show resolved Hide resolved
src/vec-push-pop.md Outdated Show resolved Hide resolved
src/vec-alloc.md Outdated Show resolved Hide resolved
src/vec-final.md Outdated Show resolved Hide resolved
src/vec-final.md Outdated Show resolved Hide resolved
src/vec-final.md Outdated Show resolved Hide resolved
src/vec-final.md Outdated Show resolved Hide resolved
src/vec-final.md Outdated Show resolved Hide resolved
Co-authored-by: Yuki Okushi <jtitor@2k36.org>
@blkerby
Copy link
Contributor Author

blkerby commented Apr 10, 2021

Thanks, I applied all the suggested changes.

@blkerby blkerby requested a review from JohnTitor April 16, 2021 13:31
Copy link
Member

@JohnTitor JohnTitor left a comment

Choose a reason for hiding this comment

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

LGTM! But I'm going to ask the libs team to review since this is a major change and I'm not sure if I've got the whole picture correctly (related Zulip topic: https://rust-lang.zulipchat.com/#narrow/stream/219381-t-libs/topic/review.20request.20for.20the.20nomicon.20PR), I'll wait for a week or so to get some more eyes. Sorry to keep you waiting.

@@ -7,20 +7,17 @@ ask Rust if `T` `needs_drop` and omit the calls to `pop`. However in practice
LLVM is *really* good at removing simple side-effect free code like this, so I
wouldn't bother unless you notice it's not being stripped (in this case it is).
Copy link
Member

Choose a reason for hiding this comment

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

Note that the above is only true if LLVM can prove that the loop is finite. This is true in the case of Vec, but for example LLVM has no way to know that a linked list has no cycles.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Makes sense. And based on the docs for needs_drop it sounds like even in the Vec case LLVM might not eliminate the loop in debug builds. In any case, it is probably fragile to rely on LLVM for this behavior. I'm thinking of a few options for how we could address this:

  1. Leave the code as is, but change the text to make the risk more clear.
  2. Use a mem::needs_drop to skip the loop if T is !Drop.
  3. Instead of an explicit loop, use ptr::drop_in_place (which is what the standard library Vec does).
  4. Start with the current code, but within the section discuss its pitfalls and iterate on it, progressing to 2 and/or 3.

I would lean toward option 4, since currently this section is very short and could benefit from more discussion and examples to illustrate the usage of mem::needs_drop and ptr::drop_in_place. If we go with 2, 3, or 4, it will also require changes to vec-raw.md and vec-final.md for consistency. If you don't mind, do you think I could create a separate PR for this change, since it addresses a separate issue from the current PR?

Copy link
Member

Choose a reason for hiding this comment

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

I agree that option 4 sounds like the best way to go. It's fine to do this in a separate PR.

if self.len == self.cap() { self.buf.grow(); }
if self.len == self.cap() {
self.buf.grow();
}

unsafe {
ptr::write(self.ptr().offset(self.len as isize), elem);
Copy link
Member

Choose a reason for hiding this comment

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

All the calls to .offset can be replaced with .add which avoids the need to cast to isize.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice! There are a couple dozen or so places throughout the chapter where this change could be made. Would you mind if I create a separate PR for this?

src/vec-insert-remove.md Outdated Show resolved Hide resolved
Comment on lines +41 to +45
Next we need to figure out what to actually do when we *do* want space. For that,
we use the global allocation functions [`alloc`][alloc], [`realloc`][realloc],
and [`dealloc`][dealloc] which are available in stable Rust in
[`std::alloc`][std_alloc]. These functions are expected to become deprecated in
favor of the methods of [`std::alloc::Global`][Global] after this type is stabilized.
Copy link
Member

Choose a reason for hiding this comment

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

At some point I really want to implement rust-lang/rust#77974.

@JohnTitor
Copy link
Member

It's been two weeks, @blkerby could you address Amanieu's reviews? Once it's done, I'm going to merge this finally.

@blkerby
Copy link
Contributor Author

blkerby commented May 2, 2021

@JohnTitor I think the reviews are identifying additional ways to improve the Vec chapter that are orthogonal to the changes in this PR. If you think it makes sense, could we merge this one and then tackle those in separate PRs?

@JohnTitor
Copy link
Member

I think the reviews are identifying additional ways to improve the Vec chapter that are orthogonal to the changes in this PR. If you think it makes sense, could we merge this one and then tackle those in separate PRs?

Works for me, I'd also open another PR. Thanks for your awesome work, @blkerby!

@JohnTitor JohnTitor merged commit 951371f into rust-lang:master May 2, 2021
@Gankra
Copy link
Contributor

Gankra commented May 2, 2021

hey, thanks a lot!!

@blkerby blkerby deleted the stable_vec branch May 2, 2021 19:57
GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this pull request May 12, 2021
Update books

## nomicon

4 commits in 8551afbb2ca6f5ea37fe58380318b209785e4e02..55de6fa3c1f331774da19472c9ee57d2ae9eb039
2021-04-01 21:58:50 +0900 to 2021-05-12 00:31:01 +0900
- Clarify some of the language around marking traits safe/unsafe. (rust-lang/nomicon#268)
- Use pointer 'add' instead of 'offset' (rust-lang/nomicon#265)
- Adjust Vec to build on stable Rust (rust-lang/nomicon#223)
- Update link to c++ atomic ordering docs (rust-lang/nomicon#264)

## reference

3 commits in d23f9da8469617e6c81121d9fd123443df70595d..5aa457bf1b54bd2cd5d4cf49797f29299bdf89a7
2021-04-28 11:16:44 -0700 to 2021-05-05 08:39:22 -0700
- Explicitly state result of compound assignment (rust-lang/reference#1013)
- Adjust the definition of `target_family` (rust-lang/reference#1006)
- Fix typo in `Traits` (rust-lang/reference#1012)

## book

2 commits in 50dd06cb71beb27fdc0eebade5509cdcc1f821ed..55a26488ddefc8433e73a2e8352d70f7a5c7fc2b
2021-04-23 13:21:54 -0500 to 2021-05-09 12:03:18 -0500
- Past-tensify "lead" -&gt; "led" (rust-lang/book#2717)
- Merge pull request rust-lang/book#2718 from rust-lang/update-rustc

## rust-by-example

2 commits in e0a721f5202e6d9bec0aff99f10e44480c0da9e7..5f8c6da200ada77760a2fe1096938ef58151c9a6
2021-04-27 09:32:15 -0300 to 2021-04-29 08:08:01 -0300
- Fix Typo in LRBE section; closes rust-lang/rust-by-example#1434 (rust-lang/rust-by-example#1437)
- Add some tests to cargo/test.md. Partially addresses rust-lang/rust-by-example#1304 (rust-lang/rust-by-example#1438)

## rustc-dev-guide

3 commits in e72b43a64925ce053dc7830e21c1a57ba00499bd..1e6c7fbda4c45e85adf63ff3f82fa9c870b1447f
2021-04-27 12:35:37 -0700 to 2021-05-10 13:38:24 +0900
- Unified CPU Requirements (rust-lang/rustc-dev-guide#1126)
- add 'waiting-for-review' incantation to main contrib page (rust-lang/rustc-dev-guide#1124)
- Link to Zulip search for finding the most recent check-in (rust-lang/rustc-dev-guide#1118)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
6 participants