Skip to content

Commit eacd23e

Browse files
committed
preliminary changes - panic & macro partequal need fixing
1 parent 814ebca commit eacd23e

File tree

3 files changed

+486
-0
lines changed

3 files changed

+486
-0
lines changed

tests/auxiliary/minicore.rs

+65
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#![feature(no_core, lang_items, rustc_attrs, decl_macro, naked_functions, f16, f128)]
1818
#![allow(unused, improper_ctypes_definitions, internal_features)]
1919
#![feature(asm_experimental_arch)]
20+
#![feature(intrinsics)]
2021
#![no_std]
2122
#![no_core]
2223

@@ -101,10 +102,74 @@ macro_rules! concat {
101102
/* compiler built-in */
102103
};
103104
}
105+
104106
#[rustc_builtin_macro]
105107
#[macro_export]
106108
macro_rules! stringify {
107109
($($t:tt)*) => {
108110
/* compiler built-in */
109111
};
110112
}
113+
114+
#[macro_export]
115+
macro_rules! panic {
116+
($msg:literal) => {
117+
$crate::panic(&$msg)
118+
};
119+
}
120+
121+
#[rustc_intrinsic]
122+
#[rustc_intrinsic_const_stable_indirect]
123+
#[rustc_intrinsic_must_be_overridden]
124+
pub const fn size_of<T>() -> usize {
125+
loop {}
126+
}
127+
128+
#[rustc_intrinsic]
129+
#[rustc_intrinsic_must_be_overridden]
130+
pub const fn abort() -> ! {
131+
loop {}
132+
}
133+
134+
#[lang = "panic"]
135+
#[rustc_const_panic_str]
136+
#[inline(never)]
137+
#[cold]
138+
#[track_caller]
139+
#[rustc_nounwind]
140+
const fn panic(expr: &&'static str) -> ! {
141+
abort();
142+
}
143+
144+
#[lang = "eq"]
145+
pub trait PartialEq<Rhs: ?Sized = Self> {
146+
fn eq(&self, other: &Rhs) -> bool;
147+
fn ne(&self, other: &Rhs) -> bool {
148+
!self.eq(other)
149+
}
150+
}
151+
152+
impl PartialEq for usize {
153+
fn eq(&self, other: &usize) -> bool {
154+
(*self) == (*other)
155+
}
156+
}
157+
158+
impl PartialEq for bool {
159+
fn eq(&self, other: &bool) -> bool {
160+
(*self) == (*other)
161+
}
162+
}
163+
164+
#[lang = "not"]
165+
pub trait Not {
166+
type Output;
167+
fn not(self) -> Self::Output;
168+
}
169+
170+
impl Not for bool {
171+
type Output = bool;
172+
fn not(self) -> Self {
173+
!self
174+
}
175+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
//@ needs-force-clang-based-tests
2+
3+
//! This test checks that the clang defines for each target allign with the core ffi types
4+
//! defined in `library/core/src/ffi/primitives.rs'.
5+
//! Therefore each rust target is queried and the clang defines for each target
6+
//! are read and compared to the core sizes to verify all types and sizes allign at buildtime.
7+
//!
8+
//! If this test fails because Rust adds a target that Clang does not support, this target should be
9+
//! added to `SKIPPED_TARGETS`.
10+
11+
use run_make_support::{clang, regex, rfs, rustc, serde_json};
12+
use serde_json::Value;
13+
14+
// It is not possible to run the Rust test-suite on these targets.
15+
const SKIPPED_TARGETS: &[&str] = &[
16+
// Clang doesn't have built-in support for the Xtensa architecture
17+
"xtensa-esp32-espidf",
18+
"xtensa-esp32-none-elf",
19+
"xtensa-esp32s2-espidf",
20+
"xtensa-esp32s2-none-elf",
21+
"xtensa-esp32s3-espidf",
22+
"xtensa-esp32s3-none-elf",
23+
// Clang doesn't include built-in support for the C-SKY architecture
24+
"csky-unknown-linux-gnuabiv2",
25+
"csky-unknown-linux-gnuabiv2hf",
26+
// GPU target with different memory model/type system - C type sizes don't map cleanly
27+
"amdgcn-amd-amdhsa",
28+
];
29+
30+
const MAPPED_TARGETS: &[(&str, &str)] = &[
31+
("armv5te-unknown-linux-uclibcgnueabi", "armv5te-unknown-linux"),
32+
("mips-unknown-linux-uclibc", "mips-unknown-linux"),
33+
("mipsel-unknown-linux-uclibc", "mips-unknown-linux"),
34+
("powerpc-unknown-linux-gnuspe", "powerpc-unknown-linux-gnu"),
35+
("powerpc-unknown-linux-muslspe", "powerpc-unknown-linux-musl"),
36+
("x86_64-unknown-l4re-uclibc", "x86_64-unknown-l4re"),
37+
];
38+
39+
fn main() {
40+
let minicore_path = run_make_support::source_root().join("tests/auxiliary/minicore.rs");
41+
42+
preprocess_core_ffi();
43+
44+
let targets_json =
45+
rustc().arg("--print").arg("all-target-specs-json").arg("-Z").arg("unstable-options").run();
46+
let targets_json_str =
47+
String::from_utf8(targets_json.stdout().to_vec()).expect("error not a string");
48+
49+
let j: Value = serde_json::from_str(&targets_json_str).unwrap();
50+
for (target, v) in j.as_object().unwrap() {
51+
let llvm_target = &v["llvm-target"].as_str().unwrap();
52+
53+
if SKIPPED_TARGETS.iter().any(|&to_skip_target| target == to_skip_target) {
54+
continue;
55+
}
56+
57+
// Create a new variable to hold either the mapped target or original llvm_target
58+
let target_to_use = MAPPED_TARGETS
59+
.iter()
60+
.find(|&&(from, _)| from == *llvm_target)
61+
.map(|&(_, to)| to)
62+
.unwrap_or(llvm_target);
63+
64+
// Run Clang's preprocessor for the relevant target, printing default macro definitions.
65+
let clang_output = clang()
66+
.args(&["-nogpulib", "-E", "-dM", "-x", "c", "/dev/null", "-target", &target_to_use])
67+
.run();
68+
69+
let defines = String::from_utf8(clang_output.stdout()).expect("Invalid UTF-8");
70+
71+
let minicore_content = rfs::read_to_string(&minicore_path);
72+
let mut rmake_content = format!(
73+
r#"
74+
#![no_std]
75+
#![no_core]
76+
#![feature(link_cfg)]
77+
#![allow(unused)]
78+
#![crate_type = "rlib"]
79+
80+
/* begin minicore content */
81+
{minicore_content}
82+
/* end minicore content */
83+
84+
/// Vendored from the 'cfg_if' crate
85+
macro_rules! cfg_if {{
86+
// match if/else chains with a final `else`
87+
(
88+
$(
89+
if #[cfg( $i_meta:meta )] {{ $( $i_tokens:tt )* }}
90+
) else+
91+
else {{ $( $e_tokens:tt )* }}
92+
) => {{
93+
cfg_if! {{
94+
@__items () ;
95+
$(
96+
(( $i_meta ) ( $( $i_tokens )* )) ,
97+
)+
98+
(() ( $( $e_tokens )* )) ,
99+
}}
100+
}};
101+
// Internal and recursive macro to emit all the items
102+
//
103+
// Collects all the previous cfgs in a list at the beginning, so they can be
104+
// negated. After the semicolon is all the remaining items.
105+
(@__items ( $( $_:meta , )* ) ; ) => {{}};
106+
(
107+
@__items ( $( $no:meta , )* ) ;
108+
(( $( $yes:meta )? ) ( $( $tokens:tt )* )) ,
109+
$( $rest:tt , )*
110+
) => {{
111+
// Emit all items within one block, applying an appropriate #[cfg]. The
112+
// #[cfg] will require all `$yes` matchers specified and must also negate
113+
// all previous matchers.
114+
#[cfg(all(
115+
$( $yes , )?
116+
not(any( $( $no ),* ))
117+
))]
118+
cfg_if! {{ @__identity $( $tokens )* }}
119+
// Recurse to emit all other items in `$rest`, and when we do so add all
120+
// our `$yes` matchers to the list of `$no` matchers as future emissions
121+
// will have to negate everything we just matched as well.
122+
cfg_if! {{
123+
@__items ( $( $no , )* $( $yes , )? ) ;
124+
$( $rest , )*
125+
}}
126+
}};
127+
// Internal macro to make __apply work out right for different match types,
128+
// because of how macros match/expand stuff.
129+
(@__identity $( $tokens:tt )* ) => {{
130+
$( $tokens )*
131+
}};
132+
}}
133+
134+
#[path = "processed_mod.rs"]
135+
mod ffi;
136+
#[path = "tests.rs"]
137+
mod tests;
138+
"#
139+
);
140+
141+
rmake_content.push_str(&format!(
142+
"
143+
const CLANG_C_CHAR_SIZE: usize = {};
144+
const CLANG_C_CHAR_SIGNED: bool = {};
145+
const CLANG_C_SHORT_SIZE: usize = {};
146+
const CLANG_C_INT_SIZE: usize = {};
147+
const CLANG_C_LONG_SIZE: usize = {};
148+
const CLANG_C_LONGLONG_SIZE: usize = {};
149+
const CLANG_C_FLOAT_SIZE: usize = {};
150+
const CLANG_C_DOUBLE_SIZE: usize = {};
151+
const CLANG_C_SIZE_T_SIZE: usize = {};
152+
const CLANG_C_PTRDIFF_T_SIZE: usize = {};
153+
",
154+
parse_size(&defines, "CHAR"),
155+
char_is_signed(&defines),
156+
parse_size(&defines, "SHORT"),
157+
parse_size(&defines, "INT"),
158+
parse_size(&defines, "LONG"),
159+
parse_size(&defines, "LONG_LONG"),
160+
parse_size(&defines, "FLOAT"),
161+
parse_size(&defines, "DOUBLE"),
162+
parse_size(&defines, "SIZE_T"),
163+
parse_size(&defines, "PTRDIFF_T"),
164+
));
165+
166+
// Generate a target-specific rmake file.
167+
// If type misalignments occur,
168+
// generated rmake file name used to identify the failing target.
169+
let file_name = format!("{}_rmake.rs", target.replace("-", "_").replace(".", "_"));
170+
171+
// Attempt to build the test file for the relevant target.
172+
// Tests use constant evaluation, so running is not necessary.
173+
rfs::write(&file_name, rmake_content);
174+
let rustc_output = rustc()
175+
.arg("-Zunstable-options")
176+
.arg("--emit=metadata")
177+
.arg("--target")
178+
.arg(target)
179+
.arg("-o-")
180+
.arg(&file_name)
181+
.run();
182+
rfs::remove_file(&file_name);
183+
if !rustc_output.status().success() {
184+
panic!("Failed for target {}", target);
185+
}
186+
}
187+
}
188+
189+
// Helper to parse size from clang defines
190+
fn parse_size(defines: &str, type_name: &str) -> usize {
191+
let search_pattern = format!("__SIZEOF_{}__ ", type_name.to_uppercase());
192+
for line in defines.lines() {
193+
if line.contains(&search_pattern) {
194+
if let Some(size_str) = line.split_whitespace().last() {
195+
return size_str.parse().unwrap_or(0);
196+
}
197+
}
198+
}
199+
200+
// Only allow CHAR to default to 1
201+
if type_name.to_uppercase() == "CHAR" {
202+
return 1;
203+
}
204+
205+
panic!("Could not find size definition for type: {}", type_name);
206+
}
207+
208+
fn char_is_signed(defines: &str) -> bool {
209+
!defines.lines().any(|line| line.contains("__CHAR_UNSIGNED__"))
210+
}
211+
212+
/// Parse core/ffi/mod.rs to retrieve only necessary macros and type defines
213+
fn preprocess_core_ffi() {
214+
let mod_path = run_make_support::source_root().join("library/core/src/ffi/primitives.rs");
215+
let mut content = rfs::read_to_string(&mod_path);
216+
217+
//remove stability features #![unstable]
218+
let mut re = regex::Regex::new(r"#!?\[(un)?stable[^]]*?\]").unwrap();
219+
content = re.replace_all(&content, "").to_string();
220+
221+
//remove doc features #[doc...]
222+
re = regex::Regex::new(r"#\[doc[^]]*?\]").unwrap();
223+
content = re.replace_all(&content, "").to_string();
224+
225+
//remove non inline modules
226+
re = regex::Regex::new(r".*mod.*;").unwrap();
227+
content = re.replace_all(&content, "").to_string();
228+
229+
let file_name = "processed_mod.rs";
230+
231+
rfs::write(&file_name, content);
232+
}

0 commit comments

Comments
 (0)