Skip to content

Commit

Permalink
Auto merge of #86860 - fee1-dead:stabilize, r=LeSeulArtichaut
Browse files Browse the repository at this point in the history
Stabilize `arbitrary_enum_discriminant`

Closes #60553.

----

## Stabilization Report

_copied from #60553 (comment)

### Summary

Enables a user to specify *explicit* discriminants on arbitrary enums.

Previously, this was hard to achieve:

```rust
#[repr(u8)]
enum Foo {
    A(u8) = 0,
    B(i8) = 1,
    C(bool) = 42,
}
```

Someone would need to add 41 hidden variants in between as a workaround with implicit discriminants.

In conjunction with [RFC 2195](https://github.com/rust-lang/rfcs/blob/master/text/2195-really-tagged-unions.md), this feature would provide more flexibility for FFI and unsafe code involving enums.

### Test cases

Most tests are in [`src/test/ui/enum-discriminant`](https://github.com/rust-lang/rust/tree/master/src/test/ui/enum-discriminant), there are two [historical](https://github.com/rust-lang/rust/blob/master/src/test/ui/parser/tag-variant-disr-non-nullary.rs) [tests](https://github.com/rust-lang/rust/blob/master/src/test/ui/parser/issue-17383.rs) that are now covered by the feature (removed by this pr due to them being obsolete).

### Edge cases

The feature is well defined and does not have many edge cases.
One [edge case](#70509) was related to another unstable feature named `repr128` and is resolved.

### Previous PRs

The [implementation PR](#60732) added documentation to the Unstable Book, rust-lang/reference#1055 was opened as a continuation of rust-lang/reference#639.

### Resolution of unresolved questions

The questions are resolved in #60553 (comment).

----

(someone please add `needs-fcp`)
  • Loading branch information
bors committed Aug 18, 2021
2 parents adf1688 + 7a62f29 commit 02b27f1
Show file tree
Hide file tree
Showing 21 changed files with 13 additions and 221 deletions.
64 changes: 2 additions & 62 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, VariantData};
use rustc_ast::{PatKind, RangeEnd};
use rustc_errors::struct_span_err;
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
use rustc_feature::{Features, GateIssue};
use rustc_session::parse::{feature_err, feature_err_issue};
use rustc_session::parse::feature_err_issue;
use rustc_session::Session;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym;
Expand Down Expand Up @@ -218,46 +218,6 @@ 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 @@ -402,26 +362,6 @@ 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: 0 additions & 4 deletions compiler/rustc_error_codes/src/error_codes/E0732.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ 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 @@ -20,8 +18,6 @@ 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: 2 additions & 0 deletions compiler/rustc_feature/src/accepted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,8 @@ 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),

// -------------------------------------------------------------------------
// feature-group-end: accepted features
Expand Down
3 changes: 0 additions & 3 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,9 +471,6 @@ 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 @@ -1383,7 +1383,7 @@ fn check_enum<'tcx>(
}
}

if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant {
if tcx.adt_def(def_id).repr.int.is_none() {
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

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#![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:4:1
--> $DIR/arbitrary_enum_discriminant-no-repr.rs:3:1
|
LL | / enum Enum {
LL | |
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// run-pass
#![feature(arbitrary_enum_discriminant, const_raw_ptr_deref, test)]
#![feature(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(arbitrary_enum_discriminant, core, core_intrinsics)]
#![feature(core, core_intrinsics)]

extern crate core;
use core::intrinsics::discriminant_value;
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(arbitrary_enum_discriminant, core_intrinsics)]
#![feature(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(arbitrary_enum_discriminant, core_intrinsics)]
#![feature(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, arbitrary_enum_discriminant)]
#![feature(repr128)]
//~^ 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, arbitrary_enum_discriminant)]
LL | #![feature(repr128)]
| ^^^^^^^
|
= 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 @@ -5,7 +5,7 @@

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

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

use std::{
Expand Down
7 changes: 0 additions & 7 deletions src/test/ui/parser/issue-17383.rs

This file was deleted.

15 changes: 0 additions & 15 deletions src/test/ui/parser/issue-17383.stderr

This file was deleted.

12 changes: 0 additions & 12 deletions src/test/ui/parser/tag-variant-disr-non-nullary.rs

This file was deleted.

25 changes: 0 additions & 25 deletions src/test/ui/parser/tag-variant-disr-non-nullary.stderr

This file was deleted.

0 comments on commit 02b27f1

Please sign in to comment.