11use rustc:: hir:: def:: { Res , DefKind } ;
22use rustc:: hir:: def_id:: DefId ;
3+ use rustc:: hir:: HirVec ;
34use rustc:: lint;
45use rustc:: ty:: { self , Ty } ;
6+ use rustc:: ty:: subst:: Subst ;
57use rustc:: ty:: adjustment;
8+ use rustc:: mir:: interpret:: { GlobalId , ConstValue } ;
69use rustc_data_structures:: fx:: FxHashMap ;
710use lint:: { LateContext , EarlyContext , LintContext , LintArray } ;
811use lint:: { LintPass , EarlyLintPass , LateLintPass } ;
@@ -23,7 +26,7 @@ use log::debug;
2326
2427declare_lint ! {
2528 pub UNUSED_MUST_USE ,
26- Warn ,
29+ Deny ,
2730 "unused result of a type flagged as `#[must_use]`" ,
2831 report_in_external_macro: true
2932}
@@ -151,8 +154,40 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
151154 let descr_pre = & format ! ( "{}boxed " , descr_pre) ;
152155 check_must_use_ty ( cx, boxed_ty, expr, span, descr_pre, descr_post, plural)
153156 }
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
156191 }
157192 ty:: Opaque ( def, _) => {
158193 let mut has_emitted = false ;
@@ -202,24 +237,43 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
202237 for ( i, ty) in tys. iter ( ) . map ( |k| k. expect_ty ( ) ) . enumerate ( ) {
203238 let descr_post = & format ! ( " in tuple element {}" , i) ;
204239 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) ;
208242 }
209243 has_emitted
210244 }
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+ }
220276 }
221- // Otherwise, we don't lint, to avoid false positives.
222- _ => false ,
223277 }
224278 _ => false ,
225279 }
0 commit comments