diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 5f682cd6c6364..81d28884aedd0 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1025,6 +1025,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::Yes, "#[rustc_fsa_entry_point] is used to determine when types should be checked by finaliser safety analysis." ), + rustc_attr!( + rustc_alloc_in, Normal, template!(Word), ErrorFollowing, + EncodeCrossCrate::Yes, + "#[rustc_alloc_in] is used to declare that a function uses a separate allocator." + ), rustc_attr!( rustc_fsa_safe_fn, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 18f207c50fbdb..e82358363145b 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -911,6 +911,10 @@ lint_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)` lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´ +lint_untracked_heap_allocation = uses a non-Alloy allocator + .note = Alloy must be able to track all heap allocations in order to correctly trace GC objects + .help = Disable this lint only if you are certain this not contain a pointer to a GC object + lint_untranslatable_diag = diagnostics should be created using translatable messages lint_unused_allocation = unnecessary allocation, use `&` instead diff --git a/compiler/rustc_lint/src/incompatible_gc_features.rs b/compiler/rustc_lint/src/incompatible_gc_features.rs new file mode 100644 index 0000000000000..67b96139bc0d2 --- /dev/null +++ b/compiler/rustc_lint/src/incompatible_gc_features.rs @@ -0,0 +1,46 @@ +use rustc_hir as hir; +use rustc_session::{declare_lint, declare_lint_pass}; +use rustc_span::sym; + +use crate::lints::UntrackedHeapAllocation as AllocationLint; +use crate::{LateContext, LateLintPass, LintContext}; + +declare_lint! { + /// The `untracked_heap_allocation` lint checks that heap allocations use the BDWGC allocator. + /// + /// ### Example + /// ```rust,compile_fail + /// #![feature(allocator_api)] + /// use std::rc::Rc; + /// use std::alloc::System; + /// + /// static A: System = System; + /// + /// fn foo() { Rc::new_in(123, A); } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Alloy must be able to track all heap allocations in order to correctly trace GC objects. + pub UNTRACKED_HEAP_ALLOCATION, + Deny, + "Allocations must go through the BDWGC allocator", +} + +declare_lint_pass!(UntrackedHeapAllocation => [UNTRACKED_HEAP_ALLOCATION]); + +impl<'tcx> LateLintPass<'tcx> for UntrackedHeapAllocation { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { + if let hir::ExprKind::Call(ref callee, _) = expr.kind { + if let hir::ExprKind::Path(ref qpath) = callee.kind { + if let Some(def_id) = cx.qpath_res(qpath, callee.hir_id).opt_def_id() { + if let Some(_) = cx.tcx.get_attr(def_id, sym::rustc_alloc_in) { + cx.emit_span_lint(UNTRACKED_HEAP_ALLOCATION, expr.span, AllocationLint); + } + } + } + } + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 69666cb6347cf..38b34ce352614 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -52,6 +52,7 @@ mod foreign_modules; pub mod hidden_unicode_codepoints; mod if_let_rescope; mod impl_trait_overcaptures; +mod incompatible_gc_features; mod internal; mod invalid_from_utf8; mod late; @@ -94,6 +95,7 @@ use for_loops_over_fallibles::*; use hidden_unicode_codepoints::*; use if_let_rescope::IfLetRescope; use impl_trait_overcaptures::ImplTraitOvercaptures; +use incompatible_gc_features::*; use internal::*; use invalid_from_utf8::*; use let_underscore::*; @@ -247,6 +249,7 @@ late_lint_methods!( StaticMutRefs: StaticMutRefs, UnqualifiedLocalImports: UnqualifiedLocalImports, MisalignedGcPointers: MisalignedGcPointers, + UntrackedHeapAllocation: UntrackedHeapAllocation, ] ] ); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 802b7dead6c72..941238db71ea0 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1911,6 +1911,11 @@ impl<'a> LintDiagnostic<'a, ()> for MisalignedGcPointers<'_> { } } +#[derive(LintDiagnostic)] +#[diag(lint_untracked_heap_allocation)] +#[help] +pub(crate) struct UntrackedHeapAllocation; + #[derive(LintDiagnostic)] #[diag(lint_variant_size_differences)] pub(crate) struct VariantSizeDifferencesDiag { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 27f428185af4a..29e4326b462cb 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -416,6 +416,7 @@ symbols! { all, alloc, alloc_error_handler, + alloc_in, alloc_layout, alloc_zeroed, allocator, @@ -1723,6 +1724,7 @@ symbols! { rust_out, rustc, rustc_abi, + rustc_alloc_in, rustc_allocator, rustc_allocator_zeroed, rustc_allow_const_fn_unstable, diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 949d44eeced76..e8879f3f4e008 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -89,6 +89,7 @@ #![warn(rustdoc::unescaped_backticks)] #![deny(ffi_unwind_calls)] #![warn(unreachable_pub)] +#![cfg_attr(not(bootstrap), allow(untracked_heap_allocation))] // // Library features: // tidy-alphabetical-start diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index d619c8d36b718..617f2c72e172a 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -240,6 +240,7 @@ //! [fully qualified syntax]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation-calling-methods-with-the-same-name #![stable(feature = "rust1", since = "1.0.0")] +#![cfg_attr(not(bootstrap), allow(untracked_heap_allocation))] use core::any::Any; use core::cell::Cell; @@ -658,12 +659,14 @@ impl Rc { /// /// ``` /// #![feature(allocator_api)] + /// #![cfg_attr(not(bootstrap), allow(untracked_heap_allocation))] /// use std::rc::Rc; /// use std::alloc::System; /// /// let five = Rc::new_in(5, System); /// ``` #[cfg(not(no_global_oom_handling))] + #[cfg_attr(not(bootstrap), rustc_alloc_in)] #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn new_in(value: T, alloc: A) -> Rc { @@ -682,6 +685,7 @@ impl Rc { /// ``` /// #![feature(get_mut_unchecked)] /// #![feature(allocator_api)] + /// #![cfg_attr(not(bootstrap), allow(untracked_heap_allocation))] /// /// use std::rc::Rc; /// use std::alloc::System; @@ -699,6 +703,7 @@ impl Rc { /// ``` #[cfg(not(no_global_oom_handling))] #[unstable(feature = "allocator_api", issue = "32838")] + #[cfg_attr(not(bootstrap), rustc_alloc_in)] // #[unstable(feature = "new_uninit", issue = "63291")] #[inline] pub fn new_uninit_in(alloc: A) -> Rc, A> { @@ -724,6 +729,7 @@ impl Rc { /// /// ``` /// #![feature(allocator_api)] + /// #![cfg_attr(not(bootstrap), allow(untracked_heap_allocation))] /// /// use std::rc::Rc; /// use std::alloc::System; @@ -736,6 +742,7 @@ impl Rc { /// /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] + #[cfg_attr(not(bootstrap), rustc_alloc_in)] #[unstable(feature = "allocator_api", issue = "32838")] // #[unstable(feature = "new_uninit", issue = "63291")] #[inline] @@ -838,6 +845,7 @@ impl Rc { /// /// ``` /// #![feature(allocator_api)] + /// #![cfg_attr(not(bootstrap), allow(untracked_heap_allocation))] /// use std::rc::Rc; /// use std::alloc::System; /// @@ -845,6 +853,7 @@ impl Rc { /// # Ok::<(), std::alloc::AllocError>(()) /// ``` #[unstable(feature = "allocator_api", issue = "32838")] + #[cfg_attr(not(bootstrap), rustc_alloc_in)] #[inline] pub fn try_new_in(value: T, alloc: A) -> Result { // There is an implicit weak pointer owned by all the strong @@ -867,6 +876,7 @@ impl Rc { /// ``` /// #![feature(allocator_api)] /// #![feature(get_mut_unchecked)] + /// #![cfg_attr(not(bootstrap), allow(untracked_heap_allocation))] /// /// use std::rc::Rc; /// use std::alloc::System; @@ -884,6 +894,7 @@ impl Rc { /// # Ok::<(), std::alloc::AllocError>(()) /// ``` #[unstable(feature = "allocator_api", issue = "32838")] + #[cfg_attr(not(bootstrap), rustc_alloc_in)] // #[unstable(feature = "new_uninit", issue = "63291")] #[inline] pub fn try_new_uninit_in(alloc: A) -> Result, A>, AllocError> { @@ -910,6 +921,7 @@ impl Rc { /// /// ``` /// #![feature(allocator_api)] + /// #![cfg_attr(not(bootstrap), allow(untracked_heap_allocation))] /// /// use std::rc::Rc; /// use std::alloc::System; @@ -923,6 +935,7 @@ impl Rc { /// /// [zeroed]: mem::MaybeUninit::zeroed #[unstable(feature = "allocator_api", issue = "32838")] + #[cfg_attr(not(bootstrap), rustc_alloc_in)] //#[unstable(feature = "new_uninit", issue = "63291")] #[inline] pub fn try_new_zeroed_in(alloc: A) -> Result, A>, AllocError> { @@ -941,6 +954,7 @@ impl Rc { /// Constructs a new `Pin>` in the provided allocator. If `T` does not implement `Unpin`, then /// `value` will be pinned in memory and unable to be moved. #[cfg(not(no_global_oom_handling))] + #[cfg_attr(not(bootstrap), rustc_alloc_in)] #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn pin_in(value: T, alloc: A) -> Pin @@ -1122,6 +1136,7 @@ impl Rc<[T], A> { /// ``` /// #![feature(get_mut_unchecked)] /// #![feature(allocator_api)] + /// #![cfg_attr(not(bootstrap), allow(untracked_heap_allocation))] /// /// use std::rc::Rc; /// use std::alloc::System; @@ -1140,6 +1155,7 @@ impl Rc<[T], A> { /// assert_eq!(*values, [1, 2, 3]) /// ``` #[cfg(not(no_global_oom_handling))] + #[cfg_attr(not(bootstrap), rustc_alloc_in)] #[unstable(feature = "allocator_api", issue = "32838")] // #[unstable(feature = "new_uninit", issue = "63291")] #[inline] @@ -1157,6 +1173,7 @@ impl Rc<[T], A> { /// /// ``` /// #![feature(allocator_api)] + /// #![cfg_attr(not(bootstrap), allow(untracked_heap_allocation))] /// /// use std::rc::Rc; /// use std::alloc::System; @@ -1169,6 +1186,7 @@ impl Rc<[T], A> { /// /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] + #[cfg_attr(not(bootstrap), rustc_alloc_in)] #[unstable(feature = "allocator_api", issue = "32838")] // #[unstable(feature = "new_uninit", issue = "63291")] #[inline] @@ -1447,6 +1465,7 @@ impl Rc { /// /// ``` /// #![feature(allocator_api)] + /// #![cfg_attr(not(bootstrap), allow(untracked_heap_allocation))] /// use std::rc::Rc; /// use std::alloc::System; /// @@ -1526,6 +1545,7 @@ impl Rc { /// /// ``` /// #![feature(allocator_api)] + /// #![cfg_attr(not(bootstrap), allow(untracked_heap_allocation))] /// /// use std::rc::Rc; /// use std::alloc::System; @@ -1548,6 +1568,7 @@ impl Rc { /// /// ``` /// #![feature(allocator_api)] + /// #![cfg_attr(not(bootstrap), allow(untracked_heap_allocation))] /// /// use std::rc::Rc; /// use std::alloc::System; @@ -1561,6 +1582,7 @@ impl Rc { /// } /// ``` #[unstable(feature = "allocator_api", issue = "32838")] + #[cfg_attr(not(bootstrap), rustc_alloc_in)] pub unsafe fn from_raw_in(ptr: *const T, alloc: A) -> Self { let offset = unsafe { data_offset(ptr) }; @@ -1644,6 +1666,7 @@ impl Rc { /// /// ``` /// #![feature(allocator_api)] + /// #![cfg_attr(not(bootstrap), allow(untracked_heap_allocation))] /// /// use std::rc::Rc; /// use std::alloc::System; @@ -1662,6 +1685,7 @@ impl Rc { /// ``` #[inline] #[unstable(feature = "allocator_api", issue = "32838")] + #[cfg_attr(not(bootstrap), rustc_alloc_in)] pub unsafe fn increment_strong_count_in(ptr: *const T, alloc: A) where A: Clone, @@ -1687,6 +1711,7 @@ impl Rc { /// /// ``` /// #![feature(allocator_api)] + /// #![cfg_attr(not(bootstrap), allow(untracked_heap_allocation))] /// /// use std::rc::Rc; /// use std::alloc::System; @@ -1705,6 +1730,7 @@ impl Rc { /// ``` #[inline] #[unstable(feature = "allocator_api", issue = "32838")] + #[cfg_attr(not(bootstrap), rustc_alloc_in)] pub unsafe fn decrement_strong_count_in(ptr: *const T, alloc: A) { unsafe { drop(Rc::from_raw_in(ptr, alloc)) }; } @@ -2114,6 +2140,7 @@ impl Rc { } #[cfg(not(no_global_oom_handling))] + #[cfg_attr(not(bootstrap), rustc_alloc_in)] fn from_box_in(src: Box) -> Rc { unsafe { let value_size = size_of_val(&*src); @@ -2215,6 +2242,7 @@ impl Rc<[T], A> { /// Allocates an `RcInner<[T]>` with the given length. #[inline] #[cfg(not(no_global_oom_handling))] + #[cfg_attr(not(bootstrap), rustc_alloc_in)] unsafe fn allocate_for_slice_in(len: usize, alloc: &A) -> *mut RcInner<[T]> { unsafe { Rc::<[T]>::allocate_for_layout( @@ -3221,6 +3249,7 @@ impl Weak { /// /// ``` /// #![feature(allocator_api)] + /// #![cfg_attr(not(bootstrap), allow(untracked_heap_allocation))] /// use std::rc::{Rc, Weak}; /// use std::alloc::System; /// diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs index 2210a7c24c06a..0ae2a0864a6d5 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloc/src/rc/tests.rs @@ -1,3 +1,4 @@ +#![cfg_attr(not(bootstrap), allow(untracked_heap_allocation))] use std::cell::RefCell; use std::clone::Clone; diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 785070fb2bbcb..db5d89959bd61 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -39,6 +39,7 @@ #![feature(vec_deque_pop_if)] #![feature(unique_rc_arc)] #![feature(macro_metavar_expr_concat)] +#![cfg_attr(not(bootstrap), allow(untracked_heap_allocation))] #![allow(internal_features)] #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index bf14187c1f554..6898b8353e9f8 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -248,6 +248,7 @@ #![warn(deprecated_in_future)] #![warn(missing_docs)] #![warn(missing_debug_implementations)] +#![cfg_attr(not(bootstrap), allow(untracked_heap_allocation))] #![allow(explicit_outlives_requirements)] #![allow(unused_lifetimes)] #![allow(internal_features)] diff --git a/tests/ui/static/gc/tracing/untracked_allocations.rs b/tests/ui/static/gc/tracing/untracked_allocations.rs new file mode 100644 index 0000000000000..3f1c758ef6e9b --- /dev/null +++ b/tests/ui/static/gc/tracing/untracked_allocations.rs @@ -0,0 +1,12 @@ +#![deny(untracked_heap_allocation)] +#![feature(allocator_api)] +#![feature(gc)] + +use std::alloc::System; +use std::rc::Rc; + +static A: System = System; + +fn main() { + let rc = Rc::new_in(123, A); //~ ERROR: uses a non-Alloy allocator +} diff --git a/tests/ui/static/gc/tracing/untracked_allocations.stderr b/tests/ui/static/gc/tracing/untracked_allocations.stderr new file mode 100644 index 0000000000000..047782334a0dc --- /dev/null +++ b/tests/ui/static/gc/tracing/untracked_allocations.stderr @@ -0,0 +1,15 @@ +error: uses a non-Alloy allocator + --> $DIR/untracked_allocations.rs:11:14 + | +LL | let rc = Rc::new_in(123, A); + | ^^^^^^^^^^^^^^^^^^ + | + = help: Disable this lint only if you are certain this not contain a pointer to a GC object +note: the lint level is defined here + --> $DIR/untracked_allocations.rs:1:9 + | +LL | #![deny(untracked_heap_allocation)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error +