Skip to content

Experiment: mark derived Clone impls as const #93255

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/deriving/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub fn expand_deriving_copy(
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
is_const: false,
supports_unions: true,
methods: Vec::new(),
associated_types: Vec::new(),
Expand Down
21 changes: 19 additions & 2 deletions compiler/rustc_builtin_macros/src/deriving/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub fn expand_deriving_clone(
item: &Annotatable,
push: &mut dyn FnMut(Annotatable),
) {
// check if we can use a short form
// check if we can use a short form, and if the impl can be const
//
// the short form is `fn clone(&self) -> Self { *self }`
//
Expand All @@ -29,6 +29,9 @@ pub fn expand_deriving_clone(
// Unions with generic parameters still can derive Clone because they require Copy
// for deriving, Clone alone is not enough.
// Whever Clone is implemented for fields is irrelevant so we don't assert it.
//
// for now, the impl is only able to be marked as const if we can use the short form;
// in the future, this may be expanded
let bounds;
let substructure;
let is_shallow;
Expand Down Expand Up @@ -73,15 +76,29 @@ pub fn expand_deriving_clone(
_ => cx.span_bug(span, "`#[derive(Clone)]` on trait item or impl item"),
}

let features = cx.sess.features_untracked();
let inline = cx.meta_word(span, sym::inline);
let attrs = vec![cx.attribute(inline)];
let is_const = is_shallow && features.const_trait_impl;
let trait_def = TraitDef {
span,
attributes: Vec::new(),
attributes: if is_const && features.staged_api {
vec![cx.attribute(cx.meta_list(
span,
sym::rustc_const_unstable,
vec![
cx.meta_name_value(span, sym::feature, Symbol::intern("const_clone")),
cx.meta_name_value(span, sym::issue, Symbol::intern("none")),
],
))]
} else {
Vec::new()
},
path: path_std!(clone::Clone),
additional_bounds: bounds,
generics: Bounds::empty(),
is_unsafe: false,
is_const,
supports_unions: true,
methods: vec![MethodDef {
name: sym::clone,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub fn expand_deriving_eq(
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
is_const: false,
supports_unions: true,
methods: vec![MethodDef {
name: sym::assert_receiver_is_total_eq,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub fn expand_deriving_ord(
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
is_const: false,
supports_unions: false,
methods: vec![MethodDef {
name: sym::cmp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ pub fn expand_deriving_partial_eq(
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
is_const: false,
supports_unions: false,
methods,
associated_types: Vec::new(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub fn expand_deriving_partial_ord(
additional_bounds: vec![],
generics: Bounds::empty(),
is_unsafe: false,
is_const: false,
supports_unions: false,
methods: vec![partial_cmp_def],
associated_types: Vec::new(),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/deriving/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub fn expand_deriving_debug(
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
is_const: false,
supports_unions: false,
methods: vec![MethodDef {
name: sym::fmt,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/deriving/decodable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub fn expand_deriving_rustc_decodable(
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
is_const: false,
supports_unions: false,
methods: vec![MethodDef {
name: sym::decode,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/deriving/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub fn expand_deriving_default(
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
is_const: false,
supports_unions: false,
methods: vec![MethodDef {
name: kw::Default,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/deriving/encodable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ pub fn expand_deriving_rustc_encodable(
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
is_const: false,
supports_unions: false,
methods: vec![MethodDef {
name: sym::encode,
Expand Down
49 changes: 42 additions & 7 deletions compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,9 @@ pub struct TraitDef<'a> {
/// Is it an `unsafe` trait?
pub is_unsafe: bool,

/// Is it a `const` impl?
pub is_const: bool,

/// Can this trait be derived for unions?
pub supports_unions: bool,

Expand Down Expand Up @@ -568,7 +571,7 @@ impl<'a> TraitDef<'a> {
});

let Generics { mut params, mut where_clause, .. } =
self.generics.to_generics(cx, self.span, type_ident, generics);
self.generics.to_generics(cx, self.span, type_ident, generics, self.is_const);
where_clause.span = generics.where_clause.span;
let ctxt = self.span.ctxt();
let span = generics.span.with_ctxt(ctxt);
Expand All @@ -583,10 +586,24 @@ impl<'a> TraitDef<'a> {
// extra restrictions on the generics parameters to the
// type being derived upon
self.additional_bounds.iter().map(|p| {
cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))
cx.trait_bound(
p.to_path(cx, self.span, type_ident, generics),
if self.is_const {
ast::TraitBoundModifier::MaybeConst
} else {
ast::TraitBoundModifier::None
},
)
}).chain(
// require the current trait
iter::once(cx.trait_bound(trait_path.clone()))
iter::once(cx.trait_bound(
trait_path.clone(),
if self.is_const {
ast::TraitBoundModifier::MaybeConst
} else {
ast::TraitBoundModifier::None
}
))
).chain(
// also add in any bounds from the declaration
param.bounds.iter().cloned()
Expand Down Expand Up @@ -663,11 +680,27 @@ impl<'a> TraitDef<'a> {
let mut bounds: Vec<_> = self
.additional_bounds
.iter()
.map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
.map(|p| {
cx.trait_bound(
p.to_path(cx, self.span, type_ident, generics),
if self.is_const {
ast::TraitBoundModifier::MaybeConst
} else {
ast::TraitBoundModifier::None
},
)
})
.collect();

// require the current trait
bounds.push(cx.trait_bound(trait_path.clone()));
bounds.push(cx.trait_bound(
trait_path.clone(),
if self.is_const {
ast::TraitBoundModifier::MaybeConst
} else {
ast::TraitBoundModifier::None
},
));

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

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

cx.item(
self.span,
Expand All @@ -732,7 +766,7 @@ impl<'a> TraitDef<'a> {
unsafety,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
constness: ast::Const::No,
constness,
generics: trait_generics,
of_trait: opt_trait_ref,
self_ty: self_type,
Expand Down Expand Up @@ -933,7 +967,8 @@ impl<'a> MethodDef<'a> {
) -> P<ast::AssocItem> {
let span = trait_.span;
// Create the generics that aren't for `Self`.
let fn_generics = self.generics.to_generics(cx, span, type_ident, generics);
let fn_generics =
self.generics.to_generics(cx, span, type_ident, generics, trait_.is_const);

let args = {
let self_args = explicit_self.map(|explicit_self| {
Expand Down
17 changes: 13 additions & 4 deletions compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,12 +200,20 @@ fn mk_ty_param(
bounds: &[Path],
self_ident: Ident,
self_generics: &Generics,
is_const: bool,
) -> ast::GenericParam {
let bounds = bounds
.iter()
.map(|b| {
let path = b.to_path(cx, span, self_ident, self_generics);
cx.trait_bound(path)
.map(|path| {
let path = path.to_path(cx, span, self_ident, self_generics);
cx.trait_bound(
path,
if is_const {
ast::TraitBoundModifier::MaybeConst
} else {
ast::TraitBoundModifier::None
},
)
})
.collect();
cx.typaram(span, Ident::new(name, span), attrs.to_owned(), bounds, None)
Expand All @@ -227,13 +235,14 @@ impl Bounds {
span: Span,
self_ty: Ident,
self_generics: &Generics,
is_const: bool,
) -> Generics {
let params = self
.bounds
.iter()
.map(|t| {
let (name, ref bounds) = *t;
mk_ty_param(cx, span, name, &[], &bounds, self_ty, self_generics)
mk_ty_param(cx, span, name, &[], &bounds, self_ty, self_generics, is_const)
})
.collect();

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/deriving/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub fn expand_deriving_hash(
additional_bounds: Vec::new(),
generics: Bounds::empty(),
is_unsafe: false,
is_const: false,
supports_unions: false,
methods: vec![MethodDef {
name: sym::hash,
Expand Down
19 changes: 14 additions & 5 deletions compiler/rustc_expand/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,12 @@ impl<'a> ExtCtxt<'a> {
}
}

pub fn trait_bound(&self, path: ast::Path) -> ast::GenericBound {
ast::GenericBound::Trait(
self.poly_trait_ref(path.span, path),
ast::TraitBoundModifier::None,
)
pub fn trait_bound(
&self,
path: ast::Path,
modif: ast::TraitBoundModifier,
) -> ast::GenericBound {
ast::GenericBound::Trait(self.poly_trait_ref(path.span, path), modif)
}

pub fn lifetime(&self, span: Span, ident: Ident) -> ast::Lifetime {
Expand Down Expand Up @@ -567,4 +568,12 @@ impl<'a> ExtCtxt<'a> {
pub fn meta_word(&self, sp: Span, w: Symbol) -> ast::MetaItem {
attr::mk_word_item(Ident::new(w, sp))
}

pub fn meta_name_value(&self, sp: Span, n: Symbol, v: Symbol) -> ast::NestedMetaItem {
ast::NestedMetaItem::MetaItem(attr::mk_name_value_item_str(Ident::new(n, sp), v, sp))
}

pub fn meta_list(&self, sp: Span, w: Symbol, items: Vec<ast::NestedMetaItem>) -> ast::MetaItem {
attr::mk_list_item(Ident::new(w, sp), items)
}
}
21 changes: 15 additions & 6 deletions library/core/src/clone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,11 @@ pub trait Clone: Sized {
/// allocations.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn clone_from(&mut self, source: &Self) {
#[default_method_body_is_const]
fn clone_from(&mut self, source: &Self)
where
Self: ~const Clone + ~const Drop,
Copy link
Contributor

Choose a reason for hiding this comment

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

does this show up in rustdoc?

{
*self = source.clone()
}
}
Expand Down Expand Up @@ -178,7 +182,8 @@ mod impls {
($($t:ty)*) => {
$(
#[stable(feature = "rust1", since = "1.0.0")]
impl Clone for $t {
#[rustc_const_unstable(feature = "const_clone", issue = "none")]
impl const Clone for $t {
#[inline]
fn clone(&self) -> Self {
*self
Expand All @@ -196,23 +201,26 @@ mod impls {
}

#[unstable(feature = "never_type", issue = "35121")]
impl Clone for ! {
#[rustc_const_unstable(feature = "const_clone", issue = "none")]
impl const Clone for ! {
#[inline]
fn clone(&self) -> Self {
*self
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Clone for *const T {
#[rustc_const_unstable(feature = "const_clone", issue = "none")]
impl<T: ?Sized> const Clone for *const T {
#[inline]
fn clone(&self) -> Self {
*self
}
}

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

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