Skip to content

Commit d608229

Browse files
committed
Auto merge of #86041 - bstrie:unmagic-array-copy, r=jackh726
Replace Copy/Clone compiler magic on arrays with library impls With const generics the compiler no longer needs to fake these impls.
2 parents 07acdb4 + 61b1394 commit d608229

File tree

12 files changed

+35
-195
lines changed

12 files changed

+35
-195
lines changed

compiler/rustc_error_codes/src/error_codes/E0206.md

+3-6
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,12 @@ enum.
44
Erroneous code example:
55

66
```compile_fail,E0206
7-
type Foo = [u8; 256];
8-
impl Copy for Foo { } // error!
9-
107
#[derive(Copy, Clone)]
118
struct Bar;
129
1310
impl Copy for &'static mut Bar { } // error!
1411
```
1512

16-
You can only implement `Copy` for a struct or an enum. Both of the previous
17-
examples will fail, because neither `[u8; 256]` nor `&'static mut Bar`
18-
(mutable reference to `Bar`) is a struct or enum.
13+
You can only implement `Copy` for a struct or an enum.
14+
The previous example will fail because `&'static mut Bar`
15+
is not a struct or enum.

compiler/rustc_mir_transform/src/shim.rs

-149
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,6 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -
310310

311311
match self_ty.kind() {
312312
_ if is_copy => builder.copy_shim(),
313-
ty::Array(ty, len) => builder.array_shim(dest, src, ty, len),
314313
ty::Closure(_, substs) => {
315314
builder.tuple_like_shim(dest, src, substs.as_closure().upvar_tys())
316315
}
@@ -459,154 +458,6 @@ impl CloneShimBuilder<'tcx> {
459458
);
460459
}
461460

462-
fn loop_header(
463-
&mut self,
464-
beg: Place<'tcx>,
465-
end: Place<'tcx>,
466-
loop_body: BasicBlock,
467-
loop_end: BasicBlock,
468-
is_cleanup: bool,
469-
) {
470-
let tcx = self.tcx;
471-
472-
let cond = self.make_place(Mutability::Mut, tcx.types.bool);
473-
let compute_cond = self.make_statement(StatementKind::Assign(Box::new((
474-
cond,
475-
Rvalue::BinaryOp(BinOp::Ne, Box::new((Operand::Copy(end), Operand::Copy(beg)))),
476-
))));
477-
478-
// `if end != beg { goto loop_body; } else { goto loop_end; }`
479-
self.block(
480-
vec![compute_cond],
481-
TerminatorKind::if_(tcx, Operand::Move(cond), loop_body, loop_end),
482-
is_cleanup,
483-
);
484-
}
485-
486-
fn make_usize(&self, value: u64) -> Box<Constant<'tcx>> {
487-
Box::new(Constant {
488-
span: self.span,
489-
user_ty: None,
490-
literal: ty::Const::from_usize(self.tcx, value).into(),
491-
})
492-
}
493-
494-
fn array_shim(
495-
&mut self,
496-
dest: Place<'tcx>,
497-
src: Place<'tcx>,
498-
ty: Ty<'tcx>,
499-
len: &'tcx ty::Const<'tcx>,
500-
) {
501-
let tcx = self.tcx;
502-
let span = self.span;
503-
504-
let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span));
505-
let end = self.make_place(Mutability::Not, tcx.types.usize);
506-
507-
// BB #0
508-
// `let mut beg = 0;`
509-
// `let end = len;`
510-
// `goto #1;`
511-
let inits = vec![
512-
self.make_statement(StatementKind::Assign(Box::new((
513-
Place::from(beg),
514-
Rvalue::Use(Operand::Constant(self.make_usize(0))),
515-
)))),
516-
self.make_statement(StatementKind::Assign(Box::new((
517-
end,
518-
Rvalue::Use(Operand::Constant(Box::new(Constant {
519-
span: self.span,
520-
user_ty: None,
521-
literal: len.into(),
522-
}))),
523-
)))),
524-
];
525-
self.block(inits, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
526-
527-
// BB #1: loop {
528-
// BB #2;
529-
// BB #3;
530-
// }
531-
// BB #4;
532-
self.loop_header(Place::from(beg), end, BasicBlock::new(2), BasicBlock::new(4), false);
533-
534-
// BB #2
535-
// `dest[i] = Clone::clone(src[beg])`;
536-
// Goto #3 if ok, #5 if unwinding happens.
537-
let dest_field = self.tcx.mk_place_index(dest, beg);
538-
let src_field = self.tcx.mk_place_index(src, beg);
539-
self.make_clone_call(dest_field, src_field, ty, BasicBlock::new(3), BasicBlock::new(5));
540-
541-
// BB #3
542-
// `beg = beg + 1;`
543-
// `goto #1`;
544-
let statements = vec![self.make_statement(StatementKind::Assign(Box::new((
545-
Place::from(beg),
546-
Rvalue::BinaryOp(
547-
BinOp::Add,
548-
Box::new((Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1)))),
549-
),
550-
))))];
551-
self.block(statements, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
552-
553-
// BB #4
554-
// `return dest;`
555-
self.block(vec![], TerminatorKind::Return, false);
556-
557-
// BB #5 (cleanup)
558-
// `let end = beg;`
559-
// `let mut beg = 0;`
560-
// goto #6;
561-
let end = beg;
562-
let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span));
563-
let init = self.make_statement(StatementKind::Assign(Box::new((
564-
Place::from(beg),
565-
Rvalue::Use(Operand::Constant(self.make_usize(0))),
566-
))));
567-
self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
568-
569-
// BB #6 (cleanup): loop {
570-
// BB #7;
571-
// BB #8;
572-
// }
573-
// BB #9;
574-
self.loop_header(
575-
Place::from(beg),
576-
Place::from(end),
577-
BasicBlock::new(7),
578-
BasicBlock::new(9),
579-
true,
580-
);
581-
582-
// BB #7 (cleanup)
583-
// `drop(dest[beg])`;
584-
self.block(
585-
vec![],
586-
TerminatorKind::Drop {
587-
place: self.tcx.mk_place_index(dest, beg),
588-
target: BasicBlock::new(8),
589-
unwind: None,
590-
},
591-
true,
592-
);
593-
594-
// BB #8 (cleanup)
595-
// `beg = beg + 1;`
596-
// `goto #6;`
597-
let statement = self.make_statement(StatementKind::Assign(Box::new((
598-
Place::from(beg),
599-
Rvalue::BinaryOp(
600-
BinOp::Add,
601-
Box::new((Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1)))),
602-
),
603-
))));
604-
self.block(vec![statement], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
605-
606-
// BB #9 (resume)
607-
self.block(vec![], TerminatorKind::Resume, true);
608-
}
609-
610461
fn tuple_like_shim<I>(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I)
611462
where
612463
I: Iterator<Item = Ty<'tcx>>,

compiler/rustc_trait_selection/src/traits/misc.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ pub fn can_type_implement_copy(
3333
| ty::Char
3434
| ty::RawPtr(..)
3535
| ty::Never
36-
| ty::Ref(_, _, hir::Mutability::Not) => return Ok(()),
36+
| ty::Ref(_, _, hir::Mutability::Not)
37+
| ty::Array(..) => return Ok(()),
3738

3839
ty::Adt(adt, substs) => (adt, substs),
3940

compiler/rustc_trait_selection/src/traits/select/mod.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -1859,7 +1859,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
18591859
| ty::Char
18601860
| ty::RawPtr(..)
18611861
| ty::Never
1862-
| ty::Ref(_, _, hir::Mutability::Not) => {
1862+
| ty::Ref(_, _, hir::Mutability::Not)
1863+
| ty::Array(..) => {
18631864
// Implementations provided in libcore
18641865
None
18651866
}
@@ -1872,11 +1873,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
18721873
| ty::Foreign(..)
18731874
| ty::Ref(_, _, hir::Mutability::Mut) => None,
18741875

1875-
ty::Array(element_ty, _) => {
1876-
// (*) binder moved here
1877-
Where(obligation.predicate.rebind(vec![element_ty]))
1878-
}
1879-
18801876
ty::Tuple(tys) => {
18811877
// (*) binder moved here
18821878
Where(obligation.predicate.rebind(tys.iter().map(|k| k.expect_ty()).collect()))

compiler/rustc_ty_utils/src/instance.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ fn resolve_associated_item<'tcx>(
362362
let is_copy = self_ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env);
363363
match self_ty.kind() {
364364
_ if is_copy => (),
365-
ty::Array(..) | ty::Closure(..) | ty::Tuple(..) => {}
365+
ty::Closure(..) | ty::Tuple(..) => {}
366366
_ => return Ok(None),
367367
};
368368

library/core/src/array/mod.rs

+20
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,26 @@ impl<T: Ord, const N: usize> Ord for [T; N] {
330330
}
331331
}
332332

333+
#[cfg(not(bootstrap))]
334+
#[stable(feature = "copy_clone_array_lib", since = "1.58.0")]
335+
impl<T: Copy, const N: usize> Copy for [T; N] {}
336+
337+
#[cfg(not(bootstrap))]
338+
#[stable(feature = "copy_clone_array_lib", since = "1.58.0")]
339+
impl<T: Clone, const N: usize> Clone for [T; N] {
340+
#[inline]
341+
fn clone(&self) -> Self {
342+
// SAFETY: we know for certain that this iterator will yield exactly `N`
343+
// items.
344+
unsafe { collect_into_array_unchecked(&mut self.iter().cloned()) }
345+
}
346+
347+
#[inline]
348+
fn clone_from(&mut self, other: &Self) {
349+
self.clone_from_slice(other);
350+
}
351+
}
352+
333353
// The Default impls cannot be done with const generics because `[T; 0]` doesn't
334354
// require Default to be implemented, and having different impl blocks for
335355
// different numbers isn't supported yet.

library/core/src/clone.rs

-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@
9393
///
9494
/// * Function item types (i.e., the distinct types defined for each function)
9595
/// * Function pointer types (e.g., `fn() -> i32`)
96-
/// * Array types, for all sizes, if the item type also implements `Clone` (e.g., `[i32; 123456]`)
9796
/// * Tuple types, if each component also implements `Clone` (e.g., `()`, `(i32, bool)`)
9897
/// * Closure types, if they capture no value from the environment
9998
/// or if all such captured values implement `Clone` themselves.

library/core/src/marker.rs

-1
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,6 @@ pub trait StructuralEq {
359359
///
360360
/// * Function item types (i.e., the distinct types defined for each function)
361361
/// * Function pointer types (e.g., `fn() -> i32`)
362-
/// * Array types, for all sizes, if the item type also implements `Copy` (e.g., `[i32; 123456]`)
363362
/// * Tuple types, if each component also implements `Copy` (e.g., `()`, `(i32, bool)`)
364363
/// * Closure types, if they capture no value from the environment
365364
/// or if all such captured values implement `Copy` themselves.

src/test/ui/builtin-clone-unwind.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ fn main() {
5353
].clone();
5454
});
5555

56-
assert!(result.is_err());
56+
assert!(child.is_err());
5757
assert_eq!(
5858
1,
5959
Rc::strong_count(&counter)

src/test/ui/chalkify/builtin-copy-clone.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@ fn test_copy_clone<T: Copy + Clone>(arg: T) {
2323
fn foo() { }
2424

2525
fn main() {
26+
// FIXME: add closures when they're considered WF
2627
test_copy_clone(foo);
2728
let f: fn() = foo;
2829
test_copy_clone(f);
29-
// FIXME: add closures when they're considered WF
30-
test_copy_clone([1; 56]);
30+
// FIXME(#86252): reinstate array test after chalk upgrade
31+
//test_copy_clone([1; 56]);
3132
test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1));
3233
test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, true, 'a', 1.1));
3334
test_copy_clone(());

src/test/ui/error-codes/E0206.rs

-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
type Foo = [u8; 256];
2-
3-
impl Copy for Foo { }
4-
//~^ ERROR the trait `Copy` may not be implemented for this type
5-
//~| ERROR only traits defined in the current crate can be implemented for arbitrary types
6-
71
#[derive(Copy, Clone)]
82
struct Bar;
93

src/test/ui/error-codes/E0206.stderr

+3-21
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,9 @@
11
error[E0206]: the trait `Copy` may not be implemented for this type
2-
--> $DIR/E0206.rs:3:15
3-
|
4-
LL | impl Copy for Foo { }
5-
| ^^^ type is not a structure or enumeration
6-
7-
error[E0206]: the trait `Copy` may not be implemented for this type
8-
--> $DIR/E0206.rs:10:15
2+
--> $DIR/E0206.rs:4:15
93
|
104
LL | impl Copy for &'static mut Bar { }
115
| ^^^^^^^^^^^^^^^^ type is not a structure or enumeration
126

13-
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
14-
--> $DIR/E0206.rs:3:1
15-
|
16-
LL | impl Copy for Foo { }
17-
| ^^^^^^^^^^^^^^---
18-
| | |
19-
| | this is not defined in the current crate because arrays are always foreign
20-
| impl doesn't use only types from inside the current crate
21-
|
22-
= note: define and implement a trait or new type instead
23-
24-
error: aborting due to 3 previous errors
7+
error: aborting due to previous error
258

26-
Some errors have detailed explanations: E0117, E0206.
27-
For more information about an error, try `rustc --explain E0117`.
9+
For more information about this error, try `rustc --explain E0206`.

0 commit comments

Comments
 (0)