Auto merge of #138831 - matthiaskrgr:rollup-3t0dqiz, r=matthiaskrgr

Rollup of 7 pull requests

Successful merges:

 - #138609 (Add stack overflow handler for cygwin)
 - #138639 (Clean UI tests 2 of n)
 - #138773 (catch_unwind intrinsic: document return value)
 - #138782 (test(ui): add tuple-struct-where-clause-suggestion ui test for #91520)
 - #138794 (expand: Do not report `cfg_attr` traces on macros as unused attributes)
 - #138801 (triagebot: add autolabel rules for D-* and L-*)
 - #138804 (Allow inlining for `Atomic*::from_ptr`)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-03-22 20:52:30 +00:00
commit b48576b4db
17 changed files with 226 additions and 86 deletions

View file

@ -1941,7 +1941,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
let attr_name = attr.ident().unwrap().name; let attr_name = attr.ident().unwrap().name;
// `#[cfg]` and `#[cfg_attr]` are special - they are // `#[cfg]` and `#[cfg_attr]` are special - they are
// eagerly evaluated. // eagerly evaluated.
if attr_name != sym::cfg && attr_name != sym::cfg_attr { if attr_name != sym::cfg && attr_name != sym::cfg_attr_trace {
self.cx.sess.psess.buffer_lint( self.cx.sess.psess.buffer_lint(
UNUSED_ATTRIBUTES, UNUSED_ATTRIBUTES,
attr.span, attr.span,

View file

@ -3002,6 +3002,7 @@ pub const fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discrimina
/// Rust's "try catch" construct for unwinding. Invokes the function pointer `try_fn` with the /// Rust's "try catch" construct for unwinding. Invokes the function pointer `try_fn` with the
/// data pointer `data`, and calls `catch_fn` if unwinding occurs while `try_fn` runs. /// data pointer `data`, and calls `catch_fn` if unwinding occurs while `try_fn` runs.
/// Returns `1` if unwinding occurred and `catch_fn` was called; returns `0` otherwise.
/// ///
/// `catch_fn` must not unwind. /// `catch_fn` must not unwind.
/// ///

View file

@ -469,6 +469,7 @@ impl AtomicBool {
/// ///
/// [valid]: crate::ptr#safety /// [valid]: crate::ptr#safety
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
#[inline]
#[stable(feature = "atomic_from_ptr", since = "1.75.0")] #[stable(feature = "atomic_from_ptr", since = "1.75.0")]
#[rustc_const_stable(feature = "const_atomic_from_ptr", since = "1.84.0")] #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "1.84.0")]
pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a AtomicBool { pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a AtomicBool {
@ -1389,6 +1390,7 @@ impl<T> AtomicPtr<T> {
/// ///
/// [valid]: crate::ptr#safety /// [valid]: crate::ptr#safety
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
#[inline]
#[stable(feature = "atomic_from_ptr", since = "1.75.0")] #[stable(feature = "atomic_from_ptr", since = "1.75.0")]
#[rustc_const_stable(feature = "const_atomic_from_ptr", since = "1.84.0")] #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "1.84.0")]
pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr<T> { pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr<T> {
@ -2525,6 +2527,7 @@ macro_rules! atomic_int {
/// ///
/// [valid]: crate::ptr#safety /// [valid]: crate::ptr#safety
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
#[inline]
#[stable(feature = "atomic_from_ptr", since = "1.75.0")] #[stable(feature = "atomic_from_ptr", since = "1.75.0")]
#[rustc_const_stable(feature = "const_atomic_from_ptr", since = "1.84.0")] #[rustc_const_stable(feature = "const_atomic_from_ptr", since = "1.84.0")]
pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a $atomic_type { pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a $atomic_type {

View file

@ -585,6 +585,7 @@ mod imp {
target_os = "openbsd", target_os = "openbsd",
target_os = "solaris", target_os = "solaris",
target_os = "illumos", target_os = "illumos",
target_os = "cygwin",
)))] )))]
mod imp { mod imp {
pub unsafe fn init() {} pub unsafe fn init() {}
@ -597,3 +598,89 @@ mod imp {
pub unsafe fn drop_handler(_data: *mut libc::c_void) {} pub unsafe fn drop_handler(_data: *mut libc::c_void) {}
} }
#[cfg(target_os = "cygwin")]
mod imp {
mod c {
pub type PVECTORED_EXCEPTION_HANDLER =
Option<unsafe extern "system" fn(exceptioninfo: *mut EXCEPTION_POINTERS) -> i32>;
pub type NTSTATUS = i32;
pub type BOOL = i32;
unsafe extern "system" {
pub fn AddVectoredExceptionHandler(
first: u32,
handler: PVECTORED_EXCEPTION_HANDLER,
) -> *mut core::ffi::c_void;
pub fn SetThreadStackGuarantee(stacksizeinbytes: *mut u32) -> BOOL;
}
pub const EXCEPTION_STACK_OVERFLOW: NTSTATUS = 0xC00000FD_u32 as _;
pub const EXCEPTION_CONTINUE_SEARCH: i32 = 1i32;
#[repr(C)]
#[derive(Clone, Copy)]
pub struct EXCEPTION_POINTERS {
pub ExceptionRecord: *mut EXCEPTION_RECORD,
// We don't need this field here
// pub Context: *mut CONTEXT,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct EXCEPTION_RECORD {
pub ExceptionCode: NTSTATUS,
pub ExceptionFlags: u32,
pub ExceptionRecord: *mut EXCEPTION_RECORD,
pub ExceptionAddress: *mut core::ffi::c_void,
pub NumberParameters: u32,
pub ExceptionInformation: [usize; 15],
}
}
/// Reserve stack space for use in stack overflow exceptions.
fn reserve_stack() {
let result = unsafe { c::SetThreadStackGuarantee(&mut 0x5000) };
// Reserving stack space is not critical so we allow it to fail in the released build of libstd.
// We still use debug assert here so that CI will test that we haven't made a mistake calling the function.
debug_assert_ne!(result, 0, "failed to reserve stack space for exception handling");
}
unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> i32 {
// SAFETY: It's up to the caller (which in this case is the OS) to ensure that `ExceptionInfo` is valid.
unsafe {
let rec = &(*(*ExceptionInfo).ExceptionRecord);
let code = rec.ExceptionCode;
if code == c::EXCEPTION_STACK_OVERFLOW {
crate::thread::with_current_name(|name| {
let name = name.unwrap_or("<unknown>");
rtprintpanic!("\nthread '{name}' has overflowed its stack\n");
});
}
c::EXCEPTION_CONTINUE_SEARCH
}
}
pub unsafe fn init() {
// SAFETY: `vectored_handler` has the correct ABI and is safe to call during exception handling.
unsafe {
let result = c::AddVectoredExceptionHandler(0, Some(vectored_handler));
// Similar to the above, adding the stack overflow handler is allowed to fail
// but a debug assert is used so CI will still test that it normally works.
debug_assert!(!result.is_null(), "failed to install exception handler");
}
// Set the thread stack guarantee for the main thread.
reserve_stack();
}
pub unsafe fn cleanup() {}
pub unsafe fn make_handler(main_thread: bool) -> super::Handler {
if !main_thread {
reserve_stack();
}
super::Handler::null()
}
pub unsafe fn drop_handler(_data: *mut libc::c_void) {}
}

View file

@ -2000,7 +2000,6 @@ ui/issues/issue-28586.rs
ui/issues/issue-28600.rs ui/issues/issue-28600.rs
ui/issues/issue-28625.rs ui/issues/issue-28625.rs
ui/issues/issue-28776.rs ui/issues/issue-28776.rs
ui/issues/issue-28777.rs
ui/issues/issue-28828.rs ui/issues/issue-28828.rs
ui/issues/issue-28839.rs ui/issues/issue-28839.rs
ui/issues/issue-28936.rs ui/issues/issue-28936.rs
@ -2063,7 +2062,6 @@ ui/issues/issue-3091.rs
ui/issues/issue-31011.rs ui/issues/issue-31011.rs
ui/issues/issue-3109.rs ui/issues/issue-3109.rs
ui/issues/issue-3121.rs ui/issues/issue-3121.rs
ui/issues/issue-31260.rs
ui/issues/issue-31267-additional.rs ui/issues/issue-31267-additional.rs
ui/issues/issue-31267.rs ui/issues/issue-31267.rs
ui/issues/issue-31299.rs ui/issues/issue-31299.rs
@ -2608,7 +2606,6 @@ ui/issues/issue-9243.rs
ui/issues/issue-9249.rs ui/issues/issue-9249.rs
ui/issues/issue-9259.rs ui/issues/issue-9259.rs
ui/issues/issue-92741.rs ui/issues/issue-92741.rs
ui/issues/issue-9382.rs
ui/issues/issue-9446.rs ui/issues/issue-9446.rs
ui/issues/issue-9719.rs ui/issues/issue-9719.rs
ui/issues/issue-9725.rs ui/issues/issue-9725.rs

View file

@ -17,7 +17,7 @@ use ignore::Walk;
const ENTRY_LIMIT: u32 = 901; const ENTRY_LIMIT: u32 = 901;
// FIXME: The following limits should be reduced eventually. // FIXME: The following limits should be reduced eventually.
const ISSUES_ENTRY_LIMIT: u32 = 1634; const ISSUES_ENTRY_LIMIT: u32 = 1631;
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
"rs", // test source files "rs", // test source files

View file

@ -0,0 +1,20 @@
//! Regression test that ensures struct field literals can be coerced into slice and `Box` types
//@ check-pass
struct Thing1<'a> {
baz: &'a [Box<isize>],
bar: Box<u64>,
}
struct Thing2<'a> {
baz: &'a [Box<isize>],
bar: u64,
}
pub fn main() {
let _a = Thing1 { baz: &[], bar: Box::new(32) };
let _b = Thing1 { baz: &Vec::new(), bar: Box::new(32) };
let _c = Thing2 { baz: &[], bar: 32 };
let _d = Thing2 { baz: &Vec::new(), bar: 32 };
}

View file

@ -0,0 +1,16 @@
//! Regression test to check that literal expressions in a struct field can be coerced to the
//! expected field type, including block expressions.
//!
//! Issue: <https://github.com/rust-lang/rust/issues/31260>
//@ check-pass
pub struct Struct<K: 'static> {
pub field: K,
}
static STRUCT: Struct<&'static [u8]> = Struct { field: { &[1] } };
static STRUCT2: Struct<&'static [u8]> = Struct { field: &[1] };
fn main() {}

View file

@ -1,22 +0,0 @@
//@ run-pass
#![allow(unused_braces)]
fn main() {
let v1 = { 1 + {2} * {3} };
let v2 = 1 + {2} * {3} ;
assert_eq!(7, v1);
assert_eq!(7, v2);
let v3;
v3 = { 1 + {2} * {3} };
let v4;
v4 = 1 + {2} * {3};
assert_eq!(7, v3);
assert_eq!(7, v4);
let v5 = { 1 + {2} * 3 };
assert_eq!(7, v5);
let v9 = { 1 + if 1 > 2 {1} else {2} * {3} };
assert_eq!(7, v9);
}

View file

@ -1,15 +0,0 @@
//@ check-pass
#![allow(dead_code)]
pub struct Struct<K: 'static> {
pub field: K,
}
static STRUCT: Struct<&'static [u8]> = Struct {
field: {&[1]}
};
static STRUCT2: Struct<&'static [u8]> = Struct {
field: &[1]
};
fn main() {}

View file

@ -1,37 +0,0 @@
//@ run-pass
#![allow(dead_code)]
// Tests for a previous bug that occurred due to an interaction
// between struct field initialization and the auto-coercion
// from a vector to a slice. The drop glue was being invoked on
// the temporary slice with a wrong type, triggering an LLVM assert.
struct Thing1<'a> {
baz: &'a [Box<isize>],
bar: Box<u64>,
}
struct Thing2<'a> {
baz: &'a [Box<isize>],
bar: u64,
}
pub fn main() {
let _t1_fixed = Thing1 {
baz: &[],
bar: Box::new(32),
};
Thing1 {
baz: &Vec::new(),
bar: Box::new(32),
};
let _t2_fixed = Thing2 {
baz: &[],
bar: 32,
};
Thing2 {
baz: &Vec::new(),
bar: 32,
};
}

View file

@ -1,5 +1,6 @@
//@ check-pass //@ check-pass
#![feature(cfg_boolean_literals)]
#![warn(unused)] #![warn(unused)]
macro_rules! foo { macro_rules! foo {
@ -17,4 +18,10 @@ fn main() {
// This does work, since the attribute is on a parent // This does work, since the attribute is on a parent
// of the macro invocation. // of the macro invocation.
#[allow(warnings)] { #[inline] foo!(); } #[allow(warnings)] { #[inline] foo!(); }
// Ok, `cfg` and `cfg_attr` are expanded eagerly and do not warn.
#[cfg(true)] foo!();
#[cfg(false)] foo!();
#[cfg_attr(true, cfg(true))] foo!();
#[cfg_attr(false, nonexistent)] foo!();
} }

View file

@ -1,41 +1,41 @@
warning: unused attribute `inline` warning: unused attribute `inline`
--> $DIR/inert-attr-macro.rs:10:5 --> $DIR/inert-attr-macro.rs:11:5
| |
LL | #[inline] foo!(); LL | #[inline] foo!();
| ^^^^^^^^^ | ^^^^^^^^^
| |
note: the built-in attribute `inline` will be ignored, since it's applied to the macro invocation `foo` note: the built-in attribute `inline` will be ignored, since it's applied to the macro invocation `foo`
--> $DIR/inert-attr-macro.rs:10:15 --> $DIR/inert-attr-macro.rs:11:15
| |
LL | #[inline] foo!(); LL | #[inline] foo!();
| ^^^ | ^^^
note: the lint level is defined here note: the lint level is defined here
--> $DIR/inert-attr-macro.rs:3:9 --> $DIR/inert-attr-macro.rs:4:9
| |
LL | #![warn(unused)] LL | #![warn(unused)]
| ^^^^^^ | ^^^^^^
= note: `#[warn(unused_attributes)]` implied by `#[warn(unused)]` = note: `#[warn(unused_attributes)]` implied by `#[warn(unused)]`
warning: unused attribute `allow` warning: unused attribute `allow`
--> $DIR/inert-attr-macro.rs:14:5 --> $DIR/inert-attr-macro.rs:15:5
| |
LL | #[allow(warnings)] #[inline] foo!(); LL | #[allow(warnings)] #[inline] foo!();
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
| |
note: the built-in attribute `allow` will be ignored, since it's applied to the macro invocation `foo` note: the built-in attribute `allow` will be ignored, since it's applied to the macro invocation `foo`
--> $DIR/inert-attr-macro.rs:14:34 --> $DIR/inert-attr-macro.rs:15:34
| |
LL | #[allow(warnings)] #[inline] foo!(); LL | #[allow(warnings)] #[inline] foo!();
| ^^^ | ^^^
warning: unused attribute `inline` warning: unused attribute `inline`
--> $DIR/inert-attr-macro.rs:14:24 --> $DIR/inert-attr-macro.rs:15:24
| |
LL | #[allow(warnings)] #[inline] foo!(); LL | #[allow(warnings)] #[inline] foo!();
| ^^^^^^^^^ | ^^^^^^^^^
| |
note: the built-in attribute `inline` will be ignored, since it's applied to the macro invocation `foo` note: the built-in attribute `inline` will be ignored, since it's applied to the macro invocation `foo`
--> $DIR/inert-attr-macro.rs:14:34 --> $DIR/inert-attr-macro.rs:15:34
| |
LL | #[allow(warnings)] #[inline] foo!(); LL | #[allow(warnings)] #[inline] foo!();
| ^^^ | ^^^

View file

@ -0,0 +1,28 @@
//! Regression test for ensuring that operator precedence is correctly handled in the presence of
//! braces
//!
//! Issue: <https://github.com/rust-lang/rust/issues/28777>
//@ run-pass
#[allow(unused_braces)]
fn main() {
let v1 = { 1 + { 2 } * { 3 } };
let v2 = 1 + { 2 } * { 3 };
assert_eq!(7, v1);
assert_eq!(7, v2);
let v3;
v3 = { 1 + { 2 } * { 3 } };
let v4;
v4 = 1 + { 2 } * { 3 };
assert_eq!(7, v3);
assert_eq!(7, v4);
let v5 = { 1 + { 2 } * 3 };
assert_eq!(7, v5);
let v9 = { 1 + if 1 > 2 { 1 } else { 2 } * { 3 } };
assert_eq!(7, v9);
}

View file

@ -0,0 +1,17 @@
// Verify that the `where` clause suggestion is in the correct place
// Previously, the suggestion to add `where` clause was placed inside the derive
// like `#[derive(Clone where Inner<T>: Clone)]`
// instead of `struct Outer<T>(Inner<T>) where Inner<T>: Clone`
#![crate_type = "lib"]
struct Inner<T>(T);
//~^ HELP consider annotating `Inner<T>` with `#[derive(Clone)]`
impl Clone for Inner<()> {
fn clone(&self) -> Self { todo!() }
}
#[derive(Clone)]
struct Outer<T>(Inner<T>);
//~^ ERROR the trait bound `Inner<T>: Clone` is not satisfied [E0277]
//~| HELP consider introducing a `where` clause

View file

@ -0,0 +1,21 @@
error[E0277]: the trait bound `Inner<T>: Clone` is not satisfied
--> $DIR/tuple-struct-where-clause-suggestion-91520.rs:15:17
|
LL | #[derive(Clone)]
| ----- in this derive macro expansion
LL | struct Outer<T>(Inner<T>);
| ^^^^^^^^ the trait `Clone` is not implemented for `Inner<T>`
|
help: consider annotating `Inner<T>` with `#[derive(Clone)]`
|
LL + #[derive(Clone)]
LL | struct Inner<T>(T);
|
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
|
LL | struct Outer<T>(Inner<T>) where Inner<T>: Clone;
| +++++++++++++++++++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -307,6 +307,23 @@ exclude_labels = [
"T-*", "T-*",
] ]
trigger_labels = [
"D-*",
"A-diagnostics",
]
[autolabel."A-diagnostics"]
trigger_labels = [
"D-*",
]
[autolabel."A-lints"]
trigger_labels = [
"L-*",
]
[autolabel."T-libs"] [autolabel."T-libs"]
trigger_files = [ trigger_files = [
"library/alloc", "library/alloc",