Skip to content

Commit 91e970f

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

File tree

3 files changed

+487
-0
lines changed

3 files changed

+487
-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,233 @@
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+
// These targets are mapped because clang doesn't recognize the left-side variants
31+
const MAPPED_TARGETS: &[(&str, &str)] = &[
32+
("armv5te-unknown-linux-uclibcgnueabi", "armv5te-unknown-linux"),
33+
("mips-unknown-linux-uclibc", "mips-unknown-linux"),
34+
("mipsel-unknown-linux-uclibc", "mips-unknown-linux"),
35+
("powerpc-unknown-linux-gnuspe", "powerpc-unknown-linux-gnu"),
36+
("powerpc-unknown-linux-muslspe", "powerpc-unknown-linux-musl"),
37+
("x86_64-unknown-l4re-uclibc", "x86_64-unknown-l4re"),
38+
];
39+
40+
fn main() {
41+
let minicore_path = run_make_support::source_root().join("tests/auxiliary/minicore.rs");
42+
43+
preprocess_core_ffi();
44+
45+
let targets_json =
46+
rustc().arg("--print").arg("all-target-specs-json").arg("-Z").arg("unstable-options").run();
47+
let targets_json_str =
48+
String::from_utf8(targets_json.stdout().to_vec()).expect("error not a string");
49+
50+
let j: Value = serde_json::from_str(&targets_json_str).unwrap();
51+
for (target, v) in j.as_object().unwrap() {
52+
let llvm_target = &v["llvm-target"].as_str().unwrap();
53+
54+
if SKIPPED_TARGETS.iter().any(|&to_skip_target| target == to_skip_target) {
55+
continue;
56+
}
57+
58+
// Create a new variable to hold either the mapped target or original llvm_target
59+
let target_to_use = MAPPED_TARGETS
60+
.iter()
61+
.find(|&&(from, _)| from == *llvm_target)
62+
.map(|&(_, to)| to)
63+
.unwrap_or(llvm_target);
64+
65+
// Run Clang's preprocessor for the relevant target, printing default macro definitions.
66+
let clang_output = clang()
67+
.args(&["-nogpulib", "-E", "-dM", "-x", "c", "/dev/null", "-target", &target_to_use])
68+
.run();
69+
70+
let defines = String::from_utf8(clang_output.stdout()).expect("Invalid UTF-8");
71+
72+
let minicore_content = rfs::read_to_string(&minicore_path);
73+
let mut rmake_content = format!(
74+
r#"
75+
#![no_std]
76+
#![no_core]
77+
#![feature(link_cfg)]
78+
#![allow(unused)]
79+
#![crate_type = "rlib"]
80+
81+
/* begin minicore content */
82+
{minicore_content}
83+
/* end minicore content */
84+
85+
/// Vendored from the 'cfg_if' crate
86+
macro_rules! cfg_if {{
87+
// match if/else chains with a final `else`
88+
(
89+
$(
90+
if #[cfg( $i_meta:meta )] {{ $( $i_tokens:tt )* }}
91+
) else+
92+
else {{ $( $e_tokens:tt )* }}
93+
) => {{
94+
cfg_if! {{
95+
@__items () ;
96+
$(
97+
(( $i_meta ) ( $( $i_tokens )* )) ,
98+
)+
99+
(() ( $( $e_tokens )* )) ,
100+
}}
101+
}};
102+
// Internal and recursive macro to emit all the items
103+
//
104+
// Collects all the previous cfgs in a list at the beginning, so they can be
105+
// negated. After the semicolon is all the remaining items.
106+
(@__items ( $( $_:meta , )* ) ; ) => {{}};
107+
(
108+
@__items ( $( $no:meta , )* ) ;
109+
(( $( $yes:meta )? ) ( $( $tokens:tt )* )) ,
110+
$( $rest:tt , )*
111+
) => {{
112+
// Emit all items within one block, applying an appropriate #[cfg]. The
113+
// #[cfg] will require all `$yes` matchers specified and must also negate
114+
// all previous matchers.
115+
#[cfg(all(
116+
$( $yes , )?
117+
not(any( $( $no ),* ))
118+
))]
119+
cfg_if! {{ @__identity $( $tokens )* }}
120+
// Recurse to emit all other items in `$rest`, and when we do so add all
121+
// our `$yes` matchers to the list of `$no` matchers as future emissions
122+
// will have to negate everything we just matched as well.
123+
cfg_if! {{
124+
@__items ( $( $no , )* $( $yes , )? ) ;
125+
$( $rest , )*
126+
}}
127+
}};
128+
// Internal macro to make __apply work out right for different match types,
129+
// because of how macros match/expand stuff.
130+
(@__identity $( $tokens:tt )* ) => {{
131+
$( $tokens )*
132+
}};
133+
}}
134+
135+
#[path = "processed_mod.rs"]
136+
mod ffi;
137+
#[path = "tests.rs"]
138+
mod tests;
139+
"#
140+
);
141+
142+
rmake_content.push_str(&format!(
143+
"
144+
const CLANG_C_CHAR_SIZE: usize = {};
145+
const CLANG_C_CHAR_SIGNED: bool = {};
146+
const CLANG_C_SHORT_SIZE: usize = {};
147+
const CLANG_C_INT_SIZE: usize = {};
148+
const CLANG_C_LONG_SIZE: usize = {};
149+
const CLANG_C_LONGLONG_SIZE: usize = {};
150+
const CLANG_C_FLOAT_SIZE: usize = {};
151+
const CLANG_C_DOUBLE_SIZE: usize = {};
152+
const CLANG_C_SIZE_T_SIZE: usize = {};
153+
const CLANG_C_PTRDIFF_T_SIZE: usize = {};
154+
",
155+
parse_size(&defines, "CHAR"),
156+
char_is_signed(&defines),
157+
parse_size(&defines, "SHORT"),
158+
parse_size(&defines, "INT"),
159+
parse_size(&defines, "LONG"),
160+
parse_size(&defines, "LONG_LONG"),
161+
parse_size(&defines, "FLOAT"),
162+
parse_size(&defines, "DOUBLE"),
163+
parse_size(&defines, "SIZE_T"),
164+
parse_size(&defines, "PTRDIFF_T"),
165+
));
166+
167+
// Generate a target-specific rmake file.
168+
// If type misalignments occur,
169+
// generated rmake file name used to identify the failing target.
170+
let file_name = format!("{}_rmake.rs", target.replace("-", "_").replace(".", "_"));
171+
172+
// Attempt to build the test file for the relevant target.
173+
// Tests use constant evaluation, so running is not necessary.
174+
rfs::write(&file_name, rmake_content);
175+
let rustc_output = rustc()
176+
.arg("-Zunstable-options")
177+
.arg("--emit=metadata")
178+
.arg("--target")
179+
.arg(target)
180+
.arg("-o-")
181+
.arg(&file_name)
182+
.run();
183+
rfs::remove_file(&file_name);
184+
if !rustc_output.status().success() {
185+
panic!("Failed for target {}", target);
186+
}
187+
}
188+
}
189+
190+
// Helper to parse size from clang defines
191+
fn parse_size(defines: &str, type_name: &str) -> usize {
192+
let search_pattern = format!("__SIZEOF_{}__ ", type_name.to_uppercase());
193+
for line in defines.lines() {
194+
if line.contains(&search_pattern) {
195+
if let Some(size_str) = line.split_whitespace().last() {
196+
return size_str.parse().unwrap_or(0);
197+
}
198+
}
199+
}
200+
201+
// Only allow CHAR to default to 1
202+
if type_name.to_uppercase() == "CHAR" {
203+
return 1;
204+
}
205+
206+
panic!("Could not find size definition for type: {}", type_name);
207+
}
208+
209+
fn char_is_signed(defines: &str) -> bool {
210+
!defines.lines().any(|line| line.contains("__CHAR_UNSIGNED__"))
211+
}
212+
213+
/// Parse core/ffi/mod.rs to retrieve only necessary macros and type defines
214+
fn preprocess_core_ffi() {
215+
let mod_path = run_make_support::source_root().join("library/core/src/ffi/primitives.rs");
216+
let mut content = rfs::read_to_string(&mod_path);
217+
218+
//remove stability features #![unstable]
219+
let mut re = regex::Regex::new(r"#!?\[(un)?stable[^]]*?\]").unwrap();
220+
content = re.replace_all(&content, "").to_string();
221+
222+
//remove doc features #[doc...]
223+
re = regex::Regex::new(r"#\[doc[^]]*?\]").unwrap();
224+
content = re.replace_all(&content, "").to_string();
225+
226+
//remove non inline modules
227+
re = regex::Regex::new(r".*mod.*;").unwrap();
228+
content = re.replace_all(&content, "").to_string();
229+
230+
let file_name = "processed_mod.rs";
231+
232+
rfs::write(&file_name, content);
233+
}

0 commit comments

Comments
 (0)