You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@teaclave.apache.org by rd...@apache.org on 2021/03/30 10:41:03 UTC

[incubator-teaclave-sgx-sdk] branch newer-compiler-03-10 created (now e4a58a8)

This is an automated email from the ASF dual-hosted git repository.

rduan pushed a change to branch newer-compiler-03-10
in repository https://gitbox.apache.org/repos/asf/incubator-teaclave-sgx-sdk.git.


      at e4a58a8  compiler: support rustc 2021-03-09

This branch includes the following new commits:

     new e4a58a8  compiler: support rustc 2021-03-09

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@teaclave.apache.org
For additional commands, e-mail: commits-help@teaclave.apache.org


[incubator-teaclave-sgx-sdk] 01/01: compiler: support rustc 2021-03-09

Posted by rd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rduan pushed a commit to branch newer-compiler-03-10
in repository https://gitbox.apache.org/repos/asf/incubator-teaclave-sgx-sdk.git

commit e4a58a8b84812c82b454bb9f6e528f5912c03fe2
Author: volcano <vo...@163.com>
AuthorDate: Tue Mar 30 18:39:49 2021 +0800

    compiler: support rustc 2021-03-09
---
 samplecode/unit-test/enclave/src/lib.rs       |   1 -
 samplecode/unit-test/enclave/src/test_rand.rs |   1 -
 samplecode/unit-test/enclave/src/test_rts.rs  |  10 +-
 samplecode/unit-test/enclave/src/test_time.rs |   1 -
 sgx_alloc/Cargo.toml                          |   1 +
 {sgx_tstd => sgx_alloc}/build.rs              |  30 +-
 sgx_alloc/src/alignalloc.rs                   |  34 +-
 sgx_alloc/src/alignbox.rs                     |  19 +-
 sgx_alloc/src/rsrvmem.rs                      |  11 +-
 sgx_alloc/src/system.rs                       |  51 ++-
 sgx_serialize_derive/src/lib.rs               |   4 +-
 sgx_tstd/build.rs                             |   6 +
 sgx_tstd/hashbrown/src/raw/sse2.rs            |   2 +-
 sgx_tstd/src/future.rs                        | 107 +----
 sgx_tstd/src/lazy.rs                          | 562 ++++++++++++++++++++++++++
 sgx_tstd/src/lib.rs                           |  11 +
 sgx_tstd/src/prelude/v1.rs                    |   3 +
 sgx_tstd/src/sync/once.rs                     |  35 +-
 sgx_urts/src/event.rs                         |   4 +-
 xargo/sgx_tstd/build.rs                       |  65 +++
 xargo/x86_64-unknown-linux-sgx.json           |  11 +-
 21 files changed, 777 insertions(+), 192 deletions(-)

diff --git a/samplecode/unit-test/enclave/src/lib.rs b/samplecode/unit-test/enclave/src/lib.rs
index b9ea49b..e010cd5 100644
--- a/samplecode/unit-test/enclave/src/lib.rs
+++ b/samplecode/unit-test/enclave/src/lib.rs
@@ -348,4 +348,3 @@ fn test_main_entrance() -> size_t {
                     test_exception_handler,
                     )
 }
-
diff --git a/samplecode/unit-test/enclave/src/test_rand.rs b/samplecode/unit-test/enclave/src/test_rand.rs
index c748642..6d2d8ca 100644
--- a/samplecode/unit-test/enclave/src/test_rand.rs
+++ b/samplecode/unit-test/enclave/src/test_rand.rs
@@ -15,7 +15,6 @@
 // specific language governing permissions and limitations
 // under the License..
 
-use std::panic;
 use sgx_rand::*;
 
 // pub use os::SgxRng
diff --git a/samplecode/unit-test/enclave/src/test_rts.rs b/samplecode/unit-test/enclave/src/test_rts.rs
index 25d6047..668e50f 100644
--- a/samplecode/unit-test/enclave/src/test_rts.rs
+++ b/samplecode/unit-test/enclave/src/test_rts.rs
@@ -94,13 +94,14 @@ pub fn test_read_rand(){
 }
 
 pub fn test_data_is_within_enclave() {
+    #[allow(dead_code)]
     #[derive(Clone, Copy)]
     struct SampleDs{
         x: i32,
         y: i32,
         z: [i32; 100],
-    };
-    unsafe impl marker::ContiguousMemory for SampleDs{};
+    }
+    unsafe impl marker::ContiguousMemory for SampleDs {}
     let mut sample_object : SampleDs = SampleDs{ x: 0, y: 0, z: [0; 100]};
     sample_object.x = 100;
     sample_object.y = 100;
@@ -138,13 +139,14 @@ pub fn test_raw_is_within_enclave(){
 }
 
 pub fn test_data_is_outside_enclave() {
+    #[allow(dead_code)]
     #[derive(Clone, Copy)]
     struct SampleDs{
         x: i32,
         y: i32,
         z: [i32; 100],
-    };
-    unsafe impl marker::ContiguousMemory for SampleDs{};
+    }
+    unsafe impl marker::ContiguousMemory for SampleDs {}
     let mut sample_object : SampleDs = SampleDs{ x: 0, y: 0, z: [0; 100]};
     sample_object.x = 100;
     sample_object.y = 100;
diff --git a/samplecode/unit-test/enclave/src/test_time.rs b/samplecode/unit-test/enclave/src/test_time.rs
index d17e6ea..a9ec118 100644
--- a/samplecode/unit-test/enclave/src/test_time.rs
+++ b/samplecode/unit-test/enclave/src/test_time.rs
@@ -1,5 +1,4 @@
 use std::time::*;
-use std::panic;
 use std::untrusted::time::{InstantEx, SystemTimeEx};
 
 pub fn test_std_time() {
diff --git a/sgx_alloc/Cargo.toml b/sgx_alloc/Cargo.toml
index 99bf1de..af14267 100644
--- a/sgx_alloc/Cargo.toml
+++ b/sgx_alloc/Cargo.toml
@@ -2,6 +2,7 @@
 name = "sgx_alloc"
 version = "1.1.3"
 authors = ["The Teaclave Authors"]
+build = "build.rs"
 repository = "https://github.com/apache/teaclave-sgx-sdk"
 license-file = "LICENSE"
 documentation = "https://dingelish.github.io/"
diff --git a/sgx_tstd/build.rs b/sgx_alloc/build.rs
similarity index 73%
copy from sgx_tstd/build.rs
copy to sgx_alloc/build.rs
index e0fd1d9..47ea68c 100644
--- a/sgx_tstd/build.rs
+++ b/sgx_alloc/build.rs
@@ -16,34 +16,14 @@
 // under the License..
 
 use std::env;
-use std::path::Path;
 use std::process::Command;
 
 fn main() {
-    if cfg!(feature = "backtrace") {
-        println!("cargo:rustc-cfg=RUST_BACKTRACE=\"1\"");
-        //println!("cargo:rustc-cfg=RUST_BACKTRACE=\"full\"");
-    }
-
-    let mut sdk_dir = env::var("SGX_SDK")
-                    .unwrap_or_else(|_| "/opt/sgxsdk".to_string());
-    let _is_sim = env::var("SGX_MODE")
-                    .unwrap_or_else(|_| "HW".to_string());
-
-    if !Path::new(&sdk_dir).exists() {
-        sdk_dir = "/opt/intel/sgxsdk".to_string();
-    }
-
-    if cfg!(feature = "thread") {
-        println!("cargo:rustc-link-search=native={}/lib64", sdk_dir);
-        println!("cargo:rustc-link-lib=static=sgx_pthread");
-    }
-
-    // since nightly-2020-11-26 (rustc 2020-11-25), auto_traits replaced
-    // optin_builtin_traits
-    // see https://github.com/rust-lang/rust/commit/810324d1f31eb8d75e8f0044df720652986ef133
-    if let Some(true) = is_min_date("2020-11-25") {
-        println!("cargo:rustc-cfg=enable_auto_traits");
+    // nightly-2020-12-05 (rustc 2020-12-04)
+    // Rename `AllocRef` to `Allocator` and `(de)alloc` to `(de)allocate`
+    // https://github.com/rust-lang/rust/commit/9274b37d99f608e5fde569788ee79bd72fc3cf13
+    if let Some(true) = is_min_date("2020-12-04") {
+        println!("cargo:rustc-cfg=enable_allocator_traits");
     }
 }
 
diff --git a/sgx_alloc/src/alignalloc.rs b/sgx_alloc/src/alignalloc.rs
index 6d5460a..f9afa9e 100644
--- a/sgx_alloc/src/alignalloc.rs
+++ b/sgx_alloc/src/alignalloc.rs
@@ -135,7 +135,7 @@ mod platform {
         if !check_layout(&layout) {
             return ptr::null_mut();
         }
-        let align_layout = match if align_req.len() == 0 {
+        let align_layout = match if align_req.is_empty() {
             let req: [AlignReq; 1] = [AlignReq {
                 offset: 0,
                 len: layout.size(),
@@ -169,7 +169,7 @@ mod platform {
         if !check_layout(&layout) {
             return ptr::null_mut();
         }
-        let align_layout = match if align_req.len() == 0 {
+        let align_layout = match if align_req.is_empty() {
             let req: [AlignReq; 1] = [AlignReq {
                 offset: 0,
                 len: layout.size(),
@@ -206,18 +206,17 @@ mod platform {
         let pad = align_layout.size() - align_layout.align() - layout.size();
 
         let raw = libc::malloc(align_layout.size() + mem::size_of::<*mut u8>()) as *mut u8;
-        let aligned_ptr = if raw.is_null() {
+        if raw.is_null() {
             raw
         } else {
-            if zeroed == true {
+            if zeroed {
                 ptr::write_bytes(raw, 0, align_layout.size());
             }
             let ptr = make_aligned_ptr(raw, align_layout.align(), pad);
             let p = ptr as *mut *mut u8;
             p.sub(1).write(raw);
             ptr
-        };
-        aligned_ptr
+        }
     }
 
     #[inline]
@@ -260,22 +259,17 @@ mod platform {
 
     #[inline]
     fn check_overflow(buf: usize, len: usize) -> bool {
-        (buf + len < len) || (buf + len < buf)
+        buf.checked_add(len).is_none()
     }
 
     fn check_layout(layout: &Layout) -> bool {
-        if layout.size() == 0
+        !(layout.size() == 0
             || !layout.align().is_power_of_two()
-            || layout.size() > usize::MAX - (layout.align() - 1)
-        {
-            false
-        } else {
-            true
-        }
+            || layout.size() > usize::MAX - (layout.align() - 1))
     }
 
     fn check_align_req(size: usize, align_req: &[AlignReq]) -> bool {
-        if align_req.len() == 0 {
+        if align_req.is_empty() {
             return false;
         }
         let len: usize = (size + 7) / 8;
@@ -335,12 +329,10 @@ mod platform {
     }
 
     fn count_lzb(bmp: i64) -> i32 {
-        if bmp == 0 {
-            -1
-        } else if bmp < 0 {
-            0
-        } else {
-            count_lzb(bmp << 1) + 1
+        match bmp {
+            0 => -1,
+            x if x < 0 => 0,
+            _ => count_lzb(bmp << 1) + 1,
         }
     }
 
diff --git a/sgx_alloc/src/alignbox.rs b/sgx_alloc/src/alignbox.rs
index 566d85a..5a888b2 100644
--- a/sgx_alloc/src/alignbox.rs
+++ b/sgx_alloc/src/alignbox.rs
@@ -166,7 +166,7 @@ unsafe impl<#[may_dangle] T> Drop for AlignBox<T> {
 
 impl<T> AlignBox<T> {
     fn new_with_req_in(align: usize, align_req: &[AlignReq]) -> Option<AlignBox<T>> {
-        if align_req.len() == 0 {
+        if align_req.is_empty() {
             AlignBox::new_in()
         } else {
             AlignBox::allocate_in(true, align, align_req)
@@ -217,7 +217,7 @@ impl<T> AlignBox<T> {
 
         Some(AlignBox {
             ptr: Unique::new(ptr.cast::<T>().as_ptr()).unwrap(),
-            align_layout: align_layout,
+            align_layout,
             origin_layout: layout,
         })
     }
@@ -242,9 +242,8 @@ impl<T> AlignBox<T> {
     {
         unsafe {
             let mut t = Self::new_in();
-            match t {
-                Some(ref mut b) => initialize(b.ptr.as_mut()),
-                None => (),
+            if let Some(ref mut b) = t {
+                initialize(b.ptr.as_mut())
             }
             t
         }
@@ -255,9 +254,8 @@ impl<T> AlignBox<T> {
     {
         unsafe {
             let mut t = Self::new_with_align(align);
-            match t {
-                Some(ref mut b) => initialize(b.ptr.as_mut()),
-                None => (),
+            if let Some(ref mut b) = t {
+                initialize(b.ptr.as_mut())
             }
             t
         }
@@ -272,9 +270,8 @@ impl<T> AlignBox<T> {
     {
         unsafe {
             let mut t = Self::new_with_req(align, data);
-            match t {
-                Some(ref mut b) => initialize(b.ptr.as_mut()),
-                None => (),
+            if let Some(ref mut b) = t {
+                initialize(b.ptr.as_mut())
             }
             t
         }
diff --git a/sgx_alloc/src/rsrvmem.rs b/sgx_alloc/src/rsrvmem.rs
index 2cf832c..793775c 100644
--- a/sgx_alloc/src/rsrvmem.rs
+++ b/sgx_alloc/src/rsrvmem.rs
@@ -30,7 +30,6 @@ pub enum ProtectAttr {
 }
 
 impl RsrvMemAlloc {
-    
     /// Allocate a range of EPC memory from the reserved memory area
     ///
     /// # Parameters
@@ -53,9 +52,9 @@ impl RsrvMemAlloc {
     /// # Parameters
     ///
     /// **addr**
-    /// 
+    ///
     /// The desired starting address to allocate the reserved memory. Should be page aligned.
-    /// 
+    ///
     /// **count**
     ///
     /// Count of pages to allocate region
@@ -65,7 +64,11 @@ impl RsrvMemAlloc {
     /// Starting address of the new allocated memory area on success;
     ///
     #[inline]
-    pub unsafe fn alloc_with_addr(&self, addr: NonNull<u8>, count: u32) -> Result<NonNull<u8>, RsrvMemAllocErr> {
+    pub unsafe fn alloc_with_addr(
+        &self,
+        addr: NonNull<u8>,
+        count: u32,
+    ) -> Result<NonNull<u8>, RsrvMemAllocErr> {
         NonNull::new(platform::alloc_with_addr(addr.as_ptr(), count)).ok_or(RsrvMemAllocErr)
     }
 
diff --git a/sgx_alloc/src/system.rs b/sgx_alloc/src/system.rs
index a29a723..defdb1a 100644
--- a/sgx_alloc/src/system.rs
+++ b/sgx_alloc/src/system.rs
@@ -22,9 +22,11 @@
 //! It is essential, because we depends on Intel SGX's SDK.
 //! 2018-06-22 Add liballoc components here
 
-use core::alloc::{
-    AllocError, AllocRef, GlobalAlloc, Layout,
-};
+use core::alloc::{AllocError, GlobalAlloc, Layout};
+#[cfg(enable_allocator_traits)]
+use core::alloc::Allocator;
+#[cfg(not(enable_allocator_traits))]
+use core::alloc::AllocRef as Allocator;
 use core::intrinsics;
 use core::ptr::{self, NonNull};
 
@@ -59,7 +61,7 @@ impl System {
         }
     }
 
-    // Safety: Same as `AllocRef::grow`
+    // Safety: Same as `Allocator::grow`
     #[inline]
     unsafe fn grow_impl(
         &self,
@@ -100,24 +102,51 @@ impl System {
             old_size => {
                 let new_ptr = self.alloc_impl(new_layout, zeroed)?;
                 ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_size);
-                AllocRef::dealloc(&self, ptr, old_layout);
+                if old_layout.size() != 0 {
+                    GlobalAlloc::dealloc(self, ptr.as_ptr(), old_layout)
+                }
                 Ok(new_ptr)
             },
         }
     }
 }
 
-unsafe impl AllocRef for System {
+unsafe impl Allocator for System {
+    #[cfg(enable_allocator_traits)]
+    #[inline]
+    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
+        self.alloc_impl(layout, false)
+    }
+
+    #[cfg(not(enable_allocator_traits))]
     #[inline]
     fn alloc(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
         self.alloc_impl(layout, false)
     }
 
+    #[cfg(enable_allocator_traits)]
+    #[inline]
+    fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
+        self.alloc_impl(layout, true)
+    }
+
+    #[cfg(not(enable_allocator_traits))]
     #[inline]
     fn alloc_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
          self.alloc_impl(layout, true)
     }
 
+    #[cfg(enable_allocator_traits)]
+    #[inline]
+    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
+        if layout.size() != 0 {
+            // SAFETY: `layout` is non-zero in size,
+            // other conditions must be upheld by the caller
+            GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
+        }
+    }
+
+    #[cfg(not(enable_allocator_traits))]
     #[inline]
     unsafe fn dealloc(&self, ptr: NonNull<u8>, layout: Layout) {
         if layout.size() != 0 {
@@ -157,7 +186,9 @@ unsafe impl AllocRef for System {
          match new_layout.size() {
              // SAFETY: conditions must be upheld by the caller
              0 => {
-                AllocRef::dealloc(&self, ptr, old_layout);
+                if old_layout.size() != 0 {
+                    GlobalAlloc::dealloc(self, ptr.as_ptr(), old_layout)
+                }
                 Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0))
              },
              // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller
@@ -176,9 +207,11 @@ unsafe impl AllocRef for System {
              // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract
              // for `dealloc` must be upheld by the caller.
              new_size => {
-                let new_ptr = AllocRef::alloc(&self, new_layout)?;
+                let new_ptr =  self.alloc_impl(new_layout, false)?;
                 ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_size);
-                AllocRef::dealloc(&self, ptr, old_layout);
+                if old_layout.size() != 0 {
+                    GlobalAlloc::dealloc(self, ptr.as_ptr(), old_layout)
+                }
                 Ok(new_ptr)
              },
          }
diff --git a/sgx_serialize_derive/src/lib.rs b/sgx_serialize_derive/src/lib.rs
index a76d1f1..29813e6 100644
--- a/sgx_serialize_derive/src/lib.rs
+++ b/sgx_serialize_derive/src/lib.rs
@@ -56,7 +56,7 @@ pub fn derive_serialize(input: TokenStream) -> TokenStream {
     let input = syn::parse_derive_input(&input.to_string()).unwrap();
     match encode::expand_derive_serialize(&input) {
         Ok(expanded) => expanded.parse().unwrap(),
-        Err(msg) => panic!(msg),
+        Err(msg) => panic!("{}", msg),
     }
 }
 
@@ -72,6 +72,6 @@ pub fn derive_deserialize(input: TokenStream) -> TokenStream {
     let input = syn::parse_derive_input(&input.to_string()).unwrap();
     match decode::expand_derive_deserialize(&input) {
         Ok(expanded) => expanded.parse().unwrap(),
-        Err(msg) => panic!(msg),
+        Err(msg) => panic!("{}", msg),
     }
 }
diff --git a/sgx_tstd/build.rs b/sgx_tstd/build.rs
index e0fd1d9..ddc7ab9 100644
--- a/sgx_tstd/build.rs
+++ b/sgx_tstd/build.rs
@@ -45,6 +45,12 @@ fn main() {
     if let Some(true) = is_min_date("2020-11-25") {
         println!("cargo:rustc-cfg=enable_auto_traits");
     }
+
+    // nightly-2021-02-08 (rustc 2021-02-07)
+    // https://github.com/rust-lang/rust/commit/dbdbd30bf2cb0d48c8bbce83c2458592664dbb18
+    if let Some(true) = is_min_date("2021-02-07") {
+        println!("cargo:rustc-cfg=derive_macros");
+    }
 }
 
 // code below copied from crate version_check
diff --git a/sgx_tstd/hashbrown/src/raw/sse2.rs b/sgx_tstd/hashbrown/src/raw/sse2.rs
index a27bc09..dbe61d8 100644
--- a/sgx_tstd/hashbrown/src/raw/sse2.rs
+++ b/sgx_tstd/hashbrown/src/raw/sse2.rs
@@ -33,7 +33,7 @@ impl Group {
         struct AlignedBytes {
             _align: [Group; 0],
             bytes: [u8; Group::WIDTH],
-        };
+        }
         const ALIGNED_BYTES: AlignedBytes = AlignedBytes {
             _align: [],
             bytes: [EMPTY; Group::WIDTH],
diff --git a/sgx_tstd/src/future.rs b/sgx_tstd/src/future.rs
index bbbc4f2..e76e41c 100644
--- a/sgx_tstd/src/future.rs
+++ b/sgx_tstd/src/future.rs
@@ -17,107 +17,14 @@
 
 //! Asynchronous values.
 
-#[cfg(bootstrap)]
-use core::{
-    cell::Cell,
-    marker::Unpin,
-    ops::{Drop, Generator, GeneratorState},
-    pin::Pin,
-    ptr::NonNull,
-    task::{Context, Poll},
-};
-
 #[doc(inline)]
-pub use core::future::*;
-
-/// Wrap a generator in a future.
-///
-/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
-/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
-// This is `const` to avoid extra errors after we recover from `const async fn`
-#[cfg(bootstrap)]
-#[doc(hidden)]
-pub const fn from_generator<T: Generator<Yield = ()>>(x: T) -> impl Future<Output = T::Return> {
-    GenFuture(x)
-}
-
-/// A wrapper around generators used to implement `Future` for `async`/`await` code.
-#[cfg(bootstrap)]
-#[doc(hidden)]
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
-struct GenFuture<T: Generator<Yield = ()>>(T);
-
-// We rely on the fact that async/await futures are immovable in order to create
-// self-referential borrows in the underlying generator.
-#[cfg(bootstrap)]
-impl<T: Generator<Yield = ()>> !Unpin for GenFuture<T> {}
-
-#[cfg(bootstrap)]
-#[doc(hidden)]
-impl<T: Generator<Yield = ()>> Future for GenFuture<T> {
-    type Output = T::Return;
-    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
-        // Safe because we're !Unpin + !Drop mapping to a ?Unpin value
-        let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) };
-        let _guard = unsafe { set_task_context(cx) };
-        match gen.resume(()) {
-            GeneratorState::Yielded(()) => Poll::Pending,
-            GeneratorState::Complete(x) => Poll::Ready(x),
-        }
-    }
-}
-
-#[cfg(bootstrap)]
-thread_local! {
-    static TLS_CX: Cell<Option<NonNull<Context<'static>>>> = Cell::new(None);
-}
+pub use core::future::Future;
 
-#[cfg(bootstrap)]
-struct SetOnDrop(Option<NonNull<Context<'static>>>);
-
-#[cfg(bootstrap)]
-impl Drop for SetOnDrop {
-    fn drop(&mut self) {
-        TLS_CX.with(|tls_cx| {
-            tls_cx.set(self.0.take());
-        });
-    }
-}
-
-// Safety: the returned guard must drop before `cx` is dropped and before
-// any previous guard is dropped.
-#[cfg(bootstrap)]
-unsafe fn set_task_context(cx: &mut Context<'_>) -> SetOnDrop {
-    // transmute the context's lifetime to 'static so we can store it.
-    let cx = core::mem::transmute::<&mut Context<'_>, &mut Context<'static>>(cx);
-    let old_cx = TLS_CX.with(|tls_cx| tls_cx.replace(Some(NonNull::from(cx))));
-    SetOnDrop(old_cx)
-}
-
-#[cfg(bootstrap)]
-#[doc(hidden)]
-/// Polls a future in the current thread-local task waker.
-pub fn poll_with_tls_context<F>(f: Pin<&mut F>) -> Poll<F::Output>
-where
-    F: Future,
-{
-    let cx_ptr = TLS_CX.with(|tls_cx| {
-        // Clear the entry so that nested `get_task_waker` calls
-        // will fail or set their own value.
-        tls_cx.replace(None)
-    });
-    let _reset = SetOnDrop(cx_ptr);
+#[doc(inline)]
+pub use core::future::{from_generator, get_context, ResumeTy};
 
-    let mut cx_ptr = cx_ptr.expect(
-        "TLS Context not set. This is a rustc bug. \
-        Please file an issue on https://github.com/rust-lang/rust.",
-    );
+#[doc(inline)]
+pub use core::future::{pending, ready, Pending, Ready};
 
-    // Safety: we've ensured exclusive access to the context by
-    // removing the pointer from TLS, only to be replaced once
-    // we're done with it.
-    //
-    // The pointer that was inserted came from an `&mut Context<'_>`,
-    // so it is safe to treat as mutable.
-    unsafe { F::poll(f, cx_ptr.as_mut()) }
-}
+#[doc(inline)]
+pub use core::future::IntoFuture;
diff --git a/sgx_tstd/src/lazy.rs b/sgx_tstd/src/lazy.rs
new file mode 100644
index 0000000..36171de
--- /dev/null
+++ b/sgx_tstd/src/lazy.rs
@@ -0,0 +1,562 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License..
+
+//! Lazy values and one-time initialization of static data.
+
+use core::cell::{Cell, UnsafeCell};
+use core::fmt;
+use core::marker::PhantomData;
+use core::mem::MaybeUninit;
+use core::ops::{Deref, Drop};
+use core::pin::Pin;
+use crate::panic::{RefUnwindSafe, UnwindSafe};
+use crate::sync::Once;
+
+#[doc(inline)]
+pub use core::lazy::*;
+
+/// A synchronization primitive which can be written to only once.
+///
+/// This type is a thread-safe `OnceCell`.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(once_cell)]
+///
+/// use std::lazy::SyncOnceCell;
+///
+/// static CELL: SyncOnceCell<String> = SyncOnceCell::new();
+/// assert!(CELL.get().is_none());
+///
+/// std::thread::spawn(|| {
+///     let value: &String = CELL.get_or_init(|| {
+///         "Hello, World!".to_string()
+///     });
+///     assert_eq!(value, "Hello, World!");
+/// }).join().unwrap();
+///
+/// let value: Option<&String> = CELL.get();
+/// assert!(value.is_some());
+/// assert_eq!(value.unwrap().as_str(), "Hello, World!");
+/// ```
+pub struct SyncOnceCell<T> {
+    once: Once,
+    // Whether or not the value is initialized is tracked by `state_and_queue`.
+    value: UnsafeCell<MaybeUninit<T>>,
+    /// `PhantomData` to make sure dropck understands we're dropping T in our Drop impl.
+    ///
+    /// ```compile_fail,E0597
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncOnceCell;
+    ///
+    /// struct A<'a>(&'a str);
+    ///
+    /// impl<'a> Drop for A<'a> {
+    ///     fn drop(&mut self) {}
+    /// }
+    ///
+    /// let cell = SyncOnceCell::new();
+    /// {
+    ///     let s = String::new();
+    ///     let _ = cell.set(A(&s));
+    /// }
+    /// ```
+    _marker: PhantomData<T>,
+}
+
+// Why do we need `T: Send`?
+// Thread A creates a `SyncOnceCell` and shares it with
+// scoped thread B, which fills the cell, which is
+// then destroyed by A. That is, destructor observes
+// a sent value.
+unsafe impl<T: Sync + Send> Sync for SyncOnceCell<T> {}
+unsafe impl<T: Send> Send for SyncOnceCell<T> {}
+
+impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for SyncOnceCell<T> {}
+impl<T: UnwindSafe> UnwindSafe for SyncOnceCell<T> {}
+
+impl<T> Default for SyncOnceCell<T> {
+    fn default() -> SyncOnceCell<T> {
+        SyncOnceCell::new()
+    }
+}
+
+impl<T: fmt::Debug> fmt::Debug for SyncOnceCell<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.get() {
+            Some(v) => f.debug_tuple("Once").field(v).finish(),
+            None => f.write_str("Once(Uninit)"),
+        }
+    }
+}
+
+impl<T: Clone> Clone for SyncOnceCell<T> {
+    fn clone(&self) -> SyncOnceCell<T> {
+        let cell = Self::new();
+        if let Some(value) = self.get() {
+            match cell.set(value.clone()) {
+                Ok(()) => (),
+                Err(_) => unreachable!(),
+            }
+        }
+        cell
+    }
+}
+
+impl<T> From<T> for SyncOnceCell<T> {
+    fn from(value: T) -> Self {
+        let cell = Self::new();
+        match cell.set(value) {
+            Ok(()) => cell,
+            Err(_) => unreachable!(),
+        }
+    }
+}
+
+impl<T: PartialEq> PartialEq for SyncOnceCell<T> {
+    fn eq(&self, other: &SyncOnceCell<T>) -> bool {
+        self.get() == other.get()
+    }
+}
+
+impl<T: Eq> Eq for SyncOnceCell<T> {}
+
+impl<T> SyncOnceCell<T> {
+    /// Creates a new empty cell.
+    pub const fn new() -> SyncOnceCell<T> {
+        SyncOnceCell {
+            once: Once::new(),
+            value: UnsafeCell::new(MaybeUninit::uninit()),
+            _marker: PhantomData,
+        }
+    }
+
+    /// Gets the reference to the underlying value.
+    ///
+    /// Returns `None` if the cell is empty, or being initialized. This
+    /// method never blocks.
+    pub fn get(&self) -> Option<&T> {
+        if self.is_initialized() {
+            // Safe b/c checked is_initialized
+            Some(unsafe { self.get_unchecked() })
+        } else {
+            None
+        }
+    }
+
+    /// Gets the mutable reference to the underlying value.
+    ///
+    /// Returns `None` if the cell is empty. This method never blocks.
+    pub fn get_mut(&mut self) -> Option<&mut T> {
+        if self.is_initialized() {
+            // Safe b/c checked is_initialized and we have a unique access
+            Some(unsafe { self.get_unchecked_mut() })
+        } else {
+            None
+        }
+    }
+
+    /// Sets the contents of this cell to `value`.
+    ///
+    /// Returns `Ok(())` if the cell's value was updated.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncOnceCell;
+    ///
+    /// static CELL: SyncOnceCell<i32> = SyncOnceCell::new();
+    ///
+    /// fn main() {
+    ///     assert!(CELL.get().is_none());
+    ///
+    ///     std::thread::spawn(|| {
+    ///         assert_eq!(CELL.set(92), Ok(()));
+    ///     }).join().unwrap();
+    ///
+    ///     assert_eq!(CELL.set(62), Err(62));
+    ///     assert_eq!(CELL.get(), Some(&92));
+    /// }
+    /// ```
+    pub fn set(&self, value: T) -> Result<(), T> {
+        let mut value = Some(value);
+        self.get_or_init(|| value.take().unwrap());
+        match value {
+            None => Ok(()),
+            Some(value) => Err(value),
+        }
+    }
+
+    /// Gets the contents of the cell, initializing it with `f` if the cell
+    /// was empty.
+    ///
+    /// Many threads may call `get_or_init` concurrently with different
+    /// initializing functions, but it is guaranteed that only one function
+    /// will be executed.
+    ///
+    /// # Panics
+    ///
+    /// If `f` panics, the panic is propagated to the caller, and the cell
+    /// remains uninitialized.
+    ///
+    /// It is an error to reentrantly initialize the cell from `f`. The
+    /// exact outcome is unspecified. Current implementation deadlocks, but
+    /// this may be changed to a panic in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncOnceCell;
+    ///
+    /// let cell = SyncOnceCell::new();
+    /// let value = cell.get_or_init(|| 92);
+    /// assert_eq!(value, &92);
+    /// let value = cell.get_or_init(|| unreachable!());
+    /// assert_eq!(value, &92);
+    /// ```
+    pub fn get_or_init<F>(&self, f: F) -> &T
+    where
+        F: FnOnce() -> T,
+    {
+        match self.get_or_try_init(|| Ok::<T, !>(f())) {
+            Ok(val) => val,
+            Err(_) => unreachable!(),
+        }
+    }
+
+    /// Gets the contents of the cell, initializing it with `f` if
+    /// the cell was empty. If the cell was empty and `f` failed, an
+    /// error is returned.
+    ///
+    /// # Panics
+    ///
+    /// If `f` panics, the panic is propagated to the caller, and
+    /// the cell remains uninitialized.
+    ///
+    /// It is an error to reentrantly initialize the cell from `f`.
+    /// The exact outcome is unspecified. Current implementation
+    /// deadlocks, but this may be changed to a panic in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncOnceCell;
+    ///
+    /// let cell = SyncOnceCell::new();
+    /// assert_eq!(cell.get_or_try_init(|| Err(())), Err(()));
+    /// assert!(cell.get().is_none());
+    /// let value = cell.get_or_try_init(|| -> Result<i32, ()> {
+    ///     Ok(92)
+    /// });
+    /// assert_eq!(value, Ok(&92));
+    /// assert_eq!(cell.get(), Some(&92))
+    /// ```
+    pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
+    where
+        F: FnOnce() -> Result<T, E>,
+    {
+        // Fast path check
+        // NOTE: We need to perform an acquire on the state in this method
+        // in order to correctly synchronize `SyncLazy::force`. This is
+        // currently done by calling `self.get()`, which in turn calls
+        // `self.is_initialized()`, which in turn performs the acquire.
+        if let Some(value) = self.get() {
+            return Ok(value);
+        }
+        self.initialize(f)?;
+
+        debug_assert!(self.is_initialized());
+
+        // SAFETY: The inner value has been initialized
+        Ok(unsafe { self.get_unchecked() })
+    }
+
+    /// Internal-only API that gets the contents of the cell, initializing it
+    /// in two steps with `f` and `g` if the cell was empty.
+    ///
+    /// `f` is called to construct the value, which is then moved into the cell
+    /// and given as a (pinned) mutable reference to `g` to finish
+    /// initialization.
+    ///
+    /// This allows `g` to inspect an manipulate the value after it has been
+    /// moved into its final place in the cell, but before the cell is
+    /// considered initialized.
+    ///
+    /// # Panics
+    ///
+    /// If `f` or `g` panics, the panic is propagated to the caller, and the
+    /// cell remains uninitialized.
+    ///
+    /// With the current implementation, if `g` panics, the value from `f` will
+    /// not be dropped. This should probably be fixed if this is ever used for
+    /// a type where this matters.
+    ///
+    /// It is an error to reentrantly initialize the cell from `f`. The exact
+    /// outcome is unspecified. Current implementation deadlocks, but this may
+    /// be changed to a panic in the future.
+    pub(crate) fn get_or_init_pin<F, G>(self: Pin<&Self>, f: F, g: G) -> Pin<&T>
+    where
+        F: FnOnce() -> T,
+        G: FnOnce(Pin<&mut T>),
+    {
+        if let Some(value) = self.get_ref().get() {
+            // SAFETY: The inner value was already initialized, and will not be
+            // moved anymore.
+            return unsafe { Pin::new_unchecked(value) };
+        }
+
+        let slot = &self.value;
+
+        // Ignore poisoning from other threads
+        // If another thread panics, then we'll be able to run our closure
+        self.once.call_once_force(|_| {
+            let value = f();
+            // SAFETY: We use the Once (self.once) to guarantee unique access
+            // to the UnsafeCell (slot).
+            let value: &mut T = unsafe { (&mut *slot.get()).write(value) };
+            // SAFETY: The value has been written to its final place in
+            // self.value. We do not to move it anymore, which we promise here
+            // with a Pin<&mut T>.
+            g(unsafe { Pin::new_unchecked(value) });
+        });
+
+        // SAFETY: The inner value has been initialized, and will not be moved
+        // anymore.
+        unsafe { Pin::new_unchecked(self.get_ref().get_unchecked()) }
+    }
+
+    /// Consumes the `SyncOnceCell`, returning the wrapped value. Returns
+    /// `None` if the cell was empty.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncOnceCell;
+    ///
+    /// let cell: SyncOnceCell<String> = SyncOnceCell::new();
+    /// assert_eq!(cell.into_inner(), None);
+    ///
+    /// let cell = SyncOnceCell::new();
+    /// cell.set("hello".to_string()).unwrap();
+    /// assert_eq!(cell.into_inner(), Some("hello".to_string()));
+    /// ```
+    pub fn into_inner(mut self) -> Option<T> {
+        self.take()
+    }
+
+    /// Takes the value out of this `SyncOnceCell`, moving it back to an uninitialized state.
+    ///
+    /// Has no effect and returns `None` if the `SyncOnceCell` hasn't been initialized.
+    ///
+    /// Safety is guaranteed by requiring a mutable reference.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncOnceCell;
+    ///
+    /// let mut cell: SyncOnceCell<String> = SyncOnceCell::new();
+    /// assert_eq!(cell.take(), None);
+    ///
+    /// let mut cell = SyncOnceCell::new();
+    /// cell.set("hello".to_string()).unwrap();
+    /// assert_eq!(cell.take(), Some("hello".to_string()));
+    /// assert_eq!(cell.get(), None);
+    /// ```
+    pub fn take(&mut self) -> Option<T> {
+        if self.is_initialized() {
+            self.once = Once::new();
+            // SAFETY: `self.value` is initialized and contains a valid `T`.
+            // `self.once` is reset, so `is_initialized()` will be false again
+            // which prevents the value from being read twice.
+            unsafe { Some((&mut *self.value.get()).assume_init_read()) }
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    fn is_initialized(&self) -> bool {
+        self.once.is_completed()
+    }
+
+    #[cold]
+    fn initialize<F, E>(&self, f: F) -> Result<(), E>
+    where
+        F: FnOnce() -> Result<T, E>,
+    {
+        let mut res: Result<(), E> = Ok(());
+        let slot = &self.value;
+
+        // Ignore poisoning from other threads
+        // If another thread panics, then we'll be able to run our closure
+        self.once.call_once_force(|p| {
+            match f() {
+                Ok(value) => {
+                    unsafe { (&mut *slot.get()).write(value) };
+                }
+                Err(e) => {
+                    res = Err(e);
+
+                    // Treat the underlying `Once` as poisoned since we
+                    // failed to initialize our value. Calls
+                    p.poison();
+                }
+            }
+        });
+        res
+    }
+
+    /// Safety: The value must be initialized
+    unsafe fn get_unchecked(&self) -> &T {
+        debug_assert!(self.is_initialized());
+        (&*self.value.get()).assume_init_ref()
+    }
+
+    /// Safety: The value must be initialized
+    unsafe fn get_unchecked_mut(&mut self) -> &mut T {
+        debug_assert!(self.is_initialized());
+        (&mut *self.value.get()).assume_init_mut()
+    }
+}
+
+unsafe impl<#[may_dangle] T> Drop for SyncOnceCell<T> {
+    fn drop(&mut self) {
+        if self.is_initialized() {
+            // Safety: The cell is initialized and being dropped, so it can't
+            // be accessed again. We also don't touch the `T` other than
+            // dropping it, which validates our usage of #[may_dangle].
+            unsafe { (&mut *self.value.get()).assume_init_drop() };
+        }
+    }
+}
+
+/// A value which is initialized on the first access.
+///
+/// This type is a thread-safe `Lazy`, and can be used in statics.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(once_cell)]
+///
+/// use std::collections::HashMap;
+///
+/// use std::lazy::SyncLazy;
+///
+/// static HASHMAP: SyncLazy<HashMap<i32, String>> = SyncLazy::new(|| {
+///     println!("initializing");
+///     let mut m = HashMap::new();
+///     m.insert(13, "Spica".to_string());
+///     m.insert(74, "Hoyten".to_string());
+///     m
+/// });
+///
+/// fn main() {
+///     println!("ready");
+///     std::thread::spawn(|| {
+///         println!("{:?}", HASHMAP.get(&13));
+///     }).join().unwrap();
+///     println!("{:?}", HASHMAP.get(&74));
+///
+///     // Prints:
+///     //   ready
+///     //   initializing
+///     //   Some("Spica")
+///     //   Some("Hoyten")
+/// }
+/// ```
+pub struct SyncLazy<T, F = fn() -> T> {
+    cell: SyncOnceCell<T>,
+    init: Cell<Option<F>>,
+}
+
+impl<T: fmt::Debug, F> fmt::Debug for SyncLazy<T, F> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish()
+    }
+}
+
+// We never create a `&F` from a `&SyncLazy<T, F>` so it is fine
+// to not impl `Sync` for `F`
+// we do create a `&mut Option<F>` in `force`, but this is
+// properly synchronized, so it only happens once
+// so it also does not contribute to this impl.
+unsafe impl<T, F: Send> Sync for SyncLazy<T, F> where SyncOnceCell<T>: Sync {}
+// auto-derived `Send` impl is OK.
+
+impl<T, F: UnwindSafe> RefUnwindSafe for SyncLazy<T, F> where SyncOnceCell<T>: RefUnwindSafe {}
+impl<T, F: UnwindSafe> UnwindSafe for SyncLazy<T, F> where SyncOnceCell<T>: UnwindSafe {}
+
+impl<T, F> SyncLazy<T, F> {
+    /// Creates a new lazy value with the given initializing
+    /// function.
+    pub const fn new(f: F) -> SyncLazy<T, F> {
+        SyncLazy { cell: SyncOnceCell::new(), init: Cell::new(Some(f)) }
+    }
+}
+
+impl<T, F: FnOnce() -> T> SyncLazy<T, F> {
+    /// Forces the evaluation of this lazy value and
+    /// returns a reference to result. This is equivalent
+    /// to the `Deref` impl, but is explicit.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell)]
+    ///
+    /// use std::lazy::SyncLazy;
+    ///
+    /// let lazy = SyncLazy::new(|| 92);
+    ///
+    /// assert_eq!(SyncLazy::force(&lazy), &92);
+    /// assert_eq!(&*lazy, &92);
+    /// ```
+    pub fn force(this: &SyncLazy<T, F>) -> &T {
+        this.cell.get_or_init(|| match this.init.take() {
+            Some(f) => f(),
+            None => panic!("Lazy instance has previously been poisoned"),
+        })
+    }
+}
+
+impl<T, F: FnOnce() -> T> Deref for SyncLazy<T, F> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        SyncLazy::force(self)
+    }
+}
+
+impl<T: Default> Default for SyncLazy<T> {
+    /// Creates a new lazy value using `Default` as the initializing function.
+    fn default() -> SyncLazy<T> {
+        SyncLazy::new(T::default)
+    }
+}
diff --git a/sgx_tstd/src/lib.rs b/sgx_tstd/src/lib.rs
index 9769cea..44db0f9 100644
--- a/sgx_tstd/src/lib.rs
+++ b/sgx_tstd/src/lib.rs
@@ -40,6 +40,7 @@
 #![allow(dead_code)]
 #![allow(deprecated)]
 #![allow(unused_assignments)]
+#![allow(stable_features)]
 
 #![feature(alloc_error_handler)]
 #![feature(allocator_api)]
@@ -66,15 +67,19 @@
 #![feature(fn_traits)]
 #![feature(generator_trait)]
 #![feature(format_args_nl)]
+#![feature(gen_future)]
 #![feature(global_asm)]
 #![feature(hashmap_internals)]
 #![feature(int_error_internals)]
+#![feature(into_future)]
 #![feature(lang_items)]
 #![feature(llvm_asm)]
 #![feature(log_syntax)]
+#![feature(maybe_uninit_extra)]
 #![feature(maybe_uninit_ref)]
 #![feature(never_type)]
 #![feature(needs_panic_runtime)]
+#![feature(once_cell)]
 #![feature(panic_unwind)]
 #![feature(prelude_import)]
 #![feature(ptr_internals)]
@@ -90,6 +95,7 @@
 #![feature(unboxed_closures)]
 #![feature(untagged_unions)]
 #![feature(unwind_attributes)]
+#![feature(wake_trait)]
 #![feature(libc)]
 #![feature(panic_internals)]
 #![feature(std_internals)]
@@ -213,10 +219,15 @@ pub mod time;
 pub mod enclave;
 pub mod untrusted;
 
+pub mod lazy;
+
 pub mod task {
     //! Types and Traits for working with asynchronous tasks.
     #[doc(inline)]
     pub use core::task::*;
+
+    #[doc(inline)]
+    pub use alloc_crate::task::*;
 }
 
 pub mod future;
diff --git a/sgx_tstd/src/prelude/v1.rs b/sgx_tstd/src/prelude/v1.rs
index 44a68f1..c6b5d7b 100644
--- a/sgx_tstd/src/prelude/v1.rs
+++ b/sgx_tstd/src/prelude/v1.rs
@@ -57,6 +57,9 @@ pub use core::prelude::v1::{
     PartialEq, PartialOrd, RustcDecodable, RustcEncodable,
 };
 
+#[cfg(derive_macros)]
+#[doc(hidden)]
+pub use core::prelude::v1::derive;
 #[doc(hidden)]
 pub use core::prelude::v1::cfg_accessible;
 
diff --git a/sgx_tstd/src/sync/once.rs b/sgx_tstd/src/sync/once.rs
index d9158fa..21201de 100644
--- a/sgx_tstd/src/sync/once.rs
+++ b/sgx_tstd/src/sync/once.rs
@@ -102,6 +102,7 @@ unsafe impl Send for Once {}
 #[derive(Debug)]
 pub struct OnceState {
     poisoned: bool,
+    set_state_on_drop_to: Cell<usize>,
 }
 
 /// Initialization value for static [`Once`] values.
@@ -215,7 +216,7 @@ impl Once {
         }
 
         let mut f = Some(f);
-        self.call_inner(true, &mut |p| f.take().unwrap()(&OnceState { poisoned: p }));
+        self.call_inner(true, &mut |p| f.take().unwrap()(p));
     }
 
     /// Returns `true` if some `call_once` call has completed
@@ -252,7 +253,7 @@ impl Once {
     // currently no way to take an `FnOnce` and call it via virtual dispatch
     // without some allocation overhead.
     #[cold]
-    fn call_inner(&self, ignore_poisoning: bool, init: &mut dyn FnMut(bool)) {
+    fn call_inner(&self, ignore_poisoning: bool, init: &mut dyn FnMut(&OnceState)) {
         let mut state_and_queue = self.state_and_queue.load(Ordering::Acquire);
         loop {
             match state_and_queue {
@@ -263,12 +264,13 @@ impl Once {
                 }
                 POISONED | INCOMPLETE => {
                     // Try to register this thread as the one RUNNING.
-                    let old = self.state_and_queue.compare_and_swap(
+                    let exchange_result = self.state_and_queue.compare_exchange(
                         state_and_queue,
                         RUNNING,
                         Ordering::Acquire,
+                        Ordering::Acquire,
                     );
-                    if old != state_and_queue {
+                    if let Err(old) = exchange_result {
                         state_and_queue = old;
                         continue;
                     }
@@ -280,8 +282,12 @@ impl Once {
                     };
                     // Run the initialization function, letting it know if we're
                     // poisoned or not.
-                    init(state_and_queue == POISONED);
-                    waiter_queue.set_state_on_drop_to = COMPLETE;
+                    let init_state = OnceState {
+                        poisoned: state_and_queue == POISONED,
+                        set_state_on_drop_to: Cell::new(COMPLETE),
+                    };
+                    init(&init_state);
+                    waiter_queue.set_state_on_drop_to = init_state.set_state_on_drop_to.get();
                     break;
                 }
                 _ => {
@@ -316,8 +322,13 @@ fn wait(state_and_queue: &AtomicUsize, mut current_state: usize) {
 
         // Try to slide in the node at the head of the linked list, making sure
         // that another thread didn't just replace the head of the linked list.
-        let old = state_and_queue.compare_and_swap(current_state, me | RUNNING, Ordering::Release);
-        if old != current_state {
+        let exchange_result = state_and_queue.compare_exchange(
+            current_state,
+            me | RUNNING,
+            Ordering::Release,
+            Ordering::Relaxed,
+        );
+        if let Err(old) = exchange_result {
             current_state = old;
             continue;
         }
@@ -363,7 +374,7 @@ impl Drop for WaiterQueue<'_> {
             let mut queue = (state_and_queue & !STATE_MASK) as *const Waiter;
             while !queue.is_null() {
                 let next = (*queue).next;
-                let thread = (*queue).thread.replace(None).unwrap();
+                let thread = (*queue).thread.take().unwrap();
                 (*queue).signaled.store(true, Ordering::Release);
                 // ^- FIXME (maybe): This is another case of issue #55005
                 // `store()` has a potentially dangling ref to `signaled`.
@@ -384,4 +395,10 @@ impl OnceState {
     pub fn poisoned(&self) -> bool {
         self.poisoned
     }
+
+    /// Poison the associated [`Once`] without explicitly panicking.
+    // NOTE: This is currently only exposed for the `lazy` module
+    pub(crate) fn poison(&self) {
+        self.set_state_on_drop_to.set(POISONED);
+    }
 }
\ No newline at end of file
diff --git a/sgx_urts/src/event.rs b/sgx_urts/src/event.rs
index 8b1f06e..ac28d26 100644
--- a/sgx_urts/src/event.rs
+++ b/sgx_urts/src/event.rs
@@ -39,7 +39,9 @@ impl SeEvent {
             if ret < 0 {
                 let err = Error::last_os_error().raw_os_error().unwrap_or(0);
                 if err == libc::ETIMEDOUT {
-                    self.event.compare_and_swap(-1, 0, Ordering::SeqCst);
+                    let _ = self
+                        .event
+                        .compare_exchange(-1, 0, Ordering::SeqCst, Ordering::SeqCst);
                     return -1;
                 }
             }
diff --git a/xargo/sgx_tstd/build.rs b/xargo/sgx_tstd/build.rs
index 3b90fc9..8d99763 100644
--- a/xargo/sgx_tstd/build.rs
+++ b/xargo/sgx_tstd/build.rs
@@ -17,6 +17,7 @@
 
 use std::env;
 use std::path::Path;
+use std::process::Command;
 
 fn main() {
     if cfg!(feature = "backtrace") {
@@ -38,4 +39,68 @@ fn main() {
         println!("cargo:rustc-link-search=native={}/lib64", sdk_dir);
         println!("cargo:rustc-link-lib=static=sgx_pthread");
     }
+
+    // since nightly-2020-11-26 (rustc 2020-11-25), auto_traits replaced
+    // optin_builtin_traits
+    // see https://github.com/rust-lang/rust/commit/810324d1f31eb8d75e8f0044df720652986ef133
+    if let Some(true) = is_min_date("2020-11-25") {
+        println!("cargo:rustc-cfg=enable_auto_traits");
+    }
+
+    // nightly-2021-02-08 (rustc 2021-02-07)
+    // https://github.com/rust-lang/rust/commit/dbdbd30bf2cb0d48c8bbce83c2458592664dbb18
+    if let Some(true) = is_min_date("2021-02-07") {
+        println!("cargo:rustc-cfg=derive_macros");
+    }
+}
+
+// code below copied from crate version_check
+// we want to remove the build dependencies to make the dependency tree
+// as clean as possible. the following codes credit to SergioBenitez
+#[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord)]
+struct Date(u32);
+
+impl Date {
+    fn read() -> Option<Date> {
+        get_version_and_date()
+            .and_then(|(_, date)| date)
+            .and_then(|date| Date::parse(&date))
+    }
+
+    fn parse(date: &str) -> Option<Date> {
+        let ymd: Vec<u32> = date.split("-")
+            .filter_map(|s| s.parse::<u32>().ok())
+            .collect();
+    
+        if ymd.len() != 3 {
+            return None
+        }
+    
+        let (y, m, d) = (ymd[0], ymd[1], ymd[2]);
+        Some(Date((y << 9) | ((m & 0xF) << 5) | (d & 0x1F)))
+    }
+}
+
+fn get_version_and_date() -> Option<(Option<String>, Option<String>)> {
+    env::var("RUSTC").ok()
+        .and_then(|rustc| Command::new(rustc).arg("--version").output().ok())
+        .or_else(|| Command::new("rustc").arg("--version").output().ok())
+        .and_then(|output| String::from_utf8(output.stdout).ok())
+        .map(|s| version_and_date_from_rustc_version(&s))
+}
+
+fn version_and_date_from_rustc_version(s: &str) -> (Option<String>, Option<String>) {
+    let last_line = s.lines().last().unwrap_or(s);
+    let mut components = last_line.trim().split(" ");
+    let version = components.nth(1);
+    let date = components.filter(|c| c.ends_with(')')).next()
+        .map(|s| s.trim_end().trim_end_matches(")").trim_start().trim_start_matches('('));
+    (version.map(|s| s.to_string()), date.map(|s| s.to_string()))
+}
+
+fn is_min_date(min_date: &str) -> Option<bool> {
+    match (Date::read(), Date::parse(min_date)) {
+        (Some(rustc_date), Some(min_date)) => Some(rustc_date >= min_date),
+        _ => None
+    }
 }
diff --git a/xargo/x86_64-unknown-linux-sgx.json b/xargo/x86_64-unknown-linux-sgx.json
index 10d37a7..69b38be 100644
--- a/xargo/x86_64-unknown-linux-sgx.json
+++ b/xargo/x86_64-unknown-linux-sgx.json
@@ -1,7 +1,7 @@
 {
   "arch": "x86_64",
   "cpu": "x86-64",
-  "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
+  "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
   "dynamic-linking": true,
   "env": "sgx",
   "exe-allocation-crate": "alloc_system",
@@ -22,7 +22,14 @@
     ]
   },
   "relro-level": "full",
-  "stack-probes": true,
+  "stack-probes": {
+    "kind": "inline-or-call",
+    "min-llvm-version-for-inline": [
+      11,
+      0,
+      1
+    ]
+  },
   "target-c-int-width": "32",
   "target-endian": "little",
   "target-family": "unix",

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@teaclave.apache.org
For additional commands, e-mail: commits-help@teaclave.apache.org