Skip to content

Commit 6a891ec

Browse files
Enforce supertrait outlives obligations hold when confirming impl
1 parent 9179d9b commit 6a891ec

10 files changed

+120
-12
lines changed

Diff for: compiler/rustc_next_trait_solver/src/solve/trait_goals.rs

+13
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,19 @@ where
8787
.map(|pred| goal.with(cx, pred));
8888
ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
8989

90+
// We currently elaborate all supertrait obligations from impls. This
91+
// can be removed when we actually do coinduction correctly and just
92+
// register that the impl header must be WF.
93+
let goal_clause: I::Clause = goal.predicate.upcast(cx);
94+
for clause in elaborate::elaborate(cx, [goal_clause]) {
95+
if matches!(
96+
clause.kind().skip_binder(),
97+
ty::ClauseKind::TypeOutlives(..) | ty::ClauseKind::RegionOutlives(..)
98+
) {
99+
ecx.add_goal(GoalSource::Misc, goal.with(cx, clause));
100+
}
101+
}
102+
90103
ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty)
91104
})
92105
}

Diff for: compiler/rustc_trait_selection/src/traits/select/mod.rs

+32-2
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@ use std::fmt::{self, Display};
77
use std::ops::ControlFlow;
88
use std::{cmp, iter};
99

10+
use hir::def::DefKind;
1011
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
1112
use rustc_data_structures::stack::ensure_sufficient_stack;
1213
use rustc_errors::{Diag, EmissionGuarantee};
1314
use rustc_hir as hir;
1415
use rustc_hir::def_id::DefId;
1516
use rustc_hir::LangItem;
1617
use rustc_infer::infer::relate::TypeRelation;
17-
use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType;
18-
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes};
18+
use rustc_infer::infer::BoundRegionConversionTime::{self, HigherRankedType};
19+
use rustc_infer::infer::DefineOpaqueTypes;
20+
use rustc_infer::traits::util::elaborate;
1921
use rustc_infer::traits::TraitObligation;
2022
use rustc_middle::bug;
2123
use rustc_middle::dep_graph::{dep_kinds, DepNodeIndex};
@@ -2798,6 +2800,34 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
27982800
});
27992801
}
28002802

2803+
if matches!(self.tcx().def_kind(def_id), DefKind::Impl { of_trait: true })
2804+
&& let Some(header) = self.tcx().impl_trait_header(def_id)
2805+
{
2806+
let trait_clause: ty::Clause<'tcx> =
2807+
header.trait_ref.instantiate(self.tcx(), args).upcast(self.tcx());
2808+
for clause in elaborate(self.tcx(), [trait_clause]) {
2809+
if matches!(
2810+
clause.kind().skip_binder(),
2811+
ty::ClauseKind::TypeOutlives(..) | ty::ClauseKind::RegionOutlives(..)
2812+
) {
2813+
let clause = normalize_with_depth_to(
2814+
self,
2815+
param_env,
2816+
cause.clone(),
2817+
recursion_depth,
2818+
clause,
2819+
&mut obligations,
2820+
);
2821+
obligations.push(Obligation {
2822+
cause: cause.clone(),
2823+
recursion_depth,
2824+
param_env,
2825+
predicate: clause.as_predicate(),
2826+
});
2827+
}
2828+
}
2829+
}
2830+
28012831
obligations
28022832
}
28032833
}

Diff for: compiler/rustc_type_ir/src/inherent.rs

+2
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,8 @@ pub trait Clause<I: Interner<Clause = Self>>:
451451
+ UpcastFrom<I, ty::Binder<I, ty::ClauseKind<I>>>
452452
+ UpcastFrom<I, ty::TraitRef<I>>
453453
+ UpcastFrom<I, ty::Binder<I, ty::TraitRef<I>>>
454+
+ UpcastFrom<I, ty::TraitPredicate<I>>
455+
+ UpcastFrom<I, ty::Binder<I, ty::TraitPredicate<I>>>
454456
+ UpcastFrom<I, ty::ProjectionPredicate<I>>
455457
+ UpcastFrom<I, ty::Binder<I, ty::ProjectionPredicate<I>>>
456458
+ IntoKind<Kind = ty::Binder<I, ty::ClauseKind<I>>>

Diff for: tests/ui/fn/implied-bounds-unnorm-associated-type-5.rs

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ trait Trait<'a>: 'a {
55
// if the `T: 'a` bound gets implied we would probably get ub here again
66
impl<'a, T> Trait<'a> for T {
77
//~^ ERROR the parameter type `T` may not live long enough
8+
//~| ERROR the parameter type `T` may not live long enough
89
type Type = ();
910
}
1011

Diff for: tests/ui/fn/implied-bounds-unnorm-associated-type-5.stderr

+15-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,21 @@ help: consider adding an explicit lifetime bound
1616
LL | impl<'a, T: 'a> Trait<'a> for T {
1717
| ++++
1818

19+
error[E0309]: the parameter type `T` may not live long enough
20+
--> $DIR/implied-bounds-unnorm-associated-type-5.rs:6:27
21+
|
22+
LL | impl<'a, T> Trait<'a> for T {
23+
| -- ^ ...so that the type `T` will meet its required lifetime bounds
24+
| |
25+
| the parameter type `T` must be valid for the lifetime `'a` as defined here...
26+
|
27+
help: consider adding an explicit lifetime bound
28+
|
29+
LL | impl<'a, T: 'a> Trait<'a> for T {
30+
| ++++
31+
1932
error[E0505]: cannot move out of `x` because it is borrowed
20-
--> $DIR/implied-bounds-unnorm-associated-type-5.rs:21:10
33+
--> $DIR/implied-bounds-unnorm-associated-type-5.rs:22:10
2134
|
2235
LL | let x = String::from("Hello World!");
2336
| - binding `x` declared here
@@ -33,7 +46,7 @@ help: consider cloning the value if the performance cost is acceptable
3346
LL | let y = f(&x.clone(), ());
3447
| ++++++++
3548

36-
error: aborting due to 2 previous errors
49+
error: aborting due to 3 previous errors
3750

3851
Some errors have detailed explanations: E0309, E0505.
3952
For more information about an error, try `rustc --explain E0309`.

Diff for: tests/ui/static/static-lifetime.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
pub trait Arbitrary: Sized + 'static {}
22

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

56
fn main() {
67
}

Diff for: tests/ui/static/static-lifetime.stderr

+28-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,32 @@ LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
1111
| ^^
1212
= note: but lifetime parameter must outlive the static lifetime
1313

14-
error: aborting due to 1 previous error
14+
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
15+
--> $DIR/static-lifetime.rs:3:34
16+
|
17+
LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
18+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
19+
|
20+
note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
21+
--> $DIR/static-lifetime.rs:3:6
22+
|
23+
LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
24+
| ^^
25+
note: ...so that the types are compatible
26+
--> $DIR/static-lifetime.rs:3:34
27+
|
28+
LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
30+
= note: expected `<Cow<'a, A> as Arbitrary>`
31+
found `<Cow<'_, A> as Arbitrary>`
32+
= note: but, the lifetime must be valid for the static lifetime...
33+
note: ...so that the declared lifetime parameter bounds are satisfied
34+
--> $DIR/static-lifetime.rs:3:34
35+
|
36+
LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
38+
39+
error: aborting due to 2 previous errors
1540

16-
For more information about this error, try `rustc --explain E0478`.
41+
Some errors have detailed explanations: E0478, E0495.
42+
For more information about an error, try `rustc --explain E0478`.

Diff for: tests/ui/wf/wf-in-where-clause-static.current.stderr

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0716]: temporary value dropped while borrowed
2+
--> $DIR/wf-in-where-clause-static.rs:18:18
3+
|
4+
LL | let s = foo(&String::from("blah blah blah"));
5+
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
6+
| | |
7+
| | creates a temporary value which is freed while still in use
8+
| argument requires that borrow lasts for `'static`
9+
10+
error: aborting due to 1 previous error
11+
12+
For more information about this error, try `rustc --explain E0716`.

Diff for: tests/ui/wf/wf-in-where-clause-static.next.stderr

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0716]: temporary value dropped while borrowed
2+
--> $DIR/wf-in-where-clause-static.rs:18:18
3+
|
4+
LL | let s = foo(&String::from("blah blah blah"));
5+
| -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
6+
| | |
7+
| | creates a temporary value which is freed while still in use
8+
| argument requires that borrow lasts for `'static`
9+
10+
error: aborting due to 1 previous error
11+
12+
For more information about this error, try `rustc --explain E0716`.

Diff for: tests/ui/wf/wf-in-where-clause-static.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
//@ check-pass
2-
//@ known-bug: #98117
3-
4-
// Should fail. Functions are responsible for checking the well-formedness of
5-
// their own where clauses, so this should fail and require an explicit bound
6-
// `T: 'static`.
1+
//@ revisions: current next
2+
//@ ignore-compare-mode-next-solver (explicit revisions)
3+
//@[next] compile-flags: -Znext-solver
74

85
use std::fmt::Display;
96

@@ -19,5 +16,6 @@ where
1916

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

0 commit comments

Comments
 (0)