Skip to content

It should be possible to get a mutable reference to a ZST literal #103821

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
joshlf opened this issue Oct 31, 2022 · 12 comments
Open

It should be possible to get a mutable reference to a ZST literal #103821

joshlf opened this issue Oct 31, 2022 · 12 comments
Labels
A-zst Area: Zero-sized types (ZST). T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@joshlf
Copy link
Contributor

joshlf commented Oct 31, 2022

The following code is legal:

fn get_mut_ref<'a>() -> &'a mut [u8] {
    &mut []
}

However, if we instead use (), it's no longer legal:

fn get_mut_ref<'a>() -> &'a mut () {
    &mut ()
}

We get this error:

error[E0515]: cannot return reference to temporary value
 --> src/lib.rs:2:5
  |
2 |     &mut ()
  |     ^^^^^--
  |     |    |
  |     |    temporary value created here
  |     returns a reference to data owned by the current function

Is there a reason that the former is legal while the latter is not? I would expect the latter to be legal - in the general case, it'd be great if it were legal for any ZST, although I'm sure that's more complicated (especially in a generic context).

On Fuchsia, we're currently using this hack to work around this limitation.

@shamatar
Copy link
Contributor

shamatar commented Nov 1, 2022

I had a similar issue, it also works with shorter hack

fn get_mut_ref<'a>() -> &'a mut () {
    static mut _HACK: () = ();

    unsafe {&mut _HACK}
}

that produces almost the same assembly as another accepted example

fn get_mut_ref_array<'a>() -> &'a mut [u8; 0] {
    &mut []
}

@Rageking8
Copy link
Contributor

@rustbot label +A-zst +T-types

@rustbot rustbot added A-zst Area: Zero-sized types (ZST). T-types Relevant to the types team, which will review and decide on the PR/issue. labels Nov 1, 2022
@ds84182
Copy link

ds84182 commented Nov 4, 2022

This seems to work well for ZSTs.

fn get_mut_ref<'a>() -> &'a mut () { Box::leak(Box::new(())) }

Does not actually invoke the allocator. Instead returns a properly aligned dangling ref.

@RalfJung
Copy link
Member

That this works for empty arrays is maintained for backwards compatibility, since this was allowed in some very early version of promotion.

I think we could plausibly allow this for more / all ZST. Cc @oli-obk

@oli-obk
Copy link
Contributor

oli-obk commented Feb 21, 2023

yea, seems ok to add more

@joshlf
Copy link
Contributor Author

joshlf commented Aug 1, 2023

Does anyone have a sense of what it would take to implement this (technically)? Also, from a process perspective, I assume this is simple enough that it could just be a PR + FCP (rather than a full RFC)?

@RalfJung
Copy link
Member

RalfJung commented Aug 1, 2023

The check for this is here:

BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow } => {
let ty = place.ty(self.body, self.tcx).ty;
// In theory, any zero-sized value could be borrowed
// mutably without consequences. However, only &mut []
// is allowed right now.
if let ty::Array(_, len) = ty.kind() {
match len.try_eval_target_usize(self.tcx, self.param_env) {
Some(0) => {}
_ => return Err(Unpromotable),
}
} else {
return Err(Unpromotable);
}
}

It needs to be adjusted to detect more zero-sized types. This is polymorphic code so we can't just compute the layout, we have to actually traverse the type. Not sure if such an analysis to predict whether a type is a ZST already exists.

And yeah I assume FCP will suffice.

@oli-obk
Copy link
Contributor

oli-obk commented Aug 1, 2023

Once the naive layout logic lands again, we could probably use it for this, too

@joshlf
Copy link
Contributor Author

joshlf commented Aug 1, 2023

Thanks for the details, @RalfJung!

Once the naive layout logic lands again, we could probably use it for this, too

@oli-obk, are there any docs/PRs I can read about this?

@RalfJung
Copy link
Member

RalfJung commented Aug 1, 2023

Naive layout was part of #113166 but the PR got reverted

@joshlf
Copy link
Contributor Author

joshlf commented Aug 1, 2023

Awesome, thanks! Is re-landing naive layout tracked anywhere?

@oli-obk
Copy link
Contributor

oli-obk commented Aug 2, 2023

I don't know what @moulins plan is, no one else is working on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-zst Area: Zero-sized types (ZST). T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

7 participants