11//@ needs-force-clang-based-tests
2+ // This test checks that the clang defines for each target allign with the core ffi types defined in
3+ // mod.rs. Therefore each rust target is queried and the clang defines for each target are read and
4+ // compared to the core sizes to verify all types and sizes allign at buildtime.
5+ //
6+ // If this test fails because Rust adds a target that Clang does not support, this target should be
7+ // added to SKIPPED_TARGETS.
28
39use run_make_support:: { clang, regex, rfs, rustc} ;
410
11+ // It is not possible to run the Rust test-suite on these targets.
512const SKIPPED_TARGETS : & [ & str ] = & [
6- "riscv" , //error: unknown target triple 'riscv32e-unknown-none-elf'
7- "wasm" , //error: unknown target triple 'wasm32v1-none'
8- "xtensa" , //error: unknown target triple 'xtensa-esp32-espidf'
13+ "riscv32gc-unknown-linux-gnu" ,
14+ "riscv32gc-unknown-linux-musl" ,
15+ "riscv32im-risc0-zkvm-elf" ,
16+ "riscv32imac-esp-espidf" ,
17+ "riscv32imafc-esp-espidf" ,
18+ "riscv32imafc-unknown-nuttx-elf" ,
19+ "riscv32imc-esp-espidf" ,
20+ "riscv32imac-unknown-nuttx-elf" ,
21+ "riscv32imac-unknown-xous-elf" ,
22+ "riscv32imc-unknown-nuttx-elf" ,
23+ "riscv32e-unknown-none-elf" ,
24+ "riscv32em-unknown-none-elf" ,
25+ "riscv32emc-unknown-none-elf" ,
26+ "riscv32i-unknown-none-elf" ,
27+ "riscv32im-unknown-none-elf" ,
28+ "riscv32imc-unknown-none-elf" ,
29+ "riscv32ima-unknown-none-elf" ,
30+ "riscv32imac-unknown-none-elf" ,
31+ "riscv32imafc-unknown-none-elf" ,
32+ "riscv64gc-unknown-freebsd" ,
33+ "riscv64gc-unknown-fuchsia" ,
34+ "riscv64gc-unknown-hermit" ,
35+ "riscv64gc-unknown-linux-gnu" ,
36+ "riscv64gc-unknown-linux-musl" ,
37+ "riscv64gc-unknown-netbsd" ,
38+ "riscv64gc-unknown-none-elf" ,
39+ "riscv64gc-unknown-nuttx-elf" ,
40+ "riscv64gc-unknown-openbsd" ,
41+ "riscv64imac-unknown-none-elf" ,
42+ "riscv64imac-unknown-nuttx-elf" ,
43+ "wasm32v1-none" ,
44+ "xtensa-esp32-espidf" ,
45+ "xtensa-esp32-none-elf" ,
46+ "xtensa-esp32s2-espidf" ,
47+ "xtensa-esp32s2-none-elf" ,
48+ "xtensa-esp32s3-espidf" ,
49+ "xtensa-esp32s3-none-elf" ,
950] ;
1051
1152fn main ( ) {
@@ -16,13 +57,18 @@ fn main() {
1657 regex_mod ( ) ;
1758
1859 for target in targets. lines ( ) {
19- if SKIPPED_TARGETS . iter ( ) . any ( |prefix | target. starts_with ( prefix ) ) {
60+ if SKIPPED_TARGETS . iter ( ) . any ( |& to_skip_target | target == to_skip_target ) {
2061 continue ;
2162 }
2263
64+ // Run Clang's preprocessor for the relevant target, printing default macro definitions.
2365 let clang_output =
2466 clang ( ) . args ( & [ "-E" , "-dM" , "-x" , "c" , "/dev/null" , "-target" , target] ) . run ( ) ;
2567
68+ if !clang_output. status ( ) . success ( ) {
69+ continue ;
70+ }
71+
2672 let defines = String :: from_utf8 ( clang_output. stdout ( ) ) . expect ( "Invalid UTF-8" ) ;
2773
2874 let minicore_content = rfs:: read_to_string ( & minicore_path) ;
@@ -33,13 +79,16 @@ fn main() {
3379 #![feature(link_cfg)]
3480 #![allow(unused)]
3581 #![crate_type = "rlib"]
36- {}
82+
83+ /* begin minicore content */
84+ {minicore_content}
85+ /* end minicore content */
86+
3787 #[path = "processed_mod.rs"]
3888 mod ffi;
3989 #[path = "tests.rs"]
4090 mod tests;
41- "# ,
42- minicore_content
91+ "#
4392 ) ;
4493
4594 rmake_content. push_str ( & format ! (
@@ -54,7 +103,7 @@ fn main() {
54103 const CLANG_C_DOUBLE_SIZE: usize = {};
55104 " ,
56105 parse_size( & defines, "CHAR" ) ,
57- parse_signed ( & defines, "CHAR" ) ,
106+ char_is_signed ( & defines) ,
58107 parse_size( & defines, "SHORT" ) ,
59108 parse_size( & defines, "INT" ) ,
60109 parse_size( & defines, "LONG" ) ,
@@ -63,20 +112,20 @@ fn main() {
63112 parse_size( & defines, "DOUBLE" ) ,
64113 ) ) ;
65114
66- // Write to target-specific rmake file
67- let mut file_name = format ! ( "{}_rmake.rs" , target. replace( "-" , "_" ) ) ;
115+ // Generate a target-specific rmake file.
116+ // If type misalignments occur, use the generated rmake file name to identify the failing target.
117+ // Replace dots (.) and hyphens (-) in the target name with underscores to ensure valid filenames.
118+ let file_name = format ! ( "{}_rmake.rs" , target. replace( "-" , "_" ) . replace( "." , "_" ) ) ;
68119
69- if target. starts_with ( "thumbv8m" ) {
70- file_name = String :: from ( "thumbv8m_rmake.rs" ) ;
71- }
72-
73- rfs:: create_file ( & file_name) ;
120+ // Attempt to build the test file for the relevant target. Tests use constant evaluation,
121+ // so running is not necessary.
74122 rfs:: write ( & file_name, rmake_content) ;
75123 let rustc_output = rustc ( )
76124 . arg ( "-Zunstable-options" )
77125 . arg ( "--emit=metadata" )
78126 . arg ( "--target" )
79127 . arg ( target)
128+ . arg ( "-o-" )
80129 . arg ( & file_name)
81130 . run ( ) ;
82131 rfs:: remove_file ( & file_name) ;
@@ -89,6 +138,7 @@ fn main() {
89138 rfs:: remove_file ( "processed_mod.rs" ) ;
90139}
91140
141+ /// Get a list of available targets for 'rustc'.
92142fn get_target_list ( ) -> String {
93143 let completed_process = rustc ( ) . arg ( "--print" ) . arg ( "target-list" ) . run ( ) ;
94144 String :: from_utf8 ( completed_process. stdout ( ) ) . expect ( "error not a string" )
@@ -113,18 +163,11 @@ fn parse_size(defines: &str, type_name: &str) -> usize {
113163 panic ! ( "Could not find size definition for type: {}" , type_name) ;
114164}
115165
116- // Helper to parse signedness from clang defines
117- fn parse_signed ( defines : & str , type_name : & str ) -> bool {
118- match type_name. to_uppercase ( ) . as_str ( ) {
119- "CHAR" => {
120- // Check if char is explicitly unsigned
121- !defines. lines ( ) . any ( |line| line. contains ( "__CHAR_UNSIGNED__" ) )
122- }
123- _ => true ,
124- }
166+ fn char_is_signed ( defines : & str ) -> bool {
167+ !defines. lines ( ) . any ( |line| line. contains ( "__CHAR_UNSIGNED__" ) )
125168}
126169
127- // Parse core/ffi/mod.rs to retrieve only necessary macros and type defines
170+ /// Parse core/ffi/mod.rs to retrieve only necessary macros and type defines
128171fn regex_mod ( ) {
129172 let mod_path = run_make_support:: source_root ( ) . join ( "library/core/src/ffi/mod.rs" ) ;
130173 let mut content = rfs:: read_to_string ( & mod_path) ;
@@ -157,7 +200,7 @@ fn regex_mod() {
157200 re = regex:: Regex :: new ( r"(?s)impl fmt::Debug for.*?\{.*?\}" ) . unwrap ( ) ;
158201 content = re. replace_all ( & content, "" ) . to_string ( ) ;
159202
160- let file_name = format ! ( "processed_mod.rs" ) ;
203+ let file_name = "processed_mod.rs" ;
161204
162205 rfs:: create_file ( & file_name) ;
163206 rfs:: write ( & file_name, content) ;
0 commit comments