From 07d3e923ac68ba6daf516f4298ae6b00471696f1 Mon Sep 17 00:00:00 2001 From: ltdk Date: Wed, 3 Sep 2025 20:10:43 -0400 Subject: [PATCH 01/20] Unstably constify ptr::drop_in_place and related methods --- library/core/src/mem/manually_drop.rs | 7 +++- library/core/src/mem/maybe_uninit.rs | 13 +++++- library/core/src/ptr/mod.rs | 8 +++- library/core/src/ptr/mut_ptr.rs | 8 +++- library/core/src/ptr/non_null.rs | 8 +++- library/coretests/tests/lib.rs | 1 + library/coretests/tests/ptr.rs | 41 ++++++++++++++++++- .../drop_in_place_retag.stderr | 6 ++- .../unaligned_pointers/drop_in_place.stderr | 6 ++- 9 files changed, 84 insertions(+), 14 deletions(-) diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index 8868f05f1b98f..334a4b7119a11 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -1,3 +1,4 @@ +use crate::marker::Destruct; use crate::ops::{Deref, DerefMut, DerefPure}; use crate::ptr; @@ -249,7 +250,11 @@ impl ManuallyDrop { /// [pinned]: crate::pin #[stable(feature = "manually_drop", since = "1.20.0")] #[inline] - pub unsafe fn drop(slot: &mut ManuallyDrop) { + #[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")] + pub const unsafe fn drop(slot: &mut ManuallyDrop) + where + T: [const] Destruct, + { // SAFETY: we are dropping the value pointed to by a mutable reference // which is guaranteed to be valid for writes. // It is up to the caller to make sure that `slot` isn't dropped again. diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index c160360cfacf9..8d666e9b130c0 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -1,4 +1,5 @@ use crate::any::type_name; +use crate::marker::Destruct; use crate::mem::ManuallyDrop; use crate::{fmt, intrinsics, ptr, slice}; @@ -714,7 +715,11 @@ impl MaybeUninit { /// /// [`assume_init`]: MaybeUninit::assume_init #[stable(feature = "maybe_uninit_extra", since = "1.60.0")] - pub unsafe fn assume_init_drop(&mut self) { + #[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")] + pub const unsafe fn assume_init_drop(&mut self) + where + T: [const] Destruct, + { // SAFETY: the caller must guarantee that `self` is initialized and // satisfies all invariants of `T`. // Dropping the value in place is safe if that is the case. @@ -1390,7 +1395,11 @@ impl [MaybeUninit] { /// behaviour. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] - pub unsafe fn assume_init_drop(&mut self) { + #[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")] + pub const unsafe fn assume_init_drop(&mut self) + where + T: [const] Destruct, + { if !self.is_empty() { // SAFETY: the caller must guarantee that every element of `self` // is initialized and satisfies all invariants of `T`. diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 6b94088cb5679..8c20b5e58b8f2 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -403,7 +403,7 @@ use crate::cmp::Ordering; use crate::intrinsics::const_eval_select; -use crate::marker::{FnPtr, PointeeSized}; +use crate::marker::{Destruct, FnPtr, PointeeSized}; use crate::mem::{self, MaybeUninit, SizedTypeProperties}; use crate::num::NonZero; use crate::{fmt, hash, intrinsics, ub_checks}; @@ -801,7 +801,11 @@ pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { #[lang = "drop_in_place"] #[allow(unconditional_recursion)] #[rustc_diagnostic_item = "ptr_drop_in_place"] -pub unsafe fn drop_in_place(to_drop: *mut T) { +#[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")] +pub const unsafe fn drop_in_place(to_drop: *mut T) +where + T: [const] Destruct, +{ // Code here does not matter - this is replaced by the // real drop glue by the compiler. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index ce6eee4f911ed..1e3bc2939320d 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1,7 +1,7 @@ use super::*; use crate::cmp::Ordering::{Equal, Greater, Less}; use crate::intrinsics::const_eval_select; -use crate::marker::PointeeSized; +use crate::marker::{Destruct, PointeeSized}; use crate::mem::{self, SizedTypeProperties}; use crate::slice::{self, SliceIndex}; @@ -1438,8 +1438,12 @@ impl *mut T { /// /// [`ptr::drop_in_place`]: crate::ptr::drop_in_place() #[stable(feature = "pointer_methods", since = "1.26.0")] + #[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")] #[inline(always)] - pub unsafe fn drop_in_place(self) { + pub const unsafe fn drop_in_place(self) + where + T: [const] Destruct, + { // SAFETY: the caller must uphold the safety contract for `drop_in_place`. unsafe { drop_in_place(self) } } diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 10f83120428b9..a762e969b52dc 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1,5 +1,5 @@ use crate::cmp::Ordering; -use crate::marker::{PointeeSized, Unsize}; +use crate::marker::{Destruct, PointeeSized, Unsize}; use crate::mem::{MaybeUninit, SizedTypeProperties}; use crate::num::NonZero; use crate::ops::{CoerceUnsized, DispatchFromDyn}; @@ -1118,7 +1118,11 @@ impl NonNull { /// [`ptr::drop_in_place`]: crate::ptr::drop_in_place() #[inline(always)] #[stable(feature = "non_null_convenience", since = "1.80.0")] - pub unsafe fn drop_in_place(self) { + #[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")] + pub const unsafe fn drop_in_place(self) + where + T: [const] Destruct, + { // SAFETY: the caller must uphold the safety contract for `drop_in_place`. unsafe { ptr::drop_in_place(self.as_ptr()) } } diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index b5658a9970fee..c8b940cf3728b 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -17,6 +17,7 @@ #![feature(clone_to_uninit)] #![feature(const_convert)] #![feature(const_destruct)] +#![feature(const_drop_in_place)] #![feature(const_eval_select)] #![feature(const_ops)] #![feature(const_option_ops)] diff --git a/library/coretests/tests/ptr.rs b/library/coretests/tests/ptr.rs index c13fb96a67f92..217e370ee8974 100644 --- a/library/coretests/tests/ptr.rs +++ b/library/coretests/tests/ptr.rs @@ -1,6 +1,6 @@ use core::cell::RefCell; use core::marker::Freeze; -use core::mem::MaybeUninit; +use core::mem::{ManuallyDrop, MaybeUninit}; use core::num::NonZero; use core::ptr; use core::ptr::*; @@ -1036,3 +1036,42 @@ fn test_ptr_default() { let default = PtrMutDefaultTest::default(); assert!(default.ptr.is_null()); } + +#[test] +fn test_const_drop_in_place() { + const COUNTER: usize = { + let mut counter = 0; + let counter_ptr = &raw mut counter; + + // only exists to make `Drop` indirect impl + #[allow(dead_code)] + struct Test(Dropped); + + struct Dropped(*mut usize); + impl const Drop for Dropped { + fn drop(&mut self) { + unsafe { + *self.0 += 1; + } + } + } + + let mut one = ManuallyDrop::new(Test(Dropped(counter_ptr))); + let mut two = ManuallyDrop::new(Test(Dropped(counter_ptr))); + let mut three = ManuallyDrop::new(Test(Dropped(counter_ptr))); + assert!(counter == 0); + unsafe { + ManuallyDrop::drop(&mut one); + } + assert!(counter == 1); + unsafe { + ManuallyDrop::drop(&mut two); + } + assert!(counter == 2); + unsafe { + ManuallyDrop::drop(&mut three); + } + counter + }; + assert_eq!(COUNTER, 3); +} diff --git a/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr index ec578db2d0a8e..e586d3f03994f 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr +++ b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr @@ -1,8 +1,10 @@ error: Undefined Behavior: trying to retag from for Unique permission at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location --> RUSTLIB/core/src/ptr/mod.rs:LL:CC | -LL | pub unsafe fn drop_in_place(to_drop: *mut T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this error occurs as part of retag at ALLOC[0x0..0x1] +LL | / pub const unsafe fn drop_in_place(to_drop: *mut T) +LL | | where +LL | | T: [const] Destruct, + | |________________________^ this error occurs as part of retag at ALLOC[0x0..0x1] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr index 72aeb0fdf8e49..ea144f206643a 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr @@ -1,8 +1,10 @@ error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) --> RUSTLIB/core/src/ptr/mod.rs:LL:CC | -LL | pub unsafe fn drop_in_place(to_drop: *mut T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here +LL | / pub const unsafe fn drop_in_place(to_drop: *mut T) +LL | | where +LL | | T: [const] Destruct, + | |________________________^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From f47c48048d6ba9d96dd4138803595284443d7708 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 9 Oct 2025 12:35:14 +0000 Subject: [PATCH 02/20] Reduce scope of unsafe block in cg_llvm allocator codegen --- compiler/rustc_codegen_llvm/src/allocator.rs | 42 ++++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 824aa501036d4..486ee817a1c79 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -95,28 +95,28 @@ pub(crate) unsafe fn codegen( &CodegenFnAttrs::new(), ); - unsafe { - // __rust_alloc_error_handler_should_panic_v2 - create_const_value_function( - tcx, - &cx, - &mangle_internal_symbol(tcx, OomStrategy::SYMBOL), - &i8, - &llvm::LLVMConstInt(i8, tcx.sess.opts.unstable_opts.oom.should_panic() as u64, FALSE), - ); + // __rust_alloc_error_handler_should_panic_v2 + create_const_value_function( + tcx, + &cx, + &mangle_internal_symbol(tcx, OomStrategy::SYMBOL), + &i8, + unsafe { + llvm::LLVMConstInt(i8, tcx.sess.opts.unstable_opts.oom.should_panic() as u64, FALSE) + }, + ); - // __rust_no_alloc_shim_is_unstable_v2 - create_wrapper_function( - tcx, - &cx, - &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), - None, - &[], - None, - false, - &CodegenFnAttrs::new(), - ); - } + // __rust_no_alloc_shim_is_unstable_v2 + create_wrapper_function( + tcx, + &cx, + &mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), + None, + &[], + None, + false, + &CodegenFnAttrs::new(), + ); if tcx.sess.opts.debuginfo != DebugInfo::None { let dbg_cx = debuginfo::CodegenUnitDebugContext::new(cx.llmod); From 116f4ae171e292423304ee6842a11c48a4fff5ba Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Jun 2025 13:44:01 +0000 Subject: [PATCH 03/20] Support #[alloc_error_handler] without the allocator shim Currently it is possible to avoid linking the allocator shim when __rust_no_alloc_shim_is_unstable_v2 is defined when linking rlibs directly as some build systems need. However this requires liballoc to be compiled with --cfg no_global_oom_handling, which places huge restrictions on what functions you can call and makes it impossible to use libstd. Or alternatively you have to define __rust_alloc_error_handler and (when using libstd) __rust_alloc_error_handler_should_panic using #[rustc_std_internal_symbol]. With this commit you can either use libstd and define __rust_alloc_error_handler_should_panic or not use libstd and use #[alloc_error_handler] instead. Both options are still unstable though. Eventually the alloc_error_handler may either be removed entirely (though the PR for that has been stale for years now) or we may start using weak symbols for it instead. For the latter case this commit is a prerequisite anyway. --- compiler/rustc_ast/src/expand/allocator.rs | 8 +----- .../src/alloc_error_handler.rs | 5 ++-- .../rustc_codegen_cranelift/src/allocator.rs | 28 ++++++++++--------- compiler/rustc_codegen_gcc/src/allocator.rs | 24 ++++++++-------- compiler/rustc_codegen_llvm/src/allocator.rs | 28 ++++++++++--------- .../src/back/symbol_export.rs | 6 ++-- compiler/rustc_metadata/src/creader.rs | 24 ++++++++-------- library/alloc/src/alloc.rs | 4 +-- library/std/src/alloc.rs | 7 +++-- src/tools/miri/src/shims/foreign_items.rs | 17 ++++++----- .../fail/alloc/alloc_error_handler.stderr | 2 +- .../alloc/alloc_error_handler_custom.stderr | 2 +- .../alloc/alloc_error_handler_no_std.stderr | 2 +- tests/run-make/bin-emit-no-symbols/rmake.rs | 2 +- tests/ui/sanitizer/dataflow-abilist.txt | 10 ------- 15 files changed, 83 insertions(+), 86 deletions(-) diff --git a/compiler/rustc_ast/src/expand/allocator.rs b/compiler/rustc_ast/src/expand/allocator.rs index 7dee2ed17b4be..a3f9ddb154f71 100644 --- a/compiler/rustc_ast/src/expand/allocator.rs +++ b/compiler/rustc_ast/src/expand/allocator.rs @@ -15,13 +15,7 @@ pub fn default_fn_name(base: Symbol) -> String { format!("__rdl_{base}") } -pub fn alloc_error_handler_name(alloc_error_handler_kind: AllocatorKind) -> &'static str { - match alloc_error_handler_kind { - AllocatorKind::Global => "__rg_oom", - AllocatorKind::Default => "__rdl_oom", - } -} - +pub const ALLOC_ERROR_HANDLER: Symbol = sym::alloc_error_handler; pub const NO_ALLOC_SHIM_IS_UNSTABLE: &str = "__rust_no_alloc_shim_is_unstable_v2"; pub enum AllocatorTy { diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index 35ef6be095e9c..40946f3b2791a 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -1,3 +1,4 @@ +use rustc_ast::expand::allocator::{ALLOC_ERROR_HANDLER, global_fn_name}; use rustc_ast::{ self as ast, Fn, FnHeader, FnSig, Generics, ItemKind, Safety, Stmt, StmtKind, TyKind, }; @@ -55,7 +56,7 @@ pub(crate) fn expand( } // #[rustc_std_internal_symbol] -// unsafe fn __rg_oom(size: usize, align: usize) -> ! { +// unsafe fn __rust_alloc_error_handler(size: usize, align: usize) -> ! { // handler(core::alloc::Layout::from_size_align_unchecked(size, align)) // } fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span) -> Stmt { @@ -84,7 +85,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span let kind = ItemKind::Fn(Box::new(Fn { defaultness: ast::Defaultness::Final, sig, - ident: Ident::from_str_and_span("__rg_oom", span), + ident: Ident::from_str_and_span(&global_fn_name(ALLOC_ERROR_HANDLER), span), generics: Generics::default(), contract: None, body, diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index 04f1129d87c1f..9533f870434ab 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -3,8 +3,8 @@ use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use rustc_ast::expand::allocator::{ - ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, - alloc_error_handler_name, default_fn_name, global_fn_name, + ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, + default_fn_name, global_fn_name, }; use rustc_codegen_ssa::base::allocator_kind_for_codegen; use rustc_session::config::OomStrategy; @@ -72,17 +72,19 @@ fn codegen_inner( } } - let sig = Signature { - call_conv: module.target_config().default_call_conv, - params: vec![AbiParam::new(usize_ty), AbiParam::new(usize_ty)], - returns: vec![], - }; - crate::common::create_wrapper_function( - module, - sig, - &mangle_internal_symbol(tcx, "__rust_alloc_error_handler"), - &mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind)), - ); + if alloc_error_handler_kind == AllocatorKind::Default { + let sig = Signature { + call_conv: module.target_config().default_call_conv, + params: vec![AbiParam::new(usize_ty), AbiParam::new(usize_ty)], + returns: vec![], + }; + crate::common::create_wrapper_function( + module, + sig, + &mangle_internal_symbol(tcx, &global_fn_name(ALLOC_ERROR_HANDLER)), + &mangle_internal_symbol(tcx, &default_fn_name(ALLOC_ERROR_HANDLER)), + ); + } { let sig = Signature { diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs index 2a95a7368aac6..3f99612fcdb02 100644 --- a/compiler/rustc_codegen_gcc/src/allocator.rs +++ b/compiler/rustc_codegen_gcc/src/allocator.rs @@ -2,8 +2,8 @@ use gccjit::FnAttribute; use gccjit::{Context, FunctionType, RValue, ToRValue, Type}; use rustc_ast::expand::allocator::{ - ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, - alloc_error_handler_name, default_fn_name, global_fn_name, + ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, + default_fn_name, global_fn_name, }; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; @@ -61,15 +61,17 @@ pub(crate) unsafe fn codegen( } } - // FIXME(bjorn3): Add noreturn attribute - create_wrapper_function( - tcx, - context, - &mangle_internal_symbol(tcx, "__rust_alloc_error_handler"), - Some(&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind))), - &[usize, usize], - None, - ); + if alloc_error_handler_kind == AllocatorKind::Default { + // FIXME(bjorn3): Add noreturn attribute + create_wrapper_function( + tcx, + context, + &mangle_internal_symbol(tcx, &global_fn_name(ALLOC_ERROR_HANDLER)), + Some(&mangle_internal_symbol(tcx, &default_fn_name(ALLOC_ERROR_HANDLER))), + &[usize, usize], + None, + ); + } create_const_value_function( tcx, diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 486ee817a1c79..b645db3f4a8b8 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -1,7 +1,7 @@ use libc::c_uint; use rustc_ast::expand::allocator::{ - ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, - alloc_error_handler_name, default_fn_name, global_fn_name, + ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, + default_fn_name, global_fn_name, }; use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _; use rustc_middle::bug; @@ -83,17 +83,19 @@ pub(crate) unsafe fn codegen( } } - // rust alloc error handler - create_wrapper_function( - tcx, - &cx, - &mangle_internal_symbol(tcx, "__rust_alloc_error_handler"), - Some(&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind))), - &[usize, usize], // size, align - None, - true, - &CodegenFnAttrs::new(), - ); + if alloc_error_handler_kind == AllocatorKind::Default { + // rust alloc error handler + create_wrapper_function( + tcx, + &cx, + &mangle_internal_symbol(tcx, &global_fn_name(ALLOC_ERROR_HANDLER)), + Some(&mangle_internal_symbol(tcx, &default_fn_name(ALLOC_ERROR_HANDLER))), + &[usize, usize], // size, align + None, + true, + &CodegenFnAttrs::new(), + ); + } // __rust_alloc_error_handler_should_panic_v2 create_const_value_function( diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index b49e67217fb01..5bc18e2d7f8bb 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -1,7 +1,9 @@ use std::collections::hash_map::Entry::*; use rustc_abi::{CanonAbi, X86Call}; -use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE, global_fn_name}; +use rustc_ast::expand::allocator::{ + ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE, global_fn_name, +}; use rustc_data_structures::unord::UnordMap; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE, LocalDefId}; @@ -498,7 +500,7 @@ pub(crate) fn allocator_shim_symbols( .iter() .map(move |method| mangle_internal_symbol(tcx, global_fn_name(method.name).as_str())) .chain([ - mangle_internal_symbol(tcx, "__rust_alloc_error_handler"), + mangle_internal_symbol(tcx, global_fn_name(ALLOC_ERROR_HANDLER).as_str()), mangle_internal_symbol(tcx, OomStrategy::SYMBOL), mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE), ]) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 7650acbd292d2..87d64817466d9 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -6,7 +6,7 @@ use std::str::FromStr; use std::time::Duration; use std::{cmp, env, iter}; -use rustc_ast::expand::allocator::{AllocatorKind, alloc_error_handler_name, global_fn_name}; +use rustc_ast::expand::allocator::{ALLOC_ERROR_HANDLER, AllocatorKind, global_fn_name}; use rustc_ast::{self as ast, *}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::owned_slice::OwnedSlice; @@ -1087,17 +1087,17 @@ impl CStore { } spans => !spans.is_empty(), }; - self.has_alloc_error_handler = match &*fn_spans( - krate, - Symbol::intern(alloc_error_handler_name(AllocatorKind::Global)), - ) { - [span1, span2, ..] => { - tcx.dcx() - .emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 }); - true - } - spans => !spans.is_empty(), - }; + self.has_alloc_error_handler = + match &*fn_spans(krate, Symbol::intern(&global_fn_name(ALLOC_ERROR_HANDLER))) { + [span1, span2, ..] => { + tcx.dcx().emit_err(errors::NoMultipleAllocErrorHandler { + span2: *span2, + span1: *span1, + }); + true + } + spans => !spans.is_empty(), + }; // Check to see if we actually need an allocator. This desire comes // about through the `#![needs_allocator]` attribute and is typically diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 65c8206e9d462..39450f69ce30a 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -361,7 +361,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { unsafe extern "Rust" { // This is the magic symbol to call the global alloc error handler. rustc generates // it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the - // default implementations below (`__rdl_oom`) otherwise. + // default implementations below (`__rdl_alloc_error_handler`) otherwise. #[rustc_std_internal_symbol] fn __rust_alloc_error_handler(size: usize, align: usize) -> !; } @@ -425,7 +425,7 @@ pub mod __alloc_error_handler { // called via generated `__rust_alloc_error_handler` if there is no // `#[alloc_error_handler]`. #[rustc_std_internal_symbol] - pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! { + pub unsafe fn __rdl_alloc_error_handler(size: usize, _align: usize) -> ! { unsafe extern "Rust" { // This symbol is emitted by rustc next to __rust_alloc_error_handler. // Its value depends on the -Zoom={panic,abort} compiler option. diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index 1d61630269ac3..daa25c5a50dd6 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -358,9 +358,10 @@ fn default_alloc_error_hook(layout: Layout) { // This is the default path taken on OOM, and the only path taken on stable with std. // Crucially, it does *not* call any user-defined code, and therefore users do not have to // worry about allocation failure causing reentrancy issues. That makes it different from - // the default `__rdl_oom` defined in alloc (i.e., the default alloc error handler that is - // called when there is no `#[alloc_error_handler]`), which triggers a regular panic and - // thus can invoke a user-defined panic hook, executing arbitrary user-defined code. + // the default `__rdl_alloc_error_handler` defined in alloc (i.e., the default alloc error + // handler that is called when there is no `#[alloc_error_handler]`), which triggers a + // regular panic and thus can invoke a user-defined panic hook, executing arbitrary + // user-defined code. rtprintpanic!("memory allocation of {} bytes failed\n", layout.size()); } } diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index eca8cccf5efc4..467ac2805fe5e 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -3,7 +3,7 @@ use std::io::Write; use std::path::Path; use rustc_abi::{Align, AlignFromBytesError, CanonAbi, Size}; -use rustc_ast::expand::allocator::alloc_error_handler_name; +use rustc_ast::expand::allocator::AllocatorKind; use rustc_hir::attrs::Linkage; use rustc_hir::def::DefKind; use rustc_hir::def_id::CrateNum; @@ -51,6 +51,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Some shims forward to other MIR bodies. match link_name.as_str() { + // FIXME should use global_fn_name, but mangle_internal_symbol requires a static str. name if name == this.mangle_internal_symbol("__rust_alloc_error_handler") => { // Forward to the right symbol that implements this function. let Some(handler_kind) = this.tcx.alloc_error_handler_kind(()) else { @@ -59,12 +60,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "`__rust_alloc_error_handler` cannot be called when no alloc error handler is set" ); }; - let name = Symbol::intern( - this.mangle_internal_symbol(alloc_error_handler_name(handler_kind)), - ); - let handler = - this.lookup_exported_symbol(name)?.expect("missing alloc error handler symbol"); - return interp_ok(Some(handler)); + if handler_kind == AllocatorKind::Default { + let name = + Symbol::intern(this.mangle_internal_symbol("__rdl_alloc_error_handler")); + let handler = this + .lookup_exported_symbol(name)? + .expect("missing alloc error handler symbol"); + return interp_ok(Some(handler)); + } } _ => {} } diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr index bbf5d14a98a1e..7f7fc63ac0ddd 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr @@ -7,7 +7,7 @@ LL | crate::process::abort() | = note: BACKTRACE: = note: inside `std::alloc::rust_oom` at RUSTLIB/std/src/alloc.rs:LL:CC - = note: inside `std::alloc::_::__rg_oom` at RUSTLIB/std/src/alloc.rs:LL:CC + = note: inside `std::alloc::_::__rust_alloc_error_handler` at RUSTLIB/std/src/alloc.rs:LL:CC = note: inside `std::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `std::alloc::handle_alloc_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr index a2a4be30eca4a..f8a96758aa2d3 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr @@ -7,7 +7,7 @@ LL | core::intrinsics::abort(); | = note: BACKTRACE: = note: inside `alloc_error_handler` at tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC -note: inside `_::__rg_oom` +note: inside `_::__rust_alloc_error_handler` --> tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC | LL | #[alloc_error_handler] diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr index 45ba366acae32..488b1d879e874 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr @@ -9,7 +9,7 @@ LL | core::intrinsics::abort(); | = note: BACKTRACE: = note: inside `panic_handler` at tests/fail/alloc/alloc_error_handler_no_std.rs:LL:CC - = note: inside `alloc::alloc::__alloc_error_handler::__rdl_oom` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `alloc::alloc::__alloc_error_handler::__rdl_alloc_error_handler` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `alloc::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `alloc::alloc::handle_alloc_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `miri_start` diff --git a/tests/run-make/bin-emit-no-symbols/rmake.rs b/tests/run-make/bin-emit-no-symbols/rmake.rs index 2faeb20025bb7..0822bd6dfd6a8 100644 --- a/tests/run-make/bin-emit-no-symbols/rmake.rs +++ b/tests/run-make/bin-emit-no-symbols/rmake.rs @@ -14,5 +14,5 @@ fn main() { let out = llvm_readobj().input("app.o").arg("--symbols").run(); out.assert_stdout_contains("rust_begin_unwind"); out.assert_stdout_contains("rust_eh_personality"); - out.assert_stdout_contains("__rg_oom"); + out.assert_stdout_contains("__rust_alloc_error_handler"); } diff --git a/tests/ui/sanitizer/dataflow-abilist.txt b/tests/ui/sanitizer/dataflow-abilist.txt index 3d32397a175d4..b6fdfe3cbf6e7 100644 --- a/tests/ui/sanitizer/dataflow-abilist.txt +++ b/tests/ui/sanitizer/dataflow-abilist.txt @@ -490,16 +490,6 @@ fun:__dfso_*=uninstrumented fun:__dfso_*=discard # Rust functions. -fun:__rdl_alloc=uninstrumented -fun:__rdl_alloc_zeroed=uninstrumented -fun:__rdl_dealloc=uninstrumented -fun:__rdl_realloc=uninstrumented -fun:__rg_oom=uninstrumented -fun:__rust_alloc=uninstrumented -fun:__rust_alloc_error_handler=uninstrumented -fun:__rust_alloc_zeroed=uninstrumented -fun:__rust_dealloc=uninstrumented -fun:__rust_realloc=uninstrumented fun:_ZN4core*=uninstrumented fun:_ZN3std*=uninstrumented fun:rust_eh_personality=uninstrumented From 7e467cd132d0546c26be02d160ca097e00e67522 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 9 Oct 2025 14:08:55 +0000 Subject: [PATCH 04/20] Move computation of allocator shim contents to cg_ssa In the future this should make it easier to use weak symbols for the allocator shim on platforms that properly support weak symbols. And it would allow reusing the allocator shim code for handling default implementations of the upcoming externally implementable items feature on platforms that don't properly support weak symbols. --- compiler/rustc_ast/src/expand/allocator.rs | 3 + .../src/global_allocator.rs | 4 +- .../rustc_codegen_cranelift/src/allocator.rs | 79 +++++-------- compiler/rustc_codegen_gcc/src/allocator.rs | 64 +++++------ compiler/rustc_codegen_gcc/src/lib.rs | 7 +- compiler/rustc_codegen_llvm/src/allocator.rs | 104 ++++++++---------- compiler/rustc_codegen_llvm/src/lib.rs | 7 +- compiler/rustc_codegen_ssa/src/base.rs | 34 ++++-- .../rustc_codegen_ssa/src/traits/backend.rs | 5 +- 9 files changed, 139 insertions(+), 168 deletions(-) diff --git a/compiler/rustc_ast/src/expand/allocator.rs b/compiler/rustc_ast/src/expand/allocator.rs index a3f9ddb154f71..6392cb77413dd 100644 --- a/compiler/rustc_ast/src/expand/allocator.rs +++ b/compiler/rustc_ast/src/expand/allocator.rs @@ -18,14 +18,17 @@ pub fn default_fn_name(base: Symbol) -> String { pub const ALLOC_ERROR_HANDLER: Symbol = sym::alloc_error_handler; pub const NO_ALLOC_SHIM_IS_UNSTABLE: &str = "__rust_no_alloc_shim_is_unstable_v2"; +#[derive(Copy, Clone)] pub enum AllocatorTy { Layout, + Never, Ptr, ResultPtr, Unit, Usize, } +#[derive(Copy, Clone)] pub struct AllocatorMethod { pub name: Symbol, pub inputs: &'static [AllocatorMethodInput], diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 96bece2a368cd..c968353504e15 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -151,7 +151,7 @@ impl AllocFnFactory<'_, '_> { self.cx.expr_ident(self.span, ident) } - AllocatorTy::ResultPtr | AllocatorTy::Unit => { + AllocatorTy::Never | AllocatorTy::ResultPtr | AllocatorTy::Unit => { panic!("can't convert AllocatorTy to an argument") } } @@ -163,7 +163,7 @@ impl AllocFnFactory<'_, '_> { AllocatorTy::Unit => self.cx.ty(self.span, TyKind::Tup(ThinVec::new())), - AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { + AllocatorTy::Layout | AllocatorTy::Never | AllocatorTy::Usize | AllocatorTy::Ptr => { panic!("can't convert `AllocatorTy` to an output") } } diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index 9533f870434ab..67b89114356b5 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -3,10 +3,9 @@ use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use rustc_ast::expand::allocator::{ - ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, - default_fn_name, global_fn_name, + AllocatorMethod, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, default_fn_name, global_fn_name, }; -use rustc_codegen_ssa::base::allocator_kind_for_codegen; +use rustc_codegen_ssa::base::{allocator_kind_for_codegen, allocator_shim_contents}; use rustc_session::config::OomStrategy; use rustc_symbol_mangling::mangle_internal_symbol; @@ -15,74 +14,54 @@ use crate::prelude::*; /// Returns whether an allocator shim was created pub(crate) fn codegen(tcx: TyCtxt<'_>, module: &mut dyn Module) -> bool { let Some(kind) = allocator_kind_for_codegen(tcx) else { return false }; - codegen_inner( - tcx, - module, - kind, - tcx.alloc_error_handler_kind(()).unwrap(), - tcx.sess.opts.unstable_opts.oom, - ); + let methods = allocator_shim_contents(tcx, kind); + codegen_inner(tcx, module, &methods, tcx.sess.opts.unstable_opts.oom); true } fn codegen_inner( tcx: TyCtxt<'_>, module: &mut dyn Module, - kind: AllocatorKind, - alloc_error_handler_kind: AllocatorKind, + methods: &[AllocatorMethod], oom_strategy: OomStrategy, ) { let usize_ty = module.target_config().pointer_type(); - if kind == AllocatorKind::Default { - for method in ALLOCATOR_METHODS { - let mut arg_tys = Vec::with_capacity(method.inputs.len()); - for input in method.inputs.iter() { - match input.ty { - AllocatorTy::Layout => { - arg_tys.push(usize_ty); // size - arg_tys.push(usize_ty); // align - } - AllocatorTy::Ptr => arg_tys.push(usize_ty), - AllocatorTy::Usize => arg_tys.push(usize_ty), - - AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"), + for method in methods { + let mut arg_tys = Vec::with_capacity(method.inputs.len()); + for input in method.inputs.iter() { + match input.ty { + AllocatorTy::Layout => { + arg_tys.push(usize_ty); // size + arg_tys.push(usize_ty); // align } - } - let output = match method.output { - AllocatorTy::ResultPtr => Some(usize_ty), - AllocatorTy::Unit => None, + AllocatorTy::Ptr => arg_tys.push(usize_ty), + AllocatorTy::Usize => arg_tys.push(usize_ty), - AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { - panic!("invalid allocator output") + AllocatorTy::Never | AllocatorTy::ResultPtr | AllocatorTy::Unit => { + panic!("invalid allocator arg") } - }; - - let sig = Signature { - call_conv: module.target_config().default_call_conv, - params: arg_tys.iter().cloned().map(AbiParam::new).collect(), - returns: output.into_iter().map(AbiParam::new).collect(), - }; - crate::common::create_wrapper_function( - module, - sig, - &mangle_internal_symbol(tcx, &global_fn_name(method.name)), - &mangle_internal_symbol(tcx, &default_fn_name(method.name)), - ); + } } - } + let output = match method.output { + AllocatorTy::ResultPtr => Some(usize_ty), + AllocatorTy::Never | AllocatorTy::Unit => None, + + AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { + panic!("invalid allocator output") + } + }; - if alloc_error_handler_kind == AllocatorKind::Default { let sig = Signature { call_conv: module.target_config().default_call_conv, - params: vec![AbiParam::new(usize_ty), AbiParam::new(usize_ty)], - returns: vec![], + params: arg_tys.iter().cloned().map(AbiParam::new).collect(), + returns: output.into_iter().map(AbiParam::new).collect(), }; crate::common::create_wrapper_function( module, sig, - &mangle_internal_symbol(tcx, &global_fn_name(ALLOC_ERROR_HANDLER)), - &mangle_internal_symbol(tcx, &default_fn_name(ALLOC_ERROR_HANDLER)), + &mangle_internal_symbol(tcx, &global_fn_name(method.name)), + &mangle_internal_symbol(tcx, &default_fn_name(method.name)), ); } diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs index 3f99612fcdb02..647569694b04d 100644 --- a/compiler/rustc_codegen_gcc/src/allocator.rs +++ b/compiler/rustc_codegen_gcc/src/allocator.rs @@ -2,8 +2,7 @@ use gccjit::FnAttribute; use gccjit::{Context, FunctionType, RValue, ToRValue, Type}; use rustc_ast::expand::allocator::{ - ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, - default_fn_name, global_fn_name, + AllocatorMethod, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, default_fn_name, global_fn_name, }; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; @@ -18,8 +17,7 @@ pub(crate) unsafe fn codegen( tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, - kind: AllocatorKind, - alloc_error_handler_kind: AllocatorKind, + methods: &[AllocatorMethod], ) { let context = &mods.context; let usize = match tcx.sess.target.pointer_width { @@ -31,46 +29,34 @@ pub(crate) unsafe fn codegen( let i8 = context.new_type::(); let i8p = i8.make_pointer(); - if kind == AllocatorKind::Default { - for method in ALLOCATOR_METHODS { - let mut types = Vec::with_capacity(method.inputs.len()); - for input in method.inputs.iter() { - match input.ty { - AllocatorTy::Layout => { - types.push(usize); - types.push(usize); - } - AllocatorTy::Ptr => types.push(i8p), - AllocatorTy::Usize => types.push(usize), - - AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"), + for method in methods { + let mut types = Vec::with_capacity(method.inputs.len()); + for input in method.inputs.iter() { + match input.ty { + AllocatorTy::Layout => { + types.push(usize); + types.push(usize); } - } - let output = match method.output { - AllocatorTy::ResultPtr => Some(i8p), - AllocatorTy::Unit => None, + AllocatorTy::Ptr => types.push(i8p), + AllocatorTy::Usize => types.push(usize), - AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { - panic!("invalid allocator output") + AllocatorTy::Never | AllocatorTy::ResultPtr | AllocatorTy::Unit => { + panic!("invalid allocator arg") } - }; - let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name)); - let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name)); - - create_wrapper_function(tcx, context, &from_name, Some(&to_name), &types, output); + } } - } + let output = match method.output { + AllocatorTy::ResultPtr => Some(i8p), + AllocatorTy::Never | AllocatorTy::Unit => None, - if alloc_error_handler_kind == AllocatorKind::Default { - // FIXME(bjorn3): Add noreturn attribute - create_wrapper_function( - tcx, - context, - &mangle_internal_symbol(tcx, &global_fn_name(ALLOC_ERROR_HANDLER)), - Some(&mangle_internal_symbol(tcx, &default_fn_name(ALLOC_ERROR_HANDLER))), - &[usize, usize], - None, - ); + AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { + panic!("invalid allocator output") + } + }; + let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name)); + let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name)); + + create_wrapper_function(tcx, context, &from_name, Some(&to_name), &types, output); } create_const_value_function( diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index ec7eab8489ab8..c85ed0ebb3390 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -92,7 +92,7 @@ use back::lto::{ThinBuffer, ThinData}; use gccjit::{CType, Context, OptimizationLevel}; #[cfg(feature = "master")] use gccjit::{TargetInfo, Version}; -use rustc_ast::expand::allocator::AllocatorKind; +use rustc_ast::expand::allocator::AllocatorMethod; use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule}; use rustc_codegen_ssa::back::write::{ CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn, @@ -284,8 +284,7 @@ impl ExtraBackendMethods for GccCodegenBackend { &self, tcx: TyCtxt<'_>, module_name: &str, - kind: AllocatorKind, - alloc_error_handler_kind: AllocatorKind, + methods: &[AllocatorMethod], ) -> Self::Module { let mut mods = GccContext { context: Arc::new(SyncContext::new(new_context(tcx))), @@ -295,7 +294,7 @@ impl ExtraBackendMethods for GccCodegenBackend { }; unsafe { - allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); + allocator::codegen(tcx, &mut mods, module_name, methods); } mods } diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index b645db3f4a8b8..a7e83f65151ae 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -1,7 +1,6 @@ use libc::c_uint; use rustc_ast::expand::allocator::{ - ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, - default_fn_name, global_fn_name, + AllocatorMethod, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, default_fn_name, global_fn_name, }; use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _; use rustc_middle::bug; @@ -21,8 +20,7 @@ pub(crate) unsafe fn codegen( tcx: TyCtxt<'_>, cx: SimpleCx<'_>, module_name: &str, - kind: AllocatorKind, - alloc_error_handler_kind: AllocatorKind, + methods: &[AllocatorMethod], ) { let usize = match tcx.sess.target.pointer_width { 16 => cx.type_i16(), @@ -33,67 +31,59 @@ pub(crate) unsafe fn codegen( let i8 = cx.type_i8(); let i8p = cx.type_ptr(); - if kind == AllocatorKind::Default { - for method in ALLOCATOR_METHODS { - let mut args = Vec::with_capacity(method.inputs.len()); - for input in method.inputs.iter() { - match input.ty { - AllocatorTy::Layout => { - args.push(usize); // size - args.push(usize); // align - } - AllocatorTy::Ptr => args.push(i8p), - AllocatorTy::Usize => args.push(usize), - - AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"), + for method in methods { + let mut args = Vec::with_capacity(method.inputs.len()); + for input in method.inputs.iter() { + match input.ty { + AllocatorTy::Layout => { + args.push(usize); // size + args.push(usize); // align } - } - let output = match method.output { - AllocatorTy::ResultPtr => Some(i8p), - AllocatorTy::Unit => None, + AllocatorTy::Ptr => args.push(i8p), + AllocatorTy::Usize => args.push(usize), - AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { - panic!("invalid allocator output") + AllocatorTy::Never | AllocatorTy::ResultPtr | AllocatorTy::Unit => { + panic!("invalid allocator arg") } - }; - - let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name)); - let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name)); - - let alloc_attr_flag = match method.name { - sym::alloc => CodegenFnAttrFlags::ALLOCATOR, - sym::dealloc => CodegenFnAttrFlags::DEALLOCATOR, - sym::realloc => CodegenFnAttrFlags::REALLOCATOR, - sym::alloc_zeroed => CodegenFnAttrFlags::ALLOCATOR_ZEROED, - _ => unreachable!("Unknown allocator method!"), - }; - - let mut attrs = CodegenFnAttrs::new(); - attrs.flags |= alloc_attr_flag; - create_wrapper_function( - tcx, - &cx, - &from_name, - Some(&to_name), - &args, - output, - false, - &attrs, - ); + } } - } - if alloc_error_handler_kind == AllocatorKind::Default { - // rust alloc error handler + let mut no_return = false; + let output = match method.output { + AllocatorTy::ResultPtr => Some(i8p), + AllocatorTy::Unit => None, + AllocatorTy::Never => { + no_return = true; + None + } + + AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { + panic!("invalid allocator output") + } + }; + + let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name)); + let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name)); + + let alloc_attr_flag = match method.name { + sym::alloc => CodegenFnAttrFlags::ALLOCATOR, + sym::dealloc => CodegenFnAttrFlags::DEALLOCATOR, + sym::realloc => CodegenFnAttrFlags::REALLOCATOR, + sym::alloc_zeroed => CodegenFnAttrFlags::ALLOCATOR_ZEROED, + _ => CodegenFnAttrFlags::empty(), + }; + + let mut attrs = CodegenFnAttrs::new(); + attrs.flags |= alloc_attr_flag; create_wrapper_function( tcx, &cx, - &mangle_internal_symbol(tcx, &global_fn_name(ALLOC_ERROR_HANDLER)), - Some(&mangle_internal_symbol(tcx, &default_fn_name(ALLOC_ERROR_HANDLER))), - &[usize, usize], // size, align - None, - true, - &CodegenFnAttrs::new(), + &from_name, + Some(&to_name), + &args, + output, + no_return, + &attrs, ); } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 807049f08d367..34fdb4a47c0ff 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -30,7 +30,7 @@ use back::write::{create_informational_target_machine, create_target_machine}; use context::SimpleCx; use errors::ParseTargetMachineConfig; use llvm_util::target_config; -use rustc_ast::expand::allocator::AllocatorKind; +use rustc_ast::expand::allocator::AllocatorMethod; use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule}; use rustc_codegen_ssa::back::write::{ CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn, @@ -107,14 +107,13 @@ impl ExtraBackendMethods for LlvmCodegenBackend { &self, tcx: TyCtxt<'tcx>, module_name: &str, - kind: AllocatorKind, - alloc_error_handler_kind: AllocatorKind, + methods: &[AllocatorMethod], ) -> ModuleLlvm { let module_llvm = ModuleLlvm::new_metadata(tcx, module_name); let cx = SimpleCx::new(module_llvm.llmod(), &module_llvm.llcx, tcx.data_layout.pointer_size()); unsafe { - allocator::codegen(tcx, cx, module_name, kind, alloc_error_handler_kind); + allocator::codegen(tcx, cx, module_name, methods); } module_llvm } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index ac3bcb1ea269f..cd9fb098e531d 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -6,7 +6,9 @@ use std::time::{Duration, Instant}; use itertools::Itertools; use rustc_abi::FIRST_VARIANT; use rustc_ast as ast; -use rustc_ast::expand::allocator::AllocatorKind; +use rustc_ast::expand::allocator::{ + ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, AllocatorKind, AllocatorMethod, AllocatorTy, +}; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::{IntoDynSyncSend, par_map}; @@ -655,6 +657,26 @@ pub(crate) fn needs_allocator_shim_for_linking( !any_dynamic_crate } +pub fn allocator_shim_contents(tcx: TyCtxt<'_>, kind: AllocatorKind) -> Vec { + let mut methods = Vec::new(); + + if kind == AllocatorKind::Default { + methods.extend(ALLOCATOR_METHODS.into_iter().copied()); + } + + // If allocator_kind is Some then alloc_error_handler_kind must + // also be Some. + if tcx.alloc_error_handler_kind(()).unwrap() == AllocatorKind::Default { + methods.push(AllocatorMethod { + name: ALLOC_ERROR_HANDLER, + inputs: &[], + output: AllocatorTy::Never, + }); + } + + methods +} + pub fn codegen_crate( backend: B, tcx: TyCtxt<'_>, @@ -699,14 +721,8 @@ pub fn codegen_crate( cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string(); tcx.sess.time("write_allocator_module", || { - let module = backend.codegen_allocator( - tcx, - &llmod_id, - kind, - // If allocator_kind is Some then alloc_error_handler_kind must - // also be Some. - tcx.alloc_error_handler_kind(()).unwrap(), - ); + let module = + backend.codegen_allocator(tcx, &llmod_id, &allocator_shim_contents(tcx, kind)); Some(ModuleCodegen::new_allocator(llmod_id, module)) }) } else { diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 2400160075e2d..ec53d9f53eb83 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -1,7 +1,7 @@ use std::any::Any; use std::hash::Hash; -use rustc_ast::expand::allocator::AllocatorKind; +use rustc_ast::expand::allocator::AllocatorMethod; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_metadata::EncodedMetadata; @@ -116,8 +116,7 @@ pub trait ExtraBackendMethods: &self, tcx: TyCtxt<'tcx>, module_name: &str, - kind: AllocatorKind, - alloc_error_handler_kind: AllocatorKind, + methods: &[AllocatorMethod], ) -> Self::Module; /// This generates the codegen unit and returns it along with From 2e25b5876fe7a9a06bb5a2248a2e54e86937e002 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 10 Oct 2025 12:24:41 +0000 Subject: [PATCH 05/20] Add a couple of comments Co-Authored-By: Ralf Jung --- src/tools/miri/src/shims/foreign_items.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 467ac2805fe5e..39e32322f5b8d 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -51,6 +51,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Some shims forward to other MIR bodies. match link_name.as_str() { + // This allocator function has forwarding shims synthesized during normal codegen + // (see `allocator_shim_contents`); this is where we emulate that behavior. // FIXME should use global_fn_name, but mangle_internal_symbol requires a static str. name if name == this.mangle_internal_symbol("__rust_alloc_error_handler") => { // Forward to the right symbol that implements this function. @@ -68,6 +70,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { .expect("missing alloc error handler symbol"); return interp_ok(Some(handler)); } + // Fall through to the `lookup_exported_symbol` below which should find + // a `__rust_alloc_error_handler`. } _ => {} } From 88e98206836bcf80b33dce9d77298c86c8778e96 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 10 Oct 2025 13:51:52 +0000 Subject: [PATCH 06/20] Fix review comments --- compiler/rustc_ast/src/expand/allocator.rs | 1 + compiler/rustc_codegen_ssa/src/base.rs | 4 ++-- compiler/rustc_metadata/src/creader.rs | 20 +++++++++----------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_ast/src/expand/allocator.rs b/compiler/rustc_ast/src/expand/allocator.rs index 6392cb77413dd..336126a01f47e 100644 --- a/compiler/rustc_ast/src/expand/allocator.rs +++ b/compiler/rustc_ast/src/expand/allocator.rs @@ -18,6 +18,7 @@ pub fn default_fn_name(base: Symbol) -> String { pub const ALLOC_ERROR_HANDLER: Symbol = sym::alloc_error_handler; pub const NO_ALLOC_SHIM_IS_UNSTABLE: &str = "__rust_no_alloc_shim_is_unstable_v2"; +/// Argument or return type for methods in the allocator shim #[derive(Copy, Clone)] pub enum AllocatorTy { Layout, diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index cd9fb098e531d..1a79038d1fcd1 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -664,8 +664,8 @@ pub fn allocator_shim_contents(tcx: TyCtxt<'_>, kind: AllocatorKind) -> Vec !spans.is_empty(), }; - self.has_alloc_error_handler = - match &*fn_spans(krate, Symbol::intern(&global_fn_name(ALLOC_ERROR_HANDLER))) { - [span1, span2, ..] => { - tcx.dcx().emit_err(errors::NoMultipleAllocErrorHandler { - span2: *span2, - span1: *span1, - }); - true - } - spans => !spans.is_empty(), - }; + let alloc_error_handler = Symbol::intern(&global_fn_name(ALLOC_ERROR_HANDLER)); + self.has_alloc_error_handler = match &*fn_spans(krate, alloc_error_handler) { + [span1, span2, ..] => { + tcx.dcx() + .emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 }); + true + } + spans => !spans.is_empty(), + }; // Check to see if we actually need an allocator. This desire comes // about through the `#![needs_allocator]` attribute and is typically From 2611bf753e2be7923f5e20e0a37479c53d75b777 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 13 Oct 2025 08:16:34 +1100 Subject: [PATCH 07/20] Tidy some patterns in `ChunkedBitSet` ops. --- compiler/rustc_index/src/bit_set.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index f7649c5f5c55e..85ec302a6aa92 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -789,7 +789,7 @@ impl BitRelations> for ChunkedBitSet { match (&mut self_chunk, &other_chunk) { (_, Zeros) | (Ones, _) => {} - (Zeros, Ones) | (Mixed(..), Ones) | (Zeros, Mixed(..)) => { + (Zeros, _) | (Mixed(..), Ones) => { // `other_chunk` fully overwrites `self_chunk` *self_chunk = other_chunk.clone(); changed = true; @@ -853,7 +853,7 @@ impl BitRelations> for ChunkedBitSet { match (&mut self_chunk, &other_chunk) { (Zeros, _) | (_, Zeros) => {} - (Ones | Mixed(_, _), Ones) => { + (Ones | Mixed(..), Ones) => { changed = true; *self_chunk = Zeros; } From 6e85c4e2d99c794e4a9172cd38468a098427c07f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 13 Oct 2025 08:35:21 +1100 Subject: [PATCH 08/20] Remove some unused bitset code. --- compiler/rustc_index/src/bit_set.rs | 51 ----------------------- compiler/rustc_index/src/bit_set/tests.rs | 28 ------------- 2 files changed, 79 deletions(-) diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 85ec302a6aa92..6f207ff20ed38 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -973,48 +973,6 @@ impl BitRelations> for ChunkedBitSet { } } -impl BitRelations> for DenseBitSet { - fn union(&mut self, other: &ChunkedBitSet) -> bool { - sequential_update(|elem| self.insert(elem), other.iter()) - } - - fn subtract(&mut self, _other: &ChunkedBitSet) -> bool { - unimplemented!("implement if/when necessary"); - } - - fn intersect(&mut self, other: &ChunkedBitSet) -> bool { - assert_eq!(self.domain_size(), other.domain_size); - let mut changed = false; - for (i, chunk) in other.chunks.iter().enumerate() { - let mut words = &mut self.words[i * CHUNK_WORDS..]; - if words.len() > CHUNK_WORDS { - words = &mut words[..CHUNK_WORDS]; - } - match chunk { - Zeros => { - for word in words { - if *word != 0 { - changed = true; - *word = 0; - } - } - } - Ones => (), - Mixed(_, data) => { - for (i, word) in words.iter_mut().enumerate() { - let new_val = *word & data[i]; - if new_val != *word { - changed = true; - *word = new_val; - } - } - } - } - } - changed - } -} - impl Clone for ChunkedBitSet { fn clone(&self) -> Self { ChunkedBitSet { @@ -1125,15 +1083,6 @@ enum ChunkIter<'a> { Finished, } -// Applies a function to mutate a bitset, and returns true if any -// of the applications return true -fn sequential_update( - mut self_update: impl FnMut(T) -> bool, - it: impl Iterator, -) -> bool { - it.fold(false, |changed, elem| self_update(elem) | changed) -} - impl fmt::Debug for ChunkedBitSet { fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { w.debug_list().entries(self.iter()).finish() diff --git a/compiler/rustc_index/src/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs index deddc87261436..341e0622df75e 100644 --- a/compiler/rustc_index/src/bit_set/tests.rs +++ b/compiler/rustc_index/src/bit_set/tests.rs @@ -306,34 +306,6 @@ fn with_elements_chunked(elements: &[usize], domain_size: usize) -> ChunkedBitSe s } -fn with_elements_standard(elements: &[usize], domain_size: usize) -> DenseBitSet { - let mut s = DenseBitSet::new_empty(domain_size); - for &e in elements { - assert!(s.insert(e)); - } - s -} - -#[test] -fn chunked_bitset_into_bitset_operations() { - let a = vec![1, 5, 7, 11, 15, 2000, 3000]; - let b = vec![3, 4, 11, 3000, 4000]; - let aub = vec![1, 3, 4, 5, 7, 11, 15, 2000, 3000, 4000]; - let aib = vec![11, 3000]; - - let b = with_elements_chunked(&b, 9876); - - let mut union = with_elements_standard(&a, 9876); - assert!(union.union(&b)); - assert!(!union.union(&b)); - assert!(union.iter().eq(aub.iter().copied())); - - let mut intersection = with_elements_standard(&a, 9876); - assert!(intersection.intersect(&b)); - assert!(!intersection.intersect(&b)); - assert!(intersection.iter().eq(aib.iter().copied())); -} - #[test] fn chunked_bitset_iter() { fn check_iter(bit: &ChunkedBitSet, vec: &Vec) { From 056c2da339428cd87514488121f8b365417ebfa0 Mon Sep 17 00:00:00 2001 From: Alessandro Decina Date: Mon, 13 Oct 2025 13:32:15 +0000 Subject: [PATCH 09/20] bpf: return results larger than one register indirectly Fixes triggering the "only small returns supported" error in the BPF target. --- compiler/rustc_target/src/callconv/bpf.rs | 6 +++ compiler/rustc_target/src/callconv/mod.rs | 1 + tests/codegen-llvm/bpf-abi-indirect-return.rs | 43 +++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 tests/codegen-llvm/bpf-abi-indirect-return.rs diff --git a/compiler/rustc_target/src/callconv/bpf.rs b/compiler/rustc_target/src/callconv/bpf.rs index f958aeb9bb654..ec5c1c2cf6860 100644 --- a/compiler/rustc_target/src/callconv/bpf.rs +++ b/compiler/rustc_target/src/callconv/bpf.rs @@ -29,3 +29,9 @@ pub(crate) fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { classify_arg(arg); } } + +pub(crate) fn compute_rust_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { + if !fn_abi.ret.is_ignore() { + classify_ret(&mut fn_abi.ret); + } +} diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index c59af581a1fe4..3f7382ee0e2b5 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -715,6 +715,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { "riscv32" | "riscv64" => riscv::compute_rust_abi_info(cx, self), "loongarch32" | "loongarch64" => loongarch::compute_rust_abi_info(cx, self), "aarch64" => aarch64::compute_rust_abi_info(cx, self), + "bpf" => bpf::compute_rust_abi_info(self), _ => {} }; diff --git a/tests/codegen-llvm/bpf-abi-indirect-return.rs b/tests/codegen-llvm/bpf-abi-indirect-return.rs new file mode 100644 index 0000000000000..b5787cc83a2b4 --- /dev/null +++ b/tests/codegen-llvm/bpf-abi-indirect-return.rs @@ -0,0 +1,43 @@ +// Checks that results larger than one register are returned indirectly +//@ only-bpf +//@ needs-llvm-components: bpf +//@ compile-flags: --target bpfel-unknown-none + +#![no_std] +#![no_main] + +#[no_mangle] +fn outer(a: u64) -> u64 { + let v = match inner_res(a) { + Ok(v) => v, + Err(()) => 0, + }; + + inner_big(v).a[0] as u64 +} + +// CHECK-LABEL: define {{.*}} @_ZN{{.*}}inner_res{{.*}}E( +// CHECK-SAME: ptr{{[^,]*}}, +// CHECK-SAME: i64{{[^)]*}} +#[inline(never)] +fn inner_res(a: u64) -> Result { + if a == 0 { Err(()) } else { Ok(a + 1) } +} + +struct Big { + a: [u16; 32], + b: u64, +} + +// CHECK-LABEL: define {{.*}} @_ZN{{.*}}inner_big{{.*}}E( +// CHECK-SAME: ptr{{[^,]*}}, +// CHECK-SAME: i64{{[^)]*}} +#[inline(never)] +fn inner_big(a: u64) -> Big { + Big { a: [a as u16; 32], b: 42 } +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} From 8386278866b7762358a2f7d7956fc5c01c3272ad Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 13 Oct 2025 08:27:27 +1100 Subject: [PATCH 10/20] Factor out a recurring pattern as `count_ones`. --- compiler/rustc_index/src/bit_set.rs | 45 ++++++++++------------------- 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 6f207ff20ed38..988c4550cdd96 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -160,7 +160,7 @@ impl DenseBitSet { /// Count the number of set bits in the set. pub fn count(&self) -> usize { - self.words.iter().map(|e| e.count_ones() as usize).sum() + count_ones(&self.words) } /// Returns `true` if `self` contains `elem`. @@ -817,10 +817,8 @@ impl BitRelations> for ChunkedBitSet { op, ); debug_assert!(has_changed); - *self_chunk_count = self_chunk_words[0..num_words] - .iter() - .map(|w| w.count_ones() as ChunkSize) - .sum(); + *self_chunk_count = + count_ones(&self_chunk_words[0..num_words]) as ChunkSize; if *self_chunk_count == chunk_domain_size { *self_chunk = Ones; } @@ -871,10 +869,7 @@ impl BitRelations> for ChunkedBitSet { let self_chunk_count = chunk_domain_size - *other_chunk_count; debug_assert_eq!( self_chunk_count, - self_chunk_words[0..num_words] - .iter() - .map(|w| w.count_ones() as ChunkSize) - .sum() + count_ones(&self_chunk_words[0..num_words]) as ChunkSize ); *self_chunk = Mixed(self_chunk_count, Rc::new(self_chunk_words)); } @@ -897,10 +892,8 @@ impl BitRelations> for ChunkedBitSet { op, ); debug_assert!(has_changed); - *self_chunk_count = self_chunk_words[0..num_words] - .iter() - .map(|w| w.count_ones() as ChunkSize) - .sum(); + *self_chunk_count = + count_ones(&self_chunk_words[0..num_words]) as ChunkSize; if *self_chunk_count == 0 { *self_chunk = Zeros; } @@ -956,10 +949,8 @@ impl BitRelations> for ChunkedBitSet { op, ); debug_assert!(has_changed); - *self_chunk_count = self_chunk_words[0..num_words] - .iter() - .map(|w| w.count_ones() as ChunkSize) - .sum(); + *self_chunk_count = + count_ones(&self_chunk_words[0..num_words]) as ChunkSize; if *self_chunk_count == 0 { *self_chunk = Zeros; } @@ -1046,21 +1037,12 @@ impl Chunk { assert!(0 < count && count < chunk_domain_size); // Check the number of set bits matches `count`. - assert_eq!( - words.iter().map(|w| w.count_ones() as ChunkSize).sum::(), - count - ); + assert_eq!(count_ones(words.as_slice()) as ChunkSize, count); // Check the not-in-use words are all zeroed. let num_words = num_words(chunk_domain_size as usize); if num_words < CHUNK_WORDS { - assert_eq!( - words[num_words..] - .iter() - .map(|w| w.count_ones() as ChunkSize) - .sum::(), - 0 - ); + assert_eq!(count_ones(&words[num_words..]) as ChunkSize, 0); } } } @@ -1542,7 +1524,7 @@ impl BitMatrix { /// Returns the number of elements in `row`. pub fn count(&self, row: R) -> usize { let (start, end) = self.range(row); - self.words[start..end].iter().map(|e| e.count_ones() as usize).sum() + count_ones(&self.words[start..end]) } } @@ -1753,6 +1735,11 @@ fn max_bit(word: Word) -> usize { WORD_BITS - 1 - word.leading_zeros() as usize } +#[inline] +fn count_ones(words: &[Word]) -> usize { + words.iter().map(|word| word.count_ones() as usize).sum() +} + /// Integral type used to represent the bit set. pub trait FiniteBitSetTy: BitAnd From 714843dc57f58e144862bd3f34416e1dd6b15167 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Tue, 14 Oct 2025 06:13:22 +0000 Subject: [PATCH 11/20] replace manual implementation with carrying_mul_add --- library/core/src/num/bignum.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs index f21fe0b4438fb..33b1e8cb56db2 100644 --- a/library/core/src/num/bignum.rs +++ b/library/core/src/num/bignum.rs @@ -38,9 +38,8 @@ macro_rules! impl_full_ops { fn full_mul_add(self, other: $ty, other2: $ty, carry: $ty) -> ($ty, $ty) { // This cannot overflow; // the output is between `0` and `2^nbits * (2^nbits - 1)`. - let v = (self as $bigty) * (other as $bigty) + (other2 as $bigty) + - (carry as $bigty); - ((v >> <$ty>::BITS) as $ty, v as $ty) + let (lo, hi) = self.carrying_mul_add(other, other2, carry); + (hi, lo) } fn full_div_rem(self, other: $ty, borrow: $ty) -> ($ty, $ty) { From 18d1b69c9237b1dff227edcc5c210a4b56884478 Mon Sep 17 00:00:00 2001 From: cyrgani <85427285+cyrgani@users.noreply.github.com> Date: Tue, 14 Oct 2025 10:23:29 +0200 Subject: [PATCH 12/20] fix missing link to `std::char` in `std` docs --- library/std/src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 46eb120d65de3..60c8f53a0cc40 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -65,7 +65,7 @@ //! So for example there is a [page for the primitive type //! `char`](primitive::char) that lists all the methods that can be called on //! characters (very useful), and there is a [page for the module -//! `std::char`] that documents iterator and error types created by these methods +//! `std::char`](crate::char) that documents iterator and error types created by these methods //! (rarely useful). //! //! Note the documentation for the primitives [`str`] and [`[T]`][prim@slice] (also @@ -180,9 +180,6 @@ //! //! //! [I/O]: io -//! [`MIN`]: i32::MIN -//! [`MAX`]: i32::MAX -//! [page for the module `std::i32`]: crate::i32 //! [TCP]: net::TcpStream //! [The Rust Prelude]: prelude //! [UDP]: net::UdpSocket From 8a145efc70f0eea89de9fae314cb37b64c1f2b75 Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 13 Sep 2025 13:01:11 +0200 Subject: [PATCH 13/20] std: improve handling of timed condition variable waits on macOS --- library/Cargo.lock | 4 +- library/std/Cargo.toml | 2 +- library/std/src/sys/pal/unix/sync/condvar.rs | 99 ++++++++++++++++---- library/std/tests/sync/condvar.rs | 32 +++++++ 4 files changed, 115 insertions(+), 22 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index 47fbf5169f491..b5b534c986b99 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -139,9 +139,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.175" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" dependencies = [ "rustc-std-workspace-core", ] diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 779b07ce240a6..d4108a57acaf0 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -33,7 +33,7 @@ miniz_oxide = { version = "0.8.0", optional = true, default-features = false } addr2line = { version = "0.25.0", optional = true, default-features = false } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] -libc = { version = "0.2.172", default-features = false, features = [ +libc = { version = "0.2.177", default-features = false, features = [ 'rustc-dep-of-std', ], public = true } diff --git a/library/std/src/sys/pal/unix/sync/condvar.rs b/library/std/src/sys/pal/unix/sync/condvar.rs index efa6f8d776559..b6c3ba4136f2a 100644 --- a/library/std/src/sys/pal/unix/sync/condvar.rs +++ b/library/std/src/sys/pal/unix/sync/condvar.rs @@ -1,11 +1,6 @@ use super::Mutex; use crate::cell::UnsafeCell; use crate::pin::Pin; -#[cfg(not(target_os = "nto"))] -use crate::sys::pal::time::TIMESPEC_MAX; -#[cfg(target_os = "nto")] -use crate::sys::pal::time::TIMESPEC_MAX_CAPPED; -use crate::sys::pal::time::Timespec; use crate::time::Duration; pub struct Condvar { @@ -47,27 +42,29 @@ impl Condvar { let r = unsafe { libc::pthread_cond_wait(self.raw(), mutex.raw()) }; debug_assert_eq!(r, 0); } +} +#[cfg(not(target_vendor = "apple"))] +impl Condvar { /// # Safety /// * `init` must have been called on this instance. /// * `mutex` must be locked by the current thread. /// * This condition variable may only be used with the same mutex. pub unsafe fn wait_timeout(&self, mutex: Pin<&Mutex>, dur: Duration) -> bool { + #[cfg(not(target_os = "nto"))] + use crate::sys::pal::time::TIMESPEC_MAX; + #[cfg(target_os = "nto")] + use crate::sys::pal::time::TIMESPEC_MAX_CAPPED; + use crate::sys::pal::time::Timespec; + let mutex = mutex.raw(); - // OSX implementation of `pthread_cond_timedwait` is buggy - // with super long durations. When duration is greater than - // 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait` - // in macOS Sierra returns error 316. - // - // This program demonstrates the issue: - // https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c - // - // To work around this issue, the timeout is clamped to 1000 years. - // - // Cygwin implementation is based on NT API and a super large timeout - // makes the syscall block forever. - #[cfg(any(target_vendor = "apple", target_os = "cygwin"))] + // Cygwin's implementation is based on the NT API, which measures time + // in units of 100 ns. Unfortunately, Cygwin does not properly guard + // against overflow when converting the time, hence we clamp the interval + // to 1000 years, which will only become a problem in around 27000 years, + // when the next rollover is less than 1000 years away... + #[cfg(target_os = "cygwin")] let dur = Duration::min(dur, Duration::from_secs(1000 * 365 * 86400)); let timeout = Timespec::now(Self::CLOCK).checked_add_duration(&dur); @@ -84,6 +81,57 @@ impl Condvar { } } +// Apple platforms (since macOS version 10.4 and iOS version 2.0) have +// `pthread_cond_timedwait_relative_np`, a non-standard extension that +// measures timeouts based on the monotonic clock and is thus resilient +// against wall-clock changes. +#[cfg(target_vendor = "apple")] +impl Condvar { + /// # Safety + /// * `init` must have been called on this instance. + /// * `mutex` must be locked by the current thread. + /// * This condition variable may only be used with the same mutex. + pub unsafe fn wait_timeout(&self, mutex: Pin<&Mutex>, dur: Duration) -> bool { + let mutex = mutex.raw(); + + // The macOS implementation of `pthread_cond_timedwait` internally + // converts the timeout passed to `pthread_cond_timedwait_relative_np` + // to nanoseconds. Unfortunately, the "psynch" variant of condvars does + // not guard against overflow during the conversion[^1], which means + // that `pthread_cond_timedwait_relative_np` will return `ETIMEDOUT` + // much earlier than expected if the relative timeout is longer than + // `u64::MAX` nanoseconds. + // + // This can be observed even on newer platforms (by setting the environment + // variable PTHREAD_MUTEX_USE_ULOCK to a value other than "1") by calling e.g. + // ``` + // condvar.wait_timeout(..., Duration::from_secs(u64::MAX.div_ceil(1_000_000_000)); + // ``` + // (see #37440, especially + // https://github.com/rust-lang/rust/issues/37440#issuecomment-3285958326). + // + // To work around this issue, always clamp the timeout to u64::MAX nanoseconds, + // even if the "ulock" variant is used (which does guard against overflow). + // + // [^1]: https://github.com/apple-oss-distributions/libpthread/blob/1ebf56b3a702df53213c2996e5e128a535d2577e/kern/kern_synch.c#L1269 + const MAX_DURATION: Duration = Duration::from_nanos(u64::MAX); + + let (dur, clamped) = if dur <= MAX_DURATION { (dur, false) } else { (MAX_DURATION, true) }; + + let timeout = libc::timespec { + // This cannot overflow because of the clamping above. + tv_sec: dur.as_secs() as i64, + tv_nsec: dur.subsec_nanos() as i64, + }; + + let r = unsafe { libc::pthread_cond_timedwait_relative_np(self.raw(), mutex, &timeout) }; + assert!(r == libc::ETIMEDOUT || r == 0); + // Report clamping as a spurious wakeup. Who knows, maybe some + // interstellar space probe will rely on this ;-). + r == 0 || clamped + } +} + #[cfg(not(any( target_os = "android", target_vendor = "apple", @@ -125,10 +173,23 @@ impl Condvar { } } +#[cfg(target_vendor = "apple")] +impl Condvar { + // `pthread_cond_timedwait_relative_np` measures the timeout + // based on the monotonic clock. + pub const PRECISE_TIMEOUT: bool = true; + + /// # Safety + /// May only be called once per instance of `Self`. + pub unsafe fn init(self: Pin<&mut Self>) { + // `PTHREAD_COND_INITIALIZER` is fully supported and we don't need to + // change clocks, so there's nothing to do here. + } +} + // `pthread_condattr_setclock` is unfortunately not supported on these platforms. #[cfg(any( target_os = "android", - target_vendor = "apple", target_os = "espidf", target_os = "horizon", target_os = "l4re", diff --git a/library/std/tests/sync/condvar.rs b/library/std/tests/sync/condvar.rs index 1b1c33efad58e..2a525f9b5e948 100644 --- a/library/std/tests/sync/condvar.rs +++ b/library/std/tests/sync/condvar.rs @@ -267,3 +267,35 @@ nonpoison_and_poison_unwrap_test!( } } ); + +// Some platforms internally cast the timeout duration into nanoseconds. +// If they fail to consider overflow during the conversion (I'm looking +// at you, macOS), `wait_timeout` will return immediately and indicate a +// timeout for durations that are slightly longer than u64::MAX nanoseconds. +// `std` should guard against this by clamping the timeout. +// See #37440 for context. +nonpoison_and_poison_unwrap_test!( + name: timeout_nanoseconds, + test_body: { + use locks::Mutex; + use locks::Condvar; + + let sent = Mutex::new(false); + let cond = Condvar::new(); + + thread::scope(|s| { + s.spawn(|| { + thread::sleep(Duration::from_secs(2)); + maybe_unwrap(sent.set(true)); + cond.notify_all(); + }); + + let guard = maybe_unwrap(sent.lock()); + // If there is internal overflow, this call will return almost + // immediately, before the other thread has reached the `notify_all` + let (guard, res) = maybe_unwrap(cond.wait_timeout(guard, Duration::from_secs(u64::MAX.div_ceil(1_000_000_000)))); + assert!(!res.timed_out()); + assert!(*guard); + }) + } +); From fe1238e69693c4d466d1ec6d8b70e89e220d204b Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 13 Sep 2025 17:27:54 +0200 Subject: [PATCH 14/20] miri: shim `pthread_cond_timedwait_relative_np` --- .../miri/src/shims/unix/foreign_items.rs | 2 +- .../src/shims/unix/macos/foreign_items.rs | 6 +++ src/tools/miri/src/shims/unix/sync.rs | 22 +++++++--- ...thread_cond_timedwait_relative_np_apple.rs | 41 +++++++++++++++++++ 4 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 src/tools/miri/tests/pass-dep/libc/pthread_cond_timedwait_relative_np_apple.rs diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 55906f4eb9548..d04ef5eac541b 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -815,7 +815,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "pthread_cond_timedwait" => { let [cond, mutex, abstime] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; + this.pthread_cond_timedwait(cond, mutex, abstime, dest, /* macos_relative_np */ false)?; } "pthread_cond_destroy" => { let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index 297d903c6ba4e..0754eb45a2d29 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -307,6 +307,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.os_unfair_lock_assert_not_owner(lock_op)?; } + "pthread_cond_timedwait_relative_np" => { + let [cond, mutex, reltime] = + this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.pthread_cond_timedwait(cond, mutex, reltime, dest, /* macos_relative_np */ true)?; + } + _ => return interp_ok(EmulateItemResult::NotSupported), }; diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs index cefd8b81ac180..a712279d57628 100644 --- a/src/tools/miri/src/shims/unix/sync.rs +++ b/src/tools/miri/src/shims/unix/sync.rs @@ -834,8 +834,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, cond_op: &OpTy<'tcx>, mutex_op: &OpTy<'tcx>, - abstime_op: &OpTy<'tcx>, + timeout_op: &OpTy<'tcx>, dest: &MPlaceTy<'tcx>, + macos_relative_np: bool, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -844,7 +845,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Extract the timeout. let duration = match this - .read_timespec(&this.deref_pointer_as(abstime_op, this.libc_ty_layout("timespec"))?)? + .read_timespec(&this.deref_pointer_as(timeout_op, this.libc_ty_layout("timespec"))?)? { Some(duration) => duration, None => { @@ -853,14 +854,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return interp_ok(()); } }; - if data.clock == TimeoutClock::RealTime { - this.check_no_isolation("`pthread_cond_timedwait` with `CLOCK_REALTIME`")?; - } + + let (clock, anchor) = if macos_relative_np { + // `pthread_cond_timedwait_relative_np` always measures time against the + // monotonic clock, regardless of the condvar clock. + (TimeoutClock::Monotonic, TimeoutAnchor::Relative) + } else { + if data.clock == TimeoutClock::RealTime { + this.check_no_isolation("`pthread_cond_timedwait` with `CLOCK_REALTIME`")?; + } + + (data.clock, TimeoutAnchor::Absolute) + }; this.condvar_wait( data.condvar_ref, mutex_ref, - Some((data.clock, TimeoutAnchor::Absolute, duration)), + Some((clock, anchor, duration)), Scalar::from_i32(0), this.eval_libc("ETIMEDOUT"), // retval_timeout dest.clone(), diff --git a/src/tools/miri/tests/pass-dep/libc/pthread_cond_timedwait_relative_np_apple.rs b/src/tools/miri/tests/pass-dep/libc/pthread_cond_timedwait_relative_np_apple.rs new file mode 100644 index 0000000000000..bcf06211b8c41 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/pthread_cond_timedwait_relative_np_apple.rs @@ -0,0 +1,41 @@ +//@only-target: apple # `pthread_cond_timedwait_relative_np` is a non-standard extension + +use std::time::Instant; + +// FIXME: remove once this is in libc. +mod libc { + pub use ::libc::*; + unsafe extern "C" { + pub unsafe fn pthread_cond_timedwait_relative_np( + cond: *mut libc::pthread_cond_t, + lock: *mut libc::pthread_mutex_t, + timeout: *const libc::timespec, + ) -> libc::c_int; + } +} + +fn main() { + unsafe { + let mut mutex: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER; + let mut cond: libc::pthread_cond_t = libc::PTHREAD_COND_INITIALIZER; + + // Wait for 100 ms. + let timeout = libc::timespec { tv_sec: 0, tv_nsec: 100_000_000 }; + + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + + let current_time = Instant::now(); + assert_eq!( + libc::pthread_cond_timedwait_relative_np(&mut cond, &mut mutex, &timeout), + libc::ETIMEDOUT + ); + let elapsed_time = current_time.elapsed().as_millis(); + // This is actually deterministic (since isolation remains enabled), + // but can change slightly with Rust updates. + assert!(90 <= elapsed_time && elapsed_time <= 110); + + assert_eq!(libc::pthread_mutex_unlock(&mut mutex), 0); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex), 0); + assert_eq!(libc::pthread_cond_destroy(&mut cond), 0); + } +} From 37fa60bbf14911ebdbd942c37444fb53460db6a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 14 Oct 2025 13:42:38 +0200 Subject: [PATCH 15/20] pretty print u128 with display --- compiler/rustc_hir/src/attrs/pretty_printing.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/compiler/rustc_hir/src/attrs/pretty_printing.rs b/compiler/rustc_hir/src/attrs/pretty_printing.rs index d13cd3fd1dab0..ea86dfbd9c80e 100644 --- a/compiler/rustc_hir/src/attrs/pretty_printing.rs +++ b/compiler/rustc_hir/src/attrs/pretty_printing.rs @@ -26,16 +26,6 @@ pub trait PrintAttribute { fn print_attribute(&self, p: &mut Printer); } -impl PrintAttribute for u128 { - fn should_render(&self) -> bool { - true - } - - fn print_attribute(&self, p: &mut Printer) { - p.word(self.to_string()) - } -} - impl PrintAttribute for &T { fn should_render(&self) -> bool { T::should_render(self) @@ -148,7 +138,7 @@ macro_rules! print_tup { print_tup!(A B C D E F G H); print_skip!(Span, (), ErrorGuaranteed); -print_disp!(u16, bool, NonZero, Limit); +print_disp!(u16, u128, bool, NonZero, Limit); print_debug!( Symbol, Ident, From 7a368c8abbf5e5f49a45fbecaa28ccfe2d836c1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 14 Oct 2025 14:27:08 +0200 Subject: [PATCH 16/20] Use span from parsed attribute --- .../rustc_codegen_ssa/src/codegen_attrs.rs | 4 ++-- compiler/rustc_hir/src/hir.rs | 2 -- compiler/rustc_lint/src/builtin.rs | 20 ++++++++++--------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index e8c8729f597b9..44de48a3ada51 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -279,7 +279,7 @@ fn process_builtin_attrs( AttributeKind::StdInternalSymbol(_) => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL } - AttributeKind::Linkage(linkage, _) => { + AttributeKind::Linkage(linkage, span) => { let linkage = Some(*linkage); if tcx.is_foreign_item(did) { @@ -287,7 +287,7 @@ fn process_builtin_attrs( if tcx.is_mutable_static(did.into()) { let mut diag = tcx.dcx().struct_span_err( - attr.span(), + *span, "extern mutable statics are not allowed with `#[linkage]`", ); diag.note( diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index bc1c47e95c3ae..2f60a9119cbe2 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1315,8 +1315,6 @@ impl AttributeExt for Attribute { // FIXME: should not be needed anymore when all attrs are parsed Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span, Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span, - Attribute::Parsed(AttributeKind::AllowInternalUnsafe(span)) => *span, - Attribute::Parsed(AttributeKind::Linkage(_, span)) => *span, a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"), } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 8a525eb11f7bb..d14bc600f2f11 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -310,15 +310,17 @@ impl EarlyLintPass for UnsafeCode { } ast::ItemKind::MacroDef(..) => { - if let Some(attr) = AttributeParser::parse_limited( - cx.builder.sess(), - &it.attrs, - sym::allow_internal_unsafe, - it.span, - DUMMY_NODE_ID, - Some(cx.builder.features()), - ) { - self.report_unsafe(cx, attr.span(), BuiltinUnsafe::AllowInternalUnsafe); + if let Some(hir::Attribute::Parsed(AttributeKind::AllowInternalUnsafe(span))) = + AttributeParser::parse_limited( + cx.builder.sess(), + &it.attrs, + sym::allow_internal_unsafe, + it.span, + DUMMY_NODE_ID, + Some(cx.builder.features()), + ) + { + self.report_unsafe(cx, span, BuiltinUnsafe::AllowInternalUnsafe); } } From c00b4ba5efbaa80785cb58dca0389d0e6d7af284 Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 14 Oct 2025 22:29:56 +0800 Subject: [PATCH 17/20] Fix ICE caused by associated_item_def_ids on wrong type in resolve diag --- compiler/rustc_resolve/src/lib.rs | 50 ++++++++++++------- .../struct-fields-ice-147325.rs | 11 ++++ .../struct-fields-ice-147325.stderr | 22 ++++++++ 3 files changed, 65 insertions(+), 18 deletions(-) create mode 100644 tests/ui/structs/default-field-values/struct-fields-ice-147325.rs create mode 100644 tests/ui/structs/default-field-values/struct-fields-ice-147325.stderr diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index d9c3f4089a0fb..efb4bbfa2b72e 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -2332,30 +2332,44 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn field_idents(&self, def_id: DefId) -> Option> { match def_id.as_local() { Some(def_id) => self.field_names.get(&def_id).cloned(), - None => Some( - self.tcx - .associated_item_def_ids(def_id) - .iter() - .map(|&def_id| { - Ident::new(self.tcx.item_name(def_id), self.tcx.def_span(def_id)) - }) - .collect(), - ), + None if matches!( + self.tcx.def_kind(def_id), + DefKind::Struct | DefKind::Union | DefKind::Variant + ) => + { + Some( + self.tcx + .associated_item_def_ids(def_id) + .iter() + .map(|&def_id| { + Ident::new(self.tcx.item_name(def_id), self.tcx.def_span(def_id)) + }) + .collect(), + ) + } + _ => None, } } fn field_defaults(&self, def_id: DefId) -> Option> { match def_id.as_local() { Some(def_id) => self.field_defaults.get(&def_id).cloned(), - None => Some( - self.tcx - .associated_item_def_ids(def_id) - .iter() - .filter_map(|&def_id| { - self.tcx.default_field(def_id).map(|_| self.tcx.item_name(def_id)) - }) - .collect(), - ), + None if matches!( + self.tcx.def_kind(def_id), + DefKind::Struct | DefKind::Union | DefKind::Variant + ) => + { + Some( + self.tcx + .associated_item_def_ids(def_id) + .iter() + .filter_map(|&def_id| { + self.tcx.default_field(def_id).map(|_| self.tcx.item_name(def_id)) + }) + .collect(), + ) + } + _ => None, } } diff --git a/tests/ui/structs/default-field-values/struct-fields-ice-147325.rs b/tests/ui/structs/default-field-values/struct-fields-ice-147325.rs new file mode 100644 index 0000000000000..fc68060a96271 --- /dev/null +++ b/tests/ui/structs/default-field-values/struct-fields-ice-147325.rs @@ -0,0 +1,11 @@ +// ICE #147325: When the user mistakenly uses struct syntax to construct an enum, +// the field_idents and field_defaults functions will trigger an error + +mod m { + struct Priv1; +} + +fn main() { + Option { field1: m::Priv1 } //~ ERROR expected struct, variant or union type, found enum + //~^ ERROR unit struct `Priv1` is private +} diff --git a/tests/ui/structs/default-field-values/struct-fields-ice-147325.stderr b/tests/ui/structs/default-field-values/struct-fields-ice-147325.stderr new file mode 100644 index 0000000000000..7193a7112b445 --- /dev/null +++ b/tests/ui/structs/default-field-values/struct-fields-ice-147325.stderr @@ -0,0 +1,22 @@ +error[E0574]: expected struct, variant or union type, found enum `Option` + --> $DIR/struct-fields-ice-147325.rs:9:5 + | +LL | Option { field1: m::Priv1 } + | ^^^^^^ not a struct, variant or union type + +error[E0603]: unit struct `Priv1` is private + --> $DIR/struct-fields-ice-147325.rs:9:25 + | +LL | Option { field1: m::Priv1 } + | ^^^^^ private unit struct + | +note: the unit struct `Priv1` is defined here + --> $DIR/struct-fields-ice-147325.rs:5:5 + | +LL | struct Priv1; + | ^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0574, E0603. +For more information about an error, try `rustc --explain E0574`. From a51a793472fc6ba16247ddc06e366f7993d8ae93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 14 Oct 2025 17:27:38 +0200 Subject: [PATCH 18/20] only check duplicates on old/unparsed attributes --- compiler/rustc_passes/src/check_attr.rs | 33 ++++++++++++++++--------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index cba6243fa1098..5f0d7cdb59ef0 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -393,8 +393,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); - if hir_id != CRATE_HIR_ID { match attr { Attribute::Parsed(_) => { /* Already validated. */ } @@ -440,8 +438,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - if let Some(BuiltinAttribute { duplicates, .. }) = builtin { - check_duplicates(self.tcx, attr, hir_id, *duplicates, &mut seen); + if let Attribute::Unparsed(unparsed_attr) = attr + && let Some(BuiltinAttribute { duplicates, .. }) = + attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) + { + check_duplicates( + self.tcx, + unparsed_attr.span, + attr, + hir_id, + *duplicates, + &mut seen, + ); } self.check_unused_attribute(hir_id, attr, style) @@ -2481,6 +2489,7 @@ pub(crate) fn provide(providers: &mut Providers) { // FIXME(jdonszelmann): remove, check during parsing fn check_duplicates( tcx: TyCtxt<'_>, + attr_span: Span, attr: &Attribute, hir_id: HirId, duplicates: AttributeDuplicates, @@ -2497,10 +2506,10 @@ fn check_duplicates( match seen.entry(attr_name) { Entry::Occupied(mut entry) => { let (this, other) = if matches!(duplicates, FutureWarnPreceding) { - let to_remove = entry.insert(attr.span()); - (to_remove, attr.span()) + let to_remove = entry.insert(attr_span); + (to_remove, attr_span) } else { - (attr.span(), *entry.get()) + (attr_span, *entry.get()) }; tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, @@ -2517,22 +2526,22 @@ fn check_duplicates( ); } Entry::Vacant(entry) => { - entry.insert(attr.span()); + entry.insert(attr_span); } } } ErrorFollowing | ErrorPreceding => match seen.entry(attr_name) { Entry::Occupied(mut entry) => { let (this, other) = if matches!(duplicates, ErrorPreceding) { - let to_remove = entry.insert(attr.span()); - (to_remove, attr.span()) + let to_remove = entry.insert(attr_span); + (to_remove, attr_span) } else { - (attr.span(), *entry.get()) + (attr_span, *entry.get()) }; tcx.dcx().emit_err(errors::UnusedMultiple { this, other, name: attr_name }); } Entry::Vacant(entry) => { - entry.insert(attr.span()); + entry.insert(attr_span); } }, } From cf0256008be86edbeac0af4300e67d1f7bcb7df9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 14 Oct 2025 15:53:40 +0000 Subject: [PATCH 19/20] Add comment to AllocatorKind and AllocatorMethod --- compiler/rustc_ast/src/expand/allocator.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_ast/src/expand/allocator.rs b/compiler/rustc_ast/src/expand/allocator.rs index 336126a01f47e..c200921e5f807 100644 --- a/compiler/rustc_ast/src/expand/allocator.rs +++ b/compiler/rustc_ast/src/expand/allocator.rs @@ -3,7 +3,9 @@ use rustc_span::{Symbol, sym}; #[derive(Clone, Debug, Copy, Eq, PartialEq, HashStable_Generic)] pub enum AllocatorKind { + /// Use `#[global_allocator]` as global allocator. Global, + /// Use the default implementation in libstd as global allocator. Default, } @@ -29,6 +31,7 @@ pub enum AllocatorTy { Usize, } +/// A method that will be codegened in the allocator shim. #[derive(Copy, Clone)] pub struct AllocatorMethod { pub name: Symbol, From 047c37cf23c1b153857b9ba36b529ceb18724812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 14 Oct 2025 16:25:39 +0200 Subject: [PATCH 20/20] convert rustc_main to the new attribute parsing infrastructure --- compiler/rustc_ast/src/entry.rs | 6 +- .../src/attributes/rustc_internal.rs | 17 +++- compiler/rustc_attr_parsing/src/context.rs | 7 +- .../rustc_builtin_macros/src/test_harness.rs | 9 ++- .../rustc_hir/src/attrs/data_structures.rs | 3 + .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_passes/messages.ftl | 3 - compiler/rustc_passes/src/check_attr.rs | 11 +-- compiler/rustc_passes/src/entry.rs | 24 ++---- compiler/rustc_passes/src/errors.rs | 8 -- ...sue-43106-gating-of-builtin-attrs-error.rs | 3 +- ...43106-gating-of-builtin-attrs-error.stderr | 79 +++++++++---------- 12 files changed, 74 insertions(+), 97 deletions(-) diff --git a/compiler/rustc_ast/src/entry.rs b/compiler/rustc_ast/src/entry.rs index 12cbb3b2a15f7..ae0cc7350a78f 100644 --- a/compiler/rustc_ast/src/entry.rs +++ b/compiler/rustc_ast/src/entry.rs @@ -1,7 +1,5 @@ use rustc_span::{Symbol, sym}; -use crate::attr::{self, AttributeExt}; - #[derive(Debug)] pub enum EntryPointType { /// This function is not an entrypoint. @@ -30,11 +28,11 @@ pub enum EntryPointType { } pub fn entry_point_type( - attrs: &[impl AttributeExt], + has_rustc_main: bool, at_root: bool, name: Option, ) -> EntryPointType { - if attr::contains_name(attrs, sym::rustc_main) { + if has_rustc_main { EntryPointType::RustcMainAttr } else if let Some(name) = name && name == sym::main diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index cf2f5c6c79024..455c61097d78d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -1,9 +1,18 @@ use super::prelude::*; use super::util::parse_single_integer; -pub(crate) struct RustcLayoutScalarValidRangeStart; +pub(crate) struct RustcMainParser; -impl SingleAttributeParser for RustcLayoutScalarValidRangeStart { +impl NoArgsAttributeParser for RustcMainParser { + const PATH: &'static [Symbol] = &[sym::rustc_main]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcMain; +} + +pub(crate) struct RustcLayoutScalarValidRangeStartParser; + +impl SingleAttributeParser for RustcLayoutScalarValidRangeStartParser { const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_start]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; @@ -16,9 +25,9 @@ impl SingleAttributeParser for RustcLayoutScalarValidRangeStart { } } -pub(crate) struct RustcLayoutScalarValidRangeEnd; +pub(crate) struct RustcLayoutScalarValidRangeEndParser; -impl SingleAttributeParser for RustcLayoutScalarValidRangeEnd { +impl SingleAttributeParser for RustcLayoutScalarValidRangeEndParser { const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_end]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index e8bb4caa41664..6749bdfb1a672 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -53,7 +53,7 @@ use crate::attributes::proc_macro_attrs::{ use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; use crate::attributes::rustc_internal::{ - RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart, + RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, RustcMainParser, RustcObjectLifetimeDefaultParser, RustcSimdMonomorphizeLaneLimitParser, }; use crate::attributes::semantics::MayDangleParser; @@ -197,8 +197,8 @@ attribute_parsers!( Single, Single, Single, - Single, - Single, + Single, + Single, Single, Single, Single, @@ -238,6 +238,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 82c59d5a3a20b..2a6ac5754bfaf 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -3,6 +3,7 @@ use std::mem; use rustc_ast as ast; +use rustc_ast::attr::contains_name; use rustc_ast::entry::EntryPointType; use rustc_ast::mut_visit::*; use rustc_ast::visit::Visitor; @@ -172,9 +173,11 @@ impl<'a> Visitor<'a> for InnerItemLinter<'_> { fn entry_point_type(item: &ast::Item, at_root: bool) -> EntryPointType { match &item.kind { - ast::ItemKind::Fn(fn_) => { - rustc_ast::entry::entry_point_type(&item.attrs, at_root, Some(fn_.ident.name)) - } + ast::ItemKind::Fn(fn_) => rustc_ast::entry::entry_point_type( + contains_name(&item.attrs, sym::rustc_main), + at_root, + Some(fn_.ident.name), + ), _ => EntryPointType::None, } } diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 2435363ef0eb8..516e7cf604fd1 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -670,6 +670,9 @@ pub enum AttributeKind { /// Represents `#[rustc_layout_scalar_valid_range_start]`. RustcLayoutScalarValidRangeStart(Box, Span), + /// Represents `#[rustc_main]`. + RustcMain, + /// Represents `#[rustc_object_lifetime_default]`. RustcObjectLifetimeDefault, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 1611b865c7726..362ab407aab35 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -88,6 +88,7 @@ impl AttributeKind { RustcCoherenceIsCore(..) => No, RustcLayoutScalarValidRangeEnd(..) => Yes, RustcLayoutScalarValidRangeStart(..) => Yes, + RustcMain => No, RustcObjectLifetimeDefault => No, RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate Sanitize { .. } => No, diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index dc956b9f3169b..c668bf0733d14 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -34,9 +34,6 @@ passes_attr_crate_level = .suggestion = to apply to the crate, use an inner attribute .note = read for more information -passes_attr_only_in_functions = - `{$attr}` attribute can only be used on functions - passes_autodiff_attr = `#[autodiff]` should be applied to a function .label = not a function diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index cba6243fa1098..357480f336b24 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -283,6 +283,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::ObjcSelector { .. } | AttributeKind::RustcCoherenceIsCore(..) | AttributeKind::DebuggerVisualizer(..) + | AttributeKind::RustcMain, ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -2395,14 +2396,8 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { // Check for builtin attributes at the crate level // which were unsuccessfully resolved due to cannot determine // resolution for the attribute macro error. - const ATTRS_TO_CHECK: &[Symbol] = &[ - sym::rustc_main, - sym::derive, - sym::test, - sym::test_case, - sym::global_allocator, - sym::bench, - ]; + const ATTRS_TO_CHECK: &[Symbol] = + &[sym::derive, sym::test, sym::test_case, sym::global_allocator, sym::bench]; for attr in attrs { // FIXME(jdonszelmann): all attrs should be combined here cleaning this up some day. diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index 2a435c4b2e05c..8ed2c2a892660 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -1,16 +1,16 @@ use rustc_ast::attr; use rustc_ast::entry::EntryPointType; use rustc_errors::codes::*; -use rustc_hir::def::DefKind; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE, LocalDefId}; -use rustc_hir::{CRATE_HIR_ID, ItemId, Node}; +use rustc_hir::{CRATE_HIR_ID, ItemId, Node, find_attr}; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::RemapFileNameExt; use rustc_session::config::{CrateType, EntryFnType, RemapPathScopeComponents, sigpipe}; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, sym}; -use crate::errors::{AttrOnlyInFunctions, ExternMain, MultipleRustcMain, NoMainErr}; +use crate::errors::{ExternMain, MultipleRustcMain, NoMainErr}; struct EntryContext<'tcx> { tcx: TyCtxt<'tcx>, @@ -44,26 +44,12 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { configure_main(tcx, &ctxt) } -fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Option { - let attrs = ctxt.tcx.hir_attrs(id.hir_id()); - attr::find_by_name(attrs, sym).map(|attr| attr.span()) -} - fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) { - if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) { - for attr in [sym::rustc_main] { - if let Some(span) = attr_span_by_symbol(ctxt, id, attr) { - ctxt.tcx.dcx().emit_err(AttrOnlyInFunctions { span, attr }); - } - } - return; - } - let at_root = ctxt.tcx.opt_local_parent(id.owner_id.def_id) == Some(CRATE_DEF_ID); let attrs = ctxt.tcx.hir_attrs(id.hir_id()); let entry_point_type = rustc_ast::entry::entry_point_type( - attrs, + find_attr!(attrs, AttributeKind::RustcMain), at_root, ctxt.tcx.opt_item_name(id.owner_id.to_def_id()), ); diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 7d184d8bb694c..f5023646b1917 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -843,14 +843,6 @@ pub(crate) struct FeaturePreviouslyDeclared<'a> { pub prev_declared: &'a str, } -#[derive(Diagnostic)] -#[diag(passes_attr_only_in_functions)] -pub(crate) struct AttrOnlyInFunctions { - #[primary_span] - pub span: Span, - pub attr: Symbol, -} - #[derive(Diagnostic)] #[diag(passes_multiple_rustc_main, code = E0137)] pub(crate) struct MultipleRustcMain { diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs index a1a78df8d5375..4bea4487f16ae 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs @@ -10,7 +10,7 @@ #![macro_export] //~^ ERROR: `#[macro_export]` attribute cannot be used on crates #![rustc_main] -//~^ ERROR: `rustc_main` attribute cannot be used at crate level +//~^ ERROR: `#[rustc_main]` attribute cannot be used on crates //~| ERROR: use of an internal attribute [E0658] //~| NOTE: the `#[rustc_main]` attribute is an internal implementation detail that will never be stable //~| NOTE: the `#[rustc_main]` attribute is used internally to specify test entry point function @@ -31,7 +31,6 @@ //~^ ERROR attribute cannot be used on mod inline { //~^ NOTE the inner attribute doesn't annotate this module - //~| NOTE the inner attribute doesn't annotate this module mod inner { #![inline] } //~^ ERROR attribute cannot be used on diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr index 13152ca12e4b8..8091b0b28e624 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr @@ -16,6 +16,14 @@ LL | #![macro_export] | = help: `#[macro_export]` can only be applied to macro defs +error: `#[rustc_main]` attribute cannot be used on crates + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:12:1 + | +LL | #![rustc_main] + | ^^^^^^^^^^^^^^ + | + = help: `#[rustc_main]` can only be applied to functions + error: `#[path]` attribute cannot be used on crates --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1 | @@ -57,7 +65,7 @@ LL | #[inline] = help: `#[inline]` can only be applied to functions error: `#[inline]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:36:17 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:35:17 | LL | mod inner { #![inline] } | ^^^^^^^^^^ @@ -65,7 +73,7 @@ LL | mod inner { #![inline] } = help: `#[inline]` can only be applied to functions error: `#[inline]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:45:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:44:5 | LL | #[inline] struct S; | ^^^^^^^^^ @@ -73,7 +81,7 @@ LL | #[inline] struct S; = help: `#[inline]` can only be applied to functions error: `#[inline]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:48:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:47:5 | LL | #[inline] type T = S; | ^^^^^^^^^ @@ -81,7 +89,7 @@ LL | #[inline] type T = S; = help: `#[inline]` can only be applied to functions error: `#[inline]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:51:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:50:5 | LL | #[inline] impl S { } | ^^^^^^^^^ @@ -89,7 +97,7 @@ LL | #[inline] impl S { } = help: `#[inline]` can only be applied to functions error: `#[export_name]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:81:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:80:1 | LL | #[export_name = "2200"] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -97,7 +105,7 @@ LL | #[export_name = "2200"] = help: `#[export_name]` can be applied to functions and statics error: `#[export_name]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:84:17 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:83:17 | LL | mod inner { #![export_name="2200"] } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -105,7 +113,7 @@ LL | mod inner { #![export_name="2200"] } = help: `#[export_name]` can be applied to functions and statics error: `#[export_name]` attribute cannot be used on structs - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:89:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:88:5 | LL | #[export_name = "2200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -113,7 +121,7 @@ LL | #[export_name = "2200"] struct S; = help: `#[export_name]` can be applied to functions and statics error: `#[export_name]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:92:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:91:5 | LL | #[export_name = "2200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +129,7 @@ LL | #[export_name = "2200"] type T = S; = help: `#[export_name]` can be applied to functions and statics error: `#[export_name]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:95:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:94:5 | LL | #[export_name = "2200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -129,7 +137,7 @@ LL | #[export_name = "2200"] impl S { } = help: `#[export_name]` can be applied to functions and statics error: `#[export_name]` attribute cannot be used on required trait methods - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:99:9 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:98:9 | LL | #[export_name = "2200"] fn foo(); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -137,7 +145,7 @@ LL | #[export_name = "2200"] fn foo(); = help: `#[export_name]` can be applied to functions, inherent methods, provided trait methods, statics, and trait methods in impl blocks error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:55:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:54:1 | LL | #[no_link] | ^^^^^^^^^^ @@ -151,7 +159,7 @@ LL | | } | |_- not an `extern crate` item error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:106:8 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:105:8 | LL | #[repr(C)] | ^ @@ -164,7 +172,7 @@ LL | | } | |_- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:130:8 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:129:8 | LL | #[repr(Rust)] | ^^^^ @@ -182,21 +190,6 @@ error: attribute should be applied to an `extern crate` item LL | #![no_link] | ^^^^^^^^^^^ not an `extern crate` item -error: `rustc_main` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:12:1 - | -LL | #![rustc_main] - | ^^^^^^^^^^^^^^ -... -LL | mod inline { - | ------ the inner attribute doesn't annotate this module - | -help: perhaps you meant to use an outer attribute - | -LL - #![rustc_main] -LL + #[rustc_main] - | - error: `repr` attribute cannot be used at crate level --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1 | @@ -213,85 +206,85 @@ LL + #[repr()] | error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:60:17 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:59:17 | LL | mod inner { #![no_link] } | ------------^^^^^^^^^^^-- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:64:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:63:5 | LL | #[no_link] fn f() { } | ^^^^^^^^^^ ---------- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:68:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:67:5 | LL | #[no_link] struct S; | ^^^^^^^^^^ --------- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:72:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:71:5 | LL | #[no_link]type T = S; | ^^^^^^^^^^----------- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:76:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:75:5 | LL | #[no_link] impl S { } | ^^^^^^^^^^ ---------- not an `extern crate` item error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:110:25 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:109:25 | LL | mod inner { #![repr(C)] } | --------------------^---- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:114:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:113:12 | LL | #[repr(C)] fn f() { } | ^ ---------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:120:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:119:12 | LL | #[repr(C)] type T = S; | ^ ----------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:124:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:123:12 | LL | #[repr(C)] impl S { } | ^ ---------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:134:25 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:133:25 | LL | mod inner { #![repr(Rust)] } | --------------------^^^^---- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:138:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:137:12 | LL | #[repr(Rust)] fn f() { } | ^^^^ ---------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:144:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:143:12 | LL | #[repr(Rust)] type T = S; | ^^^^ ----------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:148:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:147:12 | LL | #[repr(Rust)] impl S { } | ^^^^ ---------- not a struct, enum, or union error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]` - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:39:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:38:5 | LL | #[inline = "2100"] fn f() { } | ^^^^^^^^^^^^^^^^^^ @@ -306,7 +299,7 @@ Some errors have detailed explanations: E0517, E0658. For more information about an error, try `rustc --explain E0517`. Future incompatibility report: Future breakage diagnostic: error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]` - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:39:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:38:5 | LL | #[inline = "2100"] fn f() { } | ^^^^^^^^^^^^^^^^^^