From c03d10c3264b5518de8d2296e403aa50447622f0 Mon Sep 17 00:00:00 2001 From: Frank Steffahn Date: Fri, 22 Jul 2022 01:35:39 +0200 Subject: [PATCH 01/10] Remove redundant lifetime bound from `impl Borrow for Cow` The lifetime bound `B::Owned: 'a` is redundant and doesn't make a difference, because `Cow<'a, B>` comes with an implicit `B: 'a`, and associated types will outlive lifetimes outlived by the `Self` type (and all the trait's generic parameters, of which there are none in this case), so the implicit `B: 'a` implies `B::Owned: 'a` anyway. The explicit lifetime bound here does however end up in documentation, and that's confusing in my opinion, so let's remove it ^^ --- library/alloc/src/borrow.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index 904a53bb4acc7..83a1385599bec 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -21,7 +21,6 @@ use Cow::*; impl<'a, B: ?Sized> Borrow for Cow<'a, B> where B: ToOwned, - ::Owned: 'a, { fn borrow(&self) -> &B { &**self From 093b075d327d1c7c7e0730e46f1d5c2d4aa47f5a Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sun, 2 Oct 2022 17:31:43 +0200 Subject: [PATCH 02/10] rustc: Use `unix_sigpipe` instead of `rustc_driver::set_sigpipe_handler` This is the first (known) step towards starting to use `unix_sigpipe` in the wild. Eventually, `rustc_driver::set_sigpipe_handler` can be removed and all clients can use `unix_sigpipe` instead. For now we just start using `unix_sigpipe` in once place: `rustc` itself. It is easy to manually verify this change. If you remove `#[unix_sigpipe = "sig_dfl"]` and run `./x.py build` you will get an ICE when you do `./build/x86_64-unknown-linux-gnu/stage1/bin/rustc --help | false`. Add back `#[unix_sigpipe = "sig_dfl"]` and the ICE disappears again. --- compiler/rustc/src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs index 0de1a78191353..e21c9b6604440 100644 --- a/compiler/rustc/src/main.rs +++ b/compiler/rustc/src/main.rs @@ -1,3 +1,5 @@ +#![feature(unix_sigpipe)] + // A note about jemalloc: rustc uses jemalloc when built for CI and // distribution. The obvious way to do this is with the `#[global_allocator]` // mechanism. However, for complicated reasons (see @@ -23,6 +25,7 @@ // libraries. So we must reference jemalloc symbols one way or another, because // this file is the only object code in the rustc executable. +#[unix_sigpipe = "sig_dfl"] fn main() { // See the comment at the top of this file for an explanation of this. #[cfg(feature = "jemalloc-sys")] @@ -58,6 +61,5 @@ fn main() { } } - rustc_driver::set_sigpipe_handler(); rustc_driver::main() } From 2618f7ae04bb458f53fc8fe4c40b54a9377ce0bb Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Thu, 6 Oct 2022 20:35:58 -0700 Subject: [PATCH 03/10] Don't needless link to `libresolv` on Darwin in libstd --- library/std/src/sys/unix/mod.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index c84e292eac152..c84e9e0d43b60 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -352,16 +352,12 @@ cfg_if::cfg_if! { extern "C" {} } else if #[cfg(target_os = "macos")] { #[link(name = "System")] - // res_init and friends require -lresolv on macOS/iOS. - // See #41582 and https://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html - #[link(name = "resolv")] extern "C" {} } else if #[cfg(any(target_os = "ios", target_os = "watchos"))] { #[link(name = "System")] #[link(name = "objc")] #[link(name = "Security", kind = "framework")] #[link(name = "Foundation", kind = "framework")] - #[link(name = "resolv")] extern "C" {} } else if #[cfg(target_os = "fuchsia")] { #[link(name = "zircon")] From 7280f3d28aa139cec0c75072a3e66294b7f99b59 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 21 Oct 2022 17:44:35 -0700 Subject: [PATCH 04/10] Truncate thread names on Linux and Apple targets These targets have system limits on the thread names, 16 and 64 bytes respectively, and `pthread_setname_np` returns an error if the name is longer. However, we're not in a context that can propagate errors when we call this, and we used to implicitly truncate on Linux with `prctl`, so now we manually truncate these names ahead of time. --- library/std/src/sys/unix/thread.rs | 43 ++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 42ac6fcd8bf36..6a533854fad3d 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -132,8 +132,11 @@ impl Thread { #[cfg(target_os = "linux")] pub fn set_name(name: &CStr) { + const TASK_COMM_LEN: usize = 16; + unsafe { // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20. + let name = truncate_cstr(name, TASK_COMM_LEN); libc::pthread_setname_np(libc::pthread_self(), name.as_ptr()); } } @@ -148,6 +151,7 @@ impl Thread { #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] pub fn set_name(name: &CStr) { unsafe { + let name = truncate_cstr(name, libc::MAXTHREADNAMESIZE); libc::pthread_setname_np(name.as_ptr()); } } @@ -276,6 +280,20 @@ impl Drop for Thread { } } +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios", target_os = "watchos"))] +fn truncate_cstr(cstr: &CStr, max_with_nul: usize) -> crate::borrow::Cow<'_, CStr> { + use crate::{borrow::Cow, ffi::CString}; + + if cstr.to_bytes_with_nul().len() > max_with_nul { + let bytes = cstr.to_bytes()[..max_with_nul - 1].to_vec(); + // SAFETY: the non-nul bytes came straight from a CStr. + // (CString will add the terminating nul.) + Cow::Owned(unsafe { CString::from_vec_unchecked(bytes) }) + } else { + Cow::Borrowed(cstr) + } +} + pub fn available_parallelism() -> io::Result { cfg_if::cfg_if! { if #[cfg(any( @@ -902,3 +920,28 @@ fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { 2048 // just a guess } + +#[test] +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios", target_os = "watchos"))] +fn test_named_thread_truncation() { + use crate::thread::{self, Builder}; + + let long_name = crate::iter::once("test_named_thread_truncation") + .chain(crate::iter::repeat(" yada").take(100)) + .collect::(); + + let result = Builder::new().name(long_name.clone()).spawn(move || { + // Rust remembers the full thread name itself. + assert_eq!(thread::current().name(), Some(long_name.as_str())); + + // But the kernel is limited -- make sure we successfully set a truncation. + let mut buf = vec![0u8; long_name.len() + 1]; + unsafe { + libc::pthread_getname_np(libc::pthread_self(), buf.as_mut_ptr().cast(), buf.len()); + } + let cstr = CStr::from_bytes_until_nul(&buf).unwrap(); + assert!(cstr.to_bytes().len() > 0); + assert!(long_name.as_bytes().starts_with(cstr.to_bytes())); + }); + result.unwrap().join().unwrap(); +} From 12e45846ebbc32bd6a56f2de2658d3d9ad459032 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 21 Oct 2022 18:13:22 -0700 Subject: [PATCH 05/10] Move truncation next to other thread tests for tidy --- library/std/src/sys/unix/thread.rs | 25 ------------------------- library/std/src/thread/tests.rs | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 6a533854fad3d..69cd2b500a1f0 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -920,28 +920,3 @@ fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { 2048 // just a guess } - -#[test] -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios", target_os = "watchos"))] -fn test_named_thread_truncation() { - use crate::thread::{self, Builder}; - - let long_name = crate::iter::once("test_named_thread_truncation") - .chain(crate::iter::repeat(" yada").take(100)) - .collect::(); - - let result = Builder::new().name(long_name.clone()).spawn(move || { - // Rust remembers the full thread name itself. - assert_eq!(thread::current().name(), Some(long_name.as_str())); - - // But the kernel is limited -- make sure we successfully set a truncation. - let mut buf = vec![0u8; long_name.len() + 1]; - unsafe { - libc::pthread_getname_np(libc::pthread_self(), buf.as_mut_ptr().cast(), buf.len()); - } - let cstr = CStr::from_bytes_until_nul(&buf).unwrap(); - assert!(cstr.to_bytes().len() > 0); - assert!(long_name.as_bytes().starts_with(cstr.to_bytes())); - }); - result.unwrap().join().unwrap(); -} diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index dfb8765ab4eed..71eb41cd564db 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -37,6 +37,31 @@ fn test_named_thread() { .unwrap(); } +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[test] +fn test_named_thread_truncation() { + use crate::ffi::CStr; + + let long_name = crate::iter::once("test_named_thread_truncation") + .chain(crate::iter::repeat(" yada").take(100)) + .collect::(); + + let result = Builder::new().name(long_name.clone()).spawn(move || { + // Rust remembers the full thread name itself. + assert_eq!(thread::current().name(), Some(long_name.as_str())); + + // But the system is limited -- make sure we successfully set a truncation. + let mut buf = vec![0u8; long_name.len() + 1]; + unsafe { + libc::pthread_getname_np(libc::pthread_self(), buf.as_mut_ptr().cast(), buf.len()); + } + let cstr = CStr::from_bytes_until_nul(&buf).unwrap(); + assert!(cstr.to_bytes().len() > 0); + assert!(long_name.as_bytes().starts_with(cstr.to_bytes())); + }); + result.unwrap().join().unwrap(); +} + #[test] #[should_panic] fn test_invalid_named_thread() { From 988e75bb65f688d76f4f80e0fb72ef21e831d0b0 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 6 Apr 2022 11:21:10 +1000 Subject: [PATCH 06/10] Stabilize arbitrary_enum_discriminant, take 2 --- compiler/rustc_ast_passes/src/feature_gate.rs | 62 +------------------ .../src/error_codes/E0732.md | 4 -- compiler/rustc_feature/src/accepted.rs | 2 + compiler/rustc_feature/src/active.rs | 2 - .../rustc_hir_analysis/src/check/check.rs | 2 +- .../arbitrary-enum-discriminant.md | 37 ----------- src/test/ui/cast/issue-88621.rs | 2 - .../arbitrary_enum_discriminant-no-repr.rs | 1 - .../arbitrary_enum_discriminant.rs | 2 +- .../enum-discriminant/discriminant_value.rs | 2 +- ...eature-gate-arbitrary_enum_discriminant.rs | 10 --- ...re-gate-arbitrary_enum_discriminant.stderr | 36 ----------- .../issue-70453-generics-in-discr-ice-2.rs | 2 +- .../issue-70453-polymorphic-ctfe.rs | 2 +- .../issue-70509-partial_eq.rs | 2 +- .../issue-70509-partial_eq.stderr | 2 +- .../intrinsics/panic-uninitialized-zeroed.rs | 2 +- src/test/ui/macros/macros-nonfatal-errors.rs | 2 +- src/test/ui/parser/issues/issue-17383.rs | 7 --- src/test/ui/parser/issues/issue-17383.stderr | 15 ----- .../ui/parser/tag-variant-disr-non-nullary.rs | 12 ---- .../tag-variant-disr-non-nullary.stderr | 25 -------- 22 files changed, 12 insertions(+), 221 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/arbitrary-enum-discriminant.md delete mode 100644 src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.rs delete mode 100644 src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.stderr delete mode 100644 src/test/ui/parser/issues/issue-17383.rs delete mode 100644 src/test/ui/parser/issues/issue-17383.stderr delete mode 100644 src/test/ui/parser/tag-variant-disr-non-nullary.rs delete mode 100644 src/test/ui/parser/tag-variant-disr-non-nullary.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 0f11c1766528a..546010135a725 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -1,7 +1,7 @@ use rustc_ast as ast; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId}; -use rustc_ast::{PatKind, RangeEnd, VariantData}; +use rustc_ast::{PatKind, RangeEnd}; use rustc_errors::{struct_span_err, Applicability, StashKey}; use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP}; use rustc_session::parse::{feature_err, feature_err_issue, feature_warn}; @@ -116,46 +116,6 @@ impl<'a> PostExpansionVisitor<'a> { } } - fn maybe_report_invalid_custom_discriminants(&self, variants: &[ast::Variant]) { - let has_fields = variants.iter().any(|variant| match variant.data { - VariantData::Tuple(..) | VariantData::Struct(..) => true, - VariantData::Unit(..) => false, - }); - - let discriminant_spans = variants - .iter() - .filter(|variant| match variant.data { - VariantData::Tuple(..) | VariantData::Struct(..) => false, - VariantData::Unit(..) => true, - }) - .filter_map(|variant| variant.disr_expr.as_ref().map(|c| c.value.span)) - .collect::>(); - - if !discriminant_spans.is_empty() && has_fields { - let mut err = feature_err( - &self.sess.parse_sess, - sym::arbitrary_enum_discriminant, - discriminant_spans.clone(), - "custom discriminant values are not allowed in enums with tuple or struct variants", - ); - for sp in discriminant_spans { - err.span_label(sp, "disallowed custom discriminant"); - } - for variant in variants.iter() { - match &variant.data { - VariantData::Struct(..) => { - err.span_label(variant.span, "struct variant defined here"); - } - VariantData::Tuple(..) => { - err.span_label(variant.span, "tuple variant defined here"); - } - VariantData::Unit(..) => {} - } - } - err.emit(); - } - } - /// Feature gate `impl Trait` inside `type Alias = $type_expr;`. fn check_impl_trait(&self, ty: &ast::Ty) { struct ImplTraitVisitor<'a> { @@ -273,26 +233,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } - ast::ItemKind::Enum(ast::EnumDef { ref variants, .. }, ..) => { - for variant in variants { - match (&variant.data, &variant.disr_expr) { - (ast::VariantData::Unit(..), _) => {} - (_, Some(disr_expr)) => gate_feature_post!( - &self, - arbitrary_enum_discriminant, - disr_expr.value.span, - "discriminants on non-unit variants are experimental" - ), - _ => {} - } - } - - let has_feature = self.features.arbitrary_enum_discriminant; - if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) { - self.maybe_report_invalid_custom_discriminants(&variants); - } - } - ast::ItemKind::Impl(box ast::Impl { polarity, defaultness, ref of_trait, .. }) => { if let ast::ImplPolarity::Negative(span) = polarity { gate_feature_post!( diff --git a/compiler/rustc_error_codes/src/error_codes/E0732.md b/compiler/rustc_error_codes/src/error_codes/E0732.md index 7347e6654c5b3..9536fdbf0df87 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0732.md +++ b/compiler/rustc_error_codes/src/error_codes/E0732.md @@ -3,8 +3,6 @@ An `enum` with a discriminant must specify a `#[repr(inttype)]`. Erroneous code example: ```compile_fail,E0732 -#![feature(arbitrary_enum_discriminant)] - enum Enum { // error! Unit = 1, Tuple() = 2, @@ -20,8 +18,6 @@ is a well-defined way to extract a variant's discriminant from a value; for instance: ``` -#![feature(arbitrary_enum_discriminant)] - #[repr(u8)] enum Enum { Unit = 3, diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 54bf5a2c34b82..db289a64046a7 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -53,6 +53,8 @@ declare_features! ( (accepted, abi_sysv64, "1.24.0", Some(36167), None), /// Allows using ADX intrinsics from `core::arch::{x86, x86_64}`. (accepted, adx_target_feature, "1.61.0", Some(44839), None), + /// Allows explicit discriminants on non-unit enum variants. + (accepted, arbitrary_enum_discriminant, "CURRENT_RUSTC_VERSION", Some(60553), None), /// Allows using `sym` operands in inline assembly. (accepted, asm_sym, "CURRENT_RUSTC_VERSION", Some(93333), None), /// Allows the definition of associated constants in `trait` or `impl` blocks. diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 1b8d683b13361..4facb6140a300 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -292,8 +292,6 @@ declare_features! ( (incomplete, adt_const_params, "1.56.0", Some(95174), None), /// Allows defining an `#[alloc_error_handler]`. (active, alloc_error_handler, "1.29.0", Some(51540), None), - /// Allows explicit discriminants on non-unit enum variants. - (active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None), /// Allows trait methods with arbitrary self types. (active, arbitrary_self_types, "1.23.0", Some(44874), None), /// Allows using `const` operands in inline assembly. diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index a1faf80251957..b302cee4816fb 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1180,7 +1180,7 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L } } - if tcx.adt_def(def_id).repr().int.is_none() && tcx.features().arbitrary_enum_discriminant { + if tcx.adt_def(def_id).repr().int.is_none() { let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..)); let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some(); diff --git a/src/doc/unstable-book/src/language-features/arbitrary-enum-discriminant.md b/src/doc/unstable-book/src/language-features/arbitrary-enum-discriminant.md deleted file mode 100644 index e0bb782270e22..0000000000000 --- a/src/doc/unstable-book/src/language-features/arbitrary-enum-discriminant.md +++ /dev/null @@ -1,37 +0,0 @@ -# `arbitrary_enum_discriminant` - -The tracking issue for this feature is: [#60553] - -[#60553]: https://github.com/rust-lang/rust/issues/60553 - ------------------------- - -The `arbitrary_enum_discriminant` feature permits tuple-like and -struct-like enum variants with `#[repr()]` to have explicit discriminants. - -## Examples - -```rust -#![feature(arbitrary_enum_discriminant)] - -#[allow(dead_code)] -#[repr(u8)] -enum Enum { - Unit = 3, - Tuple(u16) = 2, - Struct { - a: u8, - b: u16, - } = 1, -} - -impl Enum { - fn tag(&self) -> u8 { - unsafe { *(self as *const Self as *const u8) } - } -} - -assert_eq!(3, Enum::Unit.tag()); -assert_eq!(2, Enum::Tuple(5).tag()); -assert_eq!(1, Enum::Struct{a: 7, b: 11}.tag()); -``` diff --git a/src/test/ui/cast/issue-88621.rs b/src/test/ui/cast/issue-88621.rs index 9242b80e22939..1679793ee6834 100644 --- a/src/test/ui/cast/issue-88621.rs +++ b/src/test/ui/cast/issue-88621.rs @@ -1,5 +1,3 @@ -#![feature(arbitrary_enum_discriminant)] - #[repr(u8)] enum Kind2 { Foo() = 1, diff --git a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.rs b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.rs index 4da7b5ab24b29..a6e5f70fdefa6 100644 --- a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.rs +++ b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.rs @@ -1,5 +1,4 @@ #![crate_type="lib"] -#![feature(arbitrary_enum_discriminant)] enum Enum { //~^ ERROR `#[repr(inttype)]` must be specified diff --git a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs index ccc423e4a194c..83e74a6e685a7 100644 --- a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs +++ b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs @@ -1,5 +1,5 @@ // run-pass -#![feature(arbitrary_enum_discriminant, test)] +#![feature(test)] extern crate test; diff --git a/src/test/ui/enum-discriminant/discriminant_value.rs b/src/test/ui/enum-discriminant/discriminant_value.rs index 65ab411dbcbe6..f3dfac298ad7b 100644 --- a/src/test/ui/enum-discriminant/discriminant_value.rs +++ b/src/test/ui/enum-discriminant/discriminant_value.rs @@ -1,6 +1,6 @@ // run-pass #![allow(stable_features)] -#![feature(arbitrary_enum_discriminant, core, core_intrinsics)] +#![feature(core, core_intrinsics)] extern crate core; use core::intrinsics::discriminant_value; diff --git a/src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.rs b/src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.rs deleted file mode 100644 index 3e90af4d36af3..0000000000000 --- a/src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![crate_type="lib"] - -enum Enum { - Unit = 1, - //~^ ERROR custom discriminant values are not allowed in enums with tuple or struct variants - Tuple() = 2, - //~^ ERROR discriminants on non-unit variants are experimental - Struct{} = 3, - //~^ ERROR discriminants on non-unit variants are experimental -} diff --git a/src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.stderr b/src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.stderr deleted file mode 100644 index b5f61e6e991d8..0000000000000 --- a/src/test/ui/enum-discriminant/feature-gate-arbitrary_enum_discriminant.stderr +++ /dev/null @@ -1,36 +0,0 @@ -error[E0658]: discriminants on non-unit variants are experimental - --> $DIR/feature-gate-arbitrary_enum_discriminant.rs:6:13 - | -LL | Tuple() = 2, - | ^ - | - = note: see issue #60553 for more information - = help: add `#![feature(arbitrary_enum_discriminant)]` to the crate attributes to enable - -error[E0658]: discriminants on non-unit variants are experimental - --> $DIR/feature-gate-arbitrary_enum_discriminant.rs:8:14 - | -LL | Struct{} = 3, - | ^ - | - = note: see issue #60553 for more information - = help: add `#![feature(arbitrary_enum_discriminant)]` to the crate attributes to enable - -error[E0658]: custom discriminant values are not allowed in enums with tuple or struct variants - --> $DIR/feature-gate-arbitrary_enum_discriminant.rs:4:10 - | -LL | Unit = 1, - | ^ disallowed custom discriminant -LL | -LL | Tuple() = 2, - | ----------- tuple variant defined here -LL | -LL | Struct{} = 3, - | ------------ struct variant defined here - | - = note: see issue #60553 for more information - = help: add `#![feature(arbitrary_enum_discriminant)]` to the crate attributes to enable - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.rs b/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.rs index f927dd189038a..ad9fcc25b4127 100644 --- a/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.rs +++ b/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.rs @@ -1,4 +1,4 @@ -#![feature(arbitrary_enum_discriminant, core_intrinsics)] +#![feature(core_intrinsics)] extern crate core; use core::intrinsics::discriminant_value; diff --git a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs index e62582fb5161a..42a062239d34a 100644 --- a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs +++ b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs @@ -1,4 +1,4 @@ -#![feature(arbitrary_enum_discriminant, core_intrinsics)] +#![feature(core_intrinsics)] extern crate core; use core::intrinsics::discriminant_value; diff --git a/src/test/ui/enum-discriminant/issue-70509-partial_eq.rs b/src/test/ui/enum-discriminant/issue-70509-partial_eq.rs index ae389e1146645..3adac7b72621c 100644 --- a/src/test/ui/enum-discriminant/issue-70509-partial_eq.rs +++ b/src/test/ui/enum-discriminant/issue-70509-partial_eq.rs @@ -1,5 +1,5 @@ // run-pass -#![feature(repr128, arbitrary_enum_discriminant)] +#![feature(repr128)] //~^ WARN the feature `repr128` is incomplete #[derive(PartialEq, Debug)] diff --git a/src/test/ui/enum-discriminant/issue-70509-partial_eq.stderr b/src/test/ui/enum-discriminant/issue-70509-partial_eq.stderr index ac93badf2156b..2eef930c39434 100644 --- a/src/test/ui/enum-discriminant/issue-70509-partial_eq.stderr +++ b/src/test/ui/enum-discriminant/issue-70509-partial_eq.stderr @@ -1,7 +1,7 @@ warning: the feature `repr128` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/issue-70509-partial_eq.rs:2:12 | -LL | #![feature(repr128, arbitrary_enum_discriminant)] +LL | #![feature(repr128)] | ^^^^^^^ | = note: see issue #56071 for more information diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs index ae44ffd29bd56..ec3860a322fc5 100644 --- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -7,7 +7,7 @@ // This test checks panic emitted from `mem::{uninitialized,zeroed}`. -#![feature(never_type, arbitrary_enum_discriminant)] +#![feature(never_type)] #![allow(deprecated, invalid_value)] use std::{ diff --git a/src/test/ui/macros/macros-nonfatal-errors.rs b/src/test/ui/macros/macros-nonfatal-errors.rs index 140cc5b0fd808..ab14c35893d0a 100644 --- a/src/test/ui/macros/macros-nonfatal-errors.rs +++ b/src/test/ui/macros/macros-nonfatal-errors.rs @@ -4,7 +4,7 @@ // immediately, so that we get more errors listed at a time. #![feature(trace_macros, concat_idents)] -#![feature(stmt_expr_attributes, arbitrary_enum_discriminant)] +#![feature(stmt_expr_attributes)] use std::arch::asm; diff --git a/src/test/ui/parser/issues/issue-17383.rs b/src/test/ui/parser/issues/issue-17383.rs deleted file mode 100644 index 7bf0e64f2c0a3..0000000000000 --- a/src/test/ui/parser/issues/issue-17383.rs +++ /dev/null @@ -1,7 +0,0 @@ -enum X { - A = 3, - //~^ ERROR custom discriminant values are not allowed in enums with tuple or struct variants - B(usize) -} - -fn main() {} diff --git a/src/test/ui/parser/issues/issue-17383.stderr b/src/test/ui/parser/issues/issue-17383.stderr deleted file mode 100644 index 265d6e1486614..0000000000000 --- a/src/test/ui/parser/issues/issue-17383.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0658]: custom discriminant values are not allowed in enums with tuple or struct variants - --> $DIR/issue-17383.rs:2:9 - | -LL | A = 3, - | ^ disallowed custom discriminant -LL | -LL | B(usize) - | -------- tuple variant defined here - | - = note: see issue #60553 for more information - = help: add `#![feature(arbitrary_enum_discriminant)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/parser/tag-variant-disr-non-nullary.rs b/src/test/ui/parser/tag-variant-disr-non-nullary.rs deleted file mode 100644 index a9cfdd549c752..0000000000000 --- a/src/test/ui/parser/tag-variant-disr-non-nullary.rs +++ /dev/null @@ -1,12 +0,0 @@ -enum Color { - Red = 0xff0000, - //~^ ERROR custom discriminant values are not allowed in enums with tuple or struct variants - Green = 0x00ff00, - Blue = 0x0000ff, - Black = 0x000000, - White = 0xffffff, - Other(usize), - Other2(usize, usize), -} - -fn main() {} diff --git a/src/test/ui/parser/tag-variant-disr-non-nullary.stderr b/src/test/ui/parser/tag-variant-disr-non-nullary.stderr deleted file mode 100644 index 79f044a0675b7..0000000000000 --- a/src/test/ui/parser/tag-variant-disr-non-nullary.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error[E0658]: custom discriminant values are not allowed in enums with tuple or struct variants - --> $DIR/tag-variant-disr-non-nullary.rs:2:11 - | -LL | Red = 0xff0000, - | ^^^^^^^^ disallowed custom discriminant -LL | -LL | Green = 0x00ff00, - | ^^^^^^^^ disallowed custom discriminant -LL | Blue = 0x0000ff, - | ^^^^^^^^ disallowed custom discriminant -LL | Black = 0x000000, - | ^^^^^^^^ disallowed custom discriminant -LL | White = 0xffffff, - | ^^^^^^^^ disallowed custom discriminant -LL | Other(usize), - | ------------ tuple variant defined here -LL | Other2(usize, usize), - | -------------------- tuple variant defined here - | - = note: see issue #60553 for more information - = help: add `#![feature(arbitrary_enum_discriminant)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. From b614b0e64c2990c60207aa748957728d644a5a8d Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 6 Apr 2022 13:45:30 +1000 Subject: [PATCH 07/10] Bless tests --- src/test/ui/cast/issue-88621.stderr | 2 +- .../arbitrary_enum_discriminant-no-repr.stderr | 2 +- src/test/ui/transmutability/enums/should_order_correctly.rs | 1 - .../ui/transmutability/enums/should_respect_endianness.rs | 1 - .../ui/transmutability/enums/should_respect_endianness.stderr | 4 ++-- 5 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/test/ui/cast/issue-88621.stderr b/src/test/ui/cast/issue-88621.stderr index e96d866515238..886145c1bafee 100644 --- a/src/test/ui/cast/issue-88621.stderr +++ b/src/test/ui/cast/issue-88621.stderr @@ -1,5 +1,5 @@ error[E0605]: non-primitive cast: `Kind2` as `u8` - --> $DIR/issue-88621.rs:11:13 + --> $DIR/issue-88621.rs:9:13 | LL | let _ = Kind2::Foo() as u8; | ^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object diff --git a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr index 803bb06fcc218..8cee74696295c 100644 --- a/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr +++ b/src/test/ui/enum-discriminant/arbitrary_enum_discriminant-no-repr.stderr @@ -1,5 +1,5 @@ error[E0732]: `#[repr(inttype)]` must be specified - --> $DIR/arbitrary_enum_discriminant-no-repr.rs:4:1 + --> $DIR/arbitrary_enum_discriminant-no-repr.rs:3:1 | LL | enum Enum { | ^^^^^^^^^ diff --git a/src/test/ui/transmutability/enums/should_order_correctly.rs b/src/test/ui/transmutability/enums/should_order_correctly.rs index b753cf0e62d59..1335cc9d2b17e 100644 --- a/src/test/ui/transmutability/enums/should_order_correctly.rs +++ b/src/test/ui/transmutability/enums/should_order_correctly.rs @@ -2,7 +2,6 @@ //! The payloads of an enum variant should be ordered after its tag. #![crate_type = "lib"] -#![feature(arbitrary_enum_discriminant)] #![feature(transmutability)] #![allow(dead_code)] diff --git a/src/test/ui/transmutability/enums/should_respect_endianness.rs b/src/test/ui/transmutability/enums/should_respect_endianness.rs index 19ff690050031..f3567b405f404 100644 --- a/src/test/ui/transmutability/enums/should_respect_endianness.rs +++ b/src/test/ui/transmutability/enums/should_respect_endianness.rs @@ -2,7 +2,6 @@ //! an enum with a multi-byte tag. #![crate_type = "lib"] -#![feature(arbitrary_enum_discriminant)] #![feature(transmutability)] #![allow(dead_code)] diff --git a/src/test/ui/transmutability/enums/should_respect_endianness.stderr b/src/test/ui/transmutability/enums/should_respect_endianness.stderr index fcb70813bd961..0845a5edf32e5 100644 --- a/src/test/ui/transmutability/enums/should_respect_endianness.stderr +++ b/src/test/ui/transmutability/enums/should_respect_endianness.stderr @@ -1,12 +1,12 @@ error[E0277]: `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context`. - --> $DIR/should_respect_endianness.rs:37:36 + --> $DIR/should_respect_endianness.rs:36:36 | LL | assert::is_transmutable::(); | ^^^^^^^^^^ `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context`. | = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Unexpected` note: required by a bound in `is_transmutable` - --> $DIR/should_respect_endianness.rs:15:14 + --> $DIR/should_respect_endianness.rs:14:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this From 4bd98443ed368a781812545915cf758e2091128d Mon Sep 17 00:00:00 2001 From: ouz-a Date: Sun, 16 Oct 2022 21:30:32 +0300 Subject: [PATCH 08/10] remove misc_cast and validate types --- .../rustc_const_eval/src/interpret/cast.rs | 63 +++++++++++++------ .../src/transform/validate.rs | 25 ++++++-- src/tools/miri/src/shims/intrinsics/simd.rs | 6 +- 3 files changed, 66 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 764224fd0072e..f980e606b932d 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -42,10 +42,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let res = self.pointer_from_exposed_address_cast(&src, cast_ty)?; self.write_immediate(res, dest)?; } - // FIXME: We shouldn't use `misc_cast` for these but handle them separately. - IntToInt | FloatToInt | FloatToFloat | IntToFloat | FnPtrToPtr | PtrToPtr => { + + IntToInt | IntToFloat => { let src = self.read_immediate(src)?; - let res = self.misc_cast(&src, cast_ty)?; + let res = self.int_to_int_or_float(&src, cast_ty)?; + self.write_immediate(res, dest)?; + } + + FloatToFloat | FloatToInt => { + let src = self.read_immediate(src)?; + let res = self.float_to_float_or_int(&src, cast_ty)?; + self.write_immediate(res, dest)?; + } + + FnPtrToPtr | PtrToPtr => { + let src = self.read_immediate(&src)?; + let res = self.ptr_to_ptr(&src, cast_ty)?; self.write_immediate(res, dest)?; } @@ -126,13 +138,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(()) } - pub fn misc_cast( + pub fn int_to_int_or_float( + &mut self, + src: &ImmTy<'tcx, M::Provenance>, + cast_ty: Ty<'tcx>, + ) -> InterpResult<'tcx, Immediate> { + if (src.layout.ty.is_integral() || src.layout.ty.is_char() || src.layout.ty.is_bool()) + && (cast_ty.is_floating_point() || cast_ty.is_integral() || cast_ty.is_char()) + { + let scalar = src.to_scalar(); + Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into()) + } else { + bug!("Unexpected cast from type {:?}", src.layout.ty) + } + } + + pub fn float_to_float_or_int( &mut self, src: &ImmTy<'tcx, M::Provenance>, cast_ty: Ty<'tcx>, ) -> InterpResult<'tcx, Immediate> { use rustc_type_ir::sty::TyKind::*; - trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty); match src.layout.ty.kind() { // Floating point @@ -142,19 +168,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Float(FloatTy::F64) => { return Ok(self.cast_from_float(src.to_scalar().to_f64()?, cast_ty).into()); } - // The rest is integer/pointer-"like", including fn ptr casts - _ => assert!( - src.layout.ty.is_bool() - || src.layout.ty.is_char() - || src.layout.ty.is_integral() - || src.layout.ty.is_any_ptr(), - "Unexpected cast from type {:?}", - src.layout.ty - ), + _ => { + bug!("Can't cast 'Float' type into {:?}", cast_ty); + } } + } - // # First handle non-scalar source values. - + /// Handles 'FnPtrToPtr' and 'PtrToPtr' casts. + pub fn ptr_to_ptr( + &mut self, + src: &ImmTy<'tcx, M::Provenance>, + cast_ty: Ty<'tcx>, + ) -> InterpResult<'tcx, Immediate> { // Handle casting any ptr to raw ptr (might be a fat ptr). if src.layout.ty.is_any_ptr() && cast_ty.is_unsafe_ptr() { let dest_layout = self.layout_of(cast_ty)?; @@ -178,11 +203,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), }; } + } else { + bug!("Can't cast 'Ptr' or 'FnPtr' into {:?}", cast_ty); } - - // # The remaining source values are scalar and "int-like". - let scalar = src.to_scalar(); - Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into()) } pub fn pointer_expose_address_cast( diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 8abf767f89f88..40946344a35d1 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -556,21 +556,36 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { check_kinds!(a, "Cannot shallow init type {:?}", ty::RawPtr(..)); } Rvalue::Cast(kind, operand, target_type) => { + let op_ty = operand.ty(self.body, self.tcx); match kind { CastKind::DynStar => { // FIXME(dyn-star): make sure nothing needs to be done here. } - // Nothing to check here + // FIXME: Add Checks for these CastKind::PointerFromExposedAddress | CastKind::PointerExposeAddress | CastKind::Pointer(_) => {} - _ => { - let op_ty = operand.ty(self.body, self.tcx); - if op_ty.is_enum() { + CastKind::IntToInt | CastKind::IntToFloat => { + let input_valid = op_ty.is_integral() || op_ty.is_char() || op_ty.is_bool(); + let target_valid = target_type.is_numeric() || target_type.is_char(); + if !input_valid || !target_valid { + self.fail( + location, + format!("Wrong cast kind {kind:?} for the type {op_ty}",), + ); + } + } + CastKind::FnPtrToPtr | CastKind::PtrToPtr => { + if !(op_ty.is_any_ptr() && target_type.is_unsafe_ptr()) { + self.fail(location, "Can't cast {op_ty} into 'Ptr'"); + } + } + CastKind::FloatToFloat | CastKind::FloatToInt => { + if !op_ty.is_floating_point() || !target_type.is_numeric() { self.fail( location, format!( - "enum -> int casts should go through `Rvalue::Discriminant`: {operand:?}:{op_ty} as {target_type}", + "Trying to cast non 'Float' as {kind:?} into {target_type:?}" ), ); } diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs index 163d185f66f3a..c1b949b1f7993 100644 --- a/src/tools/miri/src/shims/intrinsics/simd.rs +++ b/src/tools/miri/src/shims/intrinsics/simd.rs @@ -437,13 +437,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let val = match (op.layout.ty.kind(), dest.layout.ty.kind()) { // Int-to-(int|float): always safe (ty::Int(_) | ty::Uint(_), ty::Int(_) | ty::Uint(_) | ty::Float(_)) => - this.misc_cast(&op, dest.layout.ty)?, + this.int_to_int_or_float(&op, dest.layout.ty)?, // Float-to-float: always safe (ty::Float(_), ty::Float(_)) => - this.misc_cast(&op, dest.layout.ty)?, + this.float_to_float_or_int(&op, dest.layout.ty)?, // Float-to-int in safe mode (ty::Float(_), ty::Int(_) | ty::Uint(_)) if safe_cast => - this.misc_cast(&op, dest.layout.ty)?, + this.float_to_float_or_int(&op, dest.layout.ty)?, // Float-to-int in unchecked mode (ty::Float(FloatTy::F32), ty::Int(_) | ty::Uint(_)) if !safe_cast => this.float_to_int_unchecked(op.to_scalar().to_f32()?, dest.layout.ty)?.into(), From 8b984e5c2487d9d4029b35cf9a0b079b66f3b7c6 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Thu, 11 Aug 2022 15:40:23 +0300 Subject: [PATCH 09/10] fake capture if min_captures empty --- compiler/rustc_hir_typeck/src/upvar.rs | 7 ++++++- src/test/ui/closures/issue-93242.rs | 11 +++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/closures/issue-93242.rs diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 4dea40829f622..3aa8c56138de6 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -231,7 +231,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We now fake capture information for all variables that are mentioned within the closure // We do this after handling migrations so that min_captures computes before - if !enable_precise_capture(self.tcx, span) { + if !enable_precise_capture(self.tcx, span) + // (ouz-a) #93242 - ICE happens because closure_min_captures is empty with + // 2021 edition, because it sets `enable_precise_capture` to true, which won't allow us + // fake capture information this check sidesteps that and avoids the ICE. + || (infer_kind == None && self.typeck_results.borrow().closure_min_captures.is_empty()) + { let mut capture_information: InferredCaptureInformation<'tcx> = Default::default(); if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { diff --git a/src/test/ui/closures/issue-93242.rs b/src/test/ui/closures/issue-93242.rs new file mode 100644 index 0000000000000..56f8b0a477935 --- /dev/null +++ b/src/test/ui/closures/issue-93242.rs @@ -0,0 +1,11 @@ +// check-pass +// edition:2021 + +pub fn something(path: &[usize]) -> impl Fn() -> usize + '_ { + move || match path { + [] => 0, + _ => 1, + } +} + +fn main(){} From 15cfeb33b08c91090d52685651aa9762b8f3c43f Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Sun, 23 Oct 2022 11:53:39 -0700 Subject: [PATCH 10/10] Only test pthread_getname_np on linux-gnu --- library/std/src/thread/tests.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index 71eb41cd564db..6c9ce6fa0ddbd 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -37,7 +37,13 @@ fn test_named_thread() { .unwrap(); } -#[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios", target_os = "watchos"))] +#[cfg(any( + // Note: musl didn't add pthread_getname_np until 1.2.3 + all(target_os = "linux", target_env = "gnu"), + target_os = "macos", + target_os = "ios", + target_os = "watchos" +))] #[test] fn test_named_thread_truncation() { use crate::ffi::CStr;