Skip to content

What are semantics of empty enums that have been artificially fabricated? #4499

Description

@brson

Updated bug report follows (see bottom for original bug report)

This bug appears to have been filed in error but then spawned a very interesting conversation.

The question centers around how empty enums (e.g. enum Foo { }, which has zero variants) which in principle cannot safely exist, interact with our casting operations (namely safe as and unsafecast::transmute).

Here is an some code that I wrote that summarizes the various scenarios that were described in the comments. Most of the scenarios do not compile (which is good). The fifth, sixth, and seventh all compile; their runtime behaviors vary, but most are acceptable. The only questionable thing @pnkfelix can see here is the behavior for the seventh example, cfg ex7.
Code:

#[allow(dead_code)];
use std::cast;
enum Foo { }
struct Bar;

#[cfg(ex1)]
fn main() {
    let i = Foo as int;
    println!("i: {:?}", i);
}

#[cfg(ex2)]
fn main() {
    fn f(f: Foo) -> int { f as int }
}

#[cfg(ex3)]
fn main() {
    let i : Foo = unsafe { cast::transmute(3) };
    println!("i: {:?}", i);
}

#[cfg(ex4)]
fn main() {
    let b : Bar = Bar;
    let i : Foo = b as Foo;
    println!("b: {:?}", b);
    println!("i: {:?}", i);
}

#[cfg(ex5)]
fn main() {
    let b : Bar = Bar;
    let i : Foo = unsafe { cast::transmute(b) };
    println!("b: {:?}", b);
    println!("i: {:?}", i);
}

#[cfg(ex6)]
fn main() {
    let b : Bar = Bar;
    let i : Foo = unsafe { cast::transmute(b) };
    println!("b: {:?}", b);
    match i {
    }
}

#[cfg(ex7)]
fn main() {
    let b : Bar = Bar;
    let i : Foo = unsafe { cast::transmute(b) };
    println!("b: {:?}", b);
    match i {
        _ => { println!("The impossible!"); }
    }
}

Transcript of compile (+ runs when compilable):

% rustc --cfg ex1 /tmp/ee.rs && ./ee
/tmp/ee.rs:8:13: 8:16 error: unresolved name `Foo`.
/tmp/ee.rs:8     let i = Foo as int;
                         ^~~
error: aborting due to previous error
% rustc --cfg ex2 /tmp/ee.rs && ./ee
/tmp/ee.rs:14:27: 14:35 error: non-scalar cast: `Foo` as `int`
/tmp/ee.rs:14     fn f(f: Foo) -> int { f as int }
                                        ^~~~~~~~
error: aborting due to previous error
% rustc --cfg ex3 /tmp/ee.rs && ./ee
/tmp/ee.rs:1:1: 1:1 error: transmute called on types with different sizes: int (64 bits) to Foo (0 bits)
/tmp/ee.rs:1 #[allow(dead_code)];
             ^
% rustc --cfg ex4 /tmp/ee.rs && ./ee
/tmp/ee.rs:26:19: 26:27 error: non-scalar cast: `Bar` as `Foo`
/tmp/ee.rs:26     let i : Foo = b as Foo;
                                ^~~~~~~~
error: aborting due to previous error
% rustc --cfg ex5 /tmp/ee.rs && ./ee
b: Bar
task '<main>' failed at 'enum value matched no variant', /Users/fklock/Dev/Mozilla/rust.git/src/libstd/repr.rs:559
% rustc --cfg ex6 /tmp/ee.rs && ./ee
b: Bar
task '<main>' failed at 'scrutinizing value that can't exist', /tmp/ee.rs:44
% rustc --cfg ex7 /tmp/ee.rs && ./ee
b: Bar
The impossible!
% 

Original bug report follows:

Something like this works:

enum Foo { }

let i = Foo as int;

Doesn't make any sense.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions