Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cstr! macro. #101607

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1023,16 +1023,6 @@ dependencies = [
"winapi",
]

[[package]]
name = "cstr"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c11a39d776a3b35896711da8a04dc1835169dcd36f710878187637314e47941b"
dependencies = [
"proc-macro2",
"quote",
]

[[package]]
name = "curl"
version = "0.4.43"
Expand Down Expand Up @@ -3275,7 +3265,6 @@ name = "rustc_codegen_llvm"
version = "0.0.0"
dependencies = [
"bitflags",
"cstr",
"libc",
"measureme",
"object 0.29.0",
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_codegen_llvm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ test = false

[dependencies]
bitflags = "1.0"
cstr = "0.2"
libc = "0.2"
measureme = "10.0.0"
object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "archive", "coff", "elf", "macho", "pe"] }
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_codegen_llvm/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ use crate::context::CodegenCx;
use crate::llvm;
use crate::value::Value;

use cstr::cstr;

use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
use rustc_codegen_ssa::mono_item::MonoItemExt;
use rustc_codegen_ssa::traits::*;
Expand All @@ -34,6 +32,7 @@ use rustc_session::config::DebugInfo;
use rustc_span::symbol::Symbol;
use rustc_target::spec::SanitizerSet;

use std::ffi::cstr;
use std::time::Instant;

pub struct ValueIter<'ll> {
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::llvm::{self, AtomicOrdering, AtomicRmwBinOp, BasicBlock};
use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
use cstr::cstr;
use libc::{c_char, c_uint};
use rustc_codegen_ssa::common::{IntPredicate, RealPredicate, SynchronizationScope, TypeKind};
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
Expand All @@ -23,7 +22,7 @@ use rustc_span::Span;
use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange};
use rustc_target::spec::{HasTargetSpec, Target};
use std::borrow::Cow;
use std::ffi::CStr;
use std::ffi::{cstr, CStr};
use std::iter;
use std::ops::Deref;
use std::ptr;
Expand All @@ -44,7 +43,7 @@ impl Drop for Builder<'_, '_, '_> {
}

// FIXME(eddyb) use a checked constructor when they become `const fn`.
const EMPTY_C_STR: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"\0") };
const EMPTY_C_STR: &CStr = cstr!();

/// Empty string, to be used where LLVM expects an instruction name, indicating
/// that the instruction is to be left unnamed (i.e. numbered, in textual IR).
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::llvm_util;
use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
use cstr::cstr;
use libc::c_uint;
use rustc_codegen_ssa::traits::*;
use rustc_hir::def_id::DefId;
Expand All @@ -22,6 +21,7 @@ use rustc_middle::{bug, span_bug};
use rustc_target::abi::{
AddressSpace, Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange,
};
use std::ffi::cstr;
use std::ops::Range;

pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<'_>) -> &'ll Value {
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_codegen_llvm/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use crate::llvm_util;
use crate::type_::Type;
use crate::value::Value;

use cstr::cstr;
use rustc_codegen_ssa::base::wants_msvc_seh;
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::base_n;
Expand All @@ -33,7 +32,7 @@ use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel};
use smallvec::SmallVec;

use std::cell::{Cell, RefCell};
use std::ffi::CStr;
use std::ffi::{cstr, CStr};
use std::str;

/// There is one `CodegenCx` per compilation unit. Each one has its own LLVM
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ use crate::llvm::debuginfo::{
};
use crate::value::Value;

use cstr::cstr;
use rustc_codegen_ssa::debuginfo::type_names::cpp_like_debuginfo;
use rustc_codegen_ssa::debuginfo::type_names::VTableNameKind;
use rustc_codegen_ssa::traits::*;
Expand All @@ -45,6 +44,7 @@ use smallvec::smallvec;

use libc::{c_char, c_longlong, c_uint};
use std::borrow::Cow;
use std::ffi::cstr;
use std::fmt::{self, Write};
use std::hash::{Hash, Hasher};
use std::iter;
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_llvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#![feature(let_chains)]
#![feature(extern_types)]
#![feature(once_cell)]
#![feature(cstr_macro)]
#![feature(iter_intersperse)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
Expand Down
108 changes: 92 additions & 16 deletions library/core/src/ffi/c_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,14 @@ impl FromBytesWithNulError {
const fn interior_nul(pos: usize) -> FromBytesWithNulError {
FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) }
}

const fn not_nul_terminated() -> FromBytesWithNulError {
FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated }
}

#[doc(hidden)]
#[unstable(feature = "cstr_internals", issue = "none")]
pub fn __description(&self) -> &str {
pub const fn __description(&self) -> &str {
match self.kind {
FromBytesWithNulErrorKind::InteriorNul(..) => {
"data provided contains an interior nul byte"
Expand All @@ -139,6 +140,18 @@ impl FromBytesWithNulError {
}
}

#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
impl fmt::Display for FromBytesWithNulError {
#[allow(deprecated, deprecated_in_future)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.__description())?;
if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind {
write!(f, " at byte pos {pos}")?;
}
Ok(())
}
}

/// An error indicating that no nul byte was present.
///
/// A slice used to create a [`CStr`] must contain a nul byte somewhere
Expand All @@ -164,24 +177,87 @@ impl fmt::Debug for CStr {
}
}

#[stable(feature = "cstr_default", since = "1.10.0")]
impl Default for &CStr {
fn default() -> Self {
const SLICE: &[c_char] = &[0];
// SAFETY: `SLICE` is indeed pointing to a valid nul-terminated string.
unsafe { CStr::from_ptr(SLICE.as_ptr()) }
/// Converts a `const` string or byte slice to a `&'static Cstr`.
///
/// # Examples
///
/// ```
/// #![feature(cstr_macro)]
///
/// use core::ffi::{cstr, CStr};
///
/// const HELLO: &CStr = cstr!("Hello, world!");
/// assert_eq!(HELLO.to_bytes_with_nul(), b"Hello, world!\0");
/// ```
///
/// If the given expression contains any interior nul bytes this will
/// result in a compilation error:
///
/// ```compile_fail
/// #![feature(const_cstr_from_bytes)]
///
/// use core::ffi::{cstr, CStr};
///
/// const HELLO: &CStr = cstr!("Hello, world!\0"); // compile fail!
/// ```
#[macro_export(local_inner_macros)]
#[unstable(feature = "cstr_macro", issue = "101607")]
#[rustc_diagnostic_item = "core_cstr_macro"]
#[doc(hidden)]
macro_rules! __cstr_macro_impl {
() => {
__cstr_macro_impl!("")
};
($s:expr) => {{
const BYTES: &[u8] = $crate::ffi::__cstr_macro_impl_as_bytes($s);
const BYTES_WITH_NUL: [u8; { BYTES.len() + 1 }] =
$crate::ffi::__cstr_macro_impl_to_bytes_with_nul(BYTES);
const CSTR: &$crate::ffi::CStr =
$crate::ffi::__cstr_macro_impl_from_bytes_with_nul(&BYTES_WITH_NUL);
CSTR
}};
}
#[unstable(feature = "cstr_macro", issue = "101607")]
#[doc(inline)]
pub use __cstr_macro_impl as cstr;

#[unstable(feature = "cstr_macro", issue = "101607")]
#[doc(hidden)]
pub const fn __cstr_macro_impl_as_bytes<T>(v: &T) -> &[u8]
where
T: ?Sized + ~const AsRef<[u8]> + ~const crate::marker::Destruct,
{
v.as_ref()
}

#[unstable(feature = "cstr_macro", issue = "101607")]
#[doc(hidden)]
pub const fn __cstr_macro_impl_to_bytes_with_nul<const N: usize>(bytes: &[u8]) -> [u8; N] {
let mut bytes_with_nul = [0; N];

let mut i = 0;
while i < bytes.len() {
bytes_with_nul[i] = bytes[i];
i += 1;
}

bytes_with_nul
}

#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
impl fmt::Display for FromBytesWithNulError {
#[allow(deprecated, deprecated_in_future)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.__description())?;
if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind {
write!(f, " at byte pos {pos}")?;
}
Ok(())
#[unstable(feature = "cstr_macro", issue = "101607")]
#[doc(hidden)]
pub const fn __cstr_macro_impl_from_bytes_with_nul(bytes: &[u8]) -> &CStr {
match CStr::from_bytes_with_nul(bytes) {
Ok(cstr) => cstr,
Err(err) => panic!("{}", err.__description()),
}
}

#[stable(feature = "cstr_default", since = "1.10.0")]
#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
impl const Default for &CStr {
fn default() -> Self {
cstr!()
}
}

Expand Down
7 changes: 7 additions & 0 deletions library/core/src/ffi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ pub use self::c_str::{CStr, FromBytesUntilNulError, FromBytesWithNulError};

mod c_str;

#[unstable(feature = "cstr_macro", issue = "101607")]
#[doc(hidden)]
pub use self::c_str::{
__cstr_macro_impl_as_bytes, __cstr_macro_impl_from_bytes_with_nul,
__cstr_macro_impl_to_bytes_with_nul, cstr,
};

macro_rules! type_alias_no_nz {
{
$Docfile:tt, $Alias:ident = $Real:ty;
Expand Down
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@
#![feature(const_is_char_boundary)]
#![feature(const_cstr_methods)]
#![feature(is_ascii_octdigit)]
#![feature(cstr_macro)]
//
// Language features:
#![feature(abi_unadjusted)]
Expand Down
3 changes: 2 additions & 1 deletion library/core/src/str/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2560,7 +2560,8 @@ impl str {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<[u8]> for str {
#[rustc_const_unstable(feature = "cstr_macro", issue = "101607")]
impl const AsRef<[u8]> for str {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
Expand Down
3 changes: 3 additions & 0 deletions library/std/src/ffi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,9 @@ pub use core::ffi::{
c_ulong, c_ulonglong, c_ushort,
};

#[unstable(feature = "cstr_macro", issue = "101607")]
pub use core::ffi::cstr;

#[stable(feature = "core_c_void", since = "1.30.0")]
pub use core::ffi::c_void;

Expand Down
1 change: 1 addition & 0 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@
#![feature(maybe_uninit_uninit_array)]
#![feature(const_maybe_uninit_uninit_array)]
#![feature(const_waker)]
#![feature(cstr_macro)]
//
// Library features (alloc):
#![feature(alloc_layout_extra)]
Expand Down
4 changes: 2 additions & 2 deletions library/std/src/sys/unix/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![allow(missing_docs, nonstandard_style)]

use crate::ffi::CStr;
use crate::ffi::cstr;
use crate::io::ErrorKind;

pub use self::rand::hashmap_random_keys;
Expand Down Expand Up @@ -75,7 +75,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
// thread-id for the main thread and so renaming the main thread will rename the
// process and we only want to enable this on platforms we've tested.
if cfg!(target_os = "macos") {
thread::Thread::set_name(&CStr::from_bytes_with_nul_unchecked(b"main\0"));
thread::Thread::set_name(cstr!("main"));
}

unsafe fn sanitize_standard_fds() {
Expand Down
6 changes: 3 additions & 3 deletions library/std/src/sys/windows/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#![cfg_attr(test, allow(dead_code))]
#![unstable(issue = "none", feature = "windows_c")]

use crate::ffi::CStr;
use crate::ffi::{cstr, CStr};
use crate::mem;
use crate::os::raw::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ushort};
use crate::os::windows::io::{BorrowedHandle, HandleOrInvalid, HandleOrNull};
Expand Down Expand Up @@ -1245,7 +1245,7 @@ extern "system" {
// Functions that aren't available on every version of Windows that we support,
// but we still use them and just provide some form of a fallback implementation.
compat_fn_with_fallback! {
pub static KERNEL32: &CStr = ansi_str!("kernel32");
pub static KERNEL32: &CStr = cstr!("kernel32");

// >= Win10 1607
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription
Expand Down Expand Up @@ -1280,7 +1280,7 @@ compat_fn_optional! {
}

compat_fn_with_fallback! {
pub static NTDLL: &CStr = ansi_str!("ntdll");
pub static NTDLL: &CStr = cstr!("ntdll");

pub fn NtCreateFile(
FileHandle: *mut HANDLE,
Expand Down
Loading