Skip to content

Commit 3068dcc

Browse files
committed
Mark derived Clone impls as const
1 parent a00e130 commit 3068dcc

File tree

17 files changed

+163
-42
lines changed

17 files changed

+163
-42
lines changed

compiler/rustc_builtin_macros/src/deriving/bounds.rs

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub fn expand_deriving_copy(
2020
additional_bounds: Vec::new(),
2121
generics: Bounds::empty(),
2222
is_unsafe: false,
23+
is_const: false,
2324
supports_unions: true,
2425
methods: Vec::new(),
2526
associated_types: Vec::new(),

compiler/rustc_builtin_macros/src/deriving/clone.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub fn expand_deriving_clone(
1515
item: &Annotatable,
1616
push: &mut dyn FnMut(Annotatable),
1717
) {
18-
// check if we can use a short form
18+
// check if we can use a short form, and if the impl can be const
1919
//
2020
// the short form is `fn clone(&self) -> Self { *self }`
2121
//
@@ -29,6 +29,9 @@ pub fn expand_deriving_clone(
2929
// Unions with generic parameters still can derive Clone because they require Copy
3030
// for deriving, Clone alone is not enough.
3131
// Whever Clone is implemented for fields is irrelevant so we don't assert it.
32+
//
33+
// for now, the impl is only able to be marked as const if we can use the short form;
34+
// in the future, this may be expanded
3235
let bounds;
3336
let substructure;
3437
let is_shallow;
@@ -73,15 +76,29 @@ pub fn expand_deriving_clone(
7376
_ => cx.span_bug(span, "`#[derive(Clone)]` on trait item or impl item"),
7477
}
7578

79+
let features = cx.sess.features_untracked();
7680
let inline = cx.meta_word(span, sym::inline);
7781
let attrs = vec![cx.attribute(inline)];
82+
let is_const = is_shallow && features.const_trait_impl;
7883
let trait_def = TraitDef {
7984
span,
80-
attributes: Vec::new(),
85+
attributes: if is_const && features.staged_api {
86+
vec![cx.attribute(cx.meta_list(
87+
span,
88+
sym::rustc_const_unstable,
89+
vec![
90+
cx.meta_name_value(span, sym::feature, Symbol::intern("const_clone")),
91+
cx.meta_name_value(span, sym::issue, Symbol::intern("none")),
92+
],
93+
))]
94+
} else {
95+
Vec::new()
96+
},
8197
path: path_std!(clone::Clone),
8298
additional_bounds: bounds,
8399
generics: Bounds::empty(),
84100
is_unsafe: false,
101+
is_const,
85102
supports_unions: true,
86103
methods: vec![MethodDef {
87104
name: sym::clone,

compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub fn expand_deriving_eq(
2828
additional_bounds: Vec::new(),
2929
generics: Bounds::empty(),
3030
is_unsafe: false,
31+
is_const: false,
3132
supports_unions: true,
3233
methods: vec![MethodDef {
3334
name: sym::assert_receiver_is_total_eq,

compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub fn expand_deriving_ord(
2424
additional_bounds: Vec::new(),
2525
generics: Bounds::empty(),
2626
is_unsafe: false,
27+
is_const: false,
2728
supports_unions: false,
2829
methods: vec![MethodDef {
2930
name: sym::cmp,

compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs

+1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ pub fn expand_deriving_partial_eq(
104104
additional_bounds: Vec::new(),
105105
generics: Bounds::empty(),
106106
is_unsafe: false,
107+
is_const: false,
107108
supports_unions: false,
108109
methods,
109110
associated_types: Vec::new(),

compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ pub fn expand_deriving_partial_ord(
4747
additional_bounds: vec![],
4848
generics: Bounds::empty(),
4949
is_unsafe: false,
50+
is_const: false,
5051
supports_unions: false,
5152
methods: vec![partial_cmp_def],
5253
associated_types: Vec::new(),

compiler/rustc_builtin_macros/src/deriving/debug.rs

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub fn expand_deriving_debug(
3030
additional_bounds: Vec::new(),
3131
generics: Bounds::empty(),
3232
is_unsafe: false,
33+
is_const: false,
3334
supports_unions: false,
3435
methods: vec![MethodDef {
3536
name: sym::fmt,

compiler/rustc_builtin_macros/src/deriving/decodable.rs

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub fn expand_deriving_rustc_decodable(
2727
additional_bounds: Vec::new(),
2828
generics: Bounds::empty(),
2929
is_unsafe: false,
30+
is_const: false,
3031
supports_unions: false,
3132
methods: vec![MethodDef {
3233
name: sym::decode,

compiler/rustc_builtin_macros/src/deriving/default.rs

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub fn expand_deriving_default(
3131
additional_bounds: Vec::new(),
3232
generics: Bounds::empty(),
3333
is_unsafe: false,
34+
is_const: false,
3435
supports_unions: false,
3536
methods: vec![MethodDef {
3637
name: kw::Default,

compiler/rustc_builtin_macros/src/deriving/encodable.rs

+1
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ pub fn expand_deriving_rustc_encodable(
112112
additional_bounds: Vec::new(),
113113
generics: Bounds::empty(),
114114
is_unsafe: false,
115+
is_const: false,
115116
supports_unions: false,
116117
methods: vec![MethodDef {
117118
name: sym::encode,

compiler/rustc_builtin_macros/src/deriving/generic/mod.rs

+42-7
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,9 @@ pub struct TraitDef<'a> {
215215
/// Is it an `unsafe` trait?
216216
pub is_unsafe: bool,
217217

218+
/// Is it a `const` impl?
219+
pub is_const: bool,
220+
218221
/// Can this trait be derived for unions?
219222
pub supports_unions: bool,
220223

@@ -568,7 +571,7 @@ impl<'a> TraitDef<'a> {
568571
});
569572

570573
let Generics { mut params, mut where_clause, .. } =
571-
self.generics.to_generics(cx, self.span, type_ident, generics);
574+
self.generics.to_generics(cx, self.span, type_ident, generics, self.is_const);
572575
where_clause.span = generics.where_clause.span;
573576
let ctxt = self.span.ctxt();
574577
let span = generics.span.with_ctxt(ctxt);
@@ -583,10 +586,24 @@ impl<'a> TraitDef<'a> {
583586
// extra restrictions on the generics parameters to the
584587
// type being derived upon
585588
self.additional_bounds.iter().map(|p| {
586-
cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))
589+
cx.trait_bound(
590+
p.to_path(cx, self.span, type_ident, generics),
591+
if self.is_const {
592+
ast::TraitBoundModifier::MaybeConst
593+
} else {
594+
ast::TraitBoundModifier::None
595+
},
596+
)
587597
}).chain(
588598
// require the current trait
589-
iter::once(cx.trait_bound(trait_path.clone()))
599+
iter::once(cx.trait_bound(
600+
trait_path.clone(),
601+
if self.is_const {
602+
ast::TraitBoundModifier::MaybeConst
603+
} else {
604+
ast::TraitBoundModifier::None
605+
}
606+
))
590607
).chain(
591608
// also add in any bounds from the declaration
592609
param.bounds.iter().cloned()
@@ -663,11 +680,27 @@ impl<'a> TraitDef<'a> {
663680
let mut bounds: Vec<_> = self
664681
.additional_bounds
665682
.iter()
666-
.map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
683+
.map(|p| {
684+
cx.trait_bound(
685+
p.to_path(cx, self.span, type_ident, generics),
686+
if self.is_const {
687+
ast::TraitBoundModifier::MaybeConst
688+
} else {
689+
ast::TraitBoundModifier::None
690+
},
691+
)
692+
})
667693
.collect();
668694

669695
// require the current trait
670-
bounds.push(cx.trait_bound(trait_path.clone()));
696+
bounds.push(cx.trait_bound(
697+
trait_path.clone(),
698+
if self.is_const {
699+
ast::TraitBoundModifier::MaybeConst
700+
} else {
701+
ast::TraitBoundModifier::None
702+
},
703+
));
671704

672705
let predicate = ast::WhereBoundPredicate {
673706
span: self.span,
@@ -723,6 +756,7 @@ impl<'a> TraitDef<'a> {
723756
a.extend(self.attributes.iter().cloned());
724757

725758
let unsafety = if self.is_unsafe { ast::Unsafe::Yes(self.span) } else { ast::Unsafe::No };
759+
let constness = if self.is_const { ast::Const::Yes(self.span) } else { ast::Const::No };
726760

727761
cx.item(
728762
self.span,
@@ -732,7 +766,7 @@ impl<'a> TraitDef<'a> {
732766
unsafety,
733767
polarity: ast::ImplPolarity::Positive,
734768
defaultness: ast::Defaultness::Final,
735-
constness: ast::Const::No,
769+
constness,
736770
generics: trait_generics,
737771
of_trait: opt_trait_ref,
738772
self_ty: self_type,
@@ -933,7 +967,8 @@ impl<'a> MethodDef<'a> {
933967
) -> P<ast::AssocItem> {
934968
let span = trait_.span;
935969
// Create the generics that aren't for `Self`.
936-
let fn_generics = self.generics.to_generics(cx, span, type_ident, generics);
970+
let fn_generics =
971+
self.generics.to_generics(cx, span, type_ident, generics, trait_.is_const);
937972

938973
let args = {
939974
let self_args = explicit_self.map(|explicit_self| {

compiler/rustc_builtin_macros/src/deriving/generic/ty.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -200,12 +200,20 @@ fn mk_ty_param(
200200
bounds: &[Path],
201201
self_ident: Ident,
202202
self_generics: &Generics,
203+
is_const: bool,
203204
) -> ast::GenericParam {
204205
let bounds = bounds
205206
.iter()
206-
.map(|b| {
207-
let path = b.to_path(cx, span, self_ident, self_generics);
208-
cx.trait_bound(path)
207+
.map(|path| {
208+
let path = path.to_path(cx, span, self_ident, self_generics);
209+
cx.trait_bound(
210+
path,
211+
if is_const {
212+
ast::TraitBoundModifier::MaybeConst
213+
} else {
214+
ast::TraitBoundModifier::None
215+
},
216+
)
209217
})
210218
.collect();
211219
cx.typaram(span, Ident::new(name, span), attrs.to_owned(), bounds, None)
@@ -227,13 +235,14 @@ impl Bounds {
227235
span: Span,
228236
self_ty: Ident,
229237
self_generics: &Generics,
238+
is_const: bool,
230239
) -> Generics {
231240
let params = self
232241
.bounds
233242
.iter()
234243
.map(|t| {
235244
let (name, ref bounds) = *t;
236-
mk_ty_param(cx, span, name, &[], &bounds, self_ty, self_generics)
245+
mk_ty_param(cx, span, name, &[], &bounds, self_ty, self_generics, is_const)
237246
})
238247
.collect();
239248

compiler/rustc_builtin_macros/src/deriving/hash.rs

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub fn expand_deriving_hash(
2727
additional_bounds: Vec::new(),
2828
generics: Bounds::empty(),
2929
is_unsafe: false,
30+
is_const: false,
3031
supports_unions: false,
3132
methods: vec![MethodDef {
3233
name: sym::hash,

compiler/rustc_expand/src/build.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,12 @@ impl<'a> ExtCtxt<'a> {
128128
}
129129
}
130130

131-
pub fn trait_bound(&self, path: ast::Path) -> ast::GenericBound {
132-
ast::GenericBound::Trait(
133-
self.poly_trait_ref(path.span, path),
134-
ast::TraitBoundModifier::None,
135-
)
131+
pub fn trait_bound(
132+
&self,
133+
path: ast::Path,
134+
modif: ast::TraitBoundModifier,
135+
) -> ast::GenericBound {
136+
ast::GenericBound::Trait(self.poly_trait_ref(path.span, path), modif)
136137
}
137138

138139
pub fn lifetime(&self, span: Span, ident: Ident) -> ast::Lifetime {
@@ -567,4 +568,12 @@ impl<'a> ExtCtxt<'a> {
567568
pub fn meta_word(&self, sp: Span, w: Symbol) -> ast::MetaItem {
568569
attr::mk_word_item(Ident::new(w, sp))
569570
}
571+
572+
pub fn meta_name_value(&self, sp: Span, n: Symbol, v: Symbol) -> ast::NestedMetaItem {
573+
ast::NestedMetaItem::MetaItem(attr::mk_name_value_item_str(Ident::new(n, sp), v, sp))
574+
}
575+
576+
pub fn meta_list(&self, sp: Span, w: Symbol, items: Vec<ast::NestedMetaItem>) -> ast::MetaItem {
577+
attr::mk_list_item(Ident::new(w, sp), items)
578+
}
570579
}

library/core/src/clone.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,11 @@ pub trait Clone: Sized {
127127
/// allocations.
128128
#[inline]
129129
#[stable(feature = "rust1", since = "1.0.0")]
130-
fn clone_from(&mut self, source: &Self) {
130+
#[default_method_body_is_const]
131+
fn clone_from(&mut self, source: &Self)
132+
where
133+
Self: ~const Clone + ~const Drop,
134+
{
131135
*self = source.clone()
132136
}
133137
}
@@ -178,7 +182,8 @@ mod impls {
178182
($($t:ty)*) => {
179183
$(
180184
#[stable(feature = "rust1", since = "1.0.0")]
181-
impl Clone for $t {
185+
#[rustc_const_unstable(feature = "const_clone", issue = "none")]
186+
impl const Clone for $t {
182187
#[inline]
183188
fn clone(&self) -> Self {
184189
*self
@@ -196,23 +201,26 @@ mod impls {
196201
}
197202

198203
#[unstable(feature = "never_type", issue = "35121")]
199-
impl Clone for ! {
204+
#[rustc_const_unstable(feature = "const_clone", issue = "none")]
205+
impl const Clone for ! {
200206
#[inline]
201207
fn clone(&self) -> Self {
202208
*self
203209
}
204210
}
205211

206212
#[stable(feature = "rust1", since = "1.0.0")]
207-
impl<T: ?Sized> Clone for *const T {
213+
#[rustc_const_unstable(feature = "const_clone", issue = "none")]
214+
impl<T: ?Sized> const Clone for *const T {
208215
#[inline]
209216
fn clone(&self) -> Self {
210217
*self
211218
}
212219
}
213220

214221
#[stable(feature = "rust1", since = "1.0.0")]
215-
impl<T: ?Sized> Clone for *mut T {
222+
#[rustc_const_unstable(feature = "const_clone", issue = "none")]
223+
impl<T: ?Sized> const Clone for *mut T {
216224
#[inline]
217225
fn clone(&self) -> Self {
218226
*self
@@ -221,7 +229,8 @@ mod impls {
221229

222230
/// Shared references can be cloned, but mutable references *cannot*!
223231
#[stable(feature = "rust1", since = "1.0.0")]
224-
impl<T: ?Sized> Clone for &T {
232+
#[rustc_const_unstable(feature = "const_clone", issue = "none")]
233+
impl<T: ?Sized> const Clone for &T {
225234
#[inline]
226235
#[rustc_diagnostic_item = "noop_method_clone"]
227236
fn clone(&self) -> Self {

0 commit comments

Comments
 (0)