@@ -45,6 +45,9 @@ struct Access {
4545 /// When we encounter multiple statements at the same location, we only increase the liveness,
4646 /// in order to avoid false positives.
4747 live : bool ,
48+ /// Is this a direct access to the place itself, no projections, or to a field?
49+ /// This helps distinguish `x = ...` from `x.field = ...`
50+ is_direct : bool ,
4851}
4952
5053#[ tracing:: instrument( level = "debug" , skip( tcx) , ret) ]
@@ -650,9 +653,10 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
650653 |place : Place < ' tcx > , kind, source_info : SourceInfo , live : & DenseBitSet < PlaceIndex > | {
651654 if let Some ( ( index, extra_projections) ) = checked_places. get ( place. as_ref ( ) ) {
652655 if !is_indirect ( extra_projections) {
656+ let is_direct = extra_projections. is_empty ( ) ;
653657 match assignments[ index] . entry ( source_info) {
654658 IndexEntry :: Vacant ( v) => {
655- let access = Access { kind, live : live. contains ( index) } ;
659+ let access = Access { kind, live : live. contains ( index) , is_direct } ;
656660 v. insert ( access) ;
657661 }
658662 IndexEntry :: Occupied ( mut o) => {
@@ -742,7 +746,7 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
742746 continue ;
743747 } ;
744748 let source_info = body. local_decls [ place. local ] . source_info ;
745- let access = Access { kind, live : live. contains ( index) } ;
749+ let access = Access { kind, live : live. contains ( index) , is_direct : true } ;
746750 assignments[ index] . insert ( source_info, access) ;
747751 }
748752 }
@@ -1048,26 +1052,41 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
10481052
10491053 let Some ( ( name, decl_span) ) = self . checked_places . names [ index] else { continue } ;
10501054
1051- // We have outstanding assignments and with non-trivial drop.
1052- // This is probably a drop-guard, so we do not issue a warning there.
1053- if maybe_drop_guard (
1055+ let is_maybe_drop_guard = maybe_drop_guard (
10541056 tcx,
10551057 self . typing_env ,
10561058 index,
10571059 & self . ever_dropped ,
10581060 self . checked_places ,
10591061 self . body ,
1060- ) {
1062+ ) ;
1063+
1064+ let is_pure_drop_guard = is_maybe_drop_guard && {
1065+ // Check if ALL direct assignments are not live
1066+ // which meaning the place is never read
1067+ statements
1068+ . values ( )
1069+ . filter ( |access| access. kind == AccessKind :: Assign && access. is_direct )
1070+ . all ( |access| !access. live )
1071+ } ;
1072+
1073+ if is_pure_drop_guard {
10611074 continue ;
10621075 }
10631076
10641077 // We probed MIR in reverse order for dataflow.
10651078 // We revert the vector to give a consistent order to the user.
1066- for ( source_info, Access { live, kind } ) in statements. into_iter ( ) . rev ( ) {
1079+ for ( source_info, Access { live, kind, is_direct } ) in statements. into_iter ( ) . rev ( ) {
10671080 if live {
10681081 continue ;
10691082 }
10701083
1084+ // If this place was dropped and has non-trivial drop,
1085+ // skip reporting field assignments.
1086+ if !is_direct && is_maybe_drop_guard {
1087+ continue ;
1088+ }
1089+
10711090 // Report the dead assignment.
10721091 let Some ( hir_id) = source_info. scope . lint_root ( & self . body . source_scopes ) else {
10731092 continue ;
0 commit comments