11use rustc:: hir:: def:: { Res , DefKind } ;
22use rustc:: hir:: def_id:: DefId ;
33use rustc:: lint;
4- use rustc:: ty;
4+ use rustc:: ty:: { self , Ty } ;
55use rustc:: ty:: adjustment;
66use rustc_data_structures:: fx:: FxHashMap ;
77use lint:: { LateContext , EarlyContext , LintContext , LintArray } ;
@@ -47,43 +47,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
4747 return ;
4848 }
4949
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 , "" ) ;
8752
8853 let mut fn_warned = false ;
8954 let mut op_warned = false ;
@@ -108,7 +73,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
10873 _ => None
10974 } ;
11075 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 " , "" ) ;
11277 } else if type_permits_lack_of_use {
11378 // We don't warn about unused unit or uninhabited types.
11479 // (See https://github.com/rust-lang/rust/issues/43806 for details.)
@@ -162,18 +127,83 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
162127 cx. span_lint ( UNUSED_RESULTS , s. span , "unused result" ) ;
163128 }
164129
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 (
166196 cx : & LateContext < ' _ , ' _ > ,
167197 def_id : DefId ,
168- sp : Span ,
198+ span : Span ,
169199 descr_pre_path : & str ,
170200 descr_post_path : & str ,
171201 ) -> bool {
172202 for attr in cx. tcx . get_attrs ( def_id) . iter ( ) {
173203 if attr. check_name ( sym:: must_use) {
174204 let msg = format ! ( "unused {}`{}`{} that must be used" ,
175205 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) ;
177207 // check for #[must_use = "..."]
178208 if let Some ( note) = attr. value_str ( ) {
179209 err. note ( & note. as_str ( ) ) ;
0 commit comments