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

Revert enum discriminants #89884

Merged
merged 2 commits into from
Oct 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ Language

- [The 2021 Edition is now stable.][rust#88100]
See [the edition guide][rust-2021-edition-guide] for more details.
- [You can now specify explicit discriminant values on any Rust enum.][rust#86860]
- [The pattern in `binding @ pattern` can now also introduce new bindings.][rust#85305]
- [Union field access is permitted in `const fn`.][rust#85769]

Expand Down Expand Up @@ -51,8 +50,6 @@ Stabilised APIs
---------------

- [`std::os::unix::fs::chroot`]
- [`Iterator::intersperse`]
- [`Iterator::intersperse_with`]
- [`UnsafeCell::raw_get`]
- [`BufWriter::into_parts`]
- [`core::panic::{UnwindSafe, RefUnwindSafe, AssertUnwindSafe}`]
Expand Down
64 changes: 62 additions & 2 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use rustc_ast as ast;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::{AssocTyConstraint, AssocTyConstraintKind, NodeId};
use rustc_ast::{PatKind, RangeEnd};
use rustc_ast::{PatKind, RangeEnd, VariantData};
use rustc_errors::struct_span_err;
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
use rustc_feature::{Features, GateIssue};
use rustc_session::parse::feature_err_issue;
use rustc_session::parse::{feature_err, feature_err_issue};
use rustc_session::Session;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym;
Expand Down Expand Up @@ -218,6 +218,46 @@ impl<'a> PostExpansionVisitor<'a> {
}
}

fn maybe_report_invalid_custom_discriminants(&self, variants: &[ast::Variant]) {
let has_fields = variants.iter().any(|variant| match variant.data {
VariantData::Tuple(..) | VariantData::Struct(..) => true,
VariantData::Unit(..) => false,
});

let discriminant_spans = variants
.iter()
.filter(|variant| match variant.data {
VariantData::Tuple(..) | VariantData::Struct(..) => false,
VariantData::Unit(..) => true,
})
.filter_map(|variant| variant.disr_expr.as_ref().map(|c| c.value.span))
.collect::<Vec<_>>();

if !discriminant_spans.is_empty() && has_fields {
let mut err = feature_err(
&self.sess.parse_sess,
sym::arbitrary_enum_discriminant,
discriminant_spans.clone(),
"custom discriminant values are not allowed in enums with tuple or struct variants",
);
for sp in discriminant_spans {
err.span_label(sp, "disallowed custom discriminant");
}
for variant in variants.iter() {
match &variant.data {
VariantData::Struct(..) => {
err.span_label(variant.span, "struct variant defined here");
}
VariantData::Tuple(..) => {
err.span_label(variant.span, "tuple variant defined here");
}
VariantData::Unit(..) => {}
}
}
err.emit();
}
}

fn check_gat(&self, generics: &ast::Generics, span: Span) {
if !generics.params.is_empty() {
gate_feature_post!(
Expand Down Expand Up @@ -363,6 +403,26 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
}

ast::ItemKind::Enum(ast::EnumDef { ref variants, .. }, ..) => {
for variant in variants {
match (&variant.data, &variant.disr_expr) {
(ast::VariantData::Unit(..), _) => {}
(_, Some(disr_expr)) => gate_feature_post!(
&self,
arbitrary_enum_discriminant,
disr_expr.value.span,
"discriminants on non-unit variants are experimental"
),
_ => {}
}
}

let has_feature = self.features.arbitrary_enum_discriminant;
if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) {
self.maybe_report_invalid_custom_discriminants(&variants);
}
}

ast::ItemKind::Impl(box ast::ImplKind {
polarity, defaultness, ref of_trait, ..
}) => {
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_error_codes/src/error_codes/E0732.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ An `enum` with a discriminant must specify a `#[repr(inttype)]`.
Erroneous code example:

```compile_fail,E0732
#![feature(arbitrary_enum_discriminant)]

enum Enum { // error!
Unit = 1,
Tuple() = 2,
Expand All @@ -18,6 +20,8 @@ is a well-defined way to extract a variant's discriminant from a value;
for instance:

```
#![feature(arbitrary_enum_discriminant)]

#[repr(u8)]
enum Enum {
Unit = 3,
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_feature/src/accepted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,6 @@ declare_features! (
(accepted, const_fn_transmute, "1.56.0", Some(53605), None),
/// Allows accessing fields of unions inside `const` functions.
(accepted, const_fn_union, "1.56.0", Some(51909), None),
/// Allows explicit discriminants on non-unit enum variants.
(accepted, arbitrary_enum_discriminant, "1.56.0", Some(60553), None),
/// Allows macro attributes to observe output of `#[derive]`.
(accepted, macro_attributes_in_derive_output, "1.57.0", Some(81119), None),
/// Allows panicking during const eval (producing compile-time errors).
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,9 @@ declare_features! (
/// Allows #[repr(transparent)] on unions (RFC 2645).
(active, transparent_unions, "1.37.0", Some(60405), None),

/// Allows explicit discriminants on non-unit enum variants.
(active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None),

/// Allows `async || body` closures.
(active, async_closure, "1.37.0", Some(62290), None),

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1374,7 +1374,7 @@ fn check_enum<'tcx>(
}
}

if tcx.adt_def(def_id).repr.int.is_none() {
if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant {
let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..));

let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# `arbitrary_enum_discriminant`

The tracking issue for this feature is: [#60553]

[#60553]: https://github.com/rust-lang/rust/issues/60553

------------------------

The `arbitrary_enum_discriminant` feature permits tuple-like and
struct-like enum variants with `#[repr(<int-type>)]` to have explicit discriminants.

## Examples

```rust
#![feature(arbitrary_enum_discriminant)]

#[allow(dead_code)]
#[repr(u8)]
enum Enum {
Unit = 3,
Tuple(u16) = 2,
Struct {
a: u8,
b: u16,
} = 1,
}

impl Enum {
fn tag(&self) -> u8 {
unsafe { *(self as *const Self as *const u8) }
}
}

assert_eq!(3, Enum::Unit.tag());
assert_eq!(2, Enum::Tuple(5).tag());
assert_eq!(1, Enum::Struct{a: 7, b: 11}.tag());
```
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![crate_type="lib"]
#![feature(arbitrary_enum_discriminant)]

enum Enum {
//~^ ERROR `#[repr(inttype)]` must be specified
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0732]: `#[repr(inttype)]` must be specified
--> $DIR/arbitrary_enum_discriminant-no-repr.rs:3:1
--> $DIR/arbitrary_enum_discriminant-no-repr.rs:4:1
|
LL | / enum Enum {
LL | |
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// run-pass
#![feature(const_raw_ptr_deref, test)]
#![feature(arbitrary_enum_discriminant, const_raw_ptr_deref, test)]

extern crate test;

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/enum-discriminant/discriminant_value.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// run-pass
#![allow(stable_features)]
#![feature(core, core_intrinsics)]
#![feature(arbitrary_enum_discriminant, core, core_intrinsics)]

extern crate core;
use core::intrinsics::discriminant_value;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#![crate_type="lib"]

enum Enum {
Unit = 1,
//~^ ERROR custom discriminant values are not allowed in enums with tuple or struct variants
Tuple() = 2,
//~^ ERROR discriminants on non-unit variants are experimental
Struct{} = 3,
//~^ ERROR discriminants on non-unit variants are experimental
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
error[E0658]: discriminants on non-unit variants are experimental
--> $DIR/feature-gate-arbitrary_enum_discriminant.rs:6:13
|
LL | Tuple() = 2,
| ^
|
= note: see issue #60553 <https://github.com/rust-lang/rust/issues/60553> for more information
= help: add `#![feature(arbitrary_enum_discriminant)]` to the crate attributes to enable

error[E0658]: discriminants on non-unit variants are experimental
--> $DIR/feature-gate-arbitrary_enum_discriminant.rs:8:14
|
LL | Struct{} = 3,
| ^
|
= note: see issue #60553 <https://github.com/rust-lang/rust/issues/60553> for more information
= help: add `#![feature(arbitrary_enum_discriminant)]` to the crate attributes to enable

error[E0658]: custom discriminant values are not allowed in enums with tuple or struct variants
--> $DIR/feature-gate-arbitrary_enum_discriminant.rs:4:10
|
LL | Unit = 1,
| ^ disallowed custom discriminant
LL |
LL | Tuple() = 2,
| ----------- tuple variant defined here
LL |
LL | Struct{} = 3,
| ------------ struct variant defined here
|
= note: see issue #60553 <https://github.com/rust-lang/rust/issues/60553> for more information
= help: add `#![feature(arbitrary_enum_discriminant)]` to the crate attributes to enable

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0658`.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(core_intrinsics)]
#![feature(arbitrary_enum_discriminant, core_intrinsics)]

extern crate core;
use core::intrinsics::discriminant_value;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(core_intrinsics)]
#![feature(arbitrary_enum_discriminant, core_intrinsics)]

extern crate core;
use core::intrinsics::discriminant_value;
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/enum-discriminant/issue-70509-partial_eq.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// run-pass
#![feature(repr128)]
#![feature(repr128, arbitrary_enum_discriminant)]
//~^ WARN the feature `repr128` is incomplete

#[derive(PartialEq, Debug)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
warning: the feature `repr128` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/issue-70509-partial_eq.rs:2:12
|
LL | #![feature(repr128)]
LL | #![feature(repr128, arbitrary_enum_discriminant)]
| ^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

// This test checks panic emitted from `mem::{uninitialized,zeroed}`.

#![feature(never_type)]
#![feature(never_type, arbitrary_enum_discriminant)]
#![allow(deprecated, invalid_value)]

use std::{
Expand Down
7 changes: 7 additions & 0 deletions src/test/ui/parser/issue-17383.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
enum X {
A = 3,
//~^ ERROR custom discriminant values are not allowed in enums with tuple or struct variants
B(usize)
}

fn main() {}
15 changes: 15 additions & 0 deletions src/test/ui/parser/issue-17383.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
error[E0658]: custom discriminant values are not allowed in enums with tuple or struct variants
--> $DIR/issue-17383.rs:2:9
|
LL | A = 3,
| ^ disallowed custom discriminant
LL |
LL | B(usize)
| -------- tuple variant defined here
|
= note: see issue #60553 <https://github.com/rust-lang/rust/issues/60553> for more information
= help: add `#![feature(arbitrary_enum_discriminant)]` to the crate attributes to enable

error: aborting due to previous error

For more information about this error, try `rustc --explain E0658`.
12 changes: 12 additions & 0 deletions src/test/ui/parser/tag-variant-disr-non-nullary.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
enum Color {
Red = 0xff0000,
//~^ ERROR custom discriminant values are not allowed in enums with tuple or struct variants
Green = 0x00ff00,
Blue = 0x0000ff,
Black = 0x000000,
White = 0xffffff,
Other(usize),
Other2(usize, usize),
}

fn main() {}
25 changes: 25 additions & 0 deletions src/test/ui/parser/tag-variant-disr-non-nullary.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
error[E0658]: custom discriminant values are not allowed in enums with tuple or struct variants
--> $DIR/tag-variant-disr-non-nullary.rs:2:11
|
LL | Red = 0xff0000,
| ^^^^^^^^ disallowed custom discriminant
LL |
LL | Green = 0x00ff00,
| ^^^^^^^^ disallowed custom discriminant
LL | Blue = 0x0000ff,
| ^^^^^^^^ disallowed custom discriminant
LL | Black = 0x000000,
| ^^^^^^^^ disallowed custom discriminant
LL | White = 0xffffff,
| ^^^^^^^^ disallowed custom discriminant
LL | Other(usize),
| ------------ tuple variant defined here
LL | Other2(usize, usize),
| -------------------- tuple variant defined here
|
= note: see issue #60553 <https://github.com/rust-lang/rust/issues/60553> for more information
= help: add `#![feature(arbitrary_enum_discriminant)]` to the crate attributes to enable

error: aborting due to previous error

For more information about this error, try `rustc --explain E0658`.