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

Type called union wreaks havoc since 1.54 #88583

Closed
dtolnay opened this issue Sep 2, 2021 · 11 comments · Fixed by #88775
Closed

Type called union wreaks havoc since 1.54 #88583

dtolnay opened this issue Sep 2, 2021 · 11 comments · Fixed by #88775
Assignees
Labels
C-bug Category: This is a bug. P-critical Critical priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@dtolnay
Copy link
Member

dtolnay commented Sep 2, 2021

When C-compatible untagged unions were introduced by RFC 1444, it was careful not to break existing valid uses of union identifier, such as https://doc.rust-lang.org/std/collections/struct.BTreeSet.html#method.union.

However, the unions from RFC 2102 (#49804) appear to be more disruptive, at least as currently implemented. The following stable code works with every stable rustc from 1.0.0 through 1.53.0, but can no longer be parsed by rustc 1.54.0 or current nightly.

struct union;

impl union {
    pub fn new() -> Self {
        unimplemented!()
    }
}

fn main() {}
error: functions are not allowed in union definitions
 --> src/main.rs:4:5
  |
4 | /     pub fn new() -> Self {
5 | |         unimplemented!()
6 | |     }
  | |_____^
  |
  = help: unlike in C++, Java, and C#, functions are declared in `impl` blocks
  = help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information

error: expected `(`, found `main`
 --> src/main.rs:9:4
  |
9 | fn main() {}
  |    ^^^^ expected `(`

@jedel1043 @joshtriplett

Labeling T-compiler for what to do about the regression and T-lang because it's not clear to me what the grammar of anonymous union is intended to be from the parser's perspective.

@dtolnay dtolnay added T-lang Relevant to the language team, which will review and decide on the PR/issue. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. regression-from-stable-to-stable Performance or correctness regression from one stable version to another. C-bug Category: This is a bug. labels Sep 2, 2021
@rustbot rustbot added the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label Sep 2, 2021
@hellow554

This comment was marked as off-topic.

@apiraino
Copy link
Contributor

apiraino commented Sep 2, 2021

Assigning priority as discussed in the Zulip thread of the Prioritization Working Group.

@rustbot label -I-prioritize +P-critical

@rustbot rustbot added P-critical Critical priority and removed I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Sep 2, 2021
@joshtriplett
Copy link
Member

Anonymous unions were not intended to change the "contextual keyword" nature of union. Anonymous unions do allow the keyword union to appear in more places, but impl union { should parse as the implementation of a type named union.

I'd suggest temporarily reverting the parsing of anonymous unions until the parsing can be fixed to handle this case correctly. We should also add a test case covering this specific usage, as well as other possibilities:

struct union { field: u32 };

impl union {
    pub fn new() -> Self {
        unimplemented!()
    }
}
type union = u32;
struct S { field: union };
struct union { field: u32 };
struct S { field: union };
fn main() {
    let s = S { field: union { field: 42 } };
}

@dtolnay
Copy link
Member Author

dtolnay commented Sep 2, 2021

Is the following code intended to compile as envisioned by the anonymous unions RFC (sans any future expansion of the feature)?

#[cfg(any())]
type A = union { field: u32 };

Relatedly—?

macro_rules! ty {
    ($ty:ty) => {};
}

ty!(union { field: u32 });

@joshtriplett
Copy link
Member

@dtolnay The first wouldn't be allowed by the base RFC as written, no. This would be allowed by the "General anonymous types" possibility discussed at https://github.com/rust-lang/rfcs/blob/master/text/2102-unnamed-fields.md#general-anonymous-types , but that wasn't the approach that was approved in the RFC.

For the second, I'm not sure. An anonymous union (or anonymous struct) can't appear everywhere a type can appear, only as a field type for a field named _ in a struct or union. In theory you should be able to generate that field definition via a macro. But I think parsing union { ... } generically as a type would require "General anonymous types" again.

@dtolnay
Copy link
Member Author

dtolnay commented Sep 2, 2021

Okay. In that case the implementation approach from #84571 probably significantly has to change. According to the test:

type A =
struct {
field: u8,
};

they seem to have deferred validation until after parsing anonymous struct/union in arbitrary type position, rather than parsing it only in the narrow context you've described.

@petrochenkov

@joshtriplett
Copy link
Member

We discussed this in today's @rust-lang/lang meeting. @pnkfelix and I both agree that this should be fixed by reverting the current preliminary parsing support for anonymous unions; we can re-add it when it no longer causes this breakage.

We also think this fix needs to get into 1.56 (due to the edition).

Finally, we really need to add more test cases to catch more uses of union as a non-keyword, before we try to re-add parsing support.

@pnkfelix
Copy link
Member

pnkfelix commented Sep 7, 2021

nominating to ensure this gets eyeballs at (or before) compiler triage meeting, mostly to ensure the aforementioned revert gets done.

pnkfelix added a commit to pnkfelix/rust that referenced this issue Sep 9, 2021
@pnkfelix
Copy link
Member

pnkfelix commented Sep 9, 2021

Reversion PR posted in PR #88775

@pnkfelix pnkfelix self-assigned this Sep 9, 2021
@estebank
Copy link
Contributor

estebank commented Sep 10, 2021

Looking at the parser changes, I believe I can fix all potentially problematic issues by gating the bare types to only be allowed in ADT field types and using the "parser snapshot" approach in all other cases (clone the parser, try to parse normally, if that fails try the alternate –bare union/struct– parse and if that succeeds, complain about it). Looking at the RFC, these were only ever supposed to be supported in named field types, right? Namely, should they be accepted in tuple structs and variants?

estebank added a commit to estebank/rust that referenced this issue Sep 10, 2021
Do not unconditionally parse bare types everywhere, only parse them if
they are in a field type, and try them when recovering a misparse
everywhere else, using them only if they are successfuly fully parsed.

Fix rust-lang#88583.
@estebank
Copy link
Contributor

Opened #88815 with more restrictive parsing, without reverting the changes already in stable.

Manishearth added a commit to Manishearth/rust that referenced this issue Sep 12, 2021
… r=davidtwco

Revert anon union parsing

Revert PR rust-lang#84571 and rust-lang#85515, which implemented anonymous union parsing in a manner that broke the context-sensitivity for the `union` keyword and thus broke stable Rust code.

Fix rust-lang#88583.
workingjubilee added a commit to workingjubilee/rustc that referenced this issue Sep 12, 2021
… r=davidtwco

Revert anon union parsing

Revert PR rust-lang#84571 and rust-lang#85515, which implemented anonymous union parsing in a manner that broke the context-sensitivity for the `union` keyword and thus broke stable Rust code.

Fix rust-lang#88583.
Manishearth added a commit to Manishearth/rust that referenced this issue Sep 12, 2021
… r=davidtwco

Revert anon union parsing

Revert PR rust-lang#84571 and rust-lang#85515, which implemented anonymous union parsing in a manner that broke the context-sensitivity for the `union` keyword and thus broke stable Rust code.

Fix rust-lang#88583.
Manishearth added a commit to Manishearth/rust that referenced this issue Sep 14, 2021
… r=davidtwco

Revert anon union parsing

Revert PR rust-lang#84571 and rust-lang#85515, which implemented anonymous union parsing in a manner that broke the context-sensitivity for the `union` keyword and thus broke stable Rust code.

Fix rust-lang#88583.
Manishearth added a commit to Manishearth/rust that referenced this issue Sep 14, 2021
… r=davidtwco

Revert anon union parsing

Revert PR rust-lang#84571 and rust-lang#85515, which implemented anonymous union parsing in a manner that broke the context-sensitivity for the `union` keyword and thus broke stable Rust code.

Fix rust-lang#88583.
Manishearth added a commit to Manishearth/rust that referenced this issue Sep 14, 2021
… r=davidtwco

Revert anon union parsing

Revert PR rust-lang#84571 and rust-lang#85515, which implemented anonymous union parsing in a manner that broke the context-sensitivity for the `union` keyword and thus broke stable Rust code.

Fix rust-lang#88583.
Manishearth added a commit to Manishearth/rust that referenced this issue Sep 14, 2021
… r=davidtwco

Revert anon union parsing

Revert PR rust-lang#84571 and rust-lang#85515, which implemented anonymous union parsing in a manner that broke the context-sensitivity for the `union` keyword and thus broke stable Rust code.

Fix rust-lang#88583.
Manishearth added a commit to Manishearth/rust that referenced this issue Sep 15, 2021
… r=davidtwco

Revert anon union parsing

Revert PR rust-lang#84571 and rust-lang#85515, which implemented anonymous union parsing in a manner that broke the context-sensitivity for the `union` keyword and thus broke stable Rust code.

Fix rust-lang#88583.
@bors bors closed this as completed in fb2d7df Sep 16, 2021
cuviper pushed a commit to cuviper/rust that referenced this issue Sep 16, 2021
calebcartwright pushed a commit to calebcartwright/rust that referenced this issue Oct 20, 2021
… r=davidtwco

Revert anon union parsing

Revert PR rust-lang#84571 and rust-lang#85515, which implemented anonymous union parsing in a manner that broke the context-sensitivity for the `union` keyword and thus broke stable Rust code.

Fix rust-lang#88583.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. P-critical Critical priority regression-from-stable-to-stable Performance or correctness regression from one stable version to another. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
7 participants