Skip to content

Commit 2f45294

Browse files
arielb1Ariel Ben-Yehuda
authored and
Ariel Ben-Yehuda
committed
Clean-up assignment checking in borrowck
1 parent 40db46c commit 2f45294

File tree

5 files changed

+137
-264
lines changed

5 files changed

+137
-264
lines changed

src/librustc_borrowck/borrowck/check_loans.rs

Lines changed: 21 additions & 186 deletions
Original file line numberDiff line numberDiff line change
@@ -565,13 +565,6 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
565565
true
566566
}
567567

568-
fn is_local_variable_or_arg(&self, cmt: mc::cmt<'tcx>) -> bool {
569-
match cmt.cat {
570-
mc::cat_local(_) => true,
571-
_ => false
572-
}
573-
}
574-
575568
fn consume_common(&self,
576569
id: ast::NodeId,
577570
span: Span,
@@ -793,198 +786,40 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
793786
mode: euv::MutateMode) {
794787
debug!("check_assignment(assignee_cmt={:?})", assignee_cmt);
795788

796-
// Mutable values can be assigned, as long as they obey loans
797-
// and aliasing restrictions:
798-
if assignee_cmt.mutbl.is_mutable() {
799-
if check_for_aliasable_mutable_writes(self, assignment_span, assignee_cmt.clone()) {
800-
if mode != euv::Init {
801-
check_for_assignment_to_borrowed_path(
802-
self, assignment_id, assignment_span, assignee_cmt.clone());
803-
mark_variable_as_used_mut(self, assignee_cmt);
804-
}
805-
}
806-
807-
return;
808-
}
809-
810-
// Initializations are OK if and only if they aren't partial
811-
// reinitialization of a partially-uninitialized structure.
789+
// Initializations never cause borrow errors as they only
790+
// affect a fresh local.
812791
if mode == euv::Init {
813792
return
814793
}
815794

816-
// For immutable local variables, assignments are legal
817-
// if they cannot already have been assigned
818-
if self.is_local_variable_or_arg(assignee_cmt.clone()) {
819-
assert!(assignee_cmt.mutbl.is_immutable()); // no "const" locals
820-
let lp = opt_loan_path(&assignee_cmt).unwrap();
821-
self.move_data.each_assignment_of(assignment_id, &lp, |assign| {
822-
self.bccx.report_reassigned_immutable_variable(
823-
assignment_span,
824-
&*lp,
825-
assign);
795+
// Check that we don't invalidate any outstanding loans
796+
if let Some(loan_path) = opt_loan_path(&assignee_cmt) {
797+
let scope = region::CodeExtent::from_node_id(assignment_id);
798+
self.each_in_scope_loan_affecting_path(scope, &*loan_path, |loan| {
799+
self.report_illegal_mutation(assignment_span, &*loan_path, loan);
826800
false
827801
});
828-
return;
829-
}
830-
831-
// Otherwise, just a plain error.
832-
match assignee_cmt.note {
833-
mc::NoteClosureEnv(upvar_id) => {
834-
// If this is an `Fn` closure, it simply can't mutate upvars.
835-
// If it's an `FnMut` closure, the original variable was declared immutable.
836-
// We need to determine which is the case here.
837-
let kind = match assignee_cmt.upvar().unwrap().cat {
838-
mc::cat_upvar(mc::Upvar { kind, .. }) => kind,
839-
_ => unreachable!()
840-
};
841-
if kind == ty::FnClosureKind {
842-
self.bccx.span_err(
843-
assignment_span,
844-
&format!("cannot assign to {}",
845-
self.bccx.cmt_to_string(&*assignee_cmt)));
846-
self.bccx.span_help(
847-
self.tcx().map.span(upvar_id.closure_expr_id),
848-
"consider changing this closure to take self by mutable reference");
849-
} else {
850-
self.bccx.span_err(
851-
assignment_span,
852-
&format!("cannot assign to {} {}",
853-
assignee_cmt.mutbl.to_user_str(),
854-
self.bccx.cmt_to_string(&*assignee_cmt)));
855-
}
856-
}
857-
_ => match opt_loan_path(&assignee_cmt) {
858-
Some(lp) => {
859-
self.bccx.span_err(
860-
assignment_span,
861-
&format!("cannot assign to {} {} `{}`",
862-
assignee_cmt.mutbl.to_user_str(),
863-
self.bccx.cmt_to_string(&*assignee_cmt),
864-
self.bccx.loan_path_to_string(&*lp)));
865-
}
866-
None => {
867-
self.bccx.span_err(
868-
assignment_span,
869-
&format!("cannot assign to {} {}",
870-
assignee_cmt.mutbl.to_user_str(),
871-
self.bccx.cmt_to_string(&*assignee_cmt)));
872-
}
873-
}
874-
}
875-
return;
876-
877-
fn mark_variable_as_used_mut<'a, 'tcx>(this: &CheckLoanCtxt<'a, 'tcx>,
878-
mut cmt: mc::cmt<'tcx>) {
879-
//! If the mutability of the `cmt` being written is inherited
880-
//! from a local variable, liveness will
881-
//! not have been able to detect that this variable's mutability
882-
//! is important, so we must add the variable to the
883-
//! `used_mut_nodes` table here.
884-
885-
loop {
886-
debug!("mark_variable_as_used_mut(cmt={:?})", cmt);
887-
match cmt.cat.clone() {
888-
mc::cat_upvar(mc::Upvar { id: ty::UpvarId { var_id: id, .. }, .. }) |
889-
mc::cat_local(id) => {
890-
this.tcx().used_mut_nodes.borrow_mut().insert(id);
891-
return;
892-
}
893-
894-
mc::cat_rvalue(..) |
895-
mc::cat_static_item |
896-
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
897-
mc::cat_deref(_, _, mc::Implicit(..)) => {
898-
assert_eq!(cmt.mutbl, mc::McDeclared);
899-
return;
900-
}
901-
902-
mc::cat_deref(_, _, mc::BorrowedPtr(..)) => {
903-
assert_eq!(cmt.mutbl, mc::McDeclared);
904-
// We need to drill down to upvar if applicable
905-
match cmt.upvar() {
906-
Some(b) => cmt = b,
907-
None => return
908-
}
909-
}
910-
911-
mc::cat_deref(b, _, mc::Unique) => {
912-
assert_eq!(cmt.mutbl, mc::McInherited);
913-
cmt = b;
914-
}
915-
916-
mc::cat_downcast(b, _) |
917-
mc::cat_interior(b, _) => {
918-
assert_eq!(cmt.mutbl, mc::McInherited);
919-
cmt = b;
920-
}
921-
}
922-
}
923802
}
924803

925-
fn check_for_aliasable_mutable_writes<'a, 'tcx>(this: &CheckLoanCtxt<'a, 'tcx>,
926-
span: Span,
927-
cmt: mc::cmt<'tcx>) -> bool {
928-
//! Safety checks related to writes to aliasable, mutable locations
929-
930-
let guarantor = cmt.guarantor();
931-
debug!("check_for_aliasable_mutable_writes(cmt={:?}, guarantor={:?})",
932-
cmt, guarantor);
933-
if let mc::cat_deref(ref b, _, mc::BorrowedPtr(ty::MutBorrow, _)) = guarantor.cat {
934-
// Statically prohibit writes to `&mut` when aliasable
935-
check_for_aliasability_violation(this, span, b.clone());
804+
// Local variables can always be assigned to, expect for reassignments
805+
// of immutable variables (or assignments that invalidate loans,
806+
// of course).
807+
if let mc::cat_local(local_id) = assignee_cmt.cat {
808+
if assignee_cmt.mutbl.is_mutable() {
809+
self.tcx().used_mut_nodes.borrow_mut().insert(local_id);
936810
}
937811

938-
return true; // no errors reported
939-
}
940-
941-
fn check_for_aliasability_violation<'a, 'tcx>(this: &CheckLoanCtxt<'a, 'tcx>,
942-
span: Span,
943-
cmt: mc::cmt<'tcx>)
944-
-> bool {
945-
match cmt.freely_aliasable(this.tcx()) {
946-
mc::Aliasability::NonAliasable => {
947-
return true;
948-
}
949-
mc::Aliasability::FreelyAliasable(mc::AliasableStaticMut(..)) => {
950-
return true;
951-
}
952-
mc::Aliasability::ImmutableUnique(_) => {
953-
this.bccx.report_aliasability_violation(
954-
span,
955-
MutabilityViolation,
956-
mc::AliasableReason::UnaliasableImmutable);
957-
return false;
958-
}
959-
mc::Aliasability::FreelyAliasable(cause) => {
960-
this.bccx.report_aliasability_violation(
961-
span,
962-
MutabilityViolation,
963-
cause);
964-
return false;
812+
let lp = opt_loan_path(&assignee_cmt).unwrap();
813+
self.move_data.each_assignment_of(assignment_id, &lp, |assign| {
814+
if !assignee_cmt.mutbl.is_mutable() {
815+
self.bccx.report_reassigned_immutable_variable(
816+
assignment_span,
817+
&*lp,
818+
assign);
965819
}
966-
}
967-
}
968-
969-
fn check_for_assignment_to_borrowed_path<'a, 'tcx>(
970-
this: &CheckLoanCtxt<'a, 'tcx>,
971-
assignment_id: ast::NodeId,
972-
assignment_span: Span,
973-
assignee_cmt: mc::cmt<'tcx>)
974-
{
975-
//! Check for assignments that violate the terms of an
976-
//! outstanding loan.
977-
978-
let loan_path = match opt_loan_path(&assignee_cmt) {
979-
Some(lp) => lp,
980-
None => { return; /* no loan path, can't be any loans */ }
981-
};
982-
983-
let scope = region::CodeExtent::from_node_id(assignment_id);
984-
this.each_in_scope_loan_affecting_path(scope, &*loan_path, |loan| {
985-
this.report_illegal_mutation(assignment_span, &*loan_path, loan);
986820
false
987821
});
822+
return
988823
}
989824
}
990825

src/librustc_borrowck/borrowck/gather_loans/lifetime.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
137137
fn report_error(&self, code: bckerr_code) {
138138
self.bccx.report(BckError { cmt: self.cmt_original.clone(),
139139
span: self.span,
140-
cause: self.cause,
140+
cause: BorrowViolation(self.cause),
141141
code: code });
142142
}
143143
}

0 commit comments

Comments
 (0)