Skip to content

Rollup of 6 pull requests #140646

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 12 commits into from
May 5, 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
2 changes: 1 addition & 1 deletion compiler/rustc_expand/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ impl<'a> StripUnconfigured<'a> {
pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec<Attribute> {
validate_attr::check_attribute_safety(
&self.sess.psess,
AttributeSafety::Normal,
Some(AttributeSafety::Normal),
&cfg_attr,
ast::CRATE_NODE_ID,
);
Expand Down
13 changes: 11 additions & 2 deletions compiler/rustc_log/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ use std::env::{self, VarError};
use std::fmt::{self, Display};
use std::io::{self, IsTerminal};

use tracing::dispatcher::SetGlobalDefaultError;
use tracing_core::{Event, Subscriber};
use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter};
use tracing_subscriber::fmt::FmtContext;
Expand Down Expand Up @@ -131,10 +132,10 @@ pub fn init_logger(cfg: LoggerConfig) -> Result<(), Error> {
.without_time()
.event_format(BacktraceFormatter { backtrace_target });
let subscriber = subscriber.with(fmt_layer);
tracing::subscriber::set_global_default(subscriber).unwrap();
tracing::subscriber::set_global_default(subscriber)?;
}
Err(_) => {
tracing::subscriber::set_global_default(subscriber).unwrap();
tracing::subscriber::set_global_default(subscriber)?;
}
};

Expand Down Expand Up @@ -180,6 +181,7 @@ pub enum Error {
InvalidColorValue(String),
NonUnicodeColorValue,
InvalidWraptree(String),
AlreadyInit(SetGlobalDefaultError),
}

impl std::error::Error for Error {}
Expand All @@ -199,6 +201,13 @@ impl Display for Error {
formatter,
"invalid log WRAPTREE value '{value}': expected a non-negative integer",
),
Error::AlreadyInit(tracing_error) => Display::fmt(tracing_error, formatter),
}
}
}

impl From<SetGlobalDefaultError> for Error {
fn from(tracing_error: SetGlobalDefaultError) -> Self {
Error::AlreadyInit(tracing_error)
}
}
6 changes: 5 additions & 1 deletion compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1929,13 +1929,17 @@ impl<'tcx> TyCtxt<'tcx> {
if arg_cor_ty.is_coroutine() {
let span = self.def_span(def_id);
let source_info = SourceInfo::outermost(span);
// Even minimal, empty coroutine has 3 states (RESERVED_VARIANTS),
// so variant_fields and variant_source_info should have 3 elements.
let variant_fields: IndexVec<VariantIdx, IndexVec<FieldIdx, CoroutineSavedLocal>> =
iter::repeat(IndexVec::new()).take(CoroutineArgs::RESERVED_VARIANTS).collect();
let variant_source_info: IndexVec<VariantIdx, SourceInfo> =
iter::repeat(source_info).take(CoroutineArgs::RESERVED_VARIANTS).collect();
let proxy_layout = CoroutineLayout {
field_tys: [].into(),
field_names: [].into(),
variant_fields,
variant_source_info: [source_info].into(),
variant_source_info,
storage_conflicts: BitMatrix::new(0, 0),
};
return Some(self.arena.alloc(proxy_layout));
Expand Down
61 changes: 47 additions & 14 deletions compiler/rustc_parse/src/validate_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,13 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) {
return;
}

let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
let attr_item = attr.get_normal_item();
let builtin_attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));

// All non-builtin attributes are considered safe
let safety = attr_info.map(|x| x.safety).unwrap_or(AttributeSafety::Normal);
check_attribute_safety(psess, safety, attr, id);
let builtin_attr_safety = builtin_attr_info.map(|x| x.safety);
check_attribute_safety(psess, builtin_attr_safety, attr, id);

// Check input tokens for built-in and key-value attributes.
match attr_info {
match builtin_attr_info {
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => {
match parse_meta(psess, attr) {
Expand All @@ -44,6 +42,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) {
}
}
_ => {
let attr_item = attr.get_normal_item();
if let AttrArgs::Eq { .. } = attr_item.args {
// All key-value attributes are restricted to meta-item syntax.
match parse_meta(psess, attr) {
Expand Down Expand Up @@ -157,14 +156,21 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte

pub fn check_attribute_safety(
psess: &ParseSess,
safety: AttributeSafety,
builtin_attr_safety: Option<AttributeSafety>,
attr: &Attribute,
id: NodeId,
) {
let attr_item = attr.get_normal_item();
match (builtin_attr_safety, attr_item.unsafety) {
// - Unsafe builtin attribute
// - User wrote `#[unsafe(..)]`, which is permitted on any edition
(Some(AttributeSafety::Unsafe { .. }), Safety::Unsafe(..)) => {
// OK
}

if let AttributeSafety::Unsafe { unsafe_since } = safety {
if let ast::Safety::Default = attr_item.unsafety {
// - Unsafe builtin attribute
// - User did not write `#[unsafe(..)]`
(Some(AttributeSafety::Unsafe { unsafe_since }), Safety::Default) => {
let path_span = attr_item.path.span;

// If the `attr_item`'s span is not from a macro, then just suggest
Expand Down Expand Up @@ -199,11 +205,38 @@ pub fn check_attribute_safety(
);
}
}
} else if let Safety::Unsafe(unsafe_span) = attr_item.unsafety {
psess.dcx().emit_err(errors::InvalidAttrUnsafe {
span: unsafe_span,
name: attr_item.path.clone(),
});

// - Normal builtin attribute, or any non-builtin attribute
// - All non-builtin attributes are currently considered safe; writing `#[unsafe(..)]` is
// not permitted on non-builtin attributes or normal builtin attributes
(Some(AttributeSafety::Normal) | None, Safety::Unsafe(unsafe_span)) => {
psess.dcx().emit_err(errors::InvalidAttrUnsafe {
span: unsafe_span,
name: attr_item.path.clone(),
});
}

// - Normal builtin attribute
// - No explicit `#[unsafe(..)]` written.
(Some(AttributeSafety::Normal), Safety::Default) => {
// OK
}

// - Non-builtin attribute
// - No explicit `#[unsafe(..)]` written.
(None, Safety::Default) => {
// OK
}

(
Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None,
Safety::Safe(..),
) => {
psess.dcx().span_delayed_bug(
attr_item.span(),
"`check_attribute_safety` does not expect `Safety::Safe` on attributes",
);
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions library/alloc/src/vec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3659,9 +3659,9 @@ impl<T, A: Allocator> Vec<T, A> {
///
/// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
/// or the iteration short-circuits, then the remaining elements will be retained.
/// Use [`retain`] with a negated predicate if you do not need the returned iterator.
/// Use [`retain_mut`] with a negated predicate if you do not need the returned iterator.
///
/// [`retain`]: Vec::retain
/// [`retain_mut`]: Vec::retain_mut
///
/// Using this method is equivalent to the following code:
///
Expand Down
1 change: 0 additions & 1 deletion library/core/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3320,7 +3320,6 @@ pub const fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
#[inline]
#[rustc_intrinsic]
#[rustc_intrinsic_const_stable_indirect]
#[rustc_allow_const_fn_unstable(const_swap_nonoverlapping)] // this is anyway not called since CTFE implements the intrinsic
pub const unsafe fn typed_swap_nonoverlapping<T>(x: *mut T, y: *mut T) {
// SAFETY: The caller provided single non-overlapping items behind
// pointers, so swapping them with `count: 1` is fine.
Expand Down
37 changes: 36 additions & 1 deletion library/core/src/ptr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1065,10 +1065,45 @@ pub const unsafe fn swap<T>(x: *mut T, y: *mut T) {
/// assert_eq!(x, [7, 8, 3, 4]);
/// assert_eq!(y, [1, 2, 9]);
/// ```
///
/// # Const evaluation limitations
///
/// If this function is invoked during const-evaluation, the current implementation has a small (and
/// rarely relevant) limitation: if `count` is at least 2 and the data pointed to by `x` or `y`
/// contains a pointer that crosses the boundary of two `T`-sized chunks of memory, the function may
/// fail to evaluate (similar to a panic during const-evaluation). This behavior may change in the
/// future.
///
/// The limitation is illustrated by the following example:
///
/// ```
/// use std::mem::size_of;
/// use std::ptr;
///
/// const { unsafe {
/// const PTR_SIZE: usize = size_of::<*const i32>();
/// let mut data1 = [0u8; PTR_SIZE];
/// let mut data2 = [0u8; PTR_SIZE];
/// // Store a pointer in `data1`.
/// data1.as_mut_ptr().cast::<*const i32>().write_unaligned(&42);
/// // Swap the contents of `data1` and `data2` by swapping `PTR_SIZE` many `u8`-sized chunks.
/// // This call will fail, because the pointer in `data1` crosses the boundary
/// // between several of the 1-byte chunks that are being swapped here.
/// //ptr::swap_nonoverlapping(data1.as_mut_ptr(), data2.as_mut_ptr(), PTR_SIZE);
/// // Swap the contents of `data1` and `data2` by swapping a single chunk of size
/// // `[u8; PTR_SIZE]`. That works, as there is no pointer crossing the boundary between
/// // two chunks.
/// ptr::swap_nonoverlapping(&mut data1, &mut data2, 1);
/// // Read the pointer from `data2` and dereference it.
/// let ptr = data2.as_ptr().cast::<*const i32>().read_unaligned();
/// assert!(*ptr == 42);
/// } }
/// ```
#[inline]
#[stable(feature = "swap_nonoverlapping", since = "1.27.0")]
#[rustc_const_unstable(feature = "const_swap_nonoverlapping", issue = "133668")]
#[rustc_const_stable(feature = "const_swap_nonoverlapping", since = "CURRENT_RUSTC_VERSION")]
#[rustc_diagnostic_item = "ptr_swap_nonoverlapping"]
#[rustc_allow_const_fn_unstable(const_eval_select)] // both implementations behave the same
pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
ub_checks::assert_unsafe_precondition!(
check_library_ub,
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 @@ -15,7 +15,6 @@
#![feature(char_max_len)]
#![feature(clone_to_uninit)]
#![feature(const_eval_select)]
#![feature(const_swap_nonoverlapping)]
#![feature(const_trait_impl)]
#![feature(core_intrinsics)]
#![feature(core_intrinsics_fallbacks)]
Expand Down
4 changes: 4 additions & 0 deletions library/coretests/tests/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -949,6 +949,10 @@ fn test_const_swap_ptr() {
// Make sure they still work.
assert!(*s1.0.ptr == 1);
assert!(*s2.0.ptr == 666);

// This is where we'd swap again using a `u8` type and a `count` of `size_of::<T>()` if it
// were not for the limitation of `swap_nonoverlapping` around pointers crossing multiple
// elements.
};
}

Expand Down
26 changes: 21 additions & 5 deletions src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,12 +170,28 @@ pub fn main() {
// NOTE: this compiles both versions of tracing unconditionally, because
// - The compile time hit is not that bad, especially compared to rustdoc's incremental times, and
// - Otherwise, there's no warning that logging is being ignored when `download-rustc` is enabled
// NOTE: The reason this doesn't show double logging when `download-rustc = false` and
// `debug_logging = true` is because all rustc logging goes to its version of tracing (the one
// in the sysroot), and all of rustdoc's logging goes to its version (the one in Cargo.toml).

init_logging(&early_dcx);
rustc_driver::init_logger(&early_dcx, rustc_log::LoggerConfig::from_env("RUSTDOC_LOG"));
crate::init_logging(&early_dcx);
match rustc_log::init_logger(rustc_log::LoggerConfig::from_env("RUSTDOC_LOG")) {
Ok(()) => {}
// With `download-rustc = true` there are definitely 2 distinct tracing crates in the
// dependency graph: one in the downloaded sysroot and one built just now as a dependency of
// rustdoc. So the sysroot's tracing is definitely not yet initialized here.
//
// But otherwise, depending on link style, there may or may not be 2 tracing crates in play.
// The one we just initialized in `crate::init_logging` above is rustdoc's direct dependency
// on tracing. When rustdoc is built by x.py using Cargo, rustc_driver's and rustc_log's
// tracing dependency is distinct from this one and also needs to be initialized (using the
// same RUSTDOC_LOG environment variable for both). Other build systems may use just a
// single tracing crate throughout the rustc and rustdoc build.
//
// The reason initializing 2 tracings does not show double logging when `download-rustc =
// false` and `debug_logging = true` is because all rustc logging goes only to its version
// of tracing (the one in the sysroot) and all of rustdoc's logging only goes to its version
// (the one in Cargo.toml).
Err(rustc_log::Error::AlreadyInit(_)) => {}
Err(error) => early_dcx.early_fatal(error.to_string()),
}

let exit_code = rustc_driver::catch_with_exit_code(|| {
let at_args = rustc_driver::args::raw_args(&early_dcx);
Expand Down
6 changes: 5 additions & 1 deletion tests/codegen/const-vector.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
//@ revisions: OPT0 OPT0_S390X
//@ [OPT0] ignore-s390x
//@ [OPT0_S390X] only-s390x
//@ [OPT0] compile-flags: -C no-prepopulate-passes -Copt-level=0
//@ [OPT0_S390X] compile-flags: -C no-prepopulate-passes -Copt-level=0 -C target-cpu=z13

// This test checks that constants of SIMD type are passed as immediate vectors.
// We ensure that both vector representations (struct with fields and struct wrapping array) work.
Expand Down
2 changes: 0 additions & 2 deletions tests/ui/consts/missing_span_in_backtrace.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
//@ compile-flags: -Z ui-testing=no


#![feature(const_swap_nonoverlapping)]
use std::{
mem::{self, MaybeUninit},
ptr,
Expand Down
12 changes: 6 additions & 6 deletions tests/ui/consts/missing_span_in_backtrace.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error[E0080]: evaluation of constant value failed
--> $DIR/missing_span_in_backtrace.rs:16:9
--> $DIR/missing_span_in_backtrace.rs:14:9
|
16 | / ptr::swap_nonoverlapping(
17 | | &mut ptr1 as *mut _ as *mut MaybeUninit<u8>,
18 | | &mut ptr2 as *mut _ as *mut MaybeUninit<u8>,
19 | | mem::size_of::<&i32>(),
20 | | );
14 | / ptr::swap_nonoverlapping(
15 | | &mut ptr1 as *mut _ as *mut MaybeUninit<u8>,
16 | | &mut ptr2 as *mut _ as *mut MaybeUninit<u8>,
17 | | mem::size_of::<&i32>(),
18 | | );
| |_________^ unable to copy parts of a pointer from memory at ALLOC0
|
note: inside `swap_nonoverlapping::<MaybeUninit<u8>>`
Expand Down
7 changes: 7 additions & 0 deletions tests/ui/rust-2024/unsafe-attributes/auxiliary/safe_attr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
extern crate proc_macro;
use proc_macro::TokenStream;

#[proc_macro_attribute]
pub fn safe(_attr: TokenStream, item: TokenStream) -> TokenStream {
item
}
22 changes: 22 additions & 0 deletions tests/ui/rust-2024/unsafe-attributes/safe-proc-macro-attribute.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//! Anti-regression test for `#[safe]` proc-macro attribute.

//@ revisions: unknown_attr proc_macro_attr
//@[proc_macro_attr] proc-macro: safe_attr.rs
//@[proc_macro_attr] check-pass

#![warn(unsafe_attr_outside_unsafe)]

#[cfg(proc_macro_attr)]
extern crate safe_attr;
#[cfg(proc_macro_attr)]
use safe_attr::safe;

#[safe]
//[unknown_attr]~^ ERROR cannot find attribute `safe` in this scope
fn foo() {}

#[safe(no_mangle)]
//[unknown_attr]~^ ERROR cannot find attribute `safe` in this scope
fn bar() {}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error: cannot find attribute `safe` in this scope
--> $DIR/safe-proc-macro-attribute.rs:18:3
|
LL | #[safe(no_mangle)]
| ^^^^

error: cannot find attribute `safe` in this scope
--> $DIR/safe-proc-macro-attribute.rs:14:3
|
LL | #[safe]
| ^^^^

error: aborting due to 2 previous errors

Loading