Skip to content
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

Add union field match question #30

Closed
wants to merge 1 commit into from
Closed

Add union field match question #30

wants to merge 1 commit into from

Conversation

mxxo
Copy link

@mxxo mxxo commented May 9, 2020

I was looking at the unions in the Reference and got confused by the pattern matching section: https://doc.rust-lang.org/reference/items/unions.html#pattern-matching-on-unions

A catch-all arm with a union field will transmute all union values to that field's type, which was unexpected for me, even with the unsafe block required for union field accesses.

It's a little murky, but as far as I can tell this is not undefined behaviour in C, (but is in C++) according to:

If the member used to access the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called "type punning"). This might be a trap representation.

and in this case, it's not a trap representation.

The explanation is a little rough. I thought I'd propose the general question idea and see if you'd like to include it. Please let me know whether you'd like me to rework the question details (maybe adding a constant value 1065353216 to make entering the correct answer easier).

Copy link
Owner

@dtolnay dtolnay left a comment

Choose a reason for hiding this comment

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

Thanks for the PR.

Is there a way to cover this without requiring the person to know the bit representation of 1.0f32 and doing the binary to decimal conversion in their head?

@mxxo
Copy link
Author

mxxo commented May 9, 2020

Maybe we could change the fields to u8 and bool? Like this:

#[repr(C)]
union U {
    f1: bool, 
    f2: u8,
}

fn main() {
    let u = U { f2: 8 };
    unsafe { match u {
        U { f1: i } if i => print!("{:?}", i),
        U { f1: i } => print!("{:?}", i), 
        U { f2: f } => print!("{:?}", f + 1),
    }}
}

prints false, matching the second arm but if you change it to

let u = U { f2: 7 };

it prints true, and I could talk about that in the explanation section.

Copy link
Owner

@dtolnay dtolnay left a comment

Choose a reason for hiding this comment

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

That code is UB though.

I think I would prefer not to have this question. The other questions have a better focus on exposing language aspects where reasonable languages could reasonably have diverging behavior. This question doesn't seem as strong in comparison because there is only one behavior for a match on untagged unions that could reasonably be applied.

@dtolnay dtolnay closed this May 9, 2020
@mxxo
Copy link
Author

mxxo commented May 9, 2020

I understand, thanks for looking at it. Even with the reference explicitly calling it out, I thought the last snippet might have skirted UB because the C space guarantee for bools but Miri catches it anyways.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants