about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Woerister <michaelwoerister@posteo>2018-08-07 16:04:34 +0200
committerMichael Woerister <michaelwoerister@posteo>2018-08-10 11:13:00 +0200
commit88d84b38f19eff3c25ec88931f04bf2640edf2b5 (patch)
tree1b161e6842a4e32c29ba92332eb5b28f81d0e3ec
parent9585c5dc1fa3cef34ebdc5a5d39af88db60c6f15 (diff)
downloadrust-88d84b38f19eff3c25ec88931f04bf2640edf2b5.tar.gz
rust-88d84b38f19eff3c25ec88931f04bf2640edf2b5.zip
Introduce SmallCStr and use it where applicable.
-rw-r--r--src/librustc_codegen_llvm/attributes.rs2
-rw-r--r--src/librustc_codegen_llvm/back/write.rs10
-rw-r--r--src/librustc_codegen_llvm/base.rs5
-rw-r--r--src/librustc_codegen_llvm/builder.rs8
-rw-r--r--src/librustc_codegen_llvm/context.rs10
-rw-r--r--src/librustc_codegen_llvm/debuginfo/metadata.rs74
-rw-r--r--src/librustc_codegen_llvm/debuginfo/mod.rs7
-rw-r--r--src/librustc_codegen_llvm/debuginfo/namespace.rs4
-rw-r--r--src/librustc_codegen_llvm/declare.rs14
-rw-r--r--src/librustc_codegen_llvm/llvm/mod.rs5
-rw-r--r--src/librustc_codegen_llvm/type_.rs4
-rw-r--r--src/librustc_data_structures/lib.rs1
-rw-r--r--src/librustc_data_structures/small_c_str.rs131
13 files changed, 200 insertions, 75 deletions
diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs
index 74f7e6f2ce7..816242129f3 100644
--- a/src/librustc_codegen_llvm/attributes.rs
+++ b/src/librustc_codegen_llvm/attributes.rs
@@ -128,7 +128,7 @@ pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
     llvm::AddFunctionAttrStringValue(
             llfn,
             llvm::AttributePlace::Function,
-            cstr("target-cpu\0"),
+            const_cstr!("target-cpu"),
             target_cpu.as_c_str());
 }
 
diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs
index cdfa874b177..ebe8b797414 100644
--- a/src/librustc_codegen_llvm/back/write.rs
+++ b/src/librustc_codegen_llvm/back/write.rs
@@ -31,6 +31,7 @@ use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc::ty::TyCtxt;
 use rustc::util::common::{time_ext, time_depth, set_time_depth, print_time_passes_entry};
 use rustc_fs_util::{path2cstr, link_or_copy};
+use rustc_data_structures::small_c_str::SmallCStr;
 use errors::{self, Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId};
 use errors::emitter::{Emitter};
 use syntax::attr;
@@ -170,11 +171,8 @@ pub fn target_machine_factory(sess: &Session, find_features: bool)
 
     let singlethread = sess.target.target.options.singlethread;
 
-    let triple = &sess.target.target.llvm_target;
-
-    let triple = CString::new(triple.as_bytes()).unwrap();
-    let cpu = sess.target_cpu();
-    let cpu = CString::new(cpu.as_bytes()).unwrap();
+    let triple = SmallCStr::new(&sess.target.target.llvm_target);
+    let cpu = SmallCStr::new(sess.target_cpu());
     let features = attributes::llvm_target_features(sess)
         .collect::<Vec<_>>()
         .join(",");
@@ -522,7 +520,7 @@ unsafe fn optimize(cgcx: &CodegenContext,
             // If we're verifying or linting, add them to the function pass
             // manager.
             let addpass = |pass_name: &str| {
-                let pass_name = CString::new(pass_name).unwrap();
+                let pass_name = SmallCStr::new(pass_name);
                 let pass = match llvm::LLVMRustFindAndCreatePass(pass_name.as_ptr()) {
                     Some(pass) => pass,
                     None => return false,
diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs
index 4415adc27d6..7ca6a89dd9b 100644
--- a/src/librustc_codegen_llvm/base.rs
+++ b/src/librustc_codegen_llvm/base.rs
@@ -73,6 +73,7 @@ use type_::Type;
 use type_of::LayoutLlvmExt;
 use rustc::util::nodemap::{FxHashMap, FxHashSet, DefIdSet};
 use CrateInfo;
+use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_data_structures::sync::Lrc;
 
 use std::any::Any;
@@ -533,7 +534,7 @@ pub fn set_link_section(llval: &Value, attrs: &CodegenFnAttrs) {
         None => return,
     };
     unsafe {
-        let buf = CString::new(sect.as_str().as_bytes()).unwrap();
+        let buf = SmallCStr::new(&sect.as_str());
         llvm::LLVMSetSection(llval, buf.as_ptr());
     }
 }
@@ -681,7 +682,7 @@ fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
     unsafe {
         llvm::LLVMSetInitializer(llglobal, llconst);
         let section_name = metadata::metadata_section_name(&tcx.sess.target.target);
-        let name = CString::new(section_name).unwrap();
+        let name = SmallCStr::new(section_name);
         llvm::LLVMSetSection(llglobal, name.as_ptr());
 
         // Also generate a .section directive to force no
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index bc82886714a..b0f88bd4189 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -18,9 +18,9 @@ use libc::{c_uint, c_char};
 use rustc::ty::TyCtxt;
 use rustc::ty::layout::{Align, Size};
 use rustc::session::{config, Session};
+use rustc_data_structures::small_c_str::SmallCStr;
 
 use std::borrow::Cow;
-use std::ffi::CString;
 use std::ops::Range;
 use std::ptr;
 
@@ -58,7 +58,7 @@ impl Builder<'a, 'll, 'tcx> {
     pub fn new_block<'b>(cx: &'a CodegenCx<'ll, 'tcx>, llfn: &'ll Value, name: &'b str) -> Self {
         let bx = Builder::with_cx(cx);
         let llbb = unsafe {
-            let name = CString::new(name).unwrap();
+            let name = SmallCStr::new(name);
             llvm::LLVMAppendBasicBlockInContext(
                 cx.llcx,
                 llfn,
@@ -118,7 +118,7 @@ impl Builder<'a, 'll, 'tcx> {
     }
 
     pub fn set_value_name(&self, value: &'ll Value, name: &str) {
-        let cname = CString::new(name.as_bytes()).unwrap();
+        let cname = SmallCStr::new(name);
         unsafe {
             llvm::LLVMSetValueName(value, cname.as_ptr());
         }
@@ -436,7 +436,7 @@ impl Builder<'a, 'll, 'tcx> {
             let alloca = if name.is_empty() {
                 llvm::LLVMBuildAlloca(self.llbuilder, ty, noname())
             } else {
-                let name = CString::new(name).unwrap();
+                let name = SmallCStr::new(name);
                 llvm::LLVMBuildAlloca(self.llbuilder, ty,
                                       name.as_ptr())
             };
diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs
index 7a308bb6e88..781f8ebbb78 100644
--- a/src/librustc_codegen_llvm/context.rs
+++ b/src/librustc_codegen_llvm/context.rs
@@ -26,6 +26,7 @@ use type_::Type;
 use type_of::PointeeInfo;
 
 use rustc_data_structures::base_n;
+use rustc_data_structures::small_c_str::SmallCStr;
 use rustc::mir::mono::Stats;
 use rustc::session::config::{self, DebugInfo};
 use rustc::session::Session;
@@ -34,7 +35,7 @@ use rustc::ty::{self, Ty, TyCtxt};
 use rustc::util::nodemap::FxHashMap;
 use rustc_target::spec::{HasTargetSpec, Target};
 
-use std::ffi::{CStr, CString};
+use std::ffi::CStr;
 use std::cell::{Cell, RefCell};
 use std::iter;
 use std::str;
@@ -161,7 +162,7 @@ pub unsafe fn create_module(
     llcx: &'ll llvm::Context,
     mod_name: &str,
 ) -> &'ll llvm::Module {
-    let mod_name = CString::new(mod_name).unwrap();
+    let mod_name = SmallCStr::new(mod_name);
     let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
 
     // Ensure the data-layout values hardcoded remain the defaults.
@@ -201,11 +202,10 @@ pub unsafe fn create_module(
         }
     }
 
-    let data_layout = CString::new(&sess.target.target.data_layout[..]).unwrap();
+    let data_layout = SmallCStr::new(&sess.target.target.data_layout);
     llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr());
 
-    let llvm_target = sess.target.target.llvm_target.as_bytes();
-    let llvm_target = CString::new(llvm_target).unwrap();
+    let llvm_target = SmallCStr::new(&sess.target.target.llvm_target);
     llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
 
     if is_pie_binary(sess) {
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index 3bd1a1519b6..223fa75723c 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -37,6 +37,7 @@ use rustc::ty::layout::{self, Align, LayoutOf, PrimitiveExt, Size, TyLayout};
 use rustc::session::config;
 use rustc::util::nodemap::FxHashMap;
 use rustc_fs_util::path2cstr;
+use rustc_data_structures::small_c_str::SmallCStr;
 
 use libc::{c_uint, c_longlong};
 use std::ffi::CString;
@@ -274,7 +275,7 @@ impl RecursiveTypeDescription<'ll, 'tcx> {
                 // ... and attach them to the stub to complete it.
                 set_members_of_composite_type(cx,
                                               metadata_stub,
-                                              &member_descriptions[..]);
+                                              member_descriptions);
                 return MetadataCreationResult::new(metadata_stub, true);
             }
         }
@@ -349,7 +350,7 @@ fn vec_slice_metadata(
     let (pointer_size, pointer_align) = cx.size_and_align_of(data_ptr_type);
     let (usize_size, usize_align) = cx.size_and_align_of(cx.tcx.types.usize);
 
-    let member_descriptions = [
+    let member_descriptions = vec![
         MemberDescription {
             name: "data_ptr".to_string(),
             type_metadata: data_ptr_metadata,
@@ -374,7 +375,7 @@ fn vec_slice_metadata(
                                            slice_ptr_type,
                                            &slice_type_name[..],
                                            unique_type_id,
-                                           &member_descriptions,
+                                           member_descriptions,
                                            NO_SCOPE_METADATA,
                                            file_metadata,
                                            span);
@@ -460,7 +461,7 @@ fn trait_pointer_metadata(
 
     let data_ptr_field = layout.field(cx, 0);
     let vtable_field = layout.field(cx, 1);
-    let member_descriptions = [
+    let member_descriptions = vec![
         MemberDescription {
             name: "pointer".to_string(),
             type_metadata: type_metadata(cx,
@@ -485,7 +486,7 @@ fn trait_pointer_metadata(
                             trait_object_type,
                             &trait_type_name[..],
                             unique_type_id,
-                            &member_descriptions,
+                            member_descriptions,
                             containing_scope,
                             file_metadata,
                             syntax_pos::DUMMY_SP)
@@ -746,8 +747,8 @@ fn file_metadata_raw(cx: &CodegenCx<'ll, '_>,
 
     debug!("file_metadata: file_name: {}, directory: {}", file_name, directory);
 
-    let file_name = CString::new(file_name).unwrap();
-    let directory = CString::new(directory).unwrap();
+    let file_name = SmallCStr::new(file_name);
+    let directory = SmallCStr::new(directory);
 
     let file_metadata = unsafe {
         llvm::LLVMRustDIBuilderCreateFile(DIB(cx),
@@ -782,7 +783,7 @@ fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
     };
 
     let (size, align) = cx.size_and_align_of(t);
-    let name = CString::new(name).unwrap();
+    let name = SmallCStr::new(name);
     let ty_metadata = unsafe {
         llvm::LLVMRustDIBuilderCreateBasicType(
             DIB(cx),
@@ -813,7 +814,7 @@ fn pointer_type_metadata(
 ) -> &'ll DIType {
     let (pointer_size, pointer_align) = cx.size_and_align_of(pointer_type);
     let name = compute_debuginfo_type_name(cx, pointer_type, false);
-    let name = CString::new(name).unwrap();
+    let name = SmallCStr::new(&name);
     unsafe {
         llvm::LLVMRustDIBuilderCreatePointerType(
             DIB(cx),
@@ -847,9 +848,9 @@ pub fn compile_unit_metadata(tcx: TyCtxt,
     let producer = format!("clang LLVM (rustc version {})",
                            (option_env!("CFG_VERSION")).expect("CFG_VERSION"));
 
-    let name_in_debuginfo = name_in_debuginfo.to_string_lossy().into_owned();
-    let name_in_debuginfo = CString::new(name_in_debuginfo).unwrap();
-    let work_dir = CString::new(&tcx.sess.working_dir.0.to_string_lossy()[..]).unwrap();
+    let name_in_debuginfo = name_in_debuginfo.to_string_lossy();
+    let name_in_debuginfo = SmallCStr::new(&name_in_debuginfo);
+    let work_dir = SmallCStr::new(&tcx.sess.working_dir.0.to_string_lossy());
     let producer = CString::new(producer).unwrap();
     let flags = "\0";
     let split_name = "\0";
@@ -1187,7 +1188,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
 
                 set_members_of_composite_type(cx,
                                               variant_type_metadata,
-                                              &member_descriptions[..]);
+                                              member_descriptions);
                 vec![
                     MemberDescription {
                         name: "".to_string(),
@@ -1217,7 +1218,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
 
                     set_members_of_composite_type(cx,
                                                   variant_type_metadata,
-                                                  &member_descriptions);
+                                                  member_descriptions);
                     MemberDescription {
                         name: "".to_string(),
                         type_metadata: variant_type_metadata,
@@ -1244,7 +1245,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
 
                 set_members_of_composite_type(cx,
                                               variant_type_metadata,
-                                              &variant_member_descriptions[..]);
+                                              variant_member_descriptions);
 
                 // Encode the information about the null variant in the union
                 // member's name.
@@ -1416,8 +1417,7 @@ fn prepare_enum_metadata(
     let enumerators_metadata: Vec<_> = def.discriminants(cx.tcx)
         .zip(&def.variants)
         .map(|(discr, v)| {
-            let token = v.name.as_str();
-            let name = CString::new(token.as_bytes()).unwrap();
+            let name = SmallCStr::new(&v.name.as_str());
             unsafe {
                 Some(llvm::LLVMRustDIBuilderCreateEnumerator(
                     DIB(cx),
@@ -1442,7 +1442,7 @@ fn prepare_enum_metadata(
                     type_metadata(cx, discr.to_ty(cx.tcx), syntax_pos::DUMMY_SP);
                 let discriminant_name = get_enum_discriminant_name(cx, enum_def_id).as_str();
 
-                let name = CString::new(discriminant_name.as_bytes()).unwrap();
+                let name = SmallCStr::new(&discriminant_name);
                 let discriminant_type_metadata = unsafe {
                     llvm::LLVMRustDIBuilderCreateEnumerationType(
                         DIB(cx),
@@ -1482,10 +1482,10 @@ fn prepare_enum_metadata(
 
     let (enum_type_size, enum_type_align) = layout.size_and_align();
 
-    let enum_name = CString::new(enum_name).unwrap();
-    let unique_type_id_str = CString::new(
-        debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id).as_bytes()
-    ).unwrap();
+    let enum_name = SmallCStr::new(&enum_name);
+    let unique_type_id_str = SmallCStr::new(
+        debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id)
+    );
     let enum_metadata = unsafe {
         llvm::LLVMRustDIBuilderCreateUnionType(
         DIB(cx),
@@ -1531,7 +1531,7 @@ fn composite_type_metadata(
     composite_type: Ty<'tcx>,
     composite_type_name: &str,
     composite_type_unique_id: UniqueTypeId,
-    member_descriptions: &[MemberDescription<'ll>],
+    member_descriptions: Vec<MemberDescription<'ll>>,
     containing_scope: Option<&'ll DIScope>,
 
     // Ignore source location information as long as it
@@ -1555,7 +1555,7 @@ fn composite_type_metadata(
 
 fn set_members_of_composite_type(cx: &CodegenCx<'ll, '_>,
                                  composite_type_metadata: &'ll DICompositeType,
-                                 member_descriptions: &[MemberDescription<'ll>]) {
+                                 member_descriptions: Vec<MemberDescription<'ll>>) {
     // In some rare cases LLVM metadata uniquing would lead to an existing type
     // description being used instead of a new one created in
     // create_struct_stub. This would cause a hard to trace assertion in
@@ -1574,10 +1574,9 @@ fn set_members_of_composite_type(cx: &CodegenCx<'ll, '_>,
     }
 
     let member_metadata: Vec<_> = member_descriptions
-        .iter()
+        .into_iter()
         .map(|member_description| {
-            let member_name = member_description.name.as_bytes();
-            let member_name = CString::new(member_name).unwrap();
+            let member_name = CString::new(member_description.name).unwrap();
             unsafe {
                 Some(llvm::LLVMRustDIBuilderCreateMemberType(
                     DIB(cx),
@@ -1613,10 +1612,10 @@ fn create_struct_stub(
 ) -> &'ll DICompositeType {
     let (struct_size, struct_align) = cx.size_and_align_of(struct_type);
 
-    let name = CString::new(struct_type_name).unwrap();
-    let unique_type_id = CString::new(
-        debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id).as_bytes()
-    ).unwrap();
+    let name = SmallCStr::new(struct_type_name);
+    let unique_type_id = SmallCStr::new(
+        debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id)
+    );
     let metadata_stub = unsafe {
         // LLVMRustDIBuilderCreateStructType() wants an empty array. A null
         // pointer will lead to hard to trace and debug LLVM assertions
@@ -1651,10 +1650,10 @@ fn create_union_stub(
 ) -> &'ll DICompositeType {
     let (union_size, union_align) = cx.size_and_align_of(union_type);
 
-    let name = CString::new(union_type_name).unwrap();
-    let unique_type_id = CString::new(
-        debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id).as_bytes()
-    ).unwrap();
+    let name = SmallCStr::new(union_type_name);
+    let unique_type_id = SmallCStr::new(
+        debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id)
+    );
     let metadata_stub = unsafe {
         // LLVMRustDIBuilderCreateUnionType() wants an empty array. A null
         // pointer will lead to hard to trace and debug LLVM assertions
@@ -1713,13 +1712,12 @@ pub fn create_global_var_metadata(
     let is_local_to_unit = is_node_local_to_unit(cx, def_id);
     let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx);
     let type_metadata = type_metadata(cx, variable_type, span);
-    let var_name = tcx.item_name(def_id).to_string();
-    let var_name = CString::new(var_name).unwrap();
+    let var_name = SmallCStr::new(&tcx.item_name(def_id).as_str());
     let linkage_name = if no_mangle {
         None
     } else {
         let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id));
-        Some(CString::new(linkage_name.to_string()).unwrap())
+        Some(SmallCStr::new(&linkage_name.as_str()))
     };
 
     let global_align = cx.align_of(variable_type);
diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs
index d4fb2549a75..fcb8bc3fe2b 100644
--- a/src/librustc_codegen_llvm/debuginfo/mod.rs
+++ b/src/librustc_codegen_llvm/debuginfo/mod.rs
@@ -34,6 +34,7 @@ use rustc::ty::{self, ParamEnv, Ty, InstanceDef};
 use rustc::mir;
 use rustc::session::config::{self, DebugInfo};
 use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet};
+use rustc_data_structures::small_c_str::SmallCStr;
 use value::Value;
 
 use libc::c_uint;
@@ -265,7 +266,7 @@ pub fn create_function_debug_context(
     let is_local_to_unit = is_node_local_to_unit(cx, def_id);
 
     let function_name = CString::new(name).unwrap();
-    let linkage_name = CString::new(linkage_name.to_string()).unwrap();
+    let linkage_name = SmallCStr::new(&linkage_name.as_str());
 
     let mut flags = DIFlags::FlagPrototyped;
 
@@ -407,7 +408,7 @@ pub fn create_function_debug_context(
                     let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
                     let actual_type_metadata =
                         type_metadata(cx, actual_type, syntax_pos::DUMMY_SP);
-                    let name = CString::new(name.as_str().as_bytes()).unwrap();
+                    let name = SmallCStr::new(&name.as_str());
                     Some(unsafe {
                         Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
                             DIB(cx),
@@ -510,7 +511,7 @@ pub fn declare_local(
     };
     let align = cx.align_of(variable_type);
 
-    let name = CString::new(variable_name.as_str().as_bytes()).unwrap();
+    let name = SmallCStr::new(&variable_name.as_str());
     match (variable_access, &[][..]) {
         (DirectVariable { alloca }, address_operations) |
         (IndirectVariable {alloca, address_operations}, _) => {
diff --git a/src/librustc_codegen_llvm/debuginfo/namespace.rs b/src/librustc_codegen_llvm/debuginfo/namespace.rs
index 9f1141a7e7d..06f8a4b131b 100644
--- a/src/librustc_codegen_llvm/debuginfo/namespace.rs
+++ b/src/librustc_codegen_llvm/debuginfo/namespace.rs
@@ -21,7 +21,7 @@ use rustc::hir::def_id::DefId;
 use rustc::hir::map::DefPathData;
 use common::CodegenCx;
 
-use std::ffi::CString;
+use rustc_data_structures::small_c_str::SmallCStr;
 
 pub fn mangled_name_of_instance<'a, 'tcx>(
     cx: &CodegenCx<'a, 'tcx>,
@@ -49,7 +49,7 @@ pub fn item_namespace(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
         data => data.as_interned_str().as_str()
     };
 
-    let namespace_name = CString::new(namespace_name.as_bytes()).unwrap();
+    let namespace_name = SmallCStr::new(&namespace_name);
 
     let scope = unsafe {
         llvm::LLVMRustDIBuilderCreateNameSpace(
diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs
index a0310eecd59..5e743ac51bc 100644
--- a/src/librustc_codegen_llvm/declare.rs
+++ b/src/librustc_codegen_llvm/declare.rs
@@ -25,6 +25,7 @@ use llvm::AttributePlace::Function;
 use rustc::ty::{self, Ty};
 use rustc::ty::layout::{self, LayoutOf};
 use rustc::session::config::Sanitizer;
+use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_target::spec::PanicStrategy;
 use abi::{Abi, FnType, FnTypeExt};
 use attributes;
@@ -33,7 +34,6 @@ use common;
 use type_::Type;
 use value::Value;
 
-use std::ffi::CString;
 
 /// Declare a global value.
 ///
@@ -41,9 +41,7 @@ use std::ffi::CString;
 /// return its Value instead.
 pub fn declare_global(cx: &CodegenCx<'ll, '_>, name: &str, ty: &'ll Type) -> &'ll Value {
     debug!("declare_global(name={:?})", name);
-    let namebuf = CString::new(name).unwrap_or_else(|_|{
-        bug!("name {:?} contains an interior null byte", name)
-    });
+    let namebuf = SmallCStr::new(name);
     unsafe {
         llvm::LLVMRustGetOrInsertGlobal(cx.llmod, namebuf.as_ptr(), ty)
     }
@@ -61,9 +59,7 @@ fn declare_raw_fn(
     ty: &'ll Type,
 ) -> &'ll Value {
     debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty);
-    let namebuf = CString::new(name).unwrap_or_else(|_|{
-        bug!("name {:?} contains an interior null byte", name)
-    });
+    let namebuf = SmallCStr::new(name);
     let llfn = unsafe {
         llvm::LLVMRustGetOrInsertFunction(cx.llmod, namebuf.as_ptr(), ty)
     };
@@ -214,9 +210,7 @@ pub fn define_internal_fn(
 /// Get declared value by name.
 pub fn get_declared_value(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Value> {
     debug!("get_declared_value(name={:?})", name);
-    let namebuf = CString::new(name).unwrap_or_else(|_|{
-        bug!("name {:?} contains an interior null byte", name)
-    });
+    let namebuf = SmallCStr::new(name);
     unsafe { llvm::LLVMRustGetNamedValue(cx.llmod, namebuf.as_ptr()) }
 }
 
diff --git a/src/librustc_codegen_llvm/llvm/mod.rs b/src/librustc_codegen_llvm/llvm/mod.rs
index 558d2a2bc87..4343c8c184e 100644
--- a/src/librustc_codegen_llvm/llvm/mod.rs
+++ b/src/librustc_codegen_llvm/llvm/mod.rs
@@ -24,9 +24,10 @@ pub use self::Linkage::*;
 use std::str::FromStr;
 use std::string::FromUtf8Error;
 use std::slice;
-use std::ffi::{CString, CStr};
+use std::ffi::CStr;
 use std::cell::RefCell;
 use libc::{self, c_uint, c_char, size_t};
+use rustc_data_structures::small_c_str::SmallCStr;
 
 pub mod archive_ro;
 pub mod diagnostic;
@@ -264,7 +265,7 @@ pub struct OperandBundleDef<'a> {
 
 impl OperandBundleDef<'a> {
     pub fn new(name: &str, vals: &[&'a Value]) -> Self {
-        let name = CString::new(name).unwrap();
+        let name = SmallCStr::new(name);
         let def = unsafe {
             LLVMRustBuildOperandBundleDef(name.as_ptr(), vals.as_ptr(), vals.len() as c_uint)
         };
diff --git a/src/librustc_codegen_llvm/type_.rs b/src/librustc_codegen_llvm/type_.rs
index 9fa7cc46aee..51a233d7916 100644
--- a/src/librustc_codegen_llvm/type_.rs
+++ b/src/librustc_codegen_llvm/type_.rs
@@ -19,8 +19,8 @@ use context::CodegenCx;
 
 use syntax::ast;
 use rustc::ty::layout::{self, Align, Size};
+use rustc_data_structures::small_c_str::SmallCStr;
 
-use std::ffi::CString;
 use std::fmt;
 
 use libc::c_uint;
@@ -201,7 +201,7 @@ impl Type {
     }
 
     pub fn named_struct(cx: &CodegenCx<'ll, '_>, name: &str) -> &'ll Type {
-        let name = CString::new(name).unwrap();
+        let name = SmallCStr::new(name);
         unsafe {
             llvm::LLVMStructCreateNamed(cx.llcx, name.as_ptr())
         }
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index bd11a2977ff..8a586d8c233 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -70,6 +70,7 @@ pub mod obligation_forest;
 pub mod owning_ref;
 pub mod ptr_key;
 pub mod sip128;
+pub mod small_c_str;
 pub mod small_vec;
 pub mod snapshot_map;
 pub use ena::snapshot_vec;
diff --git a/src/librustc_data_structures/small_c_str.rs b/src/librustc_data_structures/small_c_str.rs
new file mode 100644
index 00000000000..b0ad83e4979
--- /dev/null
+++ b/src/librustc_data_structures/small_c_str.rs
@@ -0,0 +1,131 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::ffi;
+use std::ops::Deref;
+
+const SIZE: usize = 38;
+
+/// Like SmallVec but for C strings.
+#[derive(Clone)]
+pub enum SmallCStr {
+    OnStack {
+        data: [u8; SIZE],
+        len_with_nul: u8,
+    },
+    OnHeap {
+        data: ffi::CString,
+    }
+}
+
+impl SmallCStr {
+    #[inline]
+    pub fn new(s: &str) -> SmallCStr {
+        if s.len() < SIZE {
+            let mut data = [0; SIZE];
+            data[.. s.len()].copy_from_slice(s.as_bytes());
+            let len_with_nul = s.len() + 1;
+
+            // Make sure once that this is a valid CStr
+            if let Err(e) = ffi::CStr::from_bytes_with_nul(&data[.. len_with_nul]) {
+                panic!("The string \"{}\" cannot be converted into a CStr: {}", s, e);
+            }
+
+            SmallCStr::OnStack {
+                data,
+                len_with_nul: len_with_nul as u8,
+            }
+        } else {
+            SmallCStr::OnHeap {
+                data: ffi::CString::new(s).unwrap()
+            }
+        }
+    }
+
+    #[inline]
+    pub fn as_c_str(&self) -> &ffi::CStr {
+        match *self {
+            SmallCStr::OnStack { ref data, len_with_nul } => {
+                unsafe {
+                    let slice = &data[.. len_with_nul as usize];
+                    ffi::CStr::from_bytes_with_nul_unchecked(slice)
+                }
+            }
+            SmallCStr::OnHeap { ref data } => {
+                data.as_c_str()
+            }
+        }
+    }
+
+    #[inline]
+    pub fn len_with_nul(&self) -> usize {
+        match *self {
+            SmallCStr::OnStack { len_with_nul, .. } => {
+                len_with_nul as usize
+            }
+            SmallCStr::OnHeap { ref data } => {
+                data.as_bytes_with_nul().len()
+            }
+        }
+    }
+}
+
+impl Deref for SmallCStr {
+    type Target = ffi::CStr;
+
+    fn deref(&self) -> &ffi::CStr {
+        self.as_c_str()
+    }
+}
+
+
+#[test]
+fn short() {
+    const TEXT: &str = "abcd";
+    let reference = ffi::CString::new(TEXT.to_string()).unwrap();
+
+    let scs = SmallCStr::new(TEXT);
+
+    assert_eq!(scs.len_with_nul(), TEXT.len() + 1);
+    assert_eq!(scs.as_c_str(), reference.as_c_str());
+    assert!(if let SmallCStr::OnStack { .. } = scs { true } else { false });
+}
+
+#[test]
+fn empty() {
+    const TEXT: &str = "";
+    let reference = ffi::CString::new(TEXT.to_string()).unwrap();
+
+    let scs = SmallCStr::new(TEXT);
+
+    assert_eq!(scs.len_with_nul(), TEXT.len() + 1);
+    assert_eq!(scs.as_c_str(), reference.as_c_str());
+    assert!(if let SmallCStr::OnStack { .. } = scs { true } else { false });
+}
+
+#[test]
+fn long() {
+    const TEXT: &str = "01234567890123456789012345678901234567890123456789\
+                        01234567890123456789012345678901234567890123456789\
+                        01234567890123456789012345678901234567890123456789";
+    let reference = ffi::CString::new(TEXT.to_string()).unwrap();
+
+    let scs = SmallCStr::new(TEXT);
+
+    assert_eq!(scs.len_with_nul(), TEXT.len() + 1);
+    assert_eq!(scs.as_c_str(), reference.as_c_str());
+    assert!(if let SmallCStr::OnHeap { .. } = scs { true } else { false });
+}
+
+#[test]
+#[should_panic]
+fn internal_nul() {
+    let _ = SmallCStr::new("abcd\0def");
+}