Skip to content

Commit a7e4de1

Browse files
committed
Auto merge of #116935 - oli-obk:different_lifetime_taits_in_same_sig, r=compiler-errors
Prevent opaque types being instantiated twice with different regions within the same function addresses https://github.com/orgs/rust-lang/projects/22/views/1?pane=issue&itemId=41329537 r? `@compiler-errors`
2 parents e760daa + be9317d commit a7e4de1

17 files changed

+383
-54
lines changed

compiler/rustc_borrowck/messages.ftl

+6
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,12 @@ borrowck_moved_due_to_usage_in_operator =
132132
*[false] operator
133133
}
134134
135+
borrowck_opaque_type_lifetime_mismatch =
136+
opaque type used twice with different lifetimes
137+
.label = lifetime `{$arg}` used here
138+
.prev_lifetime_label = lifetime `{$prev}` previously used here
139+
.note = if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
140+
135141
borrowck_opaque_type_non_generic_param =
136142
expected generic {$kind} parameter, found `{$ty}`
137143
.label = {STREQ($ty, "'static") ->

compiler/rustc_borrowck/src/region_infer/opaque_types.rs

+76-20
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,77 @@ use rustc_infer::traits::{Obligation, ObligationCause};
99
use rustc_macros::extension;
1010
use rustc_middle::traits::DefiningAnchor;
1111
use rustc_middle::ty::visit::TypeVisitableExt;
12+
use rustc_middle::ty::RegionVid;
1213
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
1314
use rustc_middle::ty::{GenericArgKind, GenericArgs};
1415
use rustc_span::Span;
1516
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
1617
use rustc_trait_selection::traits::ObligationCtxt;
1718

19+
use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
1820
use crate::session_diagnostics::NonGenericOpaqueTypeParam;
1921

2022
use super::RegionInferenceContext;
2123

2224
impl<'tcx> RegionInferenceContext<'tcx> {
25+
fn universal_name(&self, vid: ty::RegionVid) -> Option<ty::Region<'tcx>> {
26+
let scc = self.constraint_sccs.scc(vid);
27+
self.scc_values
28+
.universal_regions_outlived_by(scc)
29+
.find_map(|lb| self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?))
30+
}
31+
32+
fn generic_arg_to_region(&self, arg: ty::GenericArg<'tcx>) -> Option<RegionVid> {
33+
let region = arg.as_region()?;
34+
35+
if let ty::RePlaceholder(..) = region.kind() {
36+
None
37+
} else {
38+
Some(self.to_region_vid(region))
39+
}
40+
}
41+
42+
/// Check that all opaque types have the same region parameters if they have the same
43+
/// non-region parameters. This is necessary because within the new solver we perform various query operations
44+
/// modulo regions, and thus could unsoundly select some impls that don't hold.
45+
fn check_unique(
46+
&self,
47+
infcx: &InferCtxt<'tcx>,
48+
opaque_ty_decls: &FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
49+
) {
50+
for (i, (a, a_ty)) in opaque_ty_decls.iter().enumerate() {
51+
for (b, b_ty) in opaque_ty_decls.iter().skip(i + 1) {
52+
if a.def_id != b.def_id {
53+
continue;
54+
}
55+
// Non-lifetime params differ -> ok
56+
if infcx.tcx.erase_regions(a.args) != infcx.tcx.erase_regions(b.args) {
57+
continue;
58+
}
59+
trace!(?a, ?b);
60+
for (a, b) in a.args.iter().zip(b.args) {
61+
trace!(?a, ?b);
62+
let Some(r1) = self.generic_arg_to_region(a) else {
63+
continue;
64+
};
65+
let Some(r2) = self.generic_arg_to_region(b) else {
66+
continue;
67+
};
68+
if self.eval_equal(r1, r2) {
69+
continue;
70+
}
71+
72+
infcx.dcx().emit_err(LifetimeMismatchOpaqueParam {
73+
arg: self.universal_name(r1).unwrap().into(),
74+
prev: self.universal_name(r2).unwrap().into(),
75+
span: a_ty.span,
76+
prev_span: b_ty.span,
77+
});
78+
}
79+
}
80+
}
81+
}
82+
2383
/// Resolve any opaque types that were encountered while borrow checking
2484
/// this item. This is then used to get the type in the `type_of` query.
2585
///
@@ -65,6 +125,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
65125
infcx: &InferCtxt<'tcx>,
66126
opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
67127
) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> {
128+
self.check_unique(infcx, &opaque_ty_decls);
129+
68130
let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default();
69131

70132
let member_constraints: FxIndexMap<_, _> = self
@@ -80,26 +142,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
80142

81143
let mut arg_regions = vec![self.universal_regions.fr_static];
82144

83-
let to_universal_region = |vid, arg_regions: &mut Vec<_>| {
84-
trace!(?vid);
85-
let scc = self.constraint_sccs.scc(vid);
86-
trace!(?scc);
87-
match self.scc_values.universal_regions_outlived_by(scc).find_map(|lb| {
88-
self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?)
89-
}) {
90-
Some(region) => {
91-
let vid = self.universal_regions.to_region_vid(region);
92-
arg_regions.push(vid);
93-
region
94-
}
95-
None => {
96-
arg_regions.push(vid);
97-
ty::Region::new_error_with_message(
98-
infcx.tcx,
99-
concrete_type.span,
100-
"opaque type with non-universal region args",
101-
)
102-
}
145+
let to_universal_region = |vid, arg_regions: &mut Vec<_>| match self.universal_name(vid)
146+
{
147+
Some(region) => {
148+
let vid = self.universal_regions.to_region_vid(region);
149+
arg_regions.push(vid);
150+
region
151+
}
152+
None => {
153+
arg_regions.push(vid);
154+
ty::Region::new_error_with_message(
155+
infcx.tcx,
156+
concrete_type.span,
157+
"opaque type with non-universal region args",
158+
)
103159
}
104160
};
105161

compiler/rustc_borrowck/src/session_diagnostics.rs

+13
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,19 @@ pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> {
304304
pub param_span: Span,
305305
}
306306

307+
#[derive(Diagnostic)]
308+
#[diag(borrowck_opaque_type_lifetime_mismatch)]
309+
pub(crate) struct LifetimeMismatchOpaqueParam<'tcx> {
310+
pub arg: GenericArg<'tcx>,
311+
pub prev: GenericArg<'tcx>,
312+
#[primary_span]
313+
#[label]
314+
#[note]
315+
pub span: Span,
316+
#[label(borrowck_prev_lifetime_label)]
317+
pub prev_span: Span,
318+
}
319+
307320
#[derive(Subdiagnostic)]
308321
pub(crate) enum CaptureReasonLabel<'a> {
309322
#[label(borrowck_moved_due_to_call)]

src/tools/tidy/src/issues.txt

-1
Original file line numberDiff line numberDiff line change
@@ -1204,7 +1204,6 @@
12041204
"ui/impl-trait/issue-56445.rs",
12051205
"ui/impl-trait/issue-68532.rs",
12061206
"ui/impl-trait/issue-72911.rs",
1207-
"ui/impl-trait/issue-86465.rs",
12081207
"ui/impl-trait/issue-87450.rs",
12091208
"ui/impl-trait/issue-99073-2.rs",
12101209
"ui/impl-trait/issue-99073.rs",

tests/ui/impl-trait/issue-86465.rs

-10
This file was deleted.

tests/ui/impl-trait/issue-86465.stderr

-11
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#![feature(type_alias_impl_trait)]
2+
3+
type Foo<'a> = impl Sized;
4+
5+
fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> (Foo<'a>, Foo<'b>) {
6+
(x, y)
7+
//~^ ERROR opaque type used twice with different lifetimes
8+
//~| ERROR opaque type used twice with different lifetimes
9+
}
10+
11+
type Bar<'a, 'b> = impl std::fmt::Debug;
12+
13+
fn bar<'x, 'y>(i: &'x i32, j: &'y i32) -> (Bar<'x, 'y>, Bar<'y, 'x>) {
14+
(i, j)
15+
//~^ ERROR opaque type used twice with different lifetimes
16+
//~| ERROR opaque type used twice with different lifetimes
17+
//~| ERROR opaque type used twice with different lifetimes
18+
//~| ERROR opaque type used twice with different lifetimes
19+
}
20+
21+
fn main() {
22+
let meh = 42;
23+
let muh = 69;
24+
println!("{:?}", bar(&meh, &muh));
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
error: opaque type used twice with different lifetimes
2+
--> $DIR/lifetime_mismatch.rs:6:5
3+
|
4+
LL | (x, y)
5+
| ^^^^^^
6+
| |
7+
| lifetime `'a` used here
8+
| lifetime `'b` previously used here
9+
|
10+
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
11+
--> $DIR/lifetime_mismatch.rs:6:5
12+
|
13+
LL | (x, y)
14+
| ^^^^^^
15+
16+
error: opaque type used twice with different lifetimes
17+
--> $DIR/lifetime_mismatch.rs:6:5
18+
|
19+
LL | (x, y)
20+
| ^^^^^^
21+
| |
22+
| lifetime `'a` used here
23+
| lifetime `'b` previously used here
24+
|
25+
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
26+
--> $DIR/lifetime_mismatch.rs:6:5
27+
|
28+
LL | (x, y)
29+
| ^^^^^^
30+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
31+
32+
error: opaque type used twice with different lifetimes
33+
--> $DIR/lifetime_mismatch.rs:14:5
34+
|
35+
LL | (i, j)
36+
| ^^^^^^
37+
| |
38+
| lifetime `'x` used here
39+
| lifetime `'y` previously used here
40+
|
41+
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
42+
--> $DIR/lifetime_mismatch.rs:14:5
43+
|
44+
LL | (i, j)
45+
| ^^^^^^
46+
47+
error: opaque type used twice with different lifetimes
48+
--> $DIR/lifetime_mismatch.rs:14:5
49+
|
50+
LL | (i, j)
51+
| ^^^^^^
52+
| |
53+
| lifetime `'y` used here
54+
| lifetime `'x` previously used here
55+
|
56+
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
57+
--> $DIR/lifetime_mismatch.rs:14:5
58+
|
59+
LL | (i, j)
60+
| ^^^^^^
61+
62+
error: opaque type used twice with different lifetimes
63+
--> $DIR/lifetime_mismatch.rs:14:5
64+
|
65+
LL | (i, j)
66+
| ^^^^^^
67+
| |
68+
| lifetime `'x` used here
69+
| lifetime `'y` previously used here
70+
|
71+
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
72+
--> $DIR/lifetime_mismatch.rs:14:5
73+
|
74+
LL | (i, j)
75+
| ^^^^^^
76+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
77+
78+
error: opaque type used twice with different lifetimes
79+
--> $DIR/lifetime_mismatch.rs:14:5
80+
|
81+
LL | (i, j)
82+
| ^^^^^^
83+
| |
84+
| lifetime `'y` used here
85+
| lifetime `'x` previously used here
86+
|
87+
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
88+
--> $DIR/lifetime_mismatch.rs:14:5
89+
|
90+
LL | (i, j)
91+
| ^^^^^^
92+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
93+
94+
error: aborting due to 6 previous errors
95+

tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
type Foo<'a, 'b> = impl std::fmt::Debug;
44

55
fn foo<'x, 'y>(i: &'x i32, j: &'y i32) -> (Foo<'x, 'y>, Foo<'y, 'x>) {
6-
(i, i) //~ ERROR concrete type differs from previous
6+
(i, i)
7+
//~^ ERROR opaque type used twice with different lifetimes
8+
//~| ERROR opaque type used twice with different lifetimes
9+
//~| ERROR opaque type used twice with different lifetimes
10+
//~| ERROR opaque type used twice with different lifetimes
711
}
812

913
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,64 @@
1-
error: concrete type differs from previous defining opaque type use
1+
error: opaque type used twice with different lifetimes
22
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5
33
|
44
LL | (i, i)
55
| ^^^^^^
66
| |
7-
| expected `&'a i32`, got `&'b i32`
8-
| this expression supplies two conflicting concrete types for the same opaque type
7+
| lifetime `'x` used here
8+
| lifetime `'y` previously used here
9+
|
10+
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
11+
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5
12+
|
13+
LL | (i, i)
14+
| ^^^^^^
15+
16+
error: opaque type used twice with different lifetimes
17+
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5
18+
|
19+
LL | (i, i)
20+
| ^^^^^^
21+
| |
22+
| lifetime `'y` used here
23+
| lifetime `'x` previously used here
24+
|
25+
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
26+
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5
27+
|
28+
LL | (i, i)
29+
| ^^^^^^
30+
31+
error: opaque type used twice with different lifetimes
32+
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5
33+
|
34+
LL | (i, i)
35+
| ^^^^^^
36+
| |
37+
| lifetime `'x` used here
38+
| lifetime `'y` previously used here
39+
|
40+
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
41+
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5
42+
|
43+
LL | (i, i)
44+
| ^^^^^^
45+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
46+
47+
error: opaque type used twice with different lifetimes
48+
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5
49+
|
50+
LL | (i, i)
51+
| ^^^^^^
52+
| |
53+
| lifetime `'y` used here
54+
| lifetime `'x` previously used here
55+
|
56+
note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types
57+
--> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5
58+
|
59+
LL | (i, i)
60+
| ^^^^^^
61+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
962

10-
error: aborting due to 1 previous error
63+
error: aborting due to 4 previous errors
1164

0 commit comments

Comments
 (0)