blob: 4fd85222a3a7f227897a659383d91aec7f776e07 [file] [log] [blame]
Alex Crichton8e5f0cd2015-09-09 22:46:19 -07001extern crate gcc;
2extern crate syntex_syntax as syntax;
3
Alex Crichton310d6232015-09-10 10:56:31 -07004use std::collections::HashSet;
Alex Crichton8e5f0cd2015-09-09 22:46:19 -07005use std::env;
6use std::fs::File;
7use std::io::BufWriter;
8use std::io::prelude::*;
9use std::path::{Path, PathBuf};
10
Alex Crichton31504842015-09-10 23:43:41 -070011use syntax::abi::Abi;
Alex Crichton8e5f0cd2015-09-09 22:46:19 -070012use syntax::ast;
Alex Crichtona9adfbf2015-09-09 23:21:27 -070013use syntax::attr::{self, ReprAttr};
Alex Crichton31504842015-09-10 23:43:41 -070014use syntax::diagnostic::SpanHandler;
15use syntax::ext::base::SyntaxExtension;
16use syntax::ext::expand;
17use syntax::parse::token::{intern, InternedString};
Alex Crichton8e5f0cd2015-09-09 22:46:19 -070018use syntax::parse::{self, ParseSess};
19use syntax::visit::{self, Visitor};
20
Alex Crichton310d6232015-09-10 10:56:31 -070021macro_rules! t {
22 ($e:expr) => (match $e {
23 Ok(e) => e,
24 Err(e) => panic!("{} failed with {}", stringify!($e), e),
25 })
26}
27
Alex Crichtona9adfbf2015-09-09 23:21:27 -070028struct TestGenerator<'a> {
Alex Crichton310d6232015-09-10 10:56:31 -070029 target: String,
Alex Crichton8e5f0cd2015-09-09 22:46:19 -070030 rust: Box<Write>,
31 c: Box<Write>,
Alex Crichtona9adfbf2015-09-09 23:21:27 -070032 sh: &'a SpanHandler,
Alex Crichton310d6232015-09-10 10:56:31 -070033 structs: HashSet<String>,
Alex Crichton31504842015-09-10 23:43:41 -070034 abi: Abi,
Alex Crichton5a284332015-09-13 23:33:33 -070035 tests: Vec<String>,
Alex Crichton310d6232015-09-10 10:56:31 -070036}
37
38struct StructFinder {
39 structs: HashSet<String>,
40}
41
42impl<'a> TestGenerator<'a> {
Alex Crichton0df7c102015-09-10 16:35:37 -070043 fn defines(&self) -> Vec<&'static str> {
44 let mut ret = Vec::new();
Alex Crichton31504842015-09-10 23:43:41 -070045
46 // Pull in extra goodies on linux
Alex Crichton1cf98ae2015-09-13 11:19:02 -070047 if self.target.contains("unknown-linux-gnu") {
Alex Crichton0df7c102015-09-10 16:35:37 -070048 ret.push("_GNU_SOURCE");
49 }
Alex Crichton31504842015-09-10 23:43:41 -070050
51 // MSVC doesn't have stdalign.h so get alignof ourselves
Alex Crichtonac2bd852015-09-10 17:21:20 -070052 if self.target.contains("msvc") {
53 ret.push("alignof __alignof");
54 }
Alex Crichton31504842015-09-10 23:43:41 -070055
Alex Crichtond3d77922015-09-11 17:03:39 -070056 // android also doesn't have stdalign.h so get alignof ourselves
Alex Crichton8fc95d22015-09-14 11:06:20 -070057 if self.target.contains("android") || self.target.contains("mips") {
Alex Crichtond3d77922015-09-11 17:03:39 -070058 ret.push("alignof __alignof__");
59 }
60
Alex Crichton31504842015-09-10 23:43:41 -070061 // Pull in extra goodies on mingw
62 if self.target.contains("windows") {
63 ret.push("_WIN32_WINNT 0x8000");
64 }
Alex Crichton0df7c102015-09-10 16:35:37 -070065 return ret
66 }
67
Alex Crichton310d6232015-09-10 10:56:31 -070068 fn headers(&self) -> Vec<&'static str> {
Alex Crichtonac2bd852015-09-10 17:21:20 -070069 let mut base = Vec::new();
70
Alex Crichtonf81e3d32015-09-11 15:27:09 -070071 base.extend([
Alex Crichton0df7c102015-09-10 16:35:37 -070072 "errno.h",
73 "fcntl.h",
Alex Crichton0df7c102015-09-10 16:35:37 -070074 "limits.h",
Alex Crichton310d6232015-09-10 10:56:31 -070075 "stddef.h",
76 "stdint.h",
Alex Crichton0df7c102015-09-10 16:35:37 -070077 "stdio.h",
78 "stdlib.h",
Alex Crichton310d6232015-09-10 10:56:31 -070079 "sys/stat.h",
Alex Crichton310d6232015-09-10 10:56:31 -070080 "sys/types.h",
Alex Crichton310d6232015-09-10 10:56:31 -070081 "time.h",
Alex Crichton310d6232015-09-10 10:56:31 -070082 "wchar.h",
Alex Crichtonf81e3d32015-09-11 15:27:09 -070083 ].iter().cloned());
Alex Crichton310d6232015-09-10 10:56:31 -070084
85 if self.target.contains("apple-darwin") {
Alex Crichtone8606192015-09-10 20:19:44 -070086 base.push("mach-o/dyld.h");
Alex Crichton310d6232015-09-10 10:56:31 -070087 base.push("mach/mach_time.h");
88 }
Alex Crichtonac2bd852015-09-10 17:21:20 -070089
Alex Crichtond3d77922015-09-11 17:03:39 -070090 if self.target.contains("unknown-linux") ||
91 self.target.contains("android") {
Alex Crichton310d6232015-09-10 10:56:31 -070092 base.push("linux/if_packet.h");
93 base.push("net/ethernet.h");
94 }
95
Alex Crichtonac2bd852015-09-10 17:21:20 -070096 if self.target.contains("windows") {
Alex Crichton7da9b102015-09-10 20:57:14 -070097 base.push("winsock2.h"); // must be before windows.h
98
99 base.push("direct.h");
100 base.push("io.h");
Alex Crichton13a6f2d2015-09-10 18:10:58 -0700101 base.push("sys/utime.h");
Alex Crichton7da9b102015-09-10 20:57:14 -0700102 base.push("windows.h");
103 base.push("process.h");
104 base.push("ws2ipdef.h");
Alex Crichton31504842015-09-10 23:43:41 -0700105
106 if self.target.contains("gnu") {
107 base.push("stdalign.h");
108 base.push("ws2tcpip.h");
109 }
Alex Crichtonac2bd852015-09-10 17:21:20 -0700110 } else {
Alex Crichton22378822015-09-10 19:59:23 -0700111 base.push("ctype.h");
112 base.push("dirent.h");
Alex Crichtonac2bd852015-09-10 17:21:20 -0700113 base.push("net/if.h");
114 base.push("netdb.h");
115 base.push("netinet/in.h");
116 base.push("netinet/ip.h");
117 base.push("netinet/tcp.h");
118 base.push("pthread.h");
119 base.push("signal.h");
Alex Crichtone8606192015-09-10 20:19:44 -0700120 base.push("string.h");
Alex Crichton22378822015-09-10 19:59:23 -0700121 base.push("sys/file.h");
122 base.push("sys/ioctl.h");
Alex Crichtonac2bd852015-09-10 17:21:20 -0700123 base.push("sys/mman.h");
124 base.push("sys/resource.h");
125 base.push("sys/socket.h");
126 base.push("sys/time.h");
127 base.push("sys/un.h");
Alex Crichton22378822015-09-10 19:59:23 -0700128 base.push("sys/wait.h");
Alex Crichtonac2bd852015-09-10 17:21:20 -0700129 base.push("unistd.h");
Alex Crichton22378822015-09-10 19:59:23 -0700130 base.push("utime.h");
Alex Crichtond3d77922015-09-11 17:03:39 -0700131
132 if self.target.contains("android") {
133 base.push("arpa/inet.h");
134 } else {
135 base.push("glob.h");
136 base.push("ifaddrs.h");
Alex Crichton8fc95d22015-09-14 11:06:20 -0700137 if !self.target.contains("mips") {
138 base.push("stdalign.h");
139 }
Alex Crichtond3d77922015-09-11 17:03:39 -0700140 base.push("sys/sysctl.h");
141 }
Alex Crichtonac2bd852015-09-10 17:21:20 -0700142 }
143
Alex Crichton310d6232015-09-10 10:56:31 -0700144 return base
145 }
146
147 fn rust2c(&self, ty: &str) -> String {
Alex Crichton13a6f2d2015-09-10 18:10:58 -0700148 let windows = self.target.contains("windows");
Alex Crichton310d6232015-09-10 10:56:31 -0700149 match ty {
150 t if t.starts_with("c_") => {
151 match &ty[2..].replace("long", " long")[..] {
152 s if s.starts_with("u") => format!("unsigned {}", &s[1..]),
153 "short" => format!("short"),
154 s if s.starts_with("s") => format!("signed {}", &s[1..]),
155 s => s.to_string(),
156 }
157 }
Alex Crichton31504842015-09-10 23:43:41 -0700158
159 // Just pass all these through, no need for a "struct" prefix
Alex Crichton22378822015-09-10 19:59:23 -0700160 "glob_t" |
161 "FILE" |
162 "DIR" |
163 "fpos_t" => ty.to_string(),
Alex Crichton310d6232015-09-10 10:56:31 -0700164 t if t.starts_with("pthread") => t.to_string(),
165
Alex Crichton31504842015-09-10 23:43:41 -0700166 // Windows uppercase structs don't have `struct` in front, there's a
167 // few special cases for windows, and then otherwise put `struct` in
168 // front of everything.
Alex Crichton13a6f2d2015-09-10 18:10:58 -0700169 t if self.structs.contains(t) => {
170 if windows && ty.chars().next().unwrap().is_uppercase() {
171 t.to_string()
172 } else if windows && t == "stat" {
173 "struct __stat64".to_string()
Alex Crichton7da9b102015-09-10 20:57:14 -0700174 } else if windows && t == "utimbuf" {
175 "struct __utimbuf64".to_string()
Alex Crichton13a6f2d2015-09-10 18:10:58 -0700176 } else {
177 format!("struct {}", t)
178 }
179 }
Alex Crichton310d6232015-09-10 10:56:31 -0700180
Alex Crichton31504842015-09-10 23:43:41 -0700181 // Fixup a few types on windows that don't actually exist.
Alex Crichton13a6f2d2015-09-10 18:10:58 -0700182 "time64_t" if windows => "__time64_t".to_string(),
183 "ssize_t" if windows => "SSIZE_T".to_string(),
Alex Crichton31504842015-09-10 23:43:41 -0700184
Alex Crichton310d6232015-09-10 10:56:31 -0700185 t => t.to_string(),
186 }
187 }
188
189 fn rust2cfield(&self, struct_: &str, field: &str) -> String {
190 match field {
Alex Crichton31504842015-09-10 23:43:41 -0700191 // Our stat *_nsec fields normally don't actually exist but are part
192 // of a timeval struct
Alex Crichton310d6232015-09-10 10:56:31 -0700193 s if s.ends_with("_nsec") && struct_ == "stat" => {
194 if self.target.contains("apple-darwin") {
195 s.replace("_nsec", "spec.tv_nsec")
Alex Crichtond3d77922015-09-11 17:03:39 -0700196 } else if self.target.contains("android") {
197 s.to_string()
Alex Crichton310d6232015-09-10 10:56:31 -0700198 } else {
199 s.replace("e_nsec", ".tv_nsec")
200 }
201 }
202 s => s.to_string(),
203 }
204 }
205
206 fn cfg_list(&self) -> Vec<(&'static str, Option<&'static str>)> {
207 let mut ret = Vec::new();
208 let (arch, target_pointer_width) = if self.target.starts_with("x86_64") {
209 ("x86_64", "64")
210 } else if self.target.starts_with("i686") {
211 ("x86", "32")
Alex Crichtond3d77922015-09-11 17:03:39 -0700212 } else if self.target.starts_with("arm") {
213 ("arm", "32")
Alex Crichton8fc95d22015-09-14 11:06:20 -0700214 } else if self.target.starts_with("mips") {
215 ("mips", "32")
Alex Crichton310d6232015-09-10 10:56:31 -0700216 } else {
217 panic!("unknown arch/pointer width: {}", self.target)
218 };
Alex Crichton1cf98ae2015-09-13 11:19:02 -0700219 let (os, family, env) = if self.target.contains("unknown-linux-gnu") {
Alex Crichton310d6232015-09-10 10:56:31 -0700220 ("linux", "unix", "gnu")
Alex Crichton1cf98ae2015-09-13 11:19:02 -0700221 } else if self.target.contains("unknown-linux-musl") {
222 ("linux", "unix", "musl")
Alex Crichton310d6232015-09-10 10:56:31 -0700223 } else if self.target.contains("apple-darwin") {
224 ("macos", "unix", "")
Alex Crichtonac2bd852015-09-10 17:21:20 -0700225 } else if self.target.contains("windows-msvc") {
226 ("windows", "windows", "msvc")
227 } else if self.target.contains("windows-gnu") {
228 ("windows", "windows", "gnu")
Alex Crichtond3d77922015-09-11 17:03:39 -0700229 } else if self.target.contains("android") {
230 ("android", "unix", "")
Alex Crichton8293ced2015-09-15 17:05:19 -0700231 } else if self.target.contains("unknown-freebsd") {
232 ("freebsd", "unix", "")
Alex Crichton310d6232015-09-10 10:56:31 -0700233 } else {
234 panic!("unknown os/family width: {}", self.target)
235 };
236
237 ret.push((family, None));
238 ret.push(("target_os", Some(os)));
239 ret.push(("target_family", Some(family)));
240 ret.push(("target_arch", Some(arch)));
241 // skip endianness
242 ret.push(("target_pointer_width", Some(target_pointer_width)));
243 ret.push(("target_env", Some(env)));
244
245 return ret
246 }
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700247}
248
249fn main() {
Alex Crichton310d6232015-09-10 10:56:31 -0700250 // Prep the test generator
251 let target = t!(env::var("TARGET"));
252 let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
253 let rust_out = BufWriter::new(t!(File::create(out.join("all.rs"))));
254 let c_out = BufWriter::new(t!(File::create(out.join("all.c"))));
Alex Crichton16083062015-09-09 22:59:24 -0700255 let sess = ParseSess::new();
Alex Crichton310d6232015-09-10 10:56:31 -0700256 let mut tg = TestGenerator {
257 target: target,
258 rust: Box::new(rust_out),
259 c: Box::new(c_out),
260 sh: &sess.span_diagnostic,
261 structs: HashSet::new(),
Alex Crichton31504842015-09-10 23:43:41 -0700262 abi: Abi::C,
Alex Crichton5a284332015-09-13 23:33:33 -0700263 tests: Vec::new(),
Alex Crichton310d6232015-09-10 10:56:31 -0700264 };
265
266 // Parse the libc crate
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700267 let src = Path::new("../src/lib.rs");
268 let cfg = Vec::new();
Alex Crichton31504842015-09-10 23:43:41 -0700269 let krate = parse::parse_crate_from_file(src, cfg, &sess);
270
271 // expand macros
272 let ecfg = expand::ExpansionConfig::default("libc".to_string());
273 let exts = vec![
274 (intern("macro_rules"), SyntaxExtension::MacroRulesTT),
275 ];
276 let mut krate = expand::expand_crate(&sess, ecfg, Vec::new(),
277 exts, &mut Vec::new(), krate);
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700278
Alex Crichton310d6232015-09-10 10:56:31 -0700279 // Strip the crate down to just what's configured for our target
280 for (k, v) in tg.cfg_list() {
281 let s = InternedString::new;
282 krate.config.push(match v {
283 Some(v) => attr::mk_name_value_item_str(s(k), s(v)),
284 None => attr::mk_word_item(s(k)),
285 });
286 }
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700287 let mut gated_cfgs = Vec::new();
288 let krate = syntax::config::strip_unconfigured_items(&sess.span_diagnostic,
289 krate,
290 &mut gated_cfgs);
291
Alex Crichton310d6232015-09-10 10:56:31 -0700292 // Probe the crate to find all structs (used to convert type names to names
293 // in C).
294 let mut structs = StructFinder {
295 structs: HashSet::new(),
296 };
297 visit::walk_crate(&mut structs, &krate);
298 tg.structs = structs.structs;
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700299
Alex Crichton0df7c102015-09-10 16:35:37 -0700300 // Prep the C file by emitting header stuff
301 for define in tg.defines() {
302 t!(writeln!(tg.c, "#define {}", define));
303 }
Alex Crichton310d6232015-09-10 10:56:31 -0700304 for header in tg.headers() {
305 t!(writeln!(tg.c, "#include <{}>", header));
Alex Crichton16083062015-09-09 22:59:24 -0700306 }
Alex Crichton0df7c102015-09-10 16:35:37 -0700307
308 // Walk the crate, emitting test cases for everything found
Alex Crichton310d6232015-09-10 10:56:31 -0700309 visit::walk_crate(&mut tg, &krate);
Alex Crichton5a284332015-09-13 23:33:33 -0700310 tg.emit_run_all();
Alex Crichton16083062015-09-09 22:59:24 -0700311
Alex Crichton310d6232015-09-10 10:56:31 -0700312 // Compile our C shim to be linked into tests
Alex Crichtonac2bd852015-09-10 17:21:20 -0700313 let mut cfg = gcc::Config::new();
314 cfg.file(out.join("all.c"));
315
316 if tg.target.contains("msvc") {
Alex Crichton13a6f2d2015-09-10 18:10:58 -0700317 cfg.flag("/W3").flag("/Wall").flag("/WX")
318 .flag("/wd4820") // weird warning about adding padding?
Alex Crichton7da9b102015-09-10 20:57:14 -0700319 .flag("/wd4100") // don't warn about unused parameters
320 .flag("/wd4996"); // don't warn about deprecated functions
Alex Crichtonac2bd852015-09-10 17:21:20 -0700321 } else {
Alex Crichtonb01a8cc2015-09-10 17:37:22 -0700322 cfg.flag("-Wall").flag("-Wextra").flag("-Werror")
Alex Crichton6d3cfdb2015-09-15 14:53:01 -0700323 .flag("-Wno-unused-parameter")
324 .flag("-Wno-type-limits");
Alex Crichtonac2bd852015-09-10 17:21:20 -0700325 }
326
327 drop(tg);
328 cfg.compile("liball.a");
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700329}
330
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700331impl<'a> TestGenerator<'a> {
332 fn test_type(&mut self, ty: &str) {
Alex Crichton310d6232015-09-10 10:56:31 -0700333 match ty {
Alex Crichtond3d77922015-09-11 17:03:39 -0700334 // sighandler_t is crazy across platforms
Alex Crichton310d6232015-09-10 10:56:31 -0700335 "sighandler_t" => return,
Alex Crichtond3d77922015-09-11 17:03:39 -0700336
337 // Not actually defined on android, but it's not hurting anyone
338 "in_port_t" if self.target.contains("android") => return,
Alex Crichton310d6232015-09-10 10:56:31 -0700339 _ => {}
340 }
Alex Crichton22378822015-09-10 19:59:23 -0700341 let c = self.rust_ty_to_c_ty(ty);
Alex Crichton310d6232015-09-10 10:56:31 -0700342 self.test_size_align(ty, &c);
Alex Crichton6d3cfdb2015-09-15 14:53:01 -0700343 self.test_sign(ty, &c);
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700344 }
Alex Crichton16083062015-09-09 22:59:24 -0700345
Alex Crichton3e5155b2015-09-09 23:46:19 -0700346 fn test_struct(&mut self, ty: &str, s: &ast::StructDef) {
Alex Crichton22378822015-09-10 19:59:23 -0700347 let cty = self.rust_ty_to_c_ty(ty);
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700348 self.test_size_align(ty, &cty);
Alex Crichton3e5155b2015-09-09 23:46:19 -0700349
Alex Crichton5a284332015-09-13 23:33:33 -0700350 self.tests.push(format!("field_offset_size_{}", ty));
Alex Crichton310d6232015-09-10 10:56:31 -0700351 t!(writeln!(self.rust, r#"
Alex Crichton3e5155b2015-09-09 23:46:19 -0700352 fn field_offset_size_{ty}() {{
Alex Crichton5a284332015-09-13 23:33:33 -0700353 println!("verifying struct {ty}");
Alex Crichton310d6232015-09-10 10:56:31 -0700354 "#, ty = ty));
Alex Crichton3e5155b2015-09-09 23:46:19 -0700355 for field in s.fields.iter() {
356 let name = match field.node.kind {
357 ast::NamedField(name, ast::Public) => name,
358 ast::NamedField(_, ast::Inherited) => continue,
359 ast::UnnamedField(..) => panic!("no tuple structs in FFI"),
360 };
361
Alex Crichton310d6232015-09-10 10:56:31 -0700362 let cfield = self.rust2cfield(ty, &name.to_string());
Alex Crichton3e5155b2015-09-09 23:46:19 -0700363
Alex Crichton310d6232015-09-10 10:56:31 -0700364 t!(writeln!(self.c, r#"
Alex Crichton671376b2015-09-10 17:39:03 -0700365 uint64_t __test_offset_{ty}_{rust_field}(void) {{
Alex Crichton3e5155b2015-09-09 23:46:19 -0700366 return offsetof({cty}, {c_field});
367 }}
Alex Crichton671376b2015-09-10 17:39:03 -0700368 uint64_t __test_size_{ty}_{rust_field}(void) {{
Alex Crichton3e5155b2015-09-09 23:46:19 -0700369 {cty}* foo = NULL;
370 return sizeof(foo->{c_field});
371 }}
Alex Crichton310d6232015-09-10 10:56:31 -0700372 "#, ty = ty, cty = cty, rust_field = name, c_field = cfield));
373 t!(writeln!(self.rust, r#"
Alex Crichton3e5155b2015-09-09 23:46:19 -0700374 extern {{
375 fn __test_offset_{ty}_{field}() -> u64;
376 fn __test_size_{ty}_{field}() -> u64;
377 }}
378 unsafe {{
379 let foo = 0 as *const {ty};
380 same(offset_of!({ty}, {field}),
381 __test_offset_{ty}_{field}(),
382 "field offset {field} of {ty}");
383 same(mem::size_of_val(&(*foo).{field}) as u64,
384 __test_size_{ty}_{field}(),
385 "field size {field} of {ty}");
386 }}
Alex Crichton310d6232015-09-10 10:56:31 -0700387 "#, ty = ty, field = name));
Alex Crichton3e5155b2015-09-09 23:46:19 -0700388 }
Alex Crichton310d6232015-09-10 10:56:31 -0700389 t!(writeln!(self.rust, r#"
Alex Crichton3e5155b2015-09-09 23:46:19 -0700390 }}
Alex Crichton310d6232015-09-10 10:56:31 -0700391 "#));
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700392 }
393
394 fn test_size_align(&mut self, rust: &str, c: &str) {
Alex Crichton310d6232015-09-10 10:56:31 -0700395 t!(writeln!(self.c, r#"
Alex Crichton671376b2015-09-10 17:39:03 -0700396 uint64_t __test_size_{ty}(void) {{ return sizeof({cty}); }}
397 uint64_t __test_align_{ty}(void) {{ return alignof({cty}); }}
Alex Crichton310d6232015-09-10 10:56:31 -0700398 "#, ty = rust, cty = c));
399 t!(writeln!(self.rust, r#"
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700400 fn size_align_{ty}() {{
Alex Crichton16083062015-09-09 22:59:24 -0700401 extern {{
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700402 fn __test_size_{ty}() -> u64;
403 fn __test_align_{ty}() -> u64;
Alex Crichton16083062015-09-09 22:59:24 -0700404 }}
Alex Crichton5a284332015-09-13 23:33:33 -0700405 println!("verifying type {ty} align/size");
Alex Crichton16083062015-09-09 22:59:24 -0700406 unsafe {{
Alex Crichton3e5155b2015-09-09 23:46:19 -0700407 same(mem::size_of::<{ty}>() as u64,
Alex Crichton5a284332015-09-13 23:33:33 -0700408 __test_size_{ty}(), "{ty} size");
Alex Crichtonc8b895c2015-09-10 13:24:15 -0700409 same(align::<{ty}>() as u64,
Alex Crichton5a284332015-09-13 23:33:33 -0700410 __test_align_{ty}(), "{ty} align");
Alex Crichton16083062015-09-09 22:59:24 -0700411 }}
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700412 }}
Alex Crichton310d6232015-09-10 10:56:31 -0700413 "#, ty = rust));
Alex Crichton5a284332015-09-13 23:33:33 -0700414 self.tests.push(format!("size_align_{}", rust));
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700415 }
416
Alex Crichton6d3cfdb2015-09-15 14:53:01 -0700417 fn test_sign(&mut self, rust: &str, c: &str) {
418 match c {
419 "float" |
Alex Crichtoneef03da2015-09-15 16:57:06 -0700420 "mach_timebase_info_data_t" |
Alex Crichton6d3cfdb2015-09-15 14:53:01 -0700421 "double" => return,
Alex Crichton8293ced2015-09-15 17:05:19 -0700422 n if n.starts_with("pthread") => return,
Alex Crichton6d3cfdb2015-09-15 14:53:01 -0700423 _ => {}
424 }
425 t!(writeln!(self.c, r#"
426 uint32_t __test_signed_{ty}(void) {{
427 return ((({cty}) -1) < 0);
428 }}
429 "#, ty = rust, cty = c));
430 t!(writeln!(self.rust, r#"
431 fn sign_{ty}() {{
432 extern {{
433 fn __test_signed_{ty}() -> u32;
434 }}
435 println!("verifying type {ty} sign");
436 unsafe {{
437 same(((!(0 as {ty})) < (0 as {ty})) as u32,
438 __test_signed_{ty}(), "{ty} signed");
439 }}
440 }}
441 "#, ty = rust));
442 self.tests.push(format!("sign_{}", rust));
443 }
444
Alex Crichton22378822015-09-10 19:59:23 -0700445 fn rust_ty_to_c_ty(&self, mut rust_ty: &str) -> String {
446 let mut cty = self.rust2c(&rust_ty.replace("*mut ", "")
447 .replace("*const ", ""));
448 while rust_ty.starts_with("*") {
449 if rust_ty.starts_with("*const") {
450 cty = format!("const {}*", cty);
451 rust_ty = &rust_ty[7..];
452 } else {
453 cty = format!("{}*", cty);
454 rust_ty = &rust_ty[5..];
455 }
456 }
457 return cty
458 }
459
Alex Crichton0df7c102015-09-10 16:35:37 -0700460 fn test_const(&mut self, name: &str, rust_ty: &str) {
Alex Crichton31504842015-09-10 23:43:41 -0700461 let mingw = self.target.contains("windows-gnu");
462
463 // Apparently these don't exist in mingw headers?
464 match name {
465 "MEM_RESET_UNDO" |
466 "FILE_ATTRIBUTE_NO_SCRUB_DATA" |
467 "FILE_ATTRIBUTE_INTEGRITY_STREAM" |
468 "ERROR_NOTHING_TO_TERMINATE" if mingw => return,
469 _ => {}
470 }
471
Alex Crichton22378822015-09-10 19:59:23 -0700472 let cty = self.rust_ty_to_c_ty(rust_ty);
Alex Crichton31504842015-09-10 23:43:41 -0700473
474 // SIG_IGN has weird types on platforms, just worry about it as a size_t
Alex Crichton0df7c102015-09-10 16:35:37 -0700475 let cast = if name == "SIG_IGN" {"(size_t)"} else {""};
Alex Crichton31504842015-09-10 23:43:41 -0700476
Alex Crichton0df7c102015-09-10 16:35:37 -0700477 t!(writeln!(self.c, r#"
Alex Crichton13a6f2d2015-09-10 18:10:58 -0700478 int __test_const_{name}({cty} *outptr) {{
479 *outptr = {cast}({name});
480 return 1;
Alex Crichtone7afdd82015-09-10 17:15:20 -0700481 }}
Alex Crichton0df7c102015-09-10 16:35:37 -0700482 "#, name = name, cast = cast, cty = cty));
483 t!(writeln!(self.rust, r#"
Alex Crichton0df7c102015-09-10 16:35:37 -0700484 fn const_{name}() {{
485 extern {{
Alex Crichtone7afdd82015-09-10 17:15:20 -0700486 fn __test_const_{name}(out: *mut {ty}) -> c_int;
Alex Crichton0df7c102015-09-10 16:35:37 -0700487 }}
Alex Crichton5a284332015-09-13 23:33:33 -0700488 println!("verifying const {name} value");
Alex Crichton0df7c102015-09-10 16:35:37 -0700489 unsafe {{
Alex Crichtone7afdd82015-09-10 17:15:20 -0700490 let mut o = mem::zeroed();
491 if __test_const_{name}(&mut o) == 0 {{
Alex Crichton5a284332015-09-13 23:33:33 -0700492 panic!("{name} not defined");
Alex Crichtone7afdd82015-09-10 17:15:20 -0700493 }} else {{
Alex Crichton5a284332015-09-13 23:33:33 -0700494 same({name}, o, "{name} value");
Alex Crichtone7afdd82015-09-10 17:15:20 -0700495 }}
Alex Crichton0df7c102015-09-10 16:35:37 -0700496 }}
497 }}
498 "#, ty = rust_ty, name = name));
Alex Crichton5a284332015-09-13 23:33:33 -0700499 self.tests.push(format!("const_{}", name));
Alex Crichton0df7c102015-09-10 16:35:37 -0700500 }
501
Alex Crichton7da9b102015-09-10 20:57:14 -0700502 fn test_extern_fn(&mut self, name: &str, cname: &str,
503 args: &[String], ret: &str,
Alex Crichton31504842015-09-10 23:43:41 -0700504 variadic: bool, abi: Abi) {
Alex Crichton22378822015-09-10 19:59:23 -0700505 match name {
506 // manually verified
507 "execv" |
508 "execve" |
509 "execvp" |
Alex Crichton7da9b102015-09-10 20:57:14 -0700510 "execvpe" |
Alex Crichton22378822015-09-10 19:59:23 -0700511 "glob" |
512 "getrlimit" |
513 "setrlimit" |
Alex Crichtone8606192015-09-10 20:19:44 -0700514 "signal" |
Alex Crichton22378822015-09-10 19:59:23 -0700515 "getopt" => return,
516 _ => {}
517 }
518 let args = if args.len() == 0 && !variadic {
519 "void".to_string()
520 } else {
521 args.iter().map(|a| self.rust_ty_to_c_ty(a)).collect::<Vec<_>>()
522 .connect(", ") + if variadic {", ..."} else {""}
523 };
524 let cret = self.rust_ty_to_c_ty(ret);
Alex Crichton31504842015-09-10 23:43:41 -0700525 let abi = match abi {
526 Abi::C => "",
527 Abi::Stdcall => "__stdcall ",
528 Abi::System if self.target.contains("i686-pc-windows") => {
529 "__stdcall "
530 }
531 Abi::System => "",
532 a => panic!("unknown ABI: {}", a),
533 };
Alex Crichton22378822015-09-10 19:59:23 -0700534 t!(writeln!(self.c, r#"
Alex Crichton31504842015-09-10 23:43:41 -0700535 {ret} ({abi}*__test_fn_{name}(void))({args}) {{
Alex Crichton7da9b102015-09-10 20:57:14 -0700536 return {cname};
Alex Crichton22378822015-09-10 19:59:23 -0700537 }}
Alex Crichton31504842015-09-10 23:43:41 -0700538 "#, name = name, cname = cname, args = args, ret = cret, abi = abi));
Alex Crichton22378822015-09-10 19:59:23 -0700539 t!(writeln!(self.rust, r#"
Alex Crichton22378822015-09-10 19:59:23 -0700540 fn fn_{name}() {{
541 extern {{
542 fn __test_fn_{name}() -> size_t;
543 }}
Alex Crichton5a284332015-09-13 23:33:33 -0700544 println!("verifying function {name} pointer");
Alex Crichton22378822015-09-10 19:59:23 -0700545 unsafe {{
546 same({name} as usize,
Alex Crichton5a284332015-09-13 23:33:33 -0700547 __test_fn_{name}() as usize,
548 "{name} function pointer");
Alex Crichton22378822015-09-10 19:59:23 -0700549 }}
550 }}
551 "#, name = name));
Alex Crichton5a284332015-09-13 23:33:33 -0700552 self.tests.push(format!("fn_{}", name));
Alex Crichton22378822015-09-10 19:59:23 -0700553 }
554
555 fn assert_no_generics(&self, _i: ast::Ident, generics: &ast::Generics) {
556 assert!(generics.lifetimes.len() == 0);
557 assert!(generics.ty_params.len() == 0);
558 assert!(generics.where_clause.predicates.len() == 0);
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700559 }
Alex Crichton0df7c102015-09-10 16:35:37 -0700560
561 fn ty2name(&self, ty: &ast::Ty) -> String {
562 match ty.node {
563 ast::TyPath(_, ref path) => {
564 path.segments.last().unwrap().identifier.to_string()
565 }
566 ast::TyPtr(ref t) => {
567 format!("*{} {}", match t.mutbl {
568 ast::MutImmutable => "const",
569 ast::MutMutable => "mut",
570 }, self.ty2name(&t.ty))
571 }
Alex Crichton22378822015-09-10 19:59:23 -0700572 ast::TyBareFn(ref t) => {
573 assert!(t.lifetimes.len() == 0);
574 let (ret, mut args, variadic) = self.decl2rust(&t.decl);
575 assert!(!variadic);
576 if args.len() == 0 {
577 args.push("void".to_string());
578 }
579 format!("{}(*)({})", ret, args.connect(", "))
580 }
Alex Crichton0df7c102015-09-10 16:35:37 -0700581 _ => panic!("unknown ty {:?}", ty),
582 }
583 }
Alex Crichton22378822015-09-10 19:59:23 -0700584
585 fn decl2rust(&self, decl: &ast::FnDecl) -> (String, Vec<String>, bool) {
586 let args = decl.inputs.iter().map(|arg| {
587 self.ty2name(&arg.ty)
588 }).collect::<Vec<_>>();
589 let ret = match decl.output {
590 ast::NoReturn(..) |
591 ast::DefaultReturn(..) => "void".to_string(),
592 ast::Return(ref t) => self.ty2name(t),
593 };
594 (ret, args, decl.variadic)
595 }
Alex Crichton5a284332015-09-13 23:33:33 -0700596
597 fn emit_run_all(&mut self) {
598 t!(writeln!(self.rust, "
599 fn run_all() {{
600 "));
601 for test in self.tests.iter() {
602 if test.starts_with("fn_") {
603 // FIXME: weird dllimport issues with windows?
604 t!(writeln!(self.rust, "if cfg!(not(windows)) {{ {}(); }}",
605 test));
606 } else {
607 t!(writeln!(self.rust, "{}();", test));
608 }
609 }
610 t!(writeln!(self.rust, "
611 }}
612 "));
613 }
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700614}
615
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700616impl<'a, 'v> Visitor<'v> for TestGenerator<'a> {
Alex Crichton22378822015-09-10 19:59:23 -0700617 fn visit_item(&mut self, i: &'v ast::Item) {
Alex Crichton31504842015-09-10 23:43:41 -0700618 let prev_abi = self.abi;
Alex Crichton22378822015-09-10 19:59:23 -0700619 match i.node {
620 ast::ItemTy(_, ref generics) => {
621 self.assert_no_generics(i.ident, generics);
622 self.test_type(&i.ident.to_string());
623 }
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700624
Alex Crichton22378822015-09-10 19:59:23 -0700625 ast::ItemStruct(ref s, ref generics) => {
626 self.assert_no_generics(i.ident, generics);
627 let is_c = i.attrs.iter().any(|a| {
Alex Crichtona9adfbf2015-09-09 23:21:27 -0700628 attr::find_repr_attrs(self.sh, a).iter().any(|a| {
629 *a == ReprAttr::ReprExtern
630 })
Alex Crichton22378822015-09-10 19:59:23 -0700631 });
632 if !is_c {
633 panic!("{} is not marked #[repr(C)]", i.ident);
634 }
635 self.test_struct(&i.ident.to_string(), s);
636 }
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700637
Alex Crichton22378822015-09-10 19:59:23 -0700638 ast::ItemConst(ref ty, _) => {
639 let ty = self.ty2name(ty);
640 self.test_const(&i.ident.to_string(), &ty);
641 }
Alex Crichton0df7c102015-09-10 16:35:37 -0700642
Alex Crichton31504842015-09-10 23:43:41 -0700643 ast::ItemForeignMod(ref fm) => {
644 self.abi = fm.abi;
645 }
646
Alex Crichton22378822015-09-10 19:59:23 -0700647 _ => {}
648 }
Alex Crichton31504842015-09-10 23:43:41 -0700649 visit::walk_item(self, i);
650 self.abi = prev_abi;
Alex Crichton22378822015-09-10 19:59:23 -0700651 }
652
653 fn visit_foreign_item(&mut self, i: &'v ast::ForeignItem) {
654 match i.node {
655 ast::ForeignItemFn(ref decl, ref generics) => {
656 self.assert_no_generics(i.ident, generics);
657 let (ret, args, variadic) = self.decl2rust(decl);
Alex Crichton7da9b102015-09-10 20:57:14 -0700658 let cname = match attr::first_attr_value_str_by_name(&i.attrs,
659 "link_name") {
660 Some(ref i) if !i.to_string().contains("$") => {
661 i.to_string()
662 }
663 _ => i.ident.to_string(),
664 };
Alex Crichton31504842015-09-10 23:43:41 -0700665 let abi = self.abi;
Alex Crichton7da9b102015-09-10 20:57:14 -0700666 self.test_extern_fn(&i.ident.to_string(), &cname, &args, &ret,
Alex Crichton31504842015-09-10 23:43:41 -0700667 variadic, abi);
Alex Crichton22378822015-09-10 19:59:23 -0700668 }
669 ast::ForeignItemStatic(_, _) => {
670 }
671 }
672 visit::walk_foreign_item(self, i)
673 }
Alex Crichton8e5f0cd2015-09-09 22:46:19 -0700674}
Alex Crichton310d6232015-09-10 10:56:31 -0700675
676impl<'v> Visitor<'v> for StructFinder {
Alex Crichton22378822015-09-10 19:59:23 -0700677 fn visit_item(&mut self, i: &'v ast::Item) {
678 match i.node {
679 ast::ItemStruct(..) => {
680 self.structs.insert(i.ident.to_string());
681 }
682 ast::ItemEnum(..) => {
683 self.structs.insert(i.ident.to_string());
684 }
Alex Crichton310d6232015-09-10 10:56:31 -0700685
Alex Crichton22378822015-09-10 19:59:23 -0700686 _ => {}
687 }
688 visit::walk_item(self, i)
689 }
Alex Crichton310d6232015-09-10 10:56:31 -0700690}