Opaque pointers in FFI

Slightly, but only because it's predefined and the library implements a variety of traits for it. You can make your own !-like thing with enum Never {} the same way you can make your own ()-like thing with struct Unit.

Yes, optimizations can remove it the same way they can remove code in an if false (which also isn't a compilation error).

Code that syntactically dereferences a &! is fine, because there's no legal way to actually get such a thing to dereference. You "get" such a reference with things like if let Err(ref e) = r when r: Result<_, !>, which is just a type-level way of writing things like if 1 == 0.

Ok, that's good - I thought it was more like Box where rustc knows about it specifically.

So how come @Nemo157's example upthread, where a reference to a bogus uninhabited type is produced and used in a println!(), actually executes code? Why is the use of it not dead code eliminated? I think I understand what you're getting at with the "syntactical dereference", but at the same time all dereferences are syntactical to start with :slight_smile:.

Presumably because unsafe code lied to the type system and said "hey look, we actually have a valid instance of &! somehow. Let's use it!" and then the safe code said "k". It's not the existence of a function that accepts a reference to an uninhabited type that's at fault, since normally there'd be no way to call it in the first place and it would be dead code. The blame lies with unsafe code violating the invariants of reference types.

So another way to put it is that code elimination is done at the type expansion phase, where the compiler will eliminate all uses of the type as unreachable (i.e. the 1 == 0 analogy that @scottmcm mentioned). Ok, cool.

So what does this say, if anything, about the validity of &!/*const ! outside of type expansion? If this code is not eliminated in the same manner as generic instantiations, then it would seem ok to define these types but not read them in Rust code. But if the compiler is going to treat any &!/*const ! as unreachable (or replaceable with null in the raw pointer case), then it wouldn't work.

Note that this doesn't seem to fully happen today, though I believe it would be legal :stuck_out_tongue: Looking at the example above, you'll find

; <playground::Empty as core::fmt::Debug>::fmt
; Function Attrs: norecurse noreturn nounwind readnone uwtable
define internal zeroext i1 @"_ZN54_$LT$playground..Empty$u20$as$u20$core..fmt..Debug$GT$3fmt17h1ac3b14e592bbd2bE"(%Empty* noalias nocapture nonnull readonly %self, %"core::fmt::Formatter"* nocapture readnone dereferenceable(96) %__arg_0) unnamed_addr #2 {
start:
  unreachable
}

But apparently that doesn't get inlined into foo, so there's still some assembly generated for foo. I should write a MIR pass to DCE stuff that depends on uninhabited values...

So this is a good smoke test for inlining failures too :slight_smile:.

So missed optimizations aside, what’s the spec'd behavior supposed to be? It sounds like it’s dead code no matter if type level expansion or explicit. Is that the outcome of all those uninhabited discussions? Is the empty enum as opaque FFI broken today already? Is the above DCE plan only for references and not raw pointers? Where do we stand basically? :crazy_face:

I don't imagine it would apply to raw pointers because again, raw pointers can be whatever they want to be (or more accurately, they make no guarantees about the validity of what they point to) and the type system knows that. The only time you run into problems is when you dereference invalid pointers (which is unsafe) or turn invalid pointers into references (which is also unsafe).

1 Like

Well, this has been nominated for lang team discussion for three months now:

Personally, I find @canndrew's arguments persuasive.

1 Like

The problem is you can make an equally viable argument that it’s not really "whatever they want to be" but rather "null or undef" and then optimize on the basis that it’s null since the other option is UB.

At a glance, that seems very match focused but I'll read through it later - thanks for the pointer (no pun intended :slight_smile:).