]> git.lizzy.rs Git - rust.git/blob - src/test/ui/lint/clashing-extern-fn.rs
Rollup merge of #75837 - GuillaumeGomez:fix-font-color-help-button, r=Cldfire
[rust.git] / src / test / ui / lint / clashing-extern-fn.rs
1 // check-pass
2 // aux-build:external_extern_fn.rs
3 #![crate_type = "lib"]
4 #![warn(clashing_extern_declarations)]
5
6 mod redeclared_different_signature {
7     mod a {
8         extern "C" {
9             fn clash(x: u8);
10         }
11     }
12     mod b {
13         extern "C" {
14             fn clash(x: u64); //~ WARN `clash` redeclared with a different signature
15         }
16     }
17 }
18
19 mod redeclared_same_signature {
20     mod a {
21         extern "C" {
22             fn no_clash(x: u8);
23         }
24     }
25     mod b {
26         extern "C" {
27             fn no_clash(x: u8);
28         }
29     }
30 }
31
32 extern crate external_extern_fn;
33 mod extern_no_clash {
34     // Should not clash with external_extern_fn::extern_fn.
35     extern "C" {
36         fn extern_fn(x: u8);
37     }
38 }
39
40 extern "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
50 fn 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
65 mod a {
66     extern "C" {
67         fn different_mod(x: u8);
68     }
69 }
70 mod b {
71     extern "C" {
72         fn different_mod(x: u64); //~ WARN `different_mod` redeclared with a different signature
73     }
74 }
75
76 extern "C" {
77     fn variadic_decl(x: u8, ...);
78 }
79
80 fn 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]
87 fn no_mangle_name(x: u8) {}
88
89 extern "C" {
90     #[link_name = "unique_link_name"]
91     fn link_name_specified(x: u8);
92 }
93
94 fn 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
107 mod 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
125           // This should not trigger the lint because two::Banana is structurally equivalent to
126           // one::Banana.
127         extern "C" {
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
148 mod 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" {
171             fn draw_point(p: Point);
172             //~^ WARN `draw_point` redeclared with a different signature
173         }
174     }
175 }
176
177 mod same_sized_members_clash {
178     mod a {
179         #[repr(C)]
180         struct Point3 {
181             x: f32,
182             y: f32,
183             z: f32,
184         }
185         extern "C" { fn origin() -> Point3; }
186     }
187     mod b {
188         #[repr(C)]
189         struct Point3 {
190             x: i32,
191             y: i32,
192             z: i32, // NOTE: Incorrectly redeclared as i32
193         }
194         extern "C" { fn origin() -> Point3; }
195         //~^ WARN `origin` redeclared with a different signature
196     }
197 }
198
199 mod transparent {
200     #[repr(transparent)]
201     struct T(usize);
202     mod a {
203         use super::T;
204         extern "C" {
205             fn transparent() -> T;
206             fn transparent_incorrect() -> T;
207         }
208     }
209
210     mod b {
211         extern "C" {
212             // Shouldn't warn here, because repr(transparent) guarantees that T's layout is the
213             // same as just the usize.
214             fn transparent() -> usize;
215
216             // Should warn, because there's a signedness conversion here:
217             fn transparent_incorrect() -> isize;
218             //~^ WARN `transparent_incorrect` redeclared with a different signature
219         }
220     }
221 }
222
223 mod missing_return_type {
224     mod a {
225         extern "C" {
226             fn missing_return_type() -> usize;
227         }
228     }
229
230     mod b {
231         extern "C" {
232             // This should output a warning because we can't assume that the first declaration is
233             // the correct one -- if this one is the correct one, then calling the usize-returning
234             // version would allow reads into uninitialised memory.
235             fn missing_return_type();
236             //~^ WARN `missing_return_type` redeclared with a different signature
237         }
238     }
239 }
240
241 mod non_zero_and_non_null {
242     mod a {
243         extern "C" {
244             fn non_zero_usize() -> core::num::NonZeroUsize;
245             fn non_null_ptr() -> core::ptr::NonNull<usize>;
246         }
247     }
248     mod b {
249         extern "C" {
250             // If there's a clash in either of these cases you're either gaining an incorrect
251             // invariant that the value is non-zero, or you're missing out on that invariant. Both
252             // cases are warning for, from both a caller-convenience and optimisation perspective.
253             fn non_zero_usize() -> usize;
254             //~^ WARN `non_zero_usize` redeclared with a different signature
255             fn non_null_ptr() -> *const usize;
256             //~^ WARN `non_null_ptr` redeclared with a different signature
257         }
258     }
259 }
260
261 mod null_optimised_enums {
262     mod a {
263         extern "C" {
264             fn option_non_zero_usize() -> usize;
265             fn option_non_zero_isize() -> isize;
266             fn option_non_null_ptr() -> *const usize;
267
268             fn option_non_zero_usize_incorrect() -> usize;
269             fn option_non_null_ptr_incorrect() -> *const usize;
270         }
271     }
272     mod b {
273         extern "C" {
274             // This should be allowed, because these conversions are guaranteed to be FFI-safe (see
275             // #60300)
276             fn option_non_zero_usize() -> Option<core::num::NonZeroUsize>;
277             fn option_non_zero_isize() -> Option<core::num::NonZeroIsize>;
278             fn option_non_null_ptr() -> Option<core::ptr::NonNull<usize>>;
279
280             // However, these should be incorrect (note isize instead of usize)
281             fn option_non_zero_usize_incorrect() -> isize;
282             //~^ WARN `option_non_zero_usize_incorrect` redeclared with a different signature
283             fn option_non_null_ptr_incorrect() -> *const isize;
284             //~^ WARN `option_non_null_ptr_incorrect` redeclared with a different signature
285         }
286     }
287 }
288
289 #[allow(improper_ctypes)]
290 mod unknown_layout {
291     mod a {
292         extern "C" {
293             pub fn generic(l: Link<u32>);
294         }
295         pub struct Link<T> {
296             pub item: T,
297             pub next: *const Link<T>,
298         }
299     }
300
301     mod b {
302         extern "C" {
303             pub fn generic(l: Link<u32>);
304         }
305         pub struct Link<T> {
306             pub item: T,
307             pub next: *const Link<T>,
308         }
309     }
310 }