1
1
use rustc:: hir:: def:: { Res , DefKind } ;
2
2
use rustc:: hir:: def_id:: DefId ;
3
+ use rustc:: hir:: HirVec ;
3
4
use rustc:: lint;
4
5
use rustc:: ty:: { self , Ty } ;
6
+ use rustc:: ty:: subst:: Subst ;
5
7
use rustc:: ty:: adjustment;
6
8
use rustc_data_structures:: fx:: FxHashMap ;
7
9
use lint:: { LateContext , EarlyContext , LintContext , LintArray } ;
@@ -48,7 +50,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
48
50
}
49
51
50
52
let ty = cx. tables . expr_ty ( & expr) ;
51
- let type_permits_lack_of_use = check_must_use_ty ( cx, ty, & expr, s. span , "" , "" , 1 ) ;
53
+ let type_permits_lack_of_use = check_must_use_ty ( cx, ty, & expr, s. span , "" , "" , 1 , false ) ;
52
54
53
55
let mut fn_warned = false ;
54
56
let mut op_warned = false ;
@@ -73,7 +75,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
73
75
_ => None
74
76
} ;
75
77
if let Some ( def_id) = maybe_def_id {
76
- fn_warned = check_must_use_def ( cx, def_id, s. span , "return value of " , "" ) ;
78
+ fn_warned = check_must_use_def ( cx, def_id, s. span , "return value of " , "" , false ) ;
77
79
} else if type_permits_lack_of_use {
78
80
// We don't warn about unused unit or uninhabited types.
79
81
// (See https://github.com/rust-lang/rust/issues/43806 for details.)
@@ -135,24 +137,61 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
135
137
span : Span ,
136
138
descr_pre : & str ,
137
139
descr_post : & str ,
138
- plural_len : usize ,
140
+ len : usize ,
141
+ err : bool , // HACK: Report an error rather than a lint, for crater testing.
139
142
) -> bool {
140
- if ty . is_unit ( ) || cx. tcx . is_ty_uninhabited_from (
141
- cx . tcx . hir ( ) . get_module_parent ( expr . hir_id ) , ty )
142
- {
143
+ let module = cx. tcx . hir ( ) . get_module_parent ( expr . hir_id ) ;
144
+
145
+ if ty . is_unit ( ) || cx . tcx . is_ty_uninhabited_from ( module , ty ) {
143
146
return true ;
144
147
}
145
148
146
- let plural_suffix = pluralise ! ( plural_len ) ;
149
+ let plural_suffix = pluralise ! ( len ) ;
147
150
148
151
match ty. kind {
149
152
ty:: Adt ( ..) if ty. is_box ( ) => {
150
153
let boxed_ty = ty. boxed_ty ( ) ;
151
154
let descr_pre = & format ! ( "{}boxed " , descr_pre) ;
152
- check_must_use_ty ( cx, boxed_ty, expr, span, descr_pre, descr_post, plural_len )
155
+ check_must_use_ty ( cx, boxed_ty, expr, span, descr_pre, descr_post, len , err )
153
156
}
154
- ty:: Adt ( def, _) => {
155
- check_must_use_def ( cx, def. did , span, descr_pre, descr_post)
157
+ ty:: Adt ( def, subst) => {
158
+ // Check the type itself for `#[must_use]` annotations.
159
+ let mut has_emitted = check_must_use_def (
160
+ cx, def. did , span, descr_pre, descr_post, err) ;
161
+ // Check any fields of the type for `#[must_use]` annotations.
162
+ // We ignore ADTs with more than one variant for simplicity and to avoid
163
+ // false positives.
164
+ // Unions are also ignored (though in theory, we could lint if every field of
165
+ // a union was `#[must_use]`).
166
+ if def. variants . len ( ) == 1 && !def. is_union ( ) {
167
+ let fields = match & expr. kind {
168
+ hir:: ExprKind :: Struct ( _, fields, _) => {
169
+ fields. iter ( ) . map ( |f| & * f. expr ) . collect ( )
170
+ }
171
+ hir:: ExprKind :: Call ( _, args) => args. iter ( ) . collect ( ) ,
172
+ _ => HirVec :: new ( ) ,
173
+ } ;
174
+
175
+ for variant in & def. variants {
176
+ for ( i, field) in variant. fields . iter ( ) . enumerate ( ) {
177
+ let is_visible = def. is_enum ( ) ||
178
+ field. vis . is_accessible_from ( module, cx. tcx ) ;
179
+ if is_visible {
180
+ let descr_post
181
+ = & format ! ( " in field `{}`" , field. ident. as_str( ) ) ;
182
+ let ty = cx. tcx . type_of ( field. did ) . subst ( cx. tcx , subst) ;
183
+ let ( expr, span) = if let Some ( & field) = fields. get ( i) {
184
+ ( field, field. span )
185
+ } else {
186
+ ( expr, span)
187
+ } ;
188
+ has_emitted |= check_must_use_ty (
189
+ cx, ty, expr, span, descr_pre, descr_post, len, true ) ;
190
+ }
191
+ }
192
+ }
193
+ }
194
+ has_emitted
156
195
}
157
196
ty:: Opaque ( def, _) => {
158
197
let mut has_emitted = false ;
@@ -165,7 +204,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
165
204
descr_pre,
166
205
plural_suffix,
167
206
) ;
168
- if check_must_use_def ( cx, def_id, span, descr_pre, descr_post) {
207
+ if check_must_use_def ( cx, def_id, span, descr_pre, descr_post, err ) {
169
208
has_emitted = true ;
170
209
break ;
171
210
}
@@ -183,7 +222,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
183
222
plural_suffix,
184
223
descr_post,
185
224
) ;
186
- if check_must_use_def ( cx, def_id, span, descr_pre, descr_post) {
225
+ if check_must_use_def ( cx, def_id, span, descr_pre, descr_post, err ) {
187
226
has_emitted = true ;
188
227
break ;
189
228
}
@@ -202,32 +241,25 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
202
241
for ( i, ty) in tys. iter ( ) . map ( |k| k. expect_ty ( ) ) . enumerate ( ) {
203
242
let descr_post = & format ! ( " in tuple element {}" , i) ;
204
243
let span = * spans. get ( i) . unwrap_or ( & span) ;
205
- if check_must_use_ty (
206
- cx,
207
- ty,
208
- expr,
209
- span,
210
- descr_pre,
211
- descr_post,
212
- plural_len
213
- ) {
214
- has_emitted = true ;
215
- }
244
+ has_emitted |= check_must_use_ty (
245
+ cx, ty, expr, span, descr_pre, descr_post, len, err) ;
216
246
}
217
247
has_emitted
218
248
}
219
249
ty:: Array ( ty, len) => match len. try_eval_usize ( cx. tcx , cx. param_env ) {
220
- // If the array is definitely non-empty, we can do `#[must_use]` checking.
221
- Some ( n) if n != 0 => {
250
+ // Empty arrays won't contain any `#[must_use]` types.
251
+ Some ( 0 ) => false ,
252
+ // If the array may be non-empty, we do `#[must_use]` checking.
253
+ _ => {
222
254
let descr_pre = & format ! (
223
255
"{}array{} of " ,
224
256
descr_pre,
225
257
plural_suffix,
226
258
) ;
227
- check_must_use_ty ( cx, ty, expr, span, descr_pre, descr_post, n as usize + 1 )
259
+ // `2` is just a stand-in for a number greater than 1, for correct plurals
260
+ // in diagnostics.
261
+ check_must_use_ty ( cx, ty, expr, span, descr_pre, descr_post, 2 , err)
228
262
}
229
- // Otherwise, we don't lint, to avoid false positives.
230
- _ => false ,
231
263
}
232
264
_ => false ,
233
265
}
@@ -240,12 +272,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
240
272
span : Span ,
241
273
descr_pre_path : & str ,
242
274
descr_post_path : & str ,
275
+ force_err : bool , // HACK: Report an error rather than a lint, for crater testing.
243
276
) -> bool {
244
277
for attr in cx. tcx . get_attrs ( def_id) . iter ( ) {
245
278
if attr. check_name ( sym:: must_use) {
246
279
let msg = format ! ( "unused {}`{}`{} that must be used" ,
247
280
descr_pre_path, cx. tcx. def_path_str( def_id) , descr_post_path) ;
248
- let mut err = cx. struct_span_lint ( UNUSED_MUST_USE , span, & msg) ;
281
+ let mut err = if !force_err {
282
+ cx. struct_span_lint ( UNUSED_MUST_USE , span, & msg)
283
+ } else {
284
+ cx. sess ( ) . struct_span_err ( span, & msg)
285
+ } ;
249
286
// check for #[must_use = "..."]
250
287
if let Some ( note) = attr. value_str ( ) {
251
288
err. note ( & note. as_str ( ) ) ;
0 commit comments