Skip to content

Commit 224ff38

Browse files
authored
Rollup merge of #148807 - nnethercote:doc-Copy-Clone-problem, r=saethlin
Document (and test) a problem with `Clone`/`Copy` deriving. I think this is useful information. I have worked on `derive` impls quite a bit and didn't know about this issue until today. r? `@saethlin`
2 parents b30c004 + c6dbda8 commit 224ff38

File tree

3 files changed

+98
-15
lines changed

3 files changed

+98
-15
lines changed

compiler/rustc_resolve/src/macros.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
384384
// is applied, so they have to be produced by the container's expansion rather
385385
// than by individual derives.
386386
// - Derives in the container need to know whether one of them is a built-in `Copy`.
387+
// (But see the comment mentioning #124794 below.)
387388
// Temporarily take the data to avoid borrow checker conflicts.
388389
let mut derive_data = mem::take(&mut self.derive_data);
389390
let entry = derive_data.entry(expn_id).or_insert_with(|| DeriveData {
@@ -440,7 +441,13 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
440441
.collect();
441442
self.helper_attrs.insert(expn_id, helper_attrs);
442443
// Mark this derive as having `Copy` either if it has `Copy` itself or if its parent derive
443-
// has `Copy`, to support cases like `#[derive(Clone, Copy)] #[derive(Debug)]`.
444+
// has `Copy`, to support `#[derive(Copy, Clone)]`, `#[derive(Clone, Copy)]`, or
445+
// `#[derive(Copy)] #[derive(Clone)]`. We do this because the code generated for
446+
// `derive(Clone)` changes if `derive(Copy)` is also present.
447+
//
448+
// FIXME(#124794): unfortunately this doesn't work with `#[derive(Clone)] #[derive(Copy)]`.
449+
// When the `Clone` impl is generated the `#[derive(Copy)]` hasn't been processed and
450+
// `has_derive_copy` hasn't been set yet.
444451
if entry.has_derive_copy || self.has_derive_copy(parent_scope.expansion) {
445452
self.containers_deriving_copy.insert(expn_id);
446453
}

tests/ui/deriving/deriving-all-codegen.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ use std::from::From;
2424
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
2525
struct Empty;
2626

27-
// A basic struct. Note: because this derives `Copy`, it gets the simple
27+
// A basic struct. Note: because this derives `Copy`, it gets the trivial
2828
// `clone` implemention that just does `*self`.
2929
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
3030
struct Point {
3131
x: u32,
3232
y: u32,
3333
}
3434

35-
// A basic packed struct. Note: because this derives `Copy`, it gets the simple
35+
// A basic packed struct. Note: because this derives `Copy`, it gets the trivial
3636
// `clone` implemention that just does `*self`.
3737
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
3838
#[repr(packed)]
@@ -49,7 +49,7 @@ struct SingleField {
4949
foo: bool,
5050
}
5151

52-
// A large struct. Note: because this derives `Copy`, it gets the simple
52+
// A large struct. Note: because this derives `Copy`, it gets the trivial
5353
// `clone` implemention that just does `*self`.
5454
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
5555
struct Big {
@@ -79,25 +79,25 @@ struct Reorder {
7979
b10: &'static *const bool,
8080
}
8181

82-
// A struct that doesn't impl `Copy`, which means it gets the non-simple
82+
// A struct that doesn't impl `Copy`, which means it gets the non-trivial
8383
// `clone` implemention that clones the fields individually.
8484
#[derive(Clone)]
8585
struct NonCopy(u32);
8686

87-
// A packed struct that doesn't impl `Copy`, which means it gets the non-simple
87+
// A packed struct that doesn't impl `Copy`, which means it gets the non-trivial
8888
// `clone` implemention that clones the fields individually.
8989
#[derive(Clone)]
9090
#[repr(packed)]
9191
struct PackedNonCopy(u32);
9292

93-
// A struct that impls `Copy` manually, which means it gets the non-simple
93+
// A struct that impls `Copy` manually, which means it gets the non-trivial
9494
// `clone` implemention that clones the fields individually.
9595
#[derive(Clone)]
9696
struct ManualCopy(u32);
9797
impl Copy for ManualCopy {}
9898

9999
// A packed struct that impls `Copy` manually, which means it gets the
100-
// non-simple `clone` implemention that clones the fields individually.
100+
// non-trivial `clone` implemention that clones the fields individually.
101101
#[derive(Clone)]
102102
#[repr(packed)]
103103
struct PackedManualCopy(u32);
@@ -218,3 +218,20 @@ pub union Union {
218218
pub u: u32,
219219
pub i: i32,
220220
}
221+
222+
#[derive(Copy, Clone)]
223+
struct FooCopyClone(i32);
224+
225+
#[derive(Clone, Copy)]
226+
struct FooCloneCopy(i32);
227+
228+
#[derive(Copy)]
229+
#[derive(Clone)]
230+
struct FooCopyAndClone(i32);
231+
232+
// FIXME(#124794): the previous three structs all have a trivial `Copy`-aware
233+
// `clone`. But this one doesn't because when the `clone` is generated the
234+
// `derive(Copy)` hasn't yet been seen.
235+
#[derive(Clone)]
236+
#[derive(Copy)]
237+
struct FooCloneAndCopy(i32);

tests/ui/deriving/deriving-all-codegen.stdout

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ impl ::core::cmp::Ord for Empty {
8484
}
8585
}
8686

87-
// A basic struct. Note: because this derives `Copy`, it gets the simple
87+
// A basic struct. Note: because this derives `Copy`, it gets the trivial
8888
// `clone` implemention that just does `*self`.
8989
struct Point {
9090
x: u32,
@@ -171,7 +171,7 @@ impl ::core::cmp::Ord for Point {
171171
}
172172
}
173173

174-
// A basic packed struct. Note: because this derives `Copy`, it gets the simple
174+
// A basic packed struct. Note: because this derives `Copy`, it gets the trivial
175175
// `clone` implemention that just does `*self`.
176176
#[repr(packed)]
177177
struct PackedPoint {
@@ -409,7 +409,7 @@ impl ::core::cmp::Ord for SingleField {
409409
}
410410
}
411411

412-
// A large struct. Note: because this derives `Copy`, it gets the simple
412+
// A large struct. Note: because this derives `Copy`, it gets the trivial
413413
// `clone` implemention that just does `*self`.
414414
struct Big {
415415
b1: u32,
@@ -676,7 +676,7 @@ impl ::core::cmp::PartialOrd for Reorder {
676676
}
677677
}
678678

679-
// A struct that doesn't impl `Copy`, which means it gets the non-simple
679+
// A struct that doesn't impl `Copy`, which means it gets the non-trivial
680680
// `clone` implemention that clones the fields individually.
681681
struct NonCopy(u32);
682682
#[automatically_derived]
@@ -687,7 +687,7 @@ impl ::core::clone::Clone for NonCopy {
687687
}
688688
}
689689

690-
// A packed struct that doesn't impl `Copy`, which means it gets the non-simple
690+
// A packed struct that doesn't impl `Copy`, which means it gets the non-trivial
691691
// `clone` implemention that clones the fields individually.
692692
#[repr(packed)]
693693
struct PackedNonCopy(u32);
@@ -699,7 +699,7 @@ impl ::core::clone::Clone for PackedNonCopy {
699699
}
700700
}
701701

702-
// A struct that impls `Copy` manually, which means it gets the non-simple
702+
// A struct that impls `Copy` manually, which means it gets the non-trivial
703703
// `clone` implemention that clones the fields individually.
704704
struct ManualCopy(u32);
705705
#[automatically_derived]
@@ -712,7 +712,7 @@ impl ::core::clone::Clone for ManualCopy {
712712
impl Copy for ManualCopy {}
713713

714714
// A packed struct that impls `Copy` manually, which means it gets the
715-
// non-simple `clone` implemention that clones the fields individually.
715+
// non-trivial `clone` implemention that clones the fields individually.
716716
#[repr(packed)]
717717
struct PackedManualCopy(u32);
718718
#[automatically_derived]
@@ -1791,3 +1791,62 @@ impl ::core::clone::Clone for Union {
17911791
}
17921792
#[automatically_derived]
17931793
impl ::core::marker::Copy for Union { }
1794+
1795+
struct FooCopyClone(i32);
1796+
#[automatically_derived]
1797+
impl ::core::marker::Copy for FooCopyClone { }
1798+
#[automatically_derived]
1799+
#[doc(hidden)]
1800+
unsafe impl ::core::clone::TrivialClone for FooCopyClone { }
1801+
#[automatically_derived]
1802+
impl ::core::clone::Clone for FooCopyClone {
1803+
#[inline]
1804+
fn clone(&self) -> FooCopyClone {
1805+
let _: ::core::clone::AssertParamIsClone<i32>;
1806+
*self
1807+
}
1808+
}
1809+
1810+
struct FooCloneCopy(i32);
1811+
#[automatically_derived]
1812+
#[doc(hidden)]
1813+
unsafe impl ::core::clone::TrivialClone for FooCloneCopy { }
1814+
#[automatically_derived]
1815+
impl ::core::clone::Clone for FooCloneCopy {
1816+
#[inline]
1817+
fn clone(&self) -> FooCloneCopy {
1818+
let _: ::core::clone::AssertParamIsClone<i32>;
1819+
*self
1820+
}
1821+
}
1822+
#[automatically_derived]
1823+
impl ::core::marker::Copy for FooCloneCopy { }
1824+
1825+
struct FooCopyAndClone(i32);
1826+
#[automatically_derived]
1827+
#[doc(hidden)]
1828+
unsafe impl ::core::clone::TrivialClone for FooCopyAndClone { }
1829+
#[automatically_derived]
1830+
impl ::core::clone::Clone for FooCopyAndClone {
1831+
#[inline]
1832+
fn clone(&self) -> FooCopyAndClone {
1833+
let _: ::core::clone::AssertParamIsClone<i32>;
1834+
*self
1835+
}
1836+
}
1837+
#[automatically_derived]
1838+
impl ::core::marker::Copy for FooCopyAndClone { }
1839+
1840+
// FIXME(#124794): the previous three structs all have a trivial `Copy`-aware
1841+
// `clone`. But this one doesn't because when the `clone` is generated the
1842+
// `derive(Copy)` hasn't yet been seen.
1843+
struct FooCloneAndCopy(i32);
1844+
#[automatically_derived]
1845+
impl ::core::marker::Copy for FooCloneAndCopy { }
1846+
#[automatically_derived]
1847+
impl ::core::clone::Clone for FooCloneAndCopy {
1848+
#[inline]
1849+
fn clone(&self) -> FooCloneAndCopy {
1850+
FooCloneAndCopy(::core::clone::Clone::clone(&self.0))
1851+
}
1852+
}

0 commit comments

Comments
 (0)