Skip to content

Commit 1860ee5

Browse files
committed
std: Implement CString-related RFCs
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 rust-lang#22469 Closes rust-lang#22470 [breaking-change]
1 parent dfc5c0f commit 1860ee5

40 files changed

+555
-290
lines changed

src/doc/trpl/ffi.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -435,8 +435,8 @@ extern {
435435
}
436436
437437
fn main() {
438-
let prompt = CString::from_slice(b"[my-awesome-shell] $");
439-
unsafe {
438+
let prompt = CString::new("[my-awesome-shell] $").unwrap();
439+
unsafe {
440440
rl_prompt = prompt.as_ptr();
441441
442442
println!("{:?}", rl_prompt);

src/librustc/metadata/loader.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -744,7 +744,7 @@ fn get_metadata_section_imp(is_osx: bool, filename: &Path) -> Result<MetadataBlo
744744
}
745745
}
746746
unsafe {
747-
let buf = CString::from_slice(filename.as_vec());
747+
let buf = CString::new(filename.as_vec()).unwrap();
748748
let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr());
749749
if mb as int == 0 {
750750
return Err(format!("error reading library: '{}'",

src/librustc_llvm/archive_ro.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ impl ArchiveRO {
3030
/// raised.
3131
pub fn open(dst: &Path) -> Option<ArchiveRO> {
3232
unsafe {
33-
let s = CString::from_slice(dst.as_vec());
33+
let s = CString::new(dst.as_vec()).unwrap();
3434
let ar = ::LLVMRustOpenArchive(s.as_ptr());
3535
if ar.is_null() {
3636
None
@@ -44,7 +44,7 @@ impl ArchiveRO {
4444
pub fn read<'a>(&'a self, file: &str) -> Option<&'a [u8]> {
4545
unsafe {
4646
let mut size = 0 as libc::size_t;
47-
let file = CString::from_slice(file.as_bytes());
47+
let file = CString::new(file).unwrap();
4848
let ptr = ::LLVMRustArchiveReadSection(self.ptr, file.as_ptr(),
4949
&mut size);
5050
if ptr.is_null() {

src/librustc_llvm/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2149,7 +2149,7 @@ impl Drop for TargetData {
21492149
}
21502150

21512151
pub fn mk_target_data(string_rep: &str) -> TargetData {
2152-
let string_rep = CString::from_slice(string_rep.as_bytes());
2152+
let string_rep = CString::new(string_rep).unwrap();
21532153
TargetData {
21542154
lltd: unsafe { LLVMCreateTargetData(string_rep.as_ptr()) }
21552155
}

src/librustc_trans/back/lto.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
140140

141141
// Internalize everything but the reachable symbols of the current module
142142
let cstrs: Vec<CString> = reachable.iter().map(|s| {
143-
CString::from_slice(s.as_bytes())
143+
CString::new(s.clone()).unwrap()
144144
}).collect();
145145
let arr: Vec<*const libc::c_char> = cstrs.iter().map(|c| c.as_ptr()).collect();
146146
let ptr = arr.as_ptr();

src/librustc_trans/back/write.rs

+14-14
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use syntax::codemap;
2222
use syntax::diagnostic;
2323
use syntax::diagnostic::{Emitter, Handler, Level, mk_handler};
2424

25-
use std::ffi::{self, CString};
25+
use std::ffi::{CStr, CString};
2626
use std::old_io::Command;
2727
use std::old_io::fs;
2828
use std::iter::Unfold;
@@ -49,7 +49,7 @@ pub fn llvm_err(handler: &diagnostic::Handler, msg: String) -> ! {
4949
if cstr == ptr::null() {
5050
handler.fatal(&msg[]);
5151
} else {
52-
let err = ffi::c_str_to_bytes(&cstr);
52+
let err = CStr::from_ptr(cstr).to_bytes();
5353
let err = String::from_utf8_lossy(err).to_string();
5454
libc::free(cstr as *mut _);
5555
handler.fatal(&format!("{}: {}",
@@ -67,7 +67,7 @@ pub fn write_output_file(
6767
output: &Path,
6868
file_type: llvm::FileType) {
6969
unsafe {
70-
let output_c = CString::from_slice(output.as_vec());
70+
let output_c = CString::new(output.as_vec()).unwrap();
7171
let result = llvm::LLVMRustWriteOutputFile(
7272
target, pm, m, output_c.as_ptr(), file_type);
7373
if !result {
@@ -221,13 +221,13 @@ fn create_target_machine(sess: &Session) -> TargetMachineRef {
221221
let triple = &sess.target.target.llvm_target[];
222222

223223
let tm = unsafe {
224-
let triple = CString::from_slice(triple.as_bytes());
224+
let triple = CString::new(triple.as_bytes()).unwrap();
225225
let cpu = match sess.opts.cg.target_cpu {
226226
Some(ref s) => &**s,
227227
None => &*sess.target.target.options.cpu
228228
};
229-
let cpu = CString::from_slice(cpu.as_bytes());
230-
let features = CString::from_slice(target_feature(sess).as_bytes());
229+
let cpu = CString::new(cpu.as_bytes()).unwrap();
230+
let features = CString::new(target_feature(sess).as_bytes()).unwrap();
231231
llvm::LLVMRustCreateTargetMachine(
232232
triple.as_ptr(), cpu.as_ptr(), features.as_ptr(),
233233
code_model,
@@ -380,7 +380,7 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo
380380
}
381381

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

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

455455
for pass in &config.passes {
456-
let pass = CString::from_slice(pass.as_bytes());
456+
let pass = CString::new(pass.clone()).unwrap();
457457
if !llvm::LLVMRustAddPass(mpm, pass.as_ptr()) {
458458
cgcx.handler.warn(&format!("unknown pass {:?}, ignoring", pass));
459459
}
@@ -477,7 +477,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
477477
if config.emit_lto_bc {
478478
let name = format!("{}.lto.bc", name_extra);
479479
let out = output_names.with_extension(&name);
480-
let out = CString::from_slice(out.as_vec());
480+
let out = CString::new(out.as_vec()).unwrap();
481481
llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
482482
}
483483
},
@@ -511,15 +511,15 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
511511
if config.emit_bc {
512512
let ext = format!("{}.bc", name_extra);
513513
let out = output_names.with_extension(&ext);
514-
let out = CString::from_slice(out.as_vec());
514+
let out = CString::new(out.as_vec()).unwrap();
515515
llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
516516
}
517517

518518
time(config.time_passes, "codegen passes", (), |()| {
519519
if config.emit_ir {
520520
let ext = format!("{}.ll", name_extra);
521521
let out = output_names.with_extension(&ext);
522-
let out = CString::from_slice(out.as_vec());
522+
let out = CString::new(out.as_vec()).unwrap();
523523
with_codegen(tm, llmod, config.no_builtins, |cpm| {
524524
llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr());
525525
})
@@ -1004,7 +1004,7 @@ unsafe fn configure_llvm(sess: &Session) {
10041004
let mut llvm_args = Vec::new();
10051005
{
10061006
let mut add = |arg: &str| {
1007-
let s = CString::from_slice(arg.as_bytes());
1007+
let s = CString::new(arg).unwrap();
10081008
llvm_args.push(s.as_ptr());
10091009
llvm_c_strs.push(s);
10101010
};

src/librustc_trans/trans/asm.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
120120
ast::AsmIntel => llvm::AD_Intel
121121
};
122122

123-
let asm = CString::from_slice(ia.asm.as_bytes());
124-
let constraints = CString::from_slice(constraints.as_bytes());
123+
let asm = CString::new(ia.asm.as_bytes()).unwrap();
124+
let constraints = CString::new(constraints).unwrap();
125125
let r = InlineAsmCall(bcx,
126126
asm.as_ptr(),
127127
constraints.as_ptr(),

src/librustc_trans/trans/base.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ use util::nodemap::NodeMap;
8686

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

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

@@ -2826,7 +2826,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
28262826
&sect)[]);
28272827
}
28282828
unsafe {
2829-
let buf = CString::from_slice(sect.as_bytes());
2829+
let buf = CString::new(sect.as_bytes()).unwrap();
28302830
llvm::LLVMSetSection(v, buf.as_ptr());
28312831
}
28322832
},
@@ -2993,15 +2993,15 @@ pub fn write_metadata(cx: &SharedCrateContext, krate: &ast::Crate) -> Vec<u8> {
29932993
let name = format!("rust_metadata_{}_{}",
29942994
cx.link_meta().crate_name,
29952995
cx.link_meta().crate_hash);
2996-
let buf = CString::from_vec(name.into_bytes());
2996+
let buf = CString::new(name).unwrap();
29972997
let llglobal = unsafe {
29982998
llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(),
29992999
buf.as_ptr())
30003000
};
30013001
unsafe {
30023002
llvm::LLVMSetInitializer(llglobal, llconst);
30033003
let name = loader::meta_section_name(cx.sess().target.target.options.is_like_osx);
3004-
let name = CString::from_slice(name.as_bytes());
3004+
let name = CString::new(name).unwrap();
30053005
llvm::LLVMSetSection(llglobal, name.as_ptr())
30063006
}
30073007
return metadata;
@@ -3039,8 +3039,8 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<String>) {
30393039
continue
30403040
}
30413041

3042-
let name = ffi::c_str_to_bytes(&llvm::LLVMGetValueName(val))
3043-
.to_vec();
3042+
let name = CStr::from_ptr(llvm::LLVMGetValueName(val))
3043+
.to_bytes().to_vec();
30443044
declared.insert(name);
30453045
}
30463046
}
@@ -3056,8 +3056,8 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<String>) {
30563056
continue
30573057
}
30583058

3059-
let name = ffi::c_str_to_bytes(&llvm::LLVMGetValueName(val))
3060-
.to_vec();
3059+
let name = CStr::from_ptr(llvm::LLVMGetValueName(val))
3060+
.to_bytes().to_vec();
30613061
if !declared.contains(&name) &&
30623062
!reachable.contains(str::from_utf8(&name).unwrap()) {
30633063
llvm::SetLinkage(val, llvm::InternalLinkage);

src/librustc_trans/trans/builder.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
431431
if name.is_empty() {
432432
llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname())
433433
} else {
434-
let name = CString::from_slice(name.as_bytes());
434+
let name = CString::new(name).unwrap();
435435
llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(),
436436
name.as_ptr())
437437
}
@@ -786,7 +786,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
786786
let comment_text = format!("{} {}", "#",
787787
sanitized.replace("\n", "\n\t# "));
788788
self.count_insn("inlineasm");
789-
let comment_text = CString::from_vec(comment_text.into_bytes());
789+
let comment_text = CString::new(comment_text).unwrap();
790790
let asm = unsafe {
791791
llvm::LLVMConstInlineAsm(Type::func(&[], &Type::void(self.ccx)).to_ref(),
792792
comment_text.as_ptr(), noname(), False,

src/librustc_trans/trans/common.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
488488
opt_node_id: Option<ast::NodeId>)
489489
-> Block<'a, 'tcx> {
490490
unsafe {
491-
let name = CString::from_slice(name.as_bytes());
491+
let name = CString::new(name).unwrap();
492492
let llbb = llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(),
493493
self.llfn,
494494
name.as_ptr());
@@ -761,7 +761,7 @@ pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef {
761761

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

841841
let gsym = token::gensym("str");
842-
let buf = CString::from_vec(format!("str{}", gsym.usize()).into_bytes());
842+
let buf = CString::new(format!("str{}", gsym.usize()));
843+
let buf = buf.unwrap();
843844
let g = llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf.as_ptr());
844845
llvm::LLVMSetInitializer(g, sc);
845846
llvm::LLVMSetGlobalConstant(g, True);

src/librustc_trans/trans/context.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -225,15 +225,15 @@ impl<'a, 'tcx> Iterator for CrateContextMaybeIterator<'a, 'tcx> {
225225

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

231-
let data_layout = &*sess.target.target.data_layout;
232-
let data_layout = CString::from_slice(data_layout.as_bytes());
231+
let data_layout = sess.target.target.data_layout.as_bytes();
232+
let data_layout = CString::new(data_layout).unwrap();
233233
llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr());
234234

235-
let llvm_target = &*sess.target.target.llvm_target;
236-
let llvm_target = CString::from_slice(llvm_target.as_bytes());
235+
let llvm_target = sess.target.target.llvm_target.as_bytes();
236+
let llvm_target = CString::new(llvm_target).unwrap();
237237
llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
238238
(llcx, llmod)
239239
}

0 commit comments

Comments
 (0)