Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
ee9b61c
deprecate `std::char` constants and functions
folkertdev Mar 14, 2026
bbb9e3b
libtest: use binary search for --exact test filtering
sunshowers Apr 6, 2026
782a214
Implemented PermissionsExt ACP on Windows, which provides functions/u…
asder8215 Apr 11, 2026
8712a92
Replace the spdx-rs dependency with a minimal in-tree SPDX tag-value …
jakubadamw Apr 4, 2026
57de72c
Add a bunch of unit tests for the in-house parser
jakubadamw Apr 12, 2026
1bdbde5
Move spdx.rs to spdx/mod.rs
jakubadamw Apr 12, 2026
1d61770
Add test for coalescing of diagnostic attribute duplicates
mejrs Apr 15, 2026
f684713
triagebot.toml: Sync `assign.owners` with `autolabel."T-compiler"`
Enselic Apr 15, 2026
46f360a
Add regression test for dead code elimination with drop + panic
iyernaveenr Apr 16, 2026
e0ef87f
Add temporary scope to assert_matches
Voultapher Apr 17, 2026
3a0c0e9
Apply review feedback
Voultapher Apr 18, 2026
d6da4ea
Implement core::arch::return_address and tests
chorman0773 Apr 7, 2026
80a521b
Rollup merge of #155370 - iyernaveenr:naveen_r_iyer/issue-114532-need…
jhpratt Apr 19, 2026
0275a78
Rollup merge of #154823 - jakubadamw:spdx-rs-replacement, r=Mark-Simu…
jhpratt Apr 19, 2026
e7705cf
Rollup merge of #154972 - chorman0773:return_address, r=Mark-Simulacrum
jhpratt Apr 19, 2026
a91b375
Rollup merge of #155294 - mejrs:coalescing, r=chenyukang
jhpratt Apr 19, 2026
b7f2d67
Rollup merge of #155352 - Enselic:label-sync, r=Mark-Simulacrum
jhpratt Apr 19, 2026
9f6b3c5
Rollup merge of #155431 - Voultapher:add-tmp-scope-to-assert-matches,…
jhpratt Apr 19, 2026
42a9f7d
Rollup merge of #152995 - asder8215:windows_permissions_ext, r=Mark-S…
jhpratt Apr 19, 2026
32a1abb
Rollup merge of #153873 - folkertdev:deprecate-char-max, r=Mark-Simul…
jhpratt Apr 19, 2026
4cb516d
Rollup merge of #154865 - sunshowers:binary-search-test, r=Mark-Simul…
jhpratt Apr 19, 2026
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
149 changes: 41 additions & 108 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions compiler/rustc_builtin_macros/src/test_harness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,8 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> Box<ast::Expr> {
let ecx = &cx.ext_cx;

let mut tests = cx.test_cases.clone();
// Note that this sort is load-bearing: the libtest harness uses binary search to find tests by
// name.
tests.sort_by(|a, b| a.name.as_str().cmp(b.name.as_str()));

ecx.expr_array_ref(
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1529,6 +1529,12 @@ fn codegen_regular_intrinsic_call<'tcx>(
fx.bcx.set_cold_block(fx.bcx.current_block().unwrap());
}

sym::return_address => {
let val = fx.bcx.ins().get_return_address(fx.pointer_type);
let val = CValue::by_val(val, ret.layout());
ret.write_cvalue(fx, val);
}

// Unimplemented intrinsics must have a fallback body. The fallback body is obtained
// by converting the `InstanceKind::Intrinsic` to an `InstanceKind::Item`.
_ => {
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,12 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
}
}

sym::return_address => {
let ty = self.type_ix(32);
let val = self.const_int(ty, 0);
self.call_intrinsic("llvm.returnaddress", &[], &[val])
}

_ => {
debug!("unknown intrinsic '{}' -- falling back to default body", name);
// Call the fallback body instead of generating the intrinsic code
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
| sym::contract_checks
| sym::atomic_fence
| sym::atomic_singlethreadfence
| sym::caller_location => {}
| sym::caller_location
| sym::return_address => {}
_ => {
span_bug!(
span,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir_analysis/src/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
| sym::ptr_guaranteed_cmp
| sym::ptr_mask
| sym::ptr_metadata
| sym::return_address
| sym::rotate_left
| sym::rotate_right
| sym::round_ties_even_f16
Expand Down Expand Up @@ -801,6 +802,8 @@ pub(crate) fn check_intrinsic_type(
| sym::atomic_xor => (2, 1, vec![Ty::new_mut_ptr(tcx, param(0)), param(1)], param(0)),
sym::atomic_fence | sym::atomic_singlethreadfence => (0, 1, Vec::new(), tcx.types.unit),

sym::return_address => (0, 0, vec![], Ty::new_imm_ptr(tcx, tcx.types.unit)),

other => {
tcx.dcx().emit_err(UnrecognizedIntrinsicFunction { span, name: other });
return;
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1657,6 +1657,7 @@ symbols! {
residual,
result,
result_ffi_guarantees,
return_address,
return_position_impl_trait_in_trait,
return_type_notation,
riscv32,
Expand Down
26 changes: 26 additions & 0 deletions library/core/src/arch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,29 @@ pub macro global_asm("assembly template", $(operands,)* $(options($(option),*))?
pub fn breakpoint() {
core::intrinsics::breakpoint();
}

/// The `core::arch::return_address!()` macro returns a pointer with an address that corresponds to the caller of the function that invoked the `return_address!()` macro.
/// The pointer has no provenance, as if created by `core::ptr::without_provenance`. It cannot be used to read memory (other than ZSTs).
///
/// The value returned by the macro depends highly on the architecture and compiler (including any options set).
/// In particular, it is allowed to be wrong (particularly if inlining is involved), or even contain a nonsense value.
/// The result of this macro must not be relied upon for soundness or correctness, only for debugging purposes.
///
/// As a best effort, if a useful value cannot be determined (for example, due to limitations on the current codegen),
/// this macro tries to return a null pointer instead of nonsense (this cannot be relied upon for correctness, however).
///
/// Formally, this function returns a pointer with a non-deterministic address and no provenance.
///
/// This is equivalent to the gcc `__builtin_return_address(0)` intrinsic (other forms of the intrinsic are not supported).
/// Because the operation can be always performed by the compiler without crashing or causing undefined behaviour, invoking the macro is a safe operation.
///
/// ## Example
/// ```
/// #![feature(return_address)]
///
/// let addr = core::arch::return_address!();
/// println!("Caller is {addr:p}");
/// ```
#[unstable(feature = "return_address", issue = "154966")]
#[allow_internal_unstable(core_intrinsics)]
pub macro return_address() {{ core::intrinsics::return_address() }}
23 changes: 13 additions & 10 deletions library/core/src/char/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,31 +93,31 @@ const MAX_THREE_B: u32 = 0x10000;

/// The highest valid code point a `char` can have, `'\u{10FFFF}'`. Use [`char::MAX`] instead.
#[stable(feature = "rust1", since = "1.0.0")]
#[deprecated(since = "TBD", note = "replaced by the `MAX` associated constant on `char`")]
pub const MAX: char = char::MAX;

/// The maximum number of bytes required to [encode](char::encode_utf8) a `char` to
/// UTF-8 encoding.
#[unstable(feature = "char_max_len", issue = "121714")]
pub const MAX_LEN_UTF8: usize = char::MAX_LEN_UTF8;

/// The maximum number of two-byte units required to [encode](char::encode_utf16) a `char`
/// to UTF-16 encoding.
#[unstable(feature = "char_max_len", issue = "121714")]
pub const MAX_LEN_UTF16: usize = char::MAX_LEN_UTF16;

/// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a
/// decoding error. Use [`char::REPLACEMENT_CHARACTER`] instead.
#[stable(feature = "decode_utf16", since = "1.9.0")]
#[deprecated(
since = "TBD",
note = "replaced by the `REPLACEMENT_CHARACTER` associated constant on `char`"
)]
pub const REPLACEMENT_CHARACTER: char = char::REPLACEMENT_CHARACTER;

/// The version of [Unicode](https://www.unicode.org/) that the Unicode parts of
/// `char` and `str` methods are based on. Use [`char::UNICODE_VERSION`] instead.
#[stable(feature = "unicode_version", since = "1.45.0")]
#[deprecated(
since = "TBD",
note = "replaced by the `UNICODE_VERSION` associated constant on `char`"
)]
pub const UNICODE_VERSION: (u8, u8, u8) = char::UNICODE_VERSION;

/// Creates an iterator over the UTF-16 encoded code points in `iter`, returning
/// unpaired surrogates as `Err`s. Use [`char::decode_utf16`] instead.
#[stable(feature = "decode_utf16", since = "1.9.0")]
#[deprecated(since = "TBD", note = "replaced by the `decode_utf16` method on `char`")]
#[inline]
pub fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> DecodeUtf16<I::IntoIter> {
self::decode::decode_utf16(iter)
Expand All @@ -126,6 +126,7 @@ pub fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> DecodeUtf16<I::Into
/// Converts a `u32` to a `char`. Use [`char::from_u32`] instead.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_char_convert", since = "1.67.0")]
#[deprecated(since = "TBD", note = "replaced by the `from_u32` method on `char`")]
#[must_use]
#[inline]
pub const fn from_u32(i: u32) -> Option<char> {
Expand All @@ -136,6 +137,7 @@ pub const fn from_u32(i: u32) -> Option<char> {
/// instead.
#[stable(feature = "char_from_unchecked", since = "1.5.0")]
#[rustc_const_stable(feature = "const_char_from_u32_unchecked", since = "1.81.0")]
#[deprecated(since = "TBD", note = "replaced by the `from_u32_unchecked` method on `char`")]
#[must_use]
#[inline]
pub const unsafe fn from_u32_unchecked(i: u32) -> char {
Expand All @@ -146,6 +148,7 @@ pub const unsafe fn from_u32_unchecked(i: u32) -> char {
/// Converts a digit in the given radix to a `char`. Use [`char::from_digit`] instead.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_char_convert", since = "1.67.0")]
#[deprecated(since = "TBD", note = "replaced by the `from_digit` method on `char`")]
#[must_use]
#[inline]
pub const fn from_digit(num: u32, radix: u32) -> Option<char> {
Expand Down
13 changes: 13 additions & 0 deletions library/core/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3589,3 +3589,16 @@ pub const fn va_copy<'f>(src: &VaList<'f>) -> VaList<'f> {
pub const unsafe fn va_end(ap: &mut VaList<'_>) {
/* deliberately does nothing */
}

/// Returns the return address of the caller function (after inlining) in a best-effort manner or a null pointer if it is not supported on the current backend.
/// Returning an accurate value is a quality-of-implementation concern, but no hard guarantees are
/// made about the return value: formally, the intrinsic non-deterministically returns
/// an arbitrary pointer without provenance.
///
/// Note that unlike most intrinsics, this is safe to call. This is because it only finds the return address of the immediate caller, which is guaranteed to be possible.
/// Other forms of the corresponding gcc or llvm intrinsic (which can have wildly unpredictable results or even crash at runtime) are not exposed.
#[rustc_intrinsic]
#[rustc_nounwind]
pub fn return_address() -> *const () {
core::ptr::null()
}
8 changes: 4 additions & 4 deletions library/core/src/macros/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ macro_rules! assert_ne {
#[allow_internal_unstable(panic_internals)]
#[rustc_macro_transparency = "semiopaque"]
pub macro assert_matches {
($left:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => {
($left:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => {{
match $left {
$( $pattern )|+ $( if $guard )? => {}
ref left_val => {
Expand All @@ -179,8 +179,8 @@ pub macro assert_matches {
);
}
}
},
($left:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )?, $($arg:tt)+) => {
}},
($left:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )?, $($arg:tt)+) => {{
match $left {
$( $pattern )|+ $( if $guard )? => {}
ref left_val => {
Expand All @@ -191,7 +191,7 @@ pub macro assert_matches {
);
}
}
},
}},
}

/// Selects code at compile-time based on `cfg` predicates.
Expand Down
1 change: 0 additions & 1 deletion library/coretests/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#![feature(bstr)]
#![feature(cfg_target_has_reliable_f16_f128)]
#![feature(char_internals)]
#![feature(char_max_len)]
#![feature(clone_to_uninit)]
#![feature(cmp_minmax)]
#![feature(const_array)]
Expand Down
26 changes: 26 additions & 0 deletions library/coretests/tests/macros.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![allow(unused_must_use)]

use std::{assert_matches, debug_assert_matches};

#[allow(dead_code)]
trait Trait {
fn blah(&self);
Expand Down Expand Up @@ -219,3 +221,27 @@ fn _matches_does_not_trigger_non_exhaustive_omitted_patterns_lint(o: core::sync:
// Ordering is a #[non_exhaustive] enum from a separate crate
let _m = matches!(o, core::sync::atomic::Ordering::Relaxed);
}

struct MutRefWithDrop<'a>(&'a mut u32);

// MutRefWithDrop needs to have a non-trivial drop to encounter potential lifetime issues if the
// macros don't introduce a temporary scope.
impl Drop for MutRefWithDrop<'_> {
fn drop(&mut self) {
*self.0 = u32::MAX;
}
}

#[test]
fn temporary_scope_introduction() {
// Fails to compile if the macros don't introduce a temporary scope, since `&mut val` would
// create a second mutable borrow while `MutRefWithDrop` still holds a unique ref.
// See https://github.com/rust-lang/rust/issues/154406 for reference.
let mut val = 0;

(assert_matches!(*MutRefWithDrop(&mut val).0, 0), std::mem::take(&mut val));
(assert_matches!(*MutRefWithDrop(&mut val).0, 0, "msg"), std::mem::take(&mut val));

(debug_assert_matches!(*MutRefWithDrop(&mut val).0, 0), std::mem::take(&mut val));
(debug_assert_matches!(*MutRefWithDrop(&mut val).0, 0, "msg"), std::mem::take(&mut val));
}
65 changes: 63 additions & 2 deletions library/std/src/os/windows/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

#![stable(feature = "rust1", since = "1.0.0")]

use crate::fs::{self, Metadata, OpenOptions};
use crate::fs::{self, Metadata, OpenOptions, Permissions};
use crate::io::BorrowedCursor;
use crate::path::Path;
use crate::sealed::Sealed;
use crate::sys::{AsInner, AsInnerMut, IntoInner};
use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner};
use crate::time::SystemTime;
use crate::{io, sys};

Expand Down Expand Up @@ -368,6 +368,67 @@ impl OpenOptionsExt2 for OpenOptions {
}
}

/// Windows-specific extensions to [`fs::Permissions`]. This extension trait
/// provides extra utilities to shows what Windows file attributes are enabled
/// in [`Permissions`] and to manually set file attributes on [`Permissions`].
///
/// See Microsoft's [`File Attribute Constants`] page to know what file
/// attribute metadata are defined and stored on Windows files.
///
/// [`Permissions`]: fs::Permissions
/// [`File Attribute Constants`]:
/// https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
///
/// # Example
///
/// ```no_run
/// use std::fs::Permissions;
/// use std::os::windows::fs::PermissionsExt;
///
/// const FILE_ATTRIBUTE_SYSTEM: u32 = 0x4;
/// const FILE_ATTRIBUTE_ARCHIVE: u32 = 0x20;
/// let my_file_attr = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE;
/// let mut permissions = Permissions::from_file_attributes(my_file_attr);
/// assert_eq!(permissions.file_attributes(), my_file_attr);
///
/// const FILE_ATTRIBUTE_HIDDEN: u32 = 0x2;
/// let new_file_attr = permissions.file_attributes() | FILE_ATTRIBUTE_HIDDEN;
/// permissions.set_file_attributes(new_file_attr);
/// assert_eq!(permissions.file_attributes(), new_file_attr);
/// ```
#[unstable(feature = "windows_permissions_ext", issue = "152956")]
pub trait PermissionsExt: Sealed {
/// Returns the file attribute bits.
#[unstable(feature = "windows_permissions_ext", issue = "152956")]
fn file_attributes(&self) -> u32;

/// Sets the file attribute bits.
#[unstable(feature = "windows_permissions_ext", issue = "152956")]
fn set_file_attributes(&mut self, mask: u32);

/// Creates a new instance from the given file attribute bits.
#[unstable(feature = "windows_permissions_ext", issue = "152956")]
fn from_file_attributes(mask: u32) -> Self;
}

#[unstable(feature = "windows_permissions_ext", issue = "152956")]
impl Sealed for fs::Permissions {}

#[unstable(feature = "windows_permissions_ext", issue = "152956")]
impl PermissionsExt for fs::Permissions {
fn file_attributes(&self) -> u32 {
self.as_inner().file_attributes()
}

fn set_file_attributes(&mut self, mask: u32) {
*self = Permissions::from_inner(FromInner::from_inner(mask));
}

fn from_file_attributes(mask: u32) -> Self {
Permissions::from_inner(FromInner::from_inner(mask))
}
}

/// Windows-specific extensions to [`fs::Metadata`].
///
/// The data members that this trait exposes correspond to the members
Expand Down
10 changes: 10 additions & 0 deletions library/std/src/sys/fs/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,16 @@ impl FilePermissions {
self.attrs &= !c::FILE_ATTRIBUTE_READONLY;
}
}

pub fn file_attributes(&self) -> u32 {
self.attrs as u32
}
}

impl FromInner<u32> for FilePermissions {
fn from_inner(attrs: u32) -> FilePermissions {
FilePermissions { attrs }
}
}

impl FileTimes {
Expand Down
9 changes: 5 additions & 4 deletions library/test/src/console.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use super::helpers::metrics::MetricMap;
use super::options::{Options, OutputFormat};
use super::test_result::TestResult;
use super::time::{TestExecTime, TestSuiteExecTime};
use super::types::{NamePadding, TestDesc, TestDescAndFn};
use super::types::{NamePadding, TestDesc, TestDescAndFn, TestList};
use super::{filter_tests, run_tests, term};

/// Generic wrapper over stdout.
Expand Down Expand Up @@ -170,7 +170,7 @@ impl ConsoleTestState {
}

// List the tests to console, and optionally to logfile. Filters are honored.
pub(crate) fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> {
pub(crate) fn list_tests_console(opts: &TestOpts, tests: TestList) -> io::Result<()> {
let output = match term::stdout() {
None => OutputLocation::Raw(io::stdout().lock()),
Some(t) => OutputLocation::Pretty(t),
Expand All @@ -186,7 +186,7 @@ pub(crate) fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) ->
let mut st = ConsoleTestDiscoveryState::new(opts)?;

out.write_discovery_start()?;
for test in filter_tests(opts, tests).into_iter() {
for test in filter_tests(opts, tests) {
use crate::TestFn::*;

let TestDescAndFn { desc, testfn } = test;
Expand Down Expand Up @@ -307,8 +307,9 @@ pub(crate) fn get_formatter(opts: &TestOpts, max_name_len: usize) -> Box<dyn Out

/// A simple console test runner.
/// Runs provided tests reporting process and results to the stdout.
pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<bool> {
pub fn run_tests_console(opts: &TestOpts, tests: TestList) -> io::Result<bool> {
let max_name_len = tests
.tests
.iter()
.max_by_key(|t| len_if_padded(t))
.map(|t| t.desc.name.as_slice().len())
Expand Down
Loading
Loading