Skip to content

Commit 5f19a76

Browse files
committed
Auto merge of #116935 - oli-obk:different_lifetime_taits_in_same_sig, r=<try>
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 7db4a89 + 29b10dc commit 5f19a76

10 files changed

+182
-42
lines changed

compiler/rustc_borrowck/messages.ftl

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

compiler/rustc_borrowck/src/region_infer/opaque_types.rs

+63-9
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,75 @@ use rustc_infer::infer::TyCtxtInferExt as _;
88
use rustc_infer::traits::{Obligation, ObligationCause};
99
use rustc_middle::traits::DefiningAnchor;
1010
use rustc_middle::ty::visit::TypeVisitableExt;
11+
use rustc_middle::ty::RegionVid;
1112
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
1213
use rustc_middle::ty::{GenericArgKind, GenericArgs};
1314
use rustc_span::Span;
1415
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
1516
use rustc_trait_selection::traits::ObligationCtxt;
1617

18+
use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
1719
use crate::session_diagnostics::NonGenericOpaqueTypeParam;
1820

1921
use super::RegionInferenceContext;
2022

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

69129
let member_constraints: FxIndexMap<_, _> = self
@@ -79,13 +139,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
79139

80140
let mut subst_regions = vec![self.universal_regions.fr_static];
81141

82-
let to_universal_region = |vid, subst_regions: &mut Vec<_>| {
83-
trace!(?vid);
84-
let scc = self.constraint_sccs.scc(vid);
85-
trace!(?scc);
86-
match self.scc_values.universal_regions_outlived_by(scc).find_map(|lb| {
87-
self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?)
88-
}) {
142+
let to_universal_region =
143+
|vid, subst_regions: &mut Vec<_>| match self.universal_name(vid) {
89144
Some(region) => {
90145
let vid = self.universal_regions.to_region_vid(region);
91146
subst_regions.push(vid);
@@ -99,8 +154,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
99154
"opaque type with non-universal region args",
100155
)
101156
}
102-
}
103-
};
157+
};
104158

105159
// Start by inserting universal regions from the member_constraint choice regions.
106160
// This will ensure they get precedence when folding the regions in the concrete type.

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)]

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,22 @@
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+
}
9+
10+
type Bar<'a, 'b> = impl std::fmt::Debug;
11+
12+
fn bar<'x, 'y>(i: &'x i32, j: &'y i32) -> (Bar<'x, 'y>, Bar<'y, 'x>) {
13+
(i, j)
14+
//~^ ERROR opaque type used twice with different lifetimes
15+
//~| ERROR opaque type used twice with different lifetimes
16+
}
17+
18+
fn main() {
19+
let meh = 42;
20+
let muh = 69;
21+
println!("{:?}", bar(&meh, &muh));
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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:13:5
18+
|
19+
LL | (i, j)
20+
| ^^^^^^
21+
| |
22+
| lifetime `'x` used here
23+
| lifetime `'y` 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:13:5
27+
|
28+
LL | (i, j)
29+
| ^^^^^^
30+
31+
error: opaque type used twice with different lifetimes
32+
--> $DIR/lifetime_mismatch.rs:13:5
33+
|
34+
LL | (i, j)
35+
| ^^^^^^
36+
| |
37+
| lifetime `'y` used here
38+
| lifetime `'x` 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/lifetime_mismatch.rs:13:5
42+
|
43+
LL | (i, j)
44+
| ^^^^^^
45+
46+
error: aborting due to 3 previous errors
47+

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
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
79
}
810

911
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,32 @@
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+
| ^^^^^^
930

10-
error: aborting due to previous error
31+
error: aborting due to 2 previous errors
1132

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

+3-7
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,11 @@ fn f<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A, B>)
77
(a.clone(), a)
88
}
99

10-
type Foo<'a, 'b> = impl std::fmt::Debug;
11-
12-
fn foo<'x, 'y>(i: &'x i32, j: &'y i32) -> (Foo<'x, 'y>, Foo<'y, 'x>) {
13-
(i, j)
10+
type Tait<'x> = impl Sized;
11+
fn define<'a: 'b, 'b: 'a>(x: &'a u8, y: &'b u8) -> (Tait<'a>, Tait<'b>) {
12+
((), ())
1413
}
1514

1615
fn main() {
1716
println!("{}", <X<_, _> as ToString>::to_string(&f(42_i32, String::new()).1));
18-
let meh = 42;
19-
let muh = 69;
20-
println!("{:?}", foo(&meh, &muh));
2117
}

0 commit comments

Comments
 (0)