Skip to content

Commit

Permalink
std: Implement CString-related RFCs
Browse files Browse the repository at this point in the history
This commit is an implementation of [RFC 592][r592] and [RFC 840][r840]. These
two RFCs tweak the behavior of `CString` and add a new `CStr` unsized slice type
to the module.

[r592]: https://github.com/rust-lang/rfcs/blob/master/text/0592-c-str-deref.md
[r840]: https://github.com/rust-lang/rfcs/blob/master/text/0840-no-panic-in-c-string.md

The new `CStr` type is only constructable via two methods:

1. By `deref`'ing from a `CString`
2. Unsafely via `CStr::from_ptr`

The purpose of `CStr` is to be an unsized type which is a thin pointer to a
`libc::c_char` (currently it is a fat pointer slice due to implementation
limitations). Strings from C can be safely represented with a `CStr` and an
appropriate lifetime as well. Consumers of `&CString` should now consume `&CStr`
instead to allow producers to pass in C-originating strings instead of just
Rust-allocated strings.

A new constructor was added to `CString`, `new`, which takes `T: IntoBytes`
instead of separate `from_slice` and `from_vec` methods (both have been
deprecated in favor of `new`). The `new` method returns a `Result` instead of
panicking.  The error variant contains the relevant information about where the
error happened and bytes (if present). Conversions are provided to the
`io::Error` and `old_io::IoError` types via the `FromError` trait which
translate to `InvalidInput`.

This is a breaking change due to the modification of existing `#[unstable]` APIs
and new deprecation, and more detailed information can be found in the two RFCs.
Notable breakage includes:

* All construction of `CString` now needs to use `new` and handle the outgoing
  `Result`.
* Usage of `CString` as a byte slice now explicitly needs a `.as_bytes()` call.
* The `as_slice*` methods have been removed in favor of just having the
  `as_bytes*` methods.

Closes #22469
Closes #22470
[breaking-change]
  • Loading branch information
alexcrichton committed Feb 18, 2015
1 parent dfc5c0f commit 1860ee5
Show file tree
Hide file tree
Showing 40 changed files with 555 additions and 290 deletions.
4 changes: 2 additions & 2 deletions src/doc/trpl/ffi.md
Expand Up @@ -435,8 +435,8 @@ extern {
}
fn main() {
let prompt = CString::from_slice(b"[my-awesome-shell] $");
unsafe {
let prompt = CString::new("[my-awesome-shell] $").unwrap();
unsafe {
rl_prompt = prompt.as_ptr();
println!("{:?}", rl_prompt);
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/metadata/loader.rs
Expand Up @@ -744,7 +744,7 @@ fn get_metadata_section_imp(is_osx: bool, filename: &Path) -> Result<MetadataBlo
}
}
unsafe {
let buf = CString::from_slice(filename.as_vec());
let buf = CString::new(filename.as_vec()).unwrap();
let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr());
if mb as int == 0 {
return Err(format!("error reading library: '{}'",
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_llvm/archive_ro.rs
Expand Up @@ -30,7 +30,7 @@ impl ArchiveRO {
/// raised.
pub fn open(dst: &Path) -> Option<ArchiveRO> {
unsafe {
let s = CString::from_slice(dst.as_vec());
let s = CString::new(dst.as_vec()).unwrap();
let ar = ::LLVMRustOpenArchive(s.as_ptr());
if ar.is_null() {
None
Expand All @@ -44,7 +44,7 @@ impl ArchiveRO {
pub fn read<'a>(&'a self, file: &str) -> Option<&'a [u8]> {
unsafe {
let mut size = 0 as libc::size_t;
let file = CString::from_slice(file.as_bytes());
let file = CString::new(file).unwrap();
let ptr = ::LLVMRustArchiveReadSection(self.ptr, file.as_ptr(),
&mut size);
if ptr.is_null() {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_llvm/lib.rs
Expand Up @@ -2149,7 +2149,7 @@ impl Drop for TargetData {
}

pub fn mk_target_data(string_rep: &str) -> TargetData {
let string_rep = CString::from_slice(string_rep.as_bytes());
let string_rep = CString::new(string_rep).unwrap();
TargetData {
lltd: unsafe { LLVMCreateTargetData(string_rep.as_ptr()) }
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/back/lto.rs
Expand Up @@ -140,7 +140,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,

// Internalize everything but the reachable symbols of the current module
let cstrs: Vec<CString> = reachable.iter().map(|s| {
CString::from_slice(s.as_bytes())
CString::new(s.clone()).unwrap()
}).collect();
let arr: Vec<*const libc::c_char> = cstrs.iter().map(|c| c.as_ptr()).collect();
let ptr = arr.as_ptr();
Expand Down
28 changes: 14 additions & 14 deletions src/librustc_trans/back/write.rs
Expand Up @@ -22,7 +22,7 @@ use syntax::codemap;
use syntax::diagnostic;
use syntax::diagnostic::{Emitter, Handler, Level, mk_handler};

use std::ffi::{self, CString};
use std::ffi::{CStr, CString};
use std::old_io::Command;
use std::old_io::fs;
use std::iter::Unfold;
Expand All @@ -49,7 +49,7 @@ pub fn llvm_err(handler: &diagnostic::Handler, msg: String) -> ! {
if cstr == ptr::null() {
handler.fatal(&msg[]);
} else {
let err = ffi::c_str_to_bytes(&cstr);
let err = CStr::from_ptr(cstr).to_bytes();
let err = String::from_utf8_lossy(err).to_string();
libc::free(cstr as *mut _);
handler.fatal(&format!("{}: {}",
Expand All @@ -67,7 +67,7 @@ pub fn write_output_file(
output: &Path,
file_type: llvm::FileType) {
unsafe {
let output_c = CString::from_slice(output.as_vec());
let output_c = CString::new(output.as_vec()).unwrap();
let result = llvm::LLVMRustWriteOutputFile(
target, pm, m, output_c.as_ptr(), file_type);
if !result {
Expand Down Expand Up @@ -221,13 +221,13 @@ fn create_target_machine(sess: &Session) -> TargetMachineRef {
let triple = &sess.target.target.llvm_target[];

let tm = unsafe {
let triple = CString::from_slice(triple.as_bytes());
let triple = CString::new(triple.as_bytes()).unwrap();
let cpu = match sess.opts.cg.target_cpu {
Some(ref s) => &**s,
None => &*sess.target.target.options.cpu
};
let cpu = CString::from_slice(cpu.as_bytes());
let features = CString::from_slice(target_feature(sess).as_bytes());
let cpu = CString::new(cpu.as_bytes()).unwrap();
let features = CString::new(target_feature(sess).as_bytes()).unwrap();
llvm::LLVMRustCreateTargetMachine(
triple.as_ptr(), cpu.as_ptr(), features.as_ptr(),
code_model,
Expand Down Expand Up @@ -380,7 +380,7 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo
}

llvm::diagnostic::Optimization(opt) => {
let pass_name = str::from_utf8(ffi::c_str_to_bytes(&opt.pass_name))
let pass_name = str::from_utf8(CStr::from_ptr(opt.pass_name).to_bytes())
.ok()
.expect("got a non-UTF8 pass name from LLVM");
let enabled = match cgcx.remark {
Expand Down Expand Up @@ -424,7 +424,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
if config.emit_no_opt_bc {
let ext = format!("{}.no-opt.bc", name_extra);
let out = output_names.with_extension(&ext);
let out = CString::from_slice(out.as_vec());
let out = CString::new(out.as_vec()).unwrap();
llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
}

Expand All @@ -440,7 +440,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
// If we're verifying or linting, add them to the function pass
// manager.
let addpass = |pass: &str| {
let pass = CString::from_slice(pass.as_bytes());
let pass = CString::new(pass).unwrap();
llvm::LLVMRustAddPass(fpm, pass.as_ptr())
};
if !config.no_verify { assert!(addpass("verify")); }
Expand All @@ -453,7 +453,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
}

for pass in &config.passes {
let pass = CString::from_slice(pass.as_bytes());
let pass = CString::new(pass.clone()).unwrap();
if !llvm::LLVMRustAddPass(mpm, pass.as_ptr()) {
cgcx.handler.warn(&format!("unknown pass {:?}, ignoring", pass));
}
Expand All @@ -477,7 +477,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
if config.emit_lto_bc {
let name = format!("{}.lto.bc", name_extra);
let out = output_names.with_extension(&name);
let out = CString::from_slice(out.as_vec());
let out = CString::new(out.as_vec()).unwrap();
llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
}
},
Expand Down Expand Up @@ -511,15 +511,15 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
if config.emit_bc {
let ext = format!("{}.bc", name_extra);
let out = output_names.with_extension(&ext);
let out = CString::from_slice(out.as_vec());
let out = CString::new(out.as_vec()).unwrap();
llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
}

time(config.time_passes, "codegen passes", (), |()| {
if config.emit_ir {
let ext = format!("{}.ll", name_extra);
let out = output_names.with_extension(&ext);
let out = CString::from_slice(out.as_vec());
let out = CString::new(out.as_vec()).unwrap();
with_codegen(tm, llmod, config.no_builtins, |cpm| {
llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr());
})
Expand Down Expand Up @@ -1004,7 +1004,7 @@ unsafe fn configure_llvm(sess: &Session) {
let mut llvm_args = Vec::new();
{
let mut add = |arg: &str| {
let s = CString::from_slice(arg.as_bytes());
let s = CString::new(arg).unwrap();
llvm_args.push(s.as_ptr());
llvm_c_strs.push(s);
};
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_trans/trans/asm.rs
Expand Up @@ -120,8 +120,8 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
ast::AsmIntel => llvm::AD_Intel
};

let asm = CString::from_slice(ia.asm.as_bytes());
let constraints = CString::from_slice(constraints.as_bytes());
let asm = CString::new(ia.asm.as_bytes()).unwrap();
let constraints = CString::new(constraints).unwrap();
let r = InlineAsmCall(bcx,
asm.as_ptr(),
constraints.as_ptr(),
Expand Down
22 changes: 11 additions & 11 deletions src/librustc_trans/trans/base.rs
Expand Up @@ -86,7 +86,7 @@ use util::nodemap::NodeMap;

use arena::TypedArena;
use libc::{c_uint, uint64_t};
use std::ffi::{self, CString};
use std::ffi::{CStr, CString};
use std::cell::{Cell, RefCell};
use std::collections::HashSet;
use std::mem;
Expand Down Expand Up @@ -186,7 +186,7 @@ impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> {
pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv,
ty: Type, output: ty::FnOutput) -> ValueRef {

let buf = CString::from_slice(name.as_bytes());
let buf = CString::new(name).unwrap();
let llfn: ValueRef = unsafe {
llvm::LLVMGetOrInsertFunction(ccx.llmod(), buf.as_ptr(), ty.to_ref())
};
Expand Down Expand Up @@ -340,7 +340,7 @@ pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId,
None => ()
}
unsafe {
let buf = CString::from_slice(name.as_bytes());
let buf = CString::new(name.clone()).unwrap();
let c = llvm::LLVMAddGlobal(ccx.llmod(), ty.to_ref(), buf.as_ptr());
// Thread-local statics in some other crate need to *always* be linked
// against in a thread-local fashion, so we need to be sure to apply the
Expand Down Expand Up @@ -2788,7 +2788,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
&format!("Illegal null byte in export_name \
value: `{}`", sym)[]);
}
let buf = CString::from_slice(sym.as_bytes());
let buf = CString::new(sym.clone()).unwrap();
let g = llvm::LLVMAddGlobal(ccx.llmod(), llty,
buf.as_ptr());

Expand Down Expand Up @@ -2826,7 +2826,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
&sect)[]);
}
unsafe {
let buf = CString::from_slice(sect.as_bytes());
let buf = CString::new(sect.as_bytes()).unwrap();
llvm::LLVMSetSection(v, buf.as_ptr());
}
},
Expand Down Expand Up @@ -2993,15 +2993,15 @@ pub fn write_metadata(cx: &SharedCrateContext, krate: &ast::Crate) -> Vec<u8> {
let name = format!("rust_metadata_{}_{}",
cx.link_meta().crate_name,
cx.link_meta().crate_hash);
let buf = CString::from_vec(name.into_bytes());
let buf = CString::new(name).unwrap();
let llglobal = unsafe {
llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(),
buf.as_ptr())
};
unsafe {
llvm::LLVMSetInitializer(llglobal, llconst);
let name = loader::meta_section_name(cx.sess().target.target.options.is_like_osx);
let name = CString::from_slice(name.as_bytes());
let name = CString::new(name).unwrap();
llvm::LLVMSetSection(llglobal, name.as_ptr())
}
return metadata;
Expand Down Expand Up @@ -3039,8 +3039,8 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<String>) {
continue
}

let name = ffi::c_str_to_bytes(&llvm::LLVMGetValueName(val))
.to_vec();
let name = CStr::from_ptr(llvm::LLVMGetValueName(val))
.to_bytes().to_vec();
declared.insert(name);
}
}
Expand All @@ -3056,8 +3056,8 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<String>) {
continue
}

let name = ffi::c_str_to_bytes(&llvm::LLVMGetValueName(val))
.to_vec();
let name = CStr::from_ptr(llvm::LLVMGetValueName(val))
.to_bytes().to_vec();
if !declared.contains(&name) &&
!reachable.contains(str::from_utf8(&name).unwrap()) {
llvm::SetLinkage(val, llvm::InternalLinkage);
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_trans/trans/builder.rs
Expand Up @@ -431,7 +431,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
if name.is_empty() {
llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname())
} else {
let name = CString::from_slice(name.as_bytes());
let name = CString::new(name).unwrap();
llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(),
name.as_ptr())
}
Expand Down Expand Up @@ -786,7 +786,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let comment_text = format!("{} {}", "#",
sanitized.replace("\n", "\n\t# "));
self.count_insn("inlineasm");
let comment_text = CString::from_vec(comment_text.into_bytes());
let comment_text = CString::new(comment_text).unwrap();
let asm = unsafe {
llvm::LLVMConstInlineAsm(Type::func(&[], &Type::void(self.ccx)).to_ref(),
comment_text.as_ptr(), noname(), False,
Expand Down
7 changes: 4 additions & 3 deletions src/librustc_trans/trans/common.rs
Expand Up @@ -488,7 +488,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
opt_node_id: Option<ast::NodeId>)
-> Block<'a, 'tcx> {
unsafe {
let name = CString::from_slice(name.as_bytes());
let name = CString::new(name).unwrap();
let llbb = llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(),
self.llfn,
name.as_ptr());
Expand Down Expand Up @@ -761,7 +761,7 @@ pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef {

pub fn C_floating(s: &str, t: Type) -> ValueRef {
unsafe {
let s = CString::from_slice(s.as_bytes());
let s = CString::new(s).unwrap();
llvm::LLVMConstRealOfString(t.to_ref(), s.as_ptr())
}
}
Expand Down Expand Up @@ -839,7 +839,8 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va
!null_terminated as Bool);

let gsym = token::gensym("str");
let buf = CString::from_vec(format!("str{}", gsym.usize()).into_bytes());
let buf = CString::new(format!("str{}", gsym.usize()));
let buf = buf.unwrap();
let g = llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf.as_ptr());
llvm::LLVMSetInitializer(g, sc);
llvm::LLVMSetGlobalConstant(g, True);
Expand Down
10 changes: 5 additions & 5 deletions src/librustc_trans/trans/context.rs
Expand Up @@ -225,15 +225,15 @@ impl<'a, 'tcx> Iterator for CrateContextMaybeIterator<'a, 'tcx> {

unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) {
let llcx = llvm::LLVMContextCreate();
let mod_name = CString::from_slice(mod_name.as_bytes());
let mod_name = CString::new(mod_name).unwrap();
let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);

let data_layout = &*sess.target.target.data_layout;
let data_layout = CString::from_slice(data_layout.as_bytes());
let data_layout = sess.target.target.data_layout.as_bytes();
let data_layout = CString::new(data_layout).unwrap();
llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr());

let llvm_target = &*sess.target.target.llvm_target;
let llvm_target = CString::from_slice(llvm_target.as_bytes());
let llvm_target = sess.target.target.llvm_target.as_bytes();
let llvm_target = CString::new(llvm_target).unwrap();
llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
(llcx, llmod)
}
Expand Down

0 comments on commit 1860ee5

Please sign in to comment.