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;
68use rustc_data_structures:: fx:: FxHashMap ;
79use lint:: { LateContext , EarlyContext , LintContext , LintArray } ;
@@ -48,7 +50,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
4850 }
4951
5052 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 ) ;
5254
5355 let mut fn_warned = false ;
5456 let mut op_warned = false ;
@@ -73,7 +75,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
7375 _ => None
7476 } ;
7577 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 ) ;
7779 } else if type_permits_lack_of_use {
7880 // We don't warn about unused unit or uninhabited types.
7981 // (See https://github.com/rust-lang/rust/issues/43806 for details.)
@@ -135,24 +137,61 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
135137 span : Span ,
136138 descr_pre : & str ,
137139 descr_post : & str ,
138- plural_len : usize ,
140+ len : usize ,
141+ err : bool , // HACK: Report an error rather than a lint, for crater testing.
139142 ) -> 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 ) {
143146 return true ;
144147 }
145148
146- let plural_suffix = pluralise ! ( plural_len ) ;
149+ let plural_suffix = pluralise ! ( len ) ;
147150
148151 match ty. kind {
149152 ty:: Adt ( ..) if ty. is_box ( ) => {
150153 let boxed_ty = ty. boxed_ty ( ) ;
151154 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 )
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, 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
156195 }
157196 ty:: Opaque ( def, _) => {
158197 let mut has_emitted = false ;
@@ -165,7 +204,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
165204 descr_pre,
166205 plural_suffix,
167206 ) ;
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 ) {
169208 has_emitted = true ;
170209 break ;
171210 }
@@ -183,7 +222,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
183222 plural_suffix,
184223 descr_post,
185224 ) ;
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 ) {
187226 has_emitted = true ;
188227 break ;
189228 }
@@ -202,32 +241,25 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
202241 for ( i, ty) in tys. iter ( ) . map ( |k| k. expect_ty ( ) ) . enumerate ( ) {
203242 let descr_post = & format ! ( " in tuple element {}" , i) ;
204243 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) ;
216246 }
217247 has_emitted
218248 }
219249 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+ _ => {
222254 let descr_pre = & format ! (
223255 "{}array{} of " ,
224256 descr_pre,
225257 plural_suffix,
226258 ) ;
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)
228262 }
229- // Otherwise, we don't lint, to avoid false positives.
230- _ => false ,
231263 }
232264 _ => false ,
233265 }
@@ -240,12 +272,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
240272 span : Span ,
241273 descr_pre_path : & str ,
242274 descr_post_path : & str ,
275+ force_err : bool , // HACK: Report an error rather than a lint, for crater testing.
243276 ) -> bool {
244277 for attr in cx. tcx . get_attrs ( def_id) . iter ( ) {
245278 if attr. check_name ( sym:: must_use) {
246279 let msg = format ! ( "unused {}`{}`{} that must be used" ,
247280 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+ } ;
249286 // check for #[must_use = "..."]
250287 if let Some ( note) = attr. value_str ( ) {
251288 err. note ( & note. as_str ( ) ) ;
0 commit comments