Skip to content
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

Split TyBareFn into TyFnDef and TyFnPtr. #26284

Closed
wants to merge 1 commit into from

Conversation

eefriedman
Copy link
Contributor

There's a lot of stuff wrong with the representation of these types:
TyFnDef doesn't actually uniquely identify a function, TyFnPtr is used to
represent method calls, TyFnDef in the sub-expression of a cast isn't
correctly reified, and probably some other stuff I haven't discovered yet.
Splitting them seems like the right first step, though.

@rust-highfive
Copy link
Collaborator

r? @pnkfelix

(rust_highfive has picked a reviewer for you, use r? to override)

@eefriedman
Copy link
Contributor Author

I'm going to have to tweak this; external functions (like intrinsics) having FnPtrTy is way too confusing.

@eefriedman
Copy link
Contributor Author

Okay, should be good now; intrinsic declarations now have type FnDefTy.

There's a lot of stuff wrong with the representation of these types:
TyFnDef doesn't actually uniquely identify a function, TyFnPtr is used to
represent method calls, TyFnDef in the sub-expression of a cast isn't
correctly reified, and probably some other stuff I haven't discovered yet.
Splitting them seems like the right first step, though.
@eefriedman
Copy link
Contributor Author

It was pointed out on IRC that changing extern declarations from FnPtrTy to FnDefTy is a breaking change. You'd have to be writing sort of weird-looking code to actually hit an error message, though: it's impossible to explicitly write an FnDefTy, so you could only trigger it by doing something like "let mut a = memcpy; a = memmove;".

@eddyb
Copy link
Member

eddyb commented Jun 14, 2015

@eefriedman it's more likely to happen with a conditional, e.g.

let my_fn = if debug_enabled {
    my_fn_debug
} else {
    my_fn_fast
};
my_fn(...);

@bors
Copy link
Contributor

bors commented Jun 19, 2015

☔ The latest upstream changes (presumably #26351) made this pull request unmergeable. Please resolve the merge conflicts.

@pnkfelix
Copy link
Member

pnkfelix commented Jul 2, 2015

@eefriedman

RFC 1122 discusses the handling of breaking changes, but I do not know whether to categorize this as a "small change" or not. I suspect that examples such as the one described by @eddyb come up more often than you might think...

As a reference, @nikomatsakis went through a fair amount of future-proofing to lay the foundation for the the object defaults change in #26370

In my gut, I'm inclined to recommend that we do the same here... i.e. that we adopt a strategy of first trying to detect cases that will eventually be errors and emit warnings for them in the short term.

But its possible others think that would be overkill.

cc @rust-lang/lang

@eefriedman
Copy link
Contributor Author

There enough weirdness here that it should probably get cleaned up before I try to rename anything, with both the handling of extern fns and method type handling. I'm not sure how I would even about reliably detecting the unification of the types of different extern functions.

I guess I'll leave this open for now, but I'm really not sure what to do with it.

@nikomatsakis
Copy link
Contributor

A couple of things:

(1) I think this is good work, but this PR doesn't really go as far as I'd like. That is, I'd like to actually implement the zero-sized types change. Doing the work that this PR does is a good first step though. This change is (slightly) breaking in some cases.

(2) I think we should definitely evaluate the impact; I am not 100% certain whether we should go forward with a warning period or what. Unlike the default object lifetime bounds, this work falls under the category of bug or soundness fix (in particular, issue #19925.) But of course this doesn't make much difference to the end-user experience if it causes your code to break. Probably it would be best to phase in the changes with a warning cycle, but at minimum we should ensure we get very clear error messages.

@eddyb
Copy link
Member

eddyb commented Jul 6, 2015

@nikomatsakis we could also unify the results of conditionals (and maybe array elements) by coercing to a "common reified form", which should alleviate most of the possible fallout.

@pnkfelix
Copy link
Member

pnkfelix commented Jul 8, 2015

@nikomatsakis I thought your comments on #19925 implied that this would not be a soundness fix, since under the current implementation, the hole (pseudo-hole?) in the type system is not actually exploitable since we are still passing the actual functions to invoke (post-monomorphization)

Is there a different example that actually demonstrates unsoundness, as opposed to code that we would like to reject today but do not (and doesn't actually behave unsoundly when it is run) ?

@arielb1
Copy link
Contributor

arielb1 commented Jul 9, 2015

@nikomatsakis

This doesn't seem like a soundness issue to me - "TyFnDef" includes the function def-id. Also, "TyFnPtr" is mostly like a trait object, but it has some different representability properties so I don't think we can merge them.

@@ -612,7 +612,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
}
Some(def::DefStruct(_)) => {
if let ty::TyBareFn(..) = node_ty.sty {
if let ty::TyFnDef(..) = node_ty.sty {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TyFnPtr too.

@nikomatsakis
Copy link
Contributor

@pnkfelix @arielb1

@nikomatsakis I thought your comments on #19925 implied that this would not be a soundness fix

I was using "soundness" a bit generously -- that is, I think that the current treatment is a legitimate bug in the type-checker, causing it to accept some programs that ought not to be accepted. I am not saying that those programs can cause undefined behavior.

@Gankra
Copy link
Contributor

Gankra commented Jul 27, 2015

What's the status of this PR?

@eefriedman
Copy link
Contributor Author

This is on hold because it's a breaking change with regards to foreign functions, and the discussion of how to deal with that never settled on a solution.

@alexcrichton
Copy link
Member

@eefriedman ping? Should this be moved forward? Closed?

@eefriedman
Copy link
Contributor Author

I'll close it for now, given that there isn't likely to be any movement in the near future.

@eefriedman eefriedman closed this Sep 28, 2015
bors added a commit that referenced this pull request Mar 10, 2016
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants