From 83c8e284b63ceceb4e427f32829bef2cddf90287 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 4 Oct 2021 21:19:25 +0100 Subject: [PATCH 1/3] Document internal specialization attributes --- .../using-unstable-lang/specialization.md | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/code-considerations/using-unstable-lang/specialization.md b/src/code-considerations/using-unstable-lang/specialization.md index a390b15..6385b9a 100644 --- a/src/code-considerations/using-unstable-lang/specialization.md +++ b/src/code-considerations/using-unstable-lang/specialization.md @@ -58,6 +58,39 @@ impl RcFromSlice for Rc<[T]> { Only specialization using the `min_specialization` feature should be used. The full `specialization` feature is known to be unsound. +## Specialization attributes + +There are two unstable attributes that can be used to allow a trait bound in a specializing implementation that does not appear in the default implementation. + +`rustc_specialization_trait` restricts the implementations of a trait to be "always applicable". Implementing traits annotated with `rustc_specialization_trait` is unstable, so this should not be used on any stable traits exported from the standard library. `Sized` is an exception, and can have this attribute because it already cannot be implemented by an `impl` block. + +`rustc_unsafe_specialization_marker` allows specializing on a trait with no associated items. The attribute is `unsafe` because lifetime constraints from the implementations of the trait are not considered when specializing. In the following example, the specialized implementation is used for *all* shared reference types, not just those with `'static` lifetime. + +```rust,ignore +#[rustc_unsafe_specialization_marker] +trait StaticRef {} + +impl StaticRef for &'static T {} + +trait DoThing: Sized { + fn do_thing(self); +} + +impl DoThing for T { + default fn do_thing(self) { + // slow impl + } +} + +impl DoThing for T { + fn do_thing(self) { + // fast impl + } +} +``` + +`rustc_unsafe_specialization_marker` exists to allow existing specializations that are based on marker traits exported from `std`, such as `Copy`, `FusedIterator` or `Eq`. New uses of `rustc_unsafe_specialization_marker` should be avoided. + ## For reviewers Look out for any `default` annotations on public trait implementations. These will need to be refactored into a private dispatch trait. Also look out for uses of specialization that do more than pick a more optimized implementation. From f67d0d2ee98794def73d7c7d6e3a5c3e9f97eb6e Mon Sep 17 00:00:00 2001 From: matthewjasper <20113453+matthewjasper@users.noreply.github.com> Date: Fri, 29 Jul 2022 18:33:39 +0100 Subject: [PATCH 2/3] Apply suggestions from code review Co-authored-by: Jane Losare-Lusby --- src/code-considerations/using-unstable-lang/specialization.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/code-considerations/using-unstable-lang/specialization.md b/src/code-considerations/using-unstable-lang/specialization.md index 6385b9a..a8c7054 100644 --- a/src/code-considerations/using-unstable-lang/specialization.md +++ b/src/code-considerations/using-unstable-lang/specialization.md @@ -63,8 +63,9 @@ Only specialization using the `min_specialization` feature should be used. The f There are two unstable attributes that can be used to allow a trait bound in a specializing implementation that does not appear in the default implementation. `rustc_specialization_trait` restricts the implementations of a trait to be "always applicable". Implementing traits annotated with `rustc_specialization_trait` is unstable, so this should not be used on any stable traits exported from the standard library. `Sized` is an exception, and can have this attribute because it already cannot be implemented by an `impl` block. +**Note**: `rustc_specialization_trait` only prevents incorrect monomorphizations, it does not prevent a type from being coerced between specialized and unspecialized types which can be important when specialization must be applied consistently. See [rust-lang/rust#85863](https://github.com/rust-lang/rust/issues/85863) for more details. -`rustc_unsafe_specialization_marker` allows specializing on a trait with no associated items. The attribute is `unsafe` because lifetime constraints from the implementations of the trait are not considered when specializing. In the following example, the specialized implementation is used for *all* shared reference types, not just those with `'static` lifetime. +`rustc_unsafe_specialization_marker` allows specializing on a trait with no associated items. The attribute is `unsafe` because lifetime constraints from the implementations of the trait are not considered when specializing. The following example demonstrates incorrect usage of `rustc_unsafe_specialization_marker`, the specialized implementation is used for *all* shared reference types, not just those with `'static` lifetime. ```rust,ignore #[rustc_unsafe_specialization_marker] From 104f78a99e0679286761b9f1c62a828d3fc21f22 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 29 Jul 2022 18:54:34 +0100 Subject: [PATCH 3/3] Clarify what example is showing --- src/code-considerations/using-unstable-lang/specialization.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/code-considerations/using-unstable-lang/specialization.md b/src/code-considerations/using-unstable-lang/specialization.md index a8c7054..820fe54 100644 --- a/src/code-considerations/using-unstable-lang/specialization.md +++ b/src/code-considerations/using-unstable-lang/specialization.md @@ -65,7 +65,7 @@ There are two unstable attributes that can be used to allow a trait bound in a s `rustc_specialization_trait` restricts the implementations of a trait to be "always applicable". Implementing traits annotated with `rustc_specialization_trait` is unstable, so this should not be used on any stable traits exported from the standard library. `Sized` is an exception, and can have this attribute because it already cannot be implemented by an `impl` block. **Note**: `rustc_specialization_trait` only prevents incorrect monomorphizations, it does not prevent a type from being coerced between specialized and unspecialized types which can be important when specialization must be applied consistently. See [rust-lang/rust#85863](https://github.com/rust-lang/rust/issues/85863) for more details. -`rustc_unsafe_specialization_marker` allows specializing on a trait with no associated items. The attribute is `unsafe` because lifetime constraints from the implementations of the trait are not considered when specializing. The following example demonstrates incorrect usage of `rustc_unsafe_specialization_marker`, the specialized implementation is used for *all* shared reference types, not just those with `'static` lifetime. +`rustc_unsafe_specialization_marker` allows specializing on a trait with no associated items. The attribute is `unsafe` because lifetime constraints from the implementations of the trait are not considered when specializing. The following example demonstrates a limitation of `rustc_unsafe_specialization_marker`, the specialized implementation is used for *all* shared reference types, not just those with `'static` lifetime. Because of this, new uses of `rustc_unsafe_specialization_marker` should be avoided. ```rust,ignore #[rustc_unsafe_specialization_marker] @@ -90,7 +90,7 @@ impl DoThing for T { } ``` -`rustc_unsafe_specialization_marker` exists to allow existing specializations that are based on marker traits exported from `std`, such as `Copy`, `FusedIterator` or `Eq`. New uses of `rustc_unsafe_specialization_marker` should be avoided. +`rustc_unsafe_specialization_marker` exists to allow existing specializations that are based on marker traits exported from `std`, such as `Copy`, `FusedIterator` or `Eq`. ## For reviewers