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

let _ = <access to unsafe field> currently type-checks #54003

Closed
nikomatsakis opened this issue Sep 6, 2018 · 11 comments · Fixed by #102256
Closed

let _ = <access to unsafe field> currently type-checks #54003

nikomatsakis opened this issue Sep 6, 2018 · 11 comments · Fixed by #102256
Labels
T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Sep 6, 2018

The following example passes the unsafe checker, but probably should not:

// #![feature(nll)]

union Foo {
    x: u32,
    y: u64
}

fn main() {
    let foo = Foo { x: 22 };
    let _ = foo.x;
}

The problem here is that let _ = foo.x is a no-op -- foo.x is a place expression, and the _ pattern just plain ignores it. This means that no MIR is generated. The unsafe checker runs on MIR.

But I think that we expect an error here nonetheless.

This is a regression that was introduced in the move to doing unsafe checking on MIR. I'm not sure the best way to fix: I tend to think we should do unsafe checking on HAIR, but that would be a fairly large effort. We could certainly generate a "dummy access" as we do with matches. (But we want to be careful about borrow checker interactions -- see #53114).

I'm nominating this for lang-team discussion — we do want an unsafe error here, right?

@nikomatsakis nikomatsakis added I-nominated T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Sep 6, 2018
@nikomatsakis
Copy link
Contributor Author

On the topic of doing unsafe checking on HAIR:

This is a regression that was introduced in the move to doing unsafe checking on MIR. I'm not sure the best way to fix: I tend to think we should do unsafe checking on HAIR, but that would be a fairly large effort.

@arielb1 and @eddyb pointed out that, in HAIR, we have to be careful because field access can also occur in patterns. But I think that this is just a matter of looking for "struct patterns" that refer to packed structs, and checking if they have any ref-bindings within? Still, kind of a pain, not as nice as doing the check on MIR.

This may argue for the dummy access.

@arielb1
Copy link
Contributor

arielb1 commented Sep 6, 2018

I think you are missing a raw pointer there. Nope you are just using a union.

@eddyb
Copy link
Member

eddyb commented Sep 6, 2018

IMO this isn't as bad as match u.void {} not needing unsafe, which is what we've added the dummy accessed for, it actually seems harmless.

@arielb1
Copy link
Contributor

arielb1 commented Sep 9, 2018

IMO this isn't as bad as match u.void {} not needing unsafe, which is what we've added the dummy accessed for, it actually seems harmless.

Of course it's not as bad - only one of these is unsound.

@nikomatsakis
Copy link
Contributor Author

I agree it is not as bad, but it still seems like a bug to me. Do we want to fix?

cc @rust-lang/lang -- nominating for discussion, but feel free to leave comments, maybe we can settle async before the meeting. =) Should let _ = a.b give an error if b is the field of a union and there is no unsafe block? Currently, it does not, because this compiles to a no-op -- that is, there is no MIR for it. It is basically saying "ignore the place a.b" (in contrast to, say, let _x = a.b, which would be an access).

If we do want to fix, and we don't want to move the code to HAIR, I think we want to add some kind of UnsafeCheck(Place) statement.

UnsafeCheck would:

  • be stripped out once static checking is done
  • be used by unsafe code to report errors
  • be ignored by the borrow checker, which is only concerned with actual accesses
    • (in particular, let _ = x is ok if x is mutably borrowed or uninitialized)

@nikomatsakis
Copy link
Contributor Author

The only reason I can see not to fix this is backwards compatibility: this is a somewhat old regression by now. Not sure how old.

@aturon
Copy link
Member

aturon commented Sep 10, 2018

@nikomatsakis I think we should require an unsafe block for consistency. Breakage seems unlikely (though we should check) and very easy to deal with.

@joshtriplett
Copy link
Member

I'd like to see this fixed as well.

@Centril
Copy link
Contributor

Centril commented Sep 10, 2018

I agree with @aturon wrt. the goal and the reasoning...

...but I am concerned about complicating MIR (this would be akin to extending Haskell Core with a constructor which they are very reluctant to do for good reasons). Are there other places which would benefit from UnsafeCheck?

@eddyb
Copy link
Member

eddyb commented Sep 11, 2018

FWIW I don't think we need to fix anything, and that these are all equivalent:

let _ = a.b;
let Union { b: _ } = a;
let Union { .. } = a;

@joshtriplett
Copy link
Member

We discussed this in the @rust-lang/lang meeting, and we were generally in favor of emitting warnings about needing unsafe even on the right-hand side of let _ =.

However, we also agreed that we'd like to have a warn-by-default lint for let _ = expression_with_zero_side_effects;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants