turn rustc_box into an intrinsic

This commit is contained in:
Ralf Jung 2025-01-02 21:22:42 +01:00
parent bf6f8a4d32
commit ac9cb908ac
25 changed files with 198 additions and 208 deletions

View file

@ -933,11 +933,6 @@ 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, EncodeCrossCrate::No,
"#[rustc_box] allows creating boxes \
and it is only intended to be used in `alloc`."
),
BuiltinAttribute {
name: sym::rustc_diagnostic_item,

View file

@ -86,6 +86,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
| sym::assert_inhabited
| sym::assert_zero_valid
| sym::assert_mem_uninitialized_valid
| sym::box_new
| sym::breakpoint
| sym::size_of
| sym::min_align_of
@ -606,6 +607,8 @@ pub fn check_intrinsic_type(
sym::ub_checks => (0, 0, Vec::new(), tcx.types.bool),
sym::box_new => (1, 0, vec![param(0)], Ty::new_box(tcx, param(0))),
sym::simd_eq
| sym::simd_ne
| sym::simd_lt

View file

@ -287,11 +287,6 @@ mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabite
mir_build_rust_2024_incompatible_pat = this pattern relies on behavior which may change in edition 2024
mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly
.attributes = no other attributes may be applied
.not_box = `#[rustc_box]` may only be applied to a `Box::new()` call
.missing_box = `#[rustc_box]` requires the `owned_box` lang item
mir_build_static_in_pattern = statics cannot be referenced in patterns
.label = can't be used in patterns
mir_build_static_in_pattern_def = `static` defined here

View file

@ -1067,25 +1067,6 @@ pub(crate) enum MiscPatternSuggestion {
},
}
#[derive(Diagnostic)]
#[diag(mir_build_rustc_box_attribute_error)]
pub(crate) struct RustcBoxAttributeError {
#[primary_span]
pub(crate) span: Span,
#[subdiagnostic]
pub(crate) reason: RustcBoxAttrReason,
}
#[derive(Subdiagnostic)]
pub(crate) enum RustcBoxAttrReason {
#[note(mir_build_attributes)]
Attributes,
#[note(mir_build_not_box)]
NotBoxNew,
#[note(mir_build_missing_box)]
MissingBox,
}
#[derive(LintDiagnostic)]
#[diag(mir_build_rust_2024_incompatible_pat)]
pub(crate) struct Rust2024IncompatiblePat<'a> {

View file

@ -20,7 +20,6 @@ use rustc_middle::{bug, span_bug};
use rustc_span::{Span, sym};
use tracing::{debug, info, instrument, trace};
use crate::errors;
use crate::thir::cx::Cx;
use crate::thir::util::UserAnnotatedTyHelpers;
@ -380,45 +379,25 @@ impl<'tcx> Cx<'tcx> {
from_hir_call: true,
fn_span: expr.span,
}
} else {
let attrs = tcx.hir().attrs(expr.hir_id);
if attrs.iter().any(|a| a.name_or_empty() == sym::rustc_box) {
if attrs.len() != 1 {
tcx.dcx().emit_err(errors::RustcBoxAttributeError {
span: attrs[0].span,
reason: errors::RustcBoxAttrReason::Attributes,
});
} else if let Some(box_item) = tcx.lang_items().owned_box() {
if let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, fn_path)) =
fun.kind
&& let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
&& path.res.opt_def_id().is_some_and(|did| did == box_item)
&& fn_path.ident.name == sym::new
&& let [value] = args
{
return Expr {
temp_lifetime: TempLifetime {
temp_lifetime,
backwards_incompatible,
},
ty: expr_ty,
span: expr.span,
kind: ExprKind::Box { value: self.mirror_expr(value) },
};
} else {
tcx.dcx().emit_err(errors::RustcBoxAttributeError {
span: expr.span,
reason: errors::RustcBoxAttrReason::NotBoxNew,
});
}
} else {
tcx.dcx().emit_err(errors::RustcBoxAttributeError {
span: attrs[0].span,
reason: errors::RustcBoxAttrReason::MissingBox,
});
}
} else if let ty::FnDef(def_id, _) = self.typeck_results().expr_ty(fun).kind()
&& let Some(intrinsic) = self.tcx.intrinsic(def_id)
&& intrinsic.name == sym::box_new
{
// We don't actually evaluate `fun` here, so make sure that doesn't miss any side-effects.
if !matches!(fun.kind, hir::ExprKind::Path(_)) {
span_bug!(
expr.span,
"`box_new` intrinsic can only be called via path expression"
);
}
let value = &args[0];
return Expr {
temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
ty: expr_ty,
span: expr.span,
kind: ExprKind::Box { value: self.mirror_expr(value) },
};
} else {
// Tuple-like ADTs are represented as ExprKind::Call. We convert them here.
let adt_data = if let hir::ExprKind::Path(ref qpath) = fun.kind
&& let Some(adt_def) = expr_ty.ty_adt_def()

View file

@ -1696,7 +1696,6 @@ symbols! {
rustc_as_ptr,
rustc_attrs,
rustc_autodiff,
rustc_box,
rustc_builtin_macro,
rustc_capture_analysis,
rustc_clean,

View file

@ -339,7 +339,7 @@ unsafe impl Allocator for Global {
}
}
/// The allocator for unique pointers.
/// The allocator for `Box`.
#[cfg(all(not(no_global_oom_handling), not(test)))]
#[lang = "exchange_malloc"]
#[inline]

View file

@ -233,6 +233,27 @@ pub struct Box<
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
>(Unique<T>, A);
/// Constructs a `Box<T>` by calling the `exchange_malloc` lang item and moving the argument into
/// the newly allocated memory. This is an intrinsic to avoid unnecessary copies.
///
/// This is the surface syntax for `box <expr>` expressions.
#[cfg(not(bootstrap))]
#[rustc_intrinsic]
#[rustc_intrinsic_must_be_overridden]
#[unstable(feature = "liballoc_internals", issue = "none")]
pub fn box_new<T>(_x: T) -> Box<T> {
unreachable!()
}
/// Transition function for the next bootstrap bump.
#[cfg(bootstrap)]
#[unstable(feature = "liballoc_internals", issue = "none")]
#[inline(always)]
pub fn box_new<T>(x: T) -> Box<T> {
#[rustc_box]
Box::new(x)
}
impl<T> Box<T> {
/// Allocates memory on the heap and then places `x` into it.
///
@ -250,8 +271,7 @@ impl<T> Box<T> {
#[rustc_diagnostic_item = "box_new"]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub fn new(x: T) -> Self {
#[rustc_box]
Box::new(x)
return box_new(x);
}
/// Constructs a new box with uninitialized contents.

View file

@ -168,6 +168,7 @@
#![feature(dropck_eyepatch)]
#![feature(fundamental)]
#![feature(hashmap_internals)]
#![feature(intrinsics)]
#![feature(lang_items)]
#![feature(min_specialization)]
#![feature(multiple_supertrait_upcastable)]

View file

@ -48,10 +48,9 @@ macro_rules! vec {
);
($($x:expr),+ $(,)?) => (
<[_]>::into_vec(
// This rustc_box is not required, but it produces a dramatic improvement in compile
// Using the intrinsic produces a dramatic improvement in compile
// time when constructing arrays with many elements.
#[rustc_box]
$crate::boxed::Box::new([$($x),+])
$crate::boxed::box_new([$($x),+])
)
);
}

View file

@ -1,12 +1,3 @@
error: use of a disallowed macro `std::vec`
--> tests/ui-toml/disallowed_macros/disallowed_macros.rs:16:5
|
LL | vec![1, 2, 3];
| ^^^^^^^^^^^^^
|
= note: `-D clippy::disallowed-macros` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::disallowed_macros)]`
error: use of a disallowed macro `serde::Serialize`
--> tests/ui-toml/disallowed_macros/disallowed_macros.rs:18:14
|
@ -14,6 +5,8 @@ LL | #[derive(Serialize)]
| ^^^^^^^^^
|
= note: no serializing
= note: `-D clippy::disallowed-macros` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::disallowed_macros)]`
error: use of a disallowed macro `macros::attr`
--> tests/ui-toml/disallowed_macros/disallowed_macros.rs:31:1
@ -47,6 +40,12 @@ error: use of a disallowed macro `std::cfg`
LL | cfg!(unix);
| ^^^^^^^^^^
error: use of a disallowed macro `std::vec`
--> tests/ui-toml/disallowed_macros/disallowed_macros.rs:16:5
|
LL | vec![1, 2, 3];
| ^^^^^^^^^^^^^
error: use of a disallowed macro `macros::expr`
--> tests/ui-toml/disallowed_macros/disallowed_macros.rs:21:13
|

View file

@ -1,7 +1,7 @@
//@ test-mir-pass: ElaborateDrops
//@ needs-unwind
#![feature(rustc_attrs, stmt_expr_attributes)]
#![feature(rustc_attrs, liballoc_internals)]
// EMIT_MIR box_expr.main.ElaborateDrops.diff
fn main() {
@ -17,8 +17,7 @@ fn main() {
// CHECK: [[boxref:_.*]] = &mut [[box]];
// CHECK: <Box<S> as Drop>::drop(move [[boxref]])
let x = #[rustc_box]
Box::new(S::new());
let x = std::boxed::box_new(S::new());
drop(x);
}

View file

@ -1,25 +1,15 @@
// skip-filecheck
#![feature(stmt_expr_attributes, rustc_attrs)]
#![feature(liballoc_internals, rustc_attrs)]
// EMIT_MIR uniform_array_move_out.move_out_from_end.built.after.mir
fn move_out_from_end() {
let a = [
#[rustc_box]
Box::new(1),
#[rustc_box]
Box::new(2),
];
let a = [std::boxed::box_new(1), std::boxed::box_new(2)];
let [.., _y] = a;
}
// EMIT_MIR uniform_array_move_out.move_out_by_subslice.built.after.mir
fn move_out_by_subslice() {
let a = [
#[rustc_box]
Box::new(1),
#[rustc_box]
Box::new(2),
];
let a = [std::boxed::box_new(1), std::boxed::box_new(2)];
let [_y @ ..] = a;
}

View file

@ -2,7 +2,7 @@
//@ compile-flags: -O
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
#![feature(rustc_attrs, stmt_expr_attributes)]
#![feature(rustc_attrs, liballoc_internals)]
// Note: this test verifies that we, in fact, do not const prop `#[rustc_box]`
@ -13,7 +13,5 @@ fn main() {
// CHECK: (*{{_.*}}) = const 42_i32;
// CHECK: [[tmp:_.*]] = copy (*{{_.*}});
// CHECK: [[x]] = copy [[tmp]];
let x = *(#[rustc_box]
Box::new(42))
+ 0;
let x = *(std::boxed::box_new(42)) + 0;
}

View file

@ -3,14 +3,11 @@
// initializing it
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
#![feature(rustc_attrs)]
#![feature(rustc_attrs, liballoc_internals)]
// EMIT_MIR issue_62289.test.ElaborateDrops.before.mir
fn test() -> Option<Box<u32>> {
Some(
#[rustc_box]
Box::new(None?),
)
Some(std::boxed::box_new(None?))
}
fn main() {

View file

@ -1,18 +0,0 @@
#![feature(rustc_attrs, stmt_expr_attributes)]
fn foo(_: u32, _: u32) {}
fn bar(_: u32) {}
fn main() {
#[rustc_box]
Box::new(1); // OK
#[rustc_box]
Box::pin(1); //~ ERROR `#[rustc_box]` attribute used incorrectly
#[rustc_box]
foo(1, 1); //~ ERROR `#[rustc_box]` attribute used incorrectly
#[rustc_box]
bar(1); //~ ERROR `#[rustc_box]` attribute used incorrectly
#[rustc_box] //~ ERROR `#[rustc_box]` attribute used incorrectly
#[rustfmt::skip]
Box::new(1);
}

View file

@ -1,34 +0,0 @@
error: `#[rustc_box]` attribute used incorrectly
--> $DIR/rustc-box.rs:10:5
|
LL | Box::pin(1);
| ^^^^^^^^^^^
|
= note: `#[rustc_box]` may only be applied to a `Box::new()` call
error: `#[rustc_box]` attribute used incorrectly
--> $DIR/rustc-box.rs:12:5
|
LL | foo(1, 1);
| ^^^^^^^^^
|
= note: `#[rustc_box]` may only be applied to a `Box::new()` call
error: `#[rustc_box]` attribute used incorrectly
--> $DIR/rustc-box.rs:14:5
|
LL | bar(1);
| ^^^^^^
|
= note: `#[rustc_box]` may only be applied to a `Box::new()` call
error: `#[rustc_box]` attribute used incorrectly
--> $DIR/rustc-box.rs:15:5
|
LL | #[rustc_box]
| ^^^^^^^^^^^^
|
= note: no other attributes may be applied
error: aborting due to 4 previous errors

View file

@ -2,7 +2,7 @@
#![feature(coroutines)]
#![feature(coroutine_clone)]
#![feature(coroutine_trait)]
#![feature(rustc_attrs, stmt_expr_attributes)]
#![feature(rustc_attrs, stmt_expr_attributes, liballoc_internals)]
use std::ops::Coroutine;
use std::pin::Pin;
@ -19,8 +19,7 @@ fn main() {
// - create a Box that is ignored for trait computations;
// - compute fields (and yields);
// - assign to `t`.
let t = #[rustc_box]
Box::new((5, yield));
let t = std::boxed::box_new((5, yield));
drop(t);
};

View file

@ -1,5 +1,5 @@
error[E0382]: borrow of moved value: `g`
--> $DIR/issue-105084.rs:39:14
--> $DIR/issue-105084.rs:38:14
|
LL | let mut g = #[coroutine]
| ----- move occurs because `g` has type `{coroutine@$DIR/issue-105084.rs:16:5: 16:7}`, which does not implement the `Copy` trait
@ -23,7 +23,7 @@ LL | let mut h = copy(g.clone());
| ++++++++
error[E0277]: the trait bound `Box<(i32, ())>: Copy` is not satisfied in `{coroutine@$DIR/issue-105084.rs:16:5: 16:7}`
--> $DIR/issue-105084.rs:33:17
--> $DIR/issue-105084.rs:32:17
|
LL | || {
| -- within this `{coroutine@$DIR/issue-105084.rs:16:5: 16:7}`
@ -32,13 +32,13 @@ LL | let mut h = copy(g);
| ^^^^^^^ within `{coroutine@$DIR/issue-105084.rs:16:5: 16:7}`, the trait `Copy` is not implemented for `Box<(i32, ())>`
|
note: coroutine does not implement `Copy` as this value is used across a yield
--> $DIR/issue-105084.rs:23:22
--> $DIR/issue-105084.rs:22:41
|
LL | Box::new((5, yield));
| -------------^^^^^--
| | |
| | yield occurs here, with `Box::new((5, yield))` maybe used later
| has type `Box<(i32, ())>` which does not implement `Copy`
LL | let t = std::boxed::box_new((5, yield));
| ------------------------^^^^^--
| | |
| | yield occurs here, with `std::boxed::box_new((5, yield))` maybe used later
| has type `Box<(i32, ())>` which does not implement `Copy`
note: required by a bound in `copy`
--> $DIR/issue-105084.rs:10:12
|

View file

@ -1,7 +1,5 @@
#![feature(rustc_attrs, stmt_expr_attributes)]
#![deny(unused_allocation)]
fn main() {
_ = (#[rustc_box] Box::new([1])).len(); //~ error: unnecessary allocation, use `&` instead
_ = Box::new([1]).len(); //~ error: unnecessary allocation, use `&` instead
}

View file

@ -1,20 +1,14 @@
error: unnecessary allocation, use `&` instead
--> $DIR/unused-allocation.rs:5:9
--> $DIR/unused-allocation.rs:4:9
|
LL | _ = (#[rustc_box] Box::new([1])).len();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | _ = Box::new([1]).len();
| ^^^^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/unused-allocation.rs:2:9
--> $DIR/unused-allocation.rs:1:9
|
LL | #![deny(unused_allocation)]
| ^^^^^^^^^^^^^^^^^
error: unnecessary allocation, use `&` instead
--> $DIR/unused-allocation.rs:6:9
|
LL | _ = Box::new([1]).len();
| ^^^^^^^^^^^^^
error: aborting due to 2 previous errors
error: aborting due to 1 previous error

View file

@ -4,7 +4,9 @@
fn main() {
match Some(vec![42]) {
Some(vec![43]) => {} //~ ERROR expected pattern, found `#`
Some(vec![43]) => {} //~ ERROR expected a pattern, found a function call
//~| ERROR found associated function
//~| ERROR usage of qualified paths in this context is experimental
_ => {}
}
}

View file

@ -1,14 +1,33 @@
error: expected pattern, found `#`
error[E0532]: expected a pattern, found a function call
--> $DIR/vec-macro-in-pattern.rs:7:14
|
LL | Some(vec![43]) => {}
| ^^^^^^^^ not a tuple struct or tuple variant
|
= note: function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0658]: usage of qualified paths in this context is experimental
--> $DIR/vec-macro-in-pattern.rs:7:14
|
LL | Some(vec![43]) => {}
| ^^^^^^^^
| |
| expected pattern
| in this macro invocation
| this macro call doesn't expand to a pattern
|
= note: see issue #86935 <https://github.com/rust-lang/rust/issues/86935> for more information
= help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 1 previous error
error[E0164]: expected tuple struct or tuple variant, found associated function `<[_]>::into_vec`
--> $DIR/vec-macro-in-pattern.rs:7:14
|
LL | Some(vec![43]) => {}
| ^^^^^^^^ `fn` calls are not allowed in patterns
|
= help: for more information, visit https://doc.rust-lang.org/book/ch19-00-patterns.html
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0164, E0532, E0658.
For more information about an error, try `rustc --explain E0164`.

View file

@ -1,9 +1,8 @@
//@ compile-flags: -Zunpretty=hir
//@ compile-flags: -Zunpretty=thir-tree
//@ check-pass
#![feature(stmt_expr_attributes, rustc_attrs)]
#![feature(liballoc_internals)]
fn main() {
let _ = #[rustc_box]
Box::new(1);
let _ = std::boxed::box_new(1);
}

View file

@ -1,14 +1,90 @@
//@ compile-flags: -Zunpretty=hir
//@ check-pass
DefId(0:3 ~ box[efb9]::main):
params: [
]
body:
Expr {
ty: ()
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(11)), backwards_incompatible: None }
span: $DIR/box.rs:6:11: 8:2 (#0)
kind:
Scope {
region_scope: Node(11)
lint_level: Explicit(HirId(DefId(0:3 ~ box[efb9]::main).11))
value:
Expr {
ty: ()
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(11)), backwards_incompatible: None }
span: $DIR/box.rs:6:11: 8:2 (#0)
kind:
Block {
targeted_by_break: false
span: $DIR/box.rs:6:11: 8:2 (#0)
region_scope: Node(1)
safety_mode: Safe
stmts: [
Stmt {
kind: Let {
remainder_scope: Remainder { block: 1, first_statement_index: 0}
init_scope: Node(2)
pattern:
Pat: {
ty: std::boxed::Box<i32, std::alloc::Global>
span: $DIR/box.rs:7:9: 7:10 (#0)
kind: PatKind {
Wild
}
}
,
initializer: Some(
Expr {
ty: std::boxed::Box<i32, std::alloc::Global>
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None }
span: $DIR/box.rs:7:13: 7:35 (#0)
kind:
Scope {
region_scope: Node(3)
lint_level: Explicit(HirId(DefId(0:3 ~ box[efb9]::main).3))
value:
Expr {
ty: std::boxed::Box<i32, std::alloc::Global>
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None }
span: $DIR/box.rs:7:13: 7:35 (#0)
kind:
Box {
Expr {
ty: i32
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None }
span: $DIR/box.rs:7:33: 7:34 (#0)
kind:
Scope {
region_scope: Node(8)
lint_level: Explicit(HirId(DefId(0:3 ~ box[efb9]::main).8))
value:
Expr {
ty: i32
temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None }
span: $DIR/box.rs:7:33: 7:34 (#0)
kind:
Literal( lit: Spanned { node: Int(Pu128(1), Unsuffixed), span: $DIR/box.rs:7:33: 7:34 (#0) }, neg: false)
}
}
}
}
}
}
}
)
else_block: None
lint_level: Explicit(HirId(DefId(0:3 ~ box[efb9]::main).9))
span: $DIR/box.rs:7:5: 7:35 (#0)
}
}
]
expr: []
}
}
}
}
#![feature(stmt_expr_attributes, rustc_attrs)]
#[prelude_import]
use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
fn main() {
let _ =
#[rustc_box]
Box::new(1);
}