about summary refs log tree commit diff
diff options
context:
space:
mode:
authorscalexm <martin.alex32@hotmail.fr>2017-08-09 13:55:27 +0200
committerscalexm <martin.alex32@hotmail.fr>2017-08-14 15:07:22 +0200
commitd58b40e16b9466ba4e049fe0dae8b8d08df1d44d (patch)
tree4d701575c13491cff9e9767c0f65e7ee767dd845
parente1f1798ba90676d36906c016145f237e54eea294 (diff)
downloadrust-d58b40e16b9466ba4e049fe0dae8b8d08df1d44d.tar.gz
rust-d58b40e16b9466ba4e049fe0dae8b8d08df1d44d.zip
Use an helper struct
-rw-r--r--src/librustc_mir/shim.rs586
-rw-r--r--src/test/run-pass/builtin-clone-unwind.rs20
2 files changed, 312 insertions, 294 deletions
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index d2a42650e3d..f3c3c808446 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -277,67 +277,151 @@ fn build_clone_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
                               self_ty: ty::Ty<'tcx>)
                               -> Mir<'tcx>
 {
-    let sig = tcx.fn_sig(def_id);
-    let sig = tcx.erase_late_bound_regions(&sig);
-    let span = tcx.def_span(def_id);
-
     debug!("build_clone_shim(def_id={:?})", def_id);
 
-    let mut local_decls = local_decls_for_sig(&sig, span);
-    let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE };
+    let mut builder = CloneShimBuilder::new(tcx, def_id);
+    let is_copy = !self_ty.moves_by_default(tcx, tcx.param_env(def_id), builder.span);
 
-    let rcvr = Lvalue::Local(Local::new(1+0)).deref();
+    match self_ty.sty {
+        _ if is_copy => builder.copy_shim(),
+        ty::TyArray(ty, len) => builder.array_shim(ty, len),
+        ty::TyTuple(tys, _) => builder.tuple_shim(tys),
+        _ => {
+            bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty);
+        }
+    };
 
-    let mut blocks = IndexVec::new();
-    let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| {
-        blocks.push(BasicBlockData {
+    builder.into_mir()
+}
+
+struct CloneShimBuilder<'a, 'tcx: 'a> {
+    tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
+    def_id: DefId,
+    local_decls: IndexVec<Local, LocalDecl<'tcx>>,
+    blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
+    span: Span,
+    sig: ty::FnSig<'tcx>,
+}
+
+impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
+    fn new(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Self {
+        let sig = tcx.fn_sig(def_id);
+        let sig = tcx.erase_late_bound_regions(&sig);
+        let span = tcx.def_span(def_id);
+
+        CloneShimBuilder {
+            tcx,
+            def_id,
+            local_decls: local_decls_for_sig(&sig, span),
+            blocks: IndexVec::new(),
+            span,
+            sig,
+        }
+    }
+
+    fn into_mir(self) -> Mir<'tcx> {
+        Mir::new(
+            self.blocks,
+            IndexVec::from_elem_n(
+                VisibilityScopeData { span: self.span, parent_scope: None }, 1
+            ),
+            IndexVec::new(),
+            self.sig.output(),
+            self.local_decls,
+            self.sig.inputs().len(),
+            vec![],
+            self.span
+        )
+    }
+
+    fn source_info(&self) -> SourceInfo {
+        SourceInfo { span: self.span, scope: ARGUMENT_VISIBILITY_SCOPE }
+    }
+
+    fn block(
+        &mut self,
+        statements: Vec<Statement<'tcx>>,
+        kind: TerminatorKind<'tcx>,
+        is_cleanup: bool
+    ) -> BasicBlock {
+        let source_info = self.source_info();
+        self.blocks.push(BasicBlockData {
             statements,
             terminator: Some(Terminator { source_info, kind }),
             is_cleanup,
         })
-    };
+    }
 
-    let make_lvalue = |mutability, ty, local_decls: &mut IndexVec<_, _>| {
+    fn make_statement(&self, kind: StatementKind<'tcx>) -> Statement<'tcx> {
+        Statement {
+            source_info: self.source_info(),
+            kind,
+        }
+    }
+
+    fn copy_shim(&mut self) {
+        let rcvr = Lvalue::Local(Local::new(1+0)).deref();
+        let ret_statement = self.make_statement(
+            StatementKind::Assign(
+                Lvalue::Local(RETURN_POINTER),
+                Rvalue::Use(Operand::Consume(rcvr))
+            )
+        );
+        self.block(vec![ret_statement], TerminatorKind::Return, false);
+    }
+
+    fn make_lvalue(&mut self, mutability: Mutability, ty: ty::Ty<'tcx>) -> Lvalue<'tcx> {
+        let span = self.span;
         Lvalue::Local(
-            local_decls.push(temp_decl(mutability, ty, span))
+            self.local_decls.push(temp_decl(mutability, ty, span))
         )
-    };
+    }
+
+    fn make_clone_call(
+        &mut self,
+        ty: ty::Ty<'tcx>,
+        rcvr_field: Lvalue<'tcx>,
+        next: BasicBlock,
+        cleanup: BasicBlock
+    ) -> Lvalue<'tcx> {
+        let tcx = self.tcx;
+
+        let substs = Substs::for_item(
+            tcx,
+            self.def_id,
+            |_, _| tcx.types.re_erased,
+            |_, _| ty
+        );
 
-    let call_clone = |ty, rcvr_field, next, cleanup,
-                      blocks: &mut _, local_decls: &mut IndexVec<_, _>|
-    {
         // `func == Clone::clone(&ty) -> ty`
-        let substs = Substs::for_item(tcx, def_id, |_, _| tcx.types.re_erased, |_, _| ty);
         let func = Operand::Constant(box Constant {
-            span: span,
-            ty: tcx.mk_fn_def(def_id, substs),
+            span: self.span,
+            ty: tcx.mk_fn_def(self.def_id, substs),
             literal: Literal::Value {
-                value: ConstVal::Function(def_id, substs),
+                value: ConstVal::Function(self.def_id, substs),
             },
         });
 
-        let ref_loc = make_lvalue(
+        let ref_loc = self.make_lvalue(
             Mutability::Not,
             tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut {
                 ty,
                 mutbl: hir::Mutability::MutImmutable,
-            }),
-            local_decls
+            })
         );
 
-        let loc = make_lvalue(Mutability::Not, ty, local_decls);
+        let loc = self.make_lvalue(Mutability::Not, ty);
 
         // `let ref_loc: &ty = &rcvr_field;`
-        let statement = Statement {
-            source_info,
-            kind: StatementKind::Assign(
+        let statement = self.make_statement(
+            StatementKind::Assign(
                 ref_loc.clone(),
                 Rvalue::Ref(tcx.types.re_erased, BorrowKind::Shared, rcvr_field)
             )
-        };
+        );
 
         // `let loc = Clone::clone(ref_loc);`
-        block(blocks, vec![statement], TerminatorKind::Call {
+        self.block(vec![statement], TerminatorKind::Call {
             func,
             args: vec![Operand::Consume(ref_loc)],
             destination: Some((loc.clone(), next)),
@@ -345,280 +429,214 @@ fn build_clone_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
         }, false);
 
         loc
-    };
-
-    let is_copy = !self_ty.moves_by_default(tcx, tcx.param_env(def_id), span);
-    match self_ty.sty {
-        _ if is_copy => {
-            // `return *self;`
-            let ret_statement = Statement {
-                source_info,
-                kind: StatementKind::Assign(
-                    Lvalue::Local(RETURN_POINTER),
-                    Rvalue::Use(Operand::Consume(rcvr))
-                )
-            };
-            block(&mut blocks, vec![ret_statement], TerminatorKind::Return, false);
-        }
-        ty::TyArray(ty, len) => {
-            let make_loop = |beg, end, loop_body, loop_end,
-                             blocks: &mut _, local_decls: &mut _, is_cleanup|
-            {
-                let cond = make_lvalue(Mutability::Mut, tcx.types.bool, local_decls);
-                let compute_cond = Statement {
-                    source_info,
-                    kind: StatementKind::Assign(
-                        cond.clone(),
-                        Rvalue::BinaryOp(BinOp::Ne, Operand::Consume(end), Operand::Consume(beg))
-                    )
-                };
-
-                // `if end != beg { goto loop_body; } else { goto loop_end; }`
-                block(
-                    blocks,
-                    vec![compute_cond],
-                    TerminatorKind::if_(tcx, Operand::Consume(cond), loop_body, loop_end),
-                    is_cleanup
-                );
-            };
-
-            let make_usize = |value| {
-                let value = ConstUsize::new(value as u64, tcx.sess.target.uint_type).unwrap();
-                box Constant {
-                    span,
-                    ty: tcx.types.usize,
-                    literal: Literal::Value {
-                        value: ConstVal::Integral(ConstInt::Usize(value))
-                    }
-                }
-            };
+    }
 
-            let beg = make_lvalue(Mutability::Mut, tcx.types.usize, &mut local_decls);
-            let end = make_lvalue(Mutability::Not, tcx.types.usize, &mut local_decls);
-            let ret = make_lvalue(Mutability::Mut, tcx.mk_array(ty, len), &mut local_decls);
-
-            // BB #0
-            // `let mut beg = 0;`
-            // `let end = len;`
-            // `goto #1;`
-            let inits = vec![
-                Statement {
-                    source_info,
-                    kind: StatementKind::Assign(
-                        beg.clone(),
-                        Rvalue::Use(Operand::Constant(make_usize(0)))
-                    )
-                },
-                Statement {
-                    source_info,
-                    kind: StatementKind::Assign(
-                        end.clone(),
-                        Rvalue::Use(Operand::Constant(make_usize(len)))
-                    )
-                }
-            ];
-            block(&mut blocks, inits, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
-
-            // BB #1: loop {
-            //     BB #2;
-            //     BB #3;
-            // }
-            // BB #4;
-            make_loop(
-                beg.clone(),
-                end,
-                BasicBlock::new(2),
-                BasicBlock::new(4),
-                &mut blocks,
-                &mut local_decls,
-                false
-            );
+    fn loop_header(
+        &mut self,
+        beg: Lvalue<'tcx>,
+        end: Lvalue<'tcx>,
+        loop_body: BasicBlock,
+        loop_end: BasicBlock,
+        is_cleanup: bool
+    ) {
+        let tcx = self.tcx;
+
+        let cond = self.make_lvalue(Mutability::Mut, tcx.types.bool);
+        let compute_cond = self.make_statement(
+            StatementKind::Assign(
+                cond.clone(),
+                Rvalue::BinaryOp(BinOp::Ne, Operand::Consume(end), Operand::Consume(beg))
+            )
+        );
 
-            // BB #2
-            // `let cloned = Clone::clone(rcvr[beg])`;
-            // Goto #3 if ok, #5 if unwinding happens.
-            let rcvr_field = rcvr.clone().index(Operand::Consume(beg.clone()));
-            let cloned = call_clone(
-                ty,
-                rcvr_field,
-                BasicBlock::new(3),
-                BasicBlock::new(5),
-                &mut blocks,
-                &mut local_decls
-            );
+        // `if end != beg { goto loop_body; } else { goto loop_end; }`
+        self.block(
+            vec![compute_cond],
+            TerminatorKind::if_(tcx, Operand::Consume(cond), loop_body, loop_end),
+            is_cleanup
+        );
+    }
 
-            // BB #3
-            // `ret[beg] = cloned;`
-            // `beg = beg + 1;`
-            // `goto #1`;
-            let ret_field = ret.clone().index(Operand::Consume(beg.clone()));
-            let statements = vec![
-                Statement {
-                    source_info,
-                    kind: StatementKind::Assign(
-                        ret_field,
-                        Rvalue::Use(Operand::Consume(cloned))
-                    )
-                },
-                Statement {
-                    source_info,
-                    kind: StatementKind::Assign(
-                        beg.clone(),
-                        Rvalue::BinaryOp(
-                            BinOp::Add,
-                            Operand::Consume(beg.clone()),
-                            Operand::Constant(make_usize(1))
-                        )
-                    )
-                }
-            ];
-            block(
-                &mut blocks,
-                statements,
-                TerminatorKind::Goto { target: BasicBlock::new(1) },
-                false
-            );
+    fn make_usize(&self, value: usize) -> Box<Constant<'tcx>> {
+        let value = ConstUsize::new(value as u64, self.tcx.sess.target.uint_type).unwrap();
+        box Constant {
+            span: self.span,
+            ty: self.tcx.types.usize,
+            literal: Literal::Value {
+                value: ConstVal::Integral(ConstInt::Usize(value))
+            }
+        }
+    }
 
-            // BB #4
-            // `return ret;`
-            let ret_statement = Statement {
-                source_info: source_info,
-                kind: StatementKind::Assign(
-                    Lvalue::Local(RETURN_POINTER),
-                    Rvalue::Use(Operand::Consume(ret.clone())),
-                )
-            };
-            block(&mut blocks, vec![ret_statement], TerminatorKind::Return, false);
-
-            // BB #5 (cleanup)
-            // `let end = beg;`
-            // `let mut beg = 0;`
-            // goto #6;
-            let end = beg;
-            let beg = make_lvalue(Mutability::Mut, tcx.types.usize, &mut local_decls);
-            let init = Statement {
-                source_info,
-                kind: StatementKind::Assign(
+    fn array_shim(&mut self, ty: ty::Ty<'tcx>, len: usize) {
+        let tcx = self.tcx;
+        let rcvr = Lvalue::Local(Local::new(1+0)).deref();
+
+        let beg = self.make_lvalue(Mutability::Mut, tcx.types.usize);
+        let end = self.make_lvalue(Mutability::Not, tcx.types.usize);
+        let ret = self.make_lvalue(Mutability::Mut, tcx.mk_array(ty, len));
+
+        // BB #0
+        // `let mut beg = 0;`
+        // `let end = len;`
+        // `goto #1;`
+        let inits = vec![
+            self.make_statement(
+                StatementKind::Assign(
                     beg.clone(),
-                    Rvalue::Use(Operand::Constant(make_usize(0)))
+                    Rvalue::Use(Operand::Constant(self.make_usize(0)))
                 )
-            };
-            block(
-                &mut blocks,
-                vec![init],
-                TerminatorKind::Goto { target: BasicBlock::new(6) },
-                true
-            );
-
-            // BB #6 (cleanup): loop {
-            //     BB #7;
-            //     BB #8;
-            // }
-            // BB #9;
-            make_loop(
-                beg.clone(),
-                end,
-                BasicBlock::new(7),
-                BasicBlock::new(9),
-                &mut blocks,
-                &mut local_decls,
-                true
-            );
-
-            // BB #7 (cleanup)
-            // `drop(ret[beg])`;
-            block(&mut blocks, vec![], TerminatorKind::Drop {
-                location: ret.index(Operand::Consume(beg.clone())),
-                target: BasicBlock::new(8),
-                unwind: None,
-            }, true);
-
-            // BB #8 (cleanup)
-            // `beg = beg + 1;`
-            // `goto #6;`
-            let statement = Statement {
-                source_info,
-                kind: StatementKind::Assign(
+            ),
+            self.make_statement(
+                StatementKind::Assign(
+                    end.clone(),
+                    Rvalue::Use(Operand::Constant(self.make_usize(len)))
+                )
+            )
+        ];
+        self.block(inits, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
+
+        // BB #1: loop {
+        //     BB #2;
+        //     BB #3;
+        // }
+        // BB #4;
+        self.loop_header(beg.clone(), end, BasicBlock::new(2), BasicBlock::new(4), false);
+
+        // BB #2
+        // `let cloned = Clone::clone(rcvr[beg])`;
+        // Goto #3 if ok, #5 if unwinding happens.
+        let rcvr_field = rcvr.clone().index(Operand::Consume(beg.clone()));
+        let cloned = self.make_clone_call(ty, rcvr_field, BasicBlock::new(3), BasicBlock::new(5));
+
+        // BB #3
+        // `ret[beg] = cloned;`
+        // `beg = beg + 1;`
+        // `goto #1`;
+        let ret_field = ret.clone().index(Operand::Consume(beg.clone()));
+        let statements = vec![
+            self.make_statement(
+                StatementKind::Assign(
+                    ret_field,
+                    Rvalue::Use(Operand::Consume(cloned))
+                )
+            ),
+            self.make_statement(
+                StatementKind::Assign(
                     beg.clone(),
                     Rvalue::BinaryOp(
                         BinOp::Add,
                         Operand::Consume(beg.clone()),
-                        Operand::Constant(make_usize(1))
+                        Operand::Constant(self.make_usize(1))
                     )
                 )
-            };
-            block(
-                &mut blocks,
-                vec![statement],
-                TerminatorKind::Goto { target: BasicBlock::new(6) },
-                true
-            );
+            )
+        ];
+        self.block(statements, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
 
-            // BB #9 (resume)
-            block(&mut blocks, vec![], TerminatorKind::Resume, true);
-        }
-        ty::TyTuple(tys, _) => {
-            let mut returns = Vec::new();
-            for (i, ity) in tys.iter().enumerate() {
-                let rcvr_field = rcvr.clone().field(Field::new(i), *ity);
-
-                // BB #(2i)
-                // `returns[i] = Clone::clone(&rcvr.i);`
-                // Goto #(2i + 2) if ok, #(2i + 1) if unwinding happens.
-                returns.push(call_clone(
+        // BB #4
+        // `return ret;`
+        let ret_statement = self.make_statement(
+            StatementKind::Assign(
+                Lvalue::Local(RETURN_POINTER),
+                Rvalue::Use(Operand::Consume(ret.clone())),
+            )
+        );
+        self.block(vec![ret_statement], TerminatorKind::Return, false);
+
+        // BB #5 (cleanup)
+        // `let end = beg;`
+        // `let mut beg = 0;`
+        // goto #6;
+        let end = beg;
+        let beg = self.make_lvalue(Mutability::Mut, tcx.types.usize);
+        let init = self.make_statement(
+            StatementKind::Assign(
+                beg.clone(),
+                Rvalue::Use(Operand::Constant(self.make_usize(0)))
+            )
+        );
+        self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
+
+        // BB #6 (cleanup): loop {
+        //     BB #7;
+        //     BB #8;
+        // }
+        // BB #9;
+        self.loop_header(beg.clone(), end, BasicBlock::new(7), BasicBlock::new(9), true);
+
+        // BB #7 (cleanup)
+        // `drop(ret[beg])`;
+        self.block(vec![], TerminatorKind::Drop {
+            location: ret.index(Operand::Consume(beg.clone())),
+            target: BasicBlock::new(8),
+            unwind: None,
+        }, true);
+
+        // BB #8 (cleanup)
+        // `beg = beg + 1;`
+        // `goto #6;`
+        let statement = self.make_statement(
+            StatementKind::Assign(
+                beg.clone(),
+                Rvalue::BinaryOp(
+                    BinOp::Add,
+                    Operand::Consume(beg.clone()),
+                    Operand::Constant(self.make_usize(1))
+                )
+            )
+        );
+        self.block(vec![statement], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
+
+        // BB #9 (resume)
+        self.block(vec![], TerminatorKind::Resume, true);
+    }
+
+    fn tuple_shim(&mut self, tys: &ty::Slice<ty::Ty<'tcx>>) {
+        let rcvr = Lvalue::Local(Local::new(1+0)).deref();
+
+        let mut returns = Vec::new();
+        for (i, ity) in tys.iter().enumerate() {
+            let rcvr_field = rcvr.clone().field(Field::new(i), *ity);
+
+            // BB #(2i)
+            // `returns[i] = Clone::clone(&rcvr.i);`
+            // Goto #(2i + 2) if ok, #(2i + 1) if unwinding happens.
+            returns.push(
+                self.make_clone_call(
                     *ity,
                     rcvr_field,
                     BasicBlock::new(2 * i + 2),
                     BasicBlock::new(2 * i + 1),
-                    &mut blocks,
-                    &mut local_decls
-                ));
-
-                // BB #(2i + 1) (cleanup)
-                if i == 0 {
-                    // Nothing to drop, just resume.
-                    block(&mut blocks, vec![], TerminatorKind::Resume, true);
-                } else {
-                    // Drop previous field and goto previous cleanup block.
-                    block(&mut blocks, vec![], TerminatorKind::Drop {
-                        location: returns[i - 1].clone(),
-                        target: BasicBlock::new(2 * i - 1),
-                        unwind: None,
-                    }, true);
-                }
-            }
-
-            // `return (returns[0], returns[1], ..., returns[tys.len() - 1]);`
-            let ret_statement = Statement {
-                source_info,
-                kind: StatementKind::Assign(
-                    Lvalue::Local(RETURN_POINTER),
-                    Rvalue::Aggregate(
-                        box AggregateKind::Tuple,
-                        returns.into_iter().map(Operand::Consume).collect()
-                    )
                 )
-            };
-            block(&mut blocks, vec![ret_statement], TerminatorKind::Return, false);
-        }
-        _ => {
-            bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty);
+            );
+
+            // BB #(2i + 1) (cleanup)
+            if i == 0 {
+                // Nothing to drop, just resume.
+                self.block(vec![], TerminatorKind::Resume, true);
+            } else {
+                // Drop previous field and goto previous cleanup block.
+                self.block(vec![], TerminatorKind::Drop {
+                    location: returns[i - 1].clone(),
+                    target: BasicBlock::new(2 * i - 1),
+                    unwind: None,
+                }, true);
+            }
         }
-    };
 
-    let mir = Mir::new(
-        blocks,
-        IndexVec::from_elem_n(
-            VisibilityScopeData { span: span, parent_scope: None }, 1
-        ),
-        IndexVec::new(),
-        sig.output(),
-        local_decls,
-        sig.inputs().len(),
-        vec![],
-        span
-    );
-    mir
+        // `return (returns[0], returns[1], ..., returns[tys.len() - 1]);`
+        let ret_statement = self.make_statement(
+            StatementKind::Assign(
+                Lvalue::Local(RETURN_POINTER),
+                Rvalue::Aggregate(
+                    box AggregateKind::Tuple,
+                    returns.into_iter().map(Operand::Consume).collect()
+                )
+            )
+        );
+       self.block(vec![ret_statement], TerminatorKind::Return, false);
+    }
 }
 
 /// Build a "call" shim for `def_id`. The shim calls the
diff --git a/src/test/run-pass/builtin-clone-unwind.rs b/src/test/run-pass/builtin-clone-unwind.rs
index 2829f79812c..90a41135286 100644
--- a/src/test/run-pass/builtin-clone-unwind.rs
+++ b/src/test/run-pass/builtin-clone-unwind.rs
@@ -12,13 +12,13 @@
 // in case of unwinding.
 
 use std::thread;
-use std::sync::Arc;
+use std::rc::Rc;
 
-struct S(Arc<()>);
+struct S(Rc<()>);
 
 impl Clone for S {
     fn clone(&self) -> Self {
-        if Arc::strong_count(&self.0) == 7 {
+        if Rc::strong_count(&self.0) == 7 {
             panic!("oops");
         }
 
@@ -27,11 +27,11 @@ impl Clone for S {
 }
 
 fn main() {
-    let counter = Arc::new(());
+    let counter = Rc::new(());
 
     // Unwinding with tuples...
     let ccounter = counter.clone();
-    let child = thread::spawn(move || {
+    let result = std::panic::catch_unwind(move || {
         let _ = (
             S(ccounter.clone()),
             S(ccounter.clone()),
@@ -40,15 +40,15 @@ fn main() {
         ).clone();
     });
 
-    assert!(child.join().is_err());
+    assert!(result.is_err());
     assert_eq!(
         1,
-        Arc::strong_count(&counter)
+        Rc::strong_count(&counter)
     );
 
     // ... and with arrays.
     let ccounter = counter.clone();
-    let child = thread::spawn(move || {
+    let child = std::panic::catch_unwind(move || {
         let _ = [
             S(ccounter.clone()),
             S(ccounter.clone()),
@@ -57,9 +57,9 @@ fn main() {
         ].clone();
     });
 
-    assert!(child.join().is_err());
+    assert!(result.is_err());
     assert_eq!(
         1,
-        Arc::strong_count(&counter)
+        Rc::strong_count(&counter)
     );
 }