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

Add Weak.ptr_eq #55987

Merged
merged 3 commits into from
Dec 6, 2018
Merged

Add Weak.ptr_eq #55987

merged 3 commits into from
Dec 6, 2018

Conversation

Thomasdezeeuw
Copy link
Contributor

@Thomasdezeeuw Thomasdezeeuw commented Nov 15, 2018

I hope the doc tests alone are good enough.

We also might want to discuss the dangling pointer case (from Weak::new()).

Updates #55981.

@rust-highfive
Copy link
Collaborator

r? @sfackler

(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 Nov 15, 2018
@sfackler
Copy link
Member

There's no ABA problem here since the underlying Rc allocation isn't freed while there are outstanding Weaks, right?

I agree with the behavior for dangling Weaks.

We should define this for both Arc's and Rc's Weak.

@Thomasdezeeuw
Copy link
Contributor Author

@sfackler the memory is only deallocated once the weak count hits 0 (starts at 1), see https://github.com/rust-lang/rust/blob/master/src/liballoc/rc.rs#L855-L857 and https://github.com/rust-lang/rust/blob/master/src/liballoc/rc.rs#L1297-L1301.

As for the dangling pointers; I don't think Rc or Arc allows for dangling pointers, they can only be created with an actual value, at least when using safe code. Only Weak::new will create a dangling pointer to avoid allocating.

@sfackler
Copy link
Member

Ok cool, this approach should work then. Let's add the same method for Arc and this should be good to go.

@sfackler
Copy link
Member

cc @rust-lang/libs

@Thomasdezeeuw
Copy link
Contributor Author

Do you want the Arc and sync::Weak change in this PR? Or should I make another?

Also what should I do with the stable/unstable attribute?

@sfackler
Copy link
Member

Let's add it in this PR.

The new functions should be added as unstable initially. We can repurpose #55981 as the tracking issue.

@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-5.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
travis_time:end:18499f1b:start=1542304911622934307,finish=1542304972295575162,duration=60672640855
$ git checkout -qf FETCH_HEAD
travis_fold:end:git.checkout

Encrypted environment variables have been removed for security reasons.
See https://docs.travis-ci.com/user/pull-requests/#Pull-Requests-and-Security-Restrictions
$ export SCCACHE_BUCKET=rust-lang-ci-sccache2
$ export SCCACHE_REGION=us-west-1
Setting environment variables from .travis.yml
$ export IMAGE=x86_64-gnu-llvm-5.0
---
[00:55:21] .................................................................................................... 100/5021
[00:55:24] .................................................................................................... 200/5021
[00:55:27] .............................ii............................................ii...................ii.. 300/5021
[00:55:30] ..............................................................................................iii... 400/5021
[00:55:34] .....iiiiiiii.iii............................iii...........................................i........ 500/5021
[00:55:41] .................................................................................................... 700/5021
[00:55:48] .................................................................................i...........i...... 800/5021
[00:55:51] .................................................................................................... 900/5021
[00:55:55] iiiii..................ii.iiii...................................................................... 1000/5021
---
[00:56:35] .................................................................................................... 2200/5021
[00:56:40] .................................................................................................... 2300/5021
[00:56:44] .................................................................................................... 2400/5021
[00:56:48] .................................................................................................... 2500/5021
[00:56:51] .................................................................................iiiiiiiii.......... 2600/5021
[00:56:59] ...............................................ii................................................... 2800/5021
[00:57:03] .................................................................................................... 2900/5021
[00:57:07] .................................................................................................... 3000/5021
[00:57:10] ..........................................i......................................................... 3100/5021
---
travis_time:start:test_codegen
Check compiletest suite=codegen mode=codegen (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)
[01:12:03] 
[01:12:03] running 116 tests
[01:12:06] i..ii...iii..iiii.....i...i.........i..iii...........i.....i.....ii...i..i.ii..............i...ii..i 100/116
[01:12:06] i.i....iiii.....
[01:12:06] 
[01:12:06]  finished in 3.808
[01:12:06] travis_fold:end:test_codegen

---
travis_time:start:test_debuginfo
Check compiletest suite=debuginfo mode=debuginfo-both (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)
[01:12:23] 
[01:12:23] running 118 tests
[01:12:50] .iiiii...i.....i..i...i..i.i..i.i..i.....i..i....i..........iiii.........i.i....i...i.......ii.i.i.i 100/118
[01:12:54] ......iii.i.....ii
[01:12:54] 
[01:12:54]  finished in 31.617
[01:12:54] travis_fold:end:test_debuginfo

---
[01:24:58] 
[01:24:58] running 408 tests
[01:25:19] .................................................................................................... 100/408
[01:25:34] .....................................................................i.............................. 200/408
[01:25:49] ...................FF............................................................................... 300/408
[01:26:04] ........
[01:26:04] failures:
[01:26:04] 
[01:26:04] ---- rc.rs - rc::Weak<T>::ptr_eq (line 1291) stdout ----
[01:26:04] ---- rc.rs - rc::Weak<T>::ptr_eq (line 1291) stdout ----
[01:26:04] error[E0425]: cannot find value `third` in this scope
[01:26:04]   --> rc.rs:1300:13
[01:26:04]    |
[01:26:04] 12 | let third = third.downgrade();
[01:26:04] 
[01:26:04] 
[01:26:04] error[E0658]: use of unstable library feature 'weak_ptr_eq'
[01:26:04]  --> rc.rs:1297:10
[01:26:04]   |
[01:26:04] 9 | assert!(!Weak::ptr_eq(&first, &second));
[01:26:04]   |
[01:26:04]   |
[01:26:04]   = help: add #![feature(weak_ptr_eq)] to the crate attributes to enable
[01:26:04] 
[01:26:04] error[E0658]: use of unstable library feature 'weak_ptr_eq'
[01:26:04]   --> rc.rs:1302:10
[01:26:04]    |
[01:26:04] 14 | assert!(!Weak::ptr_eq(&first, &third));
[01:26:04]    |
[01:26:04]    |
[01:26:04]    = help: add #![feature(weak_ptr_eq)] to the crate attributes to enable
[01:26:04] thread 'rc.rs - rc::Weak<T>::ptr_eq (line 1291)' panicked at 'couldn't compile the test', librustdoc/test.rs:323:13
[01:26:04] note: Run with `RUST_BACKTRACE=1` for a backtrace.
[01:26:04] 
[01:26:04] ---- rc.rs - rc::Weak<T>::ptr_eq (line 1270) stdout ----
[01:26:04] ---- rc.rs - rc::Weak<T>::ptr_eq (line 1270) stdout ----
[01:26:04] error[E0599]: no method named `downgrade` found for type `std::rc::Rc<{integer}>` in the current scope
[01:26:04]  --> rc.rs:1274:22
[01:26:04]   |
[01:26:04] 7 | let first = first_rc.downgrade();
[01:26:04]   |             |        |
[01:26:04]   |             |        this is an associated function, not a method
[01:26:04]   |             |        this is an associated function, not a method
[01:26:04]   |             help: use associated function syntax instead: `std::rc::Rc<{integer}>::downgrade`
[01:26:04]   |
[01:26:04]   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
[01:26:04]   = note: the candidate is defined in an impl for the type `std::rc::Rc<_>`
[01:26:04] 
[01:26:04] error[E0599]: no method named `downgrade` found for type `std::rc::Rc<{integer}>` in the current scope
[01:26:04]  --> rc.rs:1275:23
[01:26:04]   |
[01:26:04] 8 | let second = first_rc.downgrade();
[01:26:04]   |              |        |
[01:26:04]   |              |        this is an associated function, not a method
[01:26:04]   |              |        this is an associated function, not a method
[01:26:04]   |              help: use associated function syntax instead: `std::rc::Rc<{integer}>::downgrade`
[01:26:04]   |
[01:26:04]   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
[01:26:04]   = note: the candidate is defined in an impl for the type `std::rc::Rc<_>`
[01:26:04] 
[01:26:04] error[E0658]: use of unstable library feature 'weak_ptr_eq'
[01:26:04]   --> rc.rs:1277:9
[01:26:04]    |
[01:26:04] 10 | assert!(Weak::ptr_eq(&first, &second));
[01:26:04]    |
[01:26:04]    |
[01:26:04]    = help: add #![feature(weak_ptr_eq)] to the crate attributes to enable
[01:26:04] 
[01:26:04] error[E0599]: no method named `downgrade` found for type `std::rc::Rc<{integer}>` in the current scope
[01:26:04]   --> rc.rs:1280:22
[01:26:04]    |
[01:26:04] 13 | let third = third_rc.downgrade();
[01:26:04]    |             |        |
[01:26:04]    |             |        this is an associated function, not a method
[01:26:04]    |             |        this is an associated function, not a method
[01:26:04]    |             help: use associated function syntax instead: `std::rc::Rc<{integer}>::downgrade`
[01:26:04]    |
[01:26:04]    = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
[01:26:04]    = note: the candidate is defined in an impl for the type `std::rc::Rc<_>`
[01:26:04] 
[01:26:04] error[E0658]: use of unstable library feature 'weak_ptr_eq'
[01:26:04]   --> rc.rs:1282:10
[01:26:04]    |
[01:26:04] 15 | assert!(!Weak::ptr_eq(&first, &third));
[01:26:04]    |
[01:26:04]    |
[01:26:04]    = help: add #![feature(weak_ptr_eq)] to the crate attributes to enable
[01:26:04] thread 'rc.rs - rc::Weak<T>::ptr_eq (line 1270)' panicked at 'couldn't compile the test', librustdoc/test.rs:323:13
[01:26:04] 
[01:26:04] 
[01:26:04] failures:
---
[01:26:04] 
[01:26:04] error: test failed, to rerun pass '--doc'
[01:26:04] 
[01:26:04] 
[01:26:04] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "test" "--target" "x86_64-unknown-linux-gnu" "-j" "4" "--release" "--locked" "--color" "always" "--features" "panic-unwind backtrace" "--manifest-path" "/checkout/src/libstd/Cargo.toml" "-p" "alloc" "--" "--quiet"
[01:26:04] 
[01:26:04] 
[01:26:04] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test
[01:26:04] Build completed unsuccessfully in 0:34:51
[01:26:04] Build completed unsuccessfully in 0:34:51
[01:26:04] Makefile:58: recipe for target 'check' failed
[01:26:04] make: *** [check] Error 1
The command "stamp sh -x -c "$RUN_SCRIPT"" exited with 2.
travis_time:start:08f317a8
$ date && (curl -fs --head https://google.com | grep ^Date: | sed 's/Date: //g' || true)
Thu Nov 15 19:29:08 UTC 2018

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@sfackler
Copy link
Member

oh, we should also add some basic tests.

@Thomasdezeeuw
Copy link
Contributor Author

@sfackler I've add examples which also serve as tests. I explicitly added the example of the dangling pointer. What other tests would you like to see?

@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-5.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
travis_time:end:0e54aaee:start=1542311928272529443,finish=1542311981984741777,duration=53712212334
$ git checkout -qf FETCH_HEAD
travis_fold:end:git.checkout

Encrypted environment variables have been removed for security reasons.
See https://docs.travis-ci.com/user/pull-requests/#Pull-Requests-and-Security-Restrictions
$ export SCCACHE_BUCKET=rust-lang-ci-sccache2
$ export SCCACHE_REGION=us-west-1
Setting environment variables from .travis.yml
$ export IMAGE=x86_64-gnu-llvm-5.0
---
[00:51:26] .................................................................................................... 100/5021
[00:51:29] .................................................................................................... 200/5021
[00:51:32] .............................ii............................................ii...................ii.. 300/5021
[00:51:35] ..............................................................................................iii... 400/5021
[00:51:38] .....iiiiiiii.iii............................iii...........................................i........ 500/5021
[00:51:45] .................................................................................................... 700/5021
[00:51:51] .................................................................................i...........i...... 800/5021
[00:51:55] .................................................................................................... 900/5021
[00:51:58] iiiii..................ii.iiii...................................................................... 1000/5021
---
[00:52:34] .................................................................................................... 2200/5021
[00:52:38] .................................................................................................... 2300/5021
[00:52:42] .................................................................................................... 2400/5021
[00:52:46] .................................................................................................... 2500/5021
[00:52:49] .................................................................................iiiiiiiii.......... 2600/5021
[00:52:56] ................................................ii.................................................. 2800/5021
[00:52:59] .................................................................................................... 2900/5021
[00:53:03] .................................................................................................... 3000/5021
[00:53:06] ..........................................i......................................................... 3100/5021
---
travis_time:start:test_codegen
Check compiletest suite=codegen mode=codegen (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)
[01:06:56] 
[01:06:56] running 116 tests
[01:06:59] i..ii...iii..iiii.....i...i.........i..iii...........i.....i.....ii...i..i.ii..............i...ii..i 100/116
[01:07:00] i.i....iiii.....
[01:07:00] 
[01:07:00]  finished in 3.545
[01:07:00] travis_fold:end:test_codegen

---
travis_time:start:test_debuginfo
Check compiletest suite=debuginfo mode=debuginfo-both (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)
[01:07:14] 
[01:07:14] running 118 tests
[01:07:39] .iiiii...i.....i..i...i..i.i..i.i..i.....i..i....i..........iiii.........i.i....i...i.......ii.i.i.i 100/118
[01:07:43] ......iii.i.....ii
[01:07:43] 
[01:07:43]  finished in 29.172
[01:07:43] travis_fold:end:test_debuginfo

---
[01:19:02] 
[01:19:02] running 410 tests
[01:19:20] .................................................................................................... 100/410
[01:19:34] .....................................................................i.............................. 200/410
[01:19:46] ...................F.F.............................................................................. 300/410
[01:19:58] ...............................................FF................................................... 400/410
[01:19:59] failures:
[01:19:59] 
[01:19:59] ---- rc.rs - rc::Weak<T>::ptr_eq (line 1270) stdout ----
[01:19:59] ---- rc.rs - rc::Weak<T>::ptr_eq (line 1270) stdout ----
[01:19:59] error[E0599]: no method named `downgrade` found for type `std::rc::Rc<{integer}>` in the current scope
[01:19:59]  --> rc.rs:1275:22
[01:19:59]   |
[01:19:59] 8 | let first = first_rc.downgrade();
[01:19:59]   |             |        |
[01:19:59]   |             |        this is an associated function, not a method
[01:19:59]   |             |        this is an associated function, not a method
[01:19:59]   |             help: use associated function syntax instead: `std::rc::Rc<{integer}>::downgrade`
[01:19:59]   |
[01:19:59]   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
[01:19:59]   = note: the candidate is defined in an impl for the type `std::rc::Rc<_>`
[01:19:59] 
[01:19:59] error[E0599]: no method named `downgrade` found for type `std::rc::Rc<{integer}>` in the current scope
[01:19:59]  --> rc.rs:1276:23
[01:19:59]   |
[01:19:59] 9 | let second = first_rc.downgrade();
[01:19:59]   |              |        |
[01:19:59]   |              |        this is an associated function, not a method
[01:19:59]   |              |        this is an associated function, not a method
[01:19:59]   |              help: use associated function syntax instead: `std::rc::Rc<{integer}>::downgrade`
[01:19:59]   |
[01:19:59]   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
[01:19:59]   = note: the candidate is defined in an impl for the type `std::rc::Rc<_>`
[01:19:59] 
[01:19:59] error[E0599]: no method named `downgrade` found for type `std::rc::Rc<{integer}>` in the current scope
[01:19:59]   --> rc.rs:1281:22
[01:19:59]    |
[01:19:59] 14 | let third = third_rc.downgrade();
[01:19:59]    |             |        |
[01:19:59]    |             |        this is an associated function, not a method
[01:19:59]    |             |        this is an associated function, not a method
[01:19:59]    |             help: use associated function syntax instead: `std::rc::Rc<{integer}>::downgrade`
[01:19:59]    |
[01:19:59]    = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
[01:19:59]    = note: the candidate is defined in an impl for the type `std::rc::Rc<_>`
[01:19:59] thread 'rc.rs - rc::Weak<T>::ptr_eq (line 1270)' panicked at 'couldn't compile the test', librustdoc/test.rs:323:13
[01:19:59] note: Run with `RUST_BACKTRACE=1` for a backtrace.
[01:19:59] 
[01:19:59] ---- rc.rs - rc::Weak<T>::ptr_eq (line 1292) stdout ----
[01:19:59] ---- rc.rs - rc::Weak<T>::ptr_eq (line 1292) stdout ----
[01:19:59] error[E0599]: no method named `downgrade` found for type `std::rc::Rc<()>` in the current scope
[01:19:59]   --> rc.rs:1302:22
[01:19:59]    |
[01:19:59] 13 | let third = third_rc.downgrade();
[01:19:59]    |             |        |
[01:19:59]    |             |        this is an associated function, not a method
[01:19:59]    |             |        this is an associated function, not a method
[01:19:59]    |             help: use associated function syntax instead: `std::rc::Rc<()>::downgrade`
[01:19:59]    |
[01:19:59]    = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
[01:19:59]    = note: the candidate is defined in an impl for the type `std::rc::Rc<_>`
[01:19:59] thread 'rc.rs - rc::Weak<T>::ptr_eq (line 1292)' panicked at 'couldn't compile the test', librustdoc/test.rs:323:13
[01:19:59] 
[01:19:59] ---- sync.rs - sync::Weak<T>::ptr_eq (line 1140) stdout ----
[01:19:59] ---- sync.rs - sync::Weak<T>::ptr_eq (line 1140) stdout ----
[01:19:59] error[E0599]: no method named `downgrade` found for type `std::sync::Arc<{integer}>` in the current scope
[01:19:59]  --> sync.rs:1145:22
[01:19:59]   |
[01:19:59] 8 | let first = first_rc.downgrade();
[01:19:59]   |             |        |
[01:19:59]   |             |        this is an associated function, not a method
[01:19:59]   |             |        this is an associated function, not a method
[01:19:59]   |             help: use associated function syntax instead: `std::sync::Arc<{integer}>::downgrade`
[01:19:59]   |
[01:19:59]   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
[01:19:59]   = note: the candidate is defined in an impl for the type `std::sync::Arc<_>`
[01:19:59] 
[01:19:59] error[E0599]: no method named `downgrade` found for type `std::sync::Arc<{integer}>` in the current scope
[01:19:59]  --> sync.rs:1146:23
[01:19:59]   |
[01:19:59] 9 | let second = first_rc.downgrade();
[01:19:59]   |              |        |
[01:19:59]   |              |        this is an associated function, not a method
[01:19:59]   |              |        this is an associated function, not a method
[01:19:59]   |              help: use associated function syntax instead: `std::sync::Arc<{integer}>::downgrade`
[01:19:59]   |
[01:19:59]   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
[01:19:59]   = note: the candidate is defined in an impl for the type `std::sync::Arc<_>`
[01:19:59] 
[01:19:59] error[E0599]: no method named `downgrade` found for type `std::sync::Arc<{integer}>` in the current scope
[01:19:59]   --> sync.rs:1151:22
[01:19:59]    |
[01:19:59] 14 | let third = third_rc.downgrade();
[01:19:59]    |             |        |
[01:19:59]    |             |        this is an associated function, not a method
[01:19:59]    |             |        this is an associated function, not a method
[01:19:59]    |             help: use associated function syntax instead: `std::sync::Arc<{integer}>::downgrade`
[01:19:59]    |
[01:19:59]    = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
[01:19:59]    = note: the candidate is defined in an impl for the type `std::sync::Arc<_>`
[01:19:59] thread 'sync.rs - sync::Weak<T>::ptr_eq (line 1140)' panicked at 'couldn't compile the test', librustdoc/test.rs:323:13
[01:19:59] 
[01:19:59] ---- sync.rs - sync::Weak<T>::ptr_eq (line 1162) stdout ----
[01:19:59] ---- sync.rs - sync::Weak<T>::ptr_eq (line 1162) stdout ----
[01:19:59] error[E0599]: no method named `downgrade` found for type `std::sync::Arc<()>` in the current scope
[01:19:59]   --> sync.rs:1172:22
[01:19:59]    |
[01:19:59] 13 | let third = third_rc.downgrade();
[01:19:59]    |             |        |
[01:19:59]    |             |        this is an associated function, not a method
[01:19:59]    |             |        this is an associated function, not a method
[01:19:59]    |             help: use associated function syntax instead: `std::sync::Arc<()>::downgrade`
[01:19:59]    |
[01:19:59]    = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
[01:19:59]    = note: the candidate is defined in an impl for the type `std::sync::Arc<_>`
[01:19:59] thread 'sync.rs - sync::Weak<T>::ptr_eq (line 1162)' panicked at 'couldn't compile the test', librustdoc/test.rs:323:13
[01:19:59] 
[01:19:59] 
[01:19:59] failures:
---
[01:19:59] 
[01:19:59] error: test failed, to rerun pass '--doc'
[01:19:59] 
[01:19:59] 
[01:19:59] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "test" "--target" "x86_64-unknown-linux-gnu" "-j" "4" "--release" "--locked" "--color" "always" "--features" "panic-unwind backtrace" "--manifest-path" "/checkout/src/libstd/Cargo.toml" "-p" "alloc" "--" "--quiet"
[01:19:59] 
[01:19:59] 
[01:19:59] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test
[01:19:59] Build completed unsuccessfully in 0:32:21
[01:19:59] Build completed unsuccessfully in 0:32:21
[01:19:59] Makefile:58: recipe for target 'check' failed
[01:19:59] make: *** [check] Error 1
The command "stamp sh -x -c "$RUN_SCRIPT"" exited with 2.
travis_time:start:2350481c
$ date && (curl -fs --head https://google.com | grep ^Date: | sed 's/Date: //g' || true)
Thu Nov 15 21:19:52 UTC 2018

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@bors
Copy link
Contributor

bors commented Nov 17, 2018

☔ The latest upstream changes (presumably #55627) made this pull request unmergeable. Please resolve the merge conflicts.

@Thomasdezeeuw
Copy link
Contributor Author

Anything I can do to progress this?

@sfackler
Copy link
Member

Oh whoops - Github doesn't email on force pushes so I didn't see it was rebased :(

@bors r+

@bors
Copy link
Contributor

bors commented Nov 21, 2018

📌 Commit 90d2914da3d15ebe8ea0c95de2b3270ef3c8bddb has been approved by sfackler

@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 Nov 21, 2018
///
/// When using `Weak::new` the `Weak` is never equal to any other `Weak`
/// until it points to actual data (e.g. by setting it to a value created by
/// calling [`Arc::downgrade`]).
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this documentation is slightly confusion. Outside of std, I don't think there is any way to turn a reference obtained through Weak::new into a reference to something real. I think it should just say something like:

References obtained through Weak::new are not equal to any other references, including other invocations of Weak::new.

(same applies to rc::Weak)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Outside of std, I don't think there is any way to turn a reference obtained through Weak::new into a reference to something real.

I'm not sure what you mean by that. You can overwrite the value, e.g.

let mut weak_value = Weak::new();
let value = Rc::new(5);
weak_value = Rc::dowgrade(&value);

As for the comparing two Weak::new() with another I agree, but isn't the example enough? Currently no pointer created via Weak::new() is equal to any other pointer, including pointers also created via Weak::new(). That is what the documentations currently says.

Copy link
Contributor

Choose a reason for hiding this comment

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

The way the documentation is written implies that you can take a Weak::new and somehow turn it into something that's not a dangling pointer. For example some fn(self: &mut Weak<T>). Assignment and mem::replace don't count.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry @jethrogb I still don't really see your point. You keep mentioning "dangling pointer", but the public documentation doesn't. Furthermore you can turn a variable with the current value of Weak::new into something else by using plain assignment. That is also possible in any function that takes &mut Weak<T>, so I don't get why that doesn't "count".

Copy link
Contributor

@jethrogb jethrogb Nov 23, 2018

Choose a reason for hiding this comment

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

"dangling pointer" and Weak::new are equivalent.

Furthermore you can turn a variable with the current value of Weak::new into something else by using plain assignment.

Dropping the old value and moving something new in its place is not the same as changing the value.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jethrogb "dangling pointer" and Weak::new are not equivalent. That is only how the current API is implementated. Previous versions of Rust (not sure what version changed it) actually allocated on the heap when calling Weak::new. A change was made to not allocate by default for most (collection) types, including Weak. However this happend without a change in the API. This means we could go back to that implementation and then Weak::new and "dangling pointer" aren't equivalent anymore.

But maybe someone else can can help here, this discussion is going off the rails and we're clearing not understanding each other.

Copy link
Contributor

Choose a reason for hiding this comment

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

@jethrogb "dangling pointer" and Weak::new are not equivalent. That is only how the current API is implementated. Previous versions of Rust (not sure what version changed it) actually allocated on the heap when calling Weak::new. A change was made to not allocate by default for most (collection) types, including Weak. However this happend without a change in the API. This means we could go back to that implementation and then Weak::new and "dangling pointer" aren't equivalent anymore.

Ok fine, I was using them equivalently, but I meant Weak::new. This point is completely orthogonal to my main point about the phrasing of the documentation.

Copy link
Contributor

Choose a reason for hiding this comment

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

When using Weak::new the Weak is never equal to any other Weak until it points to actual data

The "until it points to actual data" part clearly implies you can take a Weak::new and somehow change it to a value that is real. Dropping the old value and moving something new in its place is not the same as changing the value.

@ghost
Copy link

ghost commented Nov 22, 2018

I disagree with the handling of the dangling case.

Suppose we had an AtomicWeak<T> type and then wanted to implement a get method that loads it or initializes to 0 when dangling:

fn get(a: &AtomicWeak<i32>) -> Arc<i32> {
    loop {
        let weak = a.load();
        match weak.upgrade() {
            Some(arc) => return arc,
            None => {
                let arc = Arc::new(0);
                let prev = a.compare_and_swap(&weak, Arc::downgrade(&arc));
                if Weak::ptr_eq(&prev, &weak) {
                    return arc;
                }
            }
        }
    }
}

With the current behavior of Weak::ptr_eq for dangling pointers, the CAS operation and the if check would not work. In fact, I think it would be impossible to implement this function as intended.

@sfackler
Copy link
Member

So what should the handling be then? Are dangling weaks equal to each other? To all pointers?

@ghost
Copy link

ghost commented Nov 23, 2018

@sfackler Ah, I misunderstood by thinking "dangling weak" means "weak with strong_count = 0". :(

Never mind then, the current behavior seems good to me.

@Thomasdezeeuw
Copy link
Contributor Author

@stjepang but that still doesn't make you example work, does it? I mean you can remove the if statement and upgrade on the next loop, but that does mean some more atomic instructions.

@SimonSapin
Copy link
Contributor

It feels surprising that Weak::new() would not equal itself (not just results of other calls to Weak::new()).

@ghost
Copy link

ghost commented Nov 23, 2018

@Thomasdezeeuw Hmmm, right... if AtomicWeak is initialized to Weak::new(), then it doesn't work.

@SimonSapin also has a good point.

I think there are two ways to interpret a dangling Weak::new() pointer:

  1. It is like an uninitialized pointer and every such pointer is (potentially?) different.
  2. It is like a null pointer and all such pointers are equal.

Given these two choices, I'd prefer to go with the second one and make all dangling pointers equal.
EDIT: Not so sure anymore.

@ghost
Copy link

ghost commented Nov 23, 2018

Btw, a small nit: in the docs for std::rc::Weak::new, the link to upgrade is dangling. Might be good to fix it in this PR.

@Thomasdezeeuw
Copy link
Contributor Author

@SimonSapin I agree that it is surprising, but I went of the docs from Rc::ptr_eq which says:

Returns true if the two Rcs point to the same value (not just values that compare as equal).

Since Weak::new points to no value it can't ever point to the same value as any other Weak.

But if everybody agress that they should be equal to one another then I'm willing to change it.

@jethrogb
Copy link
Contributor

I don't think they should be equal.

@ghost
Copy link

ghost commented Nov 23, 2018

@jethrogb But do you think a dangling pointer should at least be equal to itself?

E.g. let w = Weak::new(); Weak::ptr_eq(&w, &w)

@sfackler
Copy link
Member

sfackler commented Dec 3, 2018

Seems reasonable.

@bors r+

@bors
Copy link
Contributor

bors commented Dec 3, 2018

📌 Commit 38e21f9 has been approved by sfackler

@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 Dec 3, 2018
kennytm added a commit to kennytm/rust that referenced this pull request Dec 4, 2018
Add Weak.ptr_eq

I hope the doc tests alone are good enough.

We also might want to discuss the dangling pointer case (from `Weak::new()`).

Updates rust-lang#55981.
@kennytm
Copy link
Member

kennytm commented Dec 4, 2018

@bors rollup

GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this pull request Dec 4, 2018
Add Weak.ptr_eq

I hope the doc tests alone are good enough.

We also might want to discuss the dangling pointer case (from `Weak::new()`).

Updates rust-lang#55981.
GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this pull request Dec 5, 2018
Add Weak.ptr_eq

I hope the doc tests alone are good enough.

We also might want to discuss the dangling pointer case (from `Weak::new()`).

Updates rust-lang#55981.
pietroalbini added a commit to pietroalbini/rust that referenced this pull request Dec 5, 2018
Add Weak.ptr_eq

I hope the doc tests alone are good enough.

We also might want to discuss the dangling pointer case (from `Weak::new()`).

Updates rust-lang#55981.
pietroalbini added a commit to pietroalbini/rust that referenced this pull request Dec 5, 2018
Add Weak.ptr_eq

I hope the doc tests alone are good enough.

We also might want to discuss the dangling pointer case (from `Weak::new()`).

Updates rust-lang#55981.
bors added a commit that referenced this pull request Dec 5, 2018
Rollup of 15 pull requests

Successful merges:

 - #51753 (Document `From` implementations)
 - #55563 (Improve no result found sentence in doc search)
 - #55987 (Add Weak.ptr_eq)
 - #56119 (Utilize `?` instead of `return None`.)
 - #56372 (Refer to the second borrow as the "second borrow" in E0501.rs)
 - #56388 (More MIR borrow check cleanup)
 - #56424 (Mention raw-ident syntax)
 - #56452 (Remove redundant clones)
 - #56456 (Handle existential types in dead code analysis)
 - #56466 (data_structures: remove tuple_slice)
 - #56476 (Fix invalid line number match)
 - #56497 (cleanup: remove static lifetimes from consts in libstd)
 - #56498 (Fix line numbers display)
 - #56523 (Added a bare-bones eslint config (removing jslint))
 - #56538 (Use inner iterator may_have_side_effect for Cloned)

Failed merges:

r? @ghost
@bors bors merged commit 38e21f9 into rust-lang:master Dec 6, 2018
@chpio
Copy link
Contributor

chpio commented Jun 13, 2019

what is the reason for ptr_eq to be an associated function? I mean it's just a Weak not Rc, there's no deref?

@Thomasdezeeuw
Copy link
Contributor Author

I just matched the method on Rc/Arc.

Centril added a commit to Centril/rust that referenced this pull request Jun 17, 2019
make `Weak::ptr_eq`s into methods

This makes the `Weak::ptr_eq`s associated function into methods. There's no reason for methods on `Weak`s to be associated functions, as there is no `Dered` thus no possibility of a collision. Also: methods can be called using the associated function syntax.

follow up on rust-lang#55987
[Tracking issue for weak_ptr_eq](rust-lang#55981)
Centril added a commit to Centril/rust that referenced this pull request Sep 14, 2019
Centril added a commit to Centril/rust that referenced this pull request Sep 14, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants