From cfc21deebd948e99c553cb6ad14ddb91368257d3 Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 22 May 2022 23:10:27 +0200 Subject: [PATCH 1/3] Add #[rustc_box] This commit adds an alternative content boxing syntax, and uses it inside alloc. The usage inside the very performance relevant code in liballoc is the only remaining relevant usage of box syntax in the compiler (outside of tests, which are comparatively easy to port). box syntax was originally designed to be used by all Rust developers. This introduces a replacement syntax more tailored to only being used inside the Rust compiler, and with it, lays the groundwork for eventually removing box syntax. --- compiler/rustc_ast_lowering/src/expr.rs | 14 +++++++++++++- compiler/rustc_feature/src/builtin_attrs.rs | 6 ++++++ compiler/rustc_span/src/symbol.rs | 1 + src/test/ui/type/ascription/issue-47666.stderr | 2 +- 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 3aff04f78fb85..04d88282862a8 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -41,7 +41,19 @@ impl<'hir> LoweringContext<'_, 'hir> { } ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)), ExprKind::Call(ref f, ref args) => { - if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) { + if e.attrs.get(0).map_or(false, |a| a.has_name(sym::rustc_box)) { + if let [inner] = &args[..] { + hir::ExprKind::Box(self.lower_expr(&inner)) + } else { + self.sess + .struct_span_err( + e.span, + "rustc_box requires precisely one argument", + ) + .emit(); + hir::ExprKind::Err + } + } else if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) { self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args) } else { let f = self.lower_expr(f); diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 8155e65a6dbf5..5eb2be97f8b92 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -675,6 +675,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \ the given type by annotating all impl items with #[rustc_allow_incoherent_impl]." ), + rustc_attr!( + rustc_box, AttributeType::Normal, template!(Word), ErrorFollowing, + "#[rustc_box] allows creating boxes \ + and it is only intended to be used in `alloc`." + ), + BuiltinAttribute { name: sym::rustc_diagnostic_item, // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 16162f1cc898a..1954cdc0bff66 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1173,6 +1173,7 @@ symbols! { rustc_allow_const_fn_unstable, rustc_allow_incoherent_impl, rustc_attrs, + rustc_box, rustc_builtin_macro, rustc_capture_analysis, rustc_clean, diff --git a/src/test/ui/type/ascription/issue-47666.stderr b/src/test/ui/type/ascription/issue-47666.stderr index 59b3529272688..b59a73af9f93b 100644 --- a/src/test/ui/type/ascription/issue-47666.stderr +++ b/src/test/ui/type/ascription/issue-47666.stderr @@ -1,4 +1,4 @@ -error: expected type, found `<[_]>::into_vec(box [0, 1])` +error: expected type, found `<[_]>::into_vec(#[rustc_box] ::alloc::boxed::Box::new([0, 1]))` --> $DIR/issue-47666.rs:3:25 | LL | let _ = Option:Some(vec![0, 1]); From 535e28b6c66a4e3fd5370a4f8b2fcecf12c4cc6a Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 28 May 2022 16:37:52 +0200 Subject: [PATCH 2/3] Use #[rustc_box] in alloc instead of box syntax --- library/alloc/src/boxed.rs | 30 ++++++++++++++++++++++++++---- library/alloc/src/lib.rs | 3 ++- library/alloc/src/macros.rs | 25 +++++++++++++++++++++++-- library/alloc/src/vec/mod.rs | 7 +++++-- 4 files changed, 56 insertions(+), 9 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index c07536f0d0ce1..c363ccbe48ba5 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -192,7 +192,25 @@ impl Box { /// ``` /// let five = Box::new(5); /// ``` - #[cfg(not(no_global_oom_handling))] + #[cfg(all(not(no_global_oom_handling), not(bootstrap)))] + #[inline(always)] + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] + pub fn new(x: T) -> Self { + #[rustc_box] + Box::new(x) + } + + /// Allocates memory on the heap and then places `x` into it. + /// + /// This doesn't actually allocate if `T` is zero-sized. + /// + /// # Examples + /// + /// ``` + /// let five = Box::new(5); + /// ``` + #[cfg(all(not(no_global_oom_handling), bootstrap))] #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] @@ -259,7 +277,9 @@ impl Box { #[must_use] #[inline(always)] pub fn pin(x: T) -> Pin> { - (box x).into() + (#[cfg_attr(not(bootstrap), rustc_box)] + Box::new(x)) + .into() } /// Allocates memory on the heap then places `x` into it, @@ -1186,7 +1206,8 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box { impl Default for Box { /// Creates a `Box`, with the `Default` value for T. fn default() -> Self { - box T::default() + #[cfg_attr(not(bootstrap), rustc_box)] + Box::new(T::default()) } } @@ -1550,7 +1571,8 @@ impl From<[T; N]> for Box<[T]> { /// println!("{boxed:?}"); /// ``` fn from(array: [T; N]) -> Box<[T]> { - box array + #[cfg_attr(not(bootstrap), rustc_box)] + Box::new(array) } } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index fd21b3671182b..4856a64b965f6 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -147,7 +147,7 @@ #![feature(allocator_internals)] #![feature(allow_internal_unstable)] #![feature(associated_type_bounds)] -#![feature(box_syntax)] +#![cfg_attr(bootstrap, feature(box_syntax))] #![feature(cfg_sanitize)] #![feature(const_deref)] #![feature(const_mut_refs)] @@ -170,6 +170,7 @@ #![feature(rustc_attrs)] #![feature(slice_internals)] #![feature(staged_api)] +#![feature(stmt_expr_attributes)] #![cfg_attr(test, feature(test))] #![feature(unboxed_closures)] #![feature(unsized_fn_params)] diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index d9346daa109c1..37898b6655faa 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -34,7 +34,28 @@ /// be mindful of side effects. /// /// [`Vec`]: crate::vec::Vec -#[cfg(all(not(no_global_oom_handling), not(test)))] +#[cfg(all(not(no_global_oom_handling), not(test), not(bootstrap)))] +#[macro_export] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_diagnostic_item = "vec_macro"] +#[allow_internal_unstable(rustc_attrs, liballoc_internals)] +macro_rules! vec { + () => ( + $crate::__rust_force_expr!($crate::vec::Vec::new()) + ); + ($elem:expr; $n:expr) => ( + $crate::__rust_force_expr!($crate::vec::from_elem($elem, $n)) + ); + ($($x:expr),+ $(,)?) => ( + $crate::__rust_force_expr!(<[_]>::into_vec( + #[rustc_box] + $crate::boxed::Box::new([$($x),+]) + )) + ); +} + +/// Creates a `Vec` containing the arguments (bootstrap version). +#[cfg(all(not(no_global_oom_handling), not(test), bootstrap))] #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "vec_macro"] @@ -65,7 +86,7 @@ macro_rules! vec { $crate::vec::from_elem($elem, $n) ); ($($x:expr),*) => ( - $crate::slice::into_vec(box [$($x),*]) + $crate::slice::into_vec($crate::boxed::Box::new([$($x),*])) ); ($($x:expr,)*) => (vec![$($x),*]) } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index d222fcb445f58..4429984ea6cb9 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2983,12 +2983,15 @@ impl From<[T; N]> for Vec { /// ``` #[cfg(not(test))] fn from(s: [T; N]) -> Vec { - <[T]>::into_vec(box s) + <[T]>::into_vec( + #[cfg_attr(not(bootstrap), rustc_box)] + Box::new(s), + ) } #[cfg(test)] fn from(s: [T; N]) -> Vec { - crate::slice::into_vec(box s) + crate::slice::into_vec(Box::new(s)) } } From 0a24b9493b12b71db28d11afd360dc2fea88e466 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 25 May 2022 02:30:55 +0200 Subject: [PATCH 3/3] Remove #[rustc_box] attr during lowering --- compiler/rustc_ast_lowering/src/expr.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 04d88282862a8..539e33702aa67 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -42,13 +42,16 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)), ExprKind::Call(ref f, ref args) => { if e.attrs.get(0).map_or(false, |a| a.has_name(sym::rustc_box)) { - if let [inner] = &args[..] { - hir::ExprKind::Box(self.lower_expr(&inner)) + if let [inner] = &args[..] && e.attrs.len() == 1 { + let kind = hir::ExprKind::Box(self.lower_expr(&inner)); + let hir_id = self.lower_node_id(e.id); + return hir::Expr { hir_id, kind, span: self.lower_span(e.span) }; } else { self.sess .struct_span_err( e.span, - "rustc_box requires precisely one argument", + "#[rustc_box] requires precisely one argument \ + and no other attributes are allowed", ) .emit(); hir::ExprKind::Err