@@ -60,18 +60,39 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
60
60
}
61
61
62
62
let t = cx. tables . expr_ty ( & expr) ;
63
- // FIXME(varkor): replace with `t.is_unit() || t.conservative_is_uninhabited()`.
64
- let type_permits_no_use = match t. sty {
65
- ty:: Tuple ( ref tys) if tys. is_empty ( ) => true ,
66
- ty:: Never => true ,
67
- ty:: Adt ( def, _) => {
68
- if def. variants . is_empty ( ) {
69
- true
70
- } else {
71
- check_must_use ( cx, def. did , s. span , "" )
63
+ let type_permits_lack_of_use = if t. is_unit ( )
64
+ || cx. tcx . is_ty_uninhabited_from ( cx. tcx . hir . get_module_parent ( expr. id ) , t) {
65
+ true
66
+ } else {
67
+ match t. sty {
68
+ ty:: Adt ( def, _) => check_must_use ( cx, def. did , s. span , "" , "" ) ,
69
+ ty:: Opaque ( def, _) => {
70
+ let mut must_use = false ;
71
+ for ( predicate, _) in & cx. tcx . predicates_of ( def) . predicates {
72
+ if let ty:: Predicate :: Trait ( ref poly_trait_predicate) = predicate {
73
+ let trait_ref = poly_trait_predicate. skip_binder ( ) . trait_ref ;
74
+ if check_must_use ( cx, trait_ref. def_id , s. span , "implementer of " , "" ) {
75
+ must_use = true ;
76
+ break ;
77
+ }
78
+ }
79
+ }
80
+ must_use
81
+ }
82
+ ty:: Dynamic ( binder, _) => {
83
+ let mut must_use = false ;
84
+ for predicate in binder. skip_binder ( ) . iter ( ) {
85
+ if let ty:: ExistentialPredicate :: Trait ( ref trait_ref) = predicate {
86
+ if check_must_use ( cx, trait_ref. def_id , s. span , "" , " trait object" ) {
87
+ must_use = true ;
88
+ break ;
89
+ }
90
+ }
91
+ }
92
+ must_use
72
93
}
94
+ _ => false ,
73
95
}
74
- _ => false ,
75
96
} ;
76
97
77
98
let mut fn_warned = false ;
@@ -98,8 +119,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
98
119
} ;
99
120
if let Some ( def) = maybe_def {
100
121
let def_id = def. def_id ( ) ;
101
- fn_warned = check_must_use ( cx, def_id, s. span , "return value of " ) ;
102
- } else if type_permits_no_use {
122
+ fn_warned = check_must_use ( cx, def_id, s. span , "return value of " , "" ) ;
123
+ } else if type_permits_lack_of_use {
103
124
// We don't warn about unused unit or uninhabited types.
104
125
// (See https://github.com/rust-lang/rust/issues/43806 for details.)
105
126
return ;
@@ -148,15 +169,21 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
148
169
op_warned = true ;
149
170
}
150
171
151
- if !( type_permits_no_use || fn_warned || op_warned) {
172
+ if !( type_permits_lack_of_use || fn_warned || op_warned) {
152
173
cx. span_lint ( UNUSED_RESULTS , s. span , "unused result" ) ;
153
174
}
154
175
155
- fn check_must_use ( cx : & LateContext , def_id : DefId , sp : Span , describe_path : & str ) -> bool {
176
+ fn check_must_use (
177
+ cx : & LateContext ,
178
+ def_id : DefId ,
179
+ sp : Span ,
180
+ descr_pre_path : & str ,
181
+ descr_post_path : & str ,
182
+ ) -> bool {
156
183
for attr in cx. tcx . get_attrs ( def_id) . iter ( ) {
157
184
if attr. check_name ( "must_use" ) {
158
- let msg = format ! ( "unused {}`{}` that must be used" ,
159
- describe_path , cx. tcx. item_path_str( def_id) ) ;
185
+ let msg = format ! ( "unused {}`{}`{} that must be used" ,
186
+ descr_pre_path , cx. tcx. item_path_str( def_id) , descr_post_path ) ;
160
187
let mut err = cx. struct_span_lint ( UNUSED_MUST_USE , sp, & msg) ;
161
188
// check for #[must_use = "..."]
162
189
if let Some ( note) = attr. value_str ( ) {
0 commit comments