-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Distinguish fn item types to allow reification from nothing to fn pointers. #31710
Conversation
r? @arielb1 (rust_highfive has picked a reviewer for you, use r? to override) |
Triggering a crater run. |
Crater run results: https://gist.github.com/nikomatsakis/0902ea970301a841231e One regression ( |
12fa405
to
dd04d6a
Compare
☔ The latest upstream changes (presumably #31394) made this pull request unmergeable. Please resolve the merge conflicts. |
e9fe0fc
to
8d806be
Compare
The regression should be handled by the unify-coerce logic, however I wish I could enable the full extent of it without triggering LLVM asserts 😞. |
Turns out that using The problem in question starts with My code was mistakenly assigning What usually happens is I've come up with this testcase, which should trigger the same sequence of events, but does not: fn main() {
let mut x = unsafe {std::mem::zeroed()};
let mut y = &[1, 2, 3][x];
y = &vec![];
x = ..;
} It errors with "type mismatch resolving cc @rust-lang/compiler Even though my PR appears to work now, I dread leaving an obligation-dropping bug around. |
Found the culprit: it's this let resolved_t = match unresolved_type_action {
UnresolvedTypeAction::Error => {
structurally_resolved_type(fcx, sp, t)
}
UnresolvedTypeAction::Ignore => {
// We can continue even when the type cannot be resolved
// (i.e. it is an inference variable) because `Ty::builtin_deref`
// and `try_overloaded_deref` both simply return `None`
// in such a case without producing spurious errors.
fcx.resolve_type_vars_if_possible(t)
}
};
Usually that's not an issue because a failed coercion is fatal, so at worst you get an ICE after a legitimate error. But I had code which tried coercions and continued in a different manner, resulting in projection obligations successfully selected but then their effects completely rolled back and thus The fix is very simple: replace that line with However, I would like a permanent solution, that doesn't allow access to |
307dabf
to
4d44144
Compare
@nikomatsakis Tests appear to pass, can I get another crater run? If we see any regressions caused by the scheme I chose, we'll have to tone it down, perhaps limit it to two function item types (although I really like this scheme, especially now that I've plucked the bugs out and it seems to "just work"). |
OK, I've reviewed as far as ea2510c9eaf1fe3d1fc87b30b643a51e8662d13d (though I'm still reading through d619ebedbbaef7ec0a5c3aabf72edc9a7a165f3b, which seems to be the "meaty" commit) -- it all seems quite nice thus far. |
@eddyb the crater run seems to have results now, maybe it just wasn't done before: https://gist.github.com/nikomatsakis/54fbfe9a0d09b8f51cc6
|
@eddyb so we were talking about this in the @rust-lang/lang meeting -- if we want to abide by our usual policies, we may want to think about a compatibility mode for transmute where we permit transmutes from a (zero-sized) fn to a ptr but issue a "forward compatibility" lint warning about phasing this change out. I wish there was something more ergonomic than |
…ng where possible.
@bors r=nikomatsakis |
📌 Commit 3855fa9 has been approved by |
⌛ Testing commit 3855fa9 with merge 3dc9398... |
⛄ The build was interrupted to prioritize another pull request. |
Distinguish fn item types to allow reification from nothing to fn pointers. The first commit is a rebase of #26284, except for files that have moved since. This is a [breaking-change], due to: * each FFI function has a distinct type, like all other functions currently do * all generic parameters on functions are recorded in their item types, e.g.: `size_of::<u8>` & `size_of::<i8>`'s types differ despite their identical signature. * function items are zero-sized, which will stop transmutes from working on them The first two cases are handled in most cases with the new coerce-unify logic, which will combine incompatible function item types into function pointers, at the outer-most level of if-else chains, match arms and array literals. The last case is specially handled during type-checking such that transmutes from a function item type to a pointer or integer type will continue to work for another release cycle, but are being linted against. To get rid of warnings and ensure your code will continue to compile, cast to a pointer before transmuting.
This fixes the warning appearing from rust-lang/rust#31710. The objc_msgSend functions aren't intended to be used directly, so since OSX 10.8 they are defined empty like this as long as you don't define OBJC_OLD_DISPATCH_PROTOTYPES.
This fixes the warning appearing from rust-lang/rust#31710.
FYI, special casing the transmute from functions did not prevent all regressions. I had some code that started segfaulting in 1.9.0, fixed by SSheldon/rust-objc-foundation@f918819. Basically, it boils down to looking like this: #[link(name = "objc", kind = "dylib")]
extern {
fn objc_msgSend();
}
unsafe fn msg_send<T>(t: T) {
let f: unsafe extern fn() = objc_msgSend;
let f: unsafe extern fn(T) = ::std::mem::transmute(f);
f(t)
}
fn hello() {
println!("hello");
}
fn main() {
unsafe {
msg_send(hello);
}
} That's a case where what used to be a function pointer silently becomes a 0-sized type. Anyways, fixed now, hopefully no one else is writing code like this! But figured I'd make it known in case anyone else runs into something similar. |
Type-checking and translation of zero-sized function item types (fixes #19925).
The first commit is a rebase of #26284, except for files that have moved since.
This is a [breaking-change], due to:
size_of::<u8>
&size_of::<i8>
's types differ despite their identical signature.The first two cases are handled in most cases with the new coerce-unify logic,
which will combine incompatible function item types into function pointers,
at the outer-most level of if-else chains, match arms and array literals.
The last case is specially handled during type-checking such that transmutes
from a function item type to a pointer or integer type will continue to work for
another release cycle, but are being linted against. To get rid of warnings and
ensure your code will continue to compile, cast to a pointer before transmuting.