Skip to content

Commit 0897bc2

Browse files
authored
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.
2 parents 241374a + ceac273 commit 0897bc2

File tree

5 files changed

+97
-52
lines changed

5 files changed

+97
-52
lines changed

src/librustc_typeck/check/wfcheck.rs

+28-20
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_middle::ty::{
1515
self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
1616
};
1717
use rustc_session::parse::feature_err;
18-
use rustc_span::symbol::{sym, Symbol};
18+
use rustc_span::symbol::{sym, Ident, Symbol};
1919
use rustc_span::Span;
2020
use rustc_trait_selection::opaque_types::may_define_opaque_type;
2121
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@@ -142,8 +142,8 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
142142
_ => unreachable!(),
143143
}
144144
}
145-
hir::ItemKind::Fn(..) => {
146-
check_item_fn(tcx, item);
145+
hir::ItemKind::Fn(ref sig, ..) => {
146+
check_item_fn(tcx, item.hir_id, item.ident, item.span, sig.decl);
147147
}
148148
hir::ItemKind::Static(ref ty, ..) => {
149149
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) {
153153
}
154154
hir::ItemKind::ForeignMod(ref module) => {
155155
for it in module.items.iter() {
156-
if let hir::ForeignItemKind::Static(ref ty, ..) = it.kind {
157-
check_item_type(tcx, it.hir_id, ty.span, true);
156+
match it.kind {
157+
hir::ForeignItemKind::Fn(ref decl, ..) => {
158+
check_item_fn(tcx, it.hir_id, it.ident, it.span, decl)
159+
}
160+
hir::ForeignItemKind::Static(ref ty, ..) => {
161+
check_item_type(tcx, it.hir_id, ty.span, true)
162+
}
163+
hir::ForeignItemKind::Type => (),
158164
}
159165
}
160166
}
@@ -303,7 +309,7 @@ fn check_associated_item(
303309
fcx,
304310
item.ident.span,
305311
sig,
306-
hir_sig,
312+
hir_sig.decl,
307313
item.def_id,
308314
&mut implied_bounds,
309315
);
@@ -564,22 +570,24 @@ fn check_associated_type_defaults(fcx: &FnCtxt<'_, '_>, trait_def_id: DefId) {
564570
}
565571
}
566572

567-
fn check_item_fn(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
568-
for_item(tcx, item).with_fcx(|fcx, tcx| {
569-
let def_id = fcx.tcx.hir().local_def_id(item.hir_id);
573+
fn check_item_fn(
574+
tcx: TyCtxt<'_>,
575+
item_id: hir::HirId,
576+
ident: Ident,
577+
span: Span,
578+
decl: &hir::FnDecl<'_>,
579+
) {
580+
for_id(tcx, item_id, span).with_fcx(|fcx, tcx| {
581+
let def_id = fcx.tcx.hir().local_def_id(item_id);
570582
let sig = fcx.tcx.fn_sig(def_id);
571-
let sig = fcx.normalize_associated_types_in(item.span, &sig);
583+
let sig = fcx.normalize_associated_types_in(span, &sig);
572584
let mut implied_bounds = vec![];
573-
let hir_sig = match &item.kind {
574-
ItemKind::Fn(sig, ..) => sig,
575-
_ => bug!("expected `ItemKind::Fn`, found `{:?}`", item.kind),
576-
};
577585
check_fn_or_method(
578586
tcx,
579587
fcx,
580-
item.ident.span,
588+
ident.span,
581589
sig,
582-
hir_sig,
590+
decl,
583591
def_id.to_def_id(),
584592
&mut implied_bounds,
585593
);
@@ -835,28 +843,28 @@ fn check_fn_or_method<'fcx, 'tcx>(
835843
fcx: &FnCtxt<'fcx, 'tcx>,
836844
span: Span,
837845
sig: ty::PolyFnSig<'tcx>,
838-
hir_sig: &hir::FnSig<'_>,
846+
hir_decl: &hir::FnDecl<'_>,
839847
def_id: DefId,
840848
implied_bounds: &mut Vec<Ty<'tcx>>,
841849
) {
842850
let sig = fcx.normalize_associated_types_in(span, &sig);
843851
let sig = fcx.tcx.liberate_late_bound_regions(def_id, &sig);
844852

845-
for (&input_ty, span) in sig.inputs().iter().zip(hir_sig.decl.inputs.iter().map(|t| t.span)) {
853+
for (&input_ty, span) in sig.inputs().iter().zip(hir_decl.inputs.iter().map(|t| t.span)) {
846854
fcx.register_wf_obligation(input_ty.into(), span, ObligationCauseCode::MiscObligation);
847855
}
848856
implied_bounds.extend(sig.inputs());
849857

850858
fcx.register_wf_obligation(
851859
sig.output().into(),
852-
hir_sig.decl.output.span(),
860+
hir_decl.output.span(),
853861
ObligationCauseCode::ReturnType,
854862
);
855863

856864
// FIXME(#25759) return types should not be implied bounds
857865
implied_bounds.push(sig.output());
858866

859-
check_where_clauses(tcx, fcx, span, def_id, Some((sig.output(), hir_sig.decl.output.span())));
867+
check_where_clauses(tcx, fcx, span, def_id, Some((sig.output(), hir_decl.output.span())));
860868
}
861869

862870
/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions

src/test/ui/lint/lint-ctypes.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ extern crate libc;
77

88
use std::marker::PhantomData;
99

10+
trait Bar { }
1011
trait Mirror { type It: ?Sized; }
1112
impl<T: ?Sized> Mirror for T { type It = Self; }
1213
#[repr(C)]
@@ -53,7 +54,7 @@ extern {
5354
pub fn char_type(p: char); //~ ERROR uses type `char`
5455
pub fn i128_type(p: i128); //~ ERROR uses type `i128`
5556
pub fn u128_type(p: u128); //~ ERROR uses type `u128`
56-
pub fn trait_type(p: &dyn Clone); //~ ERROR uses type `dyn std::clone::Clone`
57+
pub fn trait_type(p: &dyn Bar); //~ ERROR uses type `dyn Bar`
5758
pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)`
5859
pub fn tuple_type2(p: I32Pair); //~ ERROR uses type `(i32, i32)`
5960
pub fn zero_size(p: ZeroSize); //~ ERROR uses type `ZeroSize`

src/test/ui/lint/lint-ctypes.stderr

+31-31
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: `extern` block uses type `Foo`, which is not FFI-safe
2-
--> $DIR/lint-ctypes.rs:46:28
2+
--> $DIR/lint-ctypes.rs:47:28
33
|
44
LL | pub fn ptr_type1(size: *const Foo);
55
| ^^^^^^^^^^ not FFI-safe
@@ -12,27 +12,27 @@ LL | #![deny(improper_ctypes)]
1212
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
1313
= note: this struct has unspecified layout
1414
note: the type is defined here
15-
--> $DIR/lint-ctypes.rs:24:1
15+
--> $DIR/lint-ctypes.rs:25:1
1616
|
1717
LL | pub struct Foo;
1818
| ^^^^^^^^^^^^^^^
1919

2020
error: `extern` block uses type `Foo`, which is not FFI-safe
21-
--> $DIR/lint-ctypes.rs:47:28
21+
--> $DIR/lint-ctypes.rs:48:28
2222
|
2323
LL | pub fn ptr_type2(size: *const Foo);
2424
| ^^^^^^^^^^ not FFI-safe
2525
|
2626
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
2727
= note: this struct has unspecified layout
2828
note: the type is defined here
29-
--> $DIR/lint-ctypes.rs:24:1
29+
--> $DIR/lint-ctypes.rs:25:1
3030
|
3131
LL | pub struct Foo;
3232
| ^^^^^^^^^^^^^^^
3333

3434
error: `extern` block uses type `[u32]`, which is not FFI-safe
35-
--> $DIR/lint-ctypes.rs:48:26
35+
--> $DIR/lint-ctypes.rs:49:26
3636
|
3737
LL | pub fn slice_type(p: &[u32]);
3838
| ^^^^^^ not FFI-safe
@@ -41,7 +41,7 @@ LL | pub fn slice_type(p: &[u32]);
4141
= note: slices have no C equivalent
4242

4343
error: `extern` block uses type `str`, which is not FFI-safe
44-
--> $DIR/lint-ctypes.rs:49:24
44+
--> $DIR/lint-ctypes.rs:50:24
4545
|
4646
LL | pub fn str_type(p: &str);
4747
| ^^^^ not FFI-safe
@@ -50,7 +50,7 @@ LL | pub fn str_type(p: &str);
5050
= note: string slices have no C equivalent
5151

5252
error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe
53-
--> $DIR/lint-ctypes.rs:50:24
53+
--> $DIR/lint-ctypes.rs:51:24
5454
|
5555
LL | pub fn box_type(p: Box<u32>);
5656
| ^^^^^^^^ not FFI-safe
@@ -59,7 +59,7 @@ LL | pub fn box_type(p: Box<u32>);
5959
= note: this struct has unspecified layout
6060

6161
error: `extern` block uses type `std::option::Option<std::boxed::Box<u32>>`, which is not FFI-safe
62-
--> $DIR/lint-ctypes.rs:51:28
62+
--> $DIR/lint-ctypes.rs:52:28
6363
|
6464
LL | pub fn opt_box_type(p: Option<Box<u32>>);
6565
| ^^^^^^^^^^^^^^^^ not FFI-safe
@@ -68,7 +68,7 @@ LL | pub fn opt_box_type(p: Option<Box<u32>>);
6868
= note: enum has no representation hint
6969

7070
error: `extern` block uses type `char`, which is not FFI-safe
71-
--> $DIR/lint-ctypes.rs:53:25
71+
--> $DIR/lint-ctypes.rs:54:25
7272
|
7373
LL | pub fn char_type(p: char);
7474
| ^^^^ not FFI-safe
@@ -77,31 +77,31 @@ LL | pub fn char_type(p: char);
7777
= note: the `char` type has no C equivalent
7878

7979
error: `extern` block uses type `i128`, which is not FFI-safe
80-
--> $DIR/lint-ctypes.rs:54:25
80+
--> $DIR/lint-ctypes.rs:55:25
8181
|
8282
LL | pub fn i128_type(p: i128);
8383
| ^^^^ not FFI-safe
8484
|
8585
= note: 128-bit integers don't currently have a known stable ABI
8686

8787
error: `extern` block uses type `u128`, which is not FFI-safe
88-
--> $DIR/lint-ctypes.rs:55:25
88+
--> $DIR/lint-ctypes.rs:56:25
8989
|
9090
LL | pub fn u128_type(p: u128);
9191
| ^^^^ not FFI-safe
9292
|
9393
= note: 128-bit integers don't currently have a known stable ABI
9494

95-
error: `extern` block uses type `dyn std::clone::Clone`, which is not FFI-safe
96-
--> $DIR/lint-ctypes.rs:56:26
95+
error: `extern` block uses type `dyn Bar`, which is not FFI-safe
96+
--> $DIR/lint-ctypes.rs:57:26
9797
|
98-
LL | pub fn trait_type(p: &dyn Clone);
99-
| ^^^^^^^^^^ not FFI-safe
98+
LL | pub fn trait_type(p: &dyn Bar);
99+
| ^^^^^^^^ not FFI-safe
100100
|
101101
= note: trait objects have no C equivalent
102102

103103
error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
104-
--> $DIR/lint-ctypes.rs:57:26
104+
--> $DIR/lint-ctypes.rs:58:26
105105
|
106106
LL | pub fn tuple_type(p: (i32, i32));
107107
| ^^^^^^^^^^ not FFI-safe
@@ -110,7 +110,7 @@ LL | pub fn tuple_type(p: (i32, i32));
110110
= note: tuples have unspecified layout
111111

112112
error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
113-
--> $DIR/lint-ctypes.rs:58:27
113+
--> $DIR/lint-ctypes.rs:59:27
114114
|
115115
LL | pub fn tuple_type2(p: I32Pair);
116116
| ^^^^^^^ not FFI-safe
@@ -119,42 +119,42 @@ LL | pub fn tuple_type2(p: I32Pair);
119119
= note: tuples have unspecified layout
120120

121121
error: `extern` block uses type `ZeroSize`, which is not FFI-safe
122-
--> $DIR/lint-ctypes.rs:59:25
122+
--> $DIR/lint-ctypes.rs:60:25
123123
|
124124
LL | pub fn zero_size(p: ZeroSize);
125125
| ^^^^^^^^ not FFI-safe
126126
|
127127
= help: consider adding a member to this struct
128128
= note: this struct has no fields
129129
note: the type is defined here
130-
--> $DIR/lint-ctypes.rs:20:1
130+
--> $DIR/lint-ctypes.rs:21:1
131131
|
132132
LL | pub struct ZeroSize;
133133
| ^^^^^^^^^^^^^^^^^^^^
134134

135135
error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
136-
--> $DIR/lint-ctypes.rs:60:33
136+
--> $DIR/lint-ctypes.rs:61:33
137137
|
138138
LL | pub fn zero_size_phantom(p: ZeroSizeWithPhantomData);
139139
| ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
140140
|
141141
= note: composed only of `PhantomData`
142142
note: the type is defined here
143-
--> $DIR/lint-ctypes.rs:43:1
143+
--> $DIR/lint-ctypes.rs:44:1
144144
|
145145
LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>);
146146
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
147147

148148
error: `extern` block uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
149-
--> $DIR/lint-ctypes.rs:63:12
149+
--> $DIR/lint-ctypes.rs:64:12
150150
|
151151
LL | -> ::std::marker::PhantomData<bool>;
152152
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
153153
|
154154
= note: composed only of `PhantomData`
155155

156156
error: `extern` block uses type `fn()`, which is not FFI-safe
157-
--> $DIR/lint-ctypes.rs:64:23
157+
--> $DIR/lint-ctypes.rs:65:23
158158
|
159159
LL | pub fn fn_type(p: RustFn);
160160
| ^^^^^^ not FFI-safe
@@ -163,7 +163,7 @@ LL | pub fn fn_type(p: RustFn);
163163
= note: this function pointer has Rust-specific calling convention
164164

165165
error: `extern` block uses type `fn()`, which is not FFI-safe
166-
--> $DIR/lint-ctypes.rs:65:24
166+
--> $DIR/lint-ctypes.rs:66:24
167167
|
168168
LL | pub fn fn_type2(p: fn());
169169
| ^^^^ not FFI-safe
@@ -172,7 +172,7 @@ LL | pub fn fn_type2(p: fn());
172172
= note: this function pointer has Rust-specific calling convention
173173

174174
error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe
175-
--> $DIR/lint-ctypes.rs:66:28
175+
--> $DIR/lint-ctypes.rs:67:28
176176
|
177177
LL | pub fn fn_contained(p: RustBadRet);
178178
| ^^^^^^^^^^ not FFI-safe
@@ -181,15 +181,15 @@ LL | pub fn fn_contained(p: RustBadRet);
181181
= note: this struct has unspecified layout
182182

183183
error: `extern` block uses type `i128`, which is not FFI-safe
184-
--> $DIR/lint-ctypes.rs:67:32
184+
--> $DIR/lint-ctypes.rs:68:32
185185
|
186186
LL | pub fn transparent_i128(p: TransparentI128);
187187
| ^^^^^^^^^^^^^^^ not FFI-safe
188188
|
189189
= note: 128-bit integers don't currently have a known stable ABI
190190

191191
error: `extern` block uses type `str`, which is not FFI-safe
192-
--> $DIR/lint-ctypes.rs:68:31
192+
--> $DIR/lint-ctypes.rs:69:31
193193
|
194194
LL | pub fn transparent_str(p: TransparentStr);
195195
| ^^^^^^^^^^^^^^ not FFI-safe
@@ -198,7 +198,7 @@ LL | pub fn transparent_str(p: TransparentStr);
198198
= note: string slices have no C equivalent
199199

200200
error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe
201-
--> $DIR/lint-ctypes.rs:69:30
201+
--> $DIR/lint-ctypes.rs:70:30
202202
|
203203
LL | pub fn transparent_fn(p: TransparentBadFn);
204204
| ^^^^^^^^^^^^^^^^ not FFI-safe
@@ -207,7 +207,7 @@ LL | pub fn transparent_fn(p: TransparentBadFn);
207207
= note: this struct has unspecified layout
208208

209209
error: `extern` block uses type `[u8; 8]`, which is not FFI-safe
210-
--> $DIR/lint-ctypes.rs:70:27
210+
--> $DIR/lint-ctypes.rs:71:27
211211
|
212212
LL | pub fn raw_array(arr: [u8; 8]);
213213
| ^^^^^^^ not FFI-safe
@@ -216,15 +216,15 @@ LL | pub fn raw_array(arr: [u8; 8]);
216216
= note: passing raw arrays by value is not FFI-safe
217217

218218
error: `extern` block uses type `u128`, which is not FFI-safe
219-
--> $DIR/lint-ctypes.rs:72:34
219+
--> $DIR/lint-ctypes.rs:73:34
220220
|
221221
LL | pub static static_u128_type: u128;
222222
| ^^^^ not FFI-safe
223223
|
224224
= note: 128-bit integers don't currently have a known stable ABI
225225

226226
error: `extern` block uses type `u128`, which is not FFI-safe
227-
--> $DIR/lint-ctypes.rs:73:40
227+
--> $DIR/lint-ctypes.rs:74:40
228228
|
229229
LL | pub static static_u128_array_type: [u128; 16];
230230
| ^^^^^^^^^^ not FFI-safe
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
pub trait Unsatisfied {}
2+
3+
#[repr(transparent)]
4+
pub struct Bar<T: Unsatisfied>(T);
5+
6+
pub trait Foo {
7+
type Assoc;
8+
}
9+
10+
extern "C" {
11+
pub fn lint_me() -> <() as Foo>::Assoc;
12+
//~^ ERROR: the trait bound `(): Foo` is not satisfied [E0277]
13+
14+
pub fn lint_me_aswell() -> Bar<u32>;
15+
//~^ ERROR: the trait bound `u32: Unsatisfied` is not satisfied [E0277]
16+
}
17+
18+
fn main() {}

0 commit comments

Comments
 (0)