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 · Fixed by #37167
Closed

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

eddyb opened this issue Nov 13, 2014 · 27 comments · Fixed by #37167
Assignees
Labels
A-traits Area: Trait system A-typesystem Area: The type system E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness P-high High priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@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 Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ label Dec 12, 2014
@JustAPerson
Copy link
Contributor

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-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. label Apr 3, 2015
@ghost
Copy link

ghost commented Apr 3, 2015

@JustAPerson Thanks! Marking as E-needstest.

@nikomatsakis nikomatsakis removed the E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. label Apr 6, 2015
@nikomatsakis
Copy link
Contributor

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 High priority label Apr 29, 2015
@brson brson removed this from the 1.0 milestone Apr 29, 2015
@arielb1
Copy link
Contributor

arielb1 commented Apr 29, 2015

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

@nikomatsakis
Copy link
Contributor

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
Copy link
Member

jroesch commented Jun 16, 2015

cc me

@stevenblenkinsop
Copy link

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
Copy link

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
Copy link
Contributor

arielb1 commented Jun 15, 2016

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

@brson brson added A-typesystem Area: The type system A-traits Area: Trait system T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jun 23, 2016
@brson
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
Copy link
Contributor

brson commented Jun 23, 2016

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

@alexcrichton
Copy link
Member

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
Copy link
Contributor

triage: P-high

@rust-highfive rust-highfive added P-high High priority and removed I-nominated P-medium Medium priority labels Aug 18, 2016
@brson brson added the E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot. label Aug 25, 2016
@nikomatsakis
Copy link
Contributor

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
Copy link
Contributor

(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
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
Copy link
Contributor

@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
Copy link
Member

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

@nikomatsakis
Copy link
Contributor

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
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
Copy link
Contributor

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

@brson
Copy link
Contributor

brson commented Nov 3, 2016

Pr enqueud #37167

bors added a commit that referenced this issue Nov 4, 2016
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
euank added a commit to euank/pty-shell that referenced this issue Dec 10, 2017
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
Labels
A-traits Area: Trait system A-typesystem Area: The type system E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness P-high High priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.