rust-lang / rust-lang/rfcs

Allow FRU for types that are Copy OR types that are not Drop

Open
#1,117 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

T-lang
Dominant language
Markdown
Stars
6.6k
Forks
1.7k
Avg merge
16h 14m
Merged PRs (30d)
1

Description

RFC 736 altered Functional Record Update to treat FRU as equivalent to a full struct literal and disallow its use when the expansion would result in referencing a private field. This was done to fix a problem where this can break invariants that the struct needs to preserve (e.g. that a ptr field is unique).

This solution is overly restrictive. It prevents patterns that would otherwise be perfectly okay, such as

mod foo {
    #[derive(Debug,Copy,Clone)]
    pub struct Bar { pub a: u8, b: &'static str }
    pub fn make_bar(a: u8, b: &'static str) -> Bar {
        Bar { a: a, b: b }
    }
}

fn main() {
    let s_1 = foo::make_bar(1, "one");
    //let s_2 = foo::Bar { a: 2, ..s_1 }; // this is eqiuvalent to
    let mut s_2 = s_1; // make a copy
    s_2.a = 2;
    println!("s_1: {:?}, s_2: {:?}", s_1, s_2);
}

In this case the struct is Copy, so I can freely make a copy and change public fields, which is equivalent to what FRU is doing.

This is also true of structs that are not Copy but are also not Drop. Because of the lack of a destructor, moving fields from one instance of the struct to another is perfectly safe (as it's equivalent to moving the whole struct and then modifying the public fields).

As it turns out, the actual restriction here that we care about is whether it's legal for us to either copy the struct or move out of it. This means the struct has to either implement Copy or it has to not implement Drop. For any struct that is Copy, FRU is trivially safe because I can just copy the struct and update the public fields. For any struct that is not Drop, FRU is also safe because I can move the struct as a whole and then update the public fields.

I actually think it would be perfectly safe to go even farther and adopt Alternative 1 from RFC 736, which says that FRU should be treated as consuming the old struct value. This should be perfectly safe, with Foo { a: a, b: b, ..old_foo } being equivalent to { let mut foo = old_foo; foo.a = a; foo.b = b; foo }. But there is a bit of a question about the precise semantics; for example, if all fields of a struct are Copy and pub, and I use it with FRU, should it actually consume the struct or merely copy all of the fields? Based on that, I'm willing to defer that question until later (although I suspect the answer should be along the lines of copy fields if possible, and fall back to consuming the whole struct otherwise).


tl;dr - Adjust FRU to merely require that the source type be Copy or not be Drop, instead of looking at field visibility.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading RFC 736 and the examples in this issue. Compare the current field-visibility restriction with the proposed Copy-or-not-Drop rule, then resolve the open semantics around consuming versus copying the source value. Done means the RFC or issue records an agreed precise behavior for FRU.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.