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;
8
+ use rustc:: mir:: interpret:: { GlobalId , ConstValue } ;
6
9
use rustc_data_structures:: fx:: FxHashMap ;
7
10
use lint:: { LateContext , EarlyContext , LintContext , LintArray } ;
8
11
use lint:: { LintPass , EarlyLintPass , LateLintPass } ;
@@ -23,7 +26,7 @@ use log::debug;
23
26
24
27
declare_lint ! {
25
28
pub UNUSED_MUST_USE ,
26
- Warn ,
29
+ Deny ,
27
30
"unused result of a type flagged as `#[must_use]`" ,
28
31
report_in_external_macro: true
29
32
}
@@ -151,8 +154,40 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
151
154
let descr_pre = & format ! ( "{}boxed " , descr_pre) ;
152
155
check_must_use_ty ( cx, boxed_ty, expr, span, descr_pre, descr_post, plural)
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) ;
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. node {
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 descr_post
178
+ = & format ! ( " in field `{}`" , field. ident. as_str( ) ) ;
179
+ let ty = cx. tcx . type_of ( field. did ) . subst ( cx. tcx , subst) ;
180
+ let ( expr, span) = if let Some ( & field) = fields. get ( i) {
181
+ ( field, field. span )
182
+ } else {
183
+ ( expr, span)
184
+ } ;
185
+ has_emitted |= check_must_use_ty (
186
+ cx, ty, expr, span, descr_pre, descr_post, plural) ;
187
+ }
188
+ }
189
+ }
190
+ has_emitted
156
191
}
157
192
ty:: Opaque ( def, _) => {
158
193
let mut has_emitted = false ;
@@ -202,24 +237,43 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
202
237
for ( i, ty) in tys. iter ( ) . map ( |k| k. expect_ty ( ) ) . enumerate ( ) {
203
238
let descr_post = & format ! ( " in tuple element {}" , i) ;
204
239
let span = * spans. get ( i) . unwrap_or ( & span) ;
205
- if check_must_use_ty ( cx, ty, expr, span, descr_pre, descr_post, plural) {
206
- has_emitted = true ;
207
- }
240
+ has_emitted |= check_must_use_ty (
241
+ cx, ty, expr, span, descr_pre, descr_post, plural) ;
208
242
}
209
243
has_emitted
210
244
}
211
- ty:: Array ( ty, len) => match len. assert_usize ( cx. tcx ) {
212
- // If the array is definitely non-empty, we can do `#[must_use]` checking.
213
- Some ( n) if n != 0 => {
214
- let descr_pre = & format ! (
215
- "{}array{} of " ,
216
- descr_pre,
217
- plural_suffix,
218
- ) ;
219
- check_must_use_ty ( cx, ty, expr, span, descr_pre, descr_post, true )
245
+ ty:: Array ( ty, mut len) => {
246
+ // Try to evaluate the length if it's unevaluated.
247
+ // FIXME(59369): we should be able to remove this once we merge
248
+ // https://github.com/rust-lang/rust/pull/59369.
249
+ if let ConstValue :: Unevaluated ( def_id, substs) = len. val {
250
+ let instance = ty:: Instance :: resolve (
251
+ cx. tcx . global_tcx ( ) ,
252
+ cx. param_env ,
253
+ def_id,
254
+ substs,
255
+ ) . unwrap ( ) ;
256
+ let global_id = GlobalId {
257
+ instance,
258
+ promoted : None
259
+ } ;
260
+ if let Ok ( ct) = cx. tcx . const_eval ( cx. param_env . and ( global_id) ) {
261
+ len = ct;
262
+ }
263
+ }
264
+
265
+ match len. assert_usize ( cx. tcx ) {
266
+ Some ( 0 ) => false , // Empty arrays won't contain any `#[must_use]` types.
267
+ // If the array may be non-empty, we do `#[must_use]` checking.
268
+ _ => {
269
+ let descr_pre = & format ! (
270
+ "{}array{} of " ,
271
+ descr_pre,
272
+ plural_suffix,
273
+ ) ;
274
+ check_must_use_ty ( cx, ty, expr, span, descr_pre, descr_post, true )
275
+ }
220
276
}
221
- // Otherwise, we don't lint, to avoid false positives.
222
- _ => false ,
223
277
}
224
278
_ => false ,
225
279
}
0 commit comments