# Recent change to make exhaustiveness and uninhabited types play nicer together

**URL:** <https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602>\
**Category:** compiler\
**Created:** [January 12, 2017, 6:44pm UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602 "2017-01-12T18:44:41Z")\
**Posts on this page:** 20\
**Page:** 4

<div class="post-metadata">

**Author:** ![briansmith](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/briansmith/32/1306_2.png) [@briansmith](https://internals.rust-lang.org/u/briansmith)\
**Post date:** [January 18, 2017, 9:05pm UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602/61 "2017-01-18T21:05:02Z")

</div>

Here’s a another way to think about things. Imagine:

```rust
struct Result<V, E> {
    Ok(V),
    Err(E) if E: Inhabited,
}

```

I imagine there are lots of type-parameterized enums where some variants don’t make sense for some types of parameters, so maybe it makes sense to go this direction.

---

<div class="post-metadata">

**Author:** ![briansmith](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/briansmith/32/1306_2.png) [@briansmith](https://internals.rust-lang.org/u/briansmith)\
**Post date:** [January 18, 2017, 9:39pm UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602/62 "2017-01-18T21:39:42Z")

</div>

> [@briansmith](#):
>
> // No need to implement any methods for implementations of traits // by uninhabited types, since there are no values of `Self` or // `&Self`. Instead the compiler will automatically derive no-op // implementations. impl\<T: Uninhabited\> fmt::Debug for T {}

I just discovered that there's even an RFC for this already: [Allow uncallable method impls to be omitted by canndrew · Pull Request #1699 · rust-lang/rfcs · GitHub](https://github.com/rust-lang/rfcs/pull/1699).

---

<div class="post-metadata">

**Author:** ![comex](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/comex/32/2587_2.png) [@comex](https://internals.rust-lang.org/u/comex)\
**Post date:** [January 18, 2017, 10:11pm UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602/63 "2017-01-18T22:11:49Z")

</div>

But what is the point of requiring everyone to special-case uninhabited types if things work fine without? That would make `Result<T, !>` pretty much useless (the only reason to use it over just `T` is to make the same code work for both fallible and infallible operations). In fact, arguably it would make uninhabited types fairly useless as a whole, which seems to conflict with the acceptance of RFC 1216…

---

<div class="post-metadata">

**Author:** ![ahmedcharles](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ahmedcharles/32/4041_2.png) [@ahmedcharles](https://internals.rust-lang.org/u/ahmedcharles)\
**Post date:** [January 19, 2017, 4:36am UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602/64 "2017-01-19T04:36:27Z")

</div>

I’m trying to understand the issue here, so I decided to write some FFI code:

```rust
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

struct UninhabitedTest {
  uint64_t data;
};

struct UninhabitedTest* uninhabited_test_new(uint64_t d) {
  struct UninhabitedTest* ut = malloc(sizeof(struct UninhabitedTest));
  ut->data = d;
  puts("new");
  return ut;
}

void uninhabited_test_delete(struct UninhabitedTest* ut) {
  puts("delete");
  free(ut);
}

uint64_t uninhabited_test_get_data(struct UninhabitedTest* ut) {
  puts("get_data");
  return ut->data;
}

```

```rust
extern crate libc;

mod ut {
    mod ffi {
        #[repr(C)]
        pub struct UninhabitedTestImpl {
            _priv: u8,
        }

        extern {
            pub fn uninhabited_test_new(d: ::libc::uint64_t) -> *mut UninhabitedTestImpl;
            pub fn uninhabited_test_delete(ut: *mut UninhabitedTestImpl) -> ::libc::c_void;
            pub fn uninhabited_test_get_data(ut: *mut UninhabitedTestImpl) -> ::libc::uint64_t;
        }
    }

    pub struct UninhabitedTest {
        data: *mut ffi::UninhabitedTestImpl,
    }

    impl UninhabitedTest {
        pub fn new(d: u64) -> UninhabitedTest {
            let ut = unsafe { ffi::uninhabited_test_new(d) };
            if ut.is_null() { panic!("ran out of memory"); }
            UninhabitedTest { data: ut }
        }

        pub fn data(&self) -> u64 {
            unsafe { ffi::uninhabited_test_get_data(self.data) }
        }
    }

    impl Drop for UninhabitedTest {
        fn drop(&mut self) {
            unsafe { ffi::uninhabited_test_delete(self.data) };
        }
    }
}

fn main() {
    use ut::UninhabitedTest;

    let input = 4;
    let ut = UninhabitedTest::new(input);
    let output = ut.data();
    println!("input: {}", input);
    println!("output: {}", output);
}

```

I’d admit that having to use a u8 as a member in order to stop lints from giving me warnings is a bit annoying, but as far as I can tell, this code is correct?

Rust isn’t allowed to dereference a `*mut _` automatically and this code never does it manually, so only the C code will ever do it.

The only problem would be if the author of the `ut` module leaks a `*mut UninhabitedTestImpl` or `*const UninhabitedTestImpl` or creates `&UninhabitedTestImpl` or `&mut UninhabitedTestImpl`. I.e. authors of unsafe code have to be careful and know what they are doing. I don’t see why that is an unreasonable burden, unless I’m missing something?

---

<div class="post-metadata">

**Author:** ![ahmedcharles](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ahmedcharles/32/4041_2.png) [@ahmedcharles](https://internals.rust-lang.org/u/ahmedcharles)\
**Post date:** [January 19, 2017, 4:45am UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602/65 "2017-01-19T04:45:41Z")

</div>

```rust
   let foo = unsafe { &*foo };

```

The issue here is that you’re creating a ‘safe’ reference to a raw pointer. There’s no reason to do this if what you want is an opaque type and there’s no reason that users of the library/module should have the access required to do this either.

---

<div class="post-metadata">

**Author:** ![briansmith](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/briansmith/32/1306_2.png) [@briansmith](https://internals.rust-lang.org/u/briansmith)\
**Post date:** [January 19, 2017, 7:32am UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602/66 "2017-01-19T07:32:27Z")

</div>

> [@ahmedcharles](#):
>
> > ```rust
> > 
> > ```
> 
> let foo = unsafe { &\*foo };
> 
> ```rust
> 
> The issue here is that you're creating a 'safe' reference to a raw pointer. There's no reason to do this if what you want is an opaque type and there's no reason that users of the library/module should have the access required to do this either.
> 
> ```

I do this literally all the time in my Rust wrappers around C types. Whenever possible I try to use references instead of pointers as the types of parameters in my FFI functions because references denote aliasing and non-null requirements that pointers don't. For example, I have `fn add(result: &mut BIGNUM, a: &BIGNUM, b: &BIGNUM)` which indicates that none of the parameters may be NULL, and `result` may not alias either `a` or `b`. Therefore my wrapper around `BIGNUM` has `as_ref(&self) -> &BIGNUM { unsafe { &*self.0 } }`, which apparently (and surprisingly) is dreadfully dangerous.

If Rust had a true opaque type mechanism like `extern { type BIGNUM; }` then this would work perfectly safely, AFAICT.

---

<div class="post-metadata">

**Author:** ![ahmedcharles](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ahmedcharles/32/4041_2.png) [@ahmedcharles](https://internals.rust-lang.org/u/ahmedcharles)\
**Post date:** [January 19, 2017, 9:35am UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602/67 "2017-01-19T09:35:53Z")

</div>

I’ll just go with a straight C example. The API for Lua has a `lua_State` as an opaque pointer by virtue of it being declared but not defined in the public header file. What you’re suggesting is equivalent to dereferencing an incomplete type in C. Why should Rust allow that when even C doesn’t?

If that’s the basis of this ‘problem’ with Rust, then I don’t see why the discussion is still happening, because the goals of having opaque pointers for use in FFI and being able to form safe references to the same types in Rust seem directly opposed.

---

<div class="post-metadata">

**Author:** ![briansmith](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/briansmith/32/1306_2.png) [@briansmith](https://internals.rust-lang.org/u/briansmith)\
**Post date:** [January 19, 2017, 9:42am UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602/68 "2017-01-19T09:42:46Z")

</div>

I’m happy to admit I’m not doing it the right way. Please tell me what the right way of creating a reference to an incomplete type, such as in this C++ example, which compiles just fine, [https://godbolt.org/g/M2jdnP:](https://godbolt.org/g/M2jdnP:)

```rust
extern "C" {
    struct BIGNUM;
    BIGNUM *new_bignum();
    void delete_bignum(BIGNUM *);    
}

void foo() {
    BIGNUM *b = new_bignum();
    BIGNUM &b_ref = *b;
    delete_bignum(b);
}

```

---

<div class="post-metadata">

**Author:** ![ahmedcharles](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ahmedcharles/32/4041_2.png) [@ahmedcharles](https://internals.rust-lang.org/u/ahmedcharles)\
**Post date:** [January 19, 2017, 10:49am UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602/69 "2017-01-19T10:49:56Z")

</div>

That is in fact, conforming C++. C++ allows using the ‘indirection’ operator on a pointer to incomplete type in limited cases, one of which is to form a reference. But, I fail to see how this gives you anything useful. You can’t call functions on it directly and it can’t be used in a way that would require a lvalue-to-rvalue conversion. I suppose that leaves, passing it as a reference to a function that is defined in a context where the type is complete or to take the address and turn it back into a pointer. It can also be used in some, but not all, metaprogramming techniques.

I still fail to see how having a reference here is useful. The fact that it can’t be null isn’t really useful when you can’t actually do anything with it while it’s incomplete.

In the case of Rust, what point is there in proving that they can’t alias if Rust can’t do anything with the pointers other than pass them to an FFI function? It also doesn’t matter if it can or can’t be null if you can’t dereference it at all.

What benefit are you actually trying to achieve?

---

<div class="post-metadata">

**Author:** ![notriddle](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/notriddle/32/14082_2.png) [@notriddle](https://internals.rust-lang.org/u/notriddle)\
**Post date:** [January 19, 2017, 4:47pm UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602/70 "2017-01-19T16:47:09Z")

</div>

> [@briansmith](#):
>
> Regarding the match, the only clearly reasonable bodies of a match on such values is the empty body, which is a no-op. Therefore, it makes sense for the compiler to statically reject such matches too.

First of all, that would be a massively breaking change. Empty matches are used all over the place as a stable construct that generates an unreachable intrinsic.

Second of all, people need to write code generators sometimes. That's why [RFC 218](https://github.com/rust-lang/rfcs/pull/218) was accepted and implemented. I, at least, want to be able to invoke `quick_error!` with no arguments and get a data type that implements all the error traits, but happens to be impossible to construct because it doesn't have any variants.

---

<div class="post-metadata">

**Author:** ![mystor](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mystor/32/6542_2.png) [@mystor](https://internals.rust-lang.org/u/mystor)\
**Post date:** [January 19, 2017, 7:55pm UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602/71 "2017-01-19T19:55:51Z")

</div>

The workaround I currently use for opaque types is also really awful:

```rust
mod foo { #[repr(C)] pub struct Foo([u8;0]); }

```

Which, like your solution using `u8` instead of `[u8;0]` also runs into the moving problems, but has the advantage of being zero sized which means that things like `mem::swap`-ing between pointers of that type is a no-op.

My suggested solution at one point to this problem was [[Pre-RFC] Opaque Structs](https://internals.rust-lang.org/t/pre-rfc-opaque-structs/4005) - but the thread didn’t seem to go anywhere.

---

<div class="post-metadata">

**Author:** ![ahmedcharles](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ahmedcharles/32/4041_2.png) [@ahmedcharles](https://internals.rust-lang.org/u/ahmedcharles)\
**Post date:** [January 19, 2017, 9:55pm UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602/72 "2017-01-19T21:55:15Z")

</div>

Using a `[u8;0]` to make it 0 size is a nice trick.

I think it would be reasonable to have a way to declare a type which can only be used like `*const T` and `*mut T`, can’t be dereferenced and is `#[repr©] by default. This would allow having opaque pointers to something on the other side of the FFI boundary without any risk of Rust (or users) invoking UB, since the pointer can only be stored and passed through FFI to other code.

---

<div class="post-metadata">

**Author:** ![arielb1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/arielb1/32/3044_2.png) [@arielb1](https://internals.rust-lang.org/u/arielb1)\
**Post date:** [January 20, 2017, 12:50am UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602/73 "2017-01-20T00:50:56Z")

</div>

That actually sounds like a hole in the `improper_ctypes` lint. Not a hole that I’ll like fixed, in any case.

That makes `extern type` a rather low priority feature.

---

<div class="post-metadata">

**Author:** ![canndrew](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/canndrew/32/1676_2.png) [@canndrew](https://internals.rust-lang.org/u/canndrew)\
**Post date:** [January 21, 2017, 11:26am UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602/74 "2017-01-21T11:26:36Z")

</div>

I slapped together an RFC for the `extern type` proposal: [https://github.com/rust-lang/rfcs/pull/1861](https://github.com/rust-lang/rfcs/pull/1861)

That’s probably the best place to discuss this as this thread is getting a little off-topic.

---

<div class="post-metadata">

**Author:** ![arielb1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/arielb1/32/3044_2.png) [@arielb1](https://internals.rust-lang.org/u/arielb1)\
**Post date:** [January 24, 2017, 9:34pm UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602/75 "2017-01-24T21:34:20Z")

</div>

I’ve talked about the `&mut` issue with @nikomatsakis, and it seems that the following desirable properties are incompatible:

1. match exhaustiveness is identical between safe and unsafe code
2. &! is matchck-uninhabited in safe code
3. matches don’t assert deep validity in unsafe code
4. uninhabited types are not treated specially for UB
5. if a match is exhaustive, every arm you add to its end can never be reached

The problem is: Because of (2), you can write this code:

```rust
    let x: &! = get();
    match x {
    }

```

From (1), we also get

```rust
    unsafe {
        let x: &! = get();
        match x {
        }
    }

```

On the other hand, we also want this to be non-UB - aka (3)

```rust
    unsafe {
        let x: &Whatever = get();
        match x {
            y => println!("hi {:?}", y as *const _)
        }
    }

```

Because of (4), this is equivalent to

```rust
    unsafe {
        let x: &! = get();
        match x {
            y => println!("hi {:?}", y as *const _)
        }   
    }

```

Which contradicts (5)

---

<div class="post-metadata">

**Author:** ![canndrew](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/canndrew/32/1676_2.png) [@canndrew](https://internals.rust-lang.org/u/canndrew)\
**Post date:** [January 25, 2017, 1:09pm UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602/76 "2017-01-25T13:09:34Z")

</div>

There’s a PR to roll-back and feature gate all the changes surrounding uninhabited types in matches [here](https://github.com/rust-lang/rust/pull/39290). I also just posted and RFC arguing that these changes should be re-instated [here](https://github.com/rust-lang/rfcs/pull/1872) (before having seen @arielb1’s comment).

---

<div class="post-metadata">

**Author:** ![canndrew](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/canndrew/32/1676_2.png) [@canndrew](https://internals.rust-lang.org/u/canndrew)\
**Post date:** [January 25, 2017, 1:25pm UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602/77 "2017-01-25T13:25:20Z")

</div>

@arielb1

There’s two ways out of this that I can see: One is to say that we hit UB as soon as we try to return a `&!`. A value returned by `get()` isn’t just invalid, it’s _provably_ invalid, statically. This is different to trying to return a NULL `&u32` - we may not be able to prove that this value is valid but can’t prove that it’s invalid either. We could make a distinction between safe and unsafe code where, in safe code, we need to be able to prove that all accessible data is valid to guarantee safety whereas, in unsafe code, we just need to not be able to prove that some accessible data is invalid.

The other is to recognize that (5) is true - unless your types are lying to you. We shouldn’t force people to consider that possibility. If they do want to consider that possibility, we can say they’re welcome to and this code will run fine:

```
unsafe {
    let x: &! = get();
    match x {
        y => println!("hi {:?}", y as *const _)
    }   
}

```

But the uninhabitedness changes also allow them to write this code:

```
unsafe {
    let x: &! = get();
    match x {
    }   
}

```

Why shouldn’t they be allowed to write this? Yes it’s broken but it’s broken because they fucked up using `unsafe` to create an impossible value _and then matched on it_. I mean, how much leeway to we need to give people, really? If this code shouldn’t be allowed then neither should exhaustively matching on a `bool` by testing for both `true` and `false`. What if they create a `42: bool` and try to match on it? We don’t want their code to break! Better force them to match on every possible bit-pattern of a `bool` instead,

---

<div class="post-metadata">

**Author:** ![arielb1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/arielb1/32/3044_2.png) [@arielb1](https://internals.rust-lang.org/u/arielb1)\
**Post date:** [January 25, 2017, 1:43pm UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602/78 "2017-01-25T13:43:00Z")

</div>

The current consensus is that you can’t have a `NULL: &u8` or a `42: bool` any more than you can have a `256: u8` - any attempt to create such is instant UB.

---

<div class="post-metadata">

**Author:** ![canndrew](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/canndrew/32/1676_2.png) [@canndrew](https://internals.rust-lang.org/u/canndrew)\
**Post date:** [January 25, 2017, 1:45pm UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602/79 "2017-01-25T13:45:34Z")

</div>

Yes, and you can’t have `empty_vector_of_bits: !` either. So if you match on that it’s instant UB. This code:

```rust
unsafe {
    let x: &! = get();
    match x {
    }   
}

```

dereferences the pointer and matches on the contained `!`. That’s UB.

---

<div class="post-metadata">

**Author:** ![arielb1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/arielb1/32/3044_2.png) [@arielb1](https://internals.rust-lang.org/u/arielb1)\
**Post date:** [January 25, 2017, 1:56pm UTC](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602/80 "2017-01-25T13:56:42Z")

</div>

That’s the !(5) position. Personally, I am split between !(5) and !(1).

[Previous page](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602.md?page=3)

[Next page](https://internals.rust-lang.org/t/recent-change-to-make-exhaustiveness-and-uninhabited-types-play-nicer-together/4602.md?page=5)
