@@ -35,6 +35,7 @@ use rustc_middle::ty::adjustment::{
35
35
use rustc_middle:: ty:: Ty ;
36
36
use rustc_middle:: ty:: TypeFoldable ;
37
37
use rustc_middle:: ty:: { AdtKind , Visibility } ;
38
+ use rustc_session:: lint:: builtin:: UNUSED_ASSIGNMENTS ;
38
39
use rustc_span:: hygiene:: DesugaringKind ;
39
40
use rustc_span:: source_map:: Span ;
40
41
use rustc_span:: symbol:: { kw, sym, Symbol } ;
@@ -800,13 +801,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
800
801
801
802
self . require_type_is_sized ( lhs_ty, lhs. span , traits:: AssignmentLhsSized ) ;
802
803
804
+ self . check_unused_assign_to_field ( lhs, span) ;
805
+
803
806
if lhs_ty. references_error ( ) || rhs_ty. references_error ( ) {
804
807
self . tcx . types . err
805
808
} else {
806
809
self . tcx . mk_unit ( )
807
810
}
808
811
}
809
812
813
+ /// Check the LHS for unused assignments to fields, when they aren't bound to a local variable
814
+ pub ( crate ) fn check_unused_assign_to_field (
815
+ & self ,
816
+ lhs : & ' tcx hir:: Expr < ' tcx > ,
817
+ expr_span : & Span ,
818
+ ) {
819
+ debug ! ( "check_unused_assign(lhs = {:?})" , & lhs) ;
820
+ match lhs. kind {
821
+ ExprKind :: Struct ( ..) | ExprKind :: Tup ( ..) => {
822
+ self . tcx . struct_span_lint_hir ( UNUSED_ASSIGNMENTS , lhs. hir_id , * expr_span, |lint| {
823
+ lint. build ( "unused assignement to temporary" )
824
+ . span_label ( lhs. span , "this is not bound to any variable" )
825
+ . emit ( ) ;
826
+ } )
827
+ }
828
+ // Assigning to a field of a const is useless, since the constant will
829
+ // get evaluated and injected into the expression
830
+ ExprKind :: Path ( QPath :: Resolved (
831
+ _,
832
+ hir:: Path { res : Res :: Def ( DefKind :: Const , _) , ref segments, .. } ,
833
+ ) ) => {
834
+ let const_name = segments. last ( ) . unwrap ( ) . ident . as_str ( ) ;
835
+ let mut path_str = String :: new ( ) ;
836
+ for ( i, seg) in segments. iter ( ) . enumerate ( ) {
837
+ if i > 0 {
838
+ path_str. push_str ( "::" ) ;
839
+ }
840
+ if seg. ident . name != kw:: PathRoot {
841
+ path_str. push_str ( & seg. ident . as_str ( ) ) ;
842
+ }
843
+ }
844
+
845
+ self . tcx . struct_span_lint_hir ( UNUSED_ASSIGNMENTS , lhs. hir_id , * expr_span, |lint| {
846
+ lint. build ( "unused assignement to temporary" )
847
+ . span_label ( lhs. span , "this is not bound to any variable" )
848
+ . note ( "in Rust, constants are not associated with a specific memory location, and are inlined wherever they are used" )
849
+ . span_suggestion (
850
+ lhs. span . shrink_to_lo ( ) ,
851
+ "consider introducing a local variable" ,
852
+ format ! ( "let mut {} = {};" , ( & * const_name) . to_lowercase( ) , path_str) , Applicability :: MaybeIncorrect )
853
+ . emit ( ) ;
854
+ } )
855
+ }
856
+ ExprKind :: Field ( ref base, _) => self . check_unused_assign_to_field ( base, expr_span) ,
857
+ _ => { }
858
+ }
859
+ }
860
+
810
861
fn check_expr_loop (
811
862
& self ,
812
863
body : & ' tcx hir:: Block < ' tcx > ,
0 commit comments