@@ -188,6 +188,7 @@ use rustc_expand::base::{Annotatable, ExtCtxt};
188
188
use rustc_session:: lint:: builtin:: BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE ;
189
189
use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
190
190
use rustc_span:: { Span , DUMMY_SP } ;
191
+ use smallvec:: SmallVec ;
191
192
use std:: cell:: RefCell ;
192
193
use std:: iter;
193
194
use std:: ops:: Not ;
@@ -263,6 +264,7 @@ pub enum FieldlessVariantsStrategy {
263
264
}
264
265
265
266
/// All the data about the data structure/method being derived upon.
267
+ #[ derive( Debug ) ]
266
268
pub struct Substructure < ' a > {
267
269
/// ident of self
268
270
pub type_ident : Ident ,
@@ -273,6 +275,7 @@ pub struct Substructure<'a> {
273
275
}
274
276
275
277
/// Summary of the relevant parts of a struct/enum field.
278
+ #[ derive( Debug ) ]
276
279
pub struct FieldInfo {
277
280
pub span : Span ,
278
281
/// None for tuple structs/normal enum variants, Some for normal
@@ -284,9 +287,41 @@ pub struct FieldInfo {
284
287
/// The expressions corresponding to references to this field in
285
288
/// the other selflike arguments.
286
289
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
+ }
287
321
}
288
322
289
323
/// Fields for a static method
324
+ #[ derive( Debug ) ]
290
325
pub enum StaticFields {
291
326
/// Tuple and unit structs/enum variants like this.
292
327
Unnamed ( Vec < Span > , bool /*is tuple*/ ) ,
@@ -295,6 +330,7 @@ pub enum StaticFields {
295
330
}
296
331
297
332
/// A summary of the possible sets of fields.
333
+ #[ derive( Debug ) ]
298
334
pub enum SubstructureFields < ' a > {
299
335
/// A non-static method where `Self` is a struct.
300
336
Struct ( & ' a ast:: VariantData , Vec < FieldInfo > ) ,
@@ -1213,7 +1249,13 @@ impl<'a> MethodDef<'a> {
1213
1249
1214
1250
let self_expr = tag_exprs. remove ( 0 ) ;
1215
1251
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
+ } ;
1217
1259
1218
1260
let tag_let_stmts: ThinVec < _ > = iter:: zip ( & tag_idents, & selflike_args)
1219
1261
. map ( |( & ident, selflike_arg) | {
@@ -1517,7 +1559,12 @@ impl<'a> TraitDef<'a> {
1517
1559
. collect ( )
1518
1560
}
1519
1561
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 >
1521
1568
where
1522
1569
F : Fn ( usize , & ast:: FieldDef , Span ) -> Vec < P < ast:: Expr > > ,
1523
1570
{
@@ -1532,11 +1579,76 @@ impl<'a> TraitDef<'a> {
1532
1579
let mut exprs: Vec < _ > = mk_exprs ( i, struct_field, sp) ;
1533
1580
let self_expr = exprs. remove ( 0 ) ;
1534
1581
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
+ }
1535
1646
FieldInfo {
1536
1647
span : sp. with_ctxt ( self . span . ctxt ( ) ) ,
1537
1648
name : struct_field. ident ,
1538
1649
self_expr,
1539
1650
other_selflike_exprs,
1651
+ skipped_derives,
1540
1652
}
1541
1653
} )
1542
1654
. collect ( )
@@ -1552,7 +1664,7 @@ impl<'a> TraitDef<'a> {
1552
1664
struct_def : & ' a VariantData ,
1553
1665
prefixes : & [ String ] ,
1554
1666
) -> Vec < FieldInfo > {
1555
- self . create_fields ( struct_def, |i, _struct_field, sp| {
1667
+ self . create_fields ( cx , struct_def, |i, _struct_field, sp| {
1556
1668
prefixes
1557
1669
. iter ( )
1558
1670
. map ( |prefix| {
@@ -1570,7 +1682,7 @@ impl<'a> TraitDef<'a> {
1570
1682
struct_def : & ' a VariantData ,
1571
1683
is_packed : bool ,
1572
1684
) -> Vec < FieldInfo > {
1573
- self . create_fields ( struct_def, |i, struct_field, sp| {
1685
+ self . create_fields ( cx , struct_def, |i, struct_field, sp| {
1574
1686
selflike_args
1575
1687
. iter ( )
1576
1688
. map ( |selflike_arg| {
@@ -1665,13 +1777,19 @@ pub fn cs_fold<F>(
1665
1777
cx : & mut ExtCtxt < ' _ > ,
1666
1778
trait_span : Span ,
1667
1779
substructure : & Substructure < ' _ > ,
1780
+ trait_name : Symbol ,
1668
1781
mut f : F ,
1669
1782
) -> P < Expr >
1670
1783
where
1671
1784
F : FnMut ( & mut ExtCtxt < ' _ > , CsFold < ' _ > ) -> P < Expr > ,
1672
1785
{
1673
1786
match substructure. fields {
1674
1787
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
+
1675
1793
if all_fields. is_empty ( ) {
1676
1794
return f ( cx, CsFold :: Fieldless ) ;
1677
1795
}
@@ -1684,7 +1802,7 @@ where
1684
1802
1685
1803
let base_expr = f ( cx, CsFold :: Single ( base_field) ) ;
1686
1804
1687
- let op = |old, field : & FieldInfo | {
1805
+ let op = |old, field : & & FieldInfo | {
1688
1806
let new = f ( cx, CsFold :: Single ( field) ) ;
1689
1807
f ( cx, CsFold :: Combine ( field. span , old, new) )
1690
1808
} ;
0 commit comments