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 Arc::new_with() function for constructing self-referential data structures #72443

Closed
wants to merge 1 commit into from

Conversation

Diggsey
Copy link
Contributor

@Diggsey Diggsey commented May 21, 2020

It should be noted that this exposes a new behaviour: a Weak can now become "live" after having previously observed it as being "dead".

This does not impact the safety of the Arc because we ensure the weak reference count does not reach zero during this time.

In the process this PR changes the ArcInner::data field to use an UnsafeCell - my understanding of the unsafe code guidelines is that this change will become necessary even without the new API addition. However, the new function undeniably makes the data field internally mutable, whereas before there seemed to be some debate.

To me, all of the prior uses of ptr.as_mut() seemed suspect as they could result in aliasing mutable references. Using an UnsafeCell allows those usages to be replaced with a raw pointer which has no aliasing requirements.

edit:
This UB was fixed in a separate PR.

Perhaps @RalfJung can provide some clarity on whether these additional changes are actually required.

@rust-highfive
Copy link
Collaborator

r? @cramertj

(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 May 21, 2020
@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-8 of your PR failed (pretty log, 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.
##[section]Starting: Linux x86_64-gnu-llvm-8
##[section]Starting: Initialize job
Agent name: 'Azure Pipelines 66'
Agent machine name: 'fv-az578'
Current agent version: '2.168.2'
##[group]Operating System
16.04.6
LTS
LTS
##[endgroup]
##[group]Virtual Environment
Environment: ubuntu-16.04
Version: 20200512.2
Included Software: https://github.com/actions/virtual-environments/blob/ubuntu16/20200512.2/images/linux/Ubuntu1604-README.md
##[endgroup]
Agent running as: 'vsts'
Prepare build directory.
Set build variables.
Download all required tasks.
Download all required tasks.
Downloading task: Bash (3.163.2)
Checking job knob settings.
   Knob: AgentToolsDirectory = /opt/hostedtoolcache Source: ${AGENT_TOOLSDIRECTORY} 
   Knob: AgentPerflog = /home/vsts/perflog Source: ${VSTS_AGENT_PERFLOG} 
Start tracking orphan processes.
##[section]Finishing: Initialize job
##[section]Starting: Configure Job Name
==============================================================================
---
========================== Starting Command Output ===========================
[command]/bin/bash --noprofile --norc /home/vsts/work/_temp/2c7efe3b-c778-4cff-ad76-c92ec88dc40c.sh

##[section]Finishing: Disable git automatic line ending conversion
##[section]Starting: Checkout rust-lang/rust@refs/pull/72443/merge to s
Task         : Get sources
Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.
Version      : 1.0.0
Author       : Microsoft
---
##[command]git remote add origin https://github.com/rust-lang/rust
##[command]git config gc.auto 0
##[command]git config --get-all http.https://github.com/rust-lang/rust.extraheader
##[command]git config --get-all http.proxy
##[command]git -c http.extraheader="AUTHORIZATION: basic ***" fetch --force --tags --prune --progress --no-recurse-submodules --depth=2 origin +refs/heads/*:refs/remotes/origin/* +refs/pull/72443/merge:refs/remotes/pull/72443/merge
---
 ---> cb2676f08729
Step 5/8 : ENV RUST_CONFIGURE_ARGS       --build=x86_64-unknown-linux-gnu       --llvm-root=/usr/lib/llvm-8       --enable-llvm-link-shared       --set rust.thin-lto-import-instr-limit=10
 ---> Using cache
 ---> df25ce111862
Step 6/8 : ENV SCRIPT python2.7 ../x.py test --exclude src/tools/tidy &&            python2.7 ../x.py test src/test/mir-opt --pass=build                                   --target=armv5te-unknown-linux-gnueabi &&            python2.7 ../x.py test src/tools/tidy
 ---> 599b9ac96b27
Step 7/8 : ENV NO_DEBUG_ASSERTIONS=1
 ---> Using cache
 ---> 091087e35a36
---
   Compiling fmt_macros v0.0.0 (/checkout/src/libfmt_macros)
   Compiling chalk-rust-ir v0.10.0
   Compiling rustc_ast_pretty v0.0.0 (/checkout/src/librustc_ast_pretty)
   Compiling rustc_hir v0.0.0 (/checkout/src/librustc_hir)
   Compiling rustc_query_system v0.0.0 (/checkout/src/librustc_query_system)
   Compiling chalk-solve v0.10.0
   Compiling rustc_hir_pretty v0.0.0 (/checkout/src/librustc_hir_pretty)
   Compiling rustc_parse v0.0.0 (/checkout/src/librustc_parse)
   Compiling rustc_ast_lowering v0.0.0 (/checkout/src/librustc_ast_lowering)
---
   Compiling fmt_macros v0.0.0 (/checkout/src/libfmt_macros)
   Compiling chalk-rust-ir v0.10.0
   Compiling rustc_ast_pretty v0.0.0 (/checkout/src/librustc_ast_pretty)
   Compiling rustc_hir v0.0.0 (/checkout/src/librustc_hir)
   Compiling rustc_query_system v0.0.0 (/checkout/src/librustc_query_system)
   Compiling chalk-solve v0.10.0
   Compiling rustc_hir_pretty v0.0.0 (/checkout/src/librustc_hir_pretty)
   Compiling rustc_parse v0.0.0 (/checkout/src/librustc_parse)
   Compiling rustc_ast_lowering v0.0.0 (/checkout/src/librustc_ast_lowering)
---
...........................................................................i........................ 1800/10215
.................................................................................................... 1900/10215
..............................................................................................i..i.. 2000/10215
.................................................................................................... 2100/10215
....................................................................................iiiii........... 2200/10215
.................................................................................................... 2400/10215
.................................................................................................... 2500/10215
.................................................................................................... 2600/10215
.................................................................................................... 2700/10215
---
..........i...............i......................................................................... 5200/10215
.................................................................................................... 5300/10215
.........................................................i.......................................... 5400/10215
..................................................i................................................. 5500/10215
...........................................................ii.ii........i...i....................... 5600/10215
.i.................................................................................................. 5800/10215
.........i.......................................................................................... 5900/10215
.............................................................ii..................................... 6000/10215
i................................................................................................... 6100/10215
i................................................................................................... 6100/10215
.................................................................................................... 6200/10215
.................................................................................................... 6300/10215
......................ii...i..ii...........i........................................................ 6400/10215
.................................................................................................... 6600/10215
.................................................................................................... 6700/10215
.................................................................................................... 6700/10215
.......................................................i..ii........................................ 6800/10215
.................................................................................................... 7000/10215
.................................................................................................... 7100/10215
.........i.......................................................................................... 7200/10215
.................................................................................................... 7300/10215
---
.................................................................................................... 8100/10215
.................................................................................................... 8200/10215
.................................................................................................... 8300/10215
.................................i.................................................................. 8400/10215
.......................................................................................iiiiii.iiiiii 8500/10215
..........................................i......................................................... 8700/10215
.................................................................................................... 8800/10215
.................................................................................................... 8900/10215
.................................................................................................... 9000/10215
---
---- [ui] ui/issues/issue-29037.rs stdout ----

error: test compilation failed although it shouldn't!
status: exit code: 1
command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/issues/issue-29037.rs" "-Zthreads=1" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/issues/issue-29037" "-A" "unused" "-Crpath" "-O" "-Cdebuginfo=0" "-Zunstable-options" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/issues/issue-29037/auxiliary"
------------------------------------------

------------------------------------------
stderr:
stderr:
------------------------------------------
error[E0308]: mismatched types
  --> /checkout/src/test/ui/issues/issue-29037.rs:17:5
   |
LL |     x
   |     ^ lifetime mismatch
   |
   = note: expected struct `std::sync::Arc<&'r str>`
              found struct `std::sync::Arc<&'static str>`
note: the lifetime `'r` as defined on the function body at 16:6...
   |
   |
LL | fn c<'r>(x: Arc<&'static str>) -> Arc<&'r str> {
   |      ^^
   = note: ...does not necessarily outlive the static lifetime
error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.

---
thread 'main' panicked at 'Some tests failed', src/tools/compiletest/src/main.rs:348:22
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-tools-bin/compiletest" "--compile-lib-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib" "--run-lib-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/x86_64-unknown-linux-gnu/lib" "--rustc-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "--src-base" "/checkout/src/test/ui" "--build-base" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui" "--stage-id" "stage2-x86_64-unknown-linux-gnu" "--mode" "ui" "--target" "x86_64-unknown-linux-gnu" "--host" "x86_64-unknown-linux-gnu" "--llvm-filecheck" "/usr/lib/llvm-8/bin/FileCheck" "--nodejs" "/usr/bin/node" "--host-rustcflags" "-Crpath -O -Cdebuginfo=0 -Zunstable-options  -Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "--target-rustcflags" "-Crpath -O -Cdebuginfo=0 -Zunstable-options  -Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "--docck-python" "/usr/bin/python2.7" "--lldb-python" "/usr/bin/python2.7" "--gdb" "/usr/bin/gdb" "--quiet" "--llvm-version" "8.0.0" "--system-llvm" "--cc" "" "--cxx" "" "--cflags" "" "--llvm-components" "" "--adb-path" "adb" "--adb-test-dir" "/data/tmp/work" "--android-cross-path" "" "--color" "always"


failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test --exclude src/tools/tidy
Build completed unsuccessfully in 0:59:29
Build completed unsuccessfully in 0:59:29
== clock drift check ==
  local time: Fri May 22 00:08:53 UTC 2020
  network time: Fri, 22 May 2020 00:08:54 GMT
== end clock drift check ==

##[error]Bash exited with code '1'.
##[section]Finishing: Run build
##[section]Starting: Checkout rust-lang/rust@refs/pull/72443/merge to s
Task         : Get sources
Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.
Version      : 1.0.0
Author       : Microsoft
Author       : Microsoft
Help         : [More Information](https://go.microsoft.com/fwlink/?LinkId=798199)
==============================================================================
Cleaning any cached credential from repository: rust-lang/rust (GitHub)
##[section]Finishing: Checkout rust-lang/rust@refs/pull/72443/merge to s
Cleaning up task key
Start cleaning up orphan processes.
Terminate orphan process: pid (3660) (python)
##[section]Finishing: Finalize Job

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 @rust-lang/infra. (Feature Requests)

@Diggsey
Copy link
Contributor Author

Diggsey commented May 22, 2020

Hm, using an UnsafeCell changes the variance from covariant to invariant. AFAIK, there's no way to "override" this?

@RalfJung
Copy link
Member

RalfJung commented May 22, 2020

my understanding of the unsafe code guidelines is that this change will become necessary even without the new API addition

Do you have a reference for that? IIRC think the current code is fine. (There are other issues but those are unrelated.)

However, the new function undeniably makes the data field internally mutable, whereas before there seemed to be some debate.

So, where is the shared reference that points to data while it is being mutated? As far as I can tell, all we have here are a bunch of raw pointers, in which case you wouldn't need UnsafeCell.

src/liballoc/sync.rs Outdated Show resolved Hide resolved
@Diggsey
Copy link
Contributor Author

Diggsey commented May 22, 2020

@RalfJung yeah, for example, look at Arc::drop_slow:

rust/src/liballoc/sync.rs

Lines 866 to 870 in c60b675

#[inline(never)]
unsafe fn drop_slow(&mut self) {
// Destroy the data at this time, even though we may not free the box
// allocation itself (there may still be weak pointers lying around).
ptr::drop_in_place(&mut self.ptr.as_mut().data);

This races with Weak::inner:

rust/src/liballoc/sync.rs

Lines 1680 to 1683 in c60b675

#[inline]
fn inner(&self) -> Option<&ArcInner<T>> {
if is_dangling(self.ptr) { None } else { Some(unsafe { self.ptr.as_ref() }) }
}

Firstly, because &mut raw isn't a thing, this creates a mutable reference at the same time as the shared reference returned by Weak::inner can exist. However, even if we ignore that, calling drop_in_place mutates the data value, which AIUI is UB when we have a live shared reference to the containing struct (unless we mark the field as internally mutable somehow).

Copy link
Contributor

@danielhenrymantilla danielhenrymantilla left a comment

Choose a reason for hiding this comment

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

I started reviewing with a few nits (and a potential unsoundness with atomic ordering), but then, after thinking about it, I've realised that the whole Weak-as-input API is hard to make sound given how Weak operates: anybody can call .upgrade() on a Weak or a .clone() of it, which will call .inner().

And currently, .inner() does promote the NonNull<ArcInner<T>> to a &ArcInner<T>, thus asserting both:

  • non-aliasing of data: T (c.f., @Diggsey post above),
  • and in the future, that data is initialized. This incurs in the maintenance burden of having to be update the code if Rust "starts exploiting" that validity of the pointee is part of the validity invariant of a Rust reference (which it conservatively "officially" does: the very fact this currently isn't be a problem here is that the stdlib gets to know what isn't "exploited UB" yet).

So, instead, I suggest that, before this PR goes forward, Weak's .inner() be changed to return an Option<&'_ ArcInner<UnsafeCell<MaybeUninit<T>>> (or an Option<&'_ ArcInner<()>> with separate unsafe fns &data accessors)

  • Otherwise, the whole new_with does indeed require infecting everything with UnsafeCells, and would be relying on Rust references being allowed to refer to uninitialized data 😬

This may look cumbersome, but it will lead to the rest of Arc's API to be at peace with Weaks being, well, a very weak pointer type, that only gets to assert anything about its data if and only if strong ≥ 1.

Then, we could slightly simplify and thus improve new_with, with something along these lines:

    /// Constructs a new `Arc<T>` out of a closure that gets to have
    /// `Weak` "back"-pointer to the to-be-returned `Arc`.
    ///
    /// This is useful to create immutable graph-like structures, since
    /// those may require back pointers.
    ///
    /// Since the closure runs before such `Arc` is fully constructed,
    /// the obtained `Weak` "dangles" while the closure is running:
    /// any attempts to upgrade the `Weak` at that point will fail.
    #[inline]
    #[unstable(feature = "arc_new_with", issue = "none")]
    pub fn new_with(data_fn: impl FnOnce(&'_ Weak<T>) -> T) -> Arc<T> {
        let weak = Weak {
            ptr: Box::into_raw_nonnull(box ArcInner {
                strong: 0.into(),
                weak: 1.into(),
                data: UnsafeCell::new(mem::MaybeUninit::<T>::uninit()),
            }).cast(),
        };
        let data = data_fn(&weak);
        let inner: &'_ ArcInner<UnsafeCell<MaybeUninit<T>>> = weak.inner().unwrap();
        unsafe {
            inner
                .data
                .get() // exclusive access is guaranteed by `strong == 0`
                .write(MaybeUninit::new(data))
            ;
            // `data` has been initialized and is no longer (directly) mutated
            // so we can finally allow other `Weak`s to be upgraded.
            inner.strong.store(1, atomic::Ordering::Release);
            // "transmute"-upgrade the `Weak` to an `Arc`
            Arc::from_inner(ManuallyDrop::new(weak).ptr)
        }
    }

@Diggsey
Copy link
Contributor Author

Diggsey commented May 22, 2020

@danielhenrymantilla that sounds like a reasonable plan. What do you think about the variance issue that CI showed up?

At the moment there is no syntax for "overriding" the variance of a type parameter, and any use of UnsafeCell will cause it to become invariant.

The only solution I can see is to change the pointer inside Arc and Weak to effectively a void*, and then cast it to the correct pointer type on every access. I'll also need to add a PhantomData field to Weak.

@Diggsey
Copy link
Contributor Author

Diggsey commented May 22, 2020

Ugh, I can't even do that, because there's no way to get CoerceUnsized to work in that scenario...

@Diggsey
Copy link
Contributor Author

Diggsey commented May 22, 2020

I opened PR #72479 to address the UB as a first step.

@jhjourdan
Copy link
Contributor

Just a few remarks regarding this PR :

1- There is no reason to restrict this addition to Arc. We should also add it to Rc.

2- Instead of adding a second-order function which first create a dead Weak pointer, then call a closure and finally does the "Weak to Arc revival", why not adding a function which would only do the "Weak to Arc revival"? Its signature would look like:

fn write_and_upgrade(ptr : Weak<T>, x : T)  -> Option<Arc<T>>

It would first check that the weak count is exactly 1, then allocate some memory and copy x there and finally turn the weak pointer into a strong one.

Then, it is easy to re-implement new_with using write_and_upgrade: you first create a dead pointer using Weak::new, then call the closure and finally revive the weak pointer.

@Diggsey
Copy link
Contributor Author

Diggsey commented May 25, 2020

It would first check that the weak count is exactly 1

That would break Arc::new_with: the purpose of this function is to allow storing one or more weak references somewhere before the Arc is created.

@jhjourdan
Copy link
Contributor

It would first check that the weak count is exactly 1

That would break Arc::new_with: the purpose of this function is to allow storing one or more weak references somewhere before the Arc is created.

You are right. Then we would need to lift the restriction about the weak count. But then we need to use some kind of locking mechanism to make sure that the write_and_upgrade function is not used concurrently.

Another change we would need to make is reverting #50357 since we are actually upgrading a Weak::new()-created pointer. I don't know whether this is actually a concern since nobody actually brought any evidence that Weak::new() is a performance bottleneck.

@Diggsey
Copy link
Contributor Author

Diggsey commented May 25, 2020

Yeah, I don't think any of that is worthwhile. Also, personally I would be pretty unhappy if Weak::new() became more expensive.

@RalfJung

This comment has been minimized.

@jhjourdan
Copy link
Contributor

I personally think that's a first-order API makes it possible to write more readable code, especially if there are several cycles to build at the same time.

I guess that's a matter of taste...

@bors
Copy link
Contributor

bors commented May 27, 2020

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

@Diggsey
Copy link
Contributor Author

Diggsey commented May 27, 2020

I've updated this now that the UB fix has merged.

src/liballoc/sync.rs Outdated Show resolved Hide resolved
src/liballoc/sync.rs Outdated Show resolved Hide resolved
src/liballoc/sync.rs Outdated Show resolved Hide resolved
@RalfJung
Copy link
Member

@Diggsey what about @jhjourdan 's other point, that this should be added to Rc as well? Would be odd to let the APIs of those two diverge without a good reason.

@Diggsey
Copy link
Contributor Author

Diggsey commented May 27, 2020

TBH, I first wanted to establish that this is an API we want to add, before we get into the nitty gritty of documenting and testing it properly. I don't want to do all the work of implementing it only for everyone to agree that we don't want to extend the capabilities of Weak in this way.

Also, I agree there should be a counterpart for Rc, but I see no point in adding that until everyone is happy with the Arc implementation, otherwise I'll just have twice as many changes to make on every review comment.

@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-8 of your PR failed (pretty log, 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.
##[section]Starting: Linux x86_64-gnu-llvm-8
##[section]Starting: Initialize job
Agent name: 'Azure Pipelines 51'
Agent machine name: 'fv-az578'
Current agent version: '2.168.2'
##[group]Operating System
16.04.6
LTS
LTS
##[endgroup]
##[group]Virtual Environment
Environment: ubuntu-16.04
Version: 20200517.1
Included Software: https://github.com/actions/virtual-environments/blob/ubuntu16/20200517.1/images/linux/Ubuntu1604-README.md
##[endgroup]
Agent running as: 'vsts'
Prepare build directory.
Set build variables.
Download all required tasks.
Download all required tasks.
Downloading task: Bash (3.163.2)
Checking job knob settings.
   Knob: AgentToolsDirectory = /opt/hostedtoolcache Source: ${AGENT_TOOLSDIRECTORY} 
   Knob: AgentPerflog = /home/vsts/perflog Source: ${VSTS_AGENT_PERFLOG} 
Start tracking orphan processes.
##[section]Finishing: Initialize job
##[section]Starting: Configure Job Name
==============================================================================
---
========================== Starting Command Output ===========================
[command]/bin/bash --noprofile --norc /home/vsts/work/_temp/0bdbcbb7-a337-4a68-8d36-ac4e2706c445.sh

##[section]Finishing: Disable git automatic line ending conversion
##[section]Starting: Checkout rust-lang/rust@refs/pull/72443/merge to s
Task         : Get sources
Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.
Version      : 1.0.0
Author       : Microsoft
---
##[command]git remote add origin https://github.com/rust-lang/rust
##[command]git config gc.auto 0
##[command]git config --get-all http.https://github.com/rust-lang/rust.extraheader
##[command]git config --get-all http.proxy
##[command]git -c http.extraheader="AUTHORIZATION: basic ***" fetch --force --tags --prune --progress --no-recurse-submodules --depth=2 origin +refs/heads/*:refs/remotes/origin/* +refs/pull/72443/merge:refs/remotes/pull/72443/merge
---
 ---> cb2676f08729
Step 5/8 : ENV RUST_CONFIGURE_ARGS       --build=x86_64-unknown-linux-gnu       --llvm-root=/usr/lib/llvm-8       --enable-llvm-link-shared       --set rust.thin-lto-import-instr-limit=10
 ---> Using cache
 ---> df25ce111862
Step 6/8 : ENV SCRIPT python2.7 ../x.py test --exclude src/tools/tidy &&            python2.7 ../x.py test src/test/mir-opt --pass=build                                   --target=armv5te-unknown-linux-gnueabi &&            python2.7 ../x.py test src/tools/tidy
 ---> 599b9ac96b27
Step 7/8 : ENV NO_DEBUG_ASSERTIONS=1
 ---> Using cache
 ---> 091087e35a36
---
   Compiling fmt_macros v0.0.0 (/checkout/src/libfmt_macros)
   Compiling chalk-rust-ir v0.10.0
   Compiling rustc_ast_pretty v0.0.0 (/checkout/src/librustc_ast_pretty)
   Compiling rustc_hir v0.0.0 (/checkout/src/librustc_hir)
   Compiling rustc_query_system v0.0.0 (/checkout/src/librustc_query_system)
   Compiling chalk-solve v0.10.0
   Compiling rustc_hir_pretty v0.0.0 (/checkout/src/librustc_hir_pretty)
   Compiling rustc_parse v0.0.0 (/checkout/src/librustc_parse)
   Compiling rustc_ast_lowering v0.0.0 (/checkout/src/librustc_ast_lowering)
---
   Compiling fmt_macros v0.0.0 (/checkout/src/libfmt_macros)
   Compiling chalk-rust-ir v0.10.0
   Compiling rustc_ast_pretty v0.0.0 (/checkout/src/librustc_ast_pretty)
   Compiling rustc_hir v0.0.0 (/checkout/src/librustc_hir)
   Compiling rustc_query_system v0.0.0 (/checkout/src/librustc_query_system)
   Compiling chalk-solve v0.10.0
   Compiling rustc_hir_pretty v0.0.0 (/checkout/src/librustc_hir_pretty)
   Compiling rustc_parse v0.0.0 (/checkout/src/librustc_parse)
   Compiling rustc_ast_lowering v0.0.0 (/checkout/src/librustc_ast_lowering)
---
..............................................................................i..................... 1800/10249
.................................................................................................... 1900/10249
.................................................................................................i.. 2000/10249
i................................................................................................... 2100/10249
.......................................................................................iiiii........ 2200/10249
.................................................................................................... 2400/10249
.................................................................................................... 2500/10249
.................................................................................................... 2600/10249
.................................................................................................... 2700/10249
---
...............i...............i.................................................................... 5200/10249
.................................................................................................... 5300/10249
...............................................................i.................................... 5400/10249
........................................................i........................................... 5500/10249
....................................................................ii.ii........i...i.............. 5600/10249
...........i........................................................................................ 5800/10249
...................i................................................................................ 5900/10249
........................................................................ii.......................... 6000/10249
...........i........................................................................................ 6100/10249
...........i........................................................................................ 6100/10249
.................................................................................................... 6200/10249
.................................................................................................... 6300/10249
.................................ii...i..ii...........i............................................. 6400/10249
.................................................................................................... 6600/10249
.................................................................................................... 6700/10249
.................................................................................................... 6700/10249
..................................................................i..ii............................. 6800/10249
.................................................................................................... 7000/10249
.................................................................................................... 7100/10249
....................i............................................................................... 7200/10249
.................................................................................................... 7300/10249
---
.................................................................................................... 8200/10249
.................................................................................................... 8300/10249
.......................................................i............................................ 8400/10249
.................................................................................................... 8500/10249
.........iiiiii.iiiiii.i............................................................................ 8600/10249
.................................................................................................... 8800/10249
.................................................................................................... 8900/10249
.................................................................................................... 9000/10249
.................................................................................................... 9100/10249
---
Suite("src/test/codegen") not skipped for "bootstrap::test::Codegen" -- not in ["src/tools/tidy"]
Check compiletest suite=codegen mode=codegen (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)

running 191 tests
iiii......i..............ii.i..........i.................................i..i................i....i. 100/191
............i.i.i...iii..iiiiiiiiiiiiiiii.......................iii................ii......

 finished in 5.994
Suite("src/test/codegen-units") not skipped for "bootstrap::test::CodegenUnits" -- not in ["src/tools/tidy"]
Check compiletest suite=codegen-units mode=codegen-units (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)
---
Suite("src/test/assembly") not skipped for "bootstrap::test::Assembly" -- not in ["src/tools/tidy"]
Check compiletest suite=assembly mode=assembly (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)

running 20 tests
iiiiiiiiiiiiiiiiiiii

 finished in 0.166
Suite("src/test/incremental") not skipped for "bootstrap::test::Incremental" -- not in ["src/tools/tidy"]
Check compiletest suite=incremental mode=incremental (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)
---
Suite("src/test/debuginfo") not skipped for "bootstrap::test::Debuginfo" -- not in ["src/tools/tidy"]
Check compiletest suite=debuginfo mode=debuginfo (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)

running 115 tests
iiiii..i.....i..i...i..i.i.i..i..i..ii....i.i....ii..........iiii.........i.....i..i.......ii.i.ii.. 100/115
...iiii.....ii.

 finished in 15.488
Suite("src/test/ui-fulldeps") not skipped for "bootstrap::test::UiFullDeps" -- not in ["src/tools/tidy"]
Uplifting stage1 rustc (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)
---
.........................................................................F.FF....................... 100/116
................
failures:

---- sync::tests::test_arc_new_with_one_ref stdout ----
thread 'sync::tests::test_arc_new_with_one_ref' panicked at 'assertion failed: `(left == right)`
 right: `1`', src/liballoc/sync/tests.rs:521:9

---- sync::tests::test_arc_new_with_two_refs stdout ----
---- sync::tests::test_arc_new_with_two_refs stdout ----
thread 'sync::tests::test_arc_new_with_two_refs' panicked at 'assertion failed: `(left == right)`
 right: `1`', src/liballoc/sync/tests.rs:544:9

---- sync::tests::test_arc_new_with_zero_refs stdout ----
---- sync::tests::test_arc_new_with_zero_refs stdout ----
thread 'sync::tests::test_arc_new_with_zero_refs' panicked at 'assertion failed: `(left == right)`
 right: `1`', src/liballoc/sync/tests.rs:503:9


failures:
failures:
    sync::tests::test_arc_new_with_one_ref
    sync::tests::test_arc_new_with_two_refs
    sync::tests::test_arc_new_with_zero_refs

test result: FAILED. 113 passed; 3 failed; 0 ignored; 0 measured; 0 filtered out

error: test failed, to rerun pass '-p alloc --lib'

command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "test" "--target" "x86_64-unknown-linux-gnu" "-Zbinary-dep-depinfo" "-j" "2" "--release" "--locked" "--color" "always" "--features" "panic-unwind backtrace compiler-builtins-c" "--manifest-path" "/checkout/src/libtest/Cargo.toml" "-p" "alloc" "--" "--quiet"
expected success, got: exit code: 101

---
  local time: Fri May 29 00:25:07 UTC 2020
  network time: Fri, 29 May 2020 00:25:08 GMT
== end clock drift check ==

##[error]Bash exited with code '1'.
##[section]Finishing: Run build
##[section]Starting: Checkout rust-lang/rust@refs/pull/72443/merge to s
Task         : Get sources
Description  : Get sources from a repository. Supports Git, TfsVC, and SVN repositories.
Version      : 1.0.0
Author       : Microsoft
Author       : Microsoft
Help         : [More Information](https://go.microsoft.com/fwlink/?LinkId=798199)
==============================================================================
Cleaning any cached credential from repository: rust-lang/rust (GitHub)
##[section]Finishing: Checkout rust-lang/rust@refs/pull/72443/merge to s
Cleaning up task key
Start cleaning up orphan processes.
Terminate orphan process: pid (3547) (python)
##[section]Finishing: Finalize Job

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 @rust-lang/infra. (Feature Requests)

Copy link
Member

@RalfJung RalfJung 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 this is tricky enough to justify more eyes checking it.

Also, as discussed before, a similar API should be added to Rc once we all agree that this is worthwhile.

@Elinvynia Elinvynia added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 10, 2020
@Dylan-DPC-zz
Copy link

r? @dtolnay

@rust-highfive rust-highfive assigned dtolnay and unassigned cramertj Jun 24, 2020
@dtolnay dtolnay added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Jun 25, 2020
@dtolnay dtolnay changed the title Add Arc::new_with() function for constructing self-referential data… Add Arc::new_with() function for constructing self-referential data structures Jun 25, 2020
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.

Could someone provide a realistic code snippet showing how this would be applied in real code and/or point out an open source library where this is applicable? The doc test shows some rationale but not necessarily how this would typically be applied in practice.

@Diggsey
Copy link
Contributor Author

Diggsey commented Jun 29, 2020

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=37d17061794bd25c4cb75517ab811ea9

The only way to construct Foo is using Arc::new_with, or by using some kind of Cell (which would either make Foo !Send, or require additional synchronization).

Being able to give out reference-counted pointers to yourself is a very useful operation, and similar methods exist in C++ for a class to obtain a shared_ptr to itself.

https://en.cppreference.com/w/cpp/memory/enable_shared_from_this

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.

Thanks, makes sense. I think I would be on board with this, possibly under a different name. Does Arc::new_cyclic perhaps better capture the intended use case?

@Diggsey
Copy link
Contributor Author

Diggsey commented Jun 29, 2020

I have no particular preference as to the name: I went with new_with as we use the _with suffix elsewhere to differentiate function variants that take a closure as an argument.

@Muirrum Muirrum added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 17, 2020
@Dylan-DPC-zz Dylan-DPC-zz added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 18, 2020
@Dylan-DPC-zz
Copy link

@Diggsey waiting for you to update this PR and then we can get it reviewed again :) thanks

@bors
Copy link
Contributor

bors commented Jul 28, 2020

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

@Muirrum Muirrum added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 13, 2020
@RalfJung
Copy link
Member

Should this be closed in favor of #75505?

@Diggsey
Copy link
Contributor Author

Diggsey commented Aug 14, 2020

Yeah sorry never got around to updating this 😦

@Diggsey Diggsey closed this Aug 14, 2020
@KodrAus KodrAus mentioned this pull request Aug 24, 2020
4 tasks
bors added a commit to rust-lang-ci/rust that referenced this pull request Aug 24, 2020
@yaahc yaahc mentioned this pull request Dec 2, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. 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.