Skip to content

Rollup of 7 pull requests #139881

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Apr 15, 2025
Merged
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
250a1aa
make `AllTypes::print` return `impl fmt::Display`
yotamofek Mar 5, 2025
642995c
make `link_tooltip` return `impl fmt::Display`
yotamofek Mar 13, 2025
f7640d5
make `doc_impl_item` and `render_default_items` receive `impl fmt::Wr…
yotamofek Mar 13, 2025
8dd1cbb
lazify `render_assoc_items_inner`
yotamofek Mar 13, 2025
3df7882
Normalize ADT fields in find_tails_for_unsizing
compiler-errors Apr 14, 2025
1d75783
Remove safe remove
ChrisDenton Apr 14, 2025
f3847f0
Remove some "name isn't empty" assertions.
nnethercote Apr 8, 2025
2b43e66
Remove a `kw::Empty` usage in symbol mangling.
nnethercote Apr 8, 2025
c12b4aa
Use a dummy ident for a `lint_if_path_starts_with_module` call.
nnethercote Apr 9, 2025
c49b0bd
Use `rust-cache` to speed-up `citool` compilation
Kobzol Apr 14, 2025
73065b9
CI: rename MacOS runner
marcoieni Apr 15, 2025
043c5ff
Add warning comment to `Take::get_ref` and `Chain::get_ref`
joshtriplett Apr 15, 2025
ca0b7f4
Rollup merge of #138455 - yotamofek:pr/rustdoc/more-impl-display, r=G…
matthiaskrgr Apr 15, 2025
27f1f4d
Rollup merge of #139818 - compiler-errors:normalize-tails, r=oli-obk
matthiaskrgr Apr 15, 2025
b3e55a5
Rollup merge of #139819 - Kobzol:rust-cache, r=marcoieni
matthiaskrgr Apr 15, 2025
8bb01ff
Rollup merge of #139824 - ChrisDenton:non-canonical, r=petrochenkov
matthiaskrgr Apr 15, 2025
2144c94
Rollup merge of #139848 - nnethercote:kw-Empty-5, r=compiler-errors
matthiaskrgr Apr 15, 2025
2e363ce
Rollup merge of #139859 - marcoieni:rename-macos-runner, r=Kobzol
matthiaskrgr Apr 15, 2025
ebaef46
Rollup merge of #139877 - joshtriplett:take-care, r=dtolnay
matthiaskrgr Apr 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -53,6 +53,13 @@ jobs:
steps:
- name: Checkout the source code
uses: actions/checkout@v4
# Cache citool to make its build faster, as it's in the critical path.
# The rust-cache doesn't bleed into the main `job`, so it should not affect any other
# Rust compilation.
- name: Cache citool
uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
with:
workspaces: src/ci/citool
- name: Calculate the CI job matrix
env:
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
1 change: 0 additions & 1 deletion compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1765,7 +1765,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ident: Ident,
is_anon_in_path: IsAnonInPath,
) -> &'hir hir::Lifetime {
debug_assert_ne!(ident.name, kw::Empty);
let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
let res = match res {
LifetimeRes::Param { param, .. } => hir::LifetimeName::Param(param),
10 changes: 2 additions & 8 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
@@ -1600,11 +1600,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ok(method)
}
Err(error) => {
if segment.ident.name == kw::Empty {
span_bug!(rcvr.span, "empty method name")
} else {
Err(self.report_method_error(expr.hir_id, rcvr_t, error, expected, false))
}
Err(self.report_method_error(expr.hir_id, rcvr_t, error, expected, false))
}
};

@@ -2941,9 +2937,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return Ty::new_error(self.tcx(), guar);
}

let guar = if field.name == kw::Empty {
self.dcx().span_bug(field.span, "field name with no name")
} else if self.method_exists_for_diagnostic(
let guar = if self.method_exists_for_diagnostic(
field,
base_ty,
expr.hir_id,
3 changes: 1 addition & 2 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
@@ -27,9 +27,9 @@ use rustc_middle::ty::{
};
use rustc_middle::{bug, span_bug};
use rustc_session::lint;
use rustc_span::Span;
use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::{Span, kw};
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
use rustc_trait_selection::traits::{
self, NormalizeExt, ObligationCauseCode, StructurallyNormalizeExt,
@@ -833,7 +833,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

let trait_missing_method =
matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait();
assert_ne!(item_name.name, kw::Empty);
self.report_method_error(
hir_id,
ty.normalized,
34 changes: 6 additions & 28 deletions compiler/rustc_incremental/src/persist/fs.rs
Original file line number Diff line number Diff line change
@@ -290,7 +290,7 @@ pub(crate) fn prepare_session_directory(sess: &Session, crate_name: Symbol) {

// Try to remove the session directory we just allocated. We don't
// know if there's any garbage in it from the failed copy action.
if let Err(err) = safe_remove_dir_all(&session_dir) {
if let Err(err) = std_fs::remove_dir_all(&session_dir) {
sess.dcx().emit_warn(errors::DeletePartial { path: &session_dir, err });
}

@@ -324,7 +324,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Option<Svh>) {
incr_comp_session_dir.display()
);

if let Err(err) = safe_remove_dir_all(&*incr_comp_session_dir) {
if let Err(err) = std_fs::remove_dir_all(&*incr_comp_session_dir) {
sess.dcx().emit_warn(errors::DeleteFull { path: &incr_comp_session_dir, err });
}

@@ -715,7 +715,7 @@ pub(crate) fn garbage_collect_session_directories(sess: &Session) -> io::Result<
for directory_name in session_directories {
if !lock_file_to_session_dir.items().any(|(_, dir)| *dir == directory_name) {
let path = crate_directory.join(directory_name);
if let Err(err) = safe_remove_dir_all(&path) {
if let Err(err) = std_fs::remove_dir_all(&path) {
sess.dcx().emit_warn(errors::InvalidGcFailed { path: &path, err });
}
}
@@ -821,7 +821,7 @@ pub(crate) fn garbage_collect_session_directories(sess: &Session) -> io::Result<
all_except_most_recent(deletion_candidates).into_items().all(|(path, lock)| {
debug!("garbage_collect_session_directories() - deleting `{}`", path.display());

if let Err(err) = safe_remove_dir_all(&path) {
if let Err(err) = std_fs::remove_dir_all(&path) {
sess.dcx().emit_warn(errors::FinalizedGcFailed { path: &path, err });
} else {
delete_session_dir_lock_file(sess, &lock_file_path(&path));
@@ -839,7 +839,7 @@ pub(crate) fn garbage_collect_session_directories(sess: &Session) -> io::Result<
fn delete_old(sess: &Session, path: &Path) {
debug!("garbage_collect_session_directories() - deleting `{}`", path.display());

if let Err(err) = safe_remove_dir_all(path) {
if let Err(err) = std_fs::remove_dir_all(path) {
sess.dcx().emit_warn(errors::SessionGcFailed { path, err });
} else {
delete_session_dir_lock_file(sess, &lock_file_path(path));
@@ -862,30 +862,8 @@ fn all_except_most_recent(
}
}

/// Since paths of artifacts within session directories can get quite long, we
/// need to support deleting files with very long paths. The regular
/// WinApi functions only support paths up to 260 characters, however. In order
/// to circumvent this limitation, we canonicalize the path of the directory
/// before passing it to std::fs::remove_dir_all(). This will convert the path
/// into the '\\?\' format, which supports much longer paths.
fn safe_remove_dir_all(p: &Path) -> io::Result<()> {
let canonicalized = match try_canonicalize(p) {
Ok(canonicalized) => canonicalized,
Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()),
Err(err) => return Err(err),
};

std_fs::remove_dir_all(canonicalized)
}

fn safe_remove_file(p: &Path) -> io::Result<()> {
let canonicalized = match try_canonicalize(p) {
Ok(canonicalized) => canonicalized,
Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()),
Err(err) => return Err(err),
};

match std_fs::remove_file(canonicalized) {
match std_fs::remove_file(p) {
Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(()),
result => result,
}
63 changes: 32 additions & 31 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
@@ -688,7 +688,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
let target_ty = self.monomorphize(target_ty);
let source_ty = self.monomorphize(source_ty);
let (source_ty, target_ty) =
find_vtable_types_for_unsizing(self.tcx.at(span), source_ty, target_ty);
find_tails_for_unsizing(self.tcx.at(span), source_ty, target_ty);
// This could also be a different Unsize instruction, like
// from a fixed sized array to a slice. But we are only
// interested in things that produce a vtable.
@@ -1037,36 +1037,35 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) ->
///
/// Finally, there is also the case of custom unsizing coercions, e.g., for
/// smart pointers such as `Rc` and `Arc`.
fn find_vtable_types_for_unsizing<'tcx>(
fn find_tails_for_unsizing<'tcx>(
tcx: TyCtxtAt<'tcx>,
source_ty: Ty<'tcx>,
target_ty: Ty<'tcx>,
) -> (Ty<'tcx>, Ty<'tcx>) {
let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| {
let typing_env = ty::TypingEnv::fully_monomorphized();
if tcx.type_has_metadata(inner_source, typing_env) {
(inner_source, inner_target)
} else {
tcx.struct_lockstep_tails_for_codegen(inner_source, inner_target, typing_env)
}
};
let typing_env = ty::TypingEnv::fully_monomorphized();
debug_assert!(!source_ty.has_param(), "{source_ty} should be fully monomorphic");
debug_assert!(!target_ty.has_param(), "{target_ty} should be fully monomorphic");

match (source_ty.kind(), target_ty.kind()) {
(&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _))
| (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => ptr_vtable(a, b),
(
&ty::Ref(_, source_pointee, _),
&ty::Ref(_, target_pointee, _) | &ty::RawPtr(target_pointee, _),
)
| (&ty::RawPtr(source_pointee, _), &ty::RawPtr(target_pointee, _)) => {
tcx.struct_lockstep_tails_for_codegen(source_pointee, target_pointee, typing_env)
}

// `Box<T>` could go through the ADT code below, b/c it'll unpeel to `Unique<T>`,
// and eventually bottom out in a raw ref, but we can micro-optimize it here.
(_, _)
if let Some(source_boxed) = source_ty.boxed_ty()
&& let Some(target_boxed) = target_ty.boxed_ty() =>
{
ptr_vtable(source_boxed, target_boxed)
tcx.struct_lockstep_tails_for_codegen(source_boxed, target_boxed, typing_env)
}

// T as dyn* Trait
(_, &ty::Dynamic(_, _, ty::DynStar)) => ptr_vtable(source_ty, target_ty),

(&ty::Adt(source_adt_def, source_args), &ty::Adt(target_adt_def, target_args)) => {
assert_eq!(source_adt_def, target_adt_def);

let CustomCoerceUnsized::Struct(coerce_index) =
match crate::custom_coerce_unsize_info(tcx, source_ty, target_ty) {
Ok(ccu) => ccu,
@@ -1075,21 +1074,23 @@ fn find_vtable_types_for_unsizing<'tcx>(
return (e, e);
}
};
let coerce_field = &source_adt_def.non_enum_variant().fields[coerce_index];
// We're getting a possibly unnormalized type, so normalize it.
let source_field =
tcx.normalize_erasing_regions(typing_env, coerce_field.ty(*tcx, source_args));
let target_field =
tcx.normalize_erasing_regions(typing_env, coerce_field.ty(*tcx, target_args));
find_tails_for_unsizing(tcx, source_field, target_field)
}

let source_fields = &source_adt_def.non_enum_variant().fields;
let target_fields = &target_adt_def.non_enum_variant().fields;

assert!(
coerce_index.index() < source_fields.len()
&& source_fields.len() == target_fields.len()
);
// `T` as `dyn* Trait` unsizes *directly*.
//
// FIXME(dyn_star): This case is a bit awkward, b/c we're not really computing
// a tail here. We probably should handle this separately in the *caller* of
// this function, rather than returning something that is semantically different
// than what we return above.
(_, &ty::Dynamic(_, _, ty::DynStar)) => (source_ty, target_ty),

find_vtable_types_for_unsizing(
tcx,
source_fields[coerce_index].ty(*tcx, source_args),
target_fields[coerce_index].ty(*tcx, target_args),
)
}
_ => bug!(
"find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}",
source_ty,
@@ -1308,7 +1309,7 @@ fn visit_mentioned_item<'tcx>(
}
MentionedItem::UnsizeCast { source_ty, target_ty } => {
let (source_ty, target_ty) =
find_vtable_types_for_unsizing(tcx.at(span), source_ty, target_ty);
find_tails_for_unsizing(tcx.at(span), source_ty, target_ty);
// This could also be a different Unsize instruction, like
// from a fixed sized array to a slice. But we are only
// interested in things that produce a vtable.
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/imports.rs
Original file line number Diff line number Diff line change
@@ -1012,7 +1012,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// HACK(eddyb) `lint_if_path_starts_with_module` needs at least
// 2 segments, so the `resolve_path` above won't trigger it.
let mut full_path = import.module_path.clone();
full_path.push(Segment::from_ident(Ident::empty()));
full_path.push(Segment::from_ident(Ident::dummy()));
self.lint_if_path_starts_with_module(Some(finalize), &full_path, None);
}

2 changes: 1 addition & 1 deletion compiler/rustc_symbol_mangling/src/v0.rs
Original file line number Diff line number Diff line change
@@ -776,7 +776,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
self.push_disambiguator(
disambiguated_field.disambiguator as u64,
);
self.push_ident(field_name.unwrap_or(kw::Empty).as_str());
self.push_ident(field_name.unwrap().as_str());

field.print(self)?;
}
8 changes: 8 additions & 0 deletions library/std/src/io/mod.rs
Original file line number Diff line number Diff line change
@@ -2658,6 +2658,10 @@ impl<T, U> Chain<T, U> {

/// Gets references to the underlying readers in this `Chain`.
///
/// Care should be taken to avoid modifying the internal I/O state of the
/// underlying readers as doing so may corrupt the internal state of this
/// `Chain`.
///
/// # Examples
///
/// ```no_run
@@ -2915,6 +2919,10 @@ impl<T> Take<T> {

/// Gets a reference to the underlying reader.
///
/// Care should be taken to avoid modifying the internal I/O state of the
/// underlying reader as doing so may corrupt the internal limit of this
/// `Take`.
///
/// # Examples
///
/// ```no_run
12 changes: 6 additions & 6 deletions src/ci/github-actions/jobs.yml
Original file line number Diff line number Diff line change
@@ -23,8 +23,8 @@ runners:
os: ubuntu-24.04-16core-64gb
<<: *base-job

- &job-macos-xl
os: macos-13 # We use the standard runner for now
- &job-macos
os: macos-13
<<: *base-job

- &job-macos-m1
@@ -380,7 +380,7 @@ auto:
NO_OVERFLOW_CHECKS: 1
DIST_REQUIRE_ALL_TOOLS: 1
CODEGEN_BACKENDS: llvm,cranelift
<<: *job-macos-xl
<<: *job-macos

- name: dist-apple-various
env:
@@ -397,18 +397,18 @@ auto:
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
NO_OVERFLOW_CHECKS: 1
<<: *job-macos-xl
<<: *job-macos

- name: x86_64-apple-1
env:
<<: *env-x86_64-apple-tests
<<: *job-macos-xl
<<: *job-macos

- name: x86_64-apple-2
env:
SCRIPT: ./x.py --stage 2 test tests/ui tests/rustdoc
<<: *env-x86_64-apple-tests
<<: *job-macos-xl
<<: *job-macos

- name: dist-aarch64-apple
env:
2 changes: 1 addition & 1 deletion src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
@@ -517,7 +517,7 @@ impl Item {
Some(RenderedLink {
original_text: s.clone(),
new_text: link_text.clone(),
tooltip: link_tooltip(*id, fragment, cx),
tooltip: link_tooltip(*id, fragment, cx).to_string(),
href,
})
} else {
55 changes: 29 additions & 26 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@ use std::borrow::Cow;
use std::cmp::Ordering;
use std::fmt::{self, Display, Write};
use std::iter::{self, once};
use std::slice;

use itertools::Either;
use rustc_abi::ExternAbi;
@@ -650,33 +651,35 @@ pub(crate) fn href_relative_parts<'fqp>(
}
}

pub(crate) fn link_tooltip(did: DefId, fragment: &Option<UrlFragment>, cx: &Context<'_>) -> String {
let cache = cx.cache();
let Some((fqp, shortty)) = cache.paths.get(&did).or_else(|| cache.external_paths.get(&did))
else {
return String::new();
};
let mut buf = String::new();
let fqp = if *shortty == ItemType::Primitive {
// primitives are documented in a crate, but not actually part of it
&fqp[fqp.len() - 1..]
} else {
fqp
};
if let &Some(UrlFragment::Item(id)) = fragment {
write_str(&mut buf, format_args!("{} ", cx.tcx().def_descr(id)));
for component in fqp {
write_str(&mut buf, format_args!("{component}::"));
}
write_str(&mut buf, format_args!("{}", cx.tcx().item_name(id)));
} else if !fqp.is_empty() {
let mut fqp_it = fqp.iter();
write_str(&mut buf, format_args!("{shortty} {}", fqp_it.next().unwrap()));
for component in fqp_it {
write_str(&mut buf, format_args!("::{component}"));
pub(crate) fn link_tooltip(
did: DefId,
fragment: &Option<UrlFragment>,
cx: &Context<'_>,
) -> impl fmt::Display {
fmt::from_fn(move |f| {
let cache = cx.cache();
let Some((fqp, shortty)) = cache.paths.get(&did).or_else(|| cache.external_paths.get(&did))
else {
return Ok(());
};
let fqp = if *shortty == ItemType::Primitive {
// primitives are documented in a crate, but not actually part of it
slice::from_ref(fqp.last().unwrap())
} else {
fqp
};
if let &Some(UrlFragment::Item(id)) = fragment {
write!(f, "{} ", cx.tcx().def_descr(id))?;
for component in fqp {
write!(f, "{component}::")?;
}
write!(f, "{}", cx.tcx().item_name(id))?;
} else if !fqp.is_empty() {
write!(f, "{shortty} ")?;
fqp.iter().joined("::", f)?;
}
}
buf
Ok(())
})
}

/// Used to render a [`clean::Path`].
10 changes: 1 addition & 9 deletions src/librustdoc/html/render/context.rs
Original file line number Diff line number Diff line change
@@ -650,15 +650,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {

bar.render_into(&mut sidebar).unwrap();

let v = layout::render(
&shared.layout,
&page,
sidebar,
BufDisplay(|buf: &mut String| {
all.print(buf);
}),
&shared.style_files,
);
let v = layout::render(&shared.layout, &page, sidebar, all.print(), &shared.style_files);
shared.fs.write(final_file, v)?;

// if to avoid writing help, settings files to doc root unless we're on the final invocation
388 changes: 196 additions & 192 deletions src/librustdoc/html/render/mod.rs

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions src/librustdoc/html/render/tests.rs
Original file line number Diff line number Diff line change
@@ -47,8 +47,7 @@ fn test_all_types_prints_header_once() {
// Regression test for #82477
let all_types = AllTypes::new();

let mut buffer = String::new();
all_types.print(&mut buffer);
let buffer = all_types.print().to_string();

assert_eq!(1, buffer.matches("List of all items").count());
}
42 changes: 0 additions & 42 deletions tests/crashes/74451.rs

This file was deleted.

32 changes: 32 additions & 0 deletions tests/ui/coercion/codegen-smart-pointer-with-alias.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//@ build-pass

// Regression test for <https://github.com/rust-lang/rust/issues/139812>.

// Make sure that the unsize coercion we collect in mono for `Signal<i32> -> Signal<dyn Any>`
// doesn't choke on the fact that the inner unsized field of `Signal<T>` is a (trivial) alias.
// This exercises a normalize call that is necessary since we're getting a type from the type
// system, which isn't guaranteed to be normalized after substitution.

#![feature(coerce_unsized)]

use std::ops::CoerceUnsized;

trait Mirror {
type Assoc: ?Sized;
}
impl<T: ?Sized> Mirror for T {
type Assoc = T;
}

trait Any {}
impl<T> Any for T {}

struct Signal<'a, T: ?Sized>(<&'a T as Mirror>::Assoc);

// This `CoerceUnsized` impl isn't special; it's a bit more restricted than we'd see in the wild,
// but this ICE also reproduces if we were to make it general over `Signal<T> -> Signal<U>`.
impl<'a> CoerceUnsized<Signal<'a, dyn Any>> for Signal<'a, i32> {}

fn main() {
Signal(&1i32) as Signal<dyn Any>;
}