Skip to content

Commit 59240af

Browse files
committed
Auto merge of #155828 - JonathanBrouwer:rollup-w1XiFiF, r=<try>
Rollup of 10 pull requests try-job: dist-various-1 try-job: test-various try-job: x86_64-gnu-aux try-job: x86_64-gnu-llvm-21-3 try-job: x86_64-msvc-1 try-job: aarch64-apple try-job: x86_64-mingw-1 try-job: i686-msvc-2
2 parents c7fe5e9 + f8e1380 commit 59240af

56 files changed

Lines changed: 1259 additions & 343 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,14 +156,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
156156
.collect();
157157
generic_args.push((kw::SelfUpper, this.clone()));
158158

159-
let args = FormatArgs {
160-
this,
161-
// Unused
162-
this_sugared: String::new(),
163-
// Unused
164-
item_context: "",
165-
generic_args,
166-
};
159+
let args = FormatArgs { this, generic_args, .. };
167160
let CustomDiagnostic { message, label, notes, parent_label: _ } =
168161
directive.eval(None, &args);
169162

compiler/rustc_builtin_macros/src/format.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,16 @@ fn make_format_args(
173173
style: fmt_style,
174174
uncooked_symbol: uncooked_fmt_str,
175175
} = {
176+
// Extract snippet so that we can check cases `{}`, `{:?}` and `{:#?}` and emit help for
177+
// them later.
178+
let snippet = if let ExprKind::Block(b, None) = &efmt.kind
179+
&& b.stmts.len() <= 1
180+
{
181+
Some(ecx.sess.source_map().span_to_snippet(unexpanded_fmt_span))
182+
} else {
183+
None
184+
};
185+
176186
let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, efmt.clone(), msg) else {
177187
return ExpandResult::Retry(());
178188
};
@@ -222,12 +232,26 @@ fn make_format_args(
222232
});
223233
}
224234
sugg_fmt = sugg_fmt.trim_end().to_string();
225-
err.span_suggestion(
235+
err.span_suggestion_verbose(
226236
unexpanded_fmt_span.shrink_to_lo(),
227237
"you might be missing a string literal to format with",
228238
format!("\"{sugg_fmt}\", "),
229239
Applicability::MaybeIncorrect,
230240
);
241+
242+
if let Some(Ok(snippet)) = snippet.as_ref() {
243+
match snippet.as_str() {
244+
"{}" | "{:?}" | "{:#?}" => {
245+
err.span_suggestion_verbose(
246+
unexpanded_fmt_span,
247+
format!("you might want to enclose `{snippet}` with `\"\"`"),
248+
format!("\"{snippet}\""),
249+
Applicability::MaybeIncorrect,
250+
);
251+
}
252+
_ => {}
253+
};
254+
}
231255
}
232256
}
233257
err.emit()

compiler/rustc_expand/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// tidy-alphabetical-start
22
#![allow(internal_features)]
33
#![feature(associated_type_defaults)]
4+
#![feature(default_field_values)]
45
#![feature(macro_metavar_expr)]
56
#![feature(proc_macro_diagnostic)]
67
#![feature(proc_macro_internals)]

compiler/rustc_expand/src/mbe/diagnostics.rs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -77,19 +77,8 @@ pub(super) fn failed_to_match_macro(
7777
let CustomDiagnostic {
7878
message: custom_message, label: custom_label, notes: custom_notes, ..
7979
} = {
80-
let macro_name = name.to_string();
8180
on_unmatch_args
82-
.map(|directive| {
83-
directive.eval(
84-
None,
85-
&FormatArgs {
86-
this: macro_name.clone(),
87-
this_sugared: macro_name,
88-
item_context: "macro invocation",
89-
generic_args: Vec::new(),
90-
},
91-
)
92-
})
81+
.map(|directive| directive.eval(None, &FormatArgs { this: name.to_string(), .. }))
9382
.unwrap_or_default()
9483
};
9584

compiler/rustc_hir/src/attrs/diagnostic.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,10 +218,11 @@ impl FormatString {
218218
/// ```
219219
#[derive(Debug)]
220220
pub struct FormatArgs {
221+
/// The name of the item the attribute is on.
221222
pub this: String,
222-
pub this_sugared: String,
223-
pub item_context: &'static str,
224-
pub generic_args: Vec<(Symbol, String)>,
223+
pub this_sugared: String = String::new(),
224+
pub item_context: &'static str = "",
225+
pub generic_args: Vec<(Symbol, String)> = Vec::new(),
225226
}
226227

227228
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]

compiler/rustc_hir/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#![feature(closure_track_caller)]
88
#![feature(const_default)]
99
#![feature(const_trait_impl)]
10+
#![feature(default_field_values)]
1011
#![feature(derive_const)]
1112
#![feature(exhaustive_patterns)]
1213
#![feature(never_type)]

compiler/rustc_hir_typeck/src/expr_use_visitor.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//! normal visitor, which just walks the entire body in one shot, the
33
//! `ExprUseVisitor` determines how expressions are being used.
44
//!
5-
//! In the compiler, this is only used for upvar inference, but there
5+
//! In the compiler, this is only used for upvar inference and diagnostics, but there
66
//! are many uses within clippy.
77
88
use std::cell::{Ref, RefCell};
@@ -1855,3 +1855,27 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
18551855
}
18561856
}
18571857
}
1858+
1859+
struct ExprPlaceDelegate;
1860+
1861+
impl<'tcx> Delegate<'tcx> for ExprPlaceDelegate {
1862+
fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
1863+
1864+
fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
1865+
1866+
fn borrow(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {}
1867+
1868+
fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
1869+
1870+
fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
1871+
}
1872+
1873+
/// Categorizes `expr` as a place for diagnostic suggestions.
1874+
///
1875+
/// This should be used for diagnostics purpose only.
1876+
pub(crate) fn expr_place<'tcx>(
1877+
fcx: &FnCtxt<'_, 'tcx>,
1878+
expr: &hir::Expr<'_>,
1879+
) -> Result<PlaceWithHirId<'tcx>, ErrorGuaranteed> {
1880+
ExprUseVisitor::new(fcx, ExprPlaceDelegate).cat_expr(expr)
1881+
}

compiler/rustc_hir_typeck/src/method/suggest.rs

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ use tracing::{debug, info, instrument};
4848
use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
4949
use super::{CandidateSource, MethodError, NoMatchData};
5050
use crate::errors::{self, CandidateTraitNote, NoAssociatedItem};
51+
use crate::expr_use_visitor::expr_place;
5152
use crate::method::probe::UnsatisfiedPredicates;
5253
use crate::{Expectation, FnCtxt};
5354

@@ -189,6 +190,70 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
189190
false
190191
}
191192

193+
// Pick the iterator method to suggest: `.into_iter()` by default, and
194+
// `.iter()`/`.iter_mut()` for projections through references.
195+
fn preferred_iterator_method(
196+
&self,
197+
source: SelfSource<'tcx>,
198+
rcvr_ty: Ty<'tcx>,
199+
) -> Option<Symbol> {
200+
let SelfSource::MethodCall(rcvr_expr) = source else {
201+
return Some(sym::into_iter);
202+
};
203+
204+
let rcvr_expr = rcvr_expr.peel_drop_temps().peel_blocks();
205+
let Ok(place_with_id) = expr_place(self, rcvr_expr) else {
206+
return None;
207+
};
208+
209+
let mut projection_mutability = None;
210+
for pointer_ty in place_with_id.place.deref_tys() {
211+
match self.structurally_resolve_type(rcvr_expr.span, pointer_ty).kind() {
212+
ty::Ref(.., Mutability::Not) => {
213+
projection_mutability = Some(Mutability::Not);
214+
break;
215+
}
216+
ty::Ref(.., Mutability::Mut) => {
217+
projection_mutability.get_or_insert(Mutability::Mut);
218+
}
219+
ty::RawPtr(..) => return None,
220+
_ => {}
221+
}
222+
}
223+
224+
// Keep `.into_iter()` for receivers like `&Vec<_>`; only projections that
225+
// dereference a reference need to switch to `iter`/`iter_mut`.
226+
let Some(projection_mutability) = projection_mutability else {
227+
return Some(sym::into_iter);
228+
};
229+
230+
let call_expr = self.tcx.hir_expect_expr(self.tcx.parent_hir_id(rcvr_expr.hir_id));
231+
// `IntoIterator` does not imply inherent `iter`/`iter_mut` methods.
232+
let has_method = |method_name| {
233+
self.lookup_probe_for_diagnostic(
234+
Ident::with_dummy_span(method_name),
235+
rcvr_ty,
236+
call_expr,
237+
ProbeScope::TraitsInScope,
238+
None,
239+
)
240+
.is_ok()
241+
};
242+
243+
match projection_mutability {
244+
Mutability::Not => has_method(sym::iter).then_some(sym::iter),
245+
Mutability::Mut => {
246+
if has_method(sym::iter_mut) {
247+
Some(sym::iter_mut)
248+
} else if has_method(sym::iter) {
249+
Some(sym::iter)
250+
} else {
251+
None
252+
}
253+
}
254+
}
255+
}
256+
192257
#[instrument(level = "debug", skip(self))]
193258
pub(crate) fn report_method_error(
194259
&self,
@@ -855,10 +920,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
855920
} else if self.impl_into_iterator_should_be_iterator(rcvr_ty, span, unsatisfied_predicates)
856921
{
857922
err.span_label(span, format!("`{rcvr_ty}` is not an iterator"));
858-
if !span.in_external_macro(self.tcx.sess.source_map()) {
923+
if !span.in_external_macro(self.tcx.sess.source_map())
924+
&& let Some(method_name) = self.preferred_iterator_method(source, rcvr_ty)
925+
{
859926
err.multipart_suggestion(
860-
"call `.into_iter()` first",
861-
vec![(span.shrink_to_lo(), format!("into_iter()."))],
927+
format!("call `.{method_name}()` first"),
928+
vec![(span.shrink_to_lo(), format!("{method_name}()."))],
862929
Applicability::MaybeIncorrect,
863930
);
864931
}

compiler/rustc_lint_defs/src/builtin.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5639,7 +5639,12 @@ declare_lint! {
56395639
/// LLVM periodically updates its list of intrinsics. Deprecated intrinsics are unlikely
56405640
/// to be removed, but they may optimize less well than their new versions, so it's
56415641
/// best to use the new version. Also, some deprecated intrinsics might have buggy
5642-
/// behavior
5642+
/// behavior.
5643+
///
5644+
/// This `link_llvm_intrinsics` lint is intended to be used internally only, and requires the
5645+
/// `#![feature(link_llvm_intrinsics)]` internal feature gate. For more information, see [its chapter in
5646+
/// the Unstable Book](https://doc.rust-lang.org/unstable-book/language-features/link-llvm-intrinsics.html)
5647+
/// and [its tracking issue](https://github.com/rust-lang/rust/issues/29602).
56435648
pub DEPRECATED_LLVM_INTRINSIC,
56445649
Allow,
56455650
"detects uses of deprecated LLVM intrinsics",

compiler/rustc_parse/src/errors.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,29 +1140,27 @@ pub(crate) struct InclusiveRangeMatchArrow {
11401140
#[primary_span]
11411141
pub arrow: Span,
11421142
#[label("this is parsed as an inclusive range `..=`")]
1143-
pub span: Span,
11441143
#[suggestion(
11451144
"add a space between the pattern and `=>`",
11461145
style = "verbose",
1147-
code = " ",
1146+
code = ".. =",
11481147
applicability = "machine-applicable"
11491148
)]
1150-
pub after_pat: Span,
1149+
pub span: Span,
11511150
}
11521151

11531152
#[derive(Diagnostic)]
11541153
#[diag("inclusive range with no end", code = E0586)]
11551154
#[note("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)")]
11561155
pub(crate) struct InclusiveRangeNoEnd {
11571156
#[primary_span]
1158-
pub span: Span,
11591157
#[suggestion(
11601158
"use `..` instead",
1161-
code = "",
1159+
code = "..",
11621160
applicability = "machine-applicable",
11631161
style = "verbose"
11641162
)]
1165-
pub suggestion: Span,
1163+
pub span: Span,
11661164
}
11671165

11681166
#[derive(Subdiagnostic)]

0 commit comments

Comments
 (0)