@@ -8,7 +8,8 @@ use rustc_hir::{
8
8
Body , Expr , ExprKind , GenericArg , Impl , ImplItemKind , Item , ItemKind , Node , PathSegment , QPath , Ty , TyKind ,
9
9
} ;
10
10
use rustc_lint:: { LateContext , LateLintPass } ;
11
- use rustc_middle:: ty:: { Adt , AdtDef , SubstsRef } ;
11
+ use rustc_middle:: ty:: adjustment:: { Adjust , PointerCast } ;
12
+ use rustc_middle:: ty:: { self , Adt , AdtDef , SubstsRef , TypeckResults } ;
12
13
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
13
14
use rustc_span:: sym;
14
15
@@ -75,13 +76,27 @@ fn is_path_self(e: &Expr<'_>) -> bool {
75
76
}
76
77
}
77
78
79
+ fn contains_trait_object ( cx : & LateContext < ' _ > , ty : ty:: Ty < ' _ > ) -> bool {
80
+ match ty. kind ( ) {
81
+ ty:: TyKind :: Ref ( _, ty, _) => {
82
+ contains_trait_object ( cx, * ty)
83
+ } ,
84
+ ty:: TyKind :: Adt ( def, substs) => {
85
+ def. is_box ( ) && substs[ 0 ] . as_type ( ) . map_or ( false , |ty| contains_trait_object ( cx, ty) )
86
+ }
87
+ ty:: TyKind :: Dynamic ( ..) => true ,
88
+ _ => false ,
89
+ }
90
+ }
91
+
78
92
fn check_struct < ' tcx > (
79
93
cx : & LateContext < ' tcx > ,
80
94
item : & ' tcx Item < ' _ > ,
81
95
self_ty : & Ty < ' _ > ,
82
96
func_expr : & Expr < ' _ > ,
83
97
adt_def : AdtDef < ' _ > ,
84
98
substs : SubstsRef < ' _ > ,
99
+ typeck_results : & ' tcx TypeckResults < ' tcx > ,
85
100
) {
86
101
if let TyKind :: Path ( QPath :: Resolved ( _, p) ) = self_ty. kind {
87
102
if let Some ( PathSegment { args, .. } ) = p. segments . last ( ) {
@@ -96,10 +111,23 @@ fn check_struct<'tcx>(
96
111
}
97
112
}
98
113
}
114
+
115
+ // the default() call might unsize coerce to a trait object (e.g. Box<T> to Box<dyn Trait>),
116
+ // which would not be the same if derived (see #10158).
117
+ // this closure checks both if the expr is equivalent to a `default()` call and does not
118
+ // have such coercions.
119
+ let is_default_without_adjusts = |expr| {
120
+ is_default_equivalent ( cx, expr)
121
+ && typeck_results. expr_adjustments ( expr) . iter ( ) . all ( |adj| {
122
+ !matches ! ( adj. kind, Adjust :: Pointer ( PointerCast :: Unsize )
123
+ if contains_trait_object( cx, adj. target) )
124
+ } )
125
+ } ;
126
+
99
127
let should_emit = match peel_blocks ( func_expr) . kind {
100
- ExprKind :: Tup ( fields) => fields. iter ( ) . all ( |e| is_default_equivalent ( cx , e) ) ,
101
- ExprKind :: Call ( callee, args) if is_path_self ( callee) => args. iter ( ) . all ( |e| is_default_equivalent ( cx , e) ) ,
102
- ExprKind :: Struct ( _, fields, _) => fields. iter ( ) . all ( |ef| is_default_equivalent ( cx , ef. expr ) ) ,
128
+ ExprKind :: Tup ( fields) => fields. iter ( ) . all ( |e| is_default_without_adjusts ( e) ) ,
129
+ ExprKind :: Call ( callee, args) if is_path_self ( callee) => args. iter ( ) . all ( |e| is_default_without_adjusts ( e) ) ,
130
+ ExprKind :: Struct ( _, fields, _) => fields. iter ( ) . all ( |ef| is_default_without_adjusts ( ef. expr ) ) ,
103
131
_ => false ,
104
132
} ;
105
133
@@ -197,7 +225,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
197
225
198
226
then {
199
227
if adt_def. is_struct( ) {
200
- check_struct( cx, item, self_ty, func_expr, adt_def, substs) ;
228
+ check_struct( cx, item, self_ty, func_expr, adt_def, substs, cx . tcx . typeck_body ( * b ) ) ;
201
229
} else if adt_def. is_enum( ) && self . msrv. meets( msrvs:: DEFAULT_ENUM_ATTRIBUTE ) {
202
230
check_enum( cx, item, func_expr, adt_def) ;
203
231
}
0 commit comments