Skip to content

Commit d681dda

Browse files
authored
Rollup merge of rust-lang#144915 - compiler-errors:tail-call-ret-ty-equality, r=WaffleLapkin,lcnr
Defer tail call ret ty equality to check_tail_calls Fixes rust-lang#144892. Currently the tail call signature check assumes that return types have been accounted for. However, this is not complete for several reasons. Firstly, we were using subtyping instead of equality in the HIR typeck code: https://github.com/rust-lang/rust/blob/e1b9081e699065badfc1a9419ec9566e5c8615c4/compiler/rustc_hir_typeck/src/expr.rs#L1096 We could fix this, but it doesn't really do much for us anyways since HIR typeck doesn't care about regions. That means, secondly, we'd need to fix the terminator type check in MIR typeck to account for variances, since tail call terminators need to relate their arguments invariantly to account for the "signature must be equal" rule. This seems annoying. All of this seems like a lot of work, and we already are *manually* checking argument equality. Let's just extend the `check_tail_calls` to account for mismatches in return types anyways. r? `````@WaffleLapkin`````
2 parents c38b2c9 + 6a088fd commit d681dda

File tree

5 files changed

+61
-25
lines changed

5 files changed

+61
-25
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1895,7 +1895,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
18951895
if !output_ty
18961896
.is_privately_uninhabited(self.tcx(), self.infcx.typing_env(self.infcx.param_env))
18971897
{
1898-
span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
1898+
span_mirbug!(self, term, "call to non-diverging function {:?} w/o dest", sig);
18991899
}
19001900
} else {
19011901
let dest_ty = destination.ty(self.body, tcx).ty;

compiler/rustc_mir_build/src/check_tail_calls.rs

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -135,30 +135,23 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
135135
self.report_abi_mismatch(expr.span, caller_sig.abi, callee_sig.abi);
136136
}
137137

138+
// FIXME(explicit_tail_calls): this currently fails for cases where opaques are used.
139+
// e.g.
140+
// ```
141+
// fn a() -> impl Sized { become b() } // ICE
142+
// fn b() -> u8 { 0 }
143+
// ```
144+
// we should think what is the expected behavior here.
145+
// (we should probably just accept this by revealing opaques?)
138146
if caller_sig.inputs_and_output != callee_sig.inputs_and_output {
139-
if caller_sig.inputs() != callee_sig.inputs() {
140-
self.report_arguments_mismatch(
141-
expr.span,
142-
self.tcx.liberate_late_bound_regions(
143-
CRATE_DEF_ID.to_def_id(),
144-
self.caller_ty.fn_sig(self.tcx),
145-
),
146-
self.tcx
147-
.liberate_late_bound_regions(CRATE_DEF_ID.to_def_id(), ty.fn_sig(self.tcx)),
148-
);
149-
}
150-
151-
// FIXME(explicit_tail_calls): this currently fails for cases where opaques are used.
152-
// e.g.
153-
// ```
154-
// fn a() -> impl Sized { become b() } // ICE
155-
// fn b() -> u8 { 0 }
156-
// ```
157-
// we should think what is the expected behavior here.
158-
// (we should probably just accept this by revealing opaques?)
159-
if caller_sig.output() != callee_sig.output() {
160-
span_bug!(expr.span, "hir typeck should have checked the return type already");
161-
}
147+
self.report_signature_mismatch(
148+
expr.span,
149+
self.tcx.liberate_late_bound_regions(
150+
CRATE_DEF_ID.to_def_id(),
151+
self.caller_ty.fn_sig(self.tcx),
152+
),
153+
self.tcx.liberate_late_bound_regions(CRATE_DEF_ID.to_def_id(), ty.fn_sig(self.tcx)),
154+
);
162155
}
163156

164157
{
@@ -365,7 +358,7 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> {
365358
self.found_errors = Err(err);
366359
}
367360

368-
fn report_arguments_mismatch(
361+
fn report_signature_mismatch(
369362
&mut self,
370363
sp: Span,
371364
caller_sig: ty::FnSig<'_>,
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![feature(explicit_tail_calls)]
2+
#![expect(incomplete_features)]
3+
4+
fn foo() -> for<'a> fn(&'a i32) {
5+
become bar();
6+
//~^ ERROR mismatched signatures
7+
}
8+
9+
fn bar() -> fn(&'static i32) {
10+
dummy
11+
}
12+
13+
fn dummy(_: &i32) {}
14+
15+
fn main() {}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error: mismatched signatures
2+
--> $DIR/ret-ty-hr-mismatch.rs:5:5
3+
|
4+
LL | become bar();
5+
| ^^^^^^^^^^^^
6+
|
7+
= note: `become` requires caller and callee to have matching signatures
8+
= note: caller signature: `fn() -> for<'a> fn(&'a i32)`
9+
= note: callee signature: `fn() -> fn(&'static i32)`
10+
11+
error: aborting due to 1 previous error
12+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Ensure that we anonymize the output of a function for tail call signature compatibility.
2+
3+
//@ check-pass
4+
5+
#![feature(explicit_tail_calls)]
6+
#![expect(incomplete_features)]
7+
8+
fn foo() -> for<'a> fn(&'a ()) {
9+
become bar();
10+
}
11+
12+
fn bar() -> for<'b> fn(&'b ()) {
13+
todo!()
14+
}
15+
16+
fn main() {}

0 commit comments

Comments
 (0)