]> git.proxmox.com Git - rustc.git/blame - src/test/ui/lint/clashing-extern-fn.rs
New upstream version 1.48.0~beta.8+dfsg1
[rustc.git] / src / test / ui / lint / clashing-extern-fn.rs
CommitLineData
f035d41b
XL
1// check-pass
2// aux-build:external_extern_fn.rs
3#![crate_type = "lib"]
4#![warn(clashing_extern_declarations)]
5
3dfed10e
XL
6mod redeclared_different_signature {
7 mod a {
8 extern "C" {
9 fn clash(x: u8);
10 }
f035d41b 11 }
3dfed10e
XL
12 mod b {
13 extern "C" {
14 fn clash(x: u64); //~ WARN `clash` redeclared with a different signature
15 }
f035d41b
XL
16 }
17}
18
3dfed10e
XL
19mod redeclared_same_signature {
20 mod a {
21 extern "C" {
22 fn no_clash(x: u8);
23 }
f035d41b 24 }
3dfed10e
XL
25 mod b {
26 extern "C" {
27 fn no_clash(x: u8);
28 }
f035d41b
XL
29 }
30}
31
3dfed10e
XL
32extern crate external_extern_fn;
33mod extern_no_clash {
34 // Should not clash with external_extern_fn::extern_fn.
f035d41b 35 extern "C" {
3dfed10e 36 fn extern_fn(x: u8);
f035d41b
XL
37 }
38}
39
f035d41b
XL
40extern "C" {
41 fn some_other_new_name(x: i16);
42
43 #[link_name = "extern_link_name"]
44 fn some_new_name(x: i16);
45
46 #[link_name = "link_name_same"]
47 fn both_names_different(x: i16);
48}
49
50fn link_name_clash() {
51 extern "C" {
52 fn extern_link_name(x: u32);
53 //~^ WARN `extern_link_name` redeclared with a different signature
54
55 #[link_name = "some_other_new_name"]
56 //~^ WARN `some_other_extern_link_name` redeclares `some_other_new_name` with a different
57 fn some_other_extern_link_name(x: u32);
58
59 #[link_name = "link_name_same"]
60 //~^ WARN `other_both_names_different` redeclares `link_name_same` with a different
61 fn other_both_names_different(x: u32);
62 }
63}
64
65mod a {
66 extern "C" {
67 fn different_mod(x: u8);
68 }
69}
70mod b {
71 extern "C" {
72 fn different_mod(x: u64); //~ WARN `different_mod` redeclared with a different signature
73 }
74}
75
76extern "C" {
77 fn variadic_decl(x: u8, ...);
78}
79
80fn variadic_clash() {
81 extern "C" {
82 fn variadic_decl(x: u8); //~ WARN `variadic_decl` redeclared with a different signature
83 }
84}
85
86#[no_mangle]
87fn no_mangle_name(x: u8) {}
88
89extern "C" {
90 #[link_name = "unique_link_name"]
91 fn link_name_specified(x: u8);
92}
93
94fn tricky_no_clash() {
95 extern "C" {
96 // Shouldn't warn, because the declaration above actually declares a different symbol (and
97 // Rust's name resolution rules around shadowing will handle this gracefully).
98 fn link_name_specified() -> u32;
99
100 // The case of a no_mangle name colliding with an extern decl (see #28179) is related but
101 // shouldn't be reported by ClashingExternDeclarations, because this is an example of
102 // unmangled name clash causing bad behaviour in functions with a defined body.
103 fn no_mangle_name() -> u32;
104 }
105}
106
107mod banana {
108 mod one {
109 #[repr(C)]
110 struct Banana {
111 weight: u32,
112 length: u16,
113 }
114 extern "C" {
115 fn weigh_banana(count: *const Banana) -> u64;
116 }
117 }
118
119 mod two {
120 #[repr(C)]
121 struct Banana {
122 weight: u32,
123 length: u16,
124 } // note: distinct type
f035d41b
XL
125 // This should not trigger the lint because two::Banana is structurally equivalent to
126 // one::Banana.
3dfed10e 127 extern "C" {
f035d41b
XL
128 fn weigh_banana(count: *const Banana) -> u64;
129 }
130 }
131
132 mod three {
133 // This _should_ trigger the lint, because repr(packed) should generate a struct that has a
134 // different layout.
135 #[repr(packed)]
136 struct Banana {
137 weight: u32,
138 length: u16,
139 }
140 #[allow(improper_ctypes)]
141 extern "C" {
142 fn weigh_banana(count: *const Banana) -> u64;
143 //~^ WARN `weigh_banana` redeclared with a different signature
144 }
145 }
146}
147
148mod sameish_members {
149 mod a {
150 #[repr(C)]
151 struct Point {
152 x: i16,
153 y: i16,
154 }
155
156 extern "C" {
157 fn draw_point(p: Point);
158 }
159 }
160 mod b {
161 #[repr(C)]
162 struct Point {
163 coordinates: [i16; 2],
164 }
165
166 // It's possible we are overconservative for this case, as accessing the elements of the
167 // coordinates array might end up correctly accessing `.x` and `.y`. However, this may not
168 // always be the case, for every architecture and situation. This is also a really odd
169 // thing to do anyway.
170 extern "C" {
3dfed10e
XL
171 fn draw_point(p: Point);
172 //~^ WARN `draw_point` redeclared with a different signature
173 }
174 }
175}
176
177mod same_sized_members_clash {
178 mod a {
179 #[repr(C)]
180 struct Point3 {
181 x: f32,
182 y: f32,
183 z: f32,
184 }
1b1a35ee
XL
185 extern "C" {
186 fn origin() -> Point3;
187 }
3dfed10e
XL
188 }
189 mod b {
190 #[repr(C)]
191 struct Point3 {
192 x: i32,
193 y: i32,
194 z: i32, // NOTE: Incorrectly redeclared as i32
195 }
1b1a35ee
XL
196 extern "C" {
197 fn origin() -> Point3; //~ WARN `origin` redeclared with a different signature
198 }
3dfed10e
XL
199 }
200}
201
202mod transparent {
203 #[repr(transparent)]
204 struct T(usize);
205 mod a {
206 use super::T;
207 extern "C" {
208 fn transparent() -> T;
209 fn transparent_incorrect() -> T;
210 }
211 }
212
213 mod b {
214 extern "C" {
215 // Shouldn't warn here, because repr(transparent) guarantees that T's layout is the
216 // same as just the usize.
217 fn transparent() -> usize;
218
219 // Should warn, because there's a signedness conversion here:
220 fn transparent_incorrect() -> isize;
221 //~^ WARN `transparent_incorrect` redeclared with a different signature
222 }
223 }
224}
225
226mod missing_return_type {
227 mod a {
228 extern "C" {
229 fn missing_return_type() -> usize;
230 }
231 }
232
233 mod b {
234 extern "C" {
235 // This should output a warning because we can't assume that the first declaration is
236 // the correct one -- if this one is the correct one, then calling the usize-returning
237 // version would allow reads into uninitialised memory.
238 fn missing_return_type();
239 //~^ WARN `missing_return_type` redeclared with a different signature
240 }
241 }
242}
243
244mod non_zero_and_non_null {
245 mod a {
246 extern "C" {
247 fn non_zero_usize() -> core::num::NonZeroUsize;
248 fn non_null_ptr() -> core::ptr::NonNull<usize>;
249 }
250 }
251 mod b {
252 extern "C" {
253 // If there's a clash in either of these cases you're either gaining an incorrect
254 // invariant that the value is non-zero, or you're missing out on that invariant. Both
255 // cases are warning for, from both a caller-convenience and optimisation perspective.
256 fn non_zero_usize() -> usize;
257 //~^ WARN `non_zero_usize` redeclared with a different signature
258 fn non_null_ptr() -> *const usize;
259 //~^ WARN `non_null_ptr` redeclared with a different signature
260 }
261 }
262}
263
1b1a35ee
XL
264// See #75739
265mod non_zero_transparent {
266 mod a1 {
267 use std::num::NonZeroUsize;
268 extern "C" {
269 fn f1() -> NonZeroUsize;
270 }
271 }
272
273 mod b1 {
274 #[repr(transparent)]
275 struct X(NonZeroUsize);
276 use std::num::NonZeroUsize;
277 extern "C" {
278 fn f1() -> X;
279 }
280 }
281
282 mod a2 {
283 use std::num::NonZeroUsize;
284 extern "C" {
285 fn f2() -> NonZeroUsize;
286 }
287 }
288
289 mod b2 {
290 #[repr(transparent)]
291 struct X1(NonZeroUsize);
292
293 #[repr(transparent)]
294 struct X(X1);
295
296 use std::num::NonZeroUsize;
297 extern "C" {
298 // Same case as above, but with two layers of newtyping.
299 fn f2() -> X;
300 }
301 }
302
303 mod a3 {
304 #[repr(transparent)]
305 struct X(core::ptr::NonNull<i32>);
306
307 use std::num::NonZeroUsize;
308 extern "C" {
309 fn f3() -> X;
310 }
311 }
312
313 mod b3 {
314 extern "C" {
315 fn f3() -> core::ptr::NonNull<i32>;
316 }
317 }
318
319 mod a4 {
320 #[repr(transparent)]
321 enum E {
322 X(std::num::NonZeroUsize),
323 }
324 extern "C" {
325 fn f4() -> E;
326 }
327 }
328
329 mod b4 {
330 extern "C" {
331 fn f4() -> std::num::NonZeroUsize;
332 }
333 }
334}
335
3dfed10e
XL
336mod null_optimised_enums {
337 mod a {
338 extern "C" {
339 fn option_non_zero_usize() -> usize;
340 fn option_non_zero_isize() -> isize;
341 fn option_non_null_ptr() -> *const usize;
342
343 fn option_non_zero_usize_incorrect() -> usize;
344 fn option_non_null_ptr_incorrect() -> *const usize;
345 }
346 }
347 mod b {
348 extern "C" {
349 // This should be allowed, because these conversions are guaranteed to be FFI-safe (see
350 // #60300)
351 fn option_non_zero_usize() -> Option<core::num::NonZeroUsize>;
352 fn option_non_zero_isize() -> Option<core::num::NonZeroIsize>;
353 fn option_non_null_ptr() -> Option<core::ptr::NonNull<usize>>;
354
355 // However, these should be incorrect (note isize instead of usize)
356 fn option_non_zero_usize_incorrect() -> isize;
357 //~^ WARN `option_non_zero_usize_incorrect` redeclared with a different signature
358 fn option_non_null_ptr_incorrect() -> *const isize;
359 //~^ WARN `option_non_null_ptr_incorrect` redeclared with a different signature
f035d41b
XL
360 }
361 }
362}
1b1a35ee
XL
363
364#[allow(improper_ctypes)]
365mod unknown_layout {
366 mod a {
367 extern "C" {
368 pub fn generic(l: Link<u32>);
369 }
370 pub struct Link<T> {
371 pub item: T,
372 pub next: *const Link<T>,
373 }
374 }
375
376 mod b {
377 extern "C" {
378 pub fn generic(l: Link<u32>);
379 }
380 pub struct Link<T> {
381 pub item: T,
382 pub next: *const Link<T>,
383 }
384 }
385}