Skip to content

Commit

Permalink
Report a specialized error when a 'static obligation comes from an …
Browse files Browse the repository at this point in the history
…`impl dyn Trait`

```text
error: lifetime may not live long enough
  --> $DIR/static-impl-obligation.rs:8:27
   |
LL |     fn bar<'a>(x: &'a &'a u32) {
   |            -- lifetime `'a` defined here
LL |         let y: &dyn Foo = x;
   |                           ^ cast requires that `'a` must outlive `'static`
LL |         y.hello();
   |         --------- calling this method introduces a `'static` lifetime requirement
   |
help: relax the implicit `'static` bound on the impl
   |
LL |     impl dyn Foo + '_ {
   |                  ++++
```
```text
error: lifetime may not live long enough
  --> $DIR/static-impl-obligation.rs:173:27
   |
LL |     fn bar<'a>(x: &'a &'a u32) {
   |            -- lifetime `'a` defined here
LL |         let y: &dyn Foo = x;
   |                           ^ cast requires that `'a` must outlive `'static`
LL |         y.hello();
   |         --------- calling this method introduces a `'static` lifetime requirement
   |
note: the `impl` on `(dyn p::Foo + 'static)` has `'static` lifetime requirements
  --> $DIR/static-impl-obligation.rs:169:20
   |
LL |     impl dyn Foo + 'static where Self: 'static {
   |                    ^^^^^^^             ^^^^^^^
LL |         fn hello(&self) where Self: 'static {}
   |                                     ^^^^^^^
```
  • Loading branch information
estebank committed Feb 19, 2024
1 parent 8a49772 commit 5074501
Show file tree
Hide file tree
Showing 11 changed files with 834 additions and 55 deletions.
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3553,6 +3553,7 @@ dependencies = [
"either",
"itertools",
"polonius-engine",
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
"rustc_fluent_macro",
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_borrowck/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ edition = "2021"
either = "1.5.0"
itertools = "0.11"
polonius-engine = "0.13.0"
rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
Expand Down
306 changes: 262 additions & 44 deletions compiler/rustc_borrowck/src/diagnostics/region_errors.rs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2051,6 +2051,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
CRATE_DEF_ID.to_def_id(),
predicate_span,
))
} else if let ConstraintCategory::CallArgument(Some(fn_def)) = constraint.category {
Some(ObligationCauseCode::MethodCallConstraint(fn_def, constraint.span))
} else {
None
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,9 @@ pub enum ObligationCauseCode<'tcx> {

/// Obligations emitted during the normalization of a weak type alias.
TypeAlias(InternedObligationCauseCode<'tcx>, Span, DefId),

/// During borrowck we've found a method call that could have introduced a lifetime requirement.
MethodCallConstraint(Ty<'tcx>, Span),
}

/// Whether a value can be extracted into a const.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2683,6 +2683,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
| ObligationCauseCode::MethodReceiver
| ObligationCauseCode::ReturnNoExpression
| ObligationCauseCode::UnifyReceiver(..)
| ObligationCauseCode::MethodCallConstraint(..)
| ObligationCauseCode::MiscObligation
| ObligationCauseCode::WellFormed(..)
| ObligationCauseCode::MatchImpl(..)
Expand Down
210 changes: 210 additions & 0 deletions tests/ui/lifetimes/static-impl-obligation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
mod a {
trait Foo {}
impl<'a> Foo for &'a u32 {}
impl dyn Foo { //~ HELP consider relaxing the implicit `'static` requirement
fn hello(&self) {}
}
fn bar<'a>(x: &'a &'a u32) {
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
y.hello();
}
}
mod b {
trait Foo {}
impl<'a> Foo for &'a u32 {}
impl dyn Foo {
fn hello(&'static self) {}
}
fn bar<'a>(x: &'a &'a u32) {
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
y.hello();
}
}
mod c {
trait Foo {}
impl<'a> Foo for &'a u32 {}
impl dyn Foo {
fn hello(&'static self) where Self: 'static {}
}
fn bar<'a>(x: &'a &'a u32) {
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
y.hello();
}
}
mod d {
trait Foo {}
impl<'a> Foo for &'a u32 {}
impl dyn Foo {
fn hello(&self) where Self: 'static {}
}
fn bar<'a>(x: &'a &'a u32) {
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
y.hello();
}
}
mod e {
trait Foo {}
impl<'a> Foo for &'a u32 {}
impl dyn Foo + 'static { //~ HELP consider replacing this `'static` requirement
fn hello(&self) {}
}
fn bar<'a>(x: &'a &'a u32) {
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
y.hello();
}
}
mod f {
trait Foo {}
impl<'a> Foo for &'a u32 {}
impl dyn Foo + 'static {
fn hello(&'static self) {}
}
fn bar<'a>(x: &'a &'a u32) {
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
y.hello();
}
}
mod g {
trait Foo {}
impl<'a> Foo for &'a u32 {}
impl dyn Foo + 'static {
fn hello(&'static self) where Self: 'static {}
}
fn bar<'a>(x: &'a &'a u32) {
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
y.hello();
}
}
mod h {
trait Foo {}
impl<'a> Foo for &'a u32 {}
impl dyn Foo + 'static {
fn hello(&self) where Self: 'static {}
}
fn bar<'a>(x: &'a &'a u32) {
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
y.hello();
}
}
mod i {
trait Foo {}
impl<'a> Foo for &'a u32 {}
impl dyn Foo where Self: 'static {
fn hello(&self) {}
}
fn bar<'a>(x: &'a &'a u32) {
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
y.hello();
}
}
mod j {
trait Foo {}
impl<'a> Foo for &'a u32 {}
impl dyn Foo where Self: 'static {
fn hello(&'static self) {}
}
fn bar<'a>(x: &'a &'a u32) {
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
y.hello();
}
}
mod k {
trait Foo {}
impl<'a> Foo for &'a u32 {}
impl dyn Foo where Self: 'static {
fn hello(&'static self) where Self: 'static {}
}
fn bar<'a>(x: &'a &'a u32) {
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
y.hello();
}
}
mod l {
trait Foo {}
impl<'a> Foo for &'a u32 {}
impl dyn Foo where Self: 'static {
fn hello(&self) where Self: 'static {}
}
fn bar<'a>(x: &'a &'a u32) {
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
y.hello();
}
}
mod m {
trait Foo {}
impl<'a> Foo for &'a u32 {}
impl dyn Foo + 'static where Self: 'static {
fn hello(&self) {}
}
fn bar<'a>(x: &'a &'a u32) {
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
y.hello();
}
}
mod n {
trait Foo {}
impl<'a> Foo for &'a u32 {}
impl dyn Foo + 'static where Self: 'static {
fn hello(&'static self) {}
}
fn bar<'a>(x: &'a &'a u32) {
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
y.hello();
}
}
mod o {
trait Foo {}
impl<'a> Foo for &'a u32 {}
impl dyn Foo + 'static where Self: 'static {
fn hello(&'static self) where Self: 'static {}
}
fn bar<'a>(x: &'a &'a u32) {
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
y.hello();
}
}
mod p {
trait Foo {}
impl<'a> Foo for &'a u32 {}
impl dyn Foo + 'static where Self: 'static {
fn hello(&self) where Self: 'static {}
}
fn bar<'a>(x: &'a &'a u32) {
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
y.hello();
}
}
mod q {
struct Foo {}
impl Foo {
fn hello(&'static self) {}
}
fn bar<'a>(x: &'a &'a Foo) {
x.hello(); //~ ERROR borrowed data escapes outside of function
}
}
mod r {
struct Foo {}
impl Foo {
fn hello(&'static self) where Self: 'static {}
}
fn bar<'a>(x: &'a &'a Foo) {
x.hello(); //~ ERROR borrowed data escapes outside of function
}
}
mod s {
trait Foo {}
impl<'a> Foo for &'a u32 {}

trait Trait { fn hello(&self) {} }

impl Trait for dyn Foo { //~ HELP consider relaxing the implicit `'static` requirement on the impl
fn hello(&self) {}

}
fn convert<'a>(x: &'a &'a u32) {
let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough
y.hello();
}
}
fn main() {}
Loading

0 comments on commit 5074501

Please sign in to comment.