Skip to content

Commit 996e5ed

Browse files
committed
Disallow non-c-like but "fieldless" ADTs from being casted to integer...
... if they use arbitrary enum discriminant. Code like ```rust enum Enum { Foo = 1, Bar(), Baz{} } ``` seems to be unintentionally allowed so we couldn't disallow them now, but we could disallow them if arbitrary enum discriminant is used before 1.56 hits stable.
1 parent 308dffd commit 996e5ed

File tree

4 files changed

+37
-14
lines changed

4 files changed

+37
-14
lines changed

compiler/rustc_middle/src/ty/adt.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_data_structures::fx::FxHashMap;
88
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
99
use rustc_errors::ErrorReported;
1010
use rustc_hir as hir;
11-
use rustc_hir::def::{DefKind, Res};
11+
use rustc_hir::def::{CtorKind, DefKind, Res};
1212
use rustc_hir::def_id::DefId;
1313
use rustc_index::vec::{Idx, IndexVec};
1414
use rustc_serialize::{self, Encodable, Encoder};
@@ -314,6 +314,22 @@ impl<'tcx> AdtDef {
314314
/// Whether the ADT lacks fields. Note that this includes uninhabited enums,
315315
/// e.g., `enum Void {}` is considered payload free as well.
316316
pub fn is_payloadfree(&self) -> bool {
317+
// Treat the ADT as not payload-free if arbitrary_enum_discriminant is used (#88621).
318+
// This would disallow the following kind of enum from being casted into integer.
319+
// ```
320+
// enum Enum {
321+
// Foo() = 1,
322+
// Bar{} = 2,
323+
// Baz = 3,
324+
// }
325+
// ```
326+
if self
327+
.variants
328+
.iter()
329+
.any(|v| matches!(v.discr, VariantDiscr::Explicit(_)) && v.ctor_kind != CtorKind::Const)
330+
{
331+
return false;
332+
}
317333
self.variants.iter().all(|v| v.fields.is_empty())
318334
}
319335

src/test/ui/cast/issue-88621.rs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#[repr(u8)]
2+
enum Kind2 {
3+
Foo() = 1,
4+
Bar{} = 2,
5+
Baz = 3,
6+
}
7+
8+
fn main() {
9+
let _ = Kind2::Foo() as u8;
10+
//~^ ERROR non-primitive cast
11+
}

src/test/ui/cast/issue-88621.stderr

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0605]: non-primitive cast: `Kind2` as `u8`
2+
--> $DIR/issue-88621.rs:9:13
3+
|
4+
LL | let _ = Kind2::Foo() as u8;
5+
| ^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0605`.

src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs

-13
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,6 @@ impl Enum {
2222
}
2323
}
2424

25-
#[allow(dead_code)]
26-
#[repr(u8)]
27-
enum FieldlessEnum {
28-
Unit = 3,
29-
Tuple() = 2,
30-
Struct {} = 1,
31-
}
32-
3325
fn main() {
3426
const UNIT: Enum = Enum::Unit;
3527
const TUPLE: Enum = Enum::Tuple(5);
@@ -48,9 +40,4 @@ fn main() {
4840
assert_eq!(3, UNIT_TAG);
4941
assert_eq!(2, TUPLE_TAG);
5042
assert_eq!(1, STRUCT_TAG);
51-
52-
// Ensure `as` conversions are correct
53-
assert_eq!(3, FieldlessEnum::Unit as u8);
54-
assert_eq!(2, FieldlessEnum::Tuple() as u8);
55-
assert_eq!(1, FieldlessEnum::Struct{} as u8);
5643
}

0 commit comments

Comments
 (0)