Skip to content

Commit 683a9c8

Browse files
committed
Do leak check after function ptr coercion
1 parent 4bb4dc4 commit 683a9c8

30 files changed

+271
-256
lines changed

compiler/rustc_infer/src/infer/error_reporting/mod.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -1442,6 +1442,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
14421442
/// the message in `secondary_span` as the primary label, and apply the message that would
14431443
/// otherwise be used for the primary label on the `secondary_span` `Span`. This applies on
14441444
/// E0271, like `src/test/ui/issues/issue-39970.stderr`.
1445+
#[tracing::instrument(
1446+
level = "debug",
1447+
skip(self, diag, secondary_span, swap_secondary_and_primary, force_label)
1448+
)]
14451449
pub fn note_type_err(
14461450
&self,
14471451
diag: &mut Diagnostic,
@@ -1453,7 +1457,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
14531457
force_label: bool,
14541458
) {
14551459
let span = cause.span(self.tcx);
1456-
debug!("note_type_err cause={:?} values={:?}, terr={:?}", cause, values, terr);
14571460

14581461
// For some types of errors, expected-found does not make
14591462
// sense, so just ignore the values we were given.
@@ -1621,9 +1624,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16211624
}
16221625
};
16231626

1624-
// Ignore msg for object safe coercion
1625-
// since E0038 message will be printed
16261627
match terr {
1628+
// Ignore msg for object safe coercion
1629+
// since E0038 message will be printed
16271630
TypeError::ObjectUnsafeCoercion(_) => {}
16281631
_ => {
16291632
let mut label_or_note = |span: Span, msg: &str| {
@@ -1774,6 +1777,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
17741777
// It reads better to have the error origin as the final
17751778
// thing.
17761779
self.note_error_origin(diag, cause, exp_found, terr);
1780+
1781+
debug!(?diag);
17771782
}
17781783

17791784
fn suggest_tuple_pattern(

compiler/rustc_middle/src/ty/error.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,10 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
135135
ArgCount => write!(f, "incorrect number of function parameters"),
136136
FieldMisMatch(adt, field) => write!(f, "field type mismatch: {}.{}", adt, field),
137137
RegionsDoesNotOutlive(..) => write!(f, "lifetime mismatch"),
138-
RegionsInsufficientlyPolymorphic(br, _) => write!(
139-
f,
140-
"expected bound lifetime parameter{}, found concrete lifetime",
141-
br_string(br)
142-
),
138+
// Actually naming the region here is a bit confusing because context is lacking
139+
RegionsInsufficientlyPolymorphic(..) => {
140+
write!(f, "one type is more general than the other")
141+
}
143142
RegionsOverlyPolymorphic(br, _) => write!(
144143
f,
145144
"expected concrete lifetime, found bound lifetime parameter{}",

compiler/rustc_mir_build/src/build/matches/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
151151
///
152152
/// * From each pre-binding block to the next pre-binding block.
153153
/// * From each otherwise block to the next pre-binding block.
154+
#[tracing::instrument(level = "debug", skip(self, arms))]
154155
pub(crate) fn match_expr(
155156
&mut self,
156157
destination: Place<'tcx>,

compiler/rustc_mir_build/src/thir/cx/block.rs

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ impl<'tcx> Cx<'tcx> {
7575
};
7676

7777
let mut pattern = self.pattern_from_hir(local.pat);
78+
debug!(?pattern);
7879

7980
if let Some(ty) = &local.ty {
8081
if let Some(&user_ty) =

compiler/rustc_mir_build/src/thir/cx/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ impl<'tcx> Cx<'tcx> {
9898
}
9999
}
100100

101+
#[tracing::instrument(level = "debug", skip(self))]
101102
pub(crate) fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Pat<'tcx> {
102103
let p = match self.tcx.hir().get(p.hir_id) {
103104
Node::Pat(p) | Node::Binding(p) => p,

compiler/rustc_typeck/src/check/_match.rs

+41-32
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
5656
let mut all_arms_diverge = Diverges::WarnedAlways;
5757

5858
let expected = orig_expected.adjust_for_branches(self);
59+
debug!(?expected);
5960

6061
let mut coercion = {
6162
let coerce_first = match expected {
@@ -127,6 +128,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
127128
Some(&arm.body),
128129
arm_ty,
129130
Some(&mut |err: &mut Diagnostic| {
131+
let Some(ret) = self.ret_type_span else {
132+
return;
133+
};
134+
let Expectation::IsLast(stmt) = orig_expected else {
135+
return
136+
};
130137
let can_coerce_to_return_ty = match self.ret_coercion.as_ref() {
131138
Some(ret_coercion) if self.in_tail_expr => {
132139
let ret_ty = ret_coercion.borrow().expected_ty();
@@ -138,38 +145,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
138145
}
139146
_ => false,
140147
};
141-
if let (Expectation::IsLast(stmt), Some(ret), true) =
142-
(orig_expected, self.ret_type_span, can_coerce_to_return_ty)
143-
{
144-
let semi_span = expr.span.shrink_to_hi().with_hi(stmt.hi());
145-
let mut ret_span: MultiSpan = semi_span.into();
146-
ret_span.push_span_label(
147-
expr.span,
148-
"this could be implicitly returned but it is a statement, not a \
149-
tail expression"
150-
.to_owned(),
151-
);
152-
ret_span.push_span_label(
153-
ret,
154-
"the `match` arms can conform to this return type".to_owned(),
155-
);
156-
ret_span.push_span_label(
157-
semi_span,
158-
"the `match` is a statement because of this semicolon, consider \
159-
removing it"
160-
.to_owned(),
161-
);
162-
err.span_note(
163-
ret_span,
164-
"you might have meant to return the `match` expression",
165-
);
166-
err.tool_only_span_suggestion(
167-
semi_span,
168-
"remove this semicolon",
169-
String::new(),
170-
Applicability::MaybeIncorrect,
171-
);
148+
if !can_coerce_to_return_ty {
149+
return;
172150
}
151+
152+
let semi_span = expr.span.shrink_to_hi().with_hi(stmt.hi());
153+
let mut ret_span: MultiSpan = semi_span.into();
154+
ret_span.push_span_label(
155+
expr.span,
156+
"this could be implicitly returned but it is a statement, not a \
157+
tail expression"
158+
.to_owned(),
159+
);
160+
ret_span.push_span_label(
161+
ret,
162+
"the `match` arms can conform to this return type".to_owned(),
163+
);
164+
ret_span.push_span_label(
165+
semi_span,
166+
"the `match` is a statement because of this semicolon, consider \
167+
removing it"
168+
.to_owned(),
169+
);
170+
err.span_note(
171+
ret_span,
172+
"you might have meant to return the `match` expression",
173+
);
174+
err.tool_only_span_suggestion(
175+
semi_span,
176+
"remove this semicolon",
177+
String::new(),
178+
Applicability::MaybeIncorrect,
179+
);
173180
}),
174181
false,
175182
);
@@ -199,7 +206,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
199206
// We won't diverge unless the scrutinee or all arms diverge.
200207
self.diverges.set(scrut_diverges | all_arms_diverge);
201208

202-
coercion.complete(self)
209+
let match_ty = coercion.complete(self);
210+
debug!(?match_ty);
211+
match_ty
203212
}
204213

205214
fn get_appropriate_arm_semicolon_removal_span(

compiler/rustc_typeck/src/check/coercion.rs

+32-15
Original file line numberDiff line numberDiff line change
@@ -737,14 +737,27 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
737737
F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
738738
G: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
739739
{
740-
if let ty::FnPtr(fn_ty_b) = b.kind()
741-
&& let (hir::Unsafety::Normal, hir::Unsafety::Unsafe) =
742-
(fn_ty_a.unsafety(), fn_ty_b.unsafety())
743-
{
744-
let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
745-
return self.unify_and(unsafe_a, b, to_unsafe);
746-
}
747-
self.unify_and(a, b, normal)
740+
self.commit_unconditionally(|snapshot| {
741+
let result = if let ty::FnPtr(fn_ty_b) = b.kind()
742+
&& let (hir::Unsafety::Normal, hir::Unsafety::Unsafe) =
743+
(fn_ty_a.unsafety(), fn_ty_b.unsafety())
744+
{
745+
let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
746+
self.unify_and(unsafe_a, b, to_unsafe)
747+
} else {
748+
self.unify_and(a, b, normal)
749+
};
750+
751+
// FIXME(#73154): This is a hack. Currently LUB can generate
752+
// unsolvable constraints. Additionally, it returns `a`
753+
// unconditionally, even when the "LUB" is `b`. In the future, we
754+
// want the coerced type to be the actual supertype of these two,
755+
// but for now, we want to just error to ensure we don't lock
756+
// ourselves into a specific behavior with NLL.
757+
self.leak_check(false, snapshot)?;
758+
759+
result
760+
})
748761
}
749762

750763
fn coerce_from_fn_pointer(
@@ -1133,8 +1146,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11331146
let (adjustments, target) = self.register_infer_ok_obligations(ok);
11341147
self.apply_adjustments(new, adjustments);
11351148
debug!(
1136-
"coercion::try_find_coercion_lub: was able to coerce from previous type {:?} to new type {:?}",
1137-
prev_ty, new_ty,
1149+
"coercion::try_find_coercion_lub: was able to coerce from new type {:?} to previous type {:?} ({:?})",
1150+
new_ty, prev_ty, target
11381151
);
11391152
return Ok(target);
11401153
}
@@ -1190,15 +1203,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11901203
}
11911204
}
11921205
Ok(ok) => {
1193-
debug!(
1194-
"coercion::try_find_coercion_lub: was able to coerce previous type {:?} to new type {:?}",
1195-
prev_ty, new_ty,
1196-
);
11971206
let (adjustments, target) = self.register_infer_ok_obligations(ok);
11981207
for expr in exprs {
11991208
let expr = expr.as_coercion_site();
12001209
self.apply_adjustments(expr, adjustments.clone());
12011210
}
1211+
debug!(
1212+
"coercion::try_find_coercion_lub: was able to coerce previous type {:?} to new type {:?} ({:?})",
1213+
prev_ty, new_ty, target
1214+
);
12021215
Ok(target)
12031216
}
12041217
}
@@ -1430,6 +1443,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
14301443
})
14311444
};
14321445

1446+
debug!(?result);
14331447
match result {
14341448
Ok(v) => {
14351449
self.final_ty = Some(v);
@@ -1520,7 +1534,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
15201534
augment_error(&mut err);
15211535
}
15221536

1523-
if let Some(expr) = expression {
1537+
let is_insufficiently_polymorphic =
1538+
matches!(coercion_error, TypeError::RegionsInsufficientlyPolymorphic(..));
1539+
1540+
if !is_insufficiently_polymorphic && let Some(expr) = expression {
15241541
fcx.emit_coerce_suggestions(
15251542
&mut err,
15261543
expr,

compiler/rustc_typeck/src/check/demand.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
129129
///
130130
/// N.B., this code relies on `self.diverges` to be accurate. In particular, assignments to `!`
131131
/// will be permitted if the diverges flag is currently "always".
132+
#[tracing::instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))]
132133
pub fn demand_coerce_diag(
133134
&self,
134135
expr: &hir::Expr<'tcx>,
@@ -150,7 +151,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
150151
let expr_ty = self.resolve_vars_with_obligations(checked_ty);
151152
let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e.clone());
152153

153-
self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr, Some(e));
154+
let is_insufficiently_polymorphic =
155+
matches!(e, TypeError::RegionsInsufficientlyPolymorphic(..));
156+
157+
// FIXME(#73154): For now, we do leak check when coercing function
158+
// pointers in typeck, instead of only during borrowck. This can lead
159+
// to these `RegionsInsufficientlyPolymorphic` errors that aren't helpful.
160+
if !is_insufficiently_polymorphic {
161+
self.emit_coerce_suggestions(
162+
&mut err,
163+
expr,
164+
expr_ty,
165+
expected,
166+
expected_ty_expr,
167+
Some(e),
168+
);
169+
}
154170

155171
(expected, Some(err))
156172
}
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,12 @@
11
error[E0308]: mismatched types
2-
--> $DIR/placeholder-pattern-fail.rs:9:12
2+
--> $DIR/placeholder-pattern-fail.rs:9:47
33
|
44
LL | let _: for<'a, 'b> fn(Inv<'a>, Inv<'b>) = sub;
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
5+
| ^^^ one type is more general than the other
66
|
77
= note: expected fn pointer `for<'a, 'b> fn(Inv<'a>, Inv<'b>)`
88
found fn pointer `for<'a> fn(Inv<'a>, Inv<'a>)`
99

10-
error[E0308]: mismatched types
11-
--> $DIR/placeholder-pattern-fail.rs:9:12
12-
|
13-
LL | let _: for<'a, 'b> fn(Inv<'a>, Inv<'b>) = sub;
14-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
15-
|
16-
= note: expected fn pointer `for<'a, 'b> fn(Inv<'a>, Inv<'b>)`
17-
found fn pointer `for<'a> fn(Inv<'a>, Inv<'a>)`
18-
19-
error: lifetime may not live long enough
20-
--> $DIR/placeholder-pattern-fail.rs:14:13
21-
|
22-
LL | fn simple1<'c>(x: (&'c i32,)) {
23-
| -- lifetime `'c` defined here
24-
LL | let _x: (&'static i32,) = x;
25-
| ^^^^^^^^^^^^^^^ type annotation requires that `'c` must outlive `'static`
26-
27-
error: lifetime may not live long enough
28-
--> $DIR/placeholder-pattern-fail.rs:19:12
29-
|
30-
LL | fn simple2<'c>(x: (&'c i32,)) {
31-
| -- lifetime `'c` defined here
32-
LL | let _: (&'static i32,) = x;
33-
| ^^^^^^^^^^^^^^^ type annotation requires that `'c` must outlive `'static`
34-
35-
error: aborting due to 4 previous errors
10+
error: aborting due to previous error
3611

3712
For more information about this error, try `rustc --explain E0308`.

src/test/ui/hrtb/hrtb-exists-forall-fn.nll.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0308]: mismatched types
2-
--> $DIR/hrtb-exists-forall-fn.rs:17:12
2+
--> $DIR/hrtb-exists-forall-fn.rs:17:34
33
|
44
LL | let _: for<'b> fn(&'b u32) = foo();
5-
| ^^^^^^^^^^^^^^^^^^^ one type is more general than the other
5+
| ^^^^^ one type is more general than the other
66
|
77
= note: expected fn pointer `for<'b> fn(&'b u32)`
88
found fn pointer `fn(&u32)`

src/test/ui/lub-glb/old-lub-glb-hr-noteq1.stderr src/test/ui/lub-glb/old-lub-glb-hr-noteq1.baseleak.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
error[E0308]: `match` arms have incompatible types
2-
--> $DIR/old-lub-glb-hr-noteq1.rs:11:14
2+
--> $DIR/old-lub-glb-hr-noteq1.rs:17:14
33
|
44
LL | let z = match 22 {
55
| _____________-
66
LL | | 0 => x,
77
| | - this is found to be of type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
88
LL | | _ => y,
99
| | ^ one type is more general than the other
10+
LL | |
11+
... |
12+
LL | |
1013
LL | | };
1114
| |_____- `match` arms have incompatible types
1215
|
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0308]: `match` arms have incompatible types
2+
--> $DIR/old-lub-glb-hr-noteq1.rs:17:14
3+
|
4+
LL | let z = match 22 {
5+
| _____________-
6+
LL | | 0 => x,
7+
| | - this is found to be of type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
8+
LL | | _ => y,
9+
| | ^ one type is more general than the other
10+
LL | |
11+
... |
12+
LL | |
13+
LL | | };
14+
| |_____- `match` arms have incompatible types
15+
|
16+
= note: expected fn pointer `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
17+
found fn pointer `for<'a> fn(&'a u8, &'a u8) -> &'a u8`
18+
19+
error: aborting due to previous error
20+
21+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)