2014-06-09 20:12:30 +00:00
|
|
|
//! Some code that abstracts away much of the boilerplate of writing
|
2014-12-31 04:25:18 +00:00
|
|
|
//! `derive` instances for traits. Among other things it manages getting
|
2014-06-09 20:12:30 +00:00
|
|
|
//! access to the fields of the 4 different sorts of structs and enum
|
|
|
|
//! variants, as well as creating the method and impl ast instances.
|
|
|
|
//!
|
|
|
|
//! Supported features (fairly exhaustive):
|
|
|
|
//!
|
|
|
|
//! - Methods taking any number of parameters of any type, and returning
|
|
|
|
//! any type, other than vectors, bottom and closures.
|
|
|
|
//! - Generating `impl`s for types with type parameters and lifetimes
|
2018-11-27 02:59:49 +00:00
|
|
|
//! (e.g., `Option<T>`), the parameters are automatically given the
|
2014-06-09 20:12:30 +00:00
|
|
|
//! current trait as a bound. (This includes separate type parameters
|
|
|
|
//! and lifetimes for methods.)
|
2015-01-12 13:00:19 +00:00
|
|
|
//! - Additional bounds on the type parameters (`TraitDef.additional_bounds`)
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
2017-08-15 19:45:21 +00:00
|
|
|
//! The most important thing for implementors is the `Substructure` and
|
2014-06-09 20:12:30 +00:00
|
|
|
//! `SubstructureFields` objects. The latter groups 5 possibilities of the
|
|
|
|
//! arguments:
|
|
|
|
//!
|
|
|
|
//! - `Struct`, when `Self` is a struct (including tuple structs, e.g
|
2015-01-17 23:55:21 +00:00
|
|
|
//! `struct T(i32, char)`).
|
2014-06-09 20:12:30 +00:00
|
|
|
//! - `EnumMatching`, when `Self` is an enum and all the arguments are the
|
2018-11-27 02:59:49 +00:00
|
|
|
//! same variant of the enum (e.g., `Some(1)`, `Some(3)` and `Some(4)`)
|
2022-07-08 05:32:27 +00:00
|
|
|
//! - `EnumTag` when `Self` is an enum, for comparing the enum tags.
|
2014-06-09 20:12:30 +00:00
|
|
|
//! - `StaticEnum` and `StaticStruct` for static methods, where the type
|
|
|
|
//! being derived upon is either an enum or struct respectively. (Any
|
|
|
|
//! argument with type Self is just grouped among the non-self
|
|
|
|
//! arguments.)
|
|
|
|
//!
|
|
|
|
//! In the first two cases, the values from the corresponding fields in
|
2022-07-08 05:32:27 +00:00
|
|
|
//! all the arguments are grouped together.
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
|
|
|
//! The non-static cases have `Option<ident>` in several places associated
|
|
|
|
//! with field `expr`s. This represents the name of the field it is
|
|
|
|
//! associated with. It is only not `None` when the associated field has
|
|
|
|
//! an identifier in the source code. For example, the `x`s in the
|
|
|
|
//! following snippet
|
|
|
|
//!
|
|
|
|
//! ```rust
|
2023-10-22 19:04:50 +00:00
|
|
|
//! struct A {
|
|
|
|
//! x: i32,
|
|
|
|
//! }
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
2015-01-17 23:55:21 +00:00
|
|
|
//! struct B(i32);
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
|
|
|
//! enum C {
|
2015-01-17 23:55:21 +00:00
|
|
|
//! C0(i32),
|
|
|
|
//! C1 { x: i32 }
|
2014-06-09 20:12:30 +00:00
|
|
|
//! }
|
|
|
|
//! ```
|
|
|
|
//!
|
2015-01-17 23:55:21 +00:00
|
|
|
//! The `i32`s in `B` and `C0` don't have an identifier, so the
|
2014-06-09 20:12:30 +00:00
|
|
|
//! `Option<ident>`s would be `None` for them.
|
|
|
|
//!
|
2018-11-12 18:05:20 +00:00
|
|
|
//! In the static cases, the structure is summarized, either into the just
|
2014-06-09 20:12:30 +00:00
|
|
|
//! spans of the fields or a list of spans and the field idents (for tuple
|
|
|
|
//! structs and record structs, respectively), or a list of these, for
|
|
|
|
//! enums (one for each variant). For empty struct and empty enum
|
|
|
|
//! variants, it is represented as a count of 0.
|
|
|
|
//!
|
2015-01-12 13:00:19 +00:00
|
|
|
//! # "`cs`" functions
|
|
|
|
//!
|
2022-06-23 22:31:00 +00:00
|
|
|
//! The `cs_...` functions ("combine substructure") are designed to
|
2015-01-12 13:00:19 +00:00
|
|
|
//! make life easier by providing some pre-made recipes for common
|
2015-05-08 15:12:29 +00:00
|
|
|
//! threads; mostly calling the function being derived on all the
|
2015-01-12 13:00:19 +00:00
|
|
|
//! arguments and then combining them back together in some way (or
|
|
|
|
//! letting the user chose that). They are not meant to be the only
|
|
|
|
//! way to handle the structures that this code creates.
|
|
|
|
//!
|
2014-06-09 20:12:30 +00:00
|
|
|
//! # Examples
|
|
|
|
//!
|
|
|
|
//! The following simplified `PartialEq` is used for in-code examples:
|
|
|
|
//!
|
|
|
|
//! ```rust
|
|
|
|
//! trait PartialEq {
|
2015-11-03 16:34:11 +00:00
|
|
|
//! fn eq(&self, other: &Self) -> bool;
|
2014-06-09 20:12:30 +00:00
|
|
|
//! }
|
2023-10-22 19:04:50 +00:00
|
|
|
//!
|
2015-01-17 23:55:21 +00:00
|
|
|
//! impl PartialEq for i32 {
|
|
|
|
//! fn eq(&self, other: &i32) -> bool {
|
2014-06-09 20:12:30 +00:00
|
|
|
//! *self == *other
|
|
|
|
//! }
|
|
|
|
//! }
|
|
|
|
//! ```
|
|
|
|
//!
|
|
|
|
//! Some examples of the values of `SubstructureFields` follow, using the
|
|
|
|
//! above `PartialEq`, `A`, `B` and `C`.
|
|
|
|
//!
|
|
|
|
//! ## Structs
|
|
|
|
//!
|
|
|
|
//! When generating the `expr` for the `A` impl, the `SubstructureFields` is
|
|
|
|
//!
|
2023-09-16 09:37:41 +00:00
|
|
|
//! ```text
|
2015-01-12 13:00:19 +00:00
|
|
|
//! Struct(vec![FieldInfo {
|
2023-10-22 19:04:50 +00:00
|
|
|
//! span: <span of x>,
|
|
|
|
//! name: Some(<ident of x>),
|
|
|
|
//! self_: <expr for &self.x>,
|
|
|
|
//! other: vec![<expr for &other.x>],
|
|
|
|
//! }])
|
2014-09-16 11:27:34 +00:00
|
|
|
//! ```
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
|
|
|
//! For the `B` impl, called with `B(a)` and `B(b)`,
|
|
|
|
//!
|
2023-09-16 09:37:41 +00:00
|
|
|
//! ```text
|
2015-01-12 13:00:19 +00:00
|
|
|
//! Struct(vec![FieldInfo {
|
2023-10-22 19:04:50 +00:00
|
|
|
//! span: <span of i32>,
|
|
|
|
//! name: None,
|
|
|
|
//! self_: <expr for &a>,
|
|
|
|
//! other: vec![<expr for &b>],
|
|
|
|
//! }])
|
2014-09-16 11:27:34 +00:00
|
|
|
//! ```
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
|
|
|
//! ## Enums
|
|
|
|
//!
|
|
|
|
//! When generating the `expr` for a call with `self == C0(a)` and `other
|
|
|
|
//! == C0(b)`, the SubstructureFields is
|
|
|
|
//!
|
2023-09-16 09:37:41 +00:00
|
|
|
//! ```text
|
2023-10-22 19:04:50 +00:00
|
|
|
//! EnumMatching(
|
|
|
|
//! 0,
|
|
|
|
//! <ast::Variant for C0>,
|
|
|
|
//! vec![FieldInfo {
|
|
|
|
//! span: <span of i32>,
|
|
|
|
//! name: None,
|
|
|
|
//! self_: <expr for &a>,
|
|
|
|
//! other: vec![<expr for &b>],
|
|
|
|
//! }],
|
|
|
|
//! )
|
2014-09-16 11:27:34 +00:00
|
|
|
//! ```
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
2014-07-06 19:19:12 +00:00
|
|
|
//! For `C1 {x}` and `C1 {x}`,
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
2023-09-16 09:37:41 +00:00
|
|
|
//! ```text
|
2023-10-22 19:04:50 +00:00
|
|
|
//! EnumMatching(
|
|
|
|
//! 1,
|
|
|
|
//! <ast::Variant for C1>,
|
|
|
|
//! vec![FieldInfo {
|
|
|
|
//! span: <span of x>,
|
|
|
|
//! name: Some(<ident of x>),
|
|
|
|
//! self_: <expr for &self.x>,
|
|
|
|
//! other: vec![<expr for &other.x>],
|
|
|
|
//! }],
|
|
|
|
//! )
|
2014-09-16 11:27:34 +00:00
|
|
|
//! ```
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
2022-07-08 05:32:27 +00:00
|
|
|
//! For the tags,
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
2023-09-16 09:37:41 +00:00
|
|
|
//! ```text
|
2022-07-08 05:32:27 +00:00
|
|
|
//! EnumTag(
|
2023-10-22 19:04:50 +00:00
|
|
|
//! &[<ident of self tag>, <ident of other tag>],
|
|
|
|
//! <expr to combine with>,
|
|
|
|
//! )
|
2014-09-16 11:27:34 +00:00
|
|
|
//! ```
|
2023-10-22 19:04:50 +00:00
|
|
|
//!
|
2022-07-08 05:32:27 +00:00
|
|
|
//! Note that this setup doesn't allow for the brute-force "match every variant
|
|
|
|
//! against every other variant" approach, which is bad because it produces a
|
|
|
|
//! quadratic amount of code (see #15375).
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
|
|
|
//! ## Static
|
|
|
|
//!
|
2015-01-12 13:00:19 +00:00
|
|
|
//! A static method on the types above would result in,
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
2023-09-16 09:37:41 +00:00
|
|
|
//! ```text
|
2015-10-08 00:20:57 +00:00
|
|
|
//! StaticStruct(<ast::VariantData of A>, Named(vec![(<ident of x>, <span of x>)]))
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
2015-10-08 00:20:57 +00:00
|
|
|
//! StaticStruct(<ast::VariantData of B>, Unnamed(vec![<span of x>]))
|
2014-06-09 20:12:30 +00:00
|
|
|
//!
|
2023-10-22 19:04:50 +00:00
|
|
|
//! StaticEnum(
|
|
|
|
//! <ast::EnumDef of C>,
|
|
|
|
//! vec![
|
|
|
|
//! (<ident of C0>, <span of C0>, Unnamed(vec![<span of i32>])),
|
|
|
|
//! (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)])),
|
|
|
|
//! ],
|
|
|
|
//! )
|
2014-09-16 11:27:34 +00:00
|
|
|
//! ```
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2019-02-04 12:49:54 +00:00
|
|
|
pub use StaticFields::*;
|
|
|
|
pub use SubstructureFields::*;
|
2014-11-06 08:05:53 +00:00
|
|
|
|
2023-04-08 19:37:41 +00:00
|
|
|
use crate::{deriving, errors};
|
2020-02-29 17:37:32 +00:00
|
|
|
use rustc_ast::ptr::P;
|
2022-08-30 22:34:35 +00:00
|
|
|
use rustc_ast::{
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
self as ast, BindingAnnotation, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics,
|
|
|
|
Mutability, PatKind, TyKind, VariantData,
|
2022-08-30 22:34:35 +00:00
|
|
|
};
|
2020-01-11 12:15:20 +00:00
|
|
|
use rustc_attr as attr;
|
2019-12-29 14:23:55 +00:00
|
|
|
use rustc_expand::base::{Annotatable, ExtCtxt};
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
use rustc_session::lint::builtin::BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE;
|
2020-04-19 11:00:18 +00:00
|
|
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
2022-09-20 11:55:07 +00:00
|
|
|
use rustc_span::{Span, DUMMY_SP};
|
2022-08-17 04:22:30 +00:00
|
|
|
use std::cell::RefCell;
|
|
|
|
use std::iter;
|
2022-08-26 12:59:12 +00:00
|
|
|
use std::ops::Not;
|
2022-08-17 04:22:30 +00:00
|
|
|
use std::vec;
|
2022-11-21 22:17:20 +00:00
|
|
|
use thin_vec::{thin_vec, ThinVec};
|
2022-06-29 23:15:07 +00:00
|
|
|
use ty::{Bounds, Path, Ref, Self_, Ty};
|
2014-05-29 03:19:05 +00:00
|
|
|
|
|
|
|
pub mod ty;
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2013-12-10 07:16:18 +00:00
|
|
|
pub struct TraitDef<'a> {
|
2014-12-31 04:25:18 +00:00
|
|
|
/// The span for the current #[derive(Foo)] header.
|
2014-03-27 22:39:48 +00:00
|
|
|
pub span: Span,
|
2013-12-07 00:57:44 +00:00
|
|
|
|
2013-05-06 15:23:51 +00:00
|
|
|
/// Path of the trait, including any type parameters
|
2020-07-14 05:05:26 +00:00
|
|
|
pub path: Path,
|
2014-02-09 00:39:53 +00:00
|
|
|
|
2022-08-26 12:59:12 +00:00
|
|
|
/// Whether to skip adding the current trait as a bound to the type parameters of the type.
|
|
|
|
pub skip_path_as_bound: bool,
|
|
|
|
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
/// Whether `Copy` is needed as an additional bound on type parameters in a packed struct.
|
|
|
|
pub needs_copy_as_bound_if_packed: bool,
|
|
|
|
|
2013-05-06 15:23:51 +00:00
|
|
|
/// Additional bounds required of any type parameters of the type,
|
|
|
|
/// other than the current trait
|
2020-07-14 05:05:26 +00:00
|
|
|
pub additional_bounds: Vec<Ty>,
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2016-08-29 11:14:25 +00:00
|
|
|
/// Can this trait be derived for unions?
|
|
|
|
pub supports_unions: bool,
|
|
|
|
|
2014-03-27 22:39:48 +00:00
|
|
|
pub methods: Vec<MethodDef<'a>>,
|
2015-01-25 05:29:24 +00:00
|
|
|
|
2020-07-14 05:05:26 +00:00
|
|
|
pub associated_types: Vec<(Ident, Ty)>,
|
2022-09-20 11:55:07 +00:00
|
|
|
|
|
|
|
pub is_const: bool,
|
2014-03-27 22:39:48 +00:00
|
|
|
}
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2013-12-10 07:16:18 +00:00
|
|
|
pub struct MethodDef<'a> {
|
2013-03-28 10:50:10 +00:00
|
|
|
/// name of the method
|
2020-07-08 01:04:10 +00:00
|
|
|
pub name: Symbol,
|
2018-11-27 02:59:49 +00:00
|
|
|
/// List of generics, e.g., `R: rand::Rng`
|
2020-07-14 05:05:26 +00:00
|
|
|
pub generics: Bounds,
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2022-06-29 23:15:07 +00:00
|
|
|
/// Is there is a `&self` argument? If not, it is a static function.
|
|
|
|
pub explicit_self: bool,
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2022-07-04 22:25:47 +00:00
|
|
|
/// Arguments other than the self argument.
|
|
|
|
pub nonself_args: Vec<(Ty, Symbol)>,
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2019-02-08 13:53:55 +00:00
|
|
|
/// Returns type
|
2020-07-14 05:05:26 +00:00
|
|
|
pub ret_ty: Ty,
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2022-08-17 02:34:33 +00:00
|
|
|
pub attributes: ast::AttrVec,
|
2013-11-19 00:13:34 +00:00
|
|
|
|
2023-01-14 21:16:25 +00:00
|
|
|
pub fieldless_variants_strategy: FieldlessVariantsStrategy,
|
2016-05-12 15:54:05 +00:00
|
|
|
|
2014-04-22 06:25:18 +00:00
|
|
|
pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
2023-01-14 21:16:25 +00:00
|
|
|
/// How to handle fieldless enum variants.
|
|
|
|
#[derive(PartialEq)]
|
|
|
|
pub enum FieldlessVariantsStrategy {
|
|
|
|
/// Combine fieldless variants into a single match arm.
|
|
|
|
/// This assumes that relevant information has been handled
|
|
|
|
/// by looking at the enum's discriminant.
|
|
|
|
Unify,
|
|
|
|
/// Don't do anything special about fieldless variants. They are
|
|
|
|
/// handled like any other variant.
|
|
|
|
Default,
|
|
|
|
/// If all variants of the enum are fieldless, expand the special
|
|
|
|
/// `AllFieldLessEnum` substructure, so that the entire enum can be handled
|
|
|
|
/// at once.
|
|
|
|
SpecializeIfAllVariantsFieldless,
|
|
|
|
}
|
|
|
|
|
2013-03-28 10:50:10 +00:00
|
|
|
/// All the data about the data structure/method being derived upon.
|
2013-12-10 07:16:18 +00:00
|
|
|
pub struct Substructure<'a> {
|
2013-05-06 15:23:51 +00:00
|
|
|
/// ident of self
|
2014-03-27 22:39:48 +00:00
|
|
|
pub type_ident: Ident,
|
2022-07-07 21:57:34 +00:00
|
|
|
/// Verbatim access to any non-selflike arguments, i.e. arguments that
|
|
|
|
/// don't have type `&Self`.
|
2022-07-04 22:25:47 +00:00
|
|
|
pub nonselflike_args: &'a [P<Expr>],
|
2016-07-19 17:32:06 +00:00
|
|
|
pub fields: &'a SubstructureFields<'a>,
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
2013-11-07 07:49:01 +00:00
|
|
|
/// Summary of the relevant parts of a struct/enum field.
|
2022-07-04 22:59:17 +00:00
|
|
|
pub struct FieldInfo {
|
2014-03-27 22:39:48 +00:00
|
|
|
pub span: Span,
|
2013-11-07 07:49:01 +00:00
|
|
|
/// None for tuple structs/normal enum variants, Some for normal
|
|
|
|
/// structs/struct enum variants.
|
2014-03-27 22:39:48 +00:00
|
|
|
pub name: Option<Ident>,
|
2013-11-07 07:49:01 +00:00
|
|
|
/// The expression corresponding to this field of `self`
|
|
|
|
/// (specifically, a reference to it).
|
2022-07-04 22:47:04 +00:00
|
|
|
pub self_expr: P<Expr>,
|
2013-11-07 07:49:01 +00:00
|
|
|
/// The expressions corresponding to references to this field in
|
2022-07-04 22:47:04 +00:00
|
|
|
/// the other selflike arguments.
|
|
|
|
pub other_selflike_exprs: Vec<P<Expr>>,
|
2014-03-27 22:39:48 +00:00
|
|
|
}
|
2013-11-07 07:49:01 +00:00
|
|
|
|
|
|
|
/// Fields for a static method
|
|
|
|
pub enum StaticFields {
|
2016-08-15 18:28:17 +00:00
|
|
|
/// Tuple and unit structs/enum variants like this.
|
|
|
|
Unnamed(Vec<Span>, bool /*is tuple*/),
|
2013-11-07 07:49:01 +00:00
|
|
|
/// Normal structs/struct variants.
|
2014-05-16 07:16:13 +00:00
|
|
|
Named(Vec<(Ident, Span)>),
|
2013-11-07 07:49:01 +00:00
|
|
|
}
|
|
|
|
|
2014-09-17 13:12:58 +00:00
|
|
|
/// A summary of the possible sets of fields.
|
2013-12-10 07:16:18 +00:00
|
|
|
pub enum SubstructureFields<'a> {
|
2023-01-14 21:16:25 +00:00
|
|
|
/// A non-static method where `Self` is a struct.
|
2022-07-04 22:59:17 +00:00
|
|
|
Struct(&'a ast::VariantData, Vec<FieldInfo>),
|
2022-07-08 05:32:27 +00:00
|
|
|
|
2023-01-14 21:16:25 +00:00
|
|
|
/// A non-static method handling the entire enum at once
|
|
|
|
/// (after it has been determined that none of the enum
|
|
|
|
/// variants has any fields).
|
|
|
|
AllFieldlessEnum(&'a ast::EnumDef),
|
|
|
|
|
2017-06-16 19:59:20 +00:00
|
|
|
/// Matching variants of the enum: variant index, variant count, ast::Variant,
|
2014-09-16 11:27:34 +00:00
|
|
|
/// fields: the field name is only non-`None` in the case of a struct
|
|
|
|
/// variant.
|
2022-07-04 22:59:17 +00:00
|
|
|
EnumMatching(usize, usize, &'a ast::Variant, Vec<FieldInfo>),
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2022-07-08 05:32:27 +00:00
|
|
|
/// The tag of an enum. The first field is a `FieldInfo` for the tags, as
|
|
|
|
/// if they were fields. The second field is the expression to combine the
|
|
|
|
/// tag expression with; it will be `None` if no match is necessary.
|
|
|
|
EnumTag(FieldInfo, Option<P<Expr>>),
|
2014-07-06 19:19:12 +00:00
|
|
|
|
2014-09-17 13:02:26 +00:00
|
|
|
/// A static method where `Self` is a struct.
|
2015-10-08 00:20:57 +00:00
|
|
|
StaticStruct(&'a ast::VariantData, StaticFields),
|
2022-07-08 05:32:27 +00:00
|
|
|
|
2014-09-17 13:02:26 +00:00
|
|
|
/// A static method where `Self` is an enum.
|
2014-05-16 07:16:13 +00:00
|
|
|
StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>),
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
2014-09-16 11:27:34 +00:00
|
|
|
/// Combine the values of all the fields together. The last argument is
|
2014-09-17 13:12:58 +00:00
|
|
|
/// all the fields of all the structures.
|
2013-12-10 07:16:18 +00:00
|
|
|
pub type CombineSubstructureFunc<'a> =
|
2022-06-28 03:10:36 +00:00
|
|
|
Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &Substructure<'_>) -> BlockOrExpr + 'a>;
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2019-06-21 16:51:27 +00:00
|
|
|
pub fn combine_substructure(
|
|
|
|
f: CombineSubstructureFunc<'_>,
|
|
|
|
) -> RefCell<CombineSubstructureFunc<'_>> {
|
2014-04-22 06:25:18 +00:00
|
|
|
RefCell::new(f)
|
|
|
|
}
|
|
|
|
|
2021-09-28 22:46:29 +00:00
|
|
|
struct TypeParameter {
|
2022-11-21 22:17:20 +00:00
|
|
|
bound_generic_params: ThinVec<ast::GenericParam>,
|
2021-09-28 22:46:29 +00:00
|
|
|
ty: P<ast::Ty>,
|
|
|
|
}
|
|
|
|
|
2022-11-27 11:15:06 +00:00
|
|
|
/// The code snippets built up for derived code are sometimes used as blocks
|
|
|
|
/// (e.g. in a function body) and sometimes used as expressions (e.g. in a match
|
|
|
|
/// arm). This structure avoids committing to either form until necessary,
|
|
|
|
/// avoiding the insertion of any unnecessary blocks.
|
|
|
|
///
|
|
|
|
/// The statements come before the expression.
|
2023-01-30 03:13:27 +00:00
|
|
|
pub struct BlockOrExpr(ThinVec<ast::Stmt>, Option<P<Expr>>);
|
2022-06-28 03:10:36 +00:00
|
|
|
|
|
|
|
impl BlockOrExpr {
|
2023-01-30 03:13:27 +00:00
|
|
|
pub fn new_stmts(stmts: ThinVec<ast::Stmt>) -> BlockOrExpr {
|
2022-06-28 03:10:36 +00:00
|
|
|
BlockOrExpr(stmts, None)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn new_expr(expr: P<Expr>) -> BlockOrExpr {
|
2023-01-30 03:13:27 +00:00
|
|
|
BlockOrExpr(ThinVec::new(), Some(expr))
|
2022-06-28 03:10:36 +00:00
|
|
|
}
|
|
|
|
|
2023-01-30 03:13:27 +00:00
|
|
|
pub fn new_mixed(stmts: ThinVec<ast::Stmt>, expr: Option<P<Expr>>) -> BlockOrExpr {
|
2022-07-08 05:32:27 +00:00
|
|
|
BlockOrExpr(stmts, expr)
|
2022-06-28 03:10:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Converts it into a block.
|
|
|
|
fn into_block(mut self, cx: &ExtCtxt<'_>, span: Span) -> P<ast::Block> {
|
|
|
|
if let Some(expr) = self.1 {
|
|
|
|
self.0.push(cx.stmt_expr(expr));
|
|
|
|
}
|
|
|
|
cx.block(span, self.0)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Converts it into an expression.
|
|
|
|
fn into_expr(self, cx: &ExtCtxt<'_>, span: Span) -> P<Expr> {
|
|
|
|
if self.0.is_empty() {
|
|
|
|
match self.1 {
|
2023-01-30 03:13:27 +00:00
|
|
|
None => cx.expr_block(cx.block(span, ThinVec::new())),
|
2022-06-28 03:10:36 +00:00
|
|
|
Some(expr) => expr,
|
|
|
|
}
|
2022-07-08 05:27:42 +00:00
|
|
|
} else if self.0.len() == 1
|
|
|
|
&& let ast::StmtKind::Expr(expr) = &self.0[0].kind
|
|
|
|
&& self.1.is_none()
|
|
|
|
{
|
|
|
|
// There's only a single statement expression. Pull it out.
|
|
|
|
expr.clone()
|
2022-06-28 03:10:36 +00:00
|
|
|
} else {
|
2022-07-08 05:27:42 +00:00
|
|
|
// Multiple statements and/or expressions.
|
2022-06-28 03:10:36 +00:00
|
|
|
cx.expr_block(self.into_block(cx, span))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-24 21:43:26 +00:00
|
|
|
/// This method helps to extract all the type parameters referenced from a
|
|
|
|
/// type. For a type parameter `<T>`, it looks for either a `TyPath` that
|
|
|
|
/// is not global and starts with `T`, or a `TyQPath`.
|
2021-09-28 22:46:29 +00:00
|
|
|
/// Also include bound generic params from the input type.
|
2019-06-16 09:41:24 +00:00
|
|
|
fn find_type_parameters(
|
|
|
|
ty: &ast::Ty,
|
2020-04-19 11:00:18 +00:00
|
|
|
ty_param_names: &[Symbol],
|
2019-06-16 09:41:24 +00:00
|
|
|
cx: &ExtCtxt<'_>,
|
2021-09-28 22:46:29 +00:00
|
|
|
) -> Vec<TypeParameter> {
|
2020-02-29 17:37:32 +00:00
|
|
|
use rustc_ast::visit;
|
2015-03-24 21:43:26 +00:00
|
|
|
|
2019-06-14 16:39:39 +00:00
|
|
|
struct Visitor<'a, 'b> {
|
2016-06-24 03:23:44 +00:00
|
|
|
cx: &'a ExtCtxt<'b>,
|
2020-04-19 11:00:18 +00:00
|
|
|
ty_param_names: &'a [Symbol],
|
2022-11-21 22:17:20 +00:00
|
|
|
bound_generic_params_stack: ThinVec<ast::GenericParam>,
|
2021-09-28 22:46:29 +00:00
|
|
|
type_params: Vec<TypeParameter>,
|
2015-03-24 21:43:26 +00:00
|
|
|
}
|
|
|
|
|
2016-12-06 10:26:52 +00:00
|
|
|
impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> {
|
|
|
|
fn visit_ty(&mut self, ty: &'a ast::Ty) {
|
2022-12-06 13:22:36 +00:00
|
|
|
if let ast::TyKind::Path(_, path) = &ty.kind
|
|
|
|
&& let Some(segment) = path.segments.first()
|
|
|
|
&& self.ty_param_names.contains(&segment.ident.name)
|
|
|
|
{
|
|
|
|
self.type_params.push(TypeParameter {
|
|
|
|
bound_generic_params: self.bound_generic_params_stack.clone(),
|
|
|
|
ty: P(ty.clone()),
|
|
|
|
});
|
2015-03-24 21:43:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
visit::walk_ty(self, ty)
|
|
|
|
}
|
2016-06-24 03:23:44 +00:00
|
|
|
|
2021-09-28 22:46:29 +00:00
|
|
|
// Place bound generic params on a stack, to extract them when a type is encountered.
|
2022-08-11 01:05:26 +00:00
|
|
|
fn visit_poly_trait_ref(&mut self, trait_ref: &'a ast::PolyTraitRef) {
|
2021-09-29 01:18:56 +00:00
|
|
|
let stack_len = self.bound_generic_params_stack.len();
|
2022-08-13 13:50:01 +00:00
|
|
|
self.bound_generic_params_stack.extend(trait_ref.bound_generic_params.iter().cloned());
|
2021-09-28 22:46:29 +00:00
|
|
|
|
2022-08-11 01:05:26 +00:00
|
|
|
visit::walk_poly_trait_ref(self, trait_ref);
|
2021-09-28 22:46:29 +00:00
|
|
|
|
|
|
|
self.bound_generic_params_stack.truncate(stack_len);
|
|
|
|
}
|
|
|
|
|
2020-11-03 17:34:57 +00:00
|
|
|
fn visit_mac_call(&mut self, mac: &ast::MacCall) {
|
2023-04-08 19:37:41 +00:00
|
|
|
self.cx.emit_err(errors::DeriveMacroCall { span: mac.span() });
|
2016-06-24 03:23:44 +00:00
|
|
|
}
|
2015-03-24 21:43:26 +00:00
|
|
|
}
|
|
|
|
|
2021-09-28 22:46:29 +00:00
|
|
|
let mut visitor = Visitor {
|
|
|
|
cx,
|
|
|
|
ty_param_names,
|
2022-11-21 22:17:20 +00:00
|
|
|
bound_generic_params_stack: ThinVec::new(),
|
2021-09-28 22:46:29 +00:00
|
|
|
type_params: Vec::new(),
|
|
|
|
};
|
2015-03-24 21:43:26 +00:00
|
|
|
visit::Visitor::visit_ty(&mut visitor, ty);
|
|
|
|
|
2021-09-28 22:46:29 +00:00
|
|
|
visitor.type_params
|
2015-03-24 21:43:26 +00:00
|
|
|
}
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2013-12-10 07:16:18 +00:00
|
|
|
impl<'a> TraitDef<'a> {
|
2017-10-02 13:15:23 +00:00
|
|
|
pub fn expand(
|
|
|
|
self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2015-03-27 01:07:49 +00:00
|
|
|
mitem: &ast::MetaItem,
|
2015-05-12 02:15:02 +00:00
|
|
|
item: &'a Annotatable,
|
2018-07-12 09:58:16 +00:00
|
|
|
push: &mut dyn FnMut(Annotatable),
|
|
|
|
) {
|
2016-08-26 16:23:42 +00:00
|
|
|
self.expand_ext(cx, mitem, item, push, false);
|
|
|
|
}
|
|
|
|
|
2017-10-02 13:15:23 +00:00
|
|
|
pub fn expand_ext(
|
|
|
|
self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2016-08-26 16:23:42 +00:00
|
|
|
mitem: &ast::MetaItem,
|
|
|
|
item: &'a Annotatable,
|
2018-07-12 09:58:16 +00:00
|
|
|
push: &mut dyn FnMut(Annotatable),
|
2016-08-26 16:23:42 +00:00
|
|
|
from_scratch: bool,
|
|
|
|
) {
|
2022-12-06 13:22:36 +00:00
|
|
|
match item {
|
|
|
|
Annotatable::Item(item) => {
|
2017-10-02 13:15:23 +00:00
|
|
|
let is_packed = item.attrs.iter().any(|attr| {
|
2023-11-21 19:07:32 +00:00
|
|
|
for r in attr::find_repr_attrs(cx.sess, attr) {
|
2018-02-04 11:10:28 +00:00
|
|
|
if let attr::ReprPacked(_) = r {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
false
|
2017-10-02 13:15:23 +00:00
|
|
|
});
|
2017-11-19 15:04:24 +00:00
|
|
|
|
2022-12-06 13:22:36 +00:00
|
|
|
let newitem = match &item.kind {
|
|
|
|
ast::ItemKind::Struct(struct_def, generics) => self.expand_struct_def(
|
2017-10-02 13:15:23 +00:00
|
|
|
cx,
|
2023-11-21 19:07:32 +00:00
|
|
|
struct_def,
|
2017-10-02 13:15:23 +00:00
|
|
|
item.ident,
|
|
|
|
generics,
|
|
|
|
from_scratch,
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
is_packed,
|
2019-12-22 22:42:04 +00:00
|
|
|
),
|
2022-12-06 13:22:36 +00:00
|
|
|
ast::ItemKind::Enum(enum_def, generics) => {
|
2022-11-21 00:48:25 +00:00
|
|
|
// We ignore `is_packed` here, because `repr(packed)`
|
|
|
|
// enums cause an error later on.
|
2017-10-02 13:15:23 +00:00
|
|
|
//
|
|
|
|
// This can only cause further compilation errors
|
2022-11-21 00:48:25 +00:00
|
|
|
// downstream in blatantly illegal code, so it is fine.
|
2020-04-05 18:36:39 +00:00
|
|
|
self.expand_enum_def(cx, enum_def, item.ident, generics, from_scratch)
|
2015-04-28 05:34:39 +00:00
|
|
|
}
|
2022-12-06 13:22:36 +00:00
|
|
|
ast::ItemKind::Union(struct_def, generics) => {
|
2016-08-24 18:10:19 +00:00
|
|
|
if self.supports_unions {
|
2016-08-26 16:23:42 +00:00
|
|
|
self.expand_struct_def(
|
|
|
|
cx,
|
2023-11-21 19:07:32 +00:00
|
|
|
struct_def,
|
2016-08-26 16:23:42 +00:00
|
|
|
item.ident,
|
2017-10-02 13:15:23 +00:00
|
|
|
generics,
|
|
|
|
from_scratch,
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
is_packed,
|
2017-10-02 13:15:23 +00:00
|
|
|
)
|
2016-08-24 18:10:19 +00:00
|
|
|
} else {
|
2023-04-08 19:37:41 +00:00
|
|
|
cx.emit_err(errors::DeriveUnion { span: mitem.span });
|
2016-08-24 18:10:19 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2017-11-19 15:04:24 +00:00
|
|
|
_ => unreachable!(),
|
2015-04-28 05:34:39 +00:00
|
|
|
};
|
|
|
|
// Keep the lint attributes of the previous item to control how the
|
|
|
|
// generated implementations are linted
|
|
|
|
let mut attrs = newitem.attrs.clone();
|
2016-07-19 17:32:06 +00:00
|
|
|
attrs.extend(
|
|
|
|
item.attrs
|
|
|
|
.iter()
|
2019-03-17 11:17:47 +00:00
|
|
|
.filter(|a| {
|
2019-05-08 04:33:06 +00:00
|
|
|
[
|
|
|
|
sym::allow,
|
|
|
|
sym::warn,
|
|
|
|
sym::deny,
|
|
|
|
sym::forbid,
|
|
|
|
sym::stable,
|
|
|
|
sym::unstable,
|
|
|
|
]
|
|
|
|
.contains(&a.name_or_empty())
|
2019-03-17 11:17:47 +00:00
|
|
|
})
|
2016-07-19 17:32:06 +00:00
|
|
|
.cloned(),
|
|
|
|
);
|
2020-03-06 18:28:44 +00:00
|
|
|
push(Annotatable::Item(P(ast::Item { attrs, ..(*newitem).clone() })))
|
2014-02-13 07:53:52 +00:00
|
|
|
}
|
2020-11-18 22:55:59 +00:00
|
|
|
_ => unreachable!(),
|
2015-04-28 05:34:39 +00:00
|
|
|
}
|
2013-06-07 07:46:44 +00:00
|
|
|
}
|
|
|
|
|
2015-03-24 21:43:26 +00:00
|
|
|
/// Given that we are deriving a trait `DerivedTrait` for a type like:
|
2014-09-16 11:27:34 +00:00
|
|
|
///
|
2017-06-20 07:15:16 +00:00
|
|
|
/// ```ignore (only-for-syntax-highlight)
|
2023-10-22 19:04:50 +00:00
|
|
|
/// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z>
|
|
|
|
/// where
|
|
|
|
/// C: WhereTrait,
|
|
|
|
/// {
|
2015-03-24 21:43:26 +00:00
|
|
|
/// a: A,
|
|
|
|
/// b: B::Item,
|
|
|
|
/// b1: <B as DeclaredTrait>::Item,
|
|
|
|
/// c1: <C as WhereTrait>::Item,
|
|
|
|
/// c2: Option<<C as WhereTrait>::Item>,
|
|
|
|
/// ...
|
|
|
|
/// }
|
2014-09-16 11:27:34 +00:00
|
|
|
/// ```
|
|
|
|
///
|
2015-03-24 21:43:26 +00:00
|
|
|
/// create an impl like:
|
|
|
|
///
|
2017-06-20 07:15:16 +00:00
|
|
|
/// ```ignore (only-for-syntax-highlight)
|
2023-10-22 19:04:50 +00:00
|
|
|
/// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z>
|
|
|
|
/// where
|
|
|
|
/// C: WhereTrait,
|
2015-03-24 21:43:26 +00:00
|
|
|
/// A: DerivedTrait + B1 + ... + BN,
|
|
|
|
/// B: DerivedTrait + B1 + ... + BN,
|
|
|
|
/// C: DerivedTrait + B1 + ... + BN,
|
2023-10-22 19:04:50 +00:00
|
|
|
/// B::Item: DerivedTrait + B1 + ... + BN,
|
2015-03-24 21:43:26 +00:00
|
|
|
/// <C as WhereTrait>::Item: DerivedTrait + B1 + ... + BN,
|
|
|
|
/// ...
|
|
|
|
/// {
|
|
|
|
/// ...
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// where B1, ..., BN are the bounds given by `bounds_paths`.'. Z is a phantom type, and
|
|
|
|
/// therefore does not get bound by the derived trait.
|
2013-12-07 00:57:44 +00:00
|
|
|
fn create_derived_impl(
|
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2014-02-14 16:09:51 +00:00
|
|
|
type_ident: Ident,
|
|
|
|
generics: &Generics,
|
2015-03-24 21:43:26 +00:00
|
|
|
field_tys: Vec<P<ast::Ty>>,
|
2019-12-12 05:41:18 +00:00
|
|
|
methods: Vec<P<ast::AssocItem>>,
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
is_packed: bool,
|
2016-07-19 17:32:06 +00:00
|
|
|
) -> P<ast::Item> {
|
2013-12-07 00:57:44 +00:00
|
|
|
let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2019-12-07 23:08:09 +00:00
|
|
|
// Transform associated types from `deriving::ty::Ty` into `ast::AssocItem`
|
2019-12-12 05:41:18 +00:00
|
|
|
let associated_types = self.associated_types.iter().map(|&(ident, ref type_def)| {
|
|
|
|
P(ast::AssocItem {
|
2015-01-25 05:29:24 +00:00
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
span: self.span,
|
2017-08-07 05:54:09 +00:00
|
|
|
ident,
|
2020-08-21 23:11:00 +00:00
|
|
|
vis: ast::Visibility {
|
|
|
|
span: self.span.shrink_to_lo(),
|
|
|
|
kind: ast::VisibilityKind::Inherited,
|
|
|
|
tokens: None,
|
|
|
|
},
|
2022-08-17 02:34:33 +00:00
|
|
|
attrs: ast::AttrVec::new(),
|
2022-10-10 02:05:24 +00:00
|
|
|
kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias {
|
2021-11-07 08:43:49 +00:00
|
|
|
defaultness: ast::Defaultness::Final,
|
|
|
|
generics: Generics::default(),
|
2021-10-19 22:45:48 +00:00
|
|
|
where_clauses: (
|
|
|
|
ast::TyAliasWhereClause::default(),
|
|
|
|
ast::TyAliasWhereClause::default(),
|
|
|
|
),
|
|
|
|
where_predicates_split: 0,
|
2021-11-07 08:43:49 +00:00
|
|
|
bounds: Vec::new(),
|
|
|
|
ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)),
|
|
|
|
})),
|
2017-07-12 16:50:05 +00:00
|
|
|
tokens: None,
|
2019-12-12 05:41:18 +00:00
|
|
|
})
|
|
|
|
});
|
2015-01-25 05:29:24 +00:00
|
|
|
|
2022-11-14 04:43:10 +00:00
|
|
|
let mut where_clause = ast::WhereClause::default();
|
2021-11-03 04:19:06 +00:00
|
|
|
where_clause.span = generics.where_clause.span;
|
2021-11-20 18:46:36 +00:00
|
|
|
let ctxt = self.span.ctxt();
|
|
|
|
let span = generics.span.with_ctxt(ctxt);
|
2014-03-19 12:16:56 +00:00
|
|
|
|
2017-10-16 19:07:26 +00:00
|
|
|
// Create the generic parameters
|
2022-11-21 22:17:20 +00:00
|
|
|
let params: ThinVec<_> = generics
|
2022-11-14 04:43:10 +00:00
|
|
|
.params
|
|
|
|
.iter()
|
|
|
|
.map(|param| match ¶m.kind {
|
|
|
|
GenericParamKind::Lifetime { .. } => param.clone(),
|
|
|
|
GenericParamKind::Type { .. } => {
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
// Extra restrictions on the generics parameters to the
|
|
|
|
// type being derived upon.
|
|
|
|
let bounds: Vec<_> = self
|
|
|
|
.additional_bounds
|
|
|
|
.iter()
|
2023-02-07 20:59:48 +00:00
|
|
|
.map(|p| {
|
|
|
|
cx.trait_bound(
|
|
|
|
p.to_path(cx, self.span, type_ident, generics),
|
|
|
|
self.is_const,
|
|
|
|
)
|
|
|
|
})
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
.chain(
|
|
|
|
// Add a bound for the current trait.
|
|
|
|
self.skip_path_as_bound
|
|
|
|
.not()
|
2023-02-07 20:59:48 +00:00
|
|
|
.then(|| cx.trait_bound(trait_path.clone(), self.is_const)),
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
)
|
|
|
|
.chain({
|
|
|
|
// Add a `Copy` bound if required.
|
|
|
|
if is_packed && self.needs_copy_as_bound_if_packed {
|
|
|
|
let p = deriving::path_std!(marker::Copy);
|
2023-02-07 20:59:48 +00:00
|
|
|
Some(cx.trait_bound(
|
|
|
|
p.to_path(cx, self.span, type_ident, generics),
|
|
|
|
self.is_const,
|
|
|
|
))
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.chain(
|
|
|
|
// Also add in any bounds from the declaration.
|
|
|
|
param.bounds.iter().cloned(),
|
|
|
|
)
|
|
|
|
.collect();
|
2018-05-27 00:43:03 +00:00
|
|
|
|
2022-11-14 04:43:10 +00:00
|
|
|
cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None)
|
|
|
|
}
|
|
|
|
GenericParamKind::Const { ty, kw_span, .. } => {
|
|
|
|
let const_nodefault_kind = GenericParamKind::Const {
|
|
|
|
ty: ty.clone(),
|
|
|
|
kw_span: kw_span.with_ctxt(ctxt),
|
|
|
|
|
|
|
|
// We can't have default values inside impl block
|
|
|
|
default: None,
|
|
|
|
};
|
|
|
|
let mut param_clone = param.clone();
|
|
|
|
param_clone.kind = const_nodefault_kind;
|
|
|
|
param_clone
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
2014-12-14 05:35:35 +00:00
|
|
|
|
|
|
|
// and similarly for where clauses
|
|
|
|
where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| {
|
2021-11-17 23:47:47 +00:00
|
|
|
match clause {
|
2021-11-20 18:46:36 +00:00
|
|
|
ast::WherePredicate::BoundPredicate(wb) => {
|
|
|
|
let span = wb.span.with_ctxt(ctxt);
|
|
|
|
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
|
|
|
|
span,
|
|
|
|
..wb.clone()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
ast::WherePredicate::RegionPredicate(wr) => {
|
|
|
|
let span = wr.span.with_ctxt(ctxt);
|
|
|
|
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
|
|
|
|
span,
|
|
|
|
..wr.clone()
|
|
|
|
})
|
|
|
|
}
|
2021-11-17 23:47:47 +00:00
|
|
|
ast::WherePredicate::EqPredicate(we) => {
|
2021-11-20 18:46:36 +00:00
|
|
|
let span = we.span.with_ctxt(ctxt);
|
2022-07-29 00:16:25 +00:00
|
|
|
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { span, ..we.clone() })
|
2014-12-14 05:35:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
|
2023-10-22 19:08:20 +00:00
|
|
|
let ty_param_names: Vec<Symbol> = params
|
2023-10-22 19:05:45 +00:00
|
|
|
.iter()
|
|
|
|
.filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
|
2023-10-22 19:08:20 +00:00
|
|
|
.map(|ty_param| ty_param.ident.name)
|
|
|
|
.collect();
|
2023-10-22 19:05:45 +00:00
|
|
|
|
2023-10-22 19:08:20 +00:00
|
|
|
if !ty_param_names.is_empty() {
|
2023-10-22 19:05:45 +00:00
|
|
|
for field_ty in field_tys {
|
|
|
|
let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx);
|
|
|
|
|
|
|
|
for field_ty_param in field_ty_params {
|
|
|
|
// if we have already handled this type, skip it
|
|
|
|
if let ast::TyKind::Path(_, p) = &field_ty_param.ty.kind
|
|
|
|
&& let [sole_segment] = &*p.segments
|
|
|
|
&& ty_param_names.contains(&sole_segment.ident.name)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let mut bounds: Vec<_> = self
|
|
|
|
.additional_bounds
|
|
|
|
.iter()
|
|
|
|
.map(|p| {
|
|
|
|
cx.trait_bound(
|
2023-02-07 20:59:48 +00:00
|
|
|
p.to_path(cx, self.span, type_ident, generics),
|
|
|
|
self.is_const,
|
2023-10-22 19:05:45 +00:00
|
|
|
)
|
|
|
|
})
|
|
|
|
.collect();
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
|
2023-10-22 19:05:45 +00:00
|
|
|
// Require the current trait.
|
|
|
|
if !self.skip_path_as_bound {
|
|
|
|
bounds.push(cx.trait_bound(trait_path.clone(), self.is_const));
|
|
|
|
}
|
2015-03-24 21:43:26 +00:00
|
|
|
|
2023-10-22 19:05:45 +00:00
|
|
|
// Add a `Copy` bound if required.
|
|
|
|
if is_packed && self.needs_copy_as_bound_if_packed {
|
|
|
|
let p = deriving::path_std!(marker::Copy);
|
|
|
|
bounds.push(cx.trait_bound(
|
|
|
|
p.to_path(cx, self.span, type_ident, generics),
|
|
|
|
self.is_const,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
if !bounds.is_empty() {
|
|
|
|
let predicate = ast::WhereBoundPredicate {
|
|
|
|
span: self.span,
|
|
|
|
bound_generic_params: field_ty_param.bound_generic_params,
|
|
|
|
bounded_ty: field_ty_param.ty,
|
|
|
|
bounds,
|
|
|
|
};
|
|
|
|
|
|
|
|
let predicate = ast::WherePredicate::BoundPredicate(predicate);
|
|
|
|
where_clause.predicates.push(predicate);
|
2017-10-16 19:07:26 +00:00
|
|
|
}
|
2015-03-24 21:43:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-19 12:16:56 +00:00
|
|
|
let trait_generics = Generics { params, where_clause, span };
|
2013-06-07 07:30:38 +00:00
|
|
|
|
|
|
|
// Create the reference to the trait.
|
|
|
|
let trait_ref = cx.trait_ref(trait_path);
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2018-05-27 20:54:10 +00:00
|
|
|
let self_params: Vec<_> = generics
|
|
|
|
.params
|
|
|
|
.iter()
|
|
|
|
.map(|param| match param.kind {
|
2018-05-30 15:49:39 +00:00
|
|
|
GenericParamKind::Lifetime { .. } => {
|
2021-11-20 18:46:36 +00:00
|
|
|
GenericArg::Lifetime(cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident))
|
2018-05-27 20:54:10 +00:00
|
|
|
}
|
|
|
|
GenericParamKind::Type { .. } => {
|
2021-11-20 18:46:36 +00:00
|
|
|
GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident))
|
2018-05-27 20:54:10 +00:00
|
|
|
}
|
2019-02-05 15:50:00 +00:00
|
|
|
GenericParamKind::Const { .. } => {
|
2021-11-20 18:46:36 +00:00
|
|
|
GenericArg::Const(cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident))
|
2019-02-05 15:50:00 +00:00
|
|
|
}
|
2018-05-27 20:54:10 +00:00
|
|
|
})
|
|
|
|
.collect();
|
2018-02-08 08:58:13 +00:00
|
|
|
|
2013-06-07 07:30:38 +00:00
|
|
|
// Create the type of `self`.
|
2019-09-21 19:01:10 +00:00
|
|
|
let path = cx.path_all(self.span, false, vec![type_ident], self_params);
|
2018-05-27 20:54:10 +00:00
|
|
|
let self_type = cx.ty_path(path);
|
2016-07-19 17:32:06 +00:00
|
|
|
|
2023-02-16 17:17:55 +00:00
|
|
|
let attrs = thin_vec![cx.attr_word(sym::automatically_derived, self.span),];
|
2014-02-14 05:07:09 +00:00
|
|
|
let opt_trait_ref = Some(trait_ref);
|
2020-05-07 05:23:44 +00:00
|
|
|
|
2016-07-19 17:32:06 +00:00
|
|
|
cx.item(
|
|
|
|
self.span,
|
2021-10-17 20:20:30 +00:00
|
|
|
Ident::empty(),
|
2022-08-17 02:20:25 +00:00
|
|
|
attrs,
|
2021-11-07 08:43:49 +00:00
|
|
|
ast::ItemKind::Impl(Box::new(ast::Impl {
|
2022-06-28 01:44:37 +00:00
|
|
|
unsafety: ast::Unsafe::No,
|
2020-01-14 04:30:20 +00:00
|
|
|
polarity: ast::ImplPolarity::Positive,
|
|
|
|
defaultness: ast::Defaultness::Final,
|
2022-09-20 11:55:07 +00:00
|
|
|
constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No },
|
2020-01-14 04:30:20 +00:00
|
|
|
generics: trait_generics,
|
|
|
|
of_trait: opt_trait_ref,
|
|
|
|
self_ty: self_type,
|
|
|
|
items: methods.into_iter().chain(associated_types).collect(),
|
2021-08-05 01:53:21 +00:00
|
|
|
})),
|
2016-07-19 17:32:06 +00:00
|
|
|
)
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
2014-02-22 05:33:23 +00:00
|
|
|
fn expand_struct_def(
|
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2015-10-08 00:20:57 +00:00
|
|
|
struct_def: &'a VariantData,
|
2014-02-22 05:33:23 +00:00
|
|
|
type_ident: Ident,
|
2016-08-26 16:23:42 +00:00
|
|
|
generics: &Generics,
|
2017-10-02 13:15:23 +00:00
|
|
|
from_scratch: bool,
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
is_packed: bool,
|
2016-07-19 17:32:06 +00:00
|
|
|
) -> P<ast::Item> {
|
|
|
|
let field_tys: Vec<P<ast::Ty>> =
|
2016-04-06 08:19:10 +00:00
|
|
|
struct_def.fields().iter().map(|field| field.ty.clone()).collect();
|
2019-12-22 22:42:04 +00:00
|
|
|
|
2016-07-19 17:32:06 +00:00
|
|
|
let methods = self
|
|
|
|
.methods
|
|
|
|
.iter()
|
|
|
|
.map(|method_def| {
|
2022-07-04 22:25:47 +00:00
|
|
|
let (explicit_self, selflike_args, nonselflike_args, nonself_arg_tys) =
|
|
|
|
method_def.extract_arg_details(cx, self, type_ident, generics);
|
2016-07-19 17:32:06 +00:00
|
|
|
|
2016-08-26 16:23:42 +00:00
|
|
|
let body = if from_scratch || method_def.is_static() {
|
2016-07-19 17:32:06 +00:00
|
|
|
method_def.expand_static_struct_method_body(
|
|
|
|
cx,
|
|
|
|
self,
|
|
|
|
struct_def,
|
|
|
|
type_ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
&nonselflike_args,
|
2016-07-19 17:32:06 +00:00
|
|
|
)
|
|
|
|
} else {
|
|
|
|
method_def.expand_struct_method_body(
|
|
|
|
cx,
|
|
|
|
self,
|
|
|
|
struct_def,
|
|
|
|
type_ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
&selflike_args,
|
|
|
|
&nonselflike_args,
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
is_packed,
|
2017-10-02 13:15:23 +00:00
|
|
|
)
|
2016-07-19 17:32:06 +00:00
|
|
|
};
|
|
|
|
|
2022-07-04 22:25:47 +00:00
|
|
|
method_def.create_method(
|
|
|
|
cx,
|
|
|
|
self,
|
|
|
|
type_ident,
|
|
|
|
generics,
|
|
|
|
explicit_self,
|
|
|
|
nonself_arg_tys,
|
|
|
|
body,
|
|
|
|
)
|
2016-07-19 17:32:06 +00:00
|
|
|
})
|
|
|
|
.collect();
|
2013-03-28 10:50:10 +00:00
|
|
|
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed)
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
2014-02-22 05:33:23 +00:00
|
|
|
fn expand_enum_def(
|
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2015-05-01 01:10:06 +00:00
|
|
|
enum_def: &'a EnumDef,
|
2013-09-02 00:50:59 +00:00
|
|
|
type_ident: Ident,
|
2016-08-26 16:23:42 +00:00
|
|
|
generics: &Generics,
|
|
|
|
from_scratch: bool,
|
2016-07-19 17:32:06 +00:00
|
|
|
) -> P<ast::Item> {
|
2015-03-24 21:43:26 +00:00
|
|
|
let mut field_tys = Vec::new();
|
|
|
|
|
2015-06-10 16:22:20 +00:00
|
|
|
for variant in &enum_def.variants {
|
2016-04-06 08:19:10 +00:00
|
|
|
field_tys.extend(variant.data.fields().iter().map(|field| field.ty.clone()));
|
2015-03-24 21:43:26 +00:00
|
|
|
}
|
|
|
|
|
2016-07-19 17:32:06 +00:00
|
|
|
let methods = self
|
|
|
|
.methods
|
|
|
|
.iter()
|
|
|
|
.map(|method_def| {
|
2022-07-04 22:25:47 +00:00
|
|
|
let (explicit_self, selflike_args, nonselflike_args, nonself_arg_tys) =
|
|
|
|
method_def.extract_arg_details(cx, self, type_ident, generics);
|
2016-07-19 17:32:06 +00:00
|
|
|
|
2016-08-26 16:23:42 +00:00
|
|
|
let body = if from_scratch || method_def.is_static() {
|
2016-07-19 17:32:06 +00:00
|
|
|
method_def.expand_static_enum_method_body(
|
|
|
|
cx,
|
|
|
|
self,
|
|
|
|
enum_def,
|
|
|
|
type_ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
&nonselflike_args,
|
2016-07-19 17:32:06 +00:00
|
|
|
)
|
|
|
|
} else {
|
|
|
|
method_def.expand_enum_method_body(
|
|
|
|
cx,
|
|
|
|
self,
|
|
|
|
enum_def,
|
|
|
|
type_ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
selflike_args,
|
|
|
|
&nonselflike_args,
|
2016-07-19 17:32:06 +00:00
|
|
|
)
|
|
|
|
};
|
|
|
|
|
2022-07-04 22:25:47 +00:00
|
|
|
method_def.create_method(
|
|
|
|
cx,
|
|
|
|
self,
|
|
|
|
type_ident,
|
|
|
|
generics,
|
|
|
|
explicit_self,
|
|
|
|
nonself_arg_tys,
|
|
|
|
body,
|
|
|
|
)
|
2016-07-19 17:32:06 +00:00
|
|
|
})
|
|
|
|
.collect();
|
2013-03-28 10:50:10 +00:00
|
|
|
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
let is_packed = false; // enums are never packed
|
|
|
|
self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed)
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-10 07:16:18 +00:00
|
|
|
impl<'a> MethodDef<'a> {
|
2013-03-28 10:50:10 +00:00
|
|
|
fn call_substructure_method(
|
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
trait_: &TraitDef<'_>,
|
2013-09-02 00:50:59 +00:00
|
|
|
type_ident: Ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
nonselflike_args: &[P<Expr>],
|
2019-02-04 12:49:54 +00:00
|
|
|
fields: &SubstructureFields<'_>,
|
2022-06-28 03:10:36 +00:00
|
|
|
) -> BlockOrExpr {
|
2021-11-20 18:46:36 +00:00
|
|
|
let span = trait_.span;
|
2022-07-04 22:25:47 +00:00
|
|
|
let substructure = Substructure { type_ident, nonselflike_args, fields };
|
2014-04-22 06:25:18 +00:00
|
|
|
let mut f = self.combine_substructure.borrow_mut();
|
2019-02-04 12:49:54 +00:00
|
|
|
let f: &mut CombineSubstructureFunc<'_> = &mut *f;
|
2021-11-20 18:46:36 +00:00
|
|
|
f(cx, span, &substructure)
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
2014-02-09 00:39:53 +00:00
|
|
|
fn get_ret_ty(
|
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
trait_: &TraitDef<'_>,
|
2014-02-09 00:39:53 +00:00
|
|
|
generics: &Generics,
|
|
|
|
type_ident: Ident,
|
|
|
|
) -> P<ast::Ty> {
|
|
|
|
self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
|
2013-05-06 15:23:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn is_static(&self) -> bool {
|
2022-06-29 23:15:07 +00:00
|
|
|
!self.explicit_self
|
2013-05-06 15:23:51 +00:00
|
|
|
}
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2022-07-04 22:25:47 +00:00
|
|
|
// The return value includes:
|
|
|
|
// - explicit_self: The `&self` arg, if present.
|
|
|
|
// - selflike_args: Expressions for `&self` (if present) and also any other
|
|
|
|
// args with the same type (e.g. the `other` arg in `PartialEq::eq`).
|
|
|
|
// - nonselflike_args: Expressions for all the remaining args.
|
|
|
|
// - nonself_arg_tys: Additional information about all the args other than
|
|
|
|
// `&self`.
|
|
|
|
fn extract_arg_details(
|
2016-07-19 17:32:06 +00:00
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
trait_: &TraitDef<'_>,
|
2016-07-19 17:32:06 +00:00
|
|
|
type_ident: Ident,
|
|
|
|
generics: &Generics,
|
2022-11-23 00:55:16 +00:00
|
|
|
) -> (Option<ast::ExplicitSelf>, ThinVec<P<Expr>>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) {
|
|
|
|
let mut selflike_args = ThinVec::new();
|
2022-07-04 22:25:47 +00:00
|
|
|
let mut nonselflike_args = Vec::new();
|
|
|
|
let mut nonself_arg_tys = Vec::new();
|
2021-11-20 18:46:36 +00:00
|
|
|
let span = trait_.span;
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2023-02-15 11:43:41 +00:00
|
|
|
let explicit_self = self.explicit_self.then(|| {
|
2022-06-29 23:15:07 +00:00
|
|
|
let (self_expr, explicit_self) = ty::get_explicit_self(cx, span);
|
2022-07-04 22:25:47 +00:00
|
|
|
selflike_args.push(self_expr);
|
2023-02-15 11:43:41 +00:00
|
|
|
explicit_self
|
|
|
|
});
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2022-07-04 22:25:47 +00:00
|
|
|
for (ty, name) in self.nonself_args.iter() {
|
2021-11-20 18:46:36 +00:00
|
|
|
let ast_ty = ty.to_ty(cx, span, type_ident, generics);
|
|
|
|
let ident = Ident::new(*name, span);
|
2022-07-04 22:25:47 +00:00
|
|
|
nonself_arg_tys.push((ident, ast_ty));
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2021-11-20 18:46:36 +00:00
|
|
|
let arg_expr = cx.expr_ident(span, ident);
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2022-07-07 21:57:34 +00:00
|
|
|
match ty {
|
|
|
|
// Selflike (`&Self`) arguments only occur in non-static methods.
|
2022-07-06 06:13:51 +00:00
|
|
|
Ref(box Self_, _) if !self.is_static() => selflike_args.push(arg_expr),
|
2022-07-04 22:25:47 +00:00
|
|
|
Self_ => cx.span_bug(span, "`Self` in non-return position"),
|
|
|
|
_ => nonselflike_args.push(arg_expr),
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
}
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2022-07-04 22:25:47 +00:00
|
|
|
(explicit_self, selflike_args, nonselflike_args, nonself_arg_tys)
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
2014-02-09 00:39:53 +00:00
|
|
|
fn create_method(
|
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
trait_: &TraitDef<'_>,
|
2013-09-02 00:50:59 +00:00
|
|
|
type_ident: Ident,
|
2013-05-06 15:23:51 +00:00
|
|
|
generics: &Generics,
|
2016-03-06 12:54:44 +00:00
|
|
|
explicit_self: Option<ast::ExplicitSelf>,
|
2022-07-04 22:25:47 +00:00
|
|
|
nonself_arg_tys: Vec<(Ident, P<ast::Ty>)>,
|
2022-06-28 03:10:36 +00:00
|
|
|
body: BlockOrExpr,
|
2019-12-12 05:41:18 +00:00
|
|
|
) -> P<ast::AssocItem> {
|
2021-11-20 18:46:36 +00:00
|
|
|
let span = trait_.span;
|
2019-02-28 22:43:53 +00:00
|
|
|
// Create the generics that aren't for `Self`.
|
2021-11-20 18:46:36 +00:00
|
|
|
let fn_generics = self.generics.to_generics(cx, span, type_ident, generics);
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2014-02-09 12:37:33 +00:00
|
|
|
let args = {
|
2022-07-04 22:25:47 +00:00
|
|
|
let self_arg = explicit_self.map(|explicit_self| {
|
2021-11-20 18:46:36 +00:00
|
|
|
let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(span);
|
2019-12-03 15:38:34 +00:00
|
|
|
ast::Param::from_self(ast::AttrVec::default(), explicit_self, ident)
|
2016-03-06 12:54:44 +00:00
|
|
|
});
|
2022-07-04 22:25:47 +00:00
|
|
|
let nonself_args =
|
|
|
|
nonself_arg_tys.into_iter().map(|(name, ty)| cx.param(span, name, ty));
|
|
|
|
self_arg.into_iter().chain(nonself_args).collect()
|
2014-02-09 12:37:33 +00:00
|
|
|
};
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2014-02-09 00:39:53 +00:00
|
|
|
let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2021-11-20 18:46:36 +00:00
|
|
|
let method_ident = Ident::new(self.name, span);
|
2020-02-15 03:10:59 +00:00
|
|
|
let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
|
2022-06-28 03:10:36 +00:00
|
|
|
let body_block = body.into_block(cx, span);
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2021-11-20 18:46:36 +00:00
|
|
|
let trait_lo_sp = span.shrink_to_lo();
|
2019-10-27 22:14:35 +00:00
|
|
|
|
2022-06-28 01:44:37 +00:00
|
|
|
let sig = ast::FnSig { header: ast::FnHeader::default(), decl: fn_decl, span };
|
2021-11-07 08:43:49 +00:00
|
|
|
let defaultness = ast::Defaultness::Final;
|
2019-10-27 22:14:35 +00:00
|
|
|
|
2013-03-28 10:50:10 +00:00
|
|
|
// Create the method.
|
2019-12-12 05:41:18 +00:00
|
|
|
P(ast::AssocItem {
|
2013-09-07 02:11:55 +00:00
|
|
|
id: ast::DUMMY_NODE_ID,
|
2015-03-10 10:28:44 +00:00
|
|
|
attrs: self.attributes.clone(),
|
2021-11-20 18:46:36 +00:00
|
|
|
span,
|
2020-08-21 23:11:00 +00:00
|
|
|
vis: ast::Visibility {
|
|
|
|
span: trait_lo_sp,
|
|
|
|
kind: ast::VisibilityKind::Inherited,
|
|
|
|
tokens: None,
|
|
|
|
},
|
2015-03-10 10:28:44 +00:00
|
|
|
ident: method_ident,
|
2021-11-07 08:43:49 +00:00
|
|
|
kind: ast::AssocItemKind::Fn(Box::new(ast::Fn {
|
|
|
|
defaultness,
|
2021-08-05 01:53:21 +00:00
|
|
|
sig,
|
2021-11-07 08:43:49 +00:00
|
|
|
generics: fn_generics,
|
|
|
|
body: Some(body_block),
|
|
|
|
})),
|
2017-07-12 16:50:05 +00:00
|
|
|
tokens: None,
|
2019-12-12 05:41:18 +00:00
|
|
|
})
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
Don't use match-destructuring for derived ops on structs.
All derive ops currently use match-destructuring to access fields. This
is reasonable for enums, but sub-optimal for structs. E.g.:
```
fn eq(&self, other: &Point) -> bool {
match *other {
Self { x: ref __self_1_0, y: ref __self_1_1 } =>
match *self {
Self { x: ref __self_0_0, y: ref __self_0_1 } =>
(*__self_0_0) == (*__self_1_0) &&
(*__self_0_1) == (*__self_1_1),
},
}
}
```
This commit changes derive ops on structs to use field access instead, e.g.:
```
fn eq(&self, other: &Point) -> bool {
self.x == other.x && self.y == other.y
}
```
This is faster to compile, results in smaller binaries, and is simpler to
generate. Unfortunately, we have to keep the old pattern generating code around
for `repr(packed)` structs because something like `&self.x` (which doesn't show
up in `PartialEq` ops, but does show up in `Debug` and `Hash` ops) isn't
allowed. But this commit at least changes those cases to use let-destructuring
instead of match-destructuring, e.g.:
```
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
{
let Self(ref __self_0_0) = *self;
{ ::core::hash::Hash::hash(&(*__self_0_0), state) }
}
}
```
There are some unnecessary blocks remaining in the generated code, but I
will fix them in a follow-up PR.
2022-06-24 00:20:54 +00:00
|
|
|
/// The normal case uses field access.
|
2023-10-22 19:04:50 +00:00
|
|
|
///
|
2017-06-20 07:15:16 +00:00
|
|
|
/// ```
|
2014-12-31 04:25:18 +00:00
|
|
|
/// #[derive(PartialEq)]
|
2017-06-20 07:15:16 +00:00
|
|
|
/// # struct Dummy;
|
2022-07-07 01:09:07 +00:00
|
|
|
/// struct A { x: u8, y: u8 }
|
2014-09-16 11:27:34 +00:00
|
|
|
///
|
|
|
|
/// // equivalent to:
|
|
|
|
/// impl PartialEq for A {
|
2018-04-19 19:17:06 +00:00
|
|
|
/// fn eq(&self, other: &A) -> bool {
|
Don't use match-destructuring for derived ops on structs.
All derive ops currently use match-destructuring to access fields. This
is reasonable for enums, but sub-optimal for structs. E.g.:
```
fn eq(&self, other: &Point) -> bool {
match *other {
Self { x: ref __self_1_0, y: ref __self_1_1 } =>
match *self {
Self { x: ref __self_0_0, y: ref __self_0_1 } =>
(*__self_0_0) == (*__self_1_0) &&
(*__self_0_1) == (*__self_1_1),
},
}
}
```
This commit changes derive ops on structs to use field access instead, e.g.:
```
fn eq(&self, other: &Point) -> bool {
self.x == other.x && self.y == other.y
}
```
This is faster to compile, results in smaller binaries, and is simpler to
generate. Unfortunately, we have to keep the old pattern generating code around
for `repr(packed)` structs because something like `&self.x` (which doesn't show
up in `PartialEq` ops, but does show up in `Debug` and `Hash` ops) isn't
allowed. But this commit at least changes those cases to use let-destructuring
instead of match-destructuring, e.g.:
```
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
{
let Self(ref __self_0_0) = *self;
{ ::core::hash::Hash::hash(&(*__self_0_0), state) }
}
}
```
There are some unnecessary blocks remaining in the generated code, but I
will fix them in a follow-up PR.
2022-06-24 00:20:54 +00:00
|
|
|
/// self.x == other.x && self.y == other.y
|
2014-09-16 11:27:34 +00:00
|
|
|
/// }
|
|
|
|
/// }
|
2022-04-15 22:04:34 +00:00
|
|
|
/// ```
|
2023-10-22 19:04:50 +00:00
|
|
|
///
|
Don't use match-destructuring for derived ops on structs.
All derive ops currently use match-destructuring to access fields. This
is reasonable for enums, but sub-optimal for structs. E.g.:
```
fn eq(&self, other: &Point) -> bool {
match *other {
Self { x: ref __self_1_0, y: ref __self_1_1 } =>
match *self {
Self { x: ref __self_0_0, y: ref __self_0_1 } =>
(*__self_0_0) == (*__self_1_0) &&
(*__self_0_1) == (*__self_1_1),
},
}
}
```
This commit changes derive ops on structs to use field access instead, e.g.:
```
fn eq(&self, other: &Point) -> bool {
self.x == other.x && self.y == other.y
}
```
This is faster to compile, results in smaller binaries, and is simpler to
generate. Unfortunately, we have to keep the old pattern generating code around
for `repr(packed)` structs because something like `&self.x` (which doesn't show
up in `PartialEq` ops, but does show up in `Debug` and `Hash` ops) isn't
allowed. But this commit at least changes those cases to use let-destructuring
instead of match-destructuring, e.g.:
```
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
{
let Self(ref __self_0_0) = *self;
{ ::core::hash::Hash::hash(&(*__self_0_0), state) }
}
}
```
There are some unnecessary blocks remaining in the generated code, but I
will fix them in a follow-up PR.
2022-06-24 00:20:54 +00:00
|
|
|
/// But if the struct is `repr(packed)`, we can't use something like
|
2022-07-11 02:54:52 +00:00
|
|
|
/// `&self.x` because that might cause an unaligned ref. So for any trait
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
/// method that takes a reference, we use a local block to force a copy.
|
|
|
|
/// This requires that the field impl `Copy`.
|
2023-10-22 19:04:50 +00:00
|
|
|
///
|
2023-05-06 21:12:29 +00:00
|
|
|
/// ```rust,ignore (example)
|
2022-07-07 01:09:07 +00:00
|
|
|
/// # struct A { x: u8, y: u8 }
|
2017-10-02 13:15:23 +00:00
|
|
|
/// impl PartialEq for A {
|
2018-04-19 19:17:06 +00:00
|
|
|
/// fn eq(&self, other: &A) -> bool {
|
2022-07-11 02:54:52 +00:00
|
|
|
/// // Desugars to `{ self.x }.eq(&{ other.y }) && ...`
|
|
|
|
/// { self.x } == { other.y } && { self.y } == { other.y }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// impl Hash for A {
|
|
|
|
/// fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
|
|
|
|
/// ::core::hash::Hash::hash(&{ self.x }, state);
|
2023-10-22 19:04:50 +00:00
|
|
|
/// ::core::hash::Hash::hash(&{ self.y }, state);
|
2017-10-02 13:15:23 +00:00
|
|
|
/// }
|
|
|
|
/// }
|
2023-03-04 03:25:36 +00:00
|
|
|
/// ```
|
2015-05-01 01:10:06 +00:00
|
|
|
fn expand_struct_method_body<'b>(
|
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2016-07-19 17:32:06 +00:00
|
|
|
trait_: &TraitDef<'b>,
|
|
|
|
struct_def: &'b VariantData,
|
|
|
|
type_ident: Ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
selflike_args: &[P<Expr>],
|
|
|
|
nonselflike_args: &[P<Expr>],
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
is_packed: bool,
|
2022-06-28 03:10:36 +00:00
|
|
|
) -> BlockOrExpr {
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
assert!(selflike_args.len() == 1 || selflike_args.len() == 2);
|
|
|
|
|
2022-11-21 00:48:25 +00:00
|
|
|
let selflike_fields =
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, is_packed);
|
2022-11-21 00:48:25 +00:00
|
|
|
self.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
|
|
|
nonselflike_args,
|
|
|
|
&Struct(struct_def, selflike_fields),
|
|
|
|
)
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
2013-05-06 15:23:51 +00:00
|
|
|
fn expand_static_struct_method_body(
|
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
trait_: &TraitDef<'_>,
|
2015-10-08 00:20:57 +00:00
|
|
|
struct_def: &VariantData,
|
2013-09-02 00:50:59 +00:00
|
|
|
type_ident: Ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
nonselflike_args: &[P<Expr>],
|
2022-06-28 03:10:36 +00:00
|
|
|
) -> BlockOrExpr {
|
2014-02-09 00:39:53 +00:00
|
|
|
let summary = trait_.summarise_struct(cx, struct_def);
|
2013-03-28 10:50:10 +00:00
|
|
|
|
2014-02-09 00:39:53 +00:00
|
|
|
self.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
2013-05-06 15:23:51 +00:00
|
|
|
type_ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
nonselflike_args,
|
2013-05-06 15:23:51 +00:00
|
|
|
&StaticStruct(struct_def, summary),
|
|
|
|
)
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
2017-06-20 07:15:16 +00:00
|
|
|
/// ```
|
2014-12-31 04:25:18 +00:00
|
|
|
/// #[derive(PartialEq)]
|
2017-06-20 07:15:16 +00:00
|
|
|
/// # struct Dummy;
|
2014-09-16 11:27:34 +00:00
|
|
|
/// enum A {
|
|
|
|
/// A1,
|
2015-01-17 23:55:21 +00:00
|
|
|
/// A2(i32)
|
2014-09-16 11:27:34 +00:00
|
|
|
/// }
|
2022-06-22 05:26:47 +00:00
|
|
|
/// ```
|
2023-10-22 19:04:50 +00:00
|
|
|
///
|
2022-06-22 05:26:47 +00:00
|
|
|
/// is equivalent to:
|
2023-10-22 19:04:50 +00:00
|
|
|
///
|
2022-06-22 05:26:47 +00:00
|
|
|
/// ```
|
2022-09-16 11:10:25 +00:00
|
|
|
/// #![feature(core_intrinsics)]
|
|
|
|
/// enum A {
|
|
|
|
/// A1,
|
|
|
|
/// A2(i32)
|
|
|
|
/// }
|
2022-06-22 05:26:47 +00:00
|
|
|
/// impl ::core::cmp::PartialEq for A {
|
|
|
|
/// #[inline]
|
2022-04-15 22:04:34 +00:00
|
|
|
/// fn eq(&self, other: &A) -> bool {
|
2022-07-08 05:16:14 +00:00
|
|
|
/// let __self_tag = ::core::intrinsics::discriminant_value(self);
|
|
|
|
/// let __arg1_tag = ::core::intrinsics::discriminant_value(other);
|
2023-10-22 19:04:50 +00:00
|
|
|
/// __self_tag == __arg1_tag
|
|
|
|
/// && match (self, other) {
|
|
|
|
/// (A::A2(__self_0), A::A2(__arg1_0)) => *__self_0 == *__arg1_0,
|
2022-07-06 06:13:51 +00:00
|
|
|
/// _ => true,
|
2014-09-16 11:27:34 +00:00
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// ```
|
2023-10-22 19:04:50 +00:00
|
|
|
///
|
2022-07-08 05:32:27 +00:00
|
|
|
/// Creates a tag check combined with a match for a tuple of all
|
|
|
|
/// `selflike_args`, with an arm for each variant with fields, possibly an
|
2023-01-14 21:16:25 +00:00
|
|
|
/// arm for each fieldless variant (if `unify_fieldless_variants` is not
|
|
|
|
/// `Unify`), and possibly a default arm.
|
2022-06-22 05:26:47 +00:00
|
|
|
fn expand_enum_method_body<'b>(
|
2016-07-19 17:32:06 +00:00
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2016-07-19 17:32:06 +00:00
|
|
|
trait_: &TraitDef<'b>,
|
|
|
|
enum_def: &'b EnumDef,
|
|
|
|
type_ident: Ident,
|
2023-07-16 21:35:16 +00:00
|
|
|
mut selflike_args: ThinVec<P<Expr>>,
|
2022-07-04 22:25:47 +00:00
|
|
|
nonselflike_args: &[P<Expr>],
|
2022-06-28 03:10:36 +00:00
|
|
|
) -> BlockOrExpr {
|
2023-07-16 21:35:16 +00:00
|
|
|
assert!(
|
|
|
|
!selflike_args.is_empty(),
|
|
|
|
"static methods must use `expand_static_enum_method_body`",
|
|
|
|
);
|
|
|
|
|
2021-11-20 18:46:36 +00:00
|
|
|
let span = trait_.span;
|
2014-07-06 19:19:12 +00:00
|
|
|
let variants = &enum_def.variants;
|
|
|
|
|
2022-07-08 05:32:27 +00:00
|
|
|
// Traits that unify fieldless variants always use the tag(s).
|
2023-01-14 21:16:25 +00:00
|
|
|
let unify_fieldless_variants =
|
|
|
|
self.fieldless_variants_strategy == FieldlessVariantsStrategy::Unify;
|
2022-07-08 05:32:27 +00:00
|
|
|
|
2023-07-16 22:33:29 +00:00
|
|
|
// For zero-variant enum, this function body is unreachable. Generate
|
|
|
|
// `match *self {}`. This produces machine code identical to `unsafe {
|
|
|
|
// core::intrinsics::unreachable() }` while being safe and stable.
|
2022-07-08 05:31:09 +00:00
|
|
|
if variants.is_empty() {
|
2023-07-16 21:35:16 +00:00
|
|
|
selflike_args.truncate(1);
|
|
|
|
let match_arg = cx.expr_deref(span, selflike_args.pop().unwrap());
|
|
|
|
let match_arms = ThinVec::new();
|
|
|
|
let expr = cx.expr_match(span, match_arg, match_arms);
|
|
|
|
return BlockOrExpr(ThinVec::new(), Some(expr));
|
2022-07-08 05:31:09 +00:00
|
|
|
}
|
|
|
|
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
let prefixes = iter::once("__self".to_string())
|
2018-11-05 14:30:04 +00:00
|
|
|
.chain(
|
2022-07-04 22:25:47 +00:00
|
|
|
selflike_args
|
2018-11-05 14:30:04 +00:00
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.skip(1)
|
2023-07-25 20:00:13 +00:00
|
|
|
.map(|(arg_count, _selflike_arg)| format!("__arg{arg_count}")),
|
2018-11-05 14:30:04 +00:00
|
|
|
)
|
|
|
|
.collect::<Vec<String>>();
|
2019-12-22 22:42:04 +00:00
|
|
|
|
2022-07-08 05:32:27 +00:00
|
|
|
// Build a series of let statements mapping each selflike_arg
|
|
|
|
// to its discriminant value.
|
|
|
|
//
|
|
|
|
// e.g. for `PartialEq::eq` builds two statements:
|
|
|
|
// ```
|
|
|
|
// let __self_tag = ::core::intrinsics::discriminant_value(self);
|
|
|
|
// let __arg1_tag = ::core::intrinsics::discriminant_value(other);
|
|
|
|
// ```
|
|
|
|
let get_tag_pieces = |cx: &ExtCtxt<'_>| {
|
|
|
|
let tag_idents: Vec<_> = prefixes
|
|
|
|
.iter()
|
2023-07-25 20:00:13 +00:00
|
|
|
.map(|name| Ident::from_str_and_span(&format!("{name}_tag"), span))
|
2022-07-08 05:32:27 +00:00
|
|
|
.collect();
|
2014-07-06 19:19:12 +00:00
|
|
|
|
2022-07-08 05:32:27 +00:00
|
|
|
let mut tag_exprs: Vec<_> = tag_idents
|
|
|
|
.iter()
|
|
|
|
.map(|&ident| cx.expr_addr_of(span, cx.expr_ident(span, ident)))
|
|
|
|
.collect();
|
2014-07-06 19:19:12 +00:00
|
|
|
|
2022-07-08 05:32:27 +00:00
|
|
|
let self_expr = tag_exprs.remove(0);
|
|
|
|
let other_selflike_exprs = tag_exprs;
|
|
|
|
let tag_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs };
|
|
|
|
|
2023-01-30 03:13:27 +00:00
|
|
|
let tag_let_stmts: ThinVec<_> = iter::zip(&tag_idents, &selflike_args)
|
2022-07-08 05:32:27 +00:00
|
|
|
.map(|(&ident, selflike_arg)| {
|
|
|
|
let variant_value = deriving::call_intrinsic(
|
|
|
|
cx,
|
|
|
|
span,
|
|
|
|
sym::discriminant_value,
|
2022-11-23 00:55:16 +00:00
|
|
|
thin_vec![selflike_arg.clone()],
|
2022-07-08 05:32:27 +00:00
|
|
|
);
|
|
|
|
cx.stmt_let(span, false, ident, variant_value)
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
(tag_field, tag_let_stmts)
|
|
|
|
};
|
|
|
|
|
|
|
|
// There are some special cases involving fieldless enums where no
|
|
|
|
// match is necessary.
|
|
|
|
let all_fieldless = variants.iter().all(|v| v.data.fields().is_empty());
|
|
|
|
if all_fieldless {
|
2023-01-14 21:16:25 +00:00
|
|
|
if variants.len() > 1 {
|
|
|
|
match self.fieldless_variants_strategy {
|
|
|
|
FieldlessVariantsStrategy::Unify => {
|
|
|
|
// If the type is fieldless and the trait uses the tag and
|
|
|
|
// there are multiple variants, we need just an operation on
|
|
|
|
// the tag(s).
|
|
|
|
let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx);
|
|
|
|
let mut tag_check = self.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
|
|
|
nonselflike_args,
|
|
|
|
&EnumTag(tag_field, None),
|
|
|
|
);
|
|
|
|
tag_let_stmts.append(&mut tag_check.0);
|
|
|
|
return BlockOrExpr(tag_let_stmts, tag_check.1);
|
|
|
|
}
|
|
|
|
FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless => {
|
|
|
|
return self.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
|
|
|
nonselflike_args,
|
|
|
|
&AllFieldlessEnum(enum_def),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
FieldlessVariantsStrategy::Default => (),
|
|
|
|
}
|
|
|
|
} else if variants.len() == 1 {
|
2022-07-08 05:32:27 +00:00
|
|
|
// If there is a single variant, we don't need an operation on
|
|
|
|
// the tag(s). Just use the most degenerate result.
|
|
|
|
return self.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
|
|
|
nonselflike_args,
|
|
|
|
&EnumMatching(0, 1, &variants[0], Vec::new()),
|
|
|
|
);
|
2023-01-14 21:16:25 +00:00
|
|
|
}
|
2022-07-08 05:32:27 +00:00
|
|
|
}
|
2016-05-12 15:54:05 +00:00
|
|
|
|
2014-07-06 19:19:12 +00:00
|
|
|
// These arms are of the form:
|
|
|
|
// (Variant1, Variant1, ...) => Body1
|
|
|
|
// (Variant2, Variant2, ...) => Body2
|
|
|
|
// ...
|
2022-07-04 22:25:47 +00:00
|
|
|
// where each tuple has length = selflike_args.len()
|
2023-01-30 04:10:59 +00:00
|
|
|
let mut match_arms: ThinVec<ast::Arm> = variants
|
2016-07-19 17:32:06 +00:00
|
|
|
.iter()
|
|
|
|
.enumerate()
|
2023-01-14 21:16:25 +00:00
|
|
|
.filter(|&(_, v)| !(unify_fieldless_variants && v.data.fields().is_empty()))
|
2014-09-13 16:06:01 +00:00
|
|
|
.map(|(index, variant)| {
|
2014-07-06 19:19:12 +00:00
|
|
|
// A single arm has form (&VariantK, &VariantK, ...) => BodyK
|
|
|
|
// (see "Final wrinkle" note below for why.)
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
|
2022-11-14 02:59:54 +00:00
|
|
|
let fields = trait_.create_struct_pattern_fields(cx, &variant.data, &prefixes);
|
2022-07-06 06:13:51 +00:00
|
|
|
|
|
|
|
let sp = variant.span.with_ctxt(trait_.span.ctxt());
|
|
|
|
let variant_path = cx.path(sp, vec![type_ident, variant.ident]);
|
2022-08-30 22:34:35 +00:00
|
|
|
let by_ref = ByRef::No; // because enums can't be repr(packed)
|
2022-11-23 00:55:16 +00:00
|
|
|
let mut subpats = trait_.create_struct_patterns(
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
cx,
|
2022-07-06 06:13:51 +00:00
|
|
|
variant_path,
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
&variant.data,
|
|
|
|
&prefixes,
|
2022-08-30 22:34:35 +00:00
|
|
|
by_ref,
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
);
|
|
|
|
|
2022-07-08 05:32:27 +00:00
|
|
|
// `(VariantK, VariantK, ...)` or just `VariantK`.
|
2022-07-04 05:08:28 +00:00
|
|
|
let single_pat = if subpats.len() == 1 {
|
|
|
|
subpats.pop().unwrap()
|
|
|
|
} else {
|
|
|
|
cx.pat_tuple(span, subpats)
|
|
|
|
};
|
2014-07-06 19:19:12 +00:00
|
|
|
|
|
|
|
// For the BodyK, we need to delegate to our caller,
|
|
|
|
// passing it an EnumMatching to indicate which case
|
|
|
|
// we are in.
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
//
|
2014-07-06 19:19:12 +00:00
|
|
|
// Now, for some given VariantK, we have built up
|
|
|
|
// expressions for referencing every field of every
|
|
|
|
// Self arg, assuming all are instances of VariantK.
|
|
|
|
// Build up code associated with such a case.
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
let substructure = EnumMatching(index, variants.len(), variant, fields);
|
2022-06-28 03:10:36 +00:00
|
|
|
let arm_expr = self
|
2022-07-04 22:25:47 +00:00
|
|
|
.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
|
|
|
nonselflike_args,
|
|
|
|
&substructure,
|
|
|
|
)
|
2022-06-28 03:10:36 +00:00
|
|
|
.into_expr(cx, span);
|
2014-07-06 19:19:12 +00:00
|
|
|
|
2021-11-20 18:46:36 +00:00
|
|
|
cx.arm(span, single_pat, arm_expr)
|
2016-07-19 17:32:06 +00:00
|
|
|
})
|
|
|
|
.collect();
|
2016-05-12 15:54:05 +00:00
|
|
|
|
2022-07-08 05:32:27 +00:00
|
|
|
// Add a default arm to the match, if necessary.
|
|
|
|
let first_fieldless = variants.iter().find(|v| v.data.fields().is_empty());
|
2016-05-12 15:54:05 +00:00
|
|
|
let default = match first_fieldless {
|
2023-01-14 21:16:25 +00:00
|
|
|
Some(v) if unify_fieldless_variants => {
|
2022-07-08 05:32:27 +00:00
|
|
|
// We need a default case that handles all the fieldless
|
|
|
|
// variants. The index and actual variant aren't meaningful in
|
|
|
|
// this case, so just use dummy values.
|
2022-06-28 03:10:36 +00:00
|
|
|
Some(
|
|
|
|
self.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
nonselflike_args,
|
2022-07-08 05:32:27 +00:00
|
|
|
&EnumMatching(0, variants.len(), v, Vec::new()),
|
2022-06-28 03:10:36 +00:00
|
|
|
)
|
|
|
|
.into_expr(cx, span),
|
|
|
|
)
|
2016-05-12 15:54:05 +00:00
|
|
|
}
|
2022-07-04 22:25:47 +00:00
|
|
|
_ if variants.len() > 1 && selflike_args.len() > 1 => {
|
2022-07-08 05:32:27 +00:00
|
|
|
// Because we know that all the arguments will match if we reach
|
2016-05-12 15:54:05 +00:00
|
|
|
// the match expression we add the unreachable intrinsics as the
|
2022-07-08 05:32:27 +00:00
|
|
|
// result of the default which should help llvm in optimizing it.
|
2021-11-20 18:46:36 +00:00
|
|
|
Some(deriving::call_unreachable(cx, span))
|
2016-05-12 15:54:05 +00:00
|
|
|
}
|
2016-07-19 17:32:06 +00:00
|
|
|
_ => None,
|
2016-05-12 15:54:05 +00:00
|
|
|
};
|
|
|
|
if let Some(arm) = default {
|
2021-11-20 18:46:36 +00:00
|
|
|
match_arms.push(cx.arm(span, cx.pat_wild(span), arm));
|
2016-05-12 15:54:05 +00:00
|
|
|
}
|
|
|
|
|
2022-07-08 05:32:27 +00:00
|
|
|
// Create a match expression with one arm per discriminant plus
|
|
|
|
// possibly a default arm, e.g.:
|
|
|
|
// match (self, other) {
|
|
|
|
// (Variant1, Variant1, ...) => Body1
|
|
|
|
// (Variant2, Variant2, ...) => Body2,
|
|
|
|
// ...
|
2023-10-22 19:04:50 +00:00
|
|
|
// _ => ::core::intrinsics::unreachable(),
|
2022-07-08 05:32:27 +00:00
|
|
|
// }
|
2022-11-23 00:55:16 +00:00
|
|
|
let get_match_expr = |mut selflike_args: ThinVec<P<Expr>>| {
|
2022-07-04 22:25:47 +00:00
|
|
|
let match_arg = if selflike_args.len() == 1 {
|
|
|
|
selflike_args.pop().unwrap()
|
2022-07-04 05:08:28 +00:00
|
|
|
} else {
|
2022-07-04 22:25:47 +00:00
|
|
|
cx.expr(span, ast::ExprKind::Tup(selflike_args))
|
2022-07-04 05:08:28 +00:00
|
|
|
};
|
2022-07-08 05:32:27 +00:00
|
|
|
cx.expr_match(span, match_arg, match_arms)
|
|
|
|
};
|
|
|
|
|
|
|
|
// If the trait uses the tag and there are multiple variants, we need
|
|
|
|
// to add a tag check operation before the match. Otherwise, the match
|
|
|
|
// is enough.
|
2023-01-14 21:16:25 +00:00
|
|
|
if unify_fieldless_variants && variants.len() > 1 {
|
2022-07-08 05:32:27 +00:00
|
|
|
let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx);
|
|
|
|
|
|
|
|
// Combine a tag check with the match.
|
|
|
|
let mut tag_check_plus_match = self.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
|
|
|
nonselflike_args,
|
|
|
|
&EnumTag(tag_field, Some(get_match_expr(selflike_args))),
|
|
|
|
);
|
|
|
|
tag_let_stmts.append(&mut tag_check_plus_match.0);
|
|
|
|
BlockOrExpr(tag_let_stmts, tag_check_plus_match.1)
|
|
|
|
} else {
|
2023-01-30 03:13:27 +00:00
|
|
|
BlockOrExpr(ThinVec::new(), Some(get_match_expr(selflike_args)))
|
2014-07-06 19:19:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-06 15:23:51 +00:00
|
|
|
fn expand_static_enum_method_body(
|
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
trait_: &TraitDef<'_>,
|
2014-01-09 13:05:33 +00:00
|
|
|
enum_def: &EnumDef,
|
2013-11-07 07:49:01 +00:00
|
|
|
type_ident: Ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
nonselflike_args: &[P<Expr>],
|
2022-06-28 03:10:36 +00:00
|
|
|
) -> BlockOrExpr {
|
2016-07-19 17:32:06 +00:00
|
|
|
let summary = enum_def
|
|
|
|
.variants
|
|
|
|
.iter()
|
|
|
|
.map(|v| {
|
2017-07-31 20:04:34 +00:00
|
|
|
let sp = v.span.with_ctxt(trait_.span.ctxt());
|
2019-08-14 00:40:21 +00:00
|
|
|
let summary = trait_.summarise_struct(cx, &v.data);
|
|
|
|
(v.ident, sp, summary)
|
2016-07-19 17:32:06 +00:00
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
self.call_substructure_method(
|
|
|
|
cx,
|
|
|
|
trait_,
|
|
|
|
type_ident,
|
2022-07-04 22:25:47 +00:00
|
|
|
nonselflike_args,
|
2013-05-06 15:23:51 +00:00
|
|
|
&StaticEnum(enum_def, summary),
|
|
|
|
)
|
|
|
|
}
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
2013-12-07 00:57:44 +00:00
|
|
|
// general helper methods.
|
|
|
|
impl<'a> TraitDef<'a> {
|
2019-02-04 12:49:54 +00:00
|
|
|
fn summarise_struct(&self, cx: &mut ExtCtxt<'_>, struct_def: &VariantData) -> StaticFields {
|
2014-02-28 21:09:09 +00:00
|
|
|
let mut named_idents = Vec::new();
|
|
|
|
let mut just_spans = Vec::new();
|
2016-07-19 17:32:06 +00:00
|
|
|
for field in struct_def.fields() {
|
2017-07-31 20:04:34 +00:00
|
|
|
let sp = field.span.with_ctxt(self.span.ctxt());
|
2016-04-06 08:19:10 +00:00
|
|
|
match field.ident {
|
2016-04-02 13:47:53 +00:00
|
|
|
Some(ident) => named_idents.push((ident, sp)),
|
|
|
|
_ => just_spans.push(sp),
|
2013-12-07 00:57:44 +00:00
|
|
|
}
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
2013-05-06 15:23:51 +00:00
|
|
|
|
2020-09-18 17:11:06 +00:00
|
|
|
let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..));
|
2013-12-07 00:57:44 +00:00
|
|
|
match (just_spans.is_empty(), named_idents.is_empty()) {
|
2021-11-03 04:19:06 +00:00
|
|
|
(false, false) => {
|
|
|
|
cx.span_bug(self.span, "a struct with named and unnamed fields in generic `derive`")
|
|
|
|
}
|
2013-12-07 00:57:44 +00:00
|
|
|
// named fields
|
|
|
|
(_, false) => Named(named_idents),
|
2019-03-23 21:06:58 +00:00
|
|
|
// unnamed fields
|
|
|
|
(false, _) => Unnamed(just_spans, is_tuple),
|
|
|
|
// empty
|
|
|
|
_ => Named(Vec::new()),
|
2013-12-07 00:57:44 +00:00
|
|
|
}
|
2013-03-28 10:50:10 +00:00
|
|
|
}
|
|
|
|
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
fn create_struct_patterns(
|
2013-12-07 00:57:44 +00:00
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
struct_path: ast::Path,
|
|
|
|
struct_def: &'a VariantData,
|
|
|
|
prefixes: &[String],
|
2022-08-30 22:34:35 +00:00
|
|
|
by_ref: ByRef,
|
2022-11-23 00:55:16 +00:00
|
|
|
) -> ThinVec<P<ast::Pat>> {
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
prefixes
|
2016-07-19 17:32:06 +00:00
|
|
|
.iter()
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
.map(|prefix| {
|
2022-07-07 21:57:34 +00:00
|
|
|
let pieces_iter =
|
|
|
|
struct_def.fields().iter().enumerate().map(|(i, struct_field)| {
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
let sp = struct_field.span.with_ctxt(self.span.ctxt());
|
|
|
|
let ident = self.mk_pattern_ident(prefix, i);
|
|
|
|
let path = ident.with_span_pos(sp);
|
|
|
|
(
|
|
|
|
sp,
|
|
|
|
struct_field.ident,
|
2022-08-30 22:34:35 +00:00
|
|
|
cx.pat(
|
|
|
|
path.span,
|
|
|
|
PatKind::Ident(
|
|
|
|
BindingAnnotation(by_ref, Mutability::Not),
|
|
|
|
path,
|
|
|
|
None,
|
|
|
|
),
|
|
|
|
),
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
)
|
2022-07-07 21:57:34 +00:00
|
|
|
});
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
|
|
|
|
let struct_path = struct_path.clone();
|
|
|
|
match *struct_def {
|
|
|
|
VariantData::Struct(..) => {
|
2022-07-07 21:57:34 +00:00
|
|
|
let field_pats = pieces_iter
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
.map(|(sp, ident, pat)| {
|
|
|
|
if ident.is_none() {
|
|
|
|
cx.span_bug(
|
|
|
|
sp,
|
|
|
|
"a braced struct with unnamed fields in `derive`",
|
|
|
|
);
|
|
|
|
}
|
|
|
|
ast::PatField {
|
|
|
|
ident: ident.unwrap(),
|
|
|
|
is_shorthand: false,
|
|
|
|
attrs: ast::AttrVec::new(),
|
|
|
|
id: ast::DUMMY_NODE_ID,
|
|
|
|
span: pat.span.with_ctxt(self.span.ctxt()),
|
|
|
|
pat,
|
|
|
|
is_placeholder: false,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
cx.pat_struct(self.span, struct_path, field_pats)
|
|
|
|
}
|
|
|
|
VariantData::Tuple(..) => {
|
2022-07-07 21:57:34 +00:00
|
|
|
let subpats = pieces_iter.map(|(_, _, subpat)| subpat).collect();
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
cx.pat_tuple_struct(self.span, struct_path, subpats)
|
|
|
|
}
|
|
|
|
VariantData::Unit(..) => cx.pat_path(self.span, struct_path),
|
|
|
|
}
|
2016-07-19 17:32:06 +00:00
|
|
|
})
|
|
|
|
.collect()
|
2013-12-07 00:57:44 +00:00
|
|
|
}
|
2013-06-07 07:30:38 +00:00
|
|
|
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
fn create_fields<F>(&self, struct_def: &'a VariantData, mk_exprs: F) -> Vec<FieldInfo>
|
|
|
|
where
|
|
|
|
F: Fn(usize, &ast::FieldDef, Span) -> Vec<P<ast::Expr>>,
|
|
|
|
{
|
|
|
|
struct_def
|
|
|
|
.fields()
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(i, struct_field)| {
|
|
|
|
// For this field, get an expr for each selflike_arg. E.g. for
|
|
|
|
// `PartialEq::eq`, one for each of `&self` and `other`.
|
|
|
|
let sp = struct_field.span.with_ctxt(self.span.ctxt());
|
|
|
|
let mut exprs: Vec<_> = mk_exprs(i, struct_field, sp);
|
|
|
|
let self_expr = exprs.remove(0);
|
|
|
|
let other_selflike_exprs = exprs;
|
|
|
|
FieldInfo {
|
|
|
|
span: sp.with_ctxt(self.span.ctxt()),
|
|
|
|
name: struct_field.ident,
|
|
|
|
self_expr,
|
|
|
|
other_selflike_exprs,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
}
|
2013-06-07 07:30:38 +00:00
|
|
|
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
fn mk_pattern_ident(&self, prefix: &str, i: usize) -> Ident {
|
2023-07-25 20:00:13 +00:00
|
|
|
Ident::from_str_and_span(&format!("{prefix}_{i}"), self.span)
|
2013-12-07 00:57:44 +00:00
|
|
|
}
|
2013-06-07 07:30:38 +00:00
|
|
|
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
fn create_struct_pattern_fields(
|
Don't use match-destructuring for derived ops on structs.
All derive ops currently use match-destructuring to access fields. This
is reasonable for enums, but sub-optimal for structs. E.g.:
```
fn eq(&self, other: &Point) -> bool {
match *other {
Self { x: ref __self_1_0, y: ref __self_1_1 } =>
match *self {
Self { x: ref __self_0_0, y: ref __self_0_1 } =>
(*__self_0_0) == (*__self_1_0) &&
(*__self_0_1) == (*__self_1_1),
},
}
}
```
This commit changes derive ops on structs to use field access instead, e.g.:
```
fn eq(&self, other: &Point) -> bool {
self.x == other.x && self.y == other.y
}
```
This is faster to compile, results in smaller binaries, and is simpler to
generate. Unfortunately, we have to keep the old pattern generating code around
for `repr(packed)` structs because something like `&self.x` (which doesn't show
up in `PartialEq` ops, but does show up in `Debug` and `Hash` ops) isn't
allowed. But this commit at least changes those cases to use let-destructuring
instead of match-destructuring, e.g.:
```
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
{
let Self(ref __self_0_0) = *self;
{ ::core::hash::Hash::hash(&(*__self_0_0), state) }
}
}
```
There are some unnecessary blocks remaining in the generated code, but I
will fix them in a follow-up PR.
2022-06-24 00:20:54 +00:00
|
|
|
&self,
|
|
|
|
cx: &mut ExtCtxt<'_>,
|
|
|
|
struct_def: &'a VariantData,
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
prefixes: &[String],
|
|
|
|
) -> Vec<FieldInfo> {
|
|
|
|
self.create_fields(struct_def, |i, _struct_field, sp| {
|
|
|
|
prefixes
|
|
|
|
.iter()
|
|
|
|
.map(|prefix| {
|
|
|
|
let ident = self.mk_pattern_ident(prefix, i);
|
2022-11-14 02:59:54 +00:00
|
|
|
cx.expr_path(cx.path_ident(sp, ident))
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
})
|
Don't use match-destructuring for derived ops on structs.
All derive ops currently use match-destructuring to access fields. This
is reasonable for enums, but sub-optimal for structs. E.g.:
```
fn eq(&self, other: &Point) -> bool {
match *other {
Self { x: ref __self_1_0, y: ref __self_1_1 } =>
match *self {
Self { x: ref __self_0_0, y: ref __self_0_1 } =>
(*__self_0_0) == (*__self_1_0) &&
(*__self_0_1) == (*__self_1_1),
},
}
}
```
This commit changes derive ops on structs to use field access instead, e.g.:
```
fn eq(&self, other: &Point) -> bool {
self.x == other.x && self.y == other.y
}
```
This is faster to compile, results in smaller binaries, and is simpler to
generate. Unfortunately, we have to keep the old pattern generating code around
for `repr(packed)` structs because something like `&self.x` (which doesn't show
up in `PartialEq` ops, but does show up in `Debug` and `Hash` ops) isn't
allowed. But this commit at least changes those cases to use let-destructuring
instead of match-destructuring, e.g.:
```
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
{
let Self(ref __self_0_0) = *self;
{ ::core::hash::Hash::hash(&(*__self_0_0), state) }
}
}
```
There are some unnecessary blocks remaining in the generated code, but I
will fix them in a follow-up PR.
2022-06-24 00:20:54 +00:00
|
|
|
}
|
|
|
|
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
fn create_struct_field_access_fields(
|
2016-07-19 17:32:06 +00:00
|
|
|
&self,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
selflike_args: &[P<Expr>],
|
|
|
|
struct_def: &'a VariantData,
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
is_packed: bool,
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
) -> Vec<FieldInfo> {
|
|
|
|
self.create_fields(struct_def, |i, struct_field, sp| {
|
|
|
|
selflike_args
|
|
|
|
.iter()
|
2022-07-06 06:13:51 +00:00
|
|
|
.map(|selflike_arg| {
|
2022-07-07 01:09:07 +00:00
|
|
|
// Note: we must use `struct_field.span` rather than `sp` in the
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
// `unwrap_or_else` case otherwise the hygiene is wrong and we get
|
|
|
|
// "field `0` of struct `Point` is private" errors on tuple
|
|
|
|
// structs.
|
2022-07-11 02:54:52 +00:00
|
|
|
let mut field_expr = cx.expr(
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
sp,
|
2022-07-11 02:54:52 +00:00
|
|
|
ast::ExprKind::Field(
|
|
|
|
selflike_arg.clone(),
|
|
|
|
struct_field.ident.unwrap_or_else(|| {
|
|
|
|
Ident::from_str_and_span(&i.to_string(), struct_field.span)
|
|
|
|
}),
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
),
|
2022-07-11 02:54:52 +00:00
|
|
|
);
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
if is_packed {
|
2023-02-06 01:58:39 +00:00
|
|
|
// In general, fields in packed structs are copied via a
|
|
|
|
// block, e.g. `&{self.0}`. The two exceptions are `[u8]`
|
|
|
|
// and `str` fields, which cannot be copied and also never
|
|
|
|
// cause unaligned references. These exceptions are allowed
|
|
|
|
// to handle the `FlexZeroSlice` type in the `zerovec`
|
|
|
|
// crate within `icu4x-0.9.0`.
|
|
|
|
//
|
|
|
|
// Once use of `icu4x-0.9.0` has dropped sufficiently, this
|
|
|
|
// exception should be removed.
|
|
|
|
let is_simple_path = |ty: &P<ast::Ty>, sym| {
|
|
|
|
if let TyKind::Path(None, ast::Path { segments, .. }) = &ty.kind &&
|
|
|
|
let [seg] = segments.as_slice() &&
|
|
|
|
seg.ident.name == sym && seg.args.is_none()
|
|
|
|
{
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let exception = if let TyKind::Slice(ty) = &struct_field.ty.kind &&
|
|
|
|
is_simple_path(ty, sym::u8)
|
|
|
|
{
|
|
|
|
Some("byte")
|
|
|
|
} else if is_simple_path(&struct_field.ty, sym::str) {
|
|
|
|
Some("string")
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(ty) = exception {
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
cx.sess.parse_sess.buffer_lint_with_diagnostic(
|
|
|
|
BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
|
|
|
|
sp,
|
|
|
|
ast::CRATE_NODE_ID,
|
2023-05-16 06:04:03 +00:00
|
|
|
format!(
|
2023-07-25 20:00:13 +00:00
|
|
|
"{ty} slice in a packed struct that derives a built-in trait"
|
2023-02-06 01:58:39 +00:00
|
|
|
),
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
rustc_lint_defs::BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
// Wrap the expression in `{...}`, causing a copy.
|
|
|
|
field_expr = cx.expr_block(
|
2023-01-30 03:13:27 +00:00
|
|
|
cx.block(struct_field.span, thin_vec![cx.stmt_expr(field_expr)]),
|
Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.
The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`
Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.
Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)
This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`
In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
#[derive(Debug)]
struct NonCopy(u8);
#[derive(Debug)
#[repr(packed)]
struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)
However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
trait Trait { type A; }
#[derive(Hash)]
#[repr(packed)]
pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.
We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
#[derive(Hash)]
#[repr(packed)]
pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
#[derive(Clone)]
#[repr(packed)]
struct MyType(i32);
impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.
One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.
2022-11-21 03:40:32 +00:00
|
|
|
);
|
|
|
|
}
|
2022-07-11 02:54:52 +00:00
|
|
|
}
|
|
|
|
cx.expr_addr_of(sp, field_expr)
|
Avoid transposes in deriving code.
The deriving code has some complex parts involving iterations over
selflike args and also fields within structs and enum variants.
The return types for a few functions demonstrate this:
- `TraitDef::create_{struct_pattern,enum_variant_pattern}` returns a
`(P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>)>)`
- `TraitDef::create_struct_field_accesses` returns a `Vec<(Span,
Option<Ident>, P<Expr>)>`.
This results in per-field data stored within per-selflike-arg data, with
lots of repetition within the per-field data elements. This then has to
be "transposed" in two places (`expand_struct_method_body` and
`expand_enum_method_body`) into per-self-like-arg data stored within
per-field data. It's all quite clumsy and confusing.
This commit rearranges things greatly. Data is obtained in the needed
form up-front, avoiding the need for transposition. Also, various
functions are split, removed, and added, to make things clearer and
avoid tuple return values.
The diff is hard to read, which reflects the messiness of the original
code -- there wasn't an easy way to break these changes into small
pieces. (Sorry!) It's a net reduction of 35 lines and a readability
improvement. The generated code is unchanged.
2022-07-04 23:04:41 +00:00
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
})
|
2013-06-07 07:30:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-05 01:23:55 +00:00
|
|
|
/// The function passed to `cs_fold` is called repeatedly with a value of this
|
|
|
|
/// type. It describes one part of the code generation. The result is always an
|
|
|
|
/// expression.
|
|
|
|
pub enum CsFold<'a> {
|
|
|
|
/// The basic case: a field expression for one or more selflike args. E.g.
|
|
|
|
/// for `PartialEq::eq` this is something like `self.x == other.x`.
|
|
|
|
Single(&'a FieldInfo),
|
|
|
|
|
|
|
|
/// The combination of two field expressions. E.g. for `PartialEq::eq` this
|
|
|
|
/// is something like `<field1 equality> && <field2 equality>`.
|
|
|
|
Combine(Span, P<Expr>, P<Expr>),
|
|
|
|
|
|
|
|
// The fallback case for a struct or enum variant with no fields.
|
|
|
|
Fieldless,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Folds over fields, combining the expressions for each field in a sequence.
|
|
|
|
/// Statics may not be folded over.
|
|
|
|
pub fn cs_fold<F>(
|
2018-04-11 14:16:54 +00:00
|
|
|
use_foldl: bool,
|
2019-02-04 12:49:54 +00:00
|
|
|
cx: &mut ExtCtxt<'_>,
|
2018-04-11 14:16:54 +00:00
|
|
|
trait_span: Span,
|
2019-02-04 12:49:54 +00:00
|
|
|
substructure: &Substructure<'_>,
|
2022-07-05 01:23:55 +00:00
|
|
|
mut f: F,
|
2018-04-11 14:16:54 +00:00
|
|
|
) -> P<Expr>
|
2019-02-04 12:49:54 +00:00
|
|
|
where
|
2022-07-05 01:23:55 +00:00
|
|
|
F: FnMut(&mut ExtCtxt<'_>, CsFold<'_>) -> P<Expr>,
|
2018-04-11 14:16:54 +00:00
|
|
|
{
|
2022-07-08 05:32:27 +00:00
|
|
|
match substructure.fields {
|
|
|
|
EnumMatching(.., all_fields) | Struct(_, all_fields) => {
|
2022-07-05 01:23:55 +00:00
|
|
|
if all_fields.is_empty() {
|
|
|
|
return f(cx, CsFold::Fieldless);
|
|
|
|
}
|
|
|
|
|
|
|
|
let (base_field, rest) = if use_foldl {
|
|
|
|
all_fields.split_first().unwrap()
|
|
|
|
} else {
|
|
|
|
all_fields.split_last().unwrap()
|
|
|
|
};
|
|
|
|
|
|
|
|
let base_expr = f(cx, CsFold::Single(base_field));
|
|
|
|
|
|
|
|
let op = |old, field: &FieldInfo| {
|
|
|
|
let new = f(cx, CsFold::Single(field));
|
|
|
|
f(cx, CsFold::Combine(field.span, old, new))
|
2018-04-11 14:16:54 +00:00
|
|
|
};
|
|
|
|
|
2022-07-04 07:10:36 +00:00
|
|
|
if use_foldl {
|
2022-07-05 01:23:55 +00:00
|
|
|
rest.iter().fold(base_expr, op)
|
2022-07-04 07:10:36 +00:00
|
|
|
} else {
|
2022-07-05 01:23:55 +00:00
|
|
|
rest.iter().rfold(base_expr, op)
|
2022-07-04 07:10:36 +00:00
|
|
|
}
|
2018-04-11 14:16:54 +00:00
|
|
|
}
|
2022-07-08 05:32:27 +00:00
|
|
|
EnumTag(tag_field, match_expr) => {
|
|
|
|
let tag_check_expr = f(cx, CsFold::Single(tag_field));
|
|
|
|
if let Some(match_expr) = match_expr {
|
|
|
|
if use_foldl {
|
|
|
|
f(cx, CsFold::Combine(trait_span, tag_check_expr, match_expr.clone()))
|
|
|
|
} else {
|
|
|
|
f(cx, CsFold::Combine(trait_span, match_expr.clone(), tag_check_expr))
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
tag_check_expr
|
|
|
|
}
|
|
|
|
}
|
2022-07-04 07:10:36 +00:00
|
|
|
StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"),
|
2023-01-14 21:16:25 +00:00
|
|
|
AllFieldlessEnum(..) => cx.span_bug(trait_span, "fieldless enum in `derive`"),
|
2018-04-11 14:16:54 +00:00
|
|
|
}
|
|
|
|
}
|