@@ -188,6 +188,7 @@ use rustc_expand::base::{Annotatable, ExtCtxt};
188188use rustc_session:: lint:: builtin:: BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE ;
189189use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
190190use rustc_span:: { Span , DUMMY_SP } ;
191+ use smallvec:: SmallVec ;
191192use std:: cell:: RefCell ;
192193use std:: iter;
193194use std:: ops:: Not ;
@@ -263,6 +264,7 @@ pub enum FieldlessVariantsStrategy {
263264}
264265
265266/// All the data about the data structure/method being derived upon.
267+ #[ derive( Debug ) ]
266268pub struct Substructure < ' a > {
267269 /// ident of self
268270 pub type_ident : Ident ,
@@ -273,6 +275,7 @@ pub struct Substructure<'a> {
273275}
274276
275277/// Summary of the relevant parts of a struct/enum field.
278+ #[ derive( Debug ) ]
276279pub struct FieldInfo {
277280 pub span : Span ,
278281 /// None for tuple structs/normal enum variants, Some for normal
@@ -284,15 +287,47 @@ pub struct FieldInfo {
284287 /// The expressions corresponding to references to this field in
285288 /// the other selflike arguments.
286289 pub other_selflike_exprs : Vec < P < Expr > > ,
290+ /// The derives for which this field should be ignored
291+ pub skipped_derives : SkippedDerives ,
287292}
288293
289- #[ derive( Copy , Clone ) ]
294+ /// Derives for which this field should be ignored
295+ #[ derive( Debug ) ]
296+ pub enum SkippedDerives {
297+ /// No `#[skip]`
298+ None ,
299+ /// `#[skip(Trait, Names)]`
300+ List ( SmallVec < [ Symbol ; 1 ] > ) ,
301+ /// `#[skip]` with no arguments
302+ All ,
303+ }
304+
305+ impl SkippedDerives {
306+ pub fn add ( & mut self , derive : Symbol ) {
307+ match self {
308+ Self :: None => * self = Self :: List ( SmallVec :: from ( [ derive] ) ) ,
309+ Self :: List ( idents) => idents. push ( derive) ,
310+ Self :: All => ( ) ,
311+ }
312+ }
313+
314+ pub fn is_skipped ( & self , derive : Symbol ) -> bool {
315+ match self {
316+ Self :: None => false ,
317+ Self :: List ( idents) => idents. contains ( & derive) ,
318+ Self :: All => true ,
319+ }
320+ }
321+ }
322+
323+ #[ derive( Copy , Clone , Debug ) ]
290324pub enum IsTuple {
291325 No ,
292326 Yes ,
293327}
294328
295329/// Fields for a static method
330+ #[ derive( Debug ) ]
296331pub enum StaticFields {
297332 /// Tuple and unit structs/enum variants like this.
298333 Unnamed ( Vec < Span > , IsTuple ) ,
@@ -301,6 +336,7 @@ pub enum StaticFields {
301336}
302337
303338/// A summary of the possible sets of fields.
339+ #[ derive( Debug ) ]
304340pub enum SubstructureFields < ' a > {
305341 /// A non-static method where `Self` is a struct.
306342 Struct ( & ' a ast:: VariantData , Vec < FieldInfo > ) ,
@@ -1215,7 +1251,13 @@ impl<'a> MethodDef<'a> {
12151251
12161252 let self_expr = discr_exprs. remove ( 0 ) ;
12171253 let other_selflike_exprs = discr_exprs;
1218- let discr_field = FieldInfo { span, name : None , self_expr, other_selflike_exprs } ;
1254+ let discr_field = FieldInfo {
1255+ span,
1256+ name : None ,
1257+ self_expr,
1258+ other_selflike_exprs,
1259+ skipped_derives : SkippedDerives :: None ,
1260+ } ;
12191261
12201262 let discr_let_stmts: ThinVec < _ > = iter:: zip ( & discr_idents, & selflike_args)
12211263 . map ( |( & ident, selflike_arg) | {
@@ -1518,7 +1560,12 @@ impl<'a> TraitDef<'a> {
15181560 . collect ( )
15191561 }
15201562
1521- fn create_fields < F > ( & self , struct_def : & ' a VariantData , mk_exprs : F ) -> Vec < FieldInfo >
1563+ fn create_fields < F > (
1564+ & self ,
1565+ cx : & ExtCtxt < ' _ > ,
1566+ struct_def : & ' a VariantData ,
1567+ mk_exprs : F ,
1568+ ) -> Vec < FieldInfo >
15221569 where
15231570 F : Fn ( usize , & ast:: FieldDef , Span ) -> Vec < P < ast:: Expr > > ,
15241571 {
@@ -1533,11 +1580,76 @@ impl<'a> TraitDef<'a> {
15331580 let mut exprs: Vec < _ > = mk_exprs ( i, struct_field, sp) ;
15341581 let self_expr = exprs. remove ( 0 ) ;
15351582 let other_selflike_exprs = exprs;
1583+ let mut skipped_derives = SkippedDerives :: None ;
1584+ let skip_enabled = cx. ecfg . features . derive_skip
1585+ || struct_field. span . allows_unstable ( sym:: derive_skip) ;
1586+ for attr in attr:: filter_by_name ( & struct_field. attrs , sym:: skip) {
1587+ if !skip_enabled {
1588+ rustc_session:: parse:: feature_err (
1589+ & cx. sess ,
1590+ sym:: derive_skip,
1591+ attr. span ,
1592+ "the `#[skip]` attribute is experimental" ,
1593+ )
1594+ . emit ( ) ;
1595+ }
1596+ let Some ( skip_attr) = ast:: Attribute :: meta_kind ( attr) else {
1597+ unreachable ! ( )
1598+ } ;
1599+
1600+ // FIXME: better errors
1601+ match skip_attr {
1602+ ast:: MetaItemKind :: Word => {
1603+ skipped_derives = SkippedDerives :: All ;
1604+ break ;
1605+ }
1606+ ast:: MetaItemKind :: List ( items) => {
1607+ for item in items {
1608+ let span = item. span ( ) ;
1609+ let ast:: NestedMetaItem :: MetaItem ( ast:: MetaItem {
1610+ path,
1611+ kind : ast:: MetaItemKind :: Word ,
1612+ ..
1613+ } ) = item
1614+ else {
1615+ cx. dcx ( ) . emit_err ( errors:: DeriveSkipBadArgument {
1616+ span,
1617+ } ) ;
1618+ continue ;
1619+ } ;
1620+ let name = path. segments [ 0 ] . ident ;
1621+ const SUPPORTED_TRAITS : [ Symbol ; 5 ] = [
1622+ sym:: PartialEq ,
1623+ sym:: PartialOrd ,
1624+ sym:: Ord ,
1625+ sym:: Hash ,
1626+ sym:: Debug ,
1627+ ] ;
1628+ if SUPPORTED_TRAITS . contains ( & name. name ) {
1629+ skipped_derives. add ( path. segments [ 0 ] . ident . name )
1630+ } else {
1631+ let traits = SUPPORTED_TRAITS . iter ( ) . map ( |s| format ! ( "`{s}`" ) ) . collect :: < Vec < _ > > ( ) . join ( ", " ) ;
1632+ cx. psess ( ) . buffer_lint_with_diagnostic (
1633+ rustc_session:: lint:: builtin:: UNSUPPORTED_DERIVE_SKIP ,
1634+ span,
1635+ cx. current_expansion . lint_node_id ,
1636+ crate :: fluent_generated:: builtin_macros_derive_skip_unsupported,
1637+ rustc_session:: lint:: BuiltinLintDiag :: DeriveSkipUnsupported { traits } ,
1638+ )
1639+ }
1640+ }
1641+ }
1642+ ast:: MetaItemKind :: NameValue ( lit) => {
1643+ cx. dcx ( ) . emit_err ( errors:: DeriveSkipBadArgument { span : lit. span } ) ;
1644+ }
1645+ }
1646+ }
15361647 FieldInfo {
15371648 span : sp. with_ctxt ( self . span . ctxt ( ) ) ,
15381649 name : struct_field. ident ,
15391650 self_expr,
15401651 other_selflike_exprs,
1652+ skipped_derives,
15411653 }
15421654 } )
15431655 . collect ( )
@@ -1553,7 +1665,7 @@ impl<'a> TraitDef<'a> {
15531665 struct_def : & ' a VariantData ,
15541666 prefixes : & [ String ] ,
15551667 ) -> Vec < FieldInfo > {
1556- self . create_fields ( struct_def, |i, _struct_field, sp| {
1668+ self . create_fields ( cx , struct_def, |i, _struct_field, sp| {
15571669 prefixes
15581670 . iter ( )
15591671 . map ( |prefix| {
@@ -1571,7 +1683,7 @@ impl<'a> TraitDef<'a> {
15711683 struct_def : & ' a VariantData ,
15721684 is_packed : bool ,
15731685 ) -> Vec < FieldInfo > {
1574- self . create_fields ( struct_def, |i, struct_field, sp| {
1686+ self . create_fields ( cx , struct_def, |i, struct_field, sp| {
15751687 selflike_args
15761688 . iter ( )
15771689 . map ( |selflike_arg| {
@@ -1667,13 +1779,19 @@ pub fn cs_fold<F>(
16671779 cx : & ExtCtxt < ' _ > ,
16681780 trait_span : Span ,
16691781 substructure : & Substructure < ' _ > ,
1782+ trait_name : Symbol ,
16701783 mut f : F ,
16711784) -> P < Expr >
16721785where
16731786 F : FnMut ( & ExtCtxt < ' _ > , CsFold < ' _ > ) -> P < Expr > ,
16741787{
16751788 match substructure. fields {
16761789 EnumMatching ( .., all_fields) | Struct ( _, all_fields) => {
1790+ let all_fields = all_fields
1791+ . iter ( )
1792+ . filter ( |fi| !fi. skipped_derives . is_skipped ( trait_name) )
1793+ . collect :: < Vec < & FieldInfo > > ( ) ;
1794+
16771795 if all_fields. is_empty ( ) {
16781796 return f ( cx, CsFold :: Fieldless ) ;
16791797 }
@@ -1686,7 +1804,7 @@ where
16861804
16871805 let base_expr = f ( cx, CsFold :: Single ( base_field) ) ;
16881806
1689- let op = |old, field : & FieldInfo | {
1807+ let op = |old, field : & & FieldInfo | {
16901808 let new = f ( cx, CsFold :: Single ( field) ) ;
16911809 f ( cx, CsFold :: Combine ( field. span , old, new) )
16921810 } ;
0 commit comments