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

Methods in impls allowed more restrictive lifetime bounds than in the trait. #18937

Closed
eddyb opened this Issue Nov 13, 2014 · 27 comments

Comments

Projects
None yet
@eddyb
Copy link
Member

eddyb commented Nov 13, 2014

trait Foo {
    fn foo<T>(self) -> u64;
}
impl Foo for () {
    fn foo<T: 'static>(self) -> u64 {
        //    ^^^^^^^ this should cause an error, the bound is missing from the
        // method definition in the trait, and calls are checked against that.
        std::intrinsics::TypeId::of::<&'static T>().hash()
    }
}
fn main() {
    println!("{}", ().foo::<&()>());
}
// error: internal compiler error: non-static region found when hashing a type

cc @nikomatsakis

@huonw huonw added the I-ICE label Dec 12, 2014

@JustAPerson

This comment has been minimized.

Copy link
Contributor

JustAPerson commented Mar 29, 2015

tl;dr: this bug still reproduces but no longer causes an ICE
Updated for current Rust (on playpen as of today, 29 March 2015):

Hopefully I updated @eddyb's code properly. This compiles and executes fine.

#![feature(core, hash)]
use std::hash::{hash, SipHasher};

trait Foo {
    fn foo<T>(self) -> u64;
}
impl Foo for () {
    fn foo<T: 'static>(self) -> u64 {
        //    ^^^^^^^ this should cause an error, the bound is missing from the
        // method definition in the trait, and calls are checked against that.
        hash::<_, SipHasher>(unsafe{ &std::intrinsics::type_id::<&'static T>() })
    }
}
fn main() {
    println!("{}", ().foo::<&()>());
}
16958441930439044241

@ghost ghost added the E-needstest label Apr 3, 2015

@ghost

This comment has been minimized.

Copy link

ghost commented Apr 3, 2015

@JustAPerson Thanks! Marking as E-needstest.

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Apr 6, 2015

triage: P-backcompat-lang (1.0)

I'm removing the E-needstest label because there is still a bug here -- actually ICEing is better than accepting an illegal program. That said, this may be a dup of #22779 -- although I suspect it is somewhat different. I'm going to triage it as 1.0 and try to fix it.

@nikomatsakis nikomatsakis self-assigned this Apr 6, 2015

@rust-highfive rust-highfive added this to the 1.0 milestone Apr 6, 2015

@brson brson added the P-high label Apr 29, 2015

@brson brson removed this from the 1.0 milestone Apr 29, 2015

@arielb1

This comment has been minimized.

Copy link
Contributor

arielb1 commented Apr 29, 2015

Still broken after the fix of #22779 (http://is.gd/rZ0MgK)

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Jun 8, 2015

So I know what the problem is here, but fixing it is a bit annoying due to the way our contexts are structured (we're not processing the fulfillment context's "region obligations" list). I've been wanting to do some restructuring here that would help, I'll look into that. (The very existence of the "region obligations" list is actually a demonstration of the problem.)

@jroesch

This comment has been minimized.

Copy link
Member

jroesch commented Jun 16, 2015

cc me

@stevenblenkinsop

This comment has been minimized.

Copy link

stevenblenkinsop commented Jul 19, 2015

Ran into an example that creates unsoundness and doesn't use unsafe. I think it's ultimately the same issue:

https://play.rust-lang.org/?gist=25b7461083e5ee9b3415&version=nightly

@vacavaca

This comment has been minimized.

Copy link

vacavaca commented Jun 14, 2016

Is it planned to be fixed in stable?

PS just another example with use after free in safe code from dup issue:
https://play.rust-lang.org/?gist=e95ac4f83f16b062ee8b7c53ed52d5e2&version=stable&backtrace=0

@arielb1

This comment has been minimized.

Copy link
Contributor

arielb1 commented Jun 15, 2016

@nikomatsakis said he will look at this when he comes back from vacation.

@brson

This comment has been minimized.

Copy link
Contributor

brson commented Jun 23, 2016

@rust-lang/compiler Can you reaffirm this is P-high and somebody is on it? Maybe this can be mentored?

@brson

This comment has been minimized.

Copy link
Contributor

brson commented Jun 23, 2016

@sanxiyn Says they may be able to do this with some mentoring!

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Aug 16, 2016

I've just closed #35730 as a dupe of this which has another example of a segfault related to this we believe.

Renominating as this came up again, unfortunately...

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Aug 18, 2016

triage: P-high

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Aug 26, 2016

OK, so @jroesch and I implemented an initial fix for this (finally). I did a crater run with the following results:

  • 5819 crates tested: 4167 working / 1605 broken / 12 regressed / 3 fixed / 32 unknown.

https://gist.github.com/nikomatsakis/cba00297c8659f71740b8e45dad07137

That's not too bad. I want to dig into those results some more, but I'm hoping we can get away w/o a warning period on this one -- it would be a real pain to support!

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Aug 26, 2016

(It may also be worth investing a bit of energy in the error messages, which do not currently hint at the fact that the impl is imposing more requirements than the trait.)

@arielb1

This comment has been minimized.

Copy link
Contributor

arielb1 commented Aug 31, 2016

This appears to be broken by the fix:

pub trait Leak<T : ?Sized> {
    fn leak<'a>(self) -> &'a T where T: 'a;
}

impl<T> Leak<[T]> for Vec<T> {
    fn leak<'a>(mut self) -> &'a [T] where [T]: 'a {
        let r: *mut [T] = &mut self[..];
        std::mem::forget(self);
        unsafe { &mut *r }
    }
}
fn main() {
    println!("Hello, world!");
}
error[E0309]: the parameter type `T` may not live long enough
  --> src/lib.rs:45:5
   |
45 |     fn leak<'a>(mut self) -> &'a [T] where [T]: 'a {
   |     ^
   |
   = help: consider adding an explicit lifetime bound `T: 'a`...
note: ...so that the type `[T]` will meet its required lifetime bounds
  --> src/lib.rs:45:5
   |
45 |     fn leak<'a>(mut self) -> &'a [T] where [T]: 'a {
   |     ^
@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Aug 31, 2016

@arielb1 I feel that is an orthogonal issue. It is true that this code no longer compiles, and that it would be nice and safe if it did compile, but it is not true that it should compile with the current state of rustc's reasoning. That is, I think we should indeed deduce that if [T]: 'a than (e.g.) T: 'a must hold and so forth, but we fail to do so in other contexts too, and I'm not sure why we should go out of our way to work around it in this context vs solving that more generally.

Now, one could argue -- and I might agree -- that we should try to fix that oversight at the same time as applying this path. I think it'd be fairly straightforward to do, really, though it probably wants an RFC. I think @alexcrichton ran into this limitation in futures in some other setting.

@pnkfelix

This comment has been minimized.

Copy link
Member

pnkfelix commented Sep 22, 2016

@nikomatsakis do you think you two are still making fwd progress here, or should we delegate?

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Oct 3, 2016

Got distracted but I now have a local branch that I think both rejects the original case but accepts this case. I have to press on a bit more. The key change though is to expand on things like &'a T: 'b and use that to conclude that, indeed, 'a: 'b and T: 'b. (I did this in a fairly conservative fashion for now.)

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Oct 5, 2016

Argh. This is frustrating. So I put in some work into the error messages, which now look like this:

lunch-box. rustc --stage1 region-unrelated.rs
error[E0276]: impl has stricter requirements than trait
  --> region-unrelated.rs:21:5
   |
16 |     fn foo() where T: 'a;
   |     --------------------- definition of `foo` from trait
...
21 |     fn foo() where V: 'a { }
   |     ^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `V: 'a`

error: aborting due to previous error

I am trying to turn these into future-compatibility lints, but the current infrastructure (e.g., add_lint) is lacking (it only lets you give a string). I have to see if I can improve it easily, I guess (there is struct_span_lint, I suppose...).

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Oct 12, 2016

Update: I now have the lints mostly working, though I'm still refactoring the changes I made to that end.

bors added a commit that referenced this issue Nov 2, 2016

Auto merge of #37167 - nikomatsakis:jroesch-issue-18937, r=pnkfelix
detect extra region requirements in impls

The current "compare method" check fails to check for the "region obligations" that accrue in the fulfillment context. This branch switches that code to create a `FnCtxt` so that it can invoke the regionck code. Previous crater runs (I haven't done one with the latest tip) have found some small number of affected crates, so I went ahead and introduced a warning cycle. I will kick off a crater run with this branch shortly.

This is a [breaking-change] because previously unsound code was accepted. The crater runs also revealed some cases where legitimate code was no longer type-checking, so the branch contains one additional (but orthogonal) change. It improves the elaborator so that we elaborate region requirements more thoroughly. In particular, if we know that `&'a T: 'b`, we now deduce that `T: 'b` and `'a: 'b`.

I invested a certain amount of effort in getting a good error message. The error message looks like this:

```
error[E0276]: impl has stricter requirements than trait
  --> traits-elaborate-projection-region.rs:33:5
   |
21 |     fn foo() where T: 'a;
   |     --------------------- definition of `foo` from trait
...
33 |     fn foo() where U: 'a { }
   |     ^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `U: 'a`
   |
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #18937 <#18937>
note: lint level defined here
  --> traits-elaborate-projection-region.rs:12:9
   |
12 | #![deny(extra_requirement_in_impl)]
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
```

Obviously the warning only prints if this is a _new_ error (that resulted from the bugfix). But all existing errors that fit this description are updated to follow the general template. In order to get the lint to preserve the span-labels and the error code, I separate out the core `Diagnostic` type (which encapsulates the error code, message, span, and children) from the `DiagnosticBuilder` (which layers on a `Handler` that can be used to report errors). I also extended `add_lint` with an alternative `add_lint_diagnostic` that takes in a full diagnostic (cc @jonathandturner for those changes). This doesn't feel ideal but feels like it's moving in the right direction =).

r? @pnkfelix
cc @arielb1

Fixes #18937

bors added a commit that referenced this issue Nov 3, 2016

Auto merge of #37167 - nikomatsakis:jroesch-issue-18937, r=pnkfelix
detect extra region requirements in impls

The current "compare method" check fails to check for the "region obligations" that accrue in the fulfillment context. This branch switches that code to create a `FnCtxt` so that it can invoke the regionck code. Previous crater runs (I haven't done one with the latest tip) have found some small number of affected crates, so I went ahead and introduced a warning cycle. I will kick off a crater run with this branch shortly.

This is a [breaking-change] because previously unsound code was accepted. The crater runs also revealed some cases where legitimate code was no longer type-checking, so the branch contains one additional (but orthogonal) change. It improves the elaborator so that we elaborate region requirements more thoroughly. In particular, if we know that `&'a T: 'b`, we now deduce that `T: 'b` and `'a: 'b`.

I invested a certain amount of effort in getting a good error message. The error message looks like this:

```
error[E0276]: impl has stricter requirements than trait
  --> traits-elaborate-projection-region.rs:33:5
   |
21 |     fn foo() where T: 'a;
   |     --------------------- definition of `foo` from trait
...
33 |     fn foo() where U: 'a { }
   |     ^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `U: 'a`
   |
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #18937 <#18937>
note: lint level defined here
  --> traits-elaborate-projection-region.rs:12:9
   |
12 | #![deny(extra_requirement_in_impl)]
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
```

Obviously the warning only prints if this is a _new_ error (that resulted from the bugfix). But all existing errors that fit this description are updated to follow the general template. In order to get the lint to preserve the span-labels and the error code, I separate out the core `Diagnostic` type (which encapsulates the error code, message, span, and children) from the `DiagnosticBuilder` (which layers on a `Handler` that can be used to report errors). I also extended `add_lint` with an alternative `add_lint_diagnostic` that takes in a full diagnostic (cc @jonathandturner for those changes). This doesn't feel ideal but feels like it's moving in the right direction =).

r? @pnkfelix
cc @arielb1

Fixes #18937

bors added a commit that referenced this issue Nov 3, 2016

Auto merge of #37167 - nikomatsakis:jroesch-issue-18937, r=pnkfelix
detect extra region requirements in impls

The current "compare method" check fails to check for the "region obligations" that accrue in the fulfillment context. This branch switches that code to create a `FnCtxt` so that it can invoke the regionck code. Previous crater runs (I haven't done one with the latest tip) have found some small number of affected crates, so I went ahead and introduced a warning cycle. I will kick off a crater run with this branch shortly.

This is a [breaking-change] because previously unsound code was accepted. The crater runs also revealed some cases where legitimate code was no longer type-checking, so the branch contains one additional (but orthogonal) change. It improves the elaborator so that we elaborate region requirements more thoroughly. In particular, if we know that `&'a T: 'b`, we now deduce that `T: 'b` and `'a: 'b`.

I invested a certain amount of effort in getting a good error message. The error message looks like this:

```
error[E0276]: impl has stricter requirements than trait
  --> traits-elaborate-projection-region.rs:33:5
   |
21 |     fn foo() where T: 'a;
   |     --------------------- definition of `foo` from trait
...
33 |     fn foo() where U: 'a { }
   |     ^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `U: 'a`
   |
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #18937 <#18937>
note: lint level defined here
  --> traits-elaborate-projection-region.rs:12:9
   |
12 | #![deny(extra_requirement_in_impl)]
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
```

Obviously the warning only prints if this is a _new_ error (that resulted from the bugfix). But all existing errors that fit this description are updated to follow the general template. In order to get the lint to preserve the span-labels and the error code, I separate out the core `Diagnostic` type (which encapsulates the error code, message, span, and children) from the `DiagnosticBuilder` (which layers on a `Handler` that can be used to report errors). I also extended `add_lint` with an alternative `add_lint_diagnostic` that takes in a full diagnostic (cc @jonathandturner for those changes). This doesn't feel ideal but feels like it's moving in the right direction =).

r? @pnkfelix
cc @arielb1

Fixes #18937
@brson

This comment has been minimized.

Copy link
Contributor

brson commented Nov 3, 2016

Pr enqueud #37167

bors added a commit that referenced this issue Nov 4, 2016

Auto merge of #37167 - nikomatsakis:jroesch-issue-18937, r=pnkfelix
detect extra region requirements in impls

The current "compare method" check fails to check for the "region obligations" that accrue in the fulfillment context. This branch switches that code to create a `FnCtxt` so that it can invoke the regionck code. Previous crater runs (I haven't done one with the latest tip) have found some small number of affected crates, so I went ahead and introduced a warning cycle. I will kick off a crater run with this branch shortly.

This is a [breaking-change] because previously unsound code was accepted. The crater runs also revealed some cases where legitimate code was no longer type-checking, so the branch contains one additional (but orthogonal) change. It improves the elaborator so that we elaborate region requirements more thoroughly. In particular, if we know that `&'a T: 'b`, we now deduce that `T: 'b` and `'a: 'b`.

I invested a certain amount of effort in getting a good error message. The error message looks like this:

```
error[E0276]: impl has stricter requirements than trait
  --> traits-elaborate-projection-region.rs:33:5
   |
21 |     fn foo() where T: 'a;
   |     --------------------- definition of `foo` from trait
...
33 |     fn foo() where U: 'a { }
   |     ^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `U: 'a`
   |
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #18937 <#18937>
note: lint level defined here
  --> traits-elaborate-projection-region.rs:12:9
   |
12 | #![deny(extra_requirement_in_impl)]
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
```

Obviously the warning only prints if this is a _new_ error (that resulted from the bugfix). But all existing errors that fit this description are updated to follow the general template. In order to get the lint to preserve the span-labels and the error code, I separate out the core `Diagnostic` type (which encapsulates the error code, message, span, and children) from the `DiagnosticBuilder` (which layers on a `Handler` that can be used to report errors). I also extended `add_lint` with an alternative `add_lint_diagnostic` that takes in a full diagnostic (cc @jonathandturner for those changes). This doesn't feel ideal but feels like it's moving in the right direction =).

r? @pnkfelix
cc @arielb1

Fixes #18937

@bors bors closed this in #37167 Nov 4, 2016

euank added a commit to euank/pty-shell that referenced this issue Dec 10, 2017

Fix compile error on newer rusts
See rust-lang/rust#18937 and related issues
for upstream discussion.

Compiling the previous code on modern rust results in:
error[E0276]: impl has stricter requirements than trait

This is the most trivial way to fix this issue.

A better fix might be possible. If the event loop were to migrate to
tokio and be external to the library (as hyper does these days), that
would allow expressing a more stringent lifetime on the handler.

For now, getting it back to a compiling state seems like a good step.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.