Rollup merge of #130437 - jder:issue-130372, r=compiler-errors

Avoid crashing on variadic functions when producing arg-mismatch errors

Fixes #130372 by accommodating how variadic functions change the argument list length between HIR body and FnDecls.

Also degrades the zip_eq to a debug_assert! to match other asserts in the area to avoid being disruptive to users. There is at least one other crash in this area I am working on in #130400 and also considering how we might refactor some of this code to hoist some of this logic up higher.

r? `@compiler-errors`
This commit is contained in:
Matthias Krüger 2024-09-16 21:53:07 +02:00 committed by GitHub
commit 14ee69c250
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 44 additions and 31 deletions

View File

@ -2619,9 +2619,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
is_method: bool,
) -> Option<Vec<(Option<&hir::GenericParam<'_>>, &hir::Param<'_>)>> {
let fn_node = self.tcx.hir().get_if_local(def_id)?;
let fn_decl = fn_node.fn_decl()?;
let generic_params: Vec<Option<&hir::GenericParam<'_>>> = fn_node
.fn_decl()?
let generic_params: Vec<Option<&hir::GenericParam<'_>>> = fn_decl
.inputs
.into_iter()
.skip(if is_method { 1 } else { 0 })
@ -2642,7 +2642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
})
.collect();
let params: Vec<&hir::Param<'_>> = self
let mut params: Vec<&hir::Param<'_>> = self
.tcx
.hir()
.body(fn_node.body_id()?)
@ -2651,7 +2651,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.skip(if is_method { 1 } else { 0 })
.collect();
Some(generic_params.into_iter().zip_eq(params).collect())
// The surrounding code expects variadic functions to not have a parameter representing
// the "..." parameter. This is already true of the FnDecl but not of the body params, so
// we drop it if it exists.
if fn_decl.c_variadic {
params.pop();
}
debug_assert_eq!(params.len(), generic_params.len());
Some(generic_params.into_iter().zip(params).collect())
}
}

View File

@ -1,9 +0,0 @@
//@ known-bug: rust-lang/rust#130372
pub fn variadic_fn(n: usize, mut args: ...) {}
reuse variadic_fn;
fn main() {
variadic_fn();
}

View File

@ -1,11 +0,0 @@
//@ known-bug: rust-lang/rust#130372
pub fn test_va_copy(_: u64, mut ap: ...) {}
pub fn main() {
unsafe {
test_va_copy();
call(x);
}
}

View File

@ -1,7 +0,0 @@
//@ known-bug: rust-lang/rust#130372
fn bar() -> impl Fn() {
wrap()
}
fn wrap(...: impl ...) -> impl Fn() {}

View File

@ -0,0 +1,12 @@
#![feature(c_variadic)]
// Regression test that covers all 3 cases of https://github.com/rust-lang/rust/issues/130372
unsafe extern "C" fn test_va_copy(_: u64, mut ap: ...) {}
pub fn main() {
unsafe {
test_va_copy();
//~^ ERROR this function takes at least 1 argument but 0 arguments were supplied
}
}

View File

@ -0,0 +1,19 @@
error[E0060]: this function takes at least 1 argument but 0 arguments were supplied
--> $DIR/mismatch-args-vargs-issue-130372.rs:9:9
|
LL | test_va_copy();
| ^^^^^^^^^^^^-- argument #1 of type `u64` is missing
|
note: function defined here
--> $DIR/mismatch-args-vargs-issue-130372.rs:5:22
|
LL | unsafe extern "C" fn test_va_copy(_: u64, mut ap: ...) {}
| ^^^^^^^^^^^^ ------
help: provide the argument
|
LL | test_va_copy(/* u64 */);
| ~~~~~~~~~~~
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0060`.