Auto merge of #135959 - matthiaskrgr:rollup-0jenyfw, r=matthiaskrgr

Rollup of 7 pull requests

Successful merges:

 - #135366 (Enable `unreachable_pub` lint in `test` and `proc_macro` crates)
 - #135638 (Make it possible to build GCC on CI)
 - #135648 (support wasm inline assembly in `naked_asm!`)
 - #135827 (CI: free disk with in-tree script instead of GitHub Action)
 - #135855 (Only assert the `Parser` size on specific arches)
 - #135878 (ci: use 8 core arm runner for dist-aarch64-linux)
 - #135905 (Enable kernel sanitizers for aarch64-unknown-none-softfloat)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-01-24 04:45:50 +00:00
commit 48ef38d350
31 changed files with 664 additions and 100 deletions

View File

@ -109,7 +109,7 @@ jobs:
# intensive jobs to run on free runners, which however also have
# less disk space.
- name: free up disk space
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be
run: src/ci/scripts/free-disk-space.sh
if: matrix.free_disk
# Rust Log Analyzer can't currently detect the PR number of a GitHub

View File

@ -1,10 +1,14 @@
use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind};
use rustc_attr_parsing::InstructionSetAttr;
use rustc_hir::def_id::DefId;
use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility};
use rustc_middle::mir::{Body, InlineAsmOperand};
use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf};
use rustc_middle::ty::{Instance, TyCtxt};
use rustc_middle::{bug, ty};
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf};
use rustc_middle::ty::{Instance, Ty, TyCtxt};
use rustc_middle::{bug, span_bug, ty};
use rustc_span::sym;
use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
use rustc_target::spec::WasmCAbi;
use crate::common;
use crate::traits::{AsmCodegenMethods, BuilderMethods, GlobalAsmOperandRef, MiscCodegenMethods};
@ -32,7 +36,8 @@ pub(crate) fn codegen_naked_asm<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let item_data = cx.codegen_unit().items().get(&MonoItem::Fn(instance)).unwrap();
let name = cx.mangled_name(instance);
let (begin, end) = prefix_and_suffix(cx.tcx(), instance, &name, item_data);
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
let (begin, end) = prefix_and_suffix(cx.tcx(), instance, &name, item_data, fn_abi);
let mut template_vec = Vec::new();
template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(begin.into()));
@ -103,6 +108,7 @@ enum AsmBinaryFormat {
Elf,
Macho,
Coff,
Wasm,
}
impl AsmBinaryFormat {
@ -111,6 +117,8 @@ impl AsmBinaryFormat {
Self::Coff
} else if target.is_like_osx {
Self::Macho
} else if target.is_like_wasm {
Self::Wasm
} else {
Self::Elf
}
@ -122,6 +130,7 @@ fn prefix_and_suffix<'tcx>(
instance: Instance<'tcx>,
asm_name: &str,
item_data: &MonoItemData,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
) -> (String, String) {
use std::fmt::Write;
@ -169,7 +178,7 @@ fn prefix_and_suffix<'tcx>(
}
Linkage::LinkOnceAny | Linkage::LinkOnceODR | Linkage::WeakAny | Linkage::WeakODR => {
match asm_binary_format {
AsmBinaryFormat::Elf | AsmBinaryFormat::Coff => {
AsmBinaryFormat::Elf | AsmBinaryFormat::Coff | AsmBinaryFormat::Wasm => {
writeln!(w, ".weak {asm_name}")?;
}
AsmBinaryFormat::Macho => {
@ -264,7 +273,161 @@ fn prefix_and_suffix<'tcx>(
writeln!(end, "{}", arch_suffix).unwrap();
}
}
AsmBinaryFormat::Wasm => {
let section = link_section.unwrap_or(format!(".text.{asm_name}"));
writeln!(begin, ".section {section},\"\",@").unwrap();
// wasm functions cannot be aligned, so skip
write_linkage(&mut begin).unwrap();
if let Visibility::Hidden = item_data.visibility {
writeln!(begin, ".hidden {asm_name}").unwrap();
}
writeln!(begin, ".type {asm_name}, @function").unwrap();
if !arch_prefix.is_empty() {
writeln!(begin, "{}", arch_prefix).unwrap();
}
writeln!(begin, "{asm_name}:").unwrap();
writeln!(
begin,
".functype {asm_name} {}",
wasm_functype(tcx, fn_abi, instance.def_id())
)
.unwrap();
writeln!(end).unwrap();
// .size is ignored for function symbols, so we can skip it
writeln!(end, "end_function").unwrap();
}
}
(begin, end)
}
/// The webassembly type signature for the given function.
///
/// Used by the `.functype` directive on wasm targets.
fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id: DefId) -> String {
let mut signature = String::with_capacity(64);
let ptr_type = match tcx.data_layout.pointer_size.bits() {
32 => "i32",
64 => "i64",
other => bug!("wasm pointer size cannot be {other} bits"),
};
// FIXME: remove this once the wasm32-unknown-unknown ABI is fixed
// please also add `wasm32-unknown-unknown` back in `tests/assembly/wasm32-naked-fn.rs`
// basically the commit introducing this comment should be reverted
if let PassMode::Pair { .. } = fn_abi.ret.mode {
let _ = WasmCAbi::Legacy;
span_bug!(
tcx.def_span(def_id),
"cannot return a pair (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666"
);
}
let hidden_return = matches!(fn_abi.ret.mode, PassMode::Indirect { .. });
signature.push('(');
if hidden_return {
signature.push_str(ptr_type);
if !fn_abi.args.is_empty() {
signature.push_str(", ");
}
}
let mut it = fn_abi.args.iter().peekable();
while let Some(arg_abi) = it.next() {
wasm_type(tcx, &mut signature, arg_abi, ptr_type, def_id);
if it.peek().is_some() {
signature.push_str(", ");
}
}
signature.push_str(") -> (");
if !hidden_return {
wasm_type(tcx, &mut signature, &fn_abi.ret, ptr_type, def_id);
}
signature.push(')');
signature
}
fn wasm_type<'tcx>(
tcx: TyCtxt<'tcx>,
signature: &mut String,
arg_abi: &ArgAbi<'_, Ty<'tcx>>,
ptr_type: &'static str,
def_id: DefId,
) {
match arg_abi.mode {
PassMode::Ignore => { /* do nothing */ }
PassMode::Direct(_) => {
let direct_type = match arg_abi.layout.backend_repr {
BackendRepr::Scalar(scalar) => wasm_primitive(scalar.primitive(), ptr_type),
BackendRepr::Vector { .. } => "v128",
BackendRepr::Memory { .. } => {
// FIXME: remove this branch once the wasm32-unknown-unknown ABI is fixed
let _ = WasmCAbi::Legacy;
span_bug!(
tcx.def_span(def_id),
"cannot use memory args (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666"
);
}
other => unreachable!("unexpected BackendRepr: {:?}", other),
};
signature.push_str(direct_type);
}
PassMode::Pair(_, _) => match arg_abi.layout.backend_repr {
BackendRepr::ScalarPair(a, b) => {
signature.push_str(wasm_primitive(a.primitive(), ptr_type));
signature.push_str(", ");
signature.push_str(wasm_primitive(b.primitive(), ptr_type));
}
other => unreachable!("{other:?}"),
},
PassMode::Cast { pad_i32, ref cast } => {
// For wasm, Cast is used for single-field primitive wrappers like `struct Wrapper(i64);`
assert!(!pad_i32, "not currently used by wasm calling convention");
assert!(cast.prefix[0].is_none(), "no prefix");
assert_eq!(cast.rest.total, arg_abi.layout.size, "single item");
let wrapped_wasm_type = match cast.rest.unit.kind {
RegKind::Integer => match cast.rest.unit.size.bytes() {
..=4 => "i32",
..=8 => "i64",
_ => ptr_type,
},
RegKind::Float => match cast.rest.unit.size.bytes() {
..=4 => "f32",
..=8 => "f64",
_ => ptr_type,
},
RegKind::Vector => "v128",
};
signature.push_str(wrapped_wasm_type);
}
PassMode::Indirect { .. } => signature.push_str(ptr_type),
}
}
fn wasm_primitive(primitive: Primitive, ptr_type: &'static str) -> &'static str {
match primitive {
Primitive::Int(integer, _) => match integer {
Integer::I8 | Integer::I16 | Integer::I32 => "i32",
Integer::I64 => "i64",
Integer::I128 => "i64, i64",
},
Primitive::Float(float) => match float {
Float::F16 | Float::F32 => "f32",
Float::F64 => "f64",
Float::F128 => "i64, i64",
},
Primitive::Pointer(_) => ptr_type,
}
}

View File

@ -189,8 +189,9 @@ pub struct Parser<'a> {
}
// This type is used a lot, e.g. it's cloned when matching many declarative macro rules with
// nonterminals. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_pointer_width = "64", not(target_arch = "s390x")))]
// nonterminals. Make sure it doesn't unintentionally get bigger. We only check a few arches
// though, because `TokenTypeSet(u128)` alignment varies on others, changing the total size.
#[cfg(all(target_pointer_width = "64", any(target_arch = "aarch64", target_arch = "x86_64")))]
rustc_data_structures::static_assert_size!(Parser<'_>, 288);
/// Stores span information about a closure.

View File

@ -7,7 +7,8 @@
// For example, `-C target-cpu=cortex-a53`.
use crate::spec::{
Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, StackProbeType, Target, TargetOptions,
Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType, Target,
TargetOptions,
};
pub(crate) fn target() -> Target {
@ -19,6 +20,7 @@ pub(crate) fn target() -> Target {
relocation_model: RelocModel::Static,
disable_redzone: true,
max_atomic_width: Some(128),
supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS,
stack_probes: StackProbeType::Inline,
panic_strategy: PanicStrategy::Abort,
..Default::default()

View File

@ -3,7 +3,7 @@
use std::marker::PhantomData;
#[repr(C)]
pub struct Closure<'a, A, R> {
pub(super) struct Closure<'a, A, R> {
call: unsafe extern "C" fn(*mut Env, A) -> R,
env: *mut Env,
// Prevent Send and Sync impls. `!Send`/`!Sync` is the usual way of doing
@ -26,7 +26,7 @@ impl<'a, A, R, F: FnMut(A) -> R> From<&'a mut F> for Closure<'a, A, R> {
}
impl<'a, A, R> Closure<'a, A, R> {
pub fn call(&mut self, arg: A) -> R {
pub(super) fn call(&mut self, arg: A) -> R {
unsafe { (self.call)(self.env, arg) }
}
}

View File

@ -9,7 +9,7 @@ use std::hash::{BuildHasherDefault, Hasher};
use std::ops::BitXor;
/// Type alias for a hashmap using the `fx` hash algorithm.
pub type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
pub(super) type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
/// A speedy hash algorithm for use within rustc. The hashmap in alloc by
/// default uses SipHash which isn't quite as speedy as we want. In the compiler
@ -23,7 +23,7 @@ pub type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
/// similar or slightly worse than FNV, but the speed of the hash function
/// itself is much higher because it works on up to 8 bytes at a time.
#[derive(Default)]
pub struct FxHasher {
pub(super) struct FxHasher {
hash: usize,
}

View File

@ -67,7 +67,7 @@ macro_rules! rpc_encode_decode {
mod tag {
#[repr(u8)] enum Tag { $($variant),* }
$(pub const $variant: u8 = Tag::$variant as u8;)*
$(pub(crate) const $variant: u8 = Tag::$variant as u8;)*
}
match self {
@ -89,7 +89,7 @@ macro_rules! rpc_encode_decode {
mod tag {
#[repr(u8)] enum Tag { $($variant),* }
$(pub const $variant: u8 = Tag::$variant as u8;)*
$(pub(crate) const $variant: u8 = Tag::$variant as u8;)*
}
match u8::decode(r, s) {

View File

@ -44,7 +44,7 @@ macro_rules! define_reify_functions {
fn $name:ident $(<$($param:ident),*>)?
for $(extern $abi:tt)? fn($($arg:ident: $arg_ty:ty),*) -> $ret_ty:ty;
)+) => {
$(pub const fn $name<
$(pub(super) const fn $name<
$($($param,)*)?
F: Fn($($arg_ty),*) -> $ret_ty + Copy
>(f: F) -> $(extern $abi)? fn($($arg_ty),*) -> $ret_ty {

View File

@ -32,6 +32,7 @@
#![allow(internal_features)]
#![deny(ffi_unwind_calls)]
#![warn(rustdoc::unescaped_backticks)]
#![warn(unreachable_pub)]
#[unstable(feature = "proc_macro_internals", issue = "27812")]
#[doc(hidden)]

View File

@ -44,7 +44,7 @@ impl TestOpts {
}
/// Result of parsing the options.
pub type OptRes = Result<TestOpts, String>;
pub(crate) type OptRes = Result<TestOpts, String>;
/// Result of parsing the option part.
type OptPartRes<T> = Result<T, String>;

View File

@ -20,7 +20,7 @@ use super::types::{NamePadding, TestDesc, TestDescAndFn};
use super::{filter_tests, run_tests, term};
/// Generic wrapper over stdout.
pub enum OutputLocation<T> {
pub(crate) enum OutputLocation<T> {
Pretty(Box<term::StdoutTerminal>),
Raw(T),
}
@ -41,7 +41,7 @@ impl<T: Write> Write for OutputLocation<T> {
}
}
pub struct ConsoleTestDiscoveryState {
pub(crate) struct ConsoleTestDiscoveryState {
pub log_out: Option<File>,
pub tests: usize,
pub benchmarks: usize,
@ -49,7 +49,7 @@ pub struct ConsoleTestDiscoveryState {
}
impl ConsoleTestDiscoveryState {
pub fn new(opts: &TestOpts) -> io::Result<ConsoleTestDiscoveryState> {
pub(crate) fn new(opts: &TestOpts) -> io::Result<ConsoleTestDiscoveryState> {
let log_out = match opts.logfile {
Some(ref path) => Some(File::create(path)?),
None => None,
@ -58,7 +58,7 @@ impl ConsoleTestDiscoveryState {
Ok(ConsoleTestDiscoveryState { log_out, tests: 0, benchmarks: 0, ignored: 0 })
}
pub fn write_log<F, S>(&mut self, msg: F) -> io::Result<()>
pub(crate) fn write_log<F, S>(&mut self, msg: F) -> io::Result<()>
where
S: AsRef<str>,
F: FnOnce() -> S,
@ -74,7 +74,7 @@ impl ConsoleTestDiscoveryState {
}
}
pub struct ConsoleTestState {
pub(crate) struct ConsoleTestState {
pub log_out: Option<File>,
pub total: usize,
pub passed: usize,
@ -92,7 +92,7 @@ pub struct ConsoleTestState {
}
impl ConsoleTestState {
pub fn new(opts: &TestOpts) -> io::Result<ConsoleTestState> {
pub(crate) fn new(opts: &TestOpts) -> io::Result<ConsoleTestState> {
let log_out = match opts.logfile {
Some(ref path) => Some(File::create(path)?),
None => None,
@ -116,7 +116,7 @@ impl ConsoleTestState {
})
}
pub fn write_log<F, S>(&mut self, msg: F) -> io::Result<()>
pub(crate) fn write_log<F, S>(&mut self, msg: F) -> io::Result<()>
where
S: AsRef<str>,
F: FnOnce() -> S,
@ -131,7 +131,7 @@ impl ConsoleTestState {
}
}
pub fn write_log_result(
pub(crate) fn write_log_result(
&mut self,
test: &TestDesc,
result: &TestResult,
@ -170,7 +170,7 @@ impl ConsoleTestState {
}
// List the tests to console, and optionally to logfile. Filters are honored.
pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> {
pub(crate) fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> {
let output = match term::stdout() {
None => OutputLocation::Raw(io::stdout().lock()),
Some(t) => OutputLocation::Pretty(t),

View File

@ -13,7 +13,7 @@ pub(crate) struct JsonFormatter<T> {
}
impl<T: Write> JsonFormatter<T> {
pub fn new(out: OutputLocation<T>) -> Self {
pub(crate) fn new(out: OutputLocation<T>) -> Self {
Self { out }
}

View File

@ -8,13 +8,13 @@ use crate::test_result::TestResult;
use crate::time;
use crate::types::{TestDesc, TestType};
pub struct JunitFormatter<T> {
pub(crate) struct JunitFormatter<T> {
out: OutputLocation<T>,
results: Vec<(TestDesc, TestResult, Duration, Vec<u8>)>,
}
impl<T: Write> JunitFormatter<T> {
pub fn new(out: OutputLocation<T>) -> Self {
pub(crate) fn new(out: OutputLocation<T>) -> Self {
Self { out, results: Vec::new() }
}

View File

@ -20,7 +20,7 @@ pub(crate) struct PrettyFormatter<T> {
}
impl<T: Write> PrettyFormatter<T> {
pub fn new(
pub(crate) fn new(
out: OutputLocation<T>,
use_color: bool,
max_name_len: usize,
@ -31,19 +31,19 @@ impl<T: Write> PrettyFormatter<T> {
}
#[cfg(test)]
pub fn output_location(&self) -> &OutputLocation<T> {
pub(crate) fn output_location(&self) -> &OutputLocation<T> {
&self.out
}
pub fn write_ok(&mut self) -> io::Result<()> {
pub(crate) fn write_ok(&mut self) -> io::Result<()> {
self.write_short_result("ok", term::color::GREEN)
}
pub fn write_failed(&mut self) -> io::Result<()> {
pub(crate) fn write_failed(&mut self) -> io::Result<()> {
self.write_short_result("FAILED", term::color::RED)
}
pub fn write_ignored(&mut self, message: Option<&'static str>) -> io::Result<()> {
pub(crate) fn write_ignored(&mut self, message: Option<&'static str>) -> io::Result<()> {
if let Some(message) = message {
self.write_short_result(&format!("ignored, {message}"), term::color::YELLOW)
} else {
@ -51,15 +51,15 @@ impl<T: Write> PrettyFormatter<T> {
}
}
pub fn write_time_failed(&mut self) -> io::Result<()> {
pub(crate) fn write_time_failed(&mut self) -> io::Result<()> {
self.write_short_result("FAILED (time limit exceeded)", term::color::RED)
}
pub fn write_bench(&mut self) -> io::Result<()> {
pub(crate) fn write_bench(&mut self) -> io::Result<()> {
self.write_pretty("bench", term::color::CYAN)
}
pub fn write_short_result(
pub(crate) fn write_short_result(
&mut self,
result: &str,
color: term::color::Color,
@ -67,7 +67,7 @@ impl<T: Write> PrettyFormatter<T> {
self.write_pretty(result, color)
}
pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
pub(crate) fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
match self.out {
OutputLocation::Pretty(ref mut term) => {
if self.use_color {
@ -86,7 +86,7 @@ impl<T: Write> PrettyFormatter<T> {
}
}
pub fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> {
pub(crate) fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> {
let s = s.as_ref();
self.out.write_all(s.as_bytes())?;
self.out.flush()
@ -154,15 +154,15 @@ impl<T: Write> PrettyFormatter<T> {
Ok(())
}
pub fn write_successes(&mut self, state: &ConsoleTestState) -> io::Result<()> {
pub(crate) fn write_successes(&mut self, state: &ConsoleTestState) -> io::Result<()> {
self.write_results(&state.not_failures, "successes")
}
pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
pub(crate) fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
self.write_results(&state.failures, "failures")
}
pub fn write_time_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
pub(crate) fn write_time_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
self.write_results(&state.time_failures, "failures (time limit exceeded)")
}

View File

@ -25,7 +25,7 @@ pub(crate) struct TerseFormatter<T> {
}
impl<T: Write> TerseFormatter<T> {
pub fn new(
pub(crate) fn new(
out: OutputLocation<T>,
use_color: bool,
max_name_len: usize,
@ -42,11 +42,11 @@ impl<T: Write> TerseFormatter<T> {
}
}
pub fn write_ok(&mut self) -> io::Result<()> {
pub(crate) fn write_ok(&mut self) -> io::Result<()> {
self.write_short_result(".", term::color::GREEN)
}
pub fn write_failed(&mut self, name: &str) -> io::Result<()> {
pub(crate) fn write_failed(&mut self, name: &str) -> io::Result<()> {
// Put failed tests on their own line and include the test name, so that it's faster
// to see which test failed without having to wait for them all to run.
@ -62,15 +62,15 @@ impl<T: Write> TerseFormatter<T> {
self.write_plain("\n")
}
pub fn write_ignored(&mut self) -> io::Result<()> {
pub(crate) fn write_ignored(&mut self) -> io::Result<()> {
self.write_short_result("i", term::color::YELLOW)
}
pub fn write_bench(&mut self) -> io::Result<()> {
pub(crate) fn write_bench(&mut self) -> io::Result<()> {
self.write_pretty("bench", term::color::CYAN)
}
pub fn write_short_result(
pub(crate) fn write_short_result(
&mut self,
result: &str,
color: term::color::Color,
@ -95,7 +95,7 @@ impl<T: Write> TerseFormatter<T> {
Ok(())
}
pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
pub(crate) fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
match self.out {
OutputLocation::Pretty(ref mut term) => {
if self.use_color {
@ -114,13 +114,13 @@ impl<T: Write> TerseFormatter<T> {
}
}
pub fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> {
pub(crate) fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> {
let s = s.as_ref();
self.out.write_all(s.as_bytes())?;
self.out.flush()
}
pub fn write_outputs(&mut self, state: &ConsoleTestState) -> io::Result<()> {
pub(crate) fn write_outputs(&mut self, state: &ConsoleTestState) -> io::Result<()> {
self.write_plain("\nsuccesses:\n")?;
let mut successes = Vec::new();
let mut stdouts = String::new();
@ -146,7 +146,7 @@ impl<T: Write> TerseFormatter<T> {
Ok(())
}
pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
pub(crate) fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
self.write_plain("\nfailures:\n")?;
let mut failures = Vec::new();
let mut fail_out = String::new();

View File

@ -4,7 +4,7 @@
use std::num::NonZero;
use std::{env, thread};
pub fn get_concurrency() -> usize {
pub(crate) fn get_concurrency() -> usize {
if let Ok(value) = env::var("RUST_TEST_THREADS") {
match value.parse::<NonZero<usize>>().ok() {
Some(n) => n.get(),

View File

@ -1,6 +1,6 @@
//! Module with common helpers not directly related to tests
//! but used in `libtest`.
pub mod concurrency;
pub mod metrics;
pub mod shuffle;
pub(crate) mod concurrency;
pub(crate) mod metrics;
pub(crate) mod shuffle;

View File

@ -4,7 +4,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
use crate::cli::TestOpts;
use crate::types::{TestDescAndFn, TestId, TestName};
pub fn get_shuffle_seed(opts: &TestOpts) -> Option<u64> {
pub(crate) fn get_shuffle_seed(opts: &TestOpts) -> Option<u64> {
opts.shuffle_seed.or_else(|| {
if opts.shuffle {
Some(
@ -19,7 +19,7 @@ pub fn get_shuffle_seed(opts: &TestOpts) -> Option<u64> {
})
}
pub fn shuffle_tests(shuffle_seed: u64, tests: &mut [(TestId, TestDescAndFn)]) {
pub(crate) fn shuffle_tests(shuffle_seed: u64, tests: &mut [(TestId, TestDescAndFn)]) {
let test_names: Vec<&TestName> = tests.iter().map(|test| &test.1.desc.name).collect();
let test_names_hash = calculate_hash(&test_names);
let mut rng = Rng::new(shuffle_seed, test_names_hash);

View File

@ -27,6 +27,7 @@
#![feature(thread_spawn_hook)]
#![allow(internal_features)]
#![warn(rustdoc::unescaped_backticks)]
#![warn(unreachable_pub)]
pub use cli::TestOpts;

View File

@ -2,7 +2,7 @@
/// Number of times to run a benchmarked function
#[derive(Clone, PartialEq, Eq)]
pub enum BenchMode {
pub(crate) enum BenchMode {
Auto,
Single,
}

View File

@ -573,13 +573,13 @@ fn test_sum_f64_between_ints_that_sum_to_0() {
}
#[bench]
pub fn sum_three_items(b: &mut Bencher) {
fn sum_three_items(b: &mut Bencher) {
b.iter(|| {
[1e20f64, 1.5f64, -1e20f64].sum();
})
}
#[bench]
pub fn sum_many_f64(b: &mut Bencher) {
fn sum_many_f64(b: &mut Bencher) {
let nums = [-1e30f64, 1e60, 1e30, 1.0, -1e60];
let v = (0..500).map(|i| nums[i % 5]).collect::<Vec<_>>();
@ -589,4 +589,4 @@ pub fn sum_many_f64(b: &mut Bencher) {
}
#[bench]
pub fn no_iter(_: &mut Bencher) {}
fn no_iter(_: &mut Bencher) {}

View File

@ -62,7 +62,7 @@ pub(crate) mod color {
/// A terminal with similar capabilities to an ANSI Terminal
/// (foreground/background colors etc).
pub trait Terminal: Write {
pub(crate) trait Terminal: Write {
/// Sets the foreground color to the given color.
///
/// If the color is a bright color, but the terminal only supports 8 colors,

View File

@ -12,7 +12,7 @@ use super::types::TestDesc;
// Return code for secondary process.
// Start somewhere other than 0 so we know the return code means what we think
// it means.
pub const TR_OK: i32 = 50;
pub(crate) const TR_OK: i32 = 50;
// On Windows we use __fastfail to abort, which is documented to use this
// exception code.
@ -39,7 +39,7 @@ pub enum TestResult {
/// Creates a `TestResult` depending on the raw result of test execution
/// and associated data.
pub fn calc_result<'a>(
pub(crate) fn calc_result<'a>(
desc: &TestDesc,
task_result: Result<(), &'a (dyn Any + 'static + Send)>,
time_opts: Option<&time::TestTimeOptions>,
@ -93,7 +93,7 @@ pub fn calc_result<'a>(
}
/// Creates a `TestResult` depending on the exit code of test subprocess.
pub fn get_result_from_exit_code(
pub(crate) fn get_result_from_exit_code(
desc: &TestDesc,
status: ExitStatus,
time_opts: Option<&time::TestTimeOptions>,

View File

@ -78,7 +78,7 @@ fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
}
#[test]
pub fn do_not_run_ignored_tests() {
fn do_not_run_ignored_tests() {
fn f() -> Result<(), String> {
panic!();
}
@ -106,7 +106,7 @@ pub fn do_not_run_ignored_tests() {
}
#[test]
pub fn ignored_tests_result_in_ignored() {
fn ignored_tests_result_in_ignored() {
fn f() -> Result<(), String> {
Ok(())
}
@ -479,7 +479,7 @@ fn parse_include_ignored_flag() {
}
#[test]
pub fn filter_for_ignored_option() {
fn filter_for_ignored_option() {
// When we run ignored tests the test filter should filter out all the
// unignored tests and flip the ignore flag on the rest to false
@ -496,7 +496,7 @@ pub fn filter_for_ignored_option() {
}
#[test]
pub fn run_include_ignored_option() {
fn run_include_ignored_option() {
// When we "--include-ignored" tests, the ignore flag should be set to false on
// all tests and no test filtered out
@ -513,7 +513,7 @@ pub fn run_include_ignored_option() {
}
#[test]
pub fn exclude_should_panic_option() {
fn exclude_should_panic_option() {
let mut opts = TestOpts::new();
opts.run_tests = true;
opts.exclude_should_panic = true;
@ -544,7 +544,7 @@ pub fn exclude_should_panic_option() {
}
#[test]
pub fn exact_filter_match() {
fn exact_filter_match() {
fn tests() -> Vec<TestDescAndFn> {
["base", "base::test", "base::test1", "base::test2"]
.into_iter()
@ -667,7 +667,7 @@ fn sample_tests() -> Vec<TestDescAndFn> {
}
#[test]
pub fn shuffle_tests() {
fn shuffle_tests() {
let mut opts = TestOpts::new();
opts.shuffle = true;
@ -686,7 +686,7 @@ pub fn shuffle_tests() {
}
#[test]
pub fn shuffle_tests_with_seed() {
fn shuffle_tests_with_seed() {
let mut opts = TestOpts::new();
opts.shuffle = true;
@ -704,7 +704,7 @@ pub fn shuffle_tests_with_seed() {
}
#[test]
pub fn order_depends_on_more_than_seed() {
fn order_depends_on_more_than_seed() {
let mut opts = TestOpts::new();
opts.shuffle = true;
@ -732,7 +732,7 @@ pub fn order_depends_on_more_than_seed() {
}
#[test]
pub fn test_metricmap_compare() {
fn test_metricmap_compare() {
let mut m1 = MetricMap::new();
let mut m2 = MetricMap::new();
m1.insert_metric("in-both-noise", 1000.0, 200.0);
@ -755,7 +755,7 @@ pub fn test_metricmap_compare() {
}
#[test]
pub fn test_bench_once_no_iter() {
fn test_bench_once_no_iter() {
fn f(_: &mut Bencher) -> Result<(), String> {
Ok(())
}
@ -763,7 +763,7 @@ pub fn test_bench_once_no_iter() {
}
#[test]
pub fn test_bench_once_iter() {
fn test_bench_once_iter() {
fn f(b: &mut Bencher) -> Result<(), String> {
b.iter(|| {});
Ok(())
@ -772,7 +772,7 @@ pub fn test_bench_once_iter() {
}
#[test]
pub fn test_bench_no_iter() {
fn test_bench_no_iter() {
fn f(_: &mut Bencher) -> Result<(), String> {
Ok(())
}
@ -799,7 +799,7 @@ pub fn test_bench_no_iter() {
}
#[test]
pub fn test_bench_iter() {
fn test_bench_iter() {
fn f(b: &mut Bencher) -> Result<(), String> {
b.iter(|| {});
Ok(())

View File

@ -11,7 +11,7 @@ use std::{env, fmt};
use super::types::{TestDesc, TestType};
pub const TEST_WARN_TIMEOUT_S: u64 = 60;
pub(crate) const TEST_WARN_TIMEOUT_S: u64 = 60;
/// This small module contains constants used by `report-time` option.
/// Those constants values will be used if corresponding environment variables are not set.
@ -22,42 +22,42 @@ pub const TEST_WARN_TIMEOUT_S: u64 = 60;
///
/// Example of the expected format is `RUST_TEST_TIME_xxx=100,200`, where 100 means
/// warn time, and 200 means critical time.
pub mod time_constants {
pub(crate) mod time_constants {
use std::time::Duration;
use super::TEST_WARN_TIMEOUT_S;
/// Environment variable for overriding default threshold for unit-tests.
pub const UNIT_ENV_NAME: &str = "RUST_TEST_TIME_UNIT";
pub(crate) const UNIT_ENV_NAME: &str = "RUST_TEST_TIME_UNIT";
// Unit tests are supposed to be really quick.
pub const UNIT_WARN: Duration = Duration::from_millis(50);
pub const UNIT_CRITICAL: Duration = Duration::from_millis(100);
pub(crate) const UNIT_WARN: Duration = Duration::from_millis(50);
pub(crate) const UNIT_CRITICAL: Duration = Duration::from_millis(100);
/// Environment variable for overriding default threshold for unit-tests.
pub const INTEGRATION_ENV_NAME: &str = "RUST_TEST_TIME_INTEGRATION";
pub(crate) const INTEGRATION_ENV_NAME: &str = "RUST_TEST_TIME_INTEGRATION";
// Integration tests may have a lot of work, so they can take longer to execute.
pub const INTEGRATION_WARN: Duration = Duration::from_millis(500);
pub const INTEGRATION_CRITICAL: Duration = Duration::from_millis(1000);
pub(crate) const INTEGRATION_WARN: Duration = Duration::from_millis(500);
pub(crate) const INTEGRATION_CRITICAL: Duration = Duration::from_millis(1000);
/// Environment variable for overriding default threshold for unit-tests.
pub const DOCTEST_ENV_NAME: &str = "RUST_TEST_TIME_DOCTEST";
pub(crate) const DOCTEST_ENV_NAME: &str = "RUST_TEST_TIME_DOCTEST";
// Doctests are similar to integration tests, because they can include a lot of
// initialization code.
pub const DOCTEST_WARN: Duration = INTEGRATION_WARN;
pub const DOCTEST_CRITICAL: Duration = INTEGRATION_CRITICAL;
pub(crate) const DOCTEST_WARN: Duration = INTEGRATION_WARN;
pub(crate) const DOCTEST_CRITICAL: Duration = INTEGRATION_CRITICAL;
// Do not suppose anything about unknown tests, base limits on the
// `TEST_WARN_TIMEOUT_S` constant.
pub const UNKNOWN_WARN: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S);
pub const UNKNOWN_CRITICAL: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S * 2);
pub(crate) const UNKNOWN_WARN: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S);
pub(crate) const UNKNOWN_CRITICAL: Duration = Duration::from_secs(TEST_WARN_TIMEOUT_S * 2);
}
/// Returns an `Instance` object denoting when the test should be considered
/// timed out.
pub fn get_default_test_timeout() -> Instant {
pub(crate) fn get_default_test_timeout() -> Instant {
Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S)
}
@ -73,7 +73,7 @@ impl fmt::Display for TestExecTime {
/// The measured execution time of the whole test suite.
#[derive(Debug, Clone, Default, PartialEq)]
pub struct TestSuiteExecTime(pub Duration);
pub(crate) struct TestSuiteExecTime(pub Duration);
impl fmt::Display for TestSuiteExecTime {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

View File

@ -12,6 +12,8 @@ use std::fs;
use std::path::PathBuf;
use std::sync::OnceLock;
use build_helper::ci::CiEnv;
use crate::Kind;
use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::core::config::TargetSelection;
@ -112,16 +114,60 @@ impl Step for Gcc {
return true;
}
command(root.join("contrib/download_prerequisites")).current_dir(&root).run(builder);
command(root.join("configure"))
// GCC creates files (e.g. symlinks to the downloaded dependencies)
// in the source directory, which does not work with our CI setup, where we mount
// source directories as read-only on Linux.
// Therefore, as a part of the build in CI, we first copy the whole source directory
// to the build directory, and perform the build from there.
let src_dir = if CiEnv::is_ci() {
let src_dir = builder.gcc_out(target).join("src");
if src_dir.exists() {
builder.remove_dir(&src_dir);
}
builder.create_dir(&src_dir);
builder.cp_link_r(&root, &src_dir);
src_dir
} else {
root
};
command(src_dir.join("contrib/download_prerequisites")).current_dir(&src_dir).run(builder);
let mut configure_cmd = command(src_dir.join("configure"));
configure_cmd
.current_dir(&out_dir)
// On CI, we compile GCC with Clang.
// The -Wno-everything flag is needed to make GCC compile with Clang 19.
// `-g -O2` are the default flags that are otherwise used by Make.
// FIXME(kobzol): change the flags once we have [gcc] configuration in config.toml.
.env("CXXFLAGS", "-Wno-everything -g -O2")
.env("CFLAGS", "-Wno-everything -g -O2")
.arg("--enable-host-shared")
.arg("--enable-languages=jit")
.arg("--enable-checking=release")
.arg("--disable-bootstrap")
.arg("--disable-multilib")
.arg(format!("--prefix={}", install_dir.display()))
.run(builder);
.arg(format!("--prefix={}", install_dir.display()));
let cc = builder.build.cc(target).display().to_string();
let cc = builder
.build
.config
.ccache
.as_ref()
.map_or_else(|| cc.clone(), |ccache| format!("{ccache} {cc}"));
configure_cmd.env("CC", cc);
if let Ok(ref cxx) = builder.build.cxx(target) {
let cxx = cxx.display().to_string();
let cxx = builder
.build
.config
.ccache
.as_ref()
.map_or_else(|| cxx.clone(), |ccache| format!("{ccache} {cxx}"));
configure_cmd.env("CXX", cxx);
}
configure_cmd.run(builder);
command("make").current_dir(&out_dir).arg(format!("-j{}", builder.jobs())).run(builder);
command("make").current_dir(&out_dir).arg("install").run(builder);

View File

@ -34,6 +34,7 @@ RUN yum upgrade -y && \
python3 \
unzip \
wget \
flex \
xz \
zlib-devel.i686 \
zlib-devel.x86_64 \

View File

@ -25,5 +25,11 @@ cd zstd-$ZSTD
CFLAGS=-fPIC hide_output make -j$(nproc) VERBOSE=1
hide_output make install
# It doesn't seem to be possible to move destination directory
# of the `make install` above. We thus copy the built artifacts
# manually to our custom rustroot, so that it can be found through
# LD_LIBRARY_PATH.
cp /usr/local/lib/libzstd* /rustroot/lib64
cd ..
rm -rf zstd-$ZSTD

View File

@ -52,6 +52,8 @@ runners:
free_disk: true
os: ubuntu-22.04-arm
- &job-aarch64-linux-8c
os: ubuntu-22.04-arm64-8core-32gb
envs:
env-x86_64-apple-tests: &env-x86_64-apple-tests
SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact
@ -144,7 +146,7 @@ auto:
- name: dist-aarch64-linux
env:
CODEGEN_BACKENDS: llvm,cranelift
<<: *job-aarch64-linux
<<: *job-aarch64-linux-8c
- name: dist-android
<<: *job-linux-4c

142
src/ci/scripts/free-disk-space.sh Executable file
View File

@ -0,0 +1,142 @@
#!/bin/bash
# Free disk space on Linux GitHub action runners
# Script inspired by https://github.com/jlumbroso/free-disk-space
# print a line of the specified character
printSeparationLine() {
for ((i = 0; i < 80; i++)); do
printf "%s" "$1"
done
printf "\n"
}
# compute available space
# REF: https://unix.stackexchange.com/a/42049/60849
# REF: https://stackoverflow.com/a/450821/408734
getAvailableSpace() { echo $(df -a | awk 'NR > 1 {avail+=$4} END {print avail}'); }
# make Kb human readable (assume the input is Kb)
# REF: https://unix.stackexchange.com/a/44087/60849
formatByteCount() { echo $(numfmt --to=iec-i --suffix=B --padding=7 $1'000'); }
# macro to output saved space
printSavedSpace() {
# Disk space before the operation
local before=${1}
local title=${2:-}
local after
after=$(getAvailableSpace)
local saved=$((after - before))
echo ""
printSeparationLine "*"
if [ -n "${title}" ]; then
echo "=> ${title}: Saved $(formatByteCount "$saved")"
else
echo "=> Saved $(formatByteCount "$saved")"
fi
printSeparationLine "*"
echo ""
}
# macro to print output of df with caption
printDF() {
local caption=${1}
printSeparationLine "="
echo "${caption}"
echo ""
echo "$ df -h"
echo ""
df -h
printSeparationLine "="
}
removeDir() {
dir=${1}
local before
before=$(getAvailableSpace)
sudo rm -rf "$dir" || true
printSavedSpace "$before" "$dir"
}
execAndMeasureSpaceChange() {
local operation=${1} # Function to execute
local title=${2}
local before
before=$(getAvailableSpace)
$operation
printSavedSpace "$before" "$title"
}
# Remove large packages
# REF: https://github.com/apache/flink/blob/master/tools/azure-pipelines/free_disk_space.sh
cleanPackages() {
sudo apt-get -qq remove -y --fix-missing \
'^aspnetcore-.*' \
'^dotnet-.*' \
'^llvm-.*' \
'php.*' \
'^mongodb-.*' \
'^mysql-.*' \
'azure-cli' \
'google-chrome-stable' \
'firefox' \
'powershell' \
'mono-devel' \
'libgl1-mesa-dri' \
'google-cloud-sdk' \
'google-cloud-cli'
sudo apt-get autoremove -y || echo "::warning::The command [sudo apt-get autoremove -y] failed"
sudo apt-get clean || echo "::warning::The command [sudo apt-get clean] failed failed"
}
# Remove Docker images
cleanDocker() {
echo "Removing the following docker images:"
sudo docker image ls
echo "Removing docker images..."
sudo docker image prune --all --force || true
}
# Remove Swap storage
cleanSwap() {
sudo swapoff -a || true
sudo rm -rf /mnt/swapfile || true
free -h
}
# Display initial disk space stats
AVAILABLE_INITIAL=$(getAvailableSpace)
printDF "BEFORE CLEAN-UP:"
echo ""
removeDir /usr/local/lib/android
removeDir /usr/share/dotnet
# Haskell runtime
removeDir /opt/ghc
removeDir /usr/local/.ghcup
execAndMeasureSpaceChange cleanPackages "Large misc. packages"
execAndMeasureSpaceChange cleanDocker "Docker images"
execAndMeasureSpaceChange cleanSwap "Swap storage"
# Output saved space statistic
echo ""
printDF "AFTER CLEAN-UP:"
echo ""
echo ""
printSavedSpace "$AVAILABLE_INITIAL" "Total saved"

View File

@ -0,0 +1,199 @@
// FIXME: add wasm32-unknown when the wasm32-unknown-unknown ABI is fixed
// see https://github.com/rust-lang/rust/issues/115666
//@ revisions: wasm64-unknown wasm32-wasip1
//@ add-core-stubs
//@ assembly-output: emit-asm
//@ [wasm64-unknown] compile-flags: --target wasm64-unknown-unknown
//@ [wasm32-wasip1] compile-flags: --target wasm32-wasip1
//@ [wasm64-unknown] needs-llvm-components: webassembly
//@ [wasm32-wasip1] needs-llvm-components: webassembly
#![crate_type = "lib"]
#![feature(no_core, naked_functions, asm_experimental_arch, f128, linkage, fn_align)]
#![no_core]
extern crate minicore;
use minicore::*;
// CHECK: .section .text.nop,"",@
// CHECK: .globl nop
// CHECK-LABEL: nop:
// CHECK: .functype nop () -> ()
// CHECK-NOT: .size
// CHECK: end_function
#[no_mangle]
#[naked]
unsafe extern "C" fn nop() {
naked_asm!("nop")
}
// CHECK: .section .text.weak_aligned_nop,"",@
// CHECK: .weak weak_aligned_nop
// CHECK-LABEL: nop:
// CHECK: .functype weak_aligned_nop () -> ()
// CHECK-NOT: .size
// CHECK: end_function
#[no_mangle]
#[naked]
#[linkage = "weak"]
// wasm functions cannot be aligned, so this has no effect
#[repr(align(32))]
unsafe extern "C" fn weak_aligned_nop() {
naked_asm!("nop")
}
// CHECK-LABEL: fn_i8_i8:
// CHECK-NEXT: .functype fn_i8_i8 (i32) -> (i32)
//
// CHECK-NEXT: local.get 0
// CHECK-NEXT: local.get 0
// CHECK-NEXT: i32.mul
//
// CHECK-NEXT: end_function
#[no_mangle]
#[naked]
unsafe extern "C" fn fn_i8_i8(num: i8) -> i8 {
naked_asm!("local.get 0", "local.get 0", "i32.mul")
}
// CHECK-LABEL: fn_i8_i8_i8:
// CHECK: .functype fn_i8_i8_i8 (i32, i32) -> (i32)
#[no_mangle]
#[naked]
unsafe extern "C" fn fn_i8_i8_i8(a: i8, b: i8) -> i8 {
naked_asm!("local.get 1", "local.get 0", "i32.mul")
}
// CHECK-LABEL: fn_unit_i8:
// CHECK: .functype fn_unit_i8 () -> (i32)
#[no_mangle]
#[naked]
unsafe extern "C" fn fn_unit_i8() -> i8 {
naked_asm!("i32.const 42")
}
// CHECK-LABEL: fn_i8_unit:
// CHECK: .functype fn_i8_unit (i32) -> ()
#[no_mangle]
#[naked]
unsafe extern "C" fn fn_i8_unit(_: i8) {
naked_asm!("nop")
}
// CHECK-LABEL: fn_i32_i32:
// CHECK: .functype fn_i32_i32 (i32) -> (i32)
#[no_mangle]
#[naked]
unsafe extern "C" fn fn_i32_i32(num: i32) -> i32 {
naked_asm!("local.get 0", "local.get 0", "i32.mul")
}
// CHECK-LABEL: fn_i64_i64:
// CHECK: .functype fn_i64_i64 (i64) -> (i64)
#[no_mangle]
#[naked]
unsafe extern "C" fn fn_i64_i64(num: i64) -> i64 {
naked_asm!("local.get 0", "local.get 0", "i64.mul")
}
// CHECK-LABEL: fn_i128_i128:
// wasm32-wasip1: .functype fn_i128_i128 (i32, i64, i64) -> ()
// wasm64-unknown: .functype fn_i128_i128 (i64, i64, i64) -> ()
#[allow(improper_ctypes_definitions)]
#[no_mangle]
#[naked]
unsafe extern "C" fn fn_i128_i128(num: i128) -> i128 {
naked_asm!(
"local.get 0",
"local.get 2",
"i64.store 8",
"local.get 0",
"local.get 1",
"i64.store 0",
)
}
// CHECK-LABEL: fn_f128_f128:
// wasm32-wasip1: .functype fn_f128_f128 (i32, i64, i64) -> ()
// wasm64-unknown: .functype fn_f128_f128 (i64, i64, i64) -> ()
#[no_mangle]
#[naked]
unsafe extern "C" fn fn_f128_f128(num: f128) -> f128 {
naked_asm!(
"local.get 0",
"local.get 2",
"i64.store 8",
"local.get 0",
"local.get 1",
"i64.store 0",
)
}
#[repr(C)]
struct Compound {
a: u16,
b: i64,
}
// CHECK-LABEL: fn_compound_compound:
// wasm32-wasip1: .functype fn_compound_compound (i32, i32) -> ()
// wasm64-unknown: .functype fn_compound_compound (i64, i64) -> ()
#[no_mangle]
#[naked]
unsafe extern "C" fn fn_compound_compound(_: Compound) -> Compound {
// this is the wasm32-wasip1 assembly
naked_asm!(
"local.get 0",
"local.get 1",
"i64.load 8",
"i64.store 8",
"local.get 0",
"local.get 1",
"i32.load16_u 0",
"i32.store16 0",
)
}
#[repr(C)]
struct WrapperI32(i32);
// CHECK-LABEL: fn_wrapperi32_wrapperi32:
// CHECK: .functype fn_wrapperi32_wrapperi32 (i32) -> (i32)
#[no_mangle]
#[naked]
unsafe extern "C" fn fn_wrapperi32_wrapperi32(_: WrapperI32) -> WrapperI32 {
naked_asm!("local.get 0")
}
#[repr(C)]
struct WrapperI64(i64);
// CHECK-LABEL: fn_wrapperi64_wrapperi64:
// CHECK: .functype fn_wrapperi64_wrapperi64 (i64) -> (i64)
#[no_mangle]
#[naked]
unsafe extern "C" fn fn_wrapperi64_wrapperi64(_: WrapperI64) -> WrapperI64 {
naked_asm!("local.get 0")
}
#[repr(C)]
struct WrapperF32(f32);
// CHECK-LABEL: fn_wrapperf32_wrapperf32:
// CHECK: .functype fn_wrapperf32_wrapperf32 (f32) -> (f32)
#[no_mangle]
#[naked]
unsafe extern "C" fn fn_wrapperf32_wrapperf32(_: WrapperF32) -> WrapperF32 {
naked_asm!("local.get 0")
}
#[repr(C)]
struct WrapperF64(f64);
// CHECK-LABEL: fn_wrapperf64_wrapperf64:
// CHECK: .functype fn_wrapperf64_wrapperf64 (f64) -> (f64)
#[no_mangle]
#[naked]
unsafe extern "C" fn fn_wrapperf64_wrapperf64(_: WrapperF64) -> WrapperF64 {
naked_asm!("local.get 0")
}