Rollup merge of #73323 - davidtwco:issue-73252-wfcheck-foreign-fn-decl, r=ecstatic-morse
wf: check foreign fn decls for well-formedness Fixes #73252 and fixes #73253. This PR extends current well-formedness checking to apply to foreign function declarations, re-using the existing machinery for regular functions. In doing this, later parts of the compiler (such as the `improper_ctypes` lint) can rely on being operations not failing as a result of invalid code which would normally be caught earlier.
This commit is contained in:
commit
0897bc2403
@ -15,7 +15,7 @@ use rustc_middle::ty::{
|
||||
self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
|
||||
};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::opaque_types::may_define_opaque_type;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
@ -142,8 +142,8 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
hir::ItemKind::Fn(..) => {
|
||||
check_item_fn(tcx, item);
|
||||
hir::ItemKind::Fn(ref sig, ..) => {
|
||||
check_item_fn(tcx, item.hir_id, item.ident, item.span, sig.decl);
|
||||
}
|
||||
hir::ItemKind::Static(ref ty, ..) => {
|
||||
check_item_type(tcx, item.hir_id, ty.span, false);
|
||||
@ -153,8 +153,14 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
}
|
||||
hir::ItemKind::ForeignMod(ref module) => {
|
||||
for it in module.items.iter() {
|
||||
if let hir::ForeignItemKind::Static(ref ty, ..) = it.kind {
|
||||
check_item_type(tcx, it.hir_id, ty.span, true);
|
||||
match it.kind {
|
||||
hir::ForeignItemKind::Fn(ref decl, ..) => {
|
||||
check_item_fn(tcx, it.hir_id, it.ident, it.span, decl)
|
||||
}
|
||||
hir::ForeignItemKind::Static(ref ty, ..) => {
|
||||
check_item_type(tcx, it.hir_id, ty.span, true)
|
||||
}
|
||||
hir::ForeignItemKind::Type => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -303,7 +309,7 @@ fn check_associated_item(
|
||||
fcx,
|
||||
item.ident.span,
|
||||
sig,
|
||||
hir_sig,
|
||||
hir_sig.decl,
|
||||
item.def_id,
|
||||
&mut implied_bounds,
|
||||
);
|
||||
@ -564,22 +570,24 @@ fn check_associated_type_defaults(fcx: &FnCtxt<'_, '_>, trait_def_id: DefId) {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_item_fn(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
|
||||
for_item(tcx, item).with_fcx(|fcx, tcx| {
|
||||
let def_id = fcx.tcx.hir().local_def_id(item.hir_id);
|
||||
fn check_item_fn(
|
||||
tcx: TyCtxt<'_>,
|
||||
item_id: hir::HirId,
|
||||
ident: Ident,
|
||||
span: Span,
|
||||
decl: &hir::FnDecl<'_>,
|
||||
) {
|
||||
for_id(tcx, item_id, span).with_fcx(|fcx, tcx| {
|
||||
let def_id = fcx.tcx.hir().local_def_id(item_id);
|
||||
let sig = fcx.tcx.fn_sig(def_id);
|
||||
let sig = fcx.normalize_associated_types_in(item.span, &sig);
|
||||
let sig = fcx.normalize_associated_types_in(span, &sig);
|
||||
let mut implied_bounds = vec![];
|
||||
let hir_sig = match &item.kind {
|
||||
ItemKind::Fn(sig, ..) => sig,
|
||||
_ => bug!("expected `ItemKind::Fn`, found `{:?}`", item.kind),
|
||||
};
|
||||
check_fn_or_method(
|
||||
tcx,
|
||||
fcx,
|
||||
item.ident.span,
|
||||
ident.span,
|
||||
sig,
|
||||
hir_sig,
|
||||
decl,
|
||||
def_id.to_def_id(),
|
||||
&mut implied_bounds,
|
||||
);
|
||||
@ -835,28 +843,28 @@ fn check_fn_or_method<'fcx, 'tcx>(
|
||||
fcx: &FnCtxt<'fcx, 'tcx>,
|
||||
span: Span,
|
||||
sig: ty::PolyFnSig<'tcx>,
|
||||
hir_sig: &hir::FnSig<'_>,
|
||||
hir_decl: &hir::FnDecl<'_>,
|
||||
def_id: DefId,
|
||||
implied_bounds: &mut Vec<Ty<'tcx>>,
|
||||
) {
|
||||
let sig = fcx.normalize_associated_types_in(span, &sig);
|
||||
let sig = fcx.tcx.liberate_late_bound_regions(def_id, &sig);
|
||||
|
||||
for (&input_ty, span) in sig.inputs().iter().zip(hir_sig.decl.inputs.iter().map(|t| t.span)) {
|
||||
for (&input_ty, span) in sig.inputs().iter().zip(hir_decl.inputs.iter().map(|t| t.span)) {
|
||||
fcx.register_wf_obligation(input_ty.into(), span, ObligationCauseCode::MiscObligation);
|
||||
}
|
||||
implied_bounds.extend(sig.inputs());
|
||||
|
||||
fcx.register_wf_obligation(
|
||||
sig.output().into(),
|
||||
hir_sig.decl.output.span(),
|
||||
hir_decl.output.span(),
|
||||
ObligationCauseCode::ReturnType,
|
||||
);
|
||||
|
||||
// FIXME(#25759) return types should not be implied bounds
|
||||
implied_bounds.push(sig.output());
|
||||
|
||||
check_where_clauses(tcx, fcx, span, def_id, Some((sig.output(), hir_sig.decl.output.span())));
|
||||
check_where_clauses(tcx, fcx, span, def_id, Some((sig.output(), hir_decl.output.span())));
|
||||
}
|
||||
|
||||
/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions
|
||||
|
@ -7,6 +7,7 @@ extern crate libc;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
trait Bar { }
|
||||
trait Mirror { type It: ?Sized; }
|
||||
impl<T: ?Sized> Mirror for T { type It = Self; }
|
||||
#[repr(C)]
|
||||
@ -53,7 +54,7 @@ extern {
|
||||
pub fn char_type(p: char); //~ ERROR uses type `char`
|
||||
pub fn i128_type(p: i128); //~ ERROR uses type `i128`
|
||||
pub fn u128_type(p: u128); //~ ERROR uses type `u128`
|
||||
pub fn trait_type(p: &dyn Clone); //~ ERROR uses type `dyn std::clone::Clone`
|
||||
pub fn trait_type(p: &dyn Bar); //~ ERROR uses type `dyn Bar`
|
||||
pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)`
|
||||
pub fn tuple_type2(p: I32Pair); //~ ERROR uses type `(i32, i32)`
|
||||
pub fn zero_size(p: ZeroSize); //~ ERROR uses type `ZeroSize`
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: `extern` block uses type `Foo`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:46:28
|
||||
--> $DIR/lint-ctypes.rs:47:28
|
||||
|
|
||||
LL | pub fn ptr_type1(size: *const Foo);
|
||||
| ^^^^^^^^^^ not FFI-safe
|
||||
@ -12,13 +12,13 @@ LL | #![deny(improper_ctypes)]
|
||||
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
|
||||
= note: this struct has unspecified layout
|
||||
note: the type is defined here
|
||||
--> $DIR/lint-ctypes.rs:24:1
|
||||
--> $DIR/lint-ctypes.rs:25:1
|
||||
|
|
||||
LL | pub struct Foo;
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: `extern` block uses type `Foo`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:47:28
|
||||
--> $DIR/lint-ctypes.rs:48:28
|
||||
|
|
||||
LL | pub fn ptr_type2(size: *const Foo);
|
||||
| ^^^^^^^^^^ not FFI-safe
|
||||
@ -26,13 +26,13 @@ LL | pub fn ptr_type2(size: *const Foo);
|
||||
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
|
||||
= note: this struct has unspecified layout
|
||||
note: the type is defined here
|
||||
--> $DIR/lint-ctypes.rs:24:1
|
||||
--> $DIR/lint-ctypes.rs:25:1
|
||||
|
|
||||
LL | pub struct Foo;
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: `extern` block uses type `[u32]`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:48:26
|
||||
--> $DIR/lint-ctypes.rs:49:26
|
||||
|
|
||||
LL | pub fn slice_type(p: &[u32]);
|
||||
| ^^^^^^ not FFI-safe
|
||||
@ -41,7 +41,7 @@ LL | pub fn slice_type(p: &[u32]);
|
||||
= note: slices have no C equivalent
|
||||
|
||||
error: `extern` block uses type `str`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:49:24
|
||||
--> $DIR/lint-ctypes.rs:50:24
|
||||
|
|
||||
LL | pub fn str_type(p: &str);
|
||||
| ^^^^ not FFI-safe
|
||||
@ -50,7 +50,7 @@ LL | pub fn str_type(p: &str);
|
||||
= note: string slices have no C equivalent
|
||||
|
||||
error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:50:24
|
||||
--> $DIR/lint-ctypes.rs:51:24
|
||||
|
|
||||
LL | pub fn box_type(p: Box<u32>);
|
||||
| ^^^^^^^^ not FFI-safe
|
||||
@ -59,7 +59,7 @@ LL | pub fn box_type(p: Box<u32>);
|
||||
= note: this struct has unspecified layout
|
||||
|
||||
error: `extern` block uses type `std::option::Option<std::boxed::Box<u32>>`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:51:28
|
||||
--> $DIR/lint-ctypes.rs:52:28
|
||||
|
|
||||
LL | pub fn opt_box_type(p: Option<Box<u32>>);
|
||||
| ^^^^^^^^^^^^^^^^ not FFI-safe
|
||||
@ -68,7 +68,7 @@ LL | pub fn opt_box_type(p: Option<Box<u32>>);
|
||||
= note: enum has no representation hint
|
||||
|
||||
error: `extern` block uses type `char`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:53:25
|
||||
--> $DIR/lint-ctypes.rs:54:25
|
||||
|
|
||||
LL | pub fn char_type(p: char);
|
||||
| ^^^^ not FFI-safe
|
||||
@ -77,7 +77,7 @@ LL | pub fn char_type(p: char);
|
||||
= note: the `char` type has no C equivalent
|
||||
|
||||
error: `extern` block uses type `i128`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:54:25
|
||||
--> $DIR/lint-ctypes.rs:55:25
|
||||
|
|
||||
LL | pub fn i128_type(p: i128);
|
||||
| ^^^^ not FFI-safe
|
||||
@ -85,23 +85,23 @@ LL | pub fn i128_type(p: i128);
|
||||
= note: 128-bit integers don't currently have a known stable ABI
|
||||
|
||||
error: `extern` block uses type `u128`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:55:25
|
||||
--> $DIR/lint-ctypes.rs:56:25
|
||||
|
|
||||
LL | pub fn u128_type(p: u128);
|
||||
| ^^^^ not FFI-safe
|
||||
|
|
||||
= note: 128-bit integers don't currently have a known stable ABI
|
||||
|
||||
error: `extern` block uses type `dyn std::clone::Clone`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:56:26
|
||||
error: `extern` block uses type `dyn Bar`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:57:26
|
||||
|
|
||||
LL | pub fn trait_type(p: &dyn Clone);
|
||||
| ^^^^^^^^^^ not FFI-safe
|
||||
LL | pub fn trait_type(p: &dyn Bar);
|
||||
| ^^^^^^^^ not FFI-safe
|
||||
|
|
||||
= note: trait objects have no C equivalent
|
||||
|
||||
error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:57:26
|
||||
--> $DIR/lint-ctypes.rs:58:26
|
||||
|
|
||||
LL | pub fn tuple_type(p: (i32, i32));
|
||||
| ^^^^^^^^^^ not FFI-safe
|
||||
@ -110,7 +110,7 @@ LL | pub fn tuple_type(p: (i32, i32));
|
||||
= note: tuples have unspecified layout
|
||||
|
||||
error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:58:27
|
||||
--> $DIR/lint-ctypes.rs:59:27
|
||||
|
|
||||
LL | pub fn tuple_type2(p: I32Pair);
|
||||
| ^^^^^^^ not FFI-safe
|
||||
@ -119,7 +119,7 @@ LL | pub fn tuple_type2(p: I32Pair);
|
||||
= note: tuples have unspecified layout
|
||||
|
||||
error: `extern` block uses type `ZeroSize`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:59:25
|
||||
--> $DIR/lint-ctypes.rs:60:25
|
||||
|
|
||||
LL | pub fn zero_size(p: ZeroSize);
|
||||
| ^^^^^^^^ not FFI-safe
|
||||
@ -127,26 +127,26 @@ LL | pub fn zero_size(p: ZeroSize);
|
||||
= help: consider adding a member to this struct
|
||||
= note: this struct has no fields
|
||||
note: the type is defined here
|
||||
--> $DIR/lint-ctypes.rs:20:1
|
||||
--> $DIR/lint-ctypes.rs:21:1
|
||||
|
|
||||
LL | pub struct ZeroSize;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:60:33
|
||||
--> $DIR/lint-ctypes.rs:61:33
|
||||
|
|
||||
LL | pub fn zero_size_phantom(p: ZeroSizeWithPhantomData);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
||||
|
|
||||
= note: composed only of `PhantomData`
|
||||
note: the type is defined here
|
||||
--> $DIR/lint-ctypes.rs:43:1
|
||||
--> $DIR/lint-ctypes.rs:44:1
|
||||
|
|
||||
LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `extern` block uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:63:12
|
||||
--> $DIR/lint-ctypes.rs:64:12
|
||||
|
|
||||
LL | -> ::std::marker::PhantomData<bool>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
||||
@ -154,7 +154,7 @@ LL | -> ::std::marker::PhantomData<bool>;
|
||||
= note: composed only of `PhantomData`
|
||||
|
||||
error: `extern` block uses type `fn()`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:64:23
|
||||
--> $DIR/lint-ctypes.rs:65:23
|
||||
|
|
||||
LL | pub fn fn_type(p: RustFn);
|
||||
| ^^^^^^ not FFI-safe
|
||||
@ -163,7 +163,7 @@ LL | pub fn fn_type(p: RustFn);
|
||||
= note: this function pointer has Rust-specific calling convention
|
||||
|
||||
error: `extern` block uses type `fn()`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:65:24
|
||||
--> $DIR/lint-ctypes.rs:66:24
|
||||
|
|
||||
LL | pub fn fn_type2(p: fn());
|
||||
| ^^^^ not FFI-safe
|
||||
@ -172,7 +172,7 @@ LL | pub fn fn_type2(p: fn());
|
||||
= note: this function pointer has Rust-specific calling convention
|
||||
|
||||
error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:66:28
|
||||
--> $DIR/lint-ctypes.rs:67:28
|
||||
|
|
||||
LL | pub fn fn_contained(p: RustBadRet);
|
||||
| ^^^^^^^^^^ not FFI-safe
|
||||
@ -181,7 +181,7 @@ LL | pub fn fn_contained(p: RustBadRet);
|
||||
= note: this struct has unspecified layout
|
||||
|
||||
error: `extern` block uses type `i128`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:67:32
|
||||
--> $DIR/lint-ctypes.rs:68:32
|
||||
|
|
||||
LL | pub fn transparent_i128(p: TransparentI128);
|
||||
| ^^^^^^^^^^^^^^^ not FFI-safe
|
||||
@ -189,7 +189,7 @@ LL | pub fn transparent_i128(p: TransparentI128);
|
||||
= note: 128-bit integers don't currently have a known stable ABI
|
||||
|
||||
error: `extern` block uses type `str`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:68:31
|
||||
--> $DIR/lint-ctypes.rs:69:31
|
||||
|
|
||||
LL | pub fn transparent_str(p: TransparentStr);
|
||||
| ^^^^^^^^^^^^^^ not FFI-safe
|
||||
@ -198,7 +198,7 @@ LL | pub fn transparent_str(p: TransparentStr);
|
||||
= note: string slices have no C equivalent
|
||||
|
||||
error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:69:30
|
||||
--> $DIR/lint-ctypes.rs:70:30
|
||||
|
|
||||
LL | pub fn transparent_fn(p: TransparentBadFn);
|
||||
| ^^^^^^^^^^^^^^^^ not FFI-safe
|
||||
@ -207,7 +207,7 @@ LL | pub fn transparent_fn(p: TransparentBadFn);
|
||||
= note: this struct has unspecified layout
|
||||
|
||||
error: `extern` block uses type `[u8; 8]`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:70:27
|
||||
--> $DIR/lint-ctypes.rs:71:27
|
||||
|
|
||||
LL | pub fn raw_array(arr: [u8; 8]);
|
||||
| ^^^^^^^ not FFI-safe
|
||||
@ -216,7 +216,7 @@ LL | pub fn raw_array(arr: [u8; 8]);
|
||||
= note: passing raw arrays by value is not FFI-safe
|
||||
|
||||
error: `extern` block uses type `u128`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:72:34
|
||||
--> $DIR/lint-ctypes.rs:73:34
|
||||
|
|
||||
LL | pub static static_u128_type: u128;
|
||||
| ^^^^ not FFI-safe
|
||||
@ -224,7 +224,7 @@ LL | pub static static_u128_type: u128;
|
||||
= note: 128-bit integers don't currently have a known stable ABI
|
||||
|
||||
error: `extern` block uses type `u128`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes.rs:73:40
|
||||
--> $DIR/lint-ctypes.rs:74:40
|
||||
|
|
||||
LL | pub static static_u128_array_type: [u128; 16];
|
||||
| ^^^^^^^^^^ not FFI-safe
|
||||
|
18
src/test/ui/wf/wf-foreign-fn-decl-ret.rs
Normal file
18
src/test/ui/wf/wf-foreign-fn-decl-ret.rs
Normal file
@ -0,0 +1,18 @@
|
||||
pub trait Unsatisfied {}
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct Bar<T: Unsatisfied>(T);
|
||||
|
||||
pub trait Foo {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn lint_me() -> <() as Foo>::Assoc;
|
||||
//~^ ERROR: the trait bound `(): Foo` is not satisfied [E0277]
|
||||
|
||||
pub fn lint_me_aswell() -> Bar<u32>;
|
||||
//~^ ERROR: the trait bound `u32: Unsatisfied` is not satisfied [E0277]
|
||||
}
|
||||
|
||||
fn main() {}
|
18
src/test/ui/wf/wf-foreign-fn-decl-ret.stderr
Normal file
18
src/test/ui/wf/wf-foreign-fn-decl-ret.stderr
Normal file
@ -0,0 +1,18 @@
|
||||
error[E0277]: the trait bound `(): Foo` is not satisfied
|
||||
--> $DIR/wf-foreign-fn-decl-ret.rs:11:5
|
||||
|
|
||||
LL | pub fn lint_me() -> <() as Foo>::Assoc;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
|
||||
|
||||
error[E0277]: the trait bound `u32: Unsatisfied` is not satisfied
|
||||
--> $DIR/wf-foreign-fn-decl-ret.rs:14:32
|
||||
|
|
||||
LL | pub struct Bar<T: Unsatisfied>(T);
|
||||
| ----------- required by this bound in `Bar`
|
||||
...
|
||||
LL | pub fn lint_me_aswell() -> Bar<u32>;
|
||||
| ^^^^^^^^ the trait `Unsatisfied` is not implemented for `u32`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
x
Reference in New Issue
Block a user