Skip to content
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

[stable] Release 1.85.1 #138521

Merged
merged 16 commits into from
Mar 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 14 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,20 @@ jobs:
- name: ensure the stable version number is correct
run: src/ci/scripts/verify-stable-version-number.sh

# Temporary fix to unblock CI
# Remove the latest Windows SDK for 32-bit Windows MSVC builds.
# See issue https://github.com/rust-lang/rust/issues/137733 for more details.
- name: Remove Windows SDK 10.0.26100.0
shell: powershell
if: ${{ matrix.image == 'i686-msvc' || matrix.image == 'dist-i686-msvc' }}
run: |
$kits = (Get-ItemProperty -path 'HKLM:\SOFTWARE\Microsoft\Windows Kits\Installed Roots').KitsRoot10
$sdk_version = "10.0.26100.0"

foreach ($kind in 'Bin', 'Lib', 'Include') {
Remove-Item -Force -Recurse $kits\$kind\$sdk_version -ErrorAction Continue
}

- name: run the build
# Redirect stderr to stdout to avoid reordering the two streams in the GHA logs.
run: src/ci/scripts/run-build-from-ci.sh 2>&1
Expand Down
11 changes: 11 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
Version 1.85.1 (2025-03-18)
==========================

<a id="1.85.1"></a>

- [Fix the doctest-merging feature of the 2024 Edition.](https://github.com/rust-lang/rust/pull/137899/)
- [Relax some `target_feature` checks when generating docs.](https://github.com/rust-lang/rust/pull/137632/)
- [Fix errors in `std::fs::rename` on Windows 1607.](https://github.com/rust-lang/rust/pull/137528/)
- [Downgrade bootstrap `cc` to fix custom targets.](https://github.com/rust-lang/rust/pull/137460/)
- [Skip submodule updates when building Rust from a source tarball.](https://github.com/rust-lang/rust/pull/137338/)

Version 1.85.0 (2025-02-20)
==========================

Expand Down
54 changes: 43 additions & 11 deletions compiler/rustc_codegen_ssa/src/target_features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::parse::feature_err;
use rustc_span::{Span, Symbol, sym};
use rustc_target::target_features;
use rustc_target::target_features::{self, Stability};

use crate::errors;

Expand Down Expand Up @@ -65,11 +65,16 @@ pub(crate) fn from_target_feature_attr(
// Only allow target features whose feature gates have been enabled
// and which are permitted to be toggled.
if let Err(reason) = stability.toggle_allowed(/*enable*/ true) {
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
span: item.span(),
feature,
reason,
});
// We skip this error in rustdoc, where we want to allow all target features of
// all targets, so we can't check their ABI compatibility and anyway we are not
// generating code so "it's fine".
if !tcx.sess.opts.actually_rustdoc {
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
span: item.span(),
feature,
reason,
});
}
} else if let Some(nightly_feature) = stability.requires_nightly()
&& !rust_features.enabled(nightly_feature)
{
Expand Down Expand Up @@ -149,11 +154,38 @@ pub(crate) fn provide(providers: &mut Providers) {
assert_eq!(cnum, LOCAL_CRATE);
let target = &tcx.sess.target;
if tcx.sess.opts.actually_rustdoc {
// rustdoc needs to be able to document functions that use all the features, so
// whitelist them all
rustc_target::target_features::all_rust_features()
.map(|(a, b)| (a.to_string(), b.compute_toggleability(target)))
.collect()
// HACK: rustdoc would like to pretend that we have all the target features, so we
// have to merge all the lists into one. To ensure an unstable target never prevents
// a stable one from working, we merge the stability info of all instances of the
// same target feature name, with the "most stable" taking precedence. And then we
// hope that this doesn't cause issues anywhere else in the compiler...
let mut result: UnordMap<String, Stability<_>> = Default::default();
for (name, stability) in rustc_target::target_features::all_rust_features() {
use std::collections::hash_map::Entry;
match result.entry(name.to_owned()) {
Entry::Vacant(vacant_entry) => {
vacant_entry.insert(stability.compute_toggleability(target));
}
Entry::Occupied(mut occupied_entry) => {
// Merge the two stabilities, "more stable" taking precedence.
match (occupied_entry.get(), &stability) {
(Stability::Stable { .. }, _)
| (
Stability::Unstable { .. },
Stability::Unstable { .. } | Stability::Forbidden { .. },
)
| (Stability::Forbidden { .. }, Stability::Forbidden { .. }) => {
// The stability in the entry is at least as good as the new one, just keep it.
}
_ => {
// Overwrite stabilite.
occupied_entry.insert(stability.compute_toggleability(target));
}
}
}
}
}
result
} else {
tcx.sess
.target
Expand Down
2 changes: 1 addition & 1 deletion library/std/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2402,7 +2402,7 @@ pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
/// # Platform-specific behavior
///
/// This function currently corresponds to the `rename` function on Unix
/// and the `SetFileInformationByHandle` function on Windows.
/// and the `MoveFileExW` or `SetFileInformationByHandle` function on Windows.
///
/// Because of this, the behavior when both `from` and `to` exist differs. On
/// Unix, if `from` is a directory, `to` must also be an (empty) directory. If
Expand Down
185 changes: 60 additions & 125 deletions library/std/src/sys/pal/windows/fs.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use super::api::{self, WinError};
use super::{IoResult, to_u16s};
use crate::alloc::{alloc, handle_alloc_error};
use crate::alloc::{Layout, alloc, dealloc};
use crate::borrow::Cow;
use crate::ffi::{OsStr, OsString, c_void};
use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom};
use crate::mem::{self, MaybeUninit};
use crate::mem::{self, MaybeUninit, offset_of};
use crate::os::windows::io::{AsHandle, BorrowedHandle};
use crate::os::windows::prelude::*;
use crate::path::{Path, PathBuf};
Expand Down Expand Up @@ -296,6 +296,10 @@ impl OpenOptions {
impl File {
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
let path = maybe_verbatim(path)?;
Self::open_native(&path, opts)
}

fn open_native(path: &[u16], opts: &OpenOptions) -> io::Result<File> {
let creation = opts.get_creation_mode()?;
let handle = unsafe {
c::CreateFileW(
Expand Down Expand Up @@ -1234,141 +1238,72 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
let old = maybe_verbatim(old)?;
let new = maybe_verbatim(new)?;

let new_len_without_nul_in_bytes = (new.len() - 1).try_into().unwrap();

// The last field of FILE_RENAME_INFO, the file name, is unsized,
// and FILE_RENAME_INFO has two padding bytes.
// Therefore we need to make sure to not allocate less than
// size_of::<c::FILE_RENAME_INFO>() bytes, which would be the case with
// 0 or 1 character paths + a null byte.
let struct_size = mem::size_of::<c::FILE_RENAME_INFO>()
.max(mem::offset_of!(c::FILE_RENAME_INFO, FileName) + new.len() * mem::size_of::<u16>());

let struct_size: u32 = struct_size.try_into().unwrap();

let create_file = |extra_access, extra_flags| {
let handle = unsafe {
HandleOrInvalid::from_raw_handle(c::CreateFileW(
old.as_ptr(),
c::SYNCHRONIZE | c::DELETE | extra_access,
c::FILE_SHARE_READ | c::FILE_SHARE_WRITE | c::FILE_SHARE_DELETE,
ptr::null(),
c::OPEN_EXISTING,
c::FILE_ATTRIBUTE_NORMAL | c::FILE_FLAG_BACKUP_SEMANTICS | extra_flags,
ptr::null_mut(),
))
};

OwnedHandle::try_from(handle).map_err(|_| io::Error::last_os_error())
};

// The following code replicates `MoveFileEx`'s behavior as reverse-engineered from its disassembly.
// If `old` refers to a mount point, we move it instead of the target.
let handle = match create_file(c::FILE_READ_ATTRIBUTES, c::FILE_FLAG_OPEN_REPARSE_POINT) {
Ok(handle) => {
let mut file_attribute_tag_info: MaybeUninit<c::FILE_ATTRIBUTE_TAG_INFO> =
MaybeUninit::uninit();

let result = unsafe {
cvt(c::GetFileInformationByHandleEx(
handle.as_raw_handle(),
c::FileAttributeTagInfo,
file_attribute_tag_info.as_mut_ptr().cast(),
mem::size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
))
if unsafe { c::MoveFileExW(old.as_ptr(), new.as_ptr(), c::MOVEFILE_REPLACE_EXISTING) } == 0 {
let err = api::get_last_error();
// if `MoveFileExW` fails with ERROR_ACCESS_DENIED then try to move
// the file while ignoring the readonly attribute.
// This is accomplished by calling `SetFileInformationByHandle` with `FileRenameInfoEx`.
if err == WinError::ACCESS_DENIED {
let mut opts = OpenOptions::new();
opts.access_mode(c::DELETE);
opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS);
let Ok(f) = File::open_native(&old, &opts) else { return Err(err).io_result() };

// Calculate the layout of the `FILE_RENAME_INFO` we pass to `SetFileInformation`
// This is a dynamically sized struct so we need to get the position of the last field to calculate the actual size.
let Ok(new_len_without_nul_in_bytes): Result<u32, _> = ((new.len() - 1) * 2).try_into()
else {
return Err(err).io_result();
};

if let Err(err) = result {
if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _)
|| err.raw_os_error() == Some(c::ERROR_INVALID_FUNCTION as _)
{
// `GetFileInformationByHandleEx` documents that not all underlying drivers support all file information classes.
// Since we know we passed the correct arguments, this means the underlying driver didn't understand our request;
// `MoveFileEx` proceeds by reopening the file without inhibiting reparse point behavior.
None
} else {
Some(Err(err))
}
} else {
// SAFETY: The struct has been initialized by GetFileInformationByHandleEx
let file_attribute_tag_info = unsafe { file_attribute_tag_info.assume_init() };
let file_type = FileType::new(
file_attribute_tag_info.FileAttributes,
file_attribute_tag_info.ReparseTag,
);

if file_type.is_symlink() {
// The file is a mount point, junction point or symlink so
// don't reopen the file so that the link gets renamed.
Some(Ok(handle))
} else {
// Otherwise reopen the file without inhibiting reparse point behavior.
None
let offset: u32 = offset_of!(c::FILE_RENAME_INFO, FileName).try_into().unwrap();
let struct_size = offset + new_len_without_nul_in_bytes + 2;
let layout =
Layout::from_size_align(struct_size as usize, align_of::<c::FILE_RENAME_INFO>())
.unwrap();

// SAFETY: We allocate enough memory for a full FILE_RENAME_INFO struct and a filename.
let file_rename_info;
unsafe {
file_rename_info = alloc(layout).cast::<c::FILE_RENAME_INFO>();
if file_rename_info.is_null() {
return Err(io::ErrorKind::OutOfMemory.into());
}
}
}
// The underlying driver may not support `FILE_FLAG_OPEN_REPARSE_POINT`: Retry without it.
Err(err) if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _) => None,
Err(err) => Some(Err(err)),
}
.unwrap_or_else(|| create_file(0, 0))?;

let layout = core::alloc::Layout::from_size_align(
struct_size as _,
mem::align_of::<c::FILE_RENAME_INFO>(),
)
.unwrap();

let file_rename_info = unsafe { alloc(layout) } as *mut c::FILE_RENAME_INFO;

if file_rename_info.is_null() {
handle_alloc_error(layout);
}

// SAFETY: file_rename_info is a non-null pointer pointing to memory allocated by the global allocator.
let mut file_rename_info = unsafe { Box::from_raw(file_rename_info) };

// SAFETY: We have allocated enough memory for a full FILE_RENAME_INFO struct and a filename.
unsafe {
(&raw mut (*file_rename_info).Anonymous).write(c::FILE_RENAME_INFO_0 {
Flags: c::FILE_RENAME_FLAG_REPLACE_IF_EXISTS | c::FILE_RENAME_FLAG_POSIX_SEMANTICS,
});

(&raw mut (*file_rename_info).RootDirectory).write(ptr::null_mut());
(&raw mut (*file_rename_info).FileNameLength).write(new_len_without_nul_in_bytes);

new.as_ptr()
.copy_to_nonoverlapping((&raw mut (*file_rename_info).FileName) as *mut u16, new.len());
}
(&raw mut (*file_rename_info).Anonymous).write(c::FILE_RENAME_INFO_0 {
Flags: c::FILE_RENAME_FLAG_REPLACE_IF_EXISTS
| c::FILE_RENAME_FLAG_POSIX_SEMANTICS,
});

// We don't use `set_file_information_by_handle` here as `FILE_RENAME_INFO` is used for both `FileRenameInfo` and `FileRenameInfoEx`.
let result = unsafe {
cvt(c::SetFileInformationByHandle(
handle.as_raw_handle(),
c::FileRenameInfoEx,
(&raw const *file_rename_info).cast::<c_void>(),
struct_size,
))
};
(&raw mut (*file_rename_info).RootDirectory).write(ptr::null_mut());
// Don't include the NULL in the size
(&raw mut (*file_rename_info).FileNameLength).write(new_len_without_nul_in_bytes);

if let Err(err) = result {
if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _) {
// FileRenameInfoEx and FILE_RENAME_FLAG_POSIX_SEMANTICS were added in Windows 10 1607; retry with FileRenameInfo.
file_rename_info.Anonymous.ReplaceIfExists = 1;
new.as_ptr().copy_to_nonoverlapping(
(&raw mut (*file_rename_info).FileName).cast::<u16>(),
new.len(),
);
}

cvt(unsafe {
let result = unsafe {
c::SetFileInformationByHandle(
handle.as_raw_handle(),
c::FileRenameInfo,
(&raw const *file_rename_info).cast::<c_void>(),
f.as_raw_handle(),
c::FileRenameInfoEx,
file_rename_info.cast::<c_void>(),
struct_size,
)
})?;
};
unsafe { dealloc(file_rename_info.cast::<u8>(), layout) };
if result == 0 {
if api::get_last_error() == WinError::DIR_NOT_EMPTY {
return Err(WinError::DIR_NOT_EMPTY).io_result();
} else {
return Err(err).io_result();
}
}
} else {
return Err(err);
return Err(err).io_result();
}
}

Ok(())
}

Expand Down
4 changes: 2 additions & 2 deletions src/bootstrap/Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ dependencies = [

[[package]]
name = "cc"
version = "1.2.0"
version = "1.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8"
checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0"
dependencies = [
"shlex",
]
Expand Down
4 changes: 3 additions & 1 deletion src/bootstrap/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ test = false
# Most of the time updating these dependencies requires modifications to the
# bootstrap codebase(e.g., https://github.com/rust-lang/rust/issues/124565);
# otherwise, some targets will fail. That's why these dependencies are explicitly pinned.
cc = "=1.2.0"
#
# Do not upgrade this crate unless https://github.com/rust-lang/cc-rs/issues/1317 is fixed.
cc = "=1.1.22"
cmake = "=0.1.48"

build_helper = { path = "../build_helper" }
Expand Down
2 changes: 1 addition & 1 deletion src/bootstrap/src/core/config/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2668,7 +2668,7 @@ impl Config {
/// used instead to provide a nice error to the user if the submodule is
/// missing.
pub(crate) fn update_submodule(&self, relative_path: &str) {
if !self.submodules() {
if self.rust_info.is_from_tarball() || !self.submodules() {
return;
}

Expand Down
4 changes: 4 additions & 0 deletions src/bootstrap/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,10 @@ impl Build {
/// The given `err_hint` will be shown to the user if the submodule is not
/// checked out and submodule management is disabled.
pub fn require_submodule(&self, submodule: &str, err_hint: Option<&str>) {
if self.rust_info().is_from_tarball() {
return;
}

// When testing bootstrap itself, it is much faster to ignore
// submodules. Almost all Steps work fine without their submodules.
if cfg!(test) && !self.config.submodules() {
Expand Down
Loading
Loading