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

Reject specialized Drop impls. #23638

Merged
merged 11 commits into from
Mar 25, 2015

Conversation

pnkfelix
Copy link
Member

Reject specialized Drop impls.

See Issue #8142 for discussion.

This makes it illegal for a Drop impl to be more specialized than the original item.

So for example, all of the following are now rejected (when they would have been blindly accepted before):

struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type

struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region

struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement

struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement

Due to examples like the above, this is a [breaking-change].

(The fix is to either remove the specialization from the Drop impl, or to transcribe the requirements into the struct/enum definition; examples of both are shown in the PR's fixed to libstd.)


This is likely to be the last thing blocking the removal of the #[unsafe_destructor] attribute.

Fix #8142
Fix #23584

@rust-highfive
Copy link
Collaborator

r? @Aatch

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

@pnkfelix
Copy link
Member Author

r? @nikomatsakis

@rust-highfive rust-highfive assigned nikomatsakis and unassigned Aatch Mar 23, 2015
@pnkfelix
Copy link
Member Author

(@nikomatsakis heh, there are still all those fixme's in there for me to add proper error codes. I will post a follow-up commit with those; but please do review the overall strategy in the meantime if you have time.)

@nikomatsakis
Copy link
Contributor

a thought for how to enforce #23638 (comment) -- instead of the current check, make skolemized versions of the type/region parameters, create inference variables for the impl parameters, and try to unify (we'll have to check regions too)

@pnkfelix
Copy link
Member Author

@nikomatsakis ironically that is what I tried to do originally... (well, sort of)

(update 25 minutes later): actually what I tried to do originally was much more ad-hoc. What you describe sounds much better. Will try it now.

@nikomatsakis
Copy link
Contributor

@pnkfelix it almost seems like it'd be easier to just let drops be more specialized and sometimes not run them

@nikomatsakis
Copy link
Contributor

@pnkfelix for the regions, we could probably use the skolemization machinery aimed at late-bound regions to avoid having to run region resolve

@nikomatsakis
Copy link
Contributor

(seems like more-or-less the perfect tool for this job, since it is designed to determine whether something is more or less polymorphic)

@nikomatsakis
Copy link
Contributor

(or you could prob just check that each type/region parameter is distinct)

@pnkfelix
Copy link
Member Author

(or you could prob just check that each type/region parameter is distinct)

@nikomatsakis yeah I keep debating about whether I'm wasting my time trying to do it via skolemization. (I am currently justifying it as a good exercise to better acquaint myself with the machinery, but if i don't get it working soon, I will probably resort to the brute-force rejection of duplicate actual parameters)

@pnkfelix
Copy link
Member Author

@nikomatsakis

it almost seems like it'd be easier to just let drops be more specialized and sometimes not run them

Well except that's not what the current implementation does in these cases, I think. To my knowledge it just blindly runs the destructors. (We could certainly try to implement what you suggest, but I think this approach is still necessary, if only as the basis for a lint.)

@nikomatsakis
Copy link
Contributor

@pnkfelix I agree this is not current behavior of trans

@nikomatsakis
Copy link
Contributor

r+

@pnkfelix pnkfelix force-pushed the fsk-reject-specialized-drops branch from 379d7e8 to c6cd92c Compare March 24, 2015 17:10
@pnkfelix
Copy link
Member Author

@bors r=nikomatsakis c6cd92c

@bors
Copy link
Contributor

bors commented Mar 24, 2015

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

See Issue 8142 for discussion.

This makes it illegal for a Drop impl to be more specialized than the
original item.

So for example, all of the following are now rejected (when they would
have been blindly accepted before):

```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type

struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region

struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement

struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```

Due to examples like the above, this is a [breaking-change].

(The fix is to either remove the specialization from the `Drop` impl,
or to transcribe the requirements into the struct/enum definition;
examples of both are shown in the PR's fixed to `libstd`.)

----

This is likely to be the last thing blocking the removal of the
`#[unsafe_destructor]` attribute.

Includes two new error codes for the new dropck check.

Update run-pass tests to accommodate new dropck pass.

Update tests and docs to reflect new destructor restriction.

----

Implementation notes:

We identify Drop impl specialization by not being as parametric as the
struct/enum definition via unification.

More specifically:

 1. Attempt unification of a skolemized instance of the struct/enum
    with an instance of the Drop impl's type expression where all of
    the impl's generics (i.e. the free variables of the type
    expression) have been replaced with unification variables.

 2. If unification fails, then reject Drop impl as specialized.

 3. If unification succeeds, check if any of the skolemized
    variables "leaked" into the constraint set for the inference
    context; if so, then reject Drop impl as specialized.

 4. Otherwise, unification succeeded without leaking skolemized
    variables: accept the Drop impl.

We identify whether a Drop impl is injecting new predicates by simply
looking whether the predicate, after an appropriate substitution,
appears on the struct/enum definition.
@pnkfelix pnkfelix force-pushed the fsk-reject-specialized-drops branch from c6cd92c to 1955e05 Compare March 24, 2015 22:08
@pnkfelix
Copy link
Member Author

@bors r=nikomatsakis 1955e05

alexcrichton added a commit to alexcrichton/rust that referenced this pull request Mar 24, 2015
Reject specialized Drop impls.

See Issue rust-lang#8142 for discussion.

This makes it illegal for a Drop impl to be more specialized than the original item.

So for example, all of the following are now rejected (when they would have been blindly accepted before):

```rust
struct S<A> { ... };
impl Drop for S<i8> { ... } // error: specialized to concrete type

struct T<'a> { ... };
impl Drop for T<'static> { ... } // error: specialized to concrete region

struct U<A> { ... };
impl<A:Clone> Drop for U<A> { ... } // error: added extra type requirement

struct V<'a,'b>;
impl<'a,'b:a> Drop for V<'a,'b> { ... } // error: added extra region requirement
```

Due to examples like the above, this is a [breaking-change].

(The fix is to either remove the specialization from the `Drop` impl, or to transcribe the requirements into the struct/enum definition; examples of both are shown in the PR's fixed to `libstd`.)

----

This is likely to be the last thing blocking the removal of the `#[unsafe_destructor]` attribute.

Fix rust-lang#8142
Fix rust-lang#23584
@bors bors merged commit 1955e05 into rust-lang:master Mar 25, 2015
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request May 6, 2023
… r=lcnr

Use fulfillment to check `Drop` impl compatibility

Use an `ObligationCtxt` to ensure that a `Drop` impl does not have stricter requirements than the ADT that it's implemented for, rather than using a `SimpleEqRelation` to (more or less) syntactically equate predicates on an ADT with predicates on an impl.

r? types

### Some background

The old code reads:

```rust
// An earlier version of this code attempted to do this checking
// via the traits::fulfill machinery. However, it ran into trouble
// since the fulfill machinery merely turns outlives-predicates
// 'a:'b and T:'b into region inference constraints. It is simpler
// just to look for all the predicates directly.
```

I'm not sure what this means, but perhaps in the 8 years since that this comment was written (cc rust-lang#23638) it's gotten easier to process region constraints after doing fulfillment? I don't know how this logic differs from anything we do in the `compare_impl_item` module. Ironically, later on it says:

```rust
// However, it may be more efficient in the future to batch
// the analysis together via the fulfill (see comment above regarding
// the usage of the fulfill machinery), rather than the
// repeated `.iter().any(..)` calls.
```

Also:
* Removes `SimpleEqRelation` which was far too syntactical in its relation.
* Fixes rust-lang#110557
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request May 6, 2023
… r=lcnr

Use fulfillment to check `Drop` impl compatibility

Use an `ObligationCtxt` to ensure that a `Drop` impl does not have stricter requirements than the ADT that it's implemented for, rather than using a `SimpleEqRelation` to (more or less) syntactically equate predicates on an ADT with predicates on an impl.

r? types

### Some background

The old code reads:

```rust
// An earlier version of this code attempted to do this checking
// via the traits::fulfill machinery. However, it ran into trouble
// since the fulfill machinery merely turns outlives-predicates
// 'a:'b and T:'b into region inference constraints. It is simpler
// just to look for all the predicates directly.
```

I'm not sure what this means, but perhaps in the 8 years since that this comment was written (cc rust-lang#23638) it's gotten easier to process region constraints after doing fulfillment? I don't know how this logic differs from anything we do in the `compare_impl_item` module. Ironically, later on it says:

```rust
// However, it may be more efficient in the future to batch
// the analysis together via the fulfill (see comment above regarding
// the usage of the fulfill machinery), rather than the
// repeated `.iter().any(..)` calls.
```

Also:
* Removes `SimpleEqRelation` which was far too syntactical in its relation.
* Fixes rust-lang#110557
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.

stdlib is instantiating Arc<T> with T's that are not Send+Sync Prohibit specialized drops
5 participants