Skip to content

Commit

Permalink
Auto merge of #86164 - FabianWolff:issue-86053, r=davidtwco
Browse files Browse the repository at this point in the history
Handle C-variadic arguments properly when reporting region errors

This pull request fixes #86053. The issue is that for a C-variadic function
```rust
#![feature(c_variadic)]
unsafe extern "C" fn foo(_: (), ...) {}
```
`foo`'s signature will contain only the first parameter (and have `c_variadic` set to `true`), whereas its body has a second argument (a `hir::Pat` for the `...`).

The code for reporting region errors iterates over the body's parameters and tries to fetch the corresponding parameter from the signature; this causes an out-of-bounds ICE for the `...` (though not in the example above, because there are no region errors to report).

I have simply restricted the iteration over the body parameters to exclude `...`, which is fine because `...` cannot cause a region error.
  • Loading branch information
bors committed Jun 17, 2021
2 parents 50a4072 + 7dccce0 commit cb3c4ee
Show file tree
Hide file tree
Showing 10 changed files with 217 additions and 68 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ impl<'a> AstValidator<'a> {
self.err_handler()
.struct_span_err(
*span,
"only foreign or `unsafe extern \"C\" functions may be C-variadic",
"only foreign or `unsafe extern \"C\"` functions may be C-variadic",
)
.emit();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,33 +56,42 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap();
let poly_fn_sig = self.tcx().fn_sig(id);
let fn_sig = self.tcx().liberate_late_bound_regions(id, poly_fn_sig);
body.params.iter().enumerate().find_map(|(index, param)| {
// May return None; sometimes the tables are not yet populated.
let ty = fn_sig.inputs()[index];
let mut found_anon_region = false;
let new_param_ty = self.tcx().fold_regions(ty, &mut false, |r, _| {
if *r == *anon_region {
found_anon_region = true;
replace_region
body.params
.iter()
.take(if fn_sig.c_variadic {
fn_sig.inputs().len()
} else {
assert_eq!(fn_sig.inputs().len(), body.params.len());
body.params.len()
})
.enumerate()
.find_map(|(index, param)| {
// May return None; sometimes the tables are not yet populated.
let ty = fn_sig.inputs()[index];
let mut found_anon_region = false;
let new_param_ty = self.tcx().fold_regions(ty, &mut false, |r, _| {
if *r == *anon_region {
found_anon_region = true;
replace_region
} else {
r
}
});
if found_anon_region {
let ty_hir_id = fn_decl.inputs[index].hir_id;
let param_ty_span = hir.span(ty_hir_id);
let is_first = index == 0;
Some(AnonymousParamInfo {
param,
param_ty: new_param_ty,
param_ty_span,
bound_region,
is_first,
})
} else {
r
None
}
});
if found_anon_region {
let ty_hir_id = fn_decl.inputs[index].hir_id;
let param_ty_span = hir.span(ty_hir_id);
let is_first = index == 0;
Some(AnonymousParamInfo {
param,
param_ty: new_param_ty,
param_ty_span,
bound_region,
is_first,
})
} else {
None
}
})
})
}

pub(super) fn future_return_type(
Expand Down
12 changes: 12 additions & 0 deletions src/test/ui/c-variadic/issue-86053-1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Regression test for the ICE described in issue #86053.
// error-pattern:unexpected `self` parameter in function
// error-pattern:`...` must be the last argument of a C-variadic function
// error-pattern:cannot find type `F` in this scope
// error-pattern:in type `&'a &'b usize`, reference has a longer lifetime than the data it references

#![feature(c_variadic)]
#![crate_type="lib"]

fn ordering4 < 'a , 'b > ( a : , self , self , self ,
self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
}
101 changes: 101 additions & 0 deletions src/test/ui/c-variadic/issue-86053-1.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
error: expected type, found `,`
--> $DIR/issue-86053-1.rs:10:47
|
LL | fn ordering4 < 'a , 'b > ( a : , self , self , self ,
| ^ expected type

error: unexpected `self` parameter in function
--> $DIR/issue-86053-1.rs:10:51
|
LL | fn ordering4 < 'a , 'b > ( a : , self , self , self ,
| ^^^^ must be the first parameter of an associated function

error: unexpected `self` parameter in function
--> $DIR/issue-86053-1.rs:10:58
|
LL | fn ordering4 < 'a , 'b > ( a : , self , self , self ,
| ^^^^ must be the first parameter of an associated function

error: unexpected `self` parameter in function
--> $DIR/issue-86053-1.rs:10:67
|
LL | fn ordering4 < 'a , 'b > ( a : , self , self , self ,
| ^^^^ must be the first parameter of an associated function

error: unexpected `self` parameter in function
--> $DIR/issue-86053-1.rs:11:5
|
LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
| ^^^^ must be the first parameter of an associated function

error: unexpected `self` parameter in function
--> $DIR/issue-86053-1.rs:11:20
|
LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
| ^^^^ must be the first parameter of an associated function

error: unexpected `self` parameter in function
--> $DIR/issue-86053-1.rs:11:29
|
LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
| ^^^^ must be the first parameter of an associated function

error: `...` must be the last argument of a C-variadic function
--> $DIR/issue-86053-1.rs:11:12
|
LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
| ^^^^

error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/issue-86053-1.rs:11:12
|
LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
| ^^^^

error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/issue-86053-1.rs:11:36
|
LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
| ^^^^

error[E0412]: cannot find type `F` in this scope
--> $DIR/issue-86053-1.rs:11:48
|
LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
| ^
|
::: $SRC_DIR/core/src/ops/function.rs:LL:COL
|
LL | pub trait Fn<Args>: FnMut<Args> {
| ------------------------------- similarly named trait `Fn` defined here
|
help: a trait with a similar name exists
|
LL | self , ... , self , self , ... ) where Fn : FnOnce ( & 'a & 'b usize ) {
| ^^
help: you might be missing a type parameter
|
LL | fn ordering4 < 'a , 'b, F > ( a : , self , self , self ,
| ^^^

error[E0491]: in type `&'a &'b usize`, reference has a longer lifetime than the data it references
--> $DIR/issue-86053-1.rs:11:52
|
LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'a` as defined on the function body at 10:16
--> $DIR/issue-86053-1.rs:10:16
|
LL | fn ordering4 < 'a , 'b > ( a : , self , self , self ,
| ^^
note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 10:21
--> $DIR/issue-86053-1.rs:10:21
|
LL | fn ordering4 < 'a , 'b > ( a : , self , self , self ,
| ^^

error: aborting due to 12 previous errors

Some errors have detailed explanations: E0412, E0491.
For more information about an error, try `rustc --explain E0412`.
11 changes: 11 additions & 0 deletions src/test/ui/c-variadic/issue-86053-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Regression test for the ICE caused by the example in
// https://github.com/rust-lang/rust/issues/86053#issuecomment-855672258

#![feature(c_variadic)]

trait H<T> {}

unsafe extern "C" fn ordering4<'a, F: H<&'static &'a ()>>(_: (), ...) {}
//~^ ERROR: in type `&'static &'a ()`, reference has a longer lifetime than the data it references [E0491]

fn main() {}
16 changes: 16 additions & 0 deletions src/test/ui/c-variadic/issue-86053-2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error[E0491]: in type `&'static &'a ()`, reference has a longer lifetime than the data it references
--> $DIR/issue-86053-2.rs:8:39
|
LL | unsafe extern "C" fn ordering4<'a, F: H<&'static &'a ()>>(_: (), ...) {}
| ^^^^^^^^^^^^^^^^^^
|
= note: the pointer is valid for the static lifetime
note: but the referenced data is only valid for the lifetime `'a` as defined on the function body at 8:32
--> $DIR/issue-86053-2.rs:8:32
|
LL | unsafe extern "C" fn ordering4<'a, F: H<&'static &'a ()>>(_: (), ...) {}
| ^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0491`.
2 changes: 1 addition & 1 deletion src/test/ui/mir/issue-83499-input-output-iteration-ice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
fn main() {}

fn foo(_: Bar, ...) -> impl {}
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR cannot find type `Bar` in this scope
//~| ERROR at least one trait must be specified
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: only foreign or `unsafe extern "C" functions may be C-variadic
error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/issue-83499-input-output-iteration-ice.rs:7:16
|
LL | fn foo(_: Bar, ...) -> impl {}
Expand Down
40 changes: 20 additions & 20 deletions src/test/ui/parser/variadic-ffi-semantic-restrictions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,32 @@
fn main() {}

fn f1_1(x: isize, ...) {}
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic

fn f1_2(...) {}
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR C-variadic function must be declared with at least one named argument

extern "C" fn f2_1(x: isize, ...) {}
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic

extern "C" fn f2_2(...) {}
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR C-variadic function must be declared with at least one named argument

extern "C" fn f2_3(..., x: isize) {}
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR `...` must be the last argument of a C-variadic function

extern "C" fn f3_1(x: isize, ...) {}
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic

extern "C" fn f3_2(...) {}
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR C-variadic function must be declared with at least one named argument

extern "C" fn f3_3(..., x: isize) {}
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR `...` must be the last argument of a C-variadic function

extern "C" {
Expand All @@ -43,35 +43,35 @@ struct X;

impl X {
fn i_f1(x: isize, ...) {}
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
fn i_f2(...) {}
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR C-variadic function must be declared with at least one named argument
fn i_f3(..., x: isize, ...) {}
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~| ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR `...` must be the last argument of a C-variadic function
fn i_f4(..., x: isize, ...) {}
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~| ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR `...` must be the last argument of a C-variadic function
}

trait T {
fn t_f1(x: isize, ...) {}
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
fn t_f2(x: isize, ...);
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
fn t_f3(...) {}
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR C-variadic function must be declared with at least one named argument
fn t_f4(...);
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR C-variadic function must be declared with at least one named argument
fn t_f5(..., x: isize) {}
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR `...` must be the last argument of a C-variadic function
fn t_f6(..., x: isize);
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR `...` must be the last argument of a C-variadic function
}
Loading

0 comments on commit cb3c4ee

Please sign in to comment.