Skip to content

Commit 8d4693c

Browse files
aliemjaylcnr
authored andcommitted
borrowck: use implied bounds from impl header
1 parent a3fe3bb commit 8d4693c

File tree

6 files changed

+89
-57
lines changed

6 files changed

+89
-57
lines changed

compiler/rustc_borrowck/src/type_check/free_region_relations.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rustc_data_structures::frozen::Frozen;
22
use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder};
3+
use rustc_hir::def::DefKind;
34
use rustc_infer::infer::canonical::QueryRegionConstraints;
45
use rustc_infer::infer::outlives;
56
use rustc_infer::infer::outlives::env::RegionBoundPairs;
@@ -195,7 +196,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
195196

196197
#[instrument(level = "debug", skip(self))]
197198
pub(crate) fn create(mut self) -> CreateResult<'tcx> {
198-
let span = self.infcx.tcx.def_span(self.universal_regions.defining_ty.def_id());
199+
let tcx = self.infcx.tcx;
200+
let defining_ty_def_id = self.universal_regions.defining_ty.def_id().expect_local();
201+
let span = tcx.def_span(defining_ty_def_id);
199202

200203
// Insert the facts we know from the predicates. Why? Why not.
201204
let param_env = self.param_env;
@@ -275,6 +278,26 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
275278
normalized_inputs_and_output.push(norm_ty);
276279
}
277280

281+
// Add implied bounds from impl header.
282+
if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) {
283+
for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) {
284+
let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = self
285+
.param_env
286+
.and(type_op::normalize::Normalize::new(ty))
287+
.fully_perform(self.infcx, span)
288+
else {
289+
tcx.dcx().span_delayed_bug(span, format!("failed to normalize {ty:?}"));
290+
continue;
291+
};
292+
constraints.extend(c);
293+
294+
// We currently add implied bounds from the normalized ty only.
295+
// This is more conservative and matches wfcheck behavior.
296+
let c = self.add_implied_bounds(norm_ty);
297+
constraints.extend(c);
298+
}
299+
}
300+
278301
for c in constraints {
279302
self.push_region_constraints(c, span);
280303
}

library/std/src/collections/hash/map.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -3049,9 +3049,8 @@ where
30493049
#[stable(feature = "hash_extend_copy", since = "1.4.0")]
30503050
impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap<K, V, S>
30513051
where
3052-
// FIXME(aliemjay): the bound `+ 'a` should not be necessary.
3053-
K: Eq + Hash + Copy + 'a,
3054-
V: Copy + 'a,
3052+
K: Eq + Hash + Copy,
3053+
V: Copy,
30553054
S: BuildHasher,
30563055
{
30573056
#[inline]

tests/ui/wf/wf-associated-const.rs

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// check that associated consts can assume the impl header is well-formed.
2+
3+
// FIXME(aliemjay): we should check the impl header is WF at the use site
4+
// but we currently don't in some cases. This is *unsound*.
5+
6+
trait Foo<'a, 'b, T>: Sized {
7+
const EVIL: fn(u: &'b u32) -> &'a u32;
8+
}
9+
10+
struct Evil<'a, 'b: 'a>(Option<&'a &'b ()>);
11+
12+
impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () {
13+
const EVIL: fn(&'b u32) -> &'a u32 = { |u| u };
14+
}
15+
16+
struct IndirectEvil<'a, 'b: 'a>(Option<&'a &'b ()>);
17+
18+
impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> {
19+
const EVIL: fn(&'b u32) -> &'a u32 = { |u| u };
20+
}
21+
22+
impl<'a, 'b> Evil<'a, 'b> {
23+
const INHERENT_EVIL: fn(&'b u32) -> &'a u32 = { |u| u };
24+
}
25+
26+
// while static methods can *assume* this, we should still
27+
// *check* that it holds at the use site.
28+
29+
fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
30+
<()>::EVIL(b) // FIXME: should be an error
31+
}
32+
33+
fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
34+
<IndirectEvil>::EVIL(b) // FIXME: should be an error
35+
}
36+
37+
fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
38+
<Evil>::INHERENT_EVIL(b)
39+
//~^ ERROR lifetime may not live long enough
40+
}
41+
42+
fn main() {}
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/wf-associated-const.rs:38:5
3+
|
4+
LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
5+
| -- -- lifetime `'b` defined here
6+
| |
7+
| lifetime `'a` defined here
8+
LL | <Evil>::INHERENT_EVIL(b)
9+
| ^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
10+
|
11+
= help: consider adding the following bound: `'b: 'a`
12+
13+
error: aborting due to previous error
14+

tests/ui/wf/wf-static-method.rs

+3-10
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
// check that static methods don't get to assume their trait-ref
2-
// is well-formed.
3-
// FIXME(#27579): this is just a bug. However, our checking with
4-
// static inherent methods isn't quite working - need to
5-
// fix that before removing the check.
1+
// check that static methods can assume their trait-ref is well-formed.
62

73
trait Foo<'a, 'b, T>: Sized {
84
fn make_me() -> Self { loop {} }
@@ -15,7 +11,6 @@ impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () {
1511
fn make_me() -> Self { }
1612
fn static_evil(u: &'b u32) -> &'a u32 {
1713
u
18-
//~^ ERROR lifetime may not live long enough
1914
}
2015
}
2116

@@ -25,20 +20,18 @@ impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> {
2520
fn make_me() -> Self { IndirectEvil(None) }
2621
fn static_evil(u: &'b u32) -> &'a u32 {
2722
let me = Self::make_me();
28-
//~^ ERROR lifetime may not live long enough
2923
loop {} // (`me` could be used for the lifetime transmute).
3024
}
3125
}
3226

3327
impl<'a, 'b> Evil<'a, 'b> {
3428
fn inherent_evil(u: &'b u32) -> &'a u32 {
3529
u
36-
//~^ ERROR lifetime may not live long enough
3730
}
3831
}
3932

40-
// while static methods don't get to *assume* this, we still
41-
// *check* that they hold.
33+
// while static methods can *assume* this, we should still
34+
// *check* that it holds at the use site.
4235

4336
fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
4437
<()>::static_evil(b)

tests/ui/wf/wf-static-method.stderr

+4-43
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,5 @@
11
error: lifetime may not live long enough
2-
--> $DIR/wf-static-method.rs:17:9
3-
|
4-
LL | impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () {
5-
| -- -- lifetime `'b` defined here
6-
| |
7-
| lifetime `'a` defined here
8-
...
9-
LL | u
10-
| ^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
11-
|
12-
= help: consider adding the following bound: `'b: 'a`
13-
14-
error: lifetime may not live long enough
15-
--> $DIR/wf-static-method.rs:27:18
16-
|
17-
LL | impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> {
18-
| -- -- lifetime `'b` defined here
19-
| |
20-
| lifetime `'a` defined here
21-
...
22-
LL | let me = Self::make_me();
23-
| ^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
24-
|
25-
= help: consider adding the following bound: `'b: 'a`
26-
27-
error: lifetime may not live long enough
28-
--> $DIR/wf-static-method.rs:35:9
29-
|
30-
LL | impl<'a, 'b> Evil<'a, 'b> {
31-
| -- -- lifetime `'b` defined here
32-
| |
33-
| lifetime `'a` defined here
34-
LL | fn inherent_evil(u: &'b u32) -> &'a u32 {
35-
LL | u
36-
| ^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
37-
|
38-
= help: consider adding the following bound: `'b: 'a`
39-
40-
error: lifetime may not live long enough
41-
--> $DIR/wf-static-method.rs:44:5
2+
--> $DIR/wf-static-method.rs:37:5
423
|
434
LL | fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
445
| -- -- lifetime `'b` defined here
@@ -50,7 +11,7 @@ LL | <()>::static_evil(b)
5011
= help: consider adding the following bound: `'b: 'a`
5112

5213
error: lifetime may not live long enough
53-
--> $DIR/wf-static-method.rs:49:5
14+
--> $DIR/wf-static-method.rs:42:5
5415
|
5516
LL | fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
5617
| -- -- lifetime `'b` defined here
@@ -62,7 +23,7 @@ LL | <IndirectEvil>::static_evil(b)
6223
= help: consider adding the following bound: `'b: 'a`
6324

6425
error: lifetime may not live long enough
65-
--> $DIR/wf-static-method.rs:54:5
26+
--> $DIR/wf-static-method.rs:47:5
6627
|
6728
LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
6829
| -- -- lifetime `'b` defined here
@@ -73,5 +34,5 @@ LL | <Evil>::inherent_evil(b)
7334
|
7435
= help: consider adding the following bound: `'b: 'a`
7536

76-
error: aborting due to 6 previous errors
37+
error: aborting due to 3 previous errors
7738

0 commit comments

Comments
 (0)