@@ -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,9 +287,41 @@ 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 ,
292+ }
293+
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+ }
287321}
288322
289323/// Fields for a static method
324+ #[ derive( Debug ) ]
290325pub enum StaticFields {
291326 /// Tuple and unit structs/enum variants like this.
292327 Unnamed ( Vec < Span > , bool /*is tuple*/ ) ,
@@ -295,6 +330,7 @@ pub enum StaticFields {
295330}
296331
297332/// A summary of the possible sets of fields.
333+ #[ derive( Debug ) ]
298334pub enum SubstructureFields < ' a > {
299335 /// A non-static method where `Self` is a struct.
300336 Struct ( & ' a ast:: VariantData , Vec < FieldInfo > ) ,
@@ -1213,7 +1249,13 @@ impl<'a> MethodDef<'a> {
12131249
12141250 let self_expr = tag_exprs. remove ( 0 ) ;
12151251 let other_selflike_exprs = tag_exprs;
1216- let tag_field = FieldInfo { span, name : None , self_expr, other_selflike_exprs } ;
1252+ let tag_field = FieldInfo {
1253+ span,
1254+ name : None ,
1255+ self_expr,
1256+ other_selflike_exprs,
1257+ skipped_derives : SkippedDerives :: None ,
1258+ } ;
12171259
12181260 let tag_let_stmts: ThinVec < _ > = iter:: zip ( & tag_idents, & selflike_args)
12191261 . map ( |( & ident, selflike_arg) | {
@@ -1517,7 +1559,12 @@ impl<'a> TraitDef<'a> {
15171559 . collect ( )
15181560 }
15191561
1520- fn create_fields < F > ( & self , struct_def : & ' a VariantData , mk_exprs : F ) -> Vec < FieldInfo >
1562+ fn create_fields < F > (
1563+ & self ,
1564+ cx : & ExtCtxt < ' _ > ,
1565+ struct_def : & ' a VariantData ,
1566+ mk_exprs : F ,
1567+ ) -> Vec < FieldInfo >
15211568 where
15221569 F : Fn ( usize , & ast:: FieldDef , Span ) -> Vec < P < ast:: Expr > > ,
15231570 {
@@ -1532,11 +1579,76 @@ impl<'a> TraitDef<'a> {
15321579 let mut exprs: Vec < _ > = mk_exprs ( i, struct_field, sp) ;
15331580 let self_expr = exprs. remove ( 0 ) ;
15341581 let other_selflike_exprs = exprs;
1582+ let mut skipped_derives = SkippedDerives :: None ;
1583+ let skip_enabled = cx. ecfg . features . derive_skip
1584+ || struct_field. span . allows_unstable ( sym:: derive_skip) ;
1585+ for attr in attr:: filter_by_name ( & struct_field. attrs , sym:: skip) {
1586+ if !skip_enabled {
1587+ rustc_session:: parse:: feature_err (
1588+ & cx. sess ,
1589+ sym:: derive_skip,
1590+ attr. span ,
1591+ "the `#[skip]` attribute is experimental" ,
1592+ )
1593+ . emit ( ) ;
1594+ }
1595+ let Some ( skip_attr) = ast:: Attribute :: meta_kind ( attr) else {
1596+ unreachable ! ( )
1597+ } ;
1598+
1599+ // FIXME: better errors
1600+ match skip_attr {
1601+ ast:: MetaItemKind :: Word => {
1602+ skipped_derives = SkippedDerives :: All ;
1603+ break ;
1604+ }
1605+ ast:: MetaItemKind :: List ( items) => {
1606+ for item in items {
1607+ let span = item. span ( ) ;
1608+ let ast:: NestedMetaItem :: MetaItem ( ast:: MetaItem {
1609+ path,
1610+ kind : ast:: MetaItemKind :: Word ,
1611+ ..
1612+ } ) = item
1613+ else {
1614+ cx. dcx ( ) . emit_err ( errors:: DeriveSkipBadArgument {
1615+ span,
1616+ } ) ;
1617+ continue ;
1618+ } ;
1619+ let name = path. segments [ 0 ] . ident ;
1620+ const SUPPORTED_TRAITS : [ Symbol ; 5 ] = [
1621+ sym:: PartialEq ,
1622+ sym:: PartialOrd ,
1623+ sym:: Ord ,
1624+ sym:: Hash ,
1625+ sym:: Debug ,
1626+ ] ;
1627+ if SUPPORTED_TRAITS . contains ( & name. name ) {
1628+ skipped_derives. add ( path. segments [ 0 ] . ident . name )
1629+ } else {
1630+ let traits = SUPPORTED_TRAITS . iter ( ) . map ( |s| format ! ( "`{s}`" ) ) . collect :: < Vec < _ > > ( ) . join ( ", " ) ;
1631+ cx. parse_sess ( ) . buffer_lint_with_diagnostic (
1632+ rustc_session:: lint:: builtin:: UNSUPPORTED_DERIVE_SKIP ,
1633+ span,
1634+ cx. current_expansion . lint_node_id ,
1635+ crate :: fluent_generated:: builtin_macros_derive_skip_unsupported,
1636+ rustc_session:: lint:: BuiltinLintDiagnostics :: DeriveSkipUnsupported { traits } ,
1637+ )
1638+ }
1639+ }
1640+ }
1641+ ast:: MetaItemKind :: NameValue ( lit) => {
1642+ cx. dcx ( ) . emit_err ( errors:: DeriveSkipBadArgument { span : lit. span } ) ;
1643+ }
1644+ }
1645+ }
15351646 FieldInfo {
15361647 span : sp. with_ctxt ( self . span . ctxt ( ) ) ,
15371648 name : struct_field. ident ,
15381649 self_expr,
15391650 other_selflike_exprs,
1651+ skipped_derives,
15401652 }
15411653 } )
15421654 . collect ( )
@@ -1552,7 +1664,7 @@ impl<'a> TraitDef<'a> {
15521664 struct_def : & ' a VariantData ,
15531665 prefixes : & [ String ] ,
15541666 ) -> Vec < FieldInfo > {
1555- self . create_fields ( struct_def, |i, _struct_field, sp| {
1667+ self . create_fields ( cx , struct_def, |i, _struct_field, sp| {
15561668 prefixes
15571669 . iter ( )
15581670 . map ( |prefix| {
@@ -1570,7 +1682,7 @@ impl<'a> TraitDef<'a> {
15701682 struct_def : & ' a VariantData ,
15711683 is_packed : bool ,
15721684 ) -> Vec < FieldInfo > {
1573- self . create_fields ( struct_def, |i, struct_field, sp| {
1685+ self . create_fields ( cx , struct_def, |i, struct_field, sp| {
15741686 selflike_args
15751687 . iter ( )
15761688 . map ( |selflike_arg| {
@@ -1665,13 +1777,19 @@ pub fn cs_fold<F>(
16651777 cx : & mut ExtCtxt < ' _ > ,
16661778 trait_span : Span ,
16671779 substructure : & Substructure < ' _ > ,
1780+ trait_name : Symbol ,
16681781 mut f : F ,
16691782) -> P < Expr >
16701783where
16711784 F : FnMut ( & mut ExtCtxt < ' _ > , CsFold < ' _ > ) -> P < Expr > ,
16721785{
16731786 match substructure. fields {
16741787 EnumMatching ( .., all_fields) | Struct ( _, all_fields) => {
1788+ let all_fields = all_fields
1789+ . iter ( )
1790+ . filter ( |fi| !fi. skipped_derives . is_skipped ( trait_name) )
1791+ . collect :: < Vec < & FieldInfo > > ( ) ;
1792+
16751793 if all_fields. is_empty ( ) {
16761794 return f ( cx, CsFold :: Fieldless ) ;
16771795 }
@@ -1684,7 +1802,7 @@ where
16841802
16851803 let base_expr = f ( cx, CsFold :: Single ( base_field) ) ;
16861804
1687- let op = |old, field : & FieldInfo | {
1805+ let op = |old, field : & & FieldInfo | {
16881806 let new = f ( cx, CsFold :: Single ( field) ) ;
16891807 f ( cx, CsFold :: Combine ( field. span , old, new) )
16901808 } ;
0 commit comments