1
1
use rustc:: hir:: def:: { Res , DefKind } ;
2
2
use rustc:: hir:: def_id:: DefId ;
3
3
use rustc:: lint;
4
- use rustc:: ty;
4
+ use rustc:: ty:: { self , Ty } ;
5
5
use rustc:: ty:: adjustment;
6
6
use rustc_data_structures:: fx:: FxHashMap ;
7
7
use lint:: { LateContext , EarlyContext , LintContext , LintArray } ;
@@ -47,43 +47,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
47
47
return ;
48
48
}
49
49
50
- let t = cx. tables . expr_ty ( & expr) ;
51
- let type_permits_lack_of_use = if t. is_unit ( )
52
- || cx. tcx . is_ty_uninhabited_from (
53
- cx. tcx . hir ( ) . get_module_parent_by_hir_id ( expr. hir_id ) , t)
54
- {
55
- true
56
- } else {
57
- match t. sty {
58
- ty:: Adt ( def, _) => check_must_use ( cx, def. did , s. span , "" , "" ) ,
59
- ty:: Opaque ( def, _) => {
60
- let mut must_use = false ;
61
- for ( predicate, _) in & cx. tcx . predicates_of ( def) . predicates {
62
- if let ty:: Predicate :: Trait ( ref poly_trait_predicate) = predicate {
63
- let trait_ref = poly_trait_predicate. skip_binder ( ) . trait_ref ;
64
- if check_must_use ( cx, trait_ref. def_id , s. span , "implementer of " , "" ) {
65
- must_use = true ;
66
- break ;
67
- }
68
- }
69
- }
70
- must_use
71
- }
72
- ty:: Dynamic ( binder, _) => {
73
- let mut must_use = false ;
74
- for predicate in binder. skip_binder ( ) . iter ( ) {
75
- if let ty:: ExistentialPredicate :: Trait ( ref trait_ref) = predicate {
76
- if check_must_use ( cx, trait_ref. def_id , s. span , "" , " trait object" ) {
77
- must_use = true ;
78
- break ;
79
- }
80
- }
81
- }
82
- must_use
83
- }
84
- _ => false ,
85
- }
86
- } ;
50
+ let ty = cx. tables . expr_ty ( & expr) ;
51
+ let type_permits_lack_of_use = check_must_use_ty ( cx, ty, & expr, s. span , "" ) ;
87
52
88
53
let mut fn_warned = false ;
89
54
let mut op_warned = false ;
@@ -108,7 +73,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
108
73
_ => None
109
74
} ;
110
75
if let Some ( def_id) = maybe_def_id {
111
- fn_warned = check_must_use ( cx, def_id, s. span , "return value of " , "" ) ;
76
+ fn_warned = check_must_use_def ( cx, def_id, s. span , "return value of " , "" ) ;
112
77
} else if type_permits_lack_of_use {
113
78
// We don't warn about unused unit or uninhabited types.
114
79
// (See https://github.com/rust-lang/rust/issues/43806 for details.)
@@ -162,18 +127,83 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
162
127
cx. span_lint ( UNUSED_RESULTS , s. span , "unused result" ) ;
163
128
}
164
129
165
- fn check_must_use (
130
+ // Returns whether an error has been emitted (and thus another does not need to be later).
131
+ fn check_must_use_ty < ' tcx > (
132
+ cx : & LateContext < ' _ , ' tcx > ,
133
+ ty : Ty < ' tcx > ,
134
+ expr : & hir:: Expr ,
135
+ span : Span ,
136
+ descr_post_path : & str ,
137
+ ) -> bool {
138
+ if ty. is_unit ( ) || cx. tcx . is_ty_uninhabited_from (
139
+ cx. tcx . hir ( ) . get_module_parent_by_hir_id ( expr. hir_id ) , ty)
140
+ {
141
+ return true ;
142
+ }
143
+
144
+ match ty. sty {
145
+ ty:: Adt ( def, _) => check_must_use_def ( cx, def. did , span, "" , descr_post_path) ,
146
+ ty:: Opaque ( def, _) => {
147
+ let mut has_emitted = false ;
148
+ for ( predicate, _) in & cx. tcx . predicates_of ( def) . predicates {
149
+ if let ty:: Predicate :: Trait ( ref poly_trait_predicate) = predicate {
150
+ let trait_ref = poly_trait_predicate. skip_binder ( ) . trait_ref ;
151
+ let def_id = trait_ref. def_id ;
152
+ if check_must_use_def ( cx, def_id, span, "implementer of " , "" ) {
153
+ has_emitted = true ;
154
+ break ;
155
+ }
156
+ }
157
+ }
158
+ has_emitted
159
+ }
160
+ ty:: Dynamic ( binder, _) => {
161
+ let mut has_emitted = false ;
162
+ for predicate in binder. skip_binder ( ) . iter ( ) {
163
+ if let ty:: ExistentialPredicate :: Trait ( ref trait_ref) = predicate {
164
+ let def_id = trait_ref. def_id ;
165
+ if check_must_use_def ( cx, def_id, span, "" , " trait object" ) {
166
+ has_emitted = true ;
167
+ break ;
168
+ }
169
+ }
170
+ }
171
+ has_emitted
172
+ }
173
+ ty:: Tuple ( ref tys) => {
174
+ let mut has_emitted = false ;
175
+ let spans = if let hir:: ExprKind :: Tup ( comps) = & expr. node {
176
+ debug_assert_eq ! ( comps. len( ) , tys. len( ) ) ;
177
+ comps. iter ( ) . map ( |e| e. span ) . collect ( )
178
+ } else {
179
+ vec ! [ ]
180
+ } ;
181
+ for ( i, ty) in tys. iter ( ) . map ( |k| k. expect_ty ( ) ) . enumerate ( ) {
182
+ let descr_post_path = & format ! ( " in tuple element {}" , i) ;
183
+ let span = * spans. get ( i) . unwrap_or ( & span) ;
184
+ if check_must_use_ty ( cx, ty, expr, span, descr_post_path) {
185
+ has_emitted = true ;
186
+ }
187
+ }
188
+ has_emitted
189
+ }
190
+ _ => false ,
191
+ }
192
+ }
193
+
194
+ // Returns whether an error has been emitted (and thus another does not need to be later).
195
+ fn check_must_use_def (
166
196
cx : & LateContext < ' _ , ' _ > ,
167
197
def_id : DefId ,
168
- sp : Span ,
198
+ span : Span ,
169
199
descr_pre_path : & str ,
170
200
descr_post_path : & str ,
171
201
) -> bool {
172
202
for attr in cx. tcx . get_attrs ( def_id) . iter ( ) {
173
203
if attr. check_name ( sym:: must_use) {
174
204
let msg = format ! ( "unused {}`{}`{} that must be used" ,
175
205
descr_pre_path, cx. tcx. def_path_str( def_id) , descr_post_path) ;
176
- let mut err = cx. struct_span_lint ( UNUSED_MUST_USE , sp , & msg) ;
206
+ let mut err = cx. struct_span_lint ( UNUSED_MUST_USE , span , & msg) ;
177
207
// check for #[must_use = "..."]
178
208
if let Some ( note) = attr. value_str ( ) {
179
209
err. note ( & note. as_str ( ) ) ;
0 commit comments