@@ -2130,21 +2130,27 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
21302130 /// misleading users in cases like `tests/ui/nll/borrowed-temporary-error.rs`.
21312131 /// We could expand the analysis to suggest hoising all of the relevant parts of
21322132 /// the users' code to make the code compile, but that could be too much.
2133- struct NestedStatementVisitor {
2133+ /// We found the `prop_expr` by the way to check whether the expression is a `FormatArguments`,
2134+ /// which is a special case since it's generated by the compiler.
2135+ struct NestedStatementVisitor < ' tcx > {
21342136 span : Span ,
21352137 current : usize ,
21362138 found : usize ,
2139+ prop_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
21372140 }
21382141
2139- impl < ' tcx > Visitor < ' tcx > for NestedStatementVisitor {
2140- fn visit_block ( & mut self , block : & hir:: Block < ' tcx > ) {
2142+ impl < ' tcx > Visitor < ' tcx > for NestedStatementVisitor < ' tcx > {
2143+ fn visit_block ( & mut self , block : & ' tcx hir:: Block < ' tcx > ) {
21412144 self . current += 1 ;
21422145 walk_block ( self , block) ;
21432146 self . current -= 1 ;
21442147 }
2145- fn visit_expr ( & mut self , expr : & hir:: Expr < ' tcx > ) {
2148+ fn visit_expr ( & mut self , expr : & ' tcx hir:: Expr < ' tcx > ) {
21462149 if self . span == expr. span . source_callsite ( ) {
21472150 self . found = self . current ;
2151+ if self . prop_expr . is_none ( ) {
2152+ self . prop_expr = Some ( expr) ;
2153+ }
21482154 }
21492155 walk_expr ( self , expr) ;
21502156 }
@@ -2162,22 +2168,40 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
21622168 span : proper_span,
21632169 current : 0 ,
21642170 found : 0 ,
2171+ prop_expr : None ,
21652172 } ;
21662173 visitor. visit_stmt ( stmt) ;
2174+
2175+ let typeck_results = self . infcx . tcx . typeck ( self . mir_def_id ( ) ) ;
2176+ let expr_ty: Option < Ty < ' _ > > = visitor. prop_expr . map ( |expr| typeck_results. expr_ty ( expr) . peel_refs ( ) ) ;
2177+
2178+ let is_format_arguments_item =
2179+ if let Some ( expr_ty) = expr_ty
2180+ && let ty:: Adt ( adt, _) = expr_ty. kind ( ) {
2181+ self . infcx . tcx . lang_items ( ) . get ( LangItem :: FormatArguments ) == Some ( adt. did ( ) )
2182+ } else {
2183+ false
2184+ } ;
2185+
21672186 if visitor. found == 0
21682187 && stmt. span . contains ( proper_span)
21692188 && let Some ( p) = sm. span_to_margin ( stmt. span )
21702189 && let Ok ( s) = sm. span_to_snippet ( proper_span)
21712190 {
2172- let addition = format ! ( "let binding = {};\n {}" , s, " " . repeat( p) ) ;
2173- err. multipart_suggestion_verbose (
2174- msg,
2175- vec ! [
2176- ( stmt. span. shrink_to_lo( ) , addition) ,
2177- ( proper_span, "binding" . to_string( ) ) ,
2178- ] ,
2179- Applicability :: MaybeIncorrect ,
2180- ) ;
2191+ if !is_format_arguments_item {
2192+ let addition = format ! ( "let binding = {};\n {}" , s, " " . repeat( p) ) ;
2193+ err. multipart_suggestion_verbose (
2194+ msg,
2195+ vec ! [
2196+ ( stmt. span. shrink_to_lo( ) , addition) ,
2197+ ( proper_span, "binding" . to_string( ) ) ,
2198+ ] ,
2199+ Applicability :: MaybeIncorrect ,
2200+ ) ;
2201+ } else {
2202+ err. note ( "the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used" ) ;
2203+ err. note ( "to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>" ) ;
2204+ }
21812205 suggested = true ;
21822206 break ;
21832207 }
0 commit comments