@@ -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,15 +287,47 @@ 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 ,
287
292
}
288
293
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 ) ]
290
324
pub enum IsTuple {
291
325
No ,
292
326
Yes ,
293
327
}
294
328
295
329
/// Fields for a static method
330
+ #[ derive( Debug ) ]
296
331
pub enum StaticFields {
297
332
/// Tuple and unit structs/enum variants like this.
298
333
Unnamed ( Vec < Span > , IsTuple ) ,
@@ -301,6 +336,7 @@ pub enum StaticFields {
301
336
}
302
337
303
338
/// A summary of the possible sets of fields.
339
+ #[ derive( Debug ) ]
304
340
pub enum SubstructureFields < ' a > {
305
341
/// A non-static method where `Self` is a struct.
306
342
Struct ( & ' a ast:: VariantData , Vec < FieldInfo > ) ,
@@ -1215,7 +1251,13 @@ impl<'a> MethodDef<'a> {
1215
1251
1216
1252
let self_expr = discr_exprs. remove ( 0 ) ;
1217
1253
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
+ } ;
1219
1261
1220
1262
let discr_let_stmts: ThinVec < _ > = iter:: zip ( & discr_idents, & selflike_args)
1221
1263
. map ( |( & ident, selflike_arg) | {
@@ -1518,7 +1560,12 @@ impl<'a> TraitDef<'a> {
1518
1560
. collect ( )
1519
1561
}
1520
1562
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 >
1522
1569
where
1523
1570
F : Fn ( usize , & ast:: FieldDef , Span ) -> Vec < P < ast:: Expr > > ,
1524
1571
{
@@ -1533,11 +1580,76 @@ impl<'a> TraitDef<'a> {
1533
1580
let mut exprs: Vec < _ > = mk_exprs ( i, struct_field, sp) ;
1534
1581
let self_expr = exprs. remove ( 0 ) ;
1535
1582
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
+ }
1536
1647
FieldInfo {
1537
1648
span : sp. with_ctxt ( self . span . ctxt ( ) ) ,
1538
1649
name : struct_field. ident ,
1539
1650
self_expr,
1540
1651
other_selflike_exprs,
1652
+ skipped_derives,
1541
1653
}
1542
1654
} )
1543
1655
. collect ( )
@@ -1553,7 +1665,7 @@ impl<'a> TraitDef<'a> {
1553
1665
struct_def : & ' a VariantData ,
1554
1666
prefixes : & [ String ] ,
1555
1667
) -> Vec < FieldInfo > {
1556
- self . create_fields ( struct_def, |i, _struct_field, sp| {
1668
+ self . create_fields ( cx , struct_def, |i, _struct_field, sp| {
1557
1669
prefixes
1558
1670
. iter ( )
1559
1671
. map ( |prefix| {
@@ -1571,7 +1683,7 @@ impl<'a> TraitDef<'a> {
1571
1683
struct_def : & ' a VariantData ,
1572
1684
is_packed : bool ,
1573
1685
) -> Vec < FieldInfo > {
1574
- self . create_fields ( struct_def, |i, struct_field, sp| {
1686
+ self . create_fields ( cx , struct_def, |i, struct_field, sp| {
1575
1687
selflike_args
1576
1688
. iter ( )
1577
1689
. map ( |selflike_arg| {
@@ -1667,13 +1779,19 @@ pub fn cs_fold<F>(
1667
1779
cx : & ExtCtxt < ' _ > ,
1668
1780
trait_span : Span ,
1669
1781
substructure : & Substructure < ' _ > ,
1782
+ trait_name : Symbol ,
1670
1783
mut f : F ,
1671
1784
) -> P < Expr >
1672
1785
where
1673
1786
F : FnMut ( & ExtCtxt < ' _ > , CsFold < ' _ > ) -> P < Expr > ,
1674
1787
{
1675
1788
match substructure. fields {
1676
1789
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
+
1677
1795
if all_fields. is_empty ( ) {
1678
1796
return f ( cx, CsFold :: Fieldless ) ;
1679
1797
}
@@ -1686,7 +1804,7 @@ where
1686
1804
1687
1805
let base_expr = f ( cx, CsFold :: Single ( base_field) ) ;
1688
1806
1689
- let op = |old, field : & FieldInfo | {
1807
+ let op = |old, field : & & FieldInfo | {
1690
1808
let new = f ( cx, CsFold :: Single ( field) ) ;
1691
1809
f ( cx, CsFold :: Combine ( field. span , old, new) )
1692
1810
} ;
0 commit comments