Skip to content

Commit

Permalink
Enforce supertrait outlives obligations hold when confirming impl
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Jul 18, 2024
1 parent b01a977 commit 44d1985
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 10 deletions.
13 changes: 13 additions & 0 deletions compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,19 @@ where
.map(|pred| goal.with(cx, pred));
ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);

// We currently elaborate all supertrait obligations from impls. This
// can be removed when we actually do coinduction correctly and just
// register that the impl header must be WF.
let goal_clause: I::Clause = goal.predicate.upcast(cx);
for clause in elaborate::elaborate(cx, [goal_clause]) {
if matches!(
clause.kind().skip_binder(),
ty::ClauseKind::TypeOutlives(..) | ty::ClauseKind::RegionOutlives(..)
) {
ecx.add_goal(GoalSource::Misc, goal.with(cx, clause));
}
}

ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty)
})
}
Expand Down
30 changes: 30 additions & 0 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use crate::traits::project::ProjectAndUnifyResult;
use crate::traits::project::ProjectionCacheKeyExt;
use crate::traits::ProjectionCacheKey;
use crate::traits::Unimplemented;
use hir::def::DefKind;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{Diag, EmissionGuarantee};
Expand All @@ -37,6 +38,7 @@ use rustc_infer::infer::relate::TypeRelation;
use rustc_infer::infer::BoundRegionConversionTime;
use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType;
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::traits::util::elaborate;
use rustc_infer::traits::TraitObligation;
use rustc_middle::bug;
use rustc_middle::dep_graph::dep_kinds;
Expand Down Expand Up @@ -2787,6 +2789,34 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
});
}

if matches!(self.tcx().def_kind(def_id), DefKind::Impl { of_trait: true })
&& let Some(header) = self.tcx().impl_trait_header(def_id)
{
let trait_clause: ty::Clause<'tcx> =
header.trait_ref.instantiate(self.tcx(), args).upcast(self.tcx());
for clause in elaborate(self.tcx(), [trait_clause]) {
if matches!(
clause.kind().skip_binder(),
ty::ClauseKind::TypeOutlives(..) | ty::ClauseKind::RegionOutlives(..)
) {
let clause = normalize_with_depth_to(
self,
param_env,
cause.clone(),
recursion_depth,
clause,
&mut obligations,
);
obligations.push(Obligation {
cause: cause.clone(),
recursion_depth,
param_env,
predicate: clause.as_predicate(),
});
}
}
}

obligations
}
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_type_ir/src/inherent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,8 @@ pub trait Clause<I: Interner<Clause = Self>>:
+ UpcastFrom<I, ty::Binder<I, ty::ClauseKind<I>>>
+ UpcastFrom<I, ty::TraitRef<I>>
+ UpcastFrom<I, ty::Binder<I, ty::TraitRef<I>>>
+ UpcastFrom<I, ty::TraitPredicate<I>>
+ UpcastFrom<I, ty::Binder<I, ty::TraitPredicate<I>>>
+ UpcastFrom<I, ty::ProjectionPredicate<I>>
+ UpcastFrom<I, ty::Binder<I, ty::ProjectionPredicate<I>>>
+ IntoKind<Kind = ty::Binder<I, ty::ClauseKind<I>>>
Expand Down
1 change: 1 addition & 0 deletions tests/ui/fn/implied-bounds-unnorm-associated-type-5.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ trait Trait<'a>: 'a {
// if the `T: 'a` bound gets implied we would probably get ub here again
impl<'a, T> Trait<'a> for T {
//~^ ERROR the parameter type `T` may not live long enough
//~| ERROR the parameter type `T` may not live long enough
type Type = ();
}

Expand Down
17 changes: 15 additions & 2 deletions tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,21 @@ help: consider adding an explicit lifetime bound
LL | impl<'a, T: 'a> Trait<'a> for T {
| ++++

error[E0309]: the parameter type `T` may not live long enough
--> $DIR/implied-bounds-unnorm-associated-type-5.rs:6:27
|
LL | impl<'a, T> Trait<'a> for T {
| -- ^ ...so that the type `T` will meet its required lifetime bounds
| |
| the parameter type `T` must be valid for the lifetime `'a` as defined here...
|
help: consider adding an explicit lifetime bound
|
LL | impl<'a, T: 'a> Trait<'a> for T {
| ++++

error[E0505]: cannot move out of `x` because it is borrowed
--> $DIR/implied-bounds-unnorm-associated-type-5.rs:21:10
--> $DIR/implied-bounds-unnorm-associated-type-5.rs:22:10
|
LL | let x = String::from("Hello World!");
| - binding `x` declared here
Expand All @@ -34,7 +47,7 @@ LL - let y = f(&x, ());
LL + let y = f(x.clone(), ());
|

error: aborting due to 2 previous errors
error: aborting due to 3 previous errors

Some errors have detailed explanations: E0309, E0505.
For more information about an error, try `rustc --explain E0309`.
1 change: 1 addition & 0 deletions tests/ui/static/static-lifetime.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub trait Arbitrary: Sized + 'static {}

impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {} //~ ERROR lifetime bound
//~^ ERROR cannot infer an appropriate lifetime for lifetime parameter `'a`

fn main() {
}
30 changes: 28 additions & 2 deletions tests/ui/static/static-lifetime.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,32 @@ LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
| ^^
= note: but lifetime parameter must outlive the static lifetime

error: aborting due to 1 previous error
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> $DIR/static-lifetime.rs:3:34
|
LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
--> $DIR/static-lifetime.rs:3:6
|
LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
| ^^
note: ...so that the types are compatible
--> $DIR/static-lifetime.rs:3:34
|
LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `<Cow<'a, A> as Arbitrary>`
found `<Cow<'_, A> as Arbitrary>`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the declared lifetime parameter bounds are satisfied
--> $DIR/static-lifetime.rs:3:34
|
LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0478`.
Some errors have detailed explanations: E0478, E0495.
For more information about an error, try `rustc --explain E0478`.
12 changes: 12 additions & 0 deletions tests/ui/wf/wf-in-where-clause-static.current.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/wf-in-where-clause-static.rs:18:18
|
LL | let s = foo(&String::from("blah blah blah"));
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
| | |
| | creates a temporary value which is freed while still in use
| argument requires that borrow lasts for `'static`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0716`.
12 changes: 12 additions & 0 deletions tests/ui/wf/wf-in-where-clause-static.next.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/wf-in-where-clause-static.rs:18:18
|
LL | let s = foo(&String::from("blah blah blah"));
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
| | |
| | creates a temporary value which is freed while still in use
| argument requires that borrow lasts for `'static`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0716`.
10 changes: 4 additions & 6 deletions tests/ui/wf/wf-in-where-clause-static.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
//@ check-pass
//@ known-bug: #98117

// Should fail. Functions are responsible for checking the well-formedness of
// their own where clauses, so this should fail and require an explicit bound
// `T: 'static`.
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver

use std::fmt::Display;

Expand All @@ -19,5 +16,6 @@ where

fn main() {
let s = foo(&String::from("blah blah blah"));
//~^ ERROR temporary value dropped while borrowed
println!("{}", s);
}

0 comments on commit 44d1985

Please sign in to comment.