@@ -2130,21 +2130,27 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
2130
2130
/// misleading users in cases like `tests/ui/nll/borrowed-temporary-error.rs`.
2131
2131
/// We could expand the analysis to suggest hoising all of the relevant parts of
2132
2132
/// 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 > {
2134
2136
span : Span ,
2135
2137
current : usize ,
2136
2138
found : usize ,
2139
+ prop_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
2137
2140
}
2138
2141
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 > ) {
2141
2144
self . current += 1 ;
2142
2145
walk_block ( self , block) ;
2143
2146
self . current -= 1 ;
2144
2147
}
2145
- fn visit_expr ( & mut self , expr : & hir:: Expr < ' tcx > ) {
2148
+ fn visit_expr ( & mut self , expr : & ' tcx hir:: Expr < ' tcx > ) {
2146
2149
if self . span == expr. span . source_callsite ( ) {
2147
2150
self . found = self . current ;
2151
+ if self . prop_expr . is_none ( ) {
2152
+ self . prop_expr = Some ( expr) ;
2153
+ }
2148
2154
}
2149
2155
walk_expr ( self , expr) ;
2150
2156
}
@@ -2162,22 +2168,40 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
2162
2168
span : proper_span,
2163
2169
current : 0 ,
2164
2170
found : 0 ,
2171
+ prop_expr : None ,
2165
2172
} ;
2166
2173
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
+
2167
2186
if visitor. found == 0
2168
2187
&& stmt. span . contains ( proper_span)
2169
2188
&& let Some ( p) = sm. span_to_margin ( stmt. span )
2170
2189
&& let Ok ( s) = sm. span_to_snippet ( proper_span)
2171
2190
{
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
+ }
2181
2205
suggested = true ;
2182
2206
break ;
2183
2207
}
0 commit comments