From 34d607f9c9e3c103fc7f98b4c6fa18ff71905bb6 Mon Sep 17 00:00:00 2001
From: Nick Cameron <ncameron@mozilla.com>
Date: Fri, 25 Apr 2014 15:14:52 +1200
Subject: [PATCH] Use the slice repr for ~[T]

---
 src/libcollections/slice.rs            |  60 ++++++++
 src/libcore/mem.rs                     |   2 +-
 src/librustc/middle/trans/adt.rs       |   4 +-
 src/librustc/middle/trans/base.rs      |  19 ++-
 src/librustc/middle/trans/debuginfo.rs |  81 +----------
 src/librustc/middle/trans/expr.rs      |  12 +-
 src/librustc/middle/trans/glue.rs      |  22 +--
 src/librustc/middle/trans/reflect.rs   |  13 +-
 src/librustc/middle/trans/tvec.rs      | 185 ++++++++++---------------
 src/librustc/middle/trans/type_.rs     |   2 +-
 src/librustc/middle/trans/type_of.rs   |  23 +--
 src/librustc/middle/ty.rs              |   3 +-
 src/librustc_back/abi.rs               |   6 -
 src/libserialize/serialize.rs          |   1 +
 src/libtime/lib.rs                     |  36 ++++-
 src/rt/rust_builtin.c                  |  42 +++++-
 16 files changed, 247 insertions(+), 264 deletions(-)

diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs
index c137cc25b25..bd8e18d1f3c 100644
--- a/src/libcollections/slice.rs
+++ b/src/libcollections/slice.rs
@@ -92,6 +92,8 @@ use core::iter::{range_step, MultiplicativeIterator};
 
 use MutableSeq;
 use vec::Vec;
+#[cfg(not(stage0))]
+use raw::Slice;
 
 pub use core::slice::{Chunks, Slice, ImmutableSlice, ImmutablePartialEqSlice};
 pub use core::slice::{ImmutableOrdSlice, MutableSlice, Items, MutItems};
@@ -282,6 +284,64 @@ pub trait CloneableVector<T> {
 
 impl<'a, T: Clone> CloneableVector<T> for &'a [T] {
     /// Returns a copy of `v`.
+    #[cfg(not(stage0))]
+    fn to_owned(&self) -> ~[T] {
+        use num::CheckedMul;
+        use option::Expect;
+
+        let len = self.len();
+
+        if len == 0 {
+            unsafe {
+                let slice: Slice<T> = Slice{data: 0 as *T, len: 0};
+                mem::transmute(slice)
+            }
+        } else {
+            let unit_size = mem::size_of::<T>();
+            let data_size = if unit_size == 0 {
+                len
+            } else {
+                let data_size = len.checked_mul(&unit_size);
+                data_size.expect("overflow in from_iter()")
+            };
+
+            unsafe {
+                // this should pass the real required alignment
+                let ret = allocate(data_size, 8) as *mut T;
+
+                if unit_size > 0 {
+                    // Be careful with the following loop. We want it to be optimized
+                    // to a memcpy (or something similarly fast) when T is Copy. LLVM
+                    // is easily confused, so any extra operations during the loop can
+                    // prevent this optimization.
+                    let mut i = 0;
+                    let p = &mut (*ret) as *mut _ as *mut T;
+                    try_finally(
+                        &mut i, (),
+                        |i, ()| while *i < len {
+                            mem::move_val_init(
+                                &mut(*p.offset(*i as int)),
+                                self.unsafe_ref(*i).clone());
+                            *i += 1;
+                        },
+                        |i| if *i < len {
+                            // we must be failing, clean up after ourselves
+                            for j in range(0, *i as int) {
+                                ptr::read(&*p.offset(j));
+                            }
+                            // FIXME: #13994 (should pass align and size here)
+                            deallocate(ret as *mut u8, 0, 8);
+                        });
+                }
+                let slice: Slice<T> = Slice{data: ret as *T, len: len};
+                mem::transmute(slice)
+            }
+        }
+    }
+
+    /// Returns a copy of `v`.
+    // NOTE: remove after snapshot
+    #[cfg(stage0)]
     #[inline]
     fn to_vec(&self) -> Vec<T> { Vec::from_slice(*self) }
 
diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs
index 4de81db1013..f0c39766ebb 100644
--- a/src/libcore/mem.rs
+++ b/src/libcore/mem.rs
@@ -174,7 +174,7 @@ pub unsafe fn overwrite<T>(dst: *mut T, src: T) {
 
 /// Deprecated, use `overwrite` instead
 #[inline]
-#[deprecated = "use ptr::write"]
+#[deprecated = "this function has been renamed to overwrite()"]
 pub unsafe fn move_val_init<T>(dst: &mut T, src: T) {
     ptr::write(dst, src)
 }
diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs
index bf8caef2e97..57f8f8d6692 100644
--- a/src/librustc/middle/trans/adt.rs
+++ b/src/librustc/middle/trans/adt.rs
@@ -305,8 +305,7 @@ impl Case {
 
                 // Box<T> could either be a thin or fat pointer depending on T
                 ty::ty_uniq(t) => match ty::get(t).sty {
-                    // Box<[T]>/Box<str> might be FatPointer in a post DST world
-                    ty::ty_vec(_, None) | ty::ty_str => continue,
+                    ty::ty_vec(_, None) | return Some(FatPointer(i, slice_elt_base)),
 
                     // Box<Trait> is a pair of pointers: the actual object and a vtable
                     ty::ty_trait(..) => return Some(FatPointer(i, trt_field_box)),
@@ -326,7 +325,6 @@ impl Case {
 
                 // Anything else is not a pointer
                 _ => continue
-
             }
         }
 
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 043636a32c0..7c2f251bd16 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -195,6 +195,16 @@ pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv,
                                                llvm::NoReturnAttribute as uint64_t)
             }
         }
+        // `~` pointer return values never alias because ownership is transferred
+        ty::ty_uniq(t)
+            => match ty::get(t).sty {
+                ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => {}
+                _ => unsafe {
+                    llvm::LLVMAddReturnAttribute(llfn,
+                                                 lib::llvm::NoAliasAttribute as c_uint,
+                                                 lib::llvm::NoReturnAttribute as uint64_t);
+                }
+            },
         _ => {}
     }
 
@@ -364,20 +374,19 @@ fn require_alloc_fn(bcx: &Block, info_ty: ty::t, it: LangItem) -> ast::DefId {
 // a given type, but with a potentially dynamic size.
 
 pub fn malloc_raw_dyn<'a>(bcx: &'a Block<'a>,
-                          ptr_ty: ty::t,
+                          llty_ptr: Type,
+                          info_ty: ty::t,
                           size: ValueRef,
                           align: ValueRef)
                           -> Result<'a> {
     let _icx = push_ctxt("malloc_raw_exchange");
-    let ccx = bcx.ccx();
 
     // Allocate space:
     let r = callee::trans_lang_call(bcx,
-        require_alloc_fn(bcx, ptr_ty, ExchangeMallocFnLangItem),
+        require_alloc_fn(bcx, info_ty, ExchangeMallocFnLangItem),
         [size, align],
         None);
 
-    let llty_ptr = type_of::type_of(ccx, ptr_ty);
     Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr))
 }
 
@@ -731,8 +740,8 @@ pub fn iter_structural_ty<'r,
           }
       }
       ty::ty_vec(_, Some(n)) => {
+        let (base, len) = tvec::get_fixed_base_and_len(cx, av, n);
         let unit_ty = ty::sequence_element_type(cx.tcx(), t);
-        let (base, len) = tvec::get_fixed_base_and_byte_len(cx, av, unit_ty, n);
         cx = tvec::iter_vec_raw(cx, base, unit_ty, len, f);
       }
       ty::ty_tup(ref args) => {
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 88bdb00a7c9..db674b4028f 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -2718,81 +2718,6 @@ fn fixed_vec_metadata(cx: &CrateContext,
     return MetadataCreationResult::new(metadata, false);
 }
 
-fn heap_vec_metadata(cx: &CrateContext,
-                     vec_pointer_type: ty::t,
-                     element_type: ty::t,
-                     unique_type_id: UniqueTypeId,
-                     span: Span)
-                  -> MetadataCreationResult {
-    let element_type_metadata = type_metadata(cx, element_type, span);
-    let element_llvm_type = type_of::type_of(cx, element_type);
-    let (element_size, element_align) = size_and_align_of(cx, element_llvm_type);
-
-    return_if_metadata_created_in_meantime!(cx, unique_type_id);
-
-    let vecbox_llvm_type = Type::vec(cx, &element_llvm_type);
-    let vec_pointer_type_name = compute_debuginfo_type_name(cx,
-                                                            vec_pointer_type,
-                                                            true);
-    let vec_pointer_type_name = vec_pointer_type_name.as_slice();
-
-    let member_llvm_types = vecbox_llvm_type.field_types();
-
-    let int_type_metadata = type_metadata(cx, ty::mk_int(), span);
-    let array_type_metadata = unsafe {
-        llvm::LLVMDIBuilderCreateArrayType(
-            DIB(cx),
-            bytes_to_bits(element_size),
-            bytes_to_bits(element_align),
-            element_type_metadata,
-            create_DIArray(DIB(cx), [llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0, 0)]))
-    };
-
-    let member_descriptions = [
-        MemberDescription {
-            name: "fill".to_string(),
-            llvm_type: *member_llvm_types.get(0),
-            type_metadata: int_type_metadata,
-            offset: ComputedMemberOffset,
-        },
-        MemberDescription {
-            name: "alloc".to_string(),
-            llvm_type: *member_llvm_types.get(1),
-            type_metadata: int_type_metadata,
-            offset: ComputedMemberOffset,
-        },
-        MemberDescription {
-            name: "elements".to_string(),
-            llvm_type: *member_llvm_types.get(2),
-            type_metadata: array_type_metadata,
-            offset: ComputedMemberOffset,
-        }
-    ];
-
-    assert!(member_descriptions.len() == member_llvm_types.len());
-
-    let loc = span_start(cx, span);
-    let file_metadata = file_metadata(cx, loc.file.name.as_slice());
-
-    let vec_box_unique_id = debug_context(cx).type_map
-                                             .borrow_mut()
-                                             .get_unique_type_id_of_heap_vec_box(cx,
-                                                                                 element_type);
-
-    let vecbox_metadata = composite_type_metadata(cx,
-                                                  vecbox_llvm_type,
-                                                  vec_pointer_type_name,
-                                                  vec_box_unique_id,
-                                                  member_descriptions,
-                                                  UNKNOWN_SCOPE_METADATA,
-                                                  file_metadata,
-                                                  span);
-
-    MetadataCreationResult::new(pointer_type_metadata(cx,
-                                                      vec_pointer_type,
-                                                      vecbox_metadata), false)
-}
-
 fn vec_slice_metadata(cx: &CrateContext,
                       vec_type: ty::t,
                       element_type: ty::t,
@@ -2995,11 +2920,13 @@ fn type_metadata(cx: &CrateContext,
         ty::ty_uniq(pointee_type) => {
             match ty::get(pointee_type).sty {
                 ty::ty_vec(ref mt, None) => {
-                    heap_vec_metadata(cx, pointee_type, mt.ty, unique_type_id, usage_site_span)
+                    let vec_metadata = vec_slice_metadata(cx, t, mt.ty, usage_site_span);
+                    pointer_type_metadata(cx, t, vec_metadata)
                 }
                 ty::ty_str => {
                     let i8_t = ty::mk_i8();
-                    heap_vec_metadata(cx, pointee_type, i8_t, unique_type_id, usage_site_span)
+                    let vec_metadata = vec_slice_metadata(cx, t, i8_t, usage_site_span);
+                    pointer_type_metadata(cx, t, vec_metadata)
                 }
                 ty::ty_trait(..) => {
                     MetadataCreationResult::new(
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 748274b1201..ead90dbe36b 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -395,8 +395,8 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>,
         ast::ExprField(ref base, ident, _) => {
             trans_rec_field(bcx, &**base, ident.node)
         }
-        ast::ExprIndex(ref base, ref idx) => {
-            trans_index(bcx, expr, &**base, &**idx, MethodCall::expr(expr.id))
+        ast::ExprIndex(base, idx) => {
+            trans_index(bcx, expr.span, &**base, &**idx, MethodCall::expr(expr.id))
         }
         ast::ExprVstore(ref contents, ast::ExprVstoreUniq) => {
             fcx.push_ast_cleanup_scope(contents.id);
@@ -465,7 +465,7 @@ fn trans_rec_field<'a>(bcx: &'a Block<'a>,
 }
 
 fn trans_index<'a>(bcx: &'a Block<'a>,
-                   index_expr: &ast::Expr,
+                   sp: codemap::Span,
                    base: &ast::Expr,
                    idx: &ast::Expr,
                    method_call: MethodCall)
@@ -1256,10 +1256,8 @@ fn trans_uniq_expr<'a>(bcx: &'a Block<'a>,
     let llty = type_of::type_of(bcx.ccx(), contents_ty);
     let size = llsize_of(bcx.ccx(), llty);
     let align = C_uint(bcx.ccx(), llalign_of_min(bcx.ccx(), llty) as uint);
-    // We need to a make a pointer type because box_ty is ty_bot
-    // if content_ty is, e.g. box fail!().
-    let real_box_ty = ty::mk_uniq(bcx.tcx(), contents_ty);
-    let Result { bcx, val } = malloc_raw_dyn(bcx, real_box_ty, size, align);
+    let llty_ptr = llty.ptr_to();
+    let Result { bcx, val } = malloc_raw_dyn(bcx, llty_ptr, box_ty, size, align);
     // Unique boxes do not allocate for zero-size types. The standard library
     // may assume that `free` is never called on the pointer returned for
     // `Box<ZeroSizeType>`.
diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs
index 570f4d37042..8faf27d1aa4 100644
--- a/src/librustc/middle/trans/glue.rs
+++ b/src/librustc/middle/trans/glue.rs
@@ -51,7 +51,7 @@ pub fn trans_free<'a>(cx: &'a Block<'a>, v: ValueRef) -> &'a Block<'a> {
         Some(expr::Ignore)).bcx
 }
 
-fn trans_exchange_free<'a>(cx: &'a Block<'a>, v: ValueRef, size: u64,
+pub fn trans_exchange_free<'a>(cx: &'a Block<'a>, v: ValueRef, size: u64,
                                align: u64) -> &'a Block<'a> {
     let _icx = push_ctxt("trans_exchange_free");
     let ccx = cx.ccx();
@@ -120,8 +120,8 @@ pub fn drop_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
                -> &'a Block<'a> {
     // NB: v is an *alias* of type t here, not a direct value.
     let _icx = push_ctxt("drop_ty");
-    let ccx = bcx.ccx();
     if ty::type_needs_drop(bcx.tcx(), t) {
+        let ccx = bcx.ccx();
         let glue = get_drop_glue(ccx, t);
         let glue_type = get_drop_glue_type(ccx, t);
         let ptr = if glue_type != t {
@@ -277,23 +277,11 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'
         ty::ty_uniq(content_ty) => {
             match ty::get(content_ty).sty {
                 ty::ty_vec(mt, None) => {
-                    let llbox = Load(bcx, v0);
-                    let not_null = IsNotNull(bcx, llbox);
-                    with_cond(bcx, not_null, |bcx| {
-                        let bcx = tvec::make_drop_glue_unboxed(bcx, llbox, mt.ty);
-                        // FIXME: #13994: the old `Box<[T]>` will not support sized deallocation
-                        trans_exchange_free(bcx, llbox, 0, 8)
-                    })
+                    tvec::make_drop_glue_unboxed(bcx, v0, mt.ty)
                 }
                 ty::ty_str => {
-                    let llbox = Load(bcx, v0);
-                    let not_null = IsNotNull(bcx, llbox);
-                    with_cond(bcx, not_null, |bcx| {
-                        let unit_ty = ty::sequence_element_type(bcx.tcx(), t);
-                        let bcx = tvec::make_drop_glue_unboxed(bcx, llbox, unit_ty);
-                        // FIXME: #13994: the old `Box<str>` will not support sized deallocation
-                        trans_exchange_free(bcx, llbox, 0, 8)
-                    })
+                    let unit_ty = ty::sequence_element_type(bcx.tcx(), t);
+                    tvec::make_drop_glue_unboxed(bcx, v0, unit_ty)
                 }
                 ty::ty_trait(..) => {
                     let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs
index 2aff12c2b68..fcc1b827876 100644
--- a/src/librustc/middle/trans/reflect.rs
+++ b/src/librustc/middle/trans/reflect.rs
@@ -164,6 +164,10 @@ impl<'a, 'b> Reflector<'a, 'b> {
               });
               self.visit("box", extra.as_slice())
           }
+          ty::ty_ptr(ref mt) => {
+              let extra = self.c_mt(mt);
+              self.visit("ptr", extra.as_slice())
+          }
           ty::ty_uniq(typ) => {
               match ty::get(typ).sty {
                   ty::ty_vec(ref mt, None) => {
@@ -188,17 +192,12 @@ impl<'a, 'b> Reflector<'a, 'b> {
                   }
               }
           }
-          ty::ty_ptr(ref mt) => {
-              let extra = self.c_mt(mt);
-              self.visit("ptr", extra.as_slice())
-          }
           ty::ty_rptr(_, ref mt) => {
               match ty::get(mt.ty).sty {
                   ty::ty_vec(ref mt, None) => {
-                      let (name, extra) = ("slice".to_string(), Vec::new());
+                      let extra = Vec::new();
                       let extra = extra.append(self.c_mt(mt).as_slice());
-                      self.visit(format!("evec_{}", name).as_slice(),
-                                 extra.as_slice())
+                      self.visit("evec_slice", extra.as_slice())
                   }
                   ty::ty_str => self.visit("estr_slice", &[]),
                   ty::ty_trait(..) => {
diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs
index 1241a85e95c..7b8537b15c5 100644
--- a/src/librustc/middle/trans/tvec.rs
+++ b/src/librustc/middle/trans/tvec.rs
@@ -17,7 +17,6 @@ use middle::lang_items::StrDupUniqFnLangItem;
 use middle::trans::base::*;
 use middle::trans::base;
 use middle::trans::build::*;
-use middle::trans::callee;
 use middle::trans::cleanup;
 use middle::trans::cleanup::CleanupMethods;
 use middle::trans::common::*;
@@ -25,7 +24,7 @@ use middle::trans::datum::*;
 use middle::trans::expr::{Dest, Ignore, SaveIn};
 use middle::trans::expr;
 use middle::trans::glue;
-use middle::trans::machine::{llsize_of, nonzero_llsize_of, llsize_of_alloc};
+use middle::trans::machine::{nonzero_llsize_of, llsize_of_alloc};
 use middle::trans::type_::Type;
 use middle::trans::type_of;
 use middle::ty;
@@ -34,14 +33,14 @@ use util::ppaux::ty_to_string;
 use syntax::ast;
 use syntax::parse::token::InternedString;
 
-pub fn get_fill(bcx: &Block, vptr: ValueRef) -> ValueRef {
-    let _icx = push_ctxt("tvec::get_fill");
-    Load(bcx, GEPi(bcx, vptr, [0u, abi::vec_elt_fill]))
+fn get_len(bcx: &Block, vptr: ValueRef) -> ValueRef {
+    let _icx = push_ctxt("tvec::get_lenl");
+    Load(bcx, GEPi(bcx, vptr, [0u, abi::slice_elt_len]))
 }
 
-pub fn get_dataptr(bcx: &Block, vptr: ValueRef) -> ValueRef {
+fn get_dataptr(bcx: &Block, vptr: ValueRef) -> ValueRef {
     let _icx = push_ctxt("tvec::get_dataptr");
-    GEPi(bcx, vptr, [0u, abi::vec_elt_elems, 0u])
+    Load(bcx, GEPi(bcx, vptr, [0u, abi::slice_elt_base]))
 }
 
 pub fn pointer_add_byte(bcx: &Block, ptr: ValueRef, bytes: ValueRef) -> ValueRef {
@@ -56,13 +55,21 @@ pub fn make_drop_glue_unboxed<'a>(
                               vptr: ValueRef,
                               unit_ty: ty::t)
                               -> &'a Block<'a> {
-    let _icx = push_ctxt("tvec::make_drop_glue_unboxed");
-    let tcx = bcx.tcx();
-    if ty::type_needs_drop(tcx, unit_ty) {
-        let fill = get_fill(bcx, vptr);
+    let not_null = IsNotNull(bcx, vptr);
+    with_cond(bcx, not_null, |bcx| {
+        let tcx = bcx.tcx();
+        let _icx = push_ctxt("tvec::make_drop_glue_unboxed");
+
+        let len = get_len(bcx, vptr);
         let dataptr = get_dataptr(bcx, vptr);
-        iter_vec_raw(bcx, dataptr, unit_ty, fill, glue::drop_ty)
-    } else { bcx }
+        let bcx = if ty::type_needs_drop(tcx, unit_ty) {
+            iter_vec_raw(bcx, dataptr, unit_ty, len, glue::drop_ty)
+        } else {
+            bcx
+        };
+
+        glue::trans_exchange_free(bcx, dataptr, 0, 8)
+    })
 }
 
 pub struct VecTypes {
@@ -112,12 +119,11 @@ pub fn trans_fixed_vstore<'a>(
     };
 }
 
-pub fn trans_slice_vstore<'a>(
-                          bcx: &'a Block<'a>,
-                          vstore_expr: &ast::Expr,
-                          content_expr: &ast::Expr,
-                          dest: expr::Dest)
-                          -> &'a Block<'a> {
+pub fn trans_slice_vstore<'a>(bcx: &'a Block<'a>,
+                              vstore_expr: &ast::Expr,
+                              content_expr: &ast::Expr,
+                              dest: expr::Dest)
+                              -> &'a Block<'a> {
     /*!
      * &[...] allocates memory on the stack and writes the values into it,
      * returning a slice (pair of ptr, len).  &"..." is similar except that
@@ -150,17 +156,16 @@ pub fn trans_slice_vstore<'a>(
     // Handle the &[...] case:
     let vt = vec_types_from_expr(bcx, vstore_expr);
     let count = elements_required(bcx, content_expr);
-    debug!("vt={}, count={:?}", vt.to_string(ccx), count);
-
+    debug!("    vt={}, count={:?}", vt.to_str(ccx), count);
     let llcount = C_uint(ccx, count);
-    let llfixed;
-    if count == 0 {
+
+    let llfixed = if count == 0 {
         // Just create a zero-sized alloca to preserve
         // the non-null invariant of the inner slice ptr
-        llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount);
+        base::arrayalloca(bcx, vt.llunit_ty, llcount)
     } else {
         // Make a fixed-length backing array and allocate it on the stack.
-        llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount);
+        let llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount);
 
         // Arrange for the backing array to be cleaned up.
         let fixed_ty = ty::mk_vec(bcx.tcx(),
@@ -176,7 +181,9 @@ pub fn trans_slice_vstore<'a>(
         // Generate the content into the backing array.
         bcx = write_content(bcx, &vt, vstore_expr,
                             content_expr, SaveIn(llfixed));
-    }
+
+        llfixed
+    };
 
     // Finally, create the slice pair itself.
     match dest {
@@ -198,7 +205,7 @@ pub fn trans_lit_str<'a>(
                      -> &'a Block<'a> {
     /*!
      * Literal strings translate to slices into static memory.  This is
-     * different from trans_slice_vstore() above because it does need to copy
+     * different from trans_slice_vstore() above because it doesn't need to copy
      * the content anywhere.
      */
 
@@ -214,17 +221,14 @@ pub fn trans_lit_str<'a>(
                 let llbytes = C_uint(bcx.ccx(), bytes);
                 let llcstr = C_cstr(bcx.ccx(), str_lit, false);
                 let llcstr = llvm::LLVMConstPointerCast(llcstr, Type::i8p(bcx.ccx()).to_ref());
-                Store(bcx, llcstr,
-                      GEPi(bcx, lldest, [0u, abi::slice_elt_base]));
-                Store(bcx, llbytes,
-                      GEPi(bcx, lldest, [0u, abi::slice_elt_len]));
+                Store(bcx, llcstr, GEPi(bcx, lldest, [0u, abi::slice_elt_base]));
+                Store(bcx, llbytes, GEPi(bcx, lldest, [0u, abi::slice_elt_len]));
                 bcx
             }
         }
     }
 }
 
-
 pub fn trans_uniq_vstore<'a>(bcx: &'a Block<'a>,
                              vstore_expr: &ast::Expr,
                              content_expr: &ast::Expr)
@@ -238,74 +242,47 @@ pub fn trans_uniq_vstore<'a>(bcx: &'a Block<'a>,
     let fcx = bcx.fcx;
     let ccx = fcx.ccx;
 
-    // Handle "".to_string().
-    match content_expr.node {
-        ast::ExprLit(lit) => {
-            match lit.node {
-                ast::LitStr(ref s, _) => {
-                    let llptrval = C_cstr(ccx, (*s).clone(), false);
-                    let llptrval = PointerCast(bcx, llptrval, Type::i8p(ccx));
-                    let llsizeval = C_uint(ccx, s.get().len());
-                    let typ = ty::mk_uniq(bcx.tcx(), ty::mk_str(bcx.tcx()));
-                    let lldestval = rvalue_scratch_datum(bcx,
-                                                         typ,
-                                                         "");
-                    let alloc_fn = langcall(bcx,
-                                            Some(lit.span),
-                                            "",
-                                            StrDupUniqFnLangItem);
-                    let bcx = callee::trans_lang_call(
-                        bcx,
-                        alloc_fn,
-                        [ llptrval, llsizeval ],
-                        Some(expr::SaveIn(lldestval.val))).bcx;
-                    return DatumBlock::new(bcx, lldestval).to_expr_datumblock();
-                }
-                _ => {}
-            }
-        }
-        _ => {}
-    }
-
-    let vec_ty = node_id_type(bcx, vstore_expr.id);
-    let vt = vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty));
+    let vt = vec_types_from_expr(bcx, vstore_expr);
     let count = elements_required(bcx, content_expr);
+    debug!("    vt={}, count={:?}", vt.to_str(ccx), count);
+    let llcount = C_uint(ccx, count);
+    let vec_ty = node_id_type(bcx, vstore_expr.id);
 
-    let llunitty = type_of::type_of(ccx, vt.unit_ty);
-    let unit_sz = nonzero_llsize_of(ccx, llunitty);
-
+    let unit_sz = nonzero_llsize_of(ccx, type_of::type_of(ccx, vt.unit_ty));
     let fill = Mul(bcx, C_uint(ccx, count), unit_sz);
-    let alloc = if count < 4u { Mul(bcx, C_int(ccx, 4), unit_sz) }
-    else { fill };
-
-    let vecsize = Add(bcx, alloc, llsize_of(ccx, ccx.opaque_vec_type));
-
-    // ~[T] is not going to be changed to support alignment, since it's obsolete.
+    let alloc = if count < 4u {
+        Mul(bcx, C_int(ccx, 4), unit_sz)
+    } else {
+        fill
+    };
+    let llty_ptr = type_of::type_of(ccx, vt.unit_ty).ptr_to();
     let align = C_uint(ccx, 8);
-    let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, vec_ty, vecsize, align);
-    Store(bcx, fill, GEPi(bcx, val, [0u, abi::vec_elt_fill]));
-    Store(bcx, alloc, GEPi(bcx, val, [0u, abi::vec_elt_alloc]));
+    let Result { bcx: bcx, val: dataptr } = malloc_raw_dyn(bcx,
+                                                           llty_ptr,
+                                                           vec_ty,
+                                                           alloc,
+                                                           align);
 
     // Create a temporary scope lest execution should fail while
     // constructing the vector.
     let temp_scope = fcx.push_custom_cleanup_scope();
-
-    // FIXME: #13994: the old `Box<[T]> will not support sized deallocation, this is a placeholder
-    let content_ty = vt.unit_ty;
+    // FIXME: #13994: the old `Box<[T]> will not support sized deallocation,
+    // this is a placeholder
     fcx.schedule_free_value(cleanup::CustomScope(temp_scope),
-                            val, cleanup::HeapExchange, content_ty);
+                            dataptr, cleanup::HeapExchange, vt.unit_ty);
 
-    let dataptr = get_dataptr(bcx, val);
+        debug!("    alloc_uniq_vec() returned dataptr={}, len={}",
+               bcx.val_to_str(dataptr), count);
 
-    debug!("alloc_uniq_vec() returned val={}, dataptr={}",
-           bcx.val_to_string(val), bcx.val_to_string(dataptr));
-
-    let bcx = write_content(bcx, &vt, vstore_expr,
-                            content_expr, SaveIn(dataptr));
+        let bcx = write_content(bcx, &vt, vstore_expr,
+                                content_expr, SaveIn(dataptr));
 
     fcx.pop_custom_cleanup_scope(temp_scope);
 
-    immediate_rvalue_bcx(bcx, val, vec_ty).to_expr_datumblock()
+    let scratch = rvalue_scratch_datum(bcx, vec_ty, "");
+    Store(bcx, dataptr, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base]));
+    Store(bcx, llcount, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len]));
+    DatumBlock(bcx, scratch.to_expr_datum())
 }
 
 pub fn write_content<'a>(
@@ -451,21 +428,19 @@ pub fn elements_required(bcx: &Block, content_expr: &ast::Expr) -> uint {
     }
 }
 
-pub fn get_fixed_base_and_byte_len(bcx: &Block,
-                                   llval: ValueRef,
-                                   unit_ty: ty::t,
-                                   vec_length: uint)
-                                   -> (ValueRef, ValueRef) {
+pub fn get_fixed_base_and_len(bcx: &Block,
+                              llval: ValueRef,
+                              vec_length: uint)
+                              -> (ValueRef, ValueRef) {
     /*!
      * Converts a fixed-length vector into the slice pair.
      * The vector should be stored in `llval` which should be by ref.
      */
 
     let ccx = bcx.ccx();
-    let vt = vec_types(bcx, unit_ty);
 
-    let base = GEPi(bcx, llval, [0u, 0u]);
-    let len = Mul(bcx, C_uint(ccx, vec_length), vt.llunit_size);
+    let base = GEPi(bcx, llval, [0u, abi::slice_elt_base]);
+    let len = C_uint(ccx, vec_length);
     (base, len)
 }
 
@@ -488,23 +463,13 @@ pub fn get_base_and_len(bcx: &Block,
             let base = GEPi(bcx, llval, [0u, 0u]);
             (base, C_uint(ccx, n))
         }
-        ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty {
+        ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty {
             ty::ty_vec(_, None) | ty::ty_str => {
-                assert!(!type_is_immediate(bcx.ccx(), vec_ty));
                 let base = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_base]));
-                let count = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len]));
-                (base, count)
+                let len = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len]));
+                (base, len)
             }
-            _ => ccx.sess().bug("unexpected type (ty_rptr) in get_base_and_len"),
-        },
-        ty::ty_uniq(t) => match ty::get(t).sty {
-            ty::ty_vec(_, None) | ty::ty_str => {
-                assert!(type_is_immediate(bcx.ccx(), vec_ty));
-                let vt = vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty));
-                let body = Load(bcx, llval);
-                (get_dataptr(bcx, body), UDiv(bcx, get_fill(bcx, body), vt.llunit_size))
-            }
-            _ => ccx.sess().bug("unexpected type (ty_uniq) in get_base_and_len"),
+            _ => ccx.sess().bug("unexpected type in get_base_and_len"),
         },
         _ => ccx.sess().bug("unexpected type in get_base_and_len"),
     }
@@ -576,13 +541,15 @@ pub fn iter_vec_raw<'r,
                     bcx: &'b Block<'b>,
                     data_ptr: ValueRef,
                     unit_ty: ty::t,
-                    fill: ValueRef,
+                    len: ValueRef,
                     f: iter_vec_block<'r,'b>)
                     -> &'b Block<'b> {
     let _icx = push_ctxt("tvec::iter_vec_raw");
     let fcx = bcx.fcx;
 
     let vt = vec_types(bcx, unit_ty);
+    let fill = Mul(bcx, len, vt.llunit_size);
+
     if vt.llunit_alloc_size == 0 {
         // Special-case vectors with elements of size 0  so they don't go out of bounds (#9890)
         iter_vec_loop(bcx, data_ptr, &vt, fill, f)
diff --git a/src/librustc/middle/trans/type_.rs b/src/librustc/middle/trans/type_.rs
index e9d92e45f62..99850fb9386 100644
--- a/src/librustc/middle/trans/type_.rs
+++ b/src/librustc/middle/trans/type_.rs
@@ -215,7 +215,7 @@ impl Type {
 
     pub fn vec(ccx: &CrateContext, ty: &Type) -> Type {
         Type::struct_(ccx,
-            [Type::int(ccx), Type::int(ccx), Type::array(ty, 0)],
+            [Type::array(ty, 0), Type::int(ccx)],
         false)
     }
 
diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs
index 8a445fc4839..bc17824ca32 100644
--- a/src/librustc/middle/trans/type_of.rs
+++ b/src/librustc/middle/trans/type_of.rs
@@ -169,14 +169,8 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type {
 
         ty::ty_box(..) |
         ty::ty_ptr(..) => Type::i8p(cx),
-        ty::ty_uniq(ty) => {
+        ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => {
             match ty::get(ty).sty {
-                ty::ty_trait(..) => Type::opaque_trait(cx),
-                _ => Type::i8p(cx),
-            }
-        }
-        ty::ty_rptr(_, mt) => {
-            match ty::get(mt.ty).sty {
                 ty::ty_vec(_, None) | ty::ty_str => {
                     Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false)
                 }
@@ -283,17 +277,10 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
       ty::ty_box(typ) => {
           Type::at_box(cx, type_of(cx, typ)).ptr_to()
       }
-      ty::ty_uniq(typ) => {
-          match ty::get(typ).sty {
-              ty::ty_vec(mt, None) => Type::vec(cx, &type_of(cx, mt.ty)).ptr_to(),
-              ty::ty_str => Type::vec(cx, &Type::i8(cx)).ptr_to(),
-              ty::ty_trait(..) => Type::opaque_trait(cx),
-              _ => type_of(cx, typ).ptr_to(),
-          }
-      }
       ty::ty_ptr(ref mt) => type_of(cx, mt.ty).ptr_to(),
-      ty::ty_rptr(_, ref mt) => {
-          match ty::get(mt.ty).sty {
+
+      ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => {
+          match ty::get(ty).sty {
               ty::ty_vec(mt, None) => {
                   let p_ty = type_of(cx, mt.ty).ptr_to();
                   let u_ty = Type::uint_from_ty(cx, ast::TyU);
@@ -304,7 +291,7 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
                   cx.tn.find_type("str_slice").unwrap()
               }
               ty::ty_trait(..) => Type::opaque_trait(cx),
-              _ => type_of(cx, mt.ty).ptr_to(),
+              _ => type_of(cx, ty).ptr_to(),
           }
       }
 
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index dc463ffe5df..c00c462afae 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -1816,8 +1816,7 @@ pub fn type_is_boxed(ty: t) -> bool {
 pub fn type_is_region_ptr(ty: t) -> bool {
     match get(ty).sty {
         ty_rptr(_, mt) => match get(mt.ty).sty {
-            // FIXME(nrc, DST) slices weren't regarded as rptrs, so we preserve this
-            // odd behaviour for now. (But ~[] were unique. I have no idea why).
+            // DST pointers should not be treated like regular pointers.
             ty_vec(_, None) | ty_str | ty_trait(..) => false,
             _ => true
         },
diff --git a/src/librustc_back/abi.rs b/src/librustc_back/abi.rs
index c722beb43ae..015331b8be0 100644
--- a/src/librustc_back/abi.rs
+++ b/src/librustc_back/abi.rs
@@ -23,11 +23,5 @@ pub static fn_field_box: uint = 1u;
 pub static trt_field_vtable: uint = 0u;
 pub static trt_field_box: uint = 1u;
 
-pub static vec_elt_fill: uint = 0u;
-
-pub static vec_elt_alloc: uint = 1u;
-
-pub static vec_elt_elems: uint = 2u;
-
 pub static slice_elt_base: uint = 0u;
 pub static slice_elt_len: uint = 1u;
diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs
index bbaac7a96e9..a9cbacb07be 100644
--- a/src/libserialize/serialize.rs
+++ b/src/libserialize/serialize.rs
@@ -18,6 +18,7 @@ use std::path;
 use std::rc::Rc;
 use std::gc::{Gc, GC};
 use std::cell::{Cell, RefCell};
+use std::strbuf::StrBuf;
 
 pub trait Encoder<E> {
     // Primitive types:
diff --git a/src/libtime/lib.rs b/src/libtime/lib.rs
index d0b4c6b1e4c..9a56dd5c0e4 100644
--- a/src/libtime/lib.rs
+++ b/src/libtime/lib.rs
@@ -268,7 +268,19 @@ pub struct Tm {
     pub tm_nsec: i32,
 }
 
+impl Tm {
+    pub fn tm_zone<'a>(&'a self) -> &'a str {
+        self.tm_zone.as_slice()
+    }
+}
+
 pub fn empty_tm() -> Tm {
+    // 64 is the max size of the timezone buffer allocated on windows
+    // in rust_localtime. In glibc the max timezone size is supposedly 3.
+    let mut zone = StrBuf::new();
+    for _ in range(0, 64) {
+        zone.push_char(' ')
+    }
     Tm {
         tm_sec: 0_i32,
         tm_min: 0_i32,
@@ -280,6 +292,7 @@ pub fn empty_tm() -> Tm {
         tm_yday: 0_i32,
         tm_isdst: 0_i32,
         tm_gmtoff: 0_i32,
+        tm_zone: zone,
         tm_nsec: 0_i32,
     }
 }
@@ -760,6 +773,7 @@ pub fn strptime(s: &str, format: &str) -> Result<Tm, String> {
           'Z' => {
             if match_str(s, pos, "UTC") || match_str(s, pos, "GMT") {
                 tm.tm_gmtoff = 0_i32;
+                tm.tm_zone = "UTC".into_strbuf();
                 Ok(pos + 3u)
             } else {
                 // It's odd, but to maintain compatibility with c's
@@ -784,6 +798,7 @@ pub fn strptime(s: &str, format: &str) -> Result<Tm, String> {
                     let (v, pos) = item;
                     if v == 0_i32 {
                         tm.tm_gmtoff = 0_i32;
+                        tm.tm_zone = "UTC".into_strbuf();
                     }
 
                     Ok(pos)
@@ -813,6 +828,7 @@ pub fn strptime(s: &str, format: &str) -> Result<Tm, String> {
         tm_yday: 0_i32,
         tm_isdst: 0_i32,
         tm_gmtoff: 0_i32,
+        tm_zone: StrBuf::new(),
         tm_nsec: 0_i32,
     };
     let mut pos = 0u;
@@ -859,6 +875,7 @@ pub fn strptime(s: &str, format: &str) -> Result<Tm, String> {
             tm_yday: tm.tm_yday,
             tm_isdst: tm.tm_isdst,
             tm_gmtoff: tm.tm_gmtoff,
+            tm_zone: tm.tm_zone.clone(),
             tm_nsec: tm.tm_nsec,
         })
     } else { result }
@@ -1060,7 +1077,7 @@ pub fn strftime(format: &str, tm: &Tm) -> String {
           'w' => (tm.tm_wday as int).to_string(),
           'Y' => (tm.tm_year as int + 1900).to_string(),
           'y' => format!("{:02d}", (tm.tm_year as int + 1900) % 100),
-          'Z' => "".to_string(),    // FIXME(pcwalton): Implement this.
+          'Z' => tm.tm_zone.as_slice().to_owned(),
           'z' => {
             let sign = if tm.tm_gmtoff > 0_i32 { '+' } else { '-' };
             let mut m = num::abs(tm.tm_gmtoff) / 60_i32;
@@ -1186,6 +1203,7 @@ mod tests {
         assert_eq!(utc.tm_yday, 43_i32);
         assert_eq!(utc.tm_isdst, 0_i32);
         assert_eq!(utc.tm_gmtoff, 0_i32);
+        assert_eq!(utc.tm_zone(), "UTC");
         assert_eq!(utc.tm_nsec, 54321_i32);
     }
 
@@ -1207,6 +1225,12 @@ mod tests {
         assert_eq!(local.tm_yday, 43_i32);
         assert_eq!(local.tm_isdst, 0_i32);
         assert_eq!(local.tm_gmtoff, -28800_i32);
+
+        // FIXME (#2350): We should probably standardize on the timezone
+        // abbreviation.
+        let zone = local.tm_zone();
+        assert!(zone == "PST" || zone == "Pacific Standard Time");
+
         assert_eq!(local.tm_nsec, 54321_i32);
     }
 
@@ -1249,6 +1273,7 @@ mod tests {
             assert!(tm.tm_wday == 0_i32);
             assert!(tm.tm_isdst == 0_i32);
             assert!(tm.tm_gmtoff == 0_i32);
+            assert!(tm.tm_zone() == "");
             assert!(tm.tm_nsec == 0_i32);
           }
           Err(_) => ()
@@ -1272,6 +1297,7 @@ mod tests {
             assert!(tm.tm_yday == 0_i32);
             assert!(tm.tm_isdst == 0_i32);
             assert!(tm.tm_gmtoff == 0_i32);
+            assert!(tm.tm_zone() == "");
             assert!(tm.tm_nsec == 12340000_i32);
           }
         }
@@ -1383,10 +1409,10 @@ mod tests {
         assert!(test("6", "%w"));
         assert!(test("2009", "%Y"));
         assert!(test("09", "%y"));
-        assert!(strptime("-0000", "%z").unwrap().tm_gmtoff ==
-            0);
-        assert!(strptime("-0800", "%z").unwrap().tm_gmtoff ==
-            0);
+        assert!(strptime("UTC", "%Z").unwrap().tm_zone() == "UTC");
+        assert!(strptime("PST", "%Z").unwrap().tm_zone() == "");
+        assert!(strptime("-0000", "%z").unwrap().tm_gmtoff == 0);
+        assert!(strptime("-0800", "%z").unwrap().tm_gmtoff == 0);
         assert!(test("%", "%%"));
 
         // Test for #7256
diff --git a/src/rt/rust_builtin.c b/src/rt/rust_builtin.c
index ba20f2c6f27..1a9b1c1c818 100644
--- a/src/rt/rust_builtin.c
+++ b/src/rt/rust_builtin.c
@@ -127,6 +127,15 @@ rust_list_dir_wfd_fp_buf(void* wfd) {
 }
 #endif
 
+typedef struct
+{
+    size_t fill;    // in bytes; if zero, heapified
+    size_t alloc;   // in bytes
+    uint8_t *data;
+} rust_vec;
+
+typedef rust_vec rust_str_buf;
+
 typedef struct {
     int32_t tm_sec;
     int32_t tm_min;
@@ -138,6 +147,7 @@ typedef struct {
     int32_t tm_yday;
     int32_t tm_isdst;
     int32_t tm_gmtoff;
+    rust_str_buf tm_zone;
     int32_t tm_nsec;
 } rust_tm;
 
@@ -154,10 +164,8 @@ void rust_tm_to_tm(rust_tm* in_tm, struct tm* out_tm) {
     out_tm->tm_isdst = in_tm->tm_isdst;
 }
 
-void tm_to_rust_tm(struct tm* in_tm,
-                   rust_tm* out_tm,
-                   int32_t gmtoff,
-                   int32_t nsec) {
+void tm_to_rust_tm(struct tm* in_tm, rust_tm* out_tm, int32_t gmtoff,
+                   const char *zone, int32_t nsec) {
     out_tm->tm_sec = in_tm->tm_sec;
     out_tm->tm_min = in_tm->tm_min;
     out_tm->tm_hour = in_tm->tm_hour;
@@ -169,6 +177,13 @@ void tm_to_rust_tm(struct tm* in_tm,
     out_tm->tm_isdst = in_tm->tm_isdst;
     out_tm->tm_gmtoff = gmtoff;
     out_tm->tm_nsec = nsec;
+
+    if (zone != NULL) {
+        size_t size = strlen(zone);
+        assert(out_tm->tm_zone.alloc >= size);
+        memcpy(out_tm->tm_zone.data, zone, size);
+        out_tm->tm_zone.fill = size;
+    }
 }
 
 #if defined(__WIN32__)
@@ -210,7 +225,7 @@ rust_gmtime(int64_t sec, int32_t nsec, rust_tm *timeptr) {
     time_t s = sec;
     GMTIME(&s, &tm);
 
-    tm_to_rust_tm(&tm, timeptr, 0, nsec);
+    tm_to_rust_tm(&tm, timeptr, 0, "UTC", nsec);
 }
 
 void
@@ -219,13 +234,28 @@ rust_localtime(int64_t sec, int32_t nsec, rust_tm *timeptr) {
     time_t s = sec;
     LOCALTIME(&s, &tm);
 
+    const char* zone = NULL;
 #if defined(__WIN32__)
     int32_t gmtoff = -timezone;
+    wchar_t wbuffer[64] = {0};
+    char buffer[256] = {0};
+    // strftime("%Z") can contain non-UTF-8 characters on non-English locale (issue #9418),
+    // so time zone should be converted from UTF-16 string.
+    // Since wcsftime depends on setlocale() result,
+    // instead we convert it using MultiByteToWideChar.
+    if (strftime(buffer, sizeof(buffer) / sizeof(char), "%Z", &tm) > 0) {
+        // ANSI -> UTF-16
+        MultiByteToWideChar(CP_ACP, 0, buffer, -1, wbuffer, sizeof(wbuffer) / sizeof(wchar_t));
+        // UTF-16 -> UTF-8
+        WideCharToMultiByte(CP_UTF8, 0, wbuffer, -1, buffer, sizeof(buffer), NULL, NULL);
+        zone = buffer;
+    }
 #else
     int32_t gmtoff = tm.tm_gmtoff;
+    zone = tm.tm_zone;
 #endif
 
-    tm_to_rust_tm(&tm, timeptr, gmtoff, nsec);
+    tm_to_rust_tm(&tm, timeptr, gmtoff, zone, nsec);
 }
 
 int64_t