diff options
Diffstat (limited to 'compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs')
-rw-r--r-- | compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs | 64 |
1 files changed, 44 insertions, 20 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index fe4a45b38..ee352e911 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1025,7 +1025,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None) } - (BorrowKind::Mut { .. }, BorrowKind::Shallow) => { + (BorrowKind::Mut { .. }, BorrowKind::Fake) => { if let Some(immutable_section_description) = self.classify_immutable_section(issued_borrow.assigned_place) { @@ -1117,11 +1117,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) } - (BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Shallow) - | ( - BorrowKind::Shallow, - BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow, - ) => unreachable!(), + (BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Fake) + | (BorrowKind::Fake, BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake) => { + unreachable!() + } }; if issued_spans == borrow_spans { @@ -2130,21 +2129,27 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// misleading users in cases like `tests/ui/nll/borrowed-temporary-error.rs`. /// We could expand the analysis to suggest hoising all of the relevant parts of /// the users' code to make the code compile, but that could be too much. - struct NestedStatementVisitor { + /// We found the `prop_expr` by the way to check whether the expression is a `FormatArguments`, + /// which is a special case since it's generated by the compiler. + struct NestedStatementVisitor<'tcx> { span: Span, current: usize, found: usize, + prop_expr: Option<&'tcx hir::Expr<'tcx>>, } - impl<'tcx> Visitor<'tcx> for NestedStatementVisitor { - fn visit_block(&mut self, block: &hir::Block<'tcx>) { + impl<'tcx> Visitor<'tcx> for NestedStatementVisitor<'tcx> { + fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) { self.current += 1; walk_block(self, block); self.current -= 1; } - fn visit_expr(&mut self, expr: &hir::Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { if self.span == expr.span.source_callsite() { self.found = self.current; + if self.prop_expr.is_none() { + self.prop_expr = Some(expr); + } } walk_expr(self, expr); } @@ -2162,22 +2167,40 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { span: proper_span, current: 0, found: 0, + prop_expr: None, }; visitor.visit_stmt(stmt); + + let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); + let expr_ty: Option<Ty<'_>> = visitor.prop_expr.map(|expr| typeck_results.expr_ty(expr).peel_refs()); + + let is_format_arguments_item = + if let Some(expr_ty) = expr_ty + && let ty::Adt(adt, _) = expr_ty.kind() { + self.infcx.tcx.lang_items().get(LangItem::FormatArguments) == Some(adt.did()) + } else { + false + }; + if visitor.found == 0 && stmt.span.contains(proper_span) && let Some(p) = sm.span_to_margin(stmt.span) && let Ok(s) = sm.span_to_snippet(proper_span) { - let addition = format!("let binding = {};\n{}", s, " ".repeat(p)); - err.multipart_suggestion_verbose( - msg, - vec![ - (stmt.span.shrink_to_lo(), addition), - (proper_span, "binding".to_string()), - ], - Applicability::MaybeIncorrect, - ); + if !is_format_arguments_item { + let addition = format!("let binding = {};\n{}", s, " ".repeat(p)); + err.multipart_suggestion_verbose( + msg, + vec![ + (stmt.span.shrink_to_lo(), addition), + (proper_span, "binding".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } else { + err.note("the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used"); + err.note("to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>"); + } suggested = true; break; } @@ -2620,7 +2643,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let loan_span = loan_spans.args_or_use(); let descr_place = self.describe_any_place(place.as_ref()); - if loan.kind == BorrowKind::Shallow { + if loan.kind == BorrowKind::Fake { if let Some(section) = self.classify_immutable_section(loan.assigned_place) { let mut err = self.cannot_mutate_in_immutable_section( span, @@ -2804,6 +2827,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } + | ProjectionElem::Subtype(_) | ProjectionElem::Index(_) => kind, }, place_ty.projection_ty(tcx, elem), |