diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 2f88e587ae9f7..bbdda155496fa 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1205,6 +1205,10 @@ impl<'a> DiagCtxtHandle<'a> { std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations) } + /// Trigger an ICE if there are any delayed bugs and no hard errors. + /// + /// This will panic if there are any stashed diagnostics. You can call + /// `emit_stashed_diagnostics` to emit those before calling `flush_delayed`. pub fn flush_delayed(&self) { self.inner.borrow_mut().flush_delayed(); } diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index fc5f159ec188e..18c1501a655fe 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -7,7 +7,7 @@ use crate::hash::Hash; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::path::{Path, PathBuf}; use crate::sys::time::SystemTime; -use crate::sys::unsupported; +use crate::sys::{helpers, unsupported}; #[expect(dead_code)] const FILE_PERMISSIONS_MASK: u64 = r_efi::protocols::file::READ_ONLY; @@ -76,6 +76,18 @@ impl FileAttr { pub fn created(&self) -> io::Result { Ok(self.created) } + + fn from_uefi(info: helpers::UefiBox) -> Self { + unsafe { + Self { + attr: (*info.as_ptr()).attribute, + size: (*info.as_ptr()).size, + modified: uefi_fs::uefi_to_systemtime((*info.as_ptr()).modification_time), + accessed: uefi_fs::uefi_to_systemtime((*info.as_ptr()).last_access_time), + created: uefi_fs::uefi_to_systemtime((*info.as_ptr()).create_time), + } + } + } } impl FilePermissions { @@ -381,8 +393,10 @@ pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { unsupported() } -pub fn stat(_p: &Path) -> io::Result { - unsupported() +pub fn stat(p: &Path) -> io::Result { + let f = uefi_fs::File::from_path(p, r_efi::protocols::file::MODE_READ, 0)?; + let inf = f.file_info()?; + Ok(FileAttr::from_uefi(inf)) } pub fn lstat(p: &Path) -> io::Result { @@ -404,7 +418,7 @@ mod uefi_fs { use crate::io; use crate::path::Path; use crate::ptr::NonNull; - use crate::sys::helpers; + use crate::sys::helpers::{self, UefiBox}; use crate::sys::time::{self, SystemTime}; pub(crate) struct File(NonNull); @@ -492,6 +506,37 @@ mod uefi_fs { let p = NonNull::new(file_opened).unwrap(); Ok(File(p)) } + + pub(crate) fn file_info(&self) -> io::Result> { + let file_ptr = self.0.as_ptr(); + let mut info_id = file::INFO_ID; + let mut buf_size = 0; + + let r = unsafe { + ((*file_ptr).get_info)( + file_ptr, + &mut info_id, + &mut buf_size, + crate::ptr::null_mut(), + ) + }; + assert!(r.is_error()); + if r != r_efi::efi::Status::BUFFER_TOO_SMALL { + return Err(io::Error::from_raw_os_error(r.as_usize())); + } + + let mut info: UefiBox = UefiBox::new(buf_size)?; + let r = unsafe { + ((*file_ptr).get_info)( + file_ptr, + &mut info_id, + &mut buf_size, + info.as_mut_ptr().cast(), + ) + }; + + if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(info) } + } } impl Drop for File { @@ -556,8 +601,7 @@ mod uefi_fs { /// EDK2 FAT driver uses EFI_UNSPECIFIED_TIMEZONE to represent localtime. So for proper /// conversion to SystemTime, we use the current time to get the timezone in such cases. - #[expect(dead_code)] - fn uefi_to_systemtime(mut time: r_efi::efi::Time) -> SystemTime { + pub(crate) fn uefi_to_systemtime(mut time: r_efi::efi::Time) -> SystemTime { time.timezone = if time.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE { time::system_time_internal::now().unwrap().timezone } else { diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index 852e0d6b051bd..bfad6491e3219 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -798,6 +798,10 @@ impl UefiBox { pub(crate) fn as_mut_ptr(&mut self) -> *mut T { self.inner.as_ptr().cast() } + + pub(crate) fn as_ptr(&self) -> *const T { + self.inner.as_ptr().cast() + } } impl Drop for UefiBox { diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 6fdd2e6995247..6d020f3f245e5 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::collections::{BTreeSet, HashMap, HashSet}; use std::iter; use std::process::Command; @@ -1011,6 +1012,13 @@ pub struct TargetCfg { // target spec). pub(crate) rustc_abi: Option, + /// ELF is the "default" binary format, so the compiler typically doesn't + /// emit a `"binary-format"` field for ELF targets. + /// + /// See `impl ToJson for Target` in `compiler/rustc_target/src/spec/json.rs`. + #[serde(default = "default_binary_format_elf")] + pub(crate) binary_format: Cow<'static, str>, + // Not present in target cfg json output, additional derived information. #[serde(skip)] /// Supported target atomic widths: e.g. `8` to `128` or `ptr`. This is derived from the builtin @@ -1032,6 +1040,10 @@ fn default_reloc_model() -> String { "pic".into() } +fn default_binary_format_elf() -> Cow<'static, str> { + Cow::Borrowed("elf") +} + #[derive(Eq, PartialEq, Clone, Debug, Default, serde::Deserialize)] #[serde(rename_all = "kebab-case")] pub enum Endian { diff --git a/src/tools/compiletest/src/directives/cfg.rs b/src/tools/compiletest/src/directives/cfg.rs index 1735866bf2cd6..531763c1b3e25 100644 --- a/src/tools/compiletest/src/directives/cfg.rs +++ b/src/tools/compiletest/src/directives/cfg.rs @@ -169,11 +169,7 @@ fn parse_cfg_name_directive<'a>( condition! { name: "elf", - condition: !config.target.contains("windows") - && !config.target.contains("wasm") - && !config.target.contains("apple") - && !config.target.contains("aix") - && !config.target.contains("uefi"), + condition: target_cfg.binary_format == "elf", message: "when the target binary format is ELF" } diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index 649dc85703419..bb8002de391e1 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -766,6 +766,29 @@ fn ignore_coverage() { assert!(check_ignore(&config, "//@ ignore-coverage-run")); } +#[test] +fn only_ignore_elf() { + let cases = &[ + ("aarch64-apple-darwin", false), + ("aarch64-unknown-linux-gnu", true), + ("powerpc64-ibm-aix", false), + ("wasm32-unknown-unknown", false), + ("wasm32-wasip1", false), + ("x86_64-apple-darwin", false), + ("x86_64-pc-windows-msvc", false), + ("x86_64-unknown-freebsd", true), + ("x86_64-unknown-illumos", true), + ("x86_64-unknown-linux-gnu", true), + ("x86_64-unknown-none", true), + ("x86_64-unknown-uefi", false), + ]; + for &(target, is_elf) in cases { + let config = &cfg().target(target).build(); + assert_eq!(is_elf, check_ignore(config, "//@ ignore-elf"), "`//@ ignore-elf` for {target}"); + assert_eq!(is_elf, !check_ignore(config, "//@ only-elf"), "`//@ only-elf` for {target}"); + } +} + #[test] fn threads_support() { let threads = [ diff --git a/tests/rustdoc/reexport/enum-variant.rs b/tests/rustdoc/reexport/enum-variant.rs new file mode 100644 index 0000000000000..7436f8853e02e --- /dev/null +++ b/tests/rustdoc/reexport/enum-variant.rs @@ -0,0 +1,14 @@ +// This test ensures that reexported enum variants correctly link to the original variant. + +#![crate_name = "foo"] + +pub enum Foo { + S { + x: u32, + }, +} + +//@ has 'foo/index.html' + +//@ has - '//*[@class="item-table reexports"]/*[@id="reexport.S"]//a[@href="enum.Foo.html#variant.S"]' 'S' +pub use self::Foo::S; diff --git a/tests/rustdoc/import_trait_associated_functions.rs b/tests/rustdoc/reexport/import_trait_associated_functions.rs similarity index 100% rename from tests/rustdoc/import_trait_associated_functions.rs rename to tests/rustdoc/reexport/import_trait_associated_functions.rs