Skip to content

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

Closed
@brson

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.

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