Skip to content

Commit 930c08d

Browse files
committed
Remove support for dynamic allocas
1 parent 8051f01 commit 930c08d

File tree

12 files changed

+108
-91
lines changed

12 files changed

+108
-91
lines changed

compiler/rustc_codegen_gcc/src/builder.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -931,10 +931,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
931931
.get_address(self.location)
932932
}
933933

934-
fn dynamic_alloca(&mut self, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> {
935-
unimplemented!();
936-
}
937-
938934
fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
939935
let block = self.llbb();
940936
let function = block.get_function();

compiler/rustc_codegen_llvm/src/builder.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -538,16 +538,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
538538
}
539539
}
540540

541-
fn dynamic_alloca(&mut self, size: &'ll Value, align: Align) -> &'ll Value {
542-
unsafe {
543-
let alloca =
544-
llvm::LLVMBuildArrayAlloca(self.llbuilder, self.cx().type_i8(), size, UNNAMED);
545-
llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint);
546-
// Cast to default addrspace if necessary
547-
llvm::LLVMBuildPointerCast(self.llbuilder, alloca, self.cx().type_ptr(), UNNAMED)
548-
}
549-
}
550-
551541
fn load(&mut self, ty: &'ll Type, ptr: &'ll Value, align: Align) -> &'ll Value {
552542
unsafe {
553543
let load = llvm::LLVMBuildLoad2(self.llbuilder, ty, ptr, UNNAMED);

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1492,12 +1492,6 @@ unsafe extern "C" {
14921492
Ty: &'a Type,
14931493
Name: *const c_char,
14941494
) -> &'a Value;
1495-
pub(crate) fn LLVMBuildArrayAlloca<'a>(
1496-
B: &Builder<'a>,
1497-
Ty: &'a Type,
1498-
Val: &'a Value,
1499-
Name: *const c_char,
1500-
) -> &'a Value;
15011495
pub(crate) fn LLVMBuildLoad2<'a>(
15021496
B: &Builder<'a>,
15031497
Ty: &'a Type,

compiler/rustc_codegen_ssa/src/mir/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ enum LocalRef<'tcx, V> {
140140
Place(PlaceRef<'tcx, V>),
141141
/// `UnsizedPlace(p)`: `p` itself is a thin pointer (indirect place).
142142
/// `*p` is the wide pointer that references the actual unsized place.
143-
/// Every time it is initialized, we have to reallocate the place
144-
/// and update the wide pointer. That's the reason why it is indirect.
143+
///
144+
/// Rust has no alloca and thus no ability to move the unsized place.
145145
UnsizedPlace(PlaceRef<'tcx, V>),
146146
/// The backend [`OperandValue`] has already been generated.
147147
Operand(OperandRef<'tcx, V>),
@@ -498,7 +498,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
498498
LocalRef::Place(PlaceRef::new_sized(llarg, arg.layout))
499499
}
500500
}
501-
// Unsized indirect qrguments
501+
// Unsized indirect arguments
502502
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
503503
// As the storage for the indirect argument lives during
504504
// the whole function call, we just copy the wide pointer.

compiler/rustc_codegen_ssa/src/mir/operand.rs

Lines changed: 1 addition & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ use tracing::{debug, instrument};
1515
use super::place::{PlaceRef, PlaceValue};
1616
use super::rvalue::transmute_immediate;
1717
use super::{FunctionCx, LocalRef};
18+
use crate::MemFlags;
1819
use crate::common::IntPredicate;
1920
use crate::traits::*;
20-
use crate::{MemFlags, size_of_val};
2121

2222
/// The representation of a Rust value. The enum variant is in fact
2323
/// uniquely determined by the value's type, but is kept as a
@@ -771,44 +771,6 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
771771
}
772772
}
773773
}
774-
775-
pub fn store_unsized<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
776-
self,
777-
bx: &mut Bx,
778-
indirect_dest: PlaceRef<'tcx, V>,
779-
) {
780-
debug!("OperandRef::store_unsized: operand={:?}, indirect_dest={:?}", self, indirect_dest);
781-
// `indirect_dest` must have `*mut T` type. We extract `T` out of it.
782-
let unsized_ty = indirect_dest
783-
.layout
784-
.ty
785-
.builtin_deref(true)
786-
.unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest));
787-
788-
let OperandValue::Ref(PlaceValue { llval: llptr, llextra: Some(llextra), .. }) = self
789-
else {
790-
bug!("store_unsized called with a sized value (or with an extern type)")
791-
};
792-
793-
// Allocate an appropriate region on the stack, and copy the value into it. Since alloca
794-
// doesn't support dynamic alignment, we allocate an extra align - 1 bytes, and align the
795-
// pointer manually.
796-
let (size, align) = size_of_val::size_and_align_of_dst(bx, unsized_ty, Some(llextra));
797-
let one = bx.const_usize(1);
798-
let align_minus_1 = bx.sub(align, one);
799-
let size_extra = bx.add(size, align_minus_1);
800-
let min_align = Align::ONE;
801-
let alloca = bx.dynamic_alloca(size_extra, min_align);
802-
let address = bx.ptrtoint(alloca, bx.type_isize());
803-
let neg_address = bx.neg(address);
804-
let offset = bx.and(neg_address, align_minus_1);
805-
let dst = bx.inbounds_ptradd(alloca, offset);
806-
bx.memcpy(dst, min_align, llptr, min_align, size, MemFlags::empty());
807-
808-
// Store the allocated region and the extra to the indirect place.
809-
let indirect_operand = OperandValue::Pair(dst, llextra);
810-
indirect_operand.store(bx, indirect_dest);
811-
}
812774
}
813775

814776
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -364,27 +364,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
364364
Some(imm)
365365
}
366366

367-
pub(crate) fn codegen_rvalue_unsized(
368-
&mut self,
369-
bx: &mut Bx,
370-
indirect_dest: PlaceRef<'tcx, Bx::Value>,
371-
rvalue: &mir::Rvalue<'tcx>,
372-
) {
373-
debug!(
374-
"codegen_rvalue_unsized(indirect_dest.llval={:?}, rvalue={:?})",
375-
indirect_dest.val.llval, rvalue
376-
);
377-
378-
match *rvalue {
379-
mir::Rvalue::Use(ref operand) => {
380-
let cg_operand = self.codegen_operand(bx, operand);
381-
cg_operand.val.store_unsized(bx, indirect_dest);
382-
}
383-
384-
_ => bug!("unsized assignment other than `Rvalue::Use`"),
385-
}
386-
}
387-
388367
pub(crate) fn codegen_rvalue_operand(
389368
&mut self,
390369
bx: &mut Bx,

compiler/rustc_codegen_ssa/src/mir/statement.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
1515
match self.locals[index] {
1616
LocalRef::Place(cg_dest) => self.codegen_rvalue(bx, cg_dest, rvalue),
1717
LocalRef::UnsizedPlace(cg_indirect_dest) => {
18-
self.codegen_rvalue_unsized(bx, cg_indirect_dest, rvalue)
18+
let ty = cg_indirect_dest.layout.ty;
19+
span_bug!(
20+
statement.source_info.span,
21+
"cannot reallocate from `UnsizedPlace(*mut {ty})` \
22+
into `{rvalue:?}`; dynamic alloca is not supported",
23+
);
1924
}
2025
LocalRef::PendingOperand => {
2126
let operand = self.codegen_rvalue_operand(bx, rvalue);

compiler/rustc_codegen_ssa/src/traits/builder.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,6 @@ pub trait BuilderMethods<'a, 'tcx>:
224224
fn to_immediate_scalar(&mut self, val: Self::Value, scalar: Scalar) -> Self::Value;
225225

226226
fn alloca(&mut self, size: Size, align: Align) -> Self::Value;
227-
fn dynamic_alloca(&mut self, size: Self::Value, align: Align) -> Self::Value;
228227

229228
fn load(&mut self, ty: Self::Type, ptr: Self::Value, align: Align) -> Self::Value;
230229
fn volatile_load(&mut self, ty: Self::Type, ptr: Self::Value) -> Self::Value;

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
528528
trace!("expr={:#?}", expr);
529529

530530
let tcx = self.tcx;
531-
match expr.kind {
531+
let ty = match expr.kind {
532532
ExprKind::Lit(ref lit) => self.check_expr_lit(lit, expected),
533533
ExprKind::Binary(op, lhs, rhs) => self.check_expr_binop(expr, op, lhs, rhs, expected),
534534
ExprKind::Assign(lhs, rhs, span) => {
@@ -602,7 +602,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
602602
self.check_expr_unsafe_binder_cast(expr.span, kind, inner_expr, ty, expected)
603603
}
604604
ExprKind::Err(guar) => Ty::new_error(tcx, guar),
605+
};
606+
607+
if tcx.features().unsized_fn_params()
608+
&& matches!(expr.kind, ExprKind::Block(..) | ExprKind::Loop(..))
609+
{
610+
// Check that the ty is `Sized`. We wouldn't normally check this here because it should
611+
// error in borrowck but that has exceptions when `#![feature(unsized_fn_params)]` is
612+
// used to let unsized values be used as call operands. And we cannot get rid of that
613+
// because it is load bearing for `Box<dyn FnOnce()>: FnOnce()`.
614+
//
615+
// Otherwise code such as
616+
// ```rust
617+
// #![feature(unsized_fn_params)]
618+
//
619+
// fn udrop<T: ?Sized>(_t: T) { }
620+
//
621+
// udrop({ *{ Box::new([0_u8; 42]) as Box<[u8]> } });
622+
// ```
623+
// ends up moving the unsized value from the block, requiring alloca to do so.
624+
self.require_type_is_sized(ty, expr.span, ObligationCauseCode::Misc);
605625
}
626+
ty
606627
}
607628

608629
fn check_expr_unop(
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//! `#![feature(unsized_fn_params)]` lets you use unsized function parameters. In particular this
2+
//! is load bearing for `Box<dyn FnOnce()>: FnOnce()`. To do that, borrowck relaxes the requirement
3+
//! that certain places must be `Sized`. That means when `unsized_fn_params` is enabled, we must
4+
//! explicitly check for the sizedness of various expressions to not ICE at codegen. Note that it is
5+
//! specifically the blocks and scopes that are problematic; `udrop::<[u8]>(*foo());` is just fine.
6+
//! Also see tests/ui/unsized_locals/unsized-exprs-rpass.rs
7+
8+
#![feature(unsized_fn_params)]
9+
10+
pub fn foo() -> Box<[u8]> {
11+
Box::new(*b"foo")
12+
}
13+
14+
pub fn udrop<T: ?Sized>(_x: T) {}
15+
16+
fn main(){
17+
{ *foo() }; //~ERROR the size for values of type `[u8]` cannot be known at compilation time
18+
{ loop { break *foo(); } }; //~ERROR the size for values of type `[u8]` cannot be known at compilation time
19+
20+
udrop::<[u8]>({ loop { break *foo(); } }); //~ERROR the size for values of type `[u8]` cannot be known at compilation time
21+
udrop::<[u8]>(if true { *foo() } else { *foo() });
22+
//~^ERROR the size for values of type `[u8]` cannot be known at compilation time
23+
//~|ERROR the size for values of type `[u8]` cannot be known at compilation time
24+
udrop::<[u8]>({ *foo() }); //~ERROR the size for values of type `[u8]` cannot be known at compilation time
25+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
2+
--> $DIR/scope_unsized.rs:17:5
3+
|
4+
LL | { *foo() };
5+
| ^^^^^^^^^^ doesn't have a size known at compile-time
6+
|
7+
= help: the trait `Sized` is not implemented for `[u8]`
8+
9+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
10+
--> $DIR/scope_unsized.rs:18:7
11+
|
12+
LL | { loop { break *foo(); } };
13+
| ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
14+
|
15+
= help: the trait `Sized` is not implemented for `[u8]`
16+
17+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
18+
--> $DIR/scope_unsized.rs:20:21
19+
|
20+
LL | udrop::<[u8]>({ loop { break *foo(); } });
21+
| ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
22+
|
23+
= help: the trait `Sized` is not implemented for `[u8]`
24+
25+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
26+
--> $DIR/scope_unsized.rs:21:27
27+
|
28+
LL | udrop::<[u8]>(if true { *foo() } else { *foo() });
29+
| ^^^^^^^^^^ doesn't have a size known at compile-time
30+
|
31+
= help: the trait `Sized` is not implemented for `[u8]`
32+
33+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
34+
--> $DIR/scope_unsized.rs:21:43
35+
|
36+
LL | udrop::<[u8]>(if true { *foo() } else { *foo() });
37+
| ^^^^^^^^^^ doesn't have a size known at compile-time
38+
|
39+
= help: the trait `Sized` is not implemented for `[u8]`
40+
41+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
42+
--> $DIR/scope_unsized.rs:24:19
43+
|
44+
LL | udrop::<[u8]>({ *foo() });
45+
| ^^^^^^^^^^ doesn't have a size known at compile-time
46+
|
47+
= help: the trait `Sized` is not implemented for `[u8]`
48+
49+
error: aborting due to 6 previous errors
50+
51+
For more information about this error, try `rustc --explain E0277`.

tests/ui/unsized-locals/unsized-exprs-rpass.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@ impl std::ops::Add<i32> for A<[u8]> {
1818
}
1919

2020
fn main() {
21-
udrop::<[u8]>(loop {
22-
break *foo();
23-
});
24-
udrop::<[u8]>(if true { *foo() } else { *foo() });
25-
udrop::<[u8]>({ *foo() });
2621
udrop::<[u8]>((*foo()));
2722
*afoo() + 42;
2823
udrop as fn([u8]);

0 commit comments

Comments
 (0)