11use crate :: { LateContext , LateLintPass , LintContext } ;
22use rustc_errors:: Applicability ;
33use rustc_hir as hir;
4- use rustc_middle:: {
5- lint:: LintDiagnosticBuilder ,
6- ty:: { self , Ty } ,
7- } ;
4+ use rustc_middle:: { lint:: LintDiagnosticBuilder , ty} ;
85use rustc_span:: Symbol ;
96
107declare_lint ! {
@@ -87,32 +84,7 @@ declare_lint! {
8784 "non-binding let on a synchronization lock"
8885}
8986
90- declare_lint ! {
91- /// The `let_underscore_must_use` lint checks for statements which don't bind
92- /// a `must_use` expression to anything, causing the lock to be released
93- /// immediately instead of at end of scope, which is typically incorrect.
94- ///
95- /// ### Example
96- /// ```rust
97- /// #[must_use]
98- /// struct SomeStruct;
99- ///
100- /// fn main() {
101- /// // SomeStuct is dropped immediately instead of at end of scope.
102- /// let _ = SomeStruct;
103- /// }
104- /// ```
105- /// ### Explanation
106- ///
107- /// Statements which assign an expression to an underscore causes the
108- /// expression to immediately drop. Usually, it's better to explicitly handle
109- /// the `must_use` expression.
110- pub LET_UNDERSCORE_MUST_USE ,
111- Allow ,
112- "non-binding let on a expression marked `must_use`"
113- }
114-
115- declare_lint_pass ! ( LetUnderscore => [ LET_UNDERSCORE_DROP , LET_UNDERSCORE_LOCK , LET_UNDERSCORE_MUST_USE ] ) ;
87+ declare_lint_pass ! ( LetUnderscore => [ LET_UNDERSCORE_DROP , LET_UNDERSCORE_LOCK ] ) ;
11688
11789const SYNC_GUARD_SYMBOLS : [ Symbol ; 3 ] = [
11890 rustc_span:: sym:: MutexGuard ,
@@ -138,8 +110,6 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
138110 . any ( |guard_symbol| cx. tcx . is_diagnostic_item ( * guard_symbol, adt. did ( ) ) ) ,
139111 _ => false ,
140112 } ;
141- let is_must_use_ty = is_must_use_ty ( cx, cx. typeck_results ( ) . expr_ty ( init) ) ;
142- let is_must_use_func_call = is_must_use_func_call ( cx, init) ;
143113
144114 if is_sync_lock {
145115 cx. struct_span_lint ( LET_UNDERSCORE_LOCK , local. span , |lint| {
@@ -150,15 +120,6 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
150120 "non-binding let on a synchronization lock" ,
151121 )
152122 } )
153- } else if is_must_use_ty || is_must_use_func_call {
154- cx. struct_span_lint ( LET_UNDERSCORE_MUST_USE , local. span , |lint| {
155- build_and_emit_lint (
156- lint,
157- local,
158- init. span ,
159- "non-binding let on a expression marked `must_use`" ,
160- ) ;
161- } )
162123 } else {
163124 cx. struct_span_lint ( LET_UNDERSCORE_DROP , local. span , |lint| {
164125 build_and_emit_lint (
@@ -194,65 +155,3 @@ fn build_and_emit_lint(
194155 )
195156 . emit ( ) ;
196157}
197-
198- // return true if `ty` is a type that is marked as `must_use`
199- fn is_must_use_ty < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> bool {
200- match ty. kind ( ) {
201- ty:: Adt ( adt, _) => has_must_use_attr ( cx, adt. did ( ) ) ,
202- ty:: Foreign ( ref did) => has_must_use_attr ( cx, * did) ,
203- ty:: Slice ( ty)
204- | ty:: Array ( ty, _)
205- | ty:: RawPtr ( ty:: TypeAndMut { ty, .. } )
206- | ty:: Ref ( _, ty, _) => {
207- // for the Array case we don't need to care for the len == 0 case
208- // because we don't want to lint functions returning empty arrays
209- is_must_use_ty ( cx, * ty)
210- }
211- ty:: Tuple ( substs) => substs. iter ( ) . any ( |ty| is_must_use_ty ( cx, ty) ) ,
212- ty:: Opaque ( ref def_id, _) => {
213- for ( predicate, _) in cx. tcx . explicit_item_bounds ( * def_id) {
214- if let ty:: PredicateKind :: Trait ( trait_predicate) = predicate. kind ( ) . skip_binder ( ) {
215- if has_must_use_attr ( cx, trait_predicate. trait_ref . def_id ) {
216- return true ;
217- }
218- }
219- }
220- false
221- }
222- ty:: Dynamic ( binder, _) => {
223- for predicate in binder. iter ( ) {
224- if let ty:: ExistentialPredicate :: Trait ( ref trait_ref) = predicate. skip_binder ( ) {
225- if has_must_use_attr ( cx, trait_ref. def_id ) {
226- return true ;
227- }
228- }
229- }
230- false
231- }
232- _ => false ,
233- }
234- }
235-
236- // check if expr is calling method or function with #[must_use] attribute
237- fn is_must_use_func_call ( cx : & LateContext < ' _ > , expr : & hir:: Expr < ' _ > ) -> bool {
238- let did = match expr. kind {
239- hir:: ExprKind :: Call ( path, _) if let hir:: ExprKind :: Path ( ref qpath) = path. kind => {
240- if let hir:: def:: Res :: Def ( _, did) = cx. qpath_res ( qpath, path. hir_id ) {
241- Some ( did)
242- } else {
243- None
244- }
245- } ,
246- hir:: ExprKind :: MethodCall ( ..) => {
247- cx. typeck_results ( ) . type_dependent_def_id ( expr. hir_id )
248- }
249- _ => None ,
250- } ;
251-
252- did. map_or ( false , |did| has_must_use_attr ( cx, did) )
253- }
254-
255- // returns true if DefId contains a `#[must_use]` attribute
256- fn has_must_use_attr ( cx : & LateContext < ' _ > , did : hir:: def_id:: DefId ) -> bool {
257- cx. tcx . has_attr ( did, rustc_span:: sym:: must_use)
258- }
0 commit comments