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

Refactor set_ptr_value as with_metadata_of #95249

Merged
merged 1 commit into from
Mar 29, 2022

Conversation

HeroicKatora
Copy link
Contributor

@HeroicKatora HeroicKatora commented Mar 23, 2022

Replaces set_ptr_value (#75091) with methods of reversed argument order:

impl<T: ?Sized> *mut T {
    pub fn with_metadata_of<U: ?Sized>(self, val: *mut U) -> *mut U;
}

impl<T: ?Sized> *const T {
    pub fn with_metadata_of<U: ?Sized>(self, val: *const U) -> *const U;
}

By reversing the arguments we achieve several clarifications:

  • The function closely resembles cast with an argument to
    initialize the metadata. This is easier to teach and answers a long
    outstanding question that had restricted cast to Sized pointee
    targets. See multiples reviews of
    Add some APIs to ptr::NonNull and fix since attributes #47631
  • The 'object identity', in the form of provenance, is now preserved
    from the receiver argument to the result. This helps explain the method as
    a builder-style, instead of some kind of setter that would modify
    something in-place. Ensuring that the result has the identity of the
    self argument is also beneficial for an intuition of effects.
  • An outstanding concern, 'Correct argument type', is avoided by not
    committing to any specific argument type. This is consistent with cast
    which does not require its receiver to be a 'raw address'.

Hopefully the usage examples in sync/rc.rs serve as sufficient examples of the style to convince the reader of the readability improvements of this style, when compared to the previous order of arguments.

I want to take the opportunity to motivate inclusion of this method separate from metadata API, separate from feature(ptr_metadata). It does not involve the Pointee trait in any form. This may be regarded as a very, very light form that does not commit to any details of the pointee trait, or its associated metadata. There are several use cases for which this is already sufficient and no further inspection of metadata is necessary.

  • Storing the coercion of *mut T into *mut dyn Trait as a way to dynamically cast some an arbitrary instance of the same type to a dyn trait instance. In particular, one can have a field of type Option<*mut dyn io::Seek> to memorize if a particular writer is seekable. Then a method fn(self: &T) -> Option<&dyn Seek> can be provided, which does not involve the static trait bound T: Seek. This makes it possible to create an API that is capable of utilizing seekable streams and non-seekable streams (instead of a possible less efficient manner such as more buffering) through the same entry-point.

  • Enabling more generic forms of unsizing for no-std smart pointers. Using the stable APIs only few concrete cases are available. One can unsize arrays to [T] by ptr::slice_from_raw_parts but unsizing a custom smart pointer to, e.g., dyn Iterator, dyn Future, dyn Debug, can't easily be done generically. Exposing with_metadata_of would allow smart pointers to offer their own unsafe escape hatch with similar parameters where the caller provides the unsized metadata. This is particularly interesting for embedded where dyn-trait usage can drastically reduce code size.

By reversing the arguments we achieve several clarifications:

- The function closely resembles `cast` but with an argument to
  initialized the metadata. This is easier to teach and answers an long
  outstanding question that had restricted cast to `Sized` targets
  initially. See multiples reviews of
  <rust-lang#47631>
- The 'object identity', in the form or provenance, is now preserved
  from the call receiver to the result. This helps explain the method as
  a builder-style, instead of some kind of setter that would modify
  something in-place. Ensuring that the result has the identity of the
  `self` argument is also beneficial for an intuition of effects.
- An outstanding concern, 'Correct argument type', is avoided by not
  committing to any specific argument type. This is consistent with cast
  which does not require its receiver to be a raw address.
@rust-highfive
Copy link
Collaborator

r? @dtolnay

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Mar 23, 2022
@dtolnay dtolnay added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Mar 28, 2022
Copy link
Member

@dtolnay dtolnay left a comment

Choose a reason for hiding this comment

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

Awesome!

Thank you for the detailed writeup. I find all of it compelling. It will be super helpful for whoever eventually writes the stabilization report for this API.

@dtolnay
Copy link
Member

dtolnay commented Mar 28, 2022

@bors r+

@bors
Copy link
Contributor

bors commented Mar 28, 2022

📌 Commit d489ea7 has been approved by dtolnay

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 28, 2022
@bors
Copy link
Contributor

bors commented Mar 28, 2022

⌛ Testing commit d489ea7 with merge c3df12a0160c390d2af772844007b3cafd79b9b4...

@bors
Copy link
Contributor

bors commented Mar 28, 2022

💔 Test failed - checks-actions

@bors bors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Mar 28, 2022
@rust-log-analyzer
Copy link
Collaborator

The job x86_64-gnu-tools failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)



The actual stderr differed from the expected stderr.
Actual stderr saved to /tmp/compiletestIL5Vsq/concurrency/libc_pthread_cond.stage-id.stderr
To only update this specific test, also pass `--test-args concurrency/libc_pthread_cond.rs`

error: 1 errors occurred comparing output.
status: exit status: 101
status: exit status: 101
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2-tools-bin/miri" "tests/run-pass/concurrency/libc_pthread_cond.rs" "-L" "/tmp/compiletestIL5Vsq" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "-C" "prefer-dynamic" "-o" "/tmp/compiletestIL5Vsq/concurrency/libc_pthread_cond.stage-id" "-A" "unused" "--edition" "2018" "-Astable-features" "--sysroot" "/home/user/.cache/miri/HOST" "-Zmiri-disable-isolation" "-Zmiri-check-number-validity" "-L" "/tmp/compiletestIL5Vsq/concurrency/libc_pthread_cond.stage-id.aux"
------------------------------------------

------------------------------------------
stderr:
---
-after wait
-

The actual stdout differed from the expected stdout.
Actual stdout saved to /tmp/compiletestIL5Vsq/concurrency/sync.stage-id.stdout

-warning: thread support is experimental and incomplete: weak memory effects are not emulated.
+thread 'rustc' panicked at 'Miri initialization error: type validation failed: encountered pointer to 0x206c5[alloc50]<40>, but expected initialized plain (non-pointer) bytes', src/tools/miri/src/eval.rs:298:13
+stack backtrace:
---
+end of query stack
 

The actual stderr differed from the expected stderr.
Actual stderr saved to /tmp/compiletestIL5Vsq/concurrency/sync.stage-id.stderr
To only update this specific test, also pass `--test-args concurrency/sync.rs`

error: 2 errors occurred comparing output.
status: exit status: 101
status: exit status: 101
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2-tools-bin/miri" "tests/run-pass/concurrency/sync.rs" "-L" "/tmp/compiletestIL5Vsq" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "-C" "prefer-dynamic" "-o" "/tmp/compiletestIL5Vsq/concurrency/sync.stage-id" "-A" "unused" "--edition" "2018" "-Astable-features" "--sysroot" "/home/user/.cache/miri/HOST" "-Zmiri-disable-isolation" "-Zmiri-check-number-validity" "-L" "/tmp/compiletestIL5Vsq/concurrency/sync.stage-id.aux"
------------------------------------------

------------------------------------------
stderr:
---



The actual stderr differed from the expected stderr.
Actual stderr saved to /tmp/compiletestIL5Vsq/vec.stage-id.stderr
To only update this specific test, also pass `--test-args vec.rs`

error: 1 errors occurred comparing output.
status: exit status: 101
status: exit status: 101
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2-tools-bin/miri" "tests/run-pass/vec.rs" "-L" "/tmp/compiletestIL5Vsq" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "-C" "prefer-dynamic" "-o" "/tmp/compiletestIL5Vsq/vec.stage-id" "-A" "unused" "--edition" "2018" "-Astable-features" "--sysroot" "/home/user/.cache/miri/HOST" "-Zmiri-tag-raw-pointers" "-Zmiri-check-number-validity" "-L" "/tmp/compiletestIL5Vsq/vec.stage-id.aux"
------------------------------------------

------------------------------------------
stderr:
---
.......... (60/61)
          (61/61)


/checkout/src/test/rustdoc-gui/search-result-display.goml search-result-display... FAILED
[ERROR] (line 6) TimeoutError: waiting for selector "#titles" failed: timeout 30000ms exceeded: for command `wait-for: "#titles"`
Build completed unsuccessfully in 0:00:44

@HeroicKatora
Copy link
Contributor Author

I could use some help interpreting the error:

2022-03-28T05:47:21.1322753Z
2022-03-28T05:47:21.1325155Z /checkout/src/test/rustdoc-gui/search-result-display.goml search-result-display... FAILED
2022-03-28T05:47:21.1326164Z [ERROR] (line 6) TimeoutError: waiting for selector "#titles" failed: timeout 30000ms exceeded: for command wait-for: "#titles"

Spurios or related to any doc-comments of this PR?

@dtolnay
Copy link
Member

dtolnay commented Mar 28, 2022

Unclear, but let's find out if spurious.

@bors retry

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 28, 2022
@bors
Copy link
Contributor

bors commented Mar 28, 2022

⌛ Testing commit d489ea7 with merge c1230e1...

@bors
Copy link
Contributor

bors commented Mar 29, 2022

☀️ Test successful - checks-actions
Approved by: dtolnay
Pushing c1230e1 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Mar 29, 2022
@bors bors merged commit c1230e1 into rust-lang:master Mar 29, 2022
@rustbot rustbot added this to the 1.61.0 milestone Mar 29, 2022
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (c1230e1): comparison url.

Summary: This benchmark run did not return any relevant results. 9 results were found to be statistically significant but too small to be relevant.

If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf.

@rustbot label: -perf-regression

@HeroicKatora HeroicKatora deleted the set-ptr-value branch March 29, 2022 07:05
yvt added a commit to r3-os/r3 that referenced this pull request Mar 30, 2022
<rust-lang/rust#95249>

This method is a part of the `set_ptr_value` unstable feature.
lopopolo added a commit to artichoke/cactusref that referenced this pull request Apr 2, 2022
rust-lang/rust#95249 reworked the `ptr::set_ptr_value` API. The new API
is called `ptr::with_metadata_of`. This PR syncs this crate's `Rc` impl
with upstream.

This nightly breakage means a new semver incompatible version bump is
due.
Dylan-DPC added a commit to Dylan-DPC/rust that referenced this pull request Oct 22, 2022
…nter_argument, r=dtolnay

Adjust argument type for mutable with_metadata_of (rust-lang#75091)

The method takes two pointer arguments: one `self` supplying the pointer value, and a second pointer supplying the metadata.

The new parameter type more clearly reflects the actual requirements. The provenance of the metadata parameter is disregarded completely. Using a mutable pointer in the call site can be coerced to a const pointer while the reverse is not true.

In some cases, the current parameter type can thus lead to a very slightly confusing additional cast. [Example](HeroicKatora/static-alloc@cad9377).

```rust
// Manually taking an unsized object from a `ManuallyDrop` into another allocation.
let val: &core::mem::ManuallyDrop<T> = …;

let ptr = val as *const _ as *mut T;
let ptr = uninit.as_ptr().with_metadata_of(ptr);
```

This could then instead be simplified to:

```rust
// Manually taking an unsized object from a `ManuallyDrop` into another allocation.
let val: &core::mem::ManuallyDrop<T> = …;

let ptr = uninit.as_ptr().with_metadata_of(&**val);
```

Tracking issue: rust-lang#75091

`@dtolnay` you're reviewed rust-lang#95249, would you mind chiming in?
Dylan-DPC added a commit to Dylan-DPC/rust that referenced this pull request Oct 22, 2022
…nter_argument, r=dtolnay

Adjust argument type for mutable with_metadata_of (rust-lang#75091)

The method takes two pointer arguments: one `self` supplying the pointer value, and a second pointer supplying the metadata.

The new parameter type more clearly reflects the actual requirements. The provenance of the metadata parameter is disregarded completely. Using a mutable pointer in the call site can be coerced to a const pointer while the reverse is not true.

In some cases, the current parameter type can thus lead to a very slightly confusing additional cast. [Example](HeroicKatora/static-alloc@cad9377).

```rust
// Manually taking an unsized object from a `ManuallyDrop` into another allocation.
let val: &core::mem::ManuallyDrop<T> = …;

let ptr = val as *const _ as *mut T;
let ptr = uninit.as_ptr().with_metadata_of(ptr);
```

This could then instead be simplified to:

```rust
// Manually taking an unsized object from a `ManuallyDrop` into another allocation.
let val: &core::mem::ManuallyDrop<T> = …;

let ptr = uninit.as_ptr().with_metadata_of(&**val);
```

Tracking issue: rust-lang#75091

``@dtolnay`` you're reviewed rust-lang#95249, would you mind chiming in?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants