Skip to content

Commit ce75ee5

Browse files
committed
Auto merge of #148829 - GuillaumeGomez:rollup-22dhdwc, r=GuillaumeGomez
Rollup of 6 pull requests Successful merges: - #147753 (Suggest add bounding value for RangeTo) - #148080 ([rustdoc] Fix invalid jump to def macro link generation) - #148465 (Adjust spans into the `for` loops context before creating the new desugaring spans.) - #148500 (Update git index before running diff-index) - #148536 (cmse: add test for `async` and `const` functions) - #148819 (Remove specialized warning for removed target) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 25d319a + d19b9b0 commit ce75ee5

29 files changed

+653
-261
lines changed

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,8 +1771,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
17711771
let pat = self.lower_pat(pat);
17721772
let for_span =
17731773
self.mark_span_with_reason(DesugaringKind::ForLoop, self.lower_span(e.span), None);
1774-
let head_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None);
1775-
let pat_span = self.mark_span_with_reason(DesugaringKind::ForLoop, pat.span, None);
1774+
let for_ctxt = for_span.ctxt();
1775+
1776+
// Try to point both the head and pat spans to their position in the for loop
1777+
// rather than inside a macro.
1778+
let head_span =
1779+
head.span.find_ancestor_in_same_ctxt(e.span).unwrap_or(head.span).with_ctxt(for_ctxt);
1780+
let pat_span =
1781+
pat.span.find_ancestor_in_same_ctxt(e.span).unwrap_or(pat.span).with_ctxt(for_ctxt);
17761782

17771783
let loop_hir_id = self.lower_node_id(e.id);
17781784
let label = self.lower_label(opt_label, e.id, loop_hir_id);

compiler/rustc_hir_typeck/src/method/suggest.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10791079
}
10801080

10811081
self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_ident, expected);
1082+
self.suggest_bounds_for_range_to_method(&mut err, source, item_ident);
10821083
err.emit()
10831084
}
10841085

@@ -3260,6 +3261,71 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
32603261
}
32613262
}
32623263

3264+
fn suggest_bounds_for_range_to_method(
3265+
&self,
3266+
err: &mut Diag<'_>,
3267+
source: SelfSource<'tcx>,
3268+
item_ident: Ident,
3269+
) {
3270+
let SelfSource::MethodCall(rcvr_expr) = source else { return };
3271+
let hir::ExprKind::Struct(qpath, fields, _) = rcvr_expr.kind else { return };
3272+
let Some(lang_item) = self.tcx.qpath_lang_item(*qpath) else {
3273+
return;
3274+
};
3275+
let is_inclusive = match lang_item {
3276+
hir::LangItem::RangeTo => false,
3277+
hir::LangItem::RangeToInclusive | hir::LangItem::RangeInclusiveCopy => true,
3278+
_ => return,
3279+
};
3280+
3281+
let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) else { return };
3282+
let Some(_) = self
3283+
.tcx
3284+
.associated_items(iterator_trait)
3285+
.filter_by_name_unhygienic(item_ident.name)
3286+
.next()
3287+
else {
3288+
return;
3289+
};
3290+
3291+
let source_map = self.tcx.sess.source_map();
3292+
let range_type = if is_inclusive { "RangeInclusive" } else { "Range" };
3293+
let Some(end_field) = fields.iter().find(|f| f.ident.name == rustc_span::sym::end) else {
3294+
return;
3295+
};
3296+
3297+
let element_ty = self.typeck_results.borrow().expr_ty_opt(end_field.expr);
3298+
let is_integral = element_ty.is_some_and(|ty| ty.is_integral());
3299+
let end_is_negative = is_integral
3300+
&& matches!(end_field.expr.kind, hir::ExprKind::Unary(rustc_ast::UnOp::Neg, _));
3301+
3302+
let Ok(snippet) = source_map.span_to_snippet(rcvr_expr.span) else { return };
3303+
3304+
let offset = snippet
3305+
.chars()
3306+
.take_while(|&c| c == '(' || c.is_whitespace())
3307+
.map(|c| c.len_utf8())
3308+
.sum::<usize>();
3309+
3310+
let insert_span = rcvr_expr
3311+
.span
3312+
.with_lo(rcvr_expr.span.lo() + rustc_span::BytePos(offset as u32))
3313+
.shrink_to_lo();
3314+
3315+
let (value, appl) = if is_integral && !end_is_negative {
3316+
("0", Applicability::MachineApplicable)
3317+
} else {
3318+
("/* start */", Applicability::HasPlaceholders)
3319+
};
3320+
3321+
err.span_suggestion_verbose(
3322+
insert_span,
3323+
format!("consider using a bounded `{range_type}` by adding a concrete starting value"),
3324+
value,
3325+
appl,
3326+
);
3327+
}
3328+
32633329
/// Print out the type for use in value namespace.
32643330
fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
32653331
match ty.kind() {

compiler/rustc_target/src/spec/mod.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3198,15 +3198,7 @@ impl Target {
31983198
return load_file(&p);
31993199
}
32003200

3201-
// Leave in a specialized error message for the removed target.
3202-
// FIXME: If you see this and it's been a few months after this has been released,
3203-
// you can probably remove it.
3204-
if target_tuple == "i586-pc-windows-msvc" {
3205-
Err("the `i586-pc-windows-msvc` target has been removed. Use the `i686-pc-windows-msvc` target instead.\n\
3206-
Windows 10 (the minimum required OS version) requires a CPU baseline of at least i686 so you can safely switch".into())
3207-
} else {
3208-
Err(format!("could not find specification for target {target_tuple:?}"))
3209-
}
3201+
Err(format!("could not find specification for target {target_tuple:?}"))
32103202
}
32113203
TargetTuple::TargetJson { ref contents, .. } => Target::from_json(contents),
32123204
}

src/build_helper/src/git.rs

Lines changed: 46 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -143,14 +143,13 @@ pub fn check_path_modifications(
143143

144144
/// Returns true if any of the passed `paths` have changed since the `base` commit.
145145
pub fn has_changed_since(git_dir: &Path, base: &str, paths: &[&str]) -> bool {
146-
let mut git = Command::new("git");
147-
git.current_dir(git_dir);
146+
run_git_diff_index(Some(git_dir), |cmd| {
147+
cmd.args(["--quiet", base, "--"]).args(paths);
148148

149-
git.args(["diff-index", "--quiet", base, "--"]).args(paths);
150-
151-
// Exit code 0 => no changes
152-
// Exit code 1 => some changes were detected
153-
!git.status().expect("cannot run git diff-index").success()
149+
// Exit code 0 => no changes
150+
// Exit code 1 => some changes were detected
151+
!cmd.status().expect("cannot run git diff-index").success()
152+
})
154153
}
155154

156155
/// Returns the latest upstream commit that modified `target_paths`, or `None` if no such commit
@@ -267,31 +266,49 @@ pub fn get_git_modified_files(
267266
return Err("No upstream commit was found".to_string());
268267
};
269268

270-
let mut git = Command::new("git");
271-
if let Some(git_dir) = git_dir {
272-
git.current_dir(git_dir);
273-
}
274-
let files = output_result(git.args(["diff-index", "--name-status", merge_base.trim()]))?
275-
.lines()
276-
.filter_map(|f| {
277-
let (status, name) = f.trim().split_once(char::is_whitespace).unwrap();
278-
if status == "D" {
279-
None
280-
} else if Path::new(name).extension().map_or(extensions.is_empty(), |ext| {
281-
// If there is no extension, we allow the path if `extensions` is empty
282-
// If there is an extension, we allow it if `extension` is empty or it contains the
283-
// extension.
284-
extensions.is_empty() || extensions.contains(&ext.to_str().unwrap())
285-
}) {
286-
Some(name.to_owned())
287-
} else {
288-
None
289-
}
290-
})
291-
.collect();
269+
let files = run_git_diff_index(git_dir, |cmd| {
270+
output_result(cmd.args(["--name-status", merge_base.trim()]))
271+
})?
272+
.lines()
273+
.filter_map(|f| {
274+
let (status, name) = f.trim().split_once(char::is_whitespace).unwrap();
275+
if status == "D" {
276+
None
277+
} else if Path::new(name).extension().map_or(extensions.is_empty(), |ext| {
278+
// If there is no extension, we allow the path if `extensions` is empty
279+
// If there is an extension, we allow it if `extension` is empty or it contains the
280+
// extension.
281+
extensions.is_empty() || extensions.contains(&ext.to_str().unwrap())
282+
}) {
283+
Some(name.to_owned())
284+
} else {
285+
None
286+
}
287+
})
288+
.collect();
292289
Ok(files)
293290
}
294291

292+
/// diff-index can return outdated information, because it does not update the git index.
293+
/// This function uses `update-index` to update the index first, and then provides `func` with a
294+
/// command prepared to run `git diff-index`.
295+
fn run_git_diff_index<F, T>(git_dir: Option<&Path>, func: F) -> T
296+
where
297+
F: FnOnce(&mut Command) -> T,
298+
{
299+
let git = || {
300+
let mut git = Command::new("git");
301+
if let Some(git_dir) = git_dir {
302+
git.current_dir(git_dir);
303+
}
304+
git
305+
};
306+
307+
// We ignore the exit code, as it errors out when some files are modified.
308+
let _ = output_result(git().args(["update-index", "--refresh", "-q"]));
309+
func(git().arg("diff-index"))
310+
}
311+
295312
/// Returns the files that haven't been added to git yet.
296313
pub fn get_git_untracked_files(git_dir: Option<&Path>) -> Result<Option<Vec<String>>, String> {
297314
let mut git = Command::new("git");

src/librustdoc/clean/inline.rs

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,30 @@ pub(crate) fn item_relative_path(tcx: TyCtxt<'_>, def_id: DefId) -> Vec<Symbol>
227227
tcx.def_path(def_id).data.into_iter().filter_map(|elem| elem.data.get_opt_name()).collect()
228228
}
229229

230+
/// Get the public Rust path to an item. This is used to generate the URL to the item's page.
231+
///
232+
/// In particular: we handle macro differently: if it's not a macro 2.0 oe a built-in macro, then
233+
/// it is generated at the top-level of the crate and its path will be `[crate_name, macro_name]`.
234+
pub(crate) fn get_item_path(tcx: TyCtxt<'_>, def_id: DefId, kind: ItemType) -> Vec<Symbol> {
235+
let crate_name = tcx.crate_name(def_id.krate);
236+
let relative = item_relative_path(tcx, def_id);
237+
238+
if let ItemType::Macro = kind {
239+
// Check to see if it is a macro 2.0 or built-in macro
240+
// More information in <https://rust-lang.github.io/rfcs/1584-macros.html>.
241+
if matches!(
242+
CStore::from_tcx(tcx).load_macro_untracked(def_id, tcx),
243+
LoadedMacro::MacroDef { def, .. } if !def.macro_rules
244+
) {
245+
once(crate_name).chain(relative).collect()
246+
} else {
247+
vec![crate_name, *relative.last().expect("relative was empty")]
248+
}
249+
} else {
250+
once(crate_name).chain(relative).collect()
251+
}
252+
}
253+
230254
/// Record an external fully qualified name in the external_paths cache.
231255
///
232256
/// These names are used later on by HTML rendering to generate things like
@@ -240,27 +264,12 @@ pub(crate) fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: ItemT
240264
return;
241265
}
242266

243-
let crate_name = cx.tcx.crate_name(did.krate);
244-
245-
let relative = item_relative_path(cx.tcx, did);
246-
let fqn = if let ItemType::Macro = kind {
247-
// Check to see if it is a macro 2.0 or built-in macro
248-
if matches!(
249-
CStore::from_tcx(cx.tcx).load_macro_untracked(did, cx.tcx),
250-
LoadedMacro::MacroDef { def, .. } if !def.macro_rules
251-
) {
252-
once(crate_name).chain(relative).collect()
253-
} else {
254-
vec![crate_name, *relative.last().expect("relative was empty")]
255-
}
256-
} else {
257-
once(crate_name).chain(relative).collect()
258-
};
267+
let item_path = get_item_path(cx.tcx, did, kind);
259268

260269
if did.is_local() {
261-
cx.cache.exact_paths.insert(did, fqn);
270+
cx.cache.exact_paths.insert(did, item_path);
262271
} else {
263-
cx.cache.external_paths.insert(did, (fqn, kind));
272+
cx.cache.external_paths.insert(did, (item_path, kind));
264273
}
265274
}
266275

src/librustdoc/clean/types.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use crate::clean::utils::{is_literal_expr, print_evaluated_const};
4040
use crate::core::DocContext;
4141
use crate::formats::cache::Cache;
4242
use crate::formats::item_type::ItemType;
43+
use crate::html::format::HrefInfo;
4344
use crate::html::render::Context;
4445
use crate::passes::collect_intra_doc_links::UrlFragment;
4546

@@ -519,16 +520,16 @@ impl Item {
519520
.iter()
520521
.filter_map(|ItemLink { link: s, link_text, page_id: id, fragment }| {
521522
debug!(?id);
522-
if let Ok((mut href, ..)) = href(*id, cx) {
523-
debug!(?href);
523+
if let Ok(HrefInfo { mut url, .. }) = href(*id, cx) {
524+
debug!(?url);
524525
if let Some(ref fragment) = *fragment {
525-
fragment.render(&mut href, cx.tcx())
526+
fragment.render(&mut url, cx.tcx())
526527
}
527528
Some(RenderedLink {
528529
original_text: s.clone(),
529530
new_text: link_text.clone(),
530531
tooltip: link_tooltip(*id, fragment, cx).to_string(),
531-
href,
532+
href: url,
532533
})
533534
} else {
534535
None

src/librustdoc/display.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,18 @@ pub(crate) trait Joined: IntoIterator {
1010
///
1111
/// The performance of `joined` is slightly better than `format`, since it doesn't need to use a `Cell` to keep track of whether [`fmt`](Display::fmt)
1212
/// was already called (`joined`'s API doesn't allow it be called more than once).
13-
fn joined(self, sep: impl Display, f: &mut Formatter<'_>) -> fmt::Result;
13+
fn joined(&mut self, sep: impl Display, f: &mut Formatter<'_>) -> fmt::Result;
1414
}
1515

1616
impl<I, T> Joined for I
1717
where
18-
I: IntoIterator<Item = T>,
18+
I: Iterator<Item = T>,
1919
T: Display,
2020
{
21-
fn joined(self, sep: impl Display, f: &mut Formatter<'_>) -> fmt::Result {
22-
let mut iter = self.into_iter();
23-
let Some(first) = iter.next() else { return Ok(()) };
21+
fn joined(&mut self, sep: impl Display, f: &mut Formatter<'_>) -> fmt::Result {
22+
let Some(first) = self.next() else { return Ok(()) };
2423
first.fmt(f)?;
25-
for item in iter {
24+
for item in self {
2625
sep.fmt(f)?;
2726
item.fmt(f)?;
2827
}

0 commit comments

Comments
 (0)