Skip to content

Unimplement unsized_locals #141811

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}

fn unsized_feature_enabled(&self) -> bool {
let features = self.tcx().features();
features.unsized_locals() || features.unsized_fn_params()
self.tcx().features().unsized_fn_params()
}

/// Equate the inferred type and the annotated type for user type annotations
Expand Down Expand Up @@ -961,7 +960,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}

// When `unsized_fn_params` or `unsized_locals` is enabled, only function calls
// When `unsized_fn_params` is enabled, only function calls
// and nullary ops are checked in `check_call_dest`.
if !self.unsized_feature_enabled() {
match self.body.local_kind(local) {
Expand Down Expand Up @@ -1951,7 +1950,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
}

// When `unsized_fn_params` and `unsized_locals` are both not enabled,
// When `unsized_fn_params` is not enabled,
// this check is done at `check_local`.
if self.unsized_feature_enabled() {
let span = term.source_info.span;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {}

trait Trait {
// This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable
// without unsized_locals), but wrappers around `Self` currently are not.
// FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented
// fn wrapper(self: Wrapper<Self>) -> i32;
fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32;
fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@ impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {}


trait Trait {
// This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable
// without unsized_locals), but wrappers around `Self` currently are not.
// FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented
// fn wrapper(self: Wrapper<Self>) -> i32;
fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32;
fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32;
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/removed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ declare_features! (
/// Allows unnamed fields of struct and union type
(removed, unnamed_fields, "1.83.0", Some(49804), Some("feature needs redesign")),
(removed, unsafe_no_drop_flag, "1.0.0", None, None),
/// Allows unsized rvalues at arguments and parameters.
(removed, unsized_locals, "CURRENT_RUSTC_VERSION", Some(48055), Some("removed due to soundness issues; see https://github.com/rust-lang/rust/issues/111942")),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(removed, unsized_locals, "CURRENT_RUSTC_VERSION", Some(48055), Some("removed due to soundness issues; see https://github.com/rust-lang/rust/issues/111942")),
(removed, unsized_locals, "CURRENT_RUSTC_VERSION", Some(48055), Some("removed due to implementation concerns; see https://github.com/rust-lang/rust/issues/111942")),

As pointed out by Ralf, it should be sound, just not sufficiently implemented

(removed, unsized_tuple_coercion, "1.87.0", Some(42877),
Some("The feature restricts possible layouts for tuples, and this restriction is not worth it.")),
/// Allows `union` fields that don't implement `Copy` as long as they don't have any drop glue.
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -669,8 +669,6 @@ declare_features! (
(incomplete, unsized_const_params, "1.82.0", Some(95174)),
/// Allows unsized fn parameters.
(internal, unsized_fn_params, "1.49.0", Some(48055)),
/// Allows unsized rvalues at arguments and parameters.
(incomplete, unsized_locals, "1.30.0", Some(48055)),
/// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute.
(unstable, used_with_arg, "1.60.0", Some(93798)),
/// Allows use of attributes in `where` clauses.
Expand Down
8 changes: 2 additions & 6 deletions compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1663,9 +1663,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
blk_id,
expression,
);
if !fcx.tcx.features().unsized_locals() {
unsized_return = self.is_return_ty_definitely_unsized(fcx);
}
unsized_return = self.is_return_ty_definitely_unsized(fcx);
}
ObligationCauseCode::ReturnValue(return_expr_id) => {
err = self.report_return_mismatched_types(
Expand All @@ -1677,9 +1675,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
return_expr_id,
expression,
);
if !fcx.tcx.features().unsized_locals() {
unsized_return = self.is_return_ty_definitely_unsized(fcx);
}
unsized_return = self.is_return_ty_definitely_unsized(fcx);
}
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
arm_span,
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -809,9 +809,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
}
// Here we want to prevent struct constructors from returning unsized types.
// There were two cases this happened: fn pointer coercion in stable
// and usual function call in presence of unsized_locals.
// Here we want to prevent struct constructors from returning unsized types,
// which can happen with fn pointer coercion on stable.
// Also, as we just want to check sizedness, instead of introducing
// placeholder lifetimes with probing, we just replace higher lifetimes
// with fresh vars.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/gather_locals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
),
);
}
} else if !self.fcx.tcx.features().unsized_locals() {
} else {
self.fcx.require_type_is_sized(
var_ty,
p.span,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/upvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let final_upvar_tys = self.final_upvar_tys(closure_def_id);
debug!(?closure_hir_id, ?args, ?final_upvar_tys);

if self.tcx.features().unsized_locals() || self.tcx.features().unsized_fn_params() {
if self.tcx.features().unsized_fn_params() {
for capture in
self.typeck_results.borrow().closure_min_captures_flattened(closure_def_id)
{
Expand Down
7 changes: 0 additions & 7 deletions compiler/rustc_middle/src/mir/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1133,13 +1133,6 @@ pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>;
/// Each local naturally corresponds to the place `Place { local, projection: [] }`. This place has
/// the address of the local's allocation and the type of the local.
///
/// **Needs clarification:** Unsized locals seem to present a bit of an issue. Their allocation
/// can't actually be created on `StorageLive`, because it's unclear how big to make the allocation.
/// Furthermore, MIR produces assignments to unsized locals, although that is not permitted under
/// `#![feature(unsized_locals)]` in Rust. Besides just putting "unsized locals are special and
/// different" in a bunch of places, I (JakobDegen) don't know how to incorporate this behavior into
/// the current MIR semantics in a clean way - possibly this needs some design work first.
///
/// For places that are not locals, ie they have a non-empty list of projections, we define the
/// values as a function of the parent place, that is the place with its last [`ProjectionElem`]
/// stripped. The way this is computed of course depends on the kind of that last projection
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ pub enum InstanceKind<'tcx> {
Intrinsic(DefId),

/// `<T as Trait>::method` where `method` receives unsizeable `self: Self` (part of the
/// `unsized_locals` feature).
/// `unsized_fn_params` feature).
///
/// The generated shim will take `Self` via `*mut Self` - conceptually this is `&owned Self` -
/// and dereference the argument to call the original function.
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_mir_build/src/builder/expr/as_operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// local variable of unsized type. For example, consider this program:
///
/// ```
/// #![feature(unsized_locals, unsized_fn_params)]
/// #![feature(unsized_fn_params)]
/// # use core::fmt::Debug;
/// fn foo(p: dyn Debug) { dbg!(p); }
/// fn foo(_p: dyn Debug) { /* ... */ }
///
/// fn bar(box_p: Box<dyn Debug>) { foo(*box_p); }
/// ```
Expand All @@ -84,7 +84,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// will actually provide a pointer to the interior of the box, and not move the `dyn Debug`
/// value to the stack.
///
/// See #68304 for more details.
/// See <https://github.com/rust-lang/rust/issues/68304> for more details.
pub(crate) fn as_local_call_operand(
&mut self,
block: BasicBlock,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_mir_transform/src/coroutine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1414,9 +1414,9 @@ fn check_field_tys_sized<'tcx>(
coroutine_layout: &CoroutineLayout<'tcx>,
def_id: LocalDefId,
) {
// No need to check if unsized_locals/unsized_fn_params is disabled,
// No need to check if unsized_fn_params is disabled,
// since we will error during typeck.
if !tcx.features().unsized_locals() && !tcx.features().unsized_fn_params() {
if !tcx.features().unsized_fn_params() {
return;
}

Expand Down
11 changes: 1 addition & 10 deletions compiler/rustc_mir_transform/src/gvn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,6 @@ struct VnState<'body, 'tcx> {
next_opaque: usize,
/// Cache the deref values.
derefs: Vec<VnIndex>,
/// Cache the value of the `unsized_locals` features, to avoid fetching it repeatedly in a loop.
feature_unsized_locals: bool,
ssa: &'body SsaLocals,
dominators: Dominators<BasicBlock>,
reused_locals: DenseBitSet<Local>,
Expand Down Expand Up @@ -273,7 +271,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
evaluated: IndexVec::with_capacity(num_values),
next_opaque: 1,
derefs: Vec::new(),
feature_unsized_locals: tcx.features().unsized_locals(),
ssa,
dominators,
reused_locals: DenseBitSet::new_empty(local_decls.len()),
Expand Down Expand Up @@ -329,13 +326,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
fn assign(&mut self, local: Local, value: VnIndex) {
debug_assert!(self.ssa.is_ssa(local));
self.locals[local] = Some(value);

// Only register the value if its type is `Sized`, as we will emit copies of it.
let is_sized = !self.feature_unsized_locals
|| self.local_decls[local].ty.is_sized(self.tcx, self.typing_env());
if is_sized {
self.rev_locals[value].push(local);
}
self.rev_locals[value].push(local);
}

fn insert_constant(&mut self, value: Const<'tcx>) -> VnIndex {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2993,9 +2993,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if local {
err.note("all local variables must have a statically known size");
}
if !tcx.features().unsized_locals() {
err.help("unsized locals are gated as an unstable feature");
}
}
ObligationCauseCode::SizedArgumentType(hir_id) => {
let mut ty = None;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -414,8 +414,8 @@ fn virtual_call_violations_for_method<'tcx>(

let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0));

// Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on.
// However, this is already considered dyn compatible. We allow it as a special case here.
// `self: Self` can't be dispatched on.
// However, this is considered dyn compatible. We allow it as a special case here.
// FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows
// `Receiver: Unsize<Receiver[Self => dyn Trait]>`.
if receiver_ty != tcx.types.self_param {
Expand Down
28 changes: 26 additions & 2 deletions library/core/src/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,32 @@ pub const fn forget<T>(t: T) {

/// Like [`forget`], but also accepts unsized values.
///
/// This function is just a shim intended to be removed when the `unsized_locals` feature gets
/// stabilized.
/// While Rust does not permit unsized locals since its removal in [#111942] it is
/// still possible to call functions with unsized values from a function argument
/// or in-place construction.
///
/// ```rust
/// #![feature(unsized_fn_params, forget_unsized)]
/// #![allow(internal_features)]
///
/// use std::mem::forget_unsized;
///
/// pub fn in_place() {
/// forget_unsized(*Box::new("str"));
/// }
///
/// pub fn param(x: str) {
/// forget_unsized(x);
/// }
/// ```
///
/// This works because the compiler will alter these functions to pass the parameter
/// by reference instead. This trick is necessary to support `Box<dyn FnOnce()>: FnOnce()`.
/// See [#68304] and [#71170] for more information.
///
/// [#111942]: https://github.com/rust-lang/rust/issues/111942
/// [#68304]: https://github.com/rust-lang/rust/issues/68304
/// [#71170]: https://github.com/rust-lang/rust/pull/71170
#[inline]
#[unstable(feature = "forget_unsized", issue = "none")]
pub fn forget_unsized<T: ?Sized>(t: T) {
Expand Down
1 change: 0 additions & 1 deletion library/coretests/tests/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,6 @@ fn thin_box() {
// if `{size,align}_of_for_meta<T: ?Sized>(T::Metadata)` are added.
// * Constructing a `ThinBox` without consuming and deallocating a `Box`
// requires either the unstable `Unsize` marker trait,
// or the unstable `unsized_locals` language feature,
// or taking `&dyn T` and restricting to `T: Copy`.

use std::alloc::*;
Expand Down
4 changes: 2 additions & 2 deletions src/doc/rustc-dev-guide/src/implementing_new_features.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ a new unstable feature:
[`incomplete_features` lint]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#incomplete-features

```rust ignore
/// Allows unsized rvalues at arguments and parameters.
(incomplete, unsized_locals, "CURRENT_RUSTC_VERSION", Some(48055), None),
/// Allows deref patterns.
(incomplete, deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121), None),
```

To avoid [semantic merge conflicts], please use `CURRENT_RUSTC_VERSION` instead of `1.70` or
Expand Down
Loading
Loading