Skip to content

Commit 7d840de

Browse files
Emit warning when assigning to a temporary variable
1 parent e91aebc commit 7d840de

File tree

2 files changed

+52
-0
lines changed

2 files changed

+52
-0
lines changed

src/librustc_typeck/check/expr.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use rustc_middle::ty::adjustment::{
3535
use rustc_middle::ty::Ty;
3636
use rustc_middle::ty::TypeFoldable;
3737
use rustc_middle::ty::{AdtKind, Visibility};
38+
use rustc_session::lint::builtin::UNUSED_ASSIGNMENTS;
3839
use rustc_span::hygiene::DesugaringKind;
3940
use rustc_span::source_map::Span;
4041
use rustc_span::symbol::{kw, sym, Symbol};
@@ -800,13 +801,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
800801

801802
self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
802803

804+
self.check_unused_assign_to_field(lhs, span);
805+
803806
if lhs_ty.references_error() || rhs_ty.references_error() {
804807
self.tcx.types.err
805808
} else {
806809
self.tcx.mk_unit()
807810
}
808811
}
809812

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+
810861
fn check_expr_loop(
811862
&self,
812863
body: &'tcx hir::Block<'tcx>,

src/librustc_typeck/check/op.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3535
};
3636

3737
self.check_lhs_assignable(lhs, "E0067", &op.span);
38+
self.check_unused_assign_to_field(lhs, &op.span);
3839

3940
ty
4041
}

0 commit comments

Comments
 (0)