-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Set transmute from fn item to type fn lint a hard error #19925
Comments
Nominating. Not sure how important this is. |
P-high, not 1.0 milestone. |
On a related note, the subtyping relation is not quite right. This code should not type check: fn foo<A>(_: A, _: A) { }
fn bar<B>() { }
fn main() {
let x = bar::<u32>;
let y = bar::<i32>;
foo(x, y);
} |
To elaborate, the type of |
Put another way, the type of a fn item ought to have the values for all of its substs (sort of like |
Nominating. Not sure how seriously to take this (but probably not that hard to fix). |
Classifying even the type-system issue as a "bug that needs fixing" -- thus we can afford to leave this as P-high, not a 1.0-blocker. |
Tagging as P-backcompat-lang since compiler incorrectly accepts things it shouldn't accept. |
Closing it as in "this has been fully implemented", by merging #34198. |
The latter point may be true, but |
Yeah...I know. |
cc @pnkfelix and @withoutboats -- your thoughts here? |
@nikomatsakis can't you always |
@withoutboats you can, indeed. In any case, the proposal is to remove the special case from transmute (and hence you will get a hard error). What I am saying is merely that I would like a more concise syntax here, since when you actually have to write (e.g.) @eddyb -- one thing, though it has more to do w/ the PR than this, I think we should make sure to give a very clear error message, along with a suggestion of what to write instead. |
@rfcbot reviewed
Sounds reasonable, just wanted to make sure I understand that this special case is just about concision & not expressibility. |
@nikomatsakis In that case, we have to keep the special-casing code where we're not emitting the lint. |
Yes, such is life. I left a comment in the PR. |
Basically nice errors == special-case code. =) |
@rfcbot reviewed |
It seems that @rfcbot went on vacation. I will put this into Final Comment Period manually: 🔔 Hear ye, hear ye! This issue is now entering a 3-week final comment period, which expires February 7, 2017. 🔔The intention is to convert this forward compatibility warning into a hard error. |
🔔 This is now entering its final comment period, as per the review above. 🔔 psst @eddyb, I wasn't able to add the |
The final comment period is now complete. |
Although the FCP is complete, the change has not been finalized, and I want to float one possible tweak to the rules that might go a long way to eliminating the annoyance that these rules can cause. Each function has a unique type, but we could make the unique types for |
I raised this with @nikomatsakis privately because this broke a significant amount of code I wrote that I just came back to after a number of months. In my view While there may be some cases of extern "C" functions that are only ever called from Rust, this seems exceedingly rare compared to extern "C" functions meant to be called from C. Since pointers are part of the C representation in such an exceedingly large % of cases, the extra type-cast we're imposing here seems inappropriate. |
@wycats You should never need the |
@eddyb you don't need the transmute because you can do a manual cast? |
I suppose we should've been stricter and not allow many type combinations, where a better option exists. |
…el-bad, r=nikomatsakis Make transmuting from fn item types to pointer-sized types a hard error. Closes #19925 by removing the future compatibility lint and the associated workarounds. This is a `[breaking-change]` if you `transmute` from a function item without casting first. For more information on how to fix your code, see #19925.
My take on this proposal that I floated earlier: I still think it's worth considering making |
The main thing that makes me sad about this is that it seems like a regression. Code that used to work now breaks without a major version change. At least there is a workaround. |
Original title: Fn item types should be zero-sized
Per RFC 401, every fn in Rust should have its own unique, zero-sized type. This fits with the overall design of closures, which also have their own unique types (but those types are not zero-sized, as they carry the environment). None of these types have any explicit syntax at present. This has been a longstanding plan, but until recently it was not fully implemented. This is changing with PR #31710, which means that some existing code will need to be adjusted to account for the new behavior. This issue attempts to summarize how things work and describe what needs to be changed.
Zero-sized fn types
What all of this means is that, if you have a function declaration
foo
:the type of
foo
is notfn(i32)
, as one might expect. Rather, it is a unique, zero-sized marker type that I will just write astypeof(foo)
. However,typeof(foo)
can be coerced to a function pointerfn(i32)
, so you rarely notice this:The reason that this matter is that the type
fn(i32)
is not specify to any particular function: it's a function pointer. So callingx()
results in a virtual call, whereasfoo()
is statically dispatched, because the type offoo
tells us precisely what function is being called.Impact on users
As noted above, coercions mean that most code will continue to work just fine before and after this issue is fully fixed. However, you can tell the difference in a few scenarios. Perhaps the most prominent is using transmute to convert a fn item into a fn pointer. This is often done as part of an FFI:
Here, transmute is being used to convert the types of the fn arguments. This pattern is now incorrect because, because the type of
foo
is a function item (typeof(foo)
), which is zero-sized, and the target type (fn()
) is a function pointer, which is not zero-sized. For now, this pattern still works due to some special-cased code in the compiler, but that code is expected to be removed. For future compatibility, this pattern should be rewritten. There are a few possible ways to do this:let f: extern "C" fn(*mut i32) = transmute(foo as extern "C" fn(_))
let f: extern "C" fn(*mut i32) = transmute(foo as usize) /* works too */
The same applies to transmutes to
*mut fn()
, which were observed frequently in practice. Note though that use of this type is generally incorrect. The intention is typically to describe a function pointer, but justfn()
alone suffices for that.*mut fn()
is a pointer to a fn pointer. (Since these values are typically just passed to C code, however, this rarely makes a difference in practice.)Current status and implementation trail
The text was updated successfully, but these errors were encountered: