Auto merge of #133059 - workingjubilee:rollup-rc5kvr1, r=workingjubilee

Rollup of 8 pull requests

Successful merges:

 - #132790 (Add as_slice/into_slice for IoSlice/IoSliceMut.)
 - #132905 ([AIX] Add crate "unwind" to link with libunwind)
 - #132977 (Fix compilation error on Solaris due to flock usage)
 - #132984 ([illumos] use pipe2 to create anonymous pipes)
 - #133019 (docs: Fix missing period and colon in methods for primitive types)
 - #133048 (use `&raw` in `{read, write}_unaligned` documentation)
 - #133050 (Always inline functions signatures containing `f16` or `f128`)
 - #133053 (tests: Fix the SIMD FFI tests with certain x86 configuration)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-11-15 03:29:57 +00:00
commit 251dc8ad84
21 changed files with 279 additions and 52 deletions

View File

@ -50,6 +50,16 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
_ => {}
}
let sig = tcx.fn_sig(def_id).instantiate_identity();
for ty in sig.inputs().skip_binder().iter().chain(std::iter::once(&sig.output().skip_binder()))
{
// FIXME(f16_f128): in order to avoid crashes building `core`, always inline to skip
// codegen if the function is not used.
if ty == &tcx.types.f16 || ty == &tcx.types.f128 {
return true;
}
}
// Don't do any inference when incremental compilation is enabled; the additional inlining that
// inference permits also creates more work for small edits.
if tcx.sess.opts.incremental.is_some() {

View File

@ -1258,9 +1258,8 @@ impl f128 {
min <= max,
"min > max, or either was NaN",
"min > max, or either was NaN. min = {min:?}, max = {max:?}",
// FIXME(f16_f128): Passed by-ref to avoid codegen crashes
min: &f128 = &min,
max: &f128 = &max,
min: f128,
max: f128,
);
if self < min {

View File

@ -1235,9 +1235,8 @@ impl f16 {
min <= max,
"min > max, or either was NaN",
"min > max, or either was NaN. min = {min:?}, max = {max:?}",
// FIXME(f16_f128): Passed by-ref to avoid codegen crashes
min: &f16 = &min,
max: &f16 = &max,
min: f16,
max: f16,
);
if self < min {

View File

@ -1300,7 +1300,7 @@ macro_rules! int_impl {
}
}
/// Unbounded shift left. Computes `self << rhs`, without bounding the value of `rhs`
/// Unbounded shift left. Computes `self << rhs`, without bounding the value of `rhs`.
///
/// If `rhs` is larger or equal to the number of bits in `self`,
/// the entire value is shifted out, and `0` is returned.
@ -1423,7 +1423,7 @@ macro_rules! int_impl {
}
}
/// Unbounded shift right. Computes `self >> rhs`, without bounding the value of `rhs`
/// Unbounded shift right. Computes `self >> rhs`, without bounding the value of `rhs`.
///
/// If `rhs` is larger or equal to the number of bits in `self`,
/// the entire value is shifted out, which yields `0` for a positive number,
@ -2389,7 +2389,7 @@ macro_rules! int_impl {
(res, overflowed ^ (rhs < 0))
}
/// Calculates `self` - `rhs`
/// Calculates `self` - `rhs`.
///
/// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow
/// would occur. If an overflow would have occurred then the wrapped value is returned.
@ -2470,7 +2470,7 @@ macro_rules! int_impl {
(c, b != d)
}
/// Calculates `self` - `rhs` with an unsigned `rhs`
/// Calculates `self` - `rhs` with an unsigned `rhs`.
///
/// Returns a tuple of the subtraction along with a boolean indicating
/// whether an arithmetic overflow would occur. If an overflow would

View File

@ -1517,7 +1517,7 @@ macro_rules! uint_impl {
}
}
/// Unbounded shift left. Computes `self << rhs`, without bounding the value of `rhs`
/// Unbounded shift left. Computes `self << rhs`, without bounding the value of `rhs`.
///
/// If `rhs` is larger or equal to the number of bits in `self`,
/// the entire value is shifted out, and `0` is returned.
@ -1640,7 +1640,7 @@ macro_rules! uint_impl {
}
}
/// Unbounded shift right. Computes `self >> rhs`, without bounding the value of `rhs`
/// Unbounded shift right. Computes `self >> rhs`, without bounding the value of `rhs`.
///
/// If `rhs` is larger or equal to the number of bits in `self`,
/// the entire value is shifted out, and `0` is returned.
@ -2299,7 +2299,7 @@ macro_rules! uint_impl {
///
/// # Examples
///
/// Basic usage
/// Basic usage:
///
/// ```
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));")]
@ -2389,7 +2389,7 @@ macro_rules! uint_impl {
(res, overflowed ^ (rhs < 0))
}
/// Calculates `self` - `rhs`
/// Calculates `self` - `rhs`.
///
/// Returns a tuple of the subtraction along with a boolean indicating
/// whether an arithmetic overflow would occur. If an overflow would
@ -2397,7 +2397,7 @@ macro_rules! uint_impl {
///
/// # Examples
///
/// Basic usage
/// Basic usage:
///
/// ```
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false));")]
@ -2550,7 +2550,7 @@ macro_rules! uint_impl {
///
/// # Examples
///
/// Basic usage
/// Basic usage:
///
/// ```
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));")]
@ -2581,7 +2581,7 @@ macro_rules! uint_impl {
///
/// # Examples
///
/// Basic usage
/// Basic usage:
///
/// ```
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false));")]
@ -2609,7 +2609,7 @@ macro_rules! uint_impl {
///
/// # Examples
///
/// Basic usage
/// Basic usage:
///
/// ```
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));")]
@ -2640,7 +2640,7 @@ macro_rules! uint_impl {
///
/// # Examples
///
/// Basic usage
/// Basic usage:
///
/// ```
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false));")]
@ -2664,7 +2664,7 @@ macro_rules! uint_impl {
///
/// # Examples
///
/// Basic usage
/// Basic usage:
///
/// ```
#[doc = concat!("assert_eq!(0", stringify!($SelfT), ".overflowing_neg(), (0, false));")]
@ -2689,7 +2689,7 @@ macro_rules! uint_impl {
///
/// # Examples
///
/// Basic usage
/// Basic usage:
///
/// ```
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(4), (0x10, false));")]
@ -2715,7 +2715,7 @@ macro_rules! uint_impl {
///
/// # Examples
///
/// Basic usage
/// Basic usage:
///
/// ```
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false));")]

View File

@ -1407,9 +1407,8 @@ pub const unsafe fn read<T>(src: *const T) -> T {
/// As a result, using `&packed.unaligned as *const FieldType` causes immediate
/// *undefined behavior* in your program.
///
/// Instead you must use the [`ptr::addr_of!`](addr_of) macro to
/// create the pointer. You may use that returned pointer together with this
/// function.
/// Instead you must use the `&raw const` syntax to create the pointer.
/// You may use that constructed pointer together with this function.
///
/// An example of what not to do and how this relates to `read_unaligned` is:
///
@ -1427,7 +1426,7 @@ pub const unsafe fn read<T>(src: *const T) -> T {
///
/// // Take the address of a 32-bit integer which is not aligned.
/// // In contrast to `&packed.unaligned as *const _`, this has no undefined behavior.
/// let unaligned = std::ptr::addr_of!(packed.unaligned);
/// let unaligned = &raw const packed.unaligned;
///
/// let v = unsafe { std::ptr::read_unaligned(unaligned) };
/// assert_eq!(v, 0x01020304);
@ -1615,9 +1614,8 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) {
/// As a result, using `&packed.unaligned as *const FieldType` causes immediate
/// *undefined behavior* in your program.
///
/// Instead, you must use the [`ptr::addr_of_mut!`](addr_of_mut)
/// macro to create the pointer. You may use that returned pointer together with
/// this function.
/// Instead, you must use the `&raw mut` syntax to create the pointer.
/// You may use that constructed pointer together with this function.
///
/// An example of how to do it and how this relates to `write_unaligned` is:
///
@ -1632,7 +1630,7 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) {
///
/// // Take the address of a 32-bit integer which is not aligned.
/// // In contrast to `&packed.unaligned as *mut _`, this has no undefined behavior.
/// let unaligned = std::ptr::addr_of_mut!(packed.unaligned);
/// let unaligned = &raw mut packed.unaligned;
///
/// unsafe { std::ptr::write_unaligned(unaligned, 42) };
///

View File

@ -2400,7 +2400,7 @@ impl str {
///
/// # Examples
///
/// Basic usage
/// Basic usage:
///
/// ```
/// let four: u32 = "4".parse().unwrap();

View File

@ -204,6 +204,13 @@ fn file_test_io_seek_and_write() {
}
#[test]
#[cfg(any(
windows,
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_vendor = "apple",
))]
fn file_lock_multiple_shared() {
let tmpdir = tmpdir();
let filename = &tmpdir.join("file_lock_multiple_shared_test.txt");
@ -220,6 +227,13 @@ fn file_lock_multiple_shared() {
}
#[test]
#[cfg(any(
windows,
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_vendor = "apple",
))]
fn file_lock_blocking() {
let tmpdir = tmpdir();
let filename = &tmpdir.join("file_lock_blocking_test.txt");
@ -237,6 +251,13 @@ fn file_lock_blocking() {
}
#[test]
#[cfg(any(
windows,
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_vendor = "apple",
))]
fn file_lock_drop() {
let tmpdir = tmpdir();
let filename = &tmpdir.join("file_lock_dup_test.txt");
@ -251,6 +272,13 @@ fn file_lock_drop() {
}
#[test]
#[cfg(any(
windows,
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_vendor = "apple",
))]
fn file_lock_dup() {
let tmpdir = tmpdir();
let filename = &tmpdir.join("file_lock_dup_test.txt");

View File

@ -1340,6 +1340,25 @@ impl<'a> IoSliceMut<'a> {
bufs[0].advance(left);
}
}
/// Get the underlying bytes as a mutable slice with the original lifetime.
///
/// # Examples
///
/// ```
/// #![feature(io_slice_as_bytes)]
/// use std::io::IoSliceMut;
///
/// let mut data = *b"abcdef";
/// let io_slice = IoSliceMut::new(&mut data);
/// io_slice.into_slice()[0] = b'A';
///
/// assert_eq!(&data, b"Abcdef");
/// ```
#[unstable(feature = "io_slice_as_bytes", issue = "132818")]
pub const fn into_slice(self) -> &'a mut [u8] {
self.0.into_slice()
}
}
#[stable(feature = "iovec", since = "1.36.0")]
@ -1482,6 +1501,32 @@ impl<'a> IoSlice<'a> {
bufs[0].advance(left);
}
}
/// Get the underlying bytes as a slice with the original lifetime.
///
/// This doesn't borrow from `self`, so is less restrictive than calling
/// `.deref()`, which does.
///
/// # Examples
///
/// ```
/// #![feature(io_slice_as_bytes)]
/// use std::io::IoSlice;
///
/// let data = b"abcdef";
///
/// let mut io_slice = IoSlice::new(data);
/// let tail = &io_slice.as_slice()[3..];
///
/// // This works because `tail` doesn't borrow `io_slice`
/// io_slice = IoSlice::new(tail);
///
/// assert_eq!(io_slice.as_slice(), b"def");
/// ```
#[unstable(feature = "io_slice_as_bytes", issue = "132818")]
pub const fn as_slice(self) -> &'a [u8] {
self.0.as_slice()
}
}
#[stable(feature = "iovec", since = "1.36.0")]

View File

@ -531,6 +531,20 @@ fn io_slice_advance_slices_beyond_total_length() {
assert!(bufs.is_empty());
}
#[test]
fn io_slice_as_slice() {
let buf = [1; 8];
let slice = IoSlice::new(&buf).as_slice();
assert_eq!(slice, buf);
}
#[test]
fn io_slice_into_slice() {
let mut buf = [1; 8];
let slice = IoSliceMut::new(&mut buf).into_slice();
assert_eq!(slice, [1; 8]);
}
/// Creates a new writer that reads from at most `n_bufs` and reads
/// `per_call` bytes (in total) per call to write.
fn test_writer(n_bufs: usize, per_call: usize) -> TestWriter {

View File

@ -33,7 +33,7 @@ impl<'a> IoSlice<'a> {
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
pub const fn as_slice(&self) -> &'a [u8] {
unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
}
}
@ -70,6 +70,11 @@ impl<'a> IoSliceMut<'a> {
unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
}
#[inline]
pub const fn into_slice(self) -> &'a mut [u8] {
unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }

View File

@ -33,7 +33,7 @@ impl<'a> IoSlice<'a> {
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
pub const fn as_slice(&self) -> &'a [u8] {
unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
}
}
@ -70,6 +70,11 @@ impl<'a> IoSliceMut<'a> {
unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
}
#[inline]
pub const fn into_slice(self) -> &'a mut [u8] {
unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }

View File

@ -1254,16 +1254,54 @@ impl File {
}
}
#[cfg(any(
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_vendor = "apple",
))]
pub fn lock(&self) -> io::Result<()> {
cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_EX) })?;
return Ok(());
}
#[cfg(not(any(
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_vendor = "apple",
)))]
pub fn lock(&self) -> io::Result<()> {
Err(io::const_io_error!(io::ErrorKind::Unsupported, "lock() not supported"))
}
#[cfg(any(
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_vendor = "apple",
))]
pub fn lock_shared(&self) -> io::Result<()> {
cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_SH) })?;
return Ok(());
}
#[cfg(not(any(
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_vendor = "apple",
)))]
pub fn lock_shared(&self) -> io::Result<()> {
Err(io::const_io_error!(io::ErrorKind::Unsupported, "lock_shared() not supported"))
}
#[cfg(any(
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_vendor = "apple",
))]
pub fn try_lock(&self) -> io::Result<bool> {
let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) });
if let Err(ref err) = result {
@ -1275,6 +1313,22 @@ impl File {
return Ok(true);
}
#[cfg(not(any(
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_vendor = "apple",
)))]
pub fn try_lock(&self) -> io::Result<bool> {
Err(io::const_io_error!(io::ErrorKind::Unsupported, "try_lock() not supported"))
}
#[cfg(any(
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_vendor = "apple",
))]
pub fn try_lock_shared(&self) -> io::Result<bool> {
let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_SH | libc::LOCK_NB) });
if let Err(ref err) = result {
@ -1286,11 +1340,37 @@ impl File {
return Ok(true);
}
#[cfg(not(any(
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_vendor = "apple",
)))]
pub fn try_lock_shared(&self) -> io::Result<bool> {
Err(io::const_io_error!(io::ErrorKind::Unsupported, "try_lock_shared() not supported"))
}
#[cfg(any(
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_vendor = "apple",
))]
pub fn unlock(&self) -> io::Result<()> {
cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_UN) })?;
return Ok(());
}
#[cfg(not(any(
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_vendor = "apple",
)))]
pub fn unlock(&self) -> io::Result<()> {
Err(io::const_io_error!(io::ErrorKind::Unsupported, "unlock() not supported"))
}
pub fn truncate(&self, size: u64) -> io::Result<()> {
let size: off64_t =
size.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;

View File

@ -33,7 +33,7 @@ impl<'a> IoSlice<'a> {
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
pub const fn as_slice(&self) -> &'a [u8] {
unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
}
}
@ -70,6 +70,11 @@ impl<'a> IoSliceMut<'a> {
unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
}
#[inline]
pub const fn into_slice(self) -> &'a mut [u8] {
unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }

View File

@ -23,6 +23,7 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
target_os = "dragonfly",
target_os = "freebsd",
target_os = "hurd",
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",

View File

@ -15,7 +15,7 @@ impl<'a> IoSlice<'a> {
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
pub const fn as_slice(&self) -> &'a [u8] {
self.0
}
}
@ -40,6 +40,11 @@ impl<'a> IoSliceMut<'a> {
self.0
}
#[inline]
pub const fn into_slice(self) -> &'a mut [u8] {
self.0
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [u8] {
self.0

View File

@ -30,7 +30,7 @@ impl<'a> IoSlice<'a> {
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
pub const fn as_slice(&self) -> &'a [u8] {
unsafe { slice::from_raw_parts(self.vec.buf as *const u8, self.vec.buf_len) }
}
}
@ -67,6 +67,11 @@ impl<'a> IoSliceMut<'a> {
unsafe { slice::from_raw_parts(self.vec.buf as *const u8, self.vec.buf_len) }
}
#[inline]
pub const fn into_slice(self) -> &'a mut [u8] {
unsafe { slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.buf_len) }
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.buf_len) }

View File

@ -36,7 +36,7 @@ impl<'a> IoSlice<'a> {
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
pub const fn as_slice(&self) -> &'a [u8] {
unsafe { slice::from_raw_parts(self.vec.buf, self.vec.len as usize) }
}
}
@ -74,6 +74,11 @@ impl<'a> IoSliceMut<'a> {
unsafe { slice::from_raw_parts(self.vec.buf, self.vec.len as usize) }
}
#[inline]
pub const fn into_slice(self) -> &'a mut [u8] {
unsafe { slice::from_raw_parts_mut(self.vec.buf, self.vec.len as usize) }
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.vec.buf, self.vec.len as usize) }

View File

@ -0,0 +1,29 @@
//@ revisions: default nopt
//@[nopt] compile-flags: -Copt-level=0 -Zcross-crate-inline-threshold=never -Zmir-opt-level=0 -Cno-prepopulate-passes
// Ensure that functions using `f16` and `f128` are always inlined to avoid crashes
// when the backend does not support these types.
#![crate_type = "lib"]
#![feature(f128)]
#![feature(f16)]
pub fn f16_arg(_a: f16) {
// CHECK-NOT: f16_arg
todo!()
}
pub fn f16_ret() -> f16 {
// CHECK-NOT: f16_ret
todo!()
}
pub fn f128_arg(_a: f128) {
// CHECK-NOT: f128_arg
todo!()
}
pub fn f128_ret() -> f128 {
// CHECK-NOT: f128_ret
todo!()
}

View File

@ -25,7 +25,7 @@ pub struct i32x4([i32; 4]);
extern "C" {
// _mm_sll_epi32
#[cfg(any(target_arch = "x86", target_arch = "x86-64"))]
#[cfg(all(any(target_arch = "x86", target_arch = "x86-64"), target_feature = "sse2"))]
#[link_name = "llvm.x86.sse2.psll.d"]
fn integer(a: i32x4, b: i32x4) -> i32x4;
@ -38,15 +38,13 @@ extern "C" {
#[link_name = "llvm.aarch64.neon.maxs.v4i32"]
fn integer(a: i32x4, b: i32x4) -> i32x4;
// just some substitute foreign symbol, not an LLVM intrinsic; so
// we still get type checking, but not as detailed as (ab)using
// LLVM.
// Use a generic LLVM intrinsic to do type checking on other platforms
#[cfg(not(any(
target_arch = "x86",
target_arch = "x86-64",
all(any(target_arch = "x86", target_arch = "x86-64"), target_feature = "sse2"),
target_arch = "arm",
target_arch = "aarch64"
)))]
#[link_name = "llvm.smax.v4i32"]
fn integer(a: i32x4, b: i32x4) -> i32x4;
}

View File

@ -1,14 +1,10 @@
#![feature(lang_items)]
#![feature(lang_items, panic_unwind)]
#![no_std]
// Since `rustc` generally passes `-nodefaultlibs` to the linker,
// Rust programs link necessary system libraries via `#[link()]`
// attributes in the `libc` crate. `libc` is a dependency of `std`,
// but as we are `#![no_std]`, we need to include it manually.
// Except on windows-msvc.
#![feature(rustc_private)]
#[cfg(not(all(windows, target_env = "msvc")))]
extern crate libc;
// Since the `unwind` crate is a dependency of the `std` crate, and we have
// `#![no_std]`, the unwinder is not included in the link command by default.
// We need to include crate `unwind` manually.
extern crate unwind;
#[panic_handler]
pub fn begin_panic_handler(_info: &core::panic::PanicInfo<'_>) -> ! {