diff --git a/RELEASES.md b/RELEASES.md index a49e072e9eaa7..821889d64a5fb 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,149 @@ +Version 1.34.0 (2019-04-11) +========================== + +Language +-------- +- [You can now use `#[deprecated = "reason"]`][58166] as a shorthand for + `#[deprecated(note = "reason")]`. This was previously allowed by mistake + but had no effect. +- [You can now accept token streams in `#[attr()]`,`#[attr[]]`, and + `#[attr{}]` procedural macros.][57367] +- [You can now write `extern crate self as foo;`][57407] to import your + crate's root into the extern prelude. + + +Compiler +-------- +- [You can now target `riscv64imac-unknown-none-elf` and + `riscv64gc-unknown-none-elf`.][58406] +- [You can now enable linker plugin LTO optimisations with + `-C linker-plugin-lto`.][58057] This allows rustc to compile your Rust code + into LLVM bitcode allowing LLVM to perform LTO optimisations across C/C++ FFI + boundaries. +- [You can now target `powerpc64-unknown-freebsd`.][57809] + + +Libraries +--------- +- [The trait bounds have been removed on some of `HashMap`'s and + `HashSet`'s basic methods.][58370] Most notably you no longer require + the `Hash` trait to create an iterator. +- [The `Ord` trait bounds have been removed on some of `BinaryHeap`'s basic + methods.][58421] Most notably you no longer require the `Ord` trait to create + an iterator. +- [The methods `overflowing_neg` and `wrapping_neg` are now `const` functions + for all numeric types.][58044] +- [Indexing a `str` is now generic over all types that + implement `SliceIndex`.][57604] +- [`str::trim`, `str::trim_matches`, `str::trim_{start, end}`, and + `str::trim_{start, end}_matches` are now `#[must_use]`][57106] and will + produce a warning if their returning type is unused. +- [The methods `checked_pow`, `saturating_pow`, `wrapping_pow`, and + `overflowing_pow` are now available for all numeric types.][57873] These are + equivalvent to methods such as `wrapping_add` for the `pow` operation. + + +Stabilized APIs +--------------- + +#### std & core +* [`Any::type_id`] +* [`Error::type_id`] +* [`atomic::AtomicI16`] +* [`atomic::AtomicI32`] +* [`atomic::AtomicI64`] +* [`atomic::AtomicI8`] +* [`atomic::AtomicU16`] +* [`atomic::AtomicU32`] +* [`atomic::AtomicU64`] +* [`atomic::AtomicU8`] +* [`convert::Infallible`] +* [`convert::TryFrom`] +* [`convert::TryInto`] +* [`iter::from_fn`] +* [`iter::successors`] +* [`num::NonZeroI128`] +* [`num::NonZeroI16`] +* [`num::NonZeroI32`] +* [`num::NonZeroI64`] +* [`num::NonZeroI8`] +* [`num::NonZeroIsize`] +* [`slice::sort_by_cached_key`] +* [`str::escape_debug`] +* [`str::escape_default`] +* [`str::escape_unicode`] +* [`str::split_ascii_whitespace`] + +#### std +* [`Instant::checked_add`] +* [`Instant::checked_sub`] +* [`SystemTime::checked_add`] +* [`SystemTime::checked_sub`] + +Cargo +----- +- [You can now use alternative registries to crates.io.][cargo/6654] + +Misc +---- +- [You can now use the `?` operator in your documentation tests without manually + adding `fn main() -> Result<(), _> {}`.][56470] + +Compatibility Notes +------------------- +- [`Command::before_exec` is now deprecated in favor of the + unsafe method `Command::pre_exec`.][58059] +- [Use of `ATOMIC_{BOOL, ISIZE, USIZE}_INIT` is now deprecated.][57425] As you + can now use `const` functions in `static` variables. + +[58370]: https://github.com/rust-lang/rust/pull/58370/ +[58406]: https://github.com/rust-lang/rust/pull/58406/ +[58421]: https://github.com/rust-lang/rust/pull/58421/ +[58166]: https://github.com/rust-lang/rust/pull/58166/ +[58044]: https://github.com/rust-lang/rust/pull/58044/ +[58057]: https://github.com/rust-lang/rust/pull/58057/ +[58059]: https://github.com/rust-lang/rust/pull/58059/ +[57809]: https://github.com/rust-lang/rust/pull/57809/ +[57873]: https://github.com/rust-lang/rust/pull/57873/ +[57604]: https://github.com/rust-lang/rust/pull/57604/ +[57367]: https://github.com/rust-lang/rust/pull/57367/ +[57407]: https://github.com/rust-lang/rust/pull/57407/ +[57425]: https://github.com/rust-lang/rust/pull/57425/ +[57106]: https://github.com/rust-lang/rust/pull/57106/ +[56470]: https://github.com/rust-lang/rust/pull/56470/ +[cargo/6654]: https://github.com/rust-lang/cargo/pull/6654/ +[`Any::type_id`]: https://doc.rust-lang.org/std/any/trait.Any.html#tymethod.type_id +[`Error::type_id`]: https://doc.rust-lang.org/std/error/trait.Error.html#tymethod.type_id +[`atomic::AtomicI16`]: https://doc.rust-lang.org/std/atomic/struct.AtomicI16.html +[`atomic::AtomicI32`]: https://doc.rust-lang.org/std/atomic/struct.AtomicI32.html +[`atomic::AtomicI64`]: https://doc.rust-lang.org/std/atomic/struct.AtomicI64.html +[`atomic::AtomicI8`]: https://doc.rust-lang.org/std/atomic/struct.AtomicI8.html +[`atomic::AtomicU16`]: https://doc.rust-lang.org/std/atomic/struct.AtomicU16.html +[`atomic::AtomicU32`]: https://doc.rust-lang.org/std/atomic/struct.AtomicU32.html +[`atomic::AtomicU64`]: https://doc.rust-lang.org/std/atomic/struct.AtomicU64.html +[`atomic::AtomicU8`]: https://doc.rust-lang.org/std/atomic/struct.AtomicU8.html +[`convert::Infallible`]: https://doc.rust-lang.org/std/convert/enum.Infallible.html +[`convert::TryFrom`]: https://doc.rust-lang.org/std/convert/trait.TryFrom.html +[`convert::TryInto`]: https://doc.rust-lang.org/std/convert/trait.TryInto.html +[`iter::from_fn`]: https://doc.rust-lang.org/std/iter/fn.from_fn.html +[`iter::successors`]: https://doc.rust-lang.org/std/iter/fn.successors.html +[`num::NonZeroI128`]: https://doc.rust-lang.org/std/num/struct.NonZeroI128.html +[`num::NonZeroI16`]: https://doc.rust-lang.org/std/num/struct.NonZeroI16.html +[`num::NonZeroI32`]: https://doc.rust-lang.org/std/num/struct.NonZeroI32.html +[`num::NonZeroI64`]: https://doc.rust-lang.org/std/num/struct.NonZeroI64.html +[`num::NonZeroI8`]: https://doc.rust-lang.org/std/num/struct.NonZeroI8.html +[`num::NonZeroIsize`]: https://doc.rust-lang.org/std/num/struct.NonZeroIsize.html +[`slice::sort_by_cached_key`]: https://doc.rust-lang.org/std/slice/fn.sort_by_cached_key +[`str::escape_debug`]: https://doc.rust-lang.org/std/primitive.str.html#method.escape_debug +[`str::escape_default`]: https://doc.rust-lang.org/std/primitive.str.html#method.escape_default +[`str::escape_unicode`]: https://doc.rust-lang.org/std/primitive.str.html#method.escape_unicode +[`str::split_ascii_whitespace`]: https://doc.rust-lang.org/std/primitive.str.html#method.split_ascii_whitespace +[`Instant::checked_add`]: https://doc.rust-lang.org/std/time/struct.Instant.html#method.checked_add +[`Instant::checked_sub`]: https://doc.rust-lang.org/std/time/struct.Instant.html#method.checked_sub +[`SystemTime::checked_add`]: https://doc.rust-lang.org/std/time/struct.SystemTime.html#method.checked_add +[`SystemTime::checked_sub`]: https://doc.rust-lang.org/std/time/struct.SystemTime.html#method.checked_sub + + Version 1.33.0 (2019-02-28) ========================== @@ -99,6 +245,8 @@ Stabilized APIs Cargo ----- +- [You can now publish crates that require a feature flag to compile with + `cargo publish --features` or `cargo publish --all-features`.][cargo/6453] - [Cargo should now rebuild a crate if a file was modified during the initial build.][cargo/6484] @@ -135,6 +283,7 @@ Compatibility Notes [57535]: https://github.com/rust-lang/rust/pull/57535/ [57566]: https://github.com/rust-lang/rust/pull/57566/ [57615]: https://github.com/rust-lang/rust/pull/57615/ +[cargo/6453]: https://github.com/rust-lang/cargo/pull/6453/ [cargo/6484]: https://github.com/rust-lang/cargo/pull/6484/ [`unix::FileExt::read_exact_at`]: https://doc.rust-lang.org/std/os/unix/fs/trait.FileExt.html#method.read_exact_at [`unix::FileExt::write_all_at`]: https://doc.rust-lang.org/std/os/unix/fs/trait.FileExt.html#method.write_all_at diff --git a/src/ci/docker/dist-various-2/build-wasi-toolchain.sh b/src/ci/docker/dist-various-2/build-wasi-toolchain.sh index a15fb8cae2566..965286e5bcf64 100755 --- a/src/ci/docker/dist-various-2/build-wasi-toolchain.sh +++ b/src/ci/docker/dist-various-2/build-wasi-toolchain.sh @@ -12,7 +12,7 @@ export PATH=`pwd`/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-14.04/bin:$PATH git clone https://github.com/CraneStation/wasi-sysroot cd wasi-sysroot -git reset --hard 320054e84f8f2440def3b1c8700cedb8fd697bf8 +git reset --hard e5f14be38362f1ab83302895a6e74b2ffd0e2302 make -j$(nproc) INSTALL_DIR=/wasm32-unknown-wasi install cd .. diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 7b9e19e36a293..e903bd936c484 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -429,6 +429,26 @@ pub trait TryInto: Sized { /// When the `!` type is stablized `Infallible` and `!` will be /// equivalent. /// +/// `TryFrom` can be implemented as follows: +/// +/// ``` +/// use std::convert::TryFrom; +/// +/// struct SuperiorThanZero(i32); +/// +/// impl TryFrom for SuperiorThanZero { +/// type Error = &'static str; +/// +/// fn try_from(value: i32) -> Result { +/// if value < 0 { +/// Err("SuperiorThanZero only accepts value superior than zero!") +/// } else { +/// Ok(SuperiorThanZero(value)) +/// } +/// } +/// } +/// ``` +/// /// # Examples /// /// As described, [`i32`] implements `TryFrom`: diff --git a/src/librustc_codegen_llvm/back/link.rs b/src/librustc_codegen_llvm/back/link.rs index f10bc0516e5bf..19419a72b94dd 100644 --- a/src/librustc_codegen_llvm/back/link.rs +++ b/src/librustc_codegen_llvm/back/link.rs @@ -1396,10 +1396,6 @@ fn add_upstream_rust_crates(cmd: &mut dyn Linker, // Same thing as above, but for dynamic crates instead of static crates. fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) { - // If we're performing LTO, then it should have been previously required - // that all upstream rust dependencies were available in an rlib format. - assert!(!are_upstream_rust_objects_already_included(sess)); - // Just need to tell the linker about where the library lives and // what its name is let parent = cratepath.parent(); diff --git a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs index 7c369daa2a8f6..46cf4cd8ae353 100644 --- a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs +++ b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs @@ -21,6 +21,15 @@ pub fn target() -> Result { "-Wl,--no-undefined-version", "-Wl,-Bsymbolic", "-Wl,--export-dynamic", + // The following symbols are needed by libunwind, which is linked after + // libstd. Make sure they're included in the link. + "-Wl,-u,__rust_abort", + "-Wl,-u,__rust_c_alloc", + "-Wl,-u,__rust_c_dealloc", + "-Wl,-u,__rust_print_err", + "-Wl,-u,__rust_rwlock_rdlock", + "-Wl,-u,__rust_rwlock_unlock", + "-Wl,-u,__rust_rwlock_wrlock", ]; const EXPORT_SYMBOLS: &[&str] = &[ diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index f92fa2e9799ad..0cd7fe9159493 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1918,7 +1918,10 @@ fn explicit_predicates_of<'a, 'tcx>( } } - let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + let hir_id = match tcx.hir().as_local_hir_id(def_id) { + Some(hir_id) => hir_id, + None => return tcx.predicates_of(def_id), + }; let node = tcx.hir().get_by_hir_id(hir_id); let mut is_trait = None; diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index adbe73b165ef4..555cb1bd64f6e 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -568,7 +568,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { (replaced.clone(), replaced.clean(self.cx)) }); - let full_generics = (&type_generics, &tcx.predicates_of(did)); + let full_generics = (&type_generics, &tcx.explicit_predicates_of(did)); let Generics { params: mut generic_params, .. diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index aaae0bafd9e01..570c61f1ffc99 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -132,7 +132,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { .collect(); let ty = self.cx.get_real_ty(def_id, def_ctor, &real_name, generics); - let predicates = infcx.tcx.predicates_of(impl_def_id); + let predicates = infcx.tcx.explicit_predicates_of(impl_def_id); impls.push(Item { source: infcx.tcx.def_span(impl_def_id).clean(self.cx), diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index d9a63969fec97..8da71cf708aa0 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -228,7 +228,7 @@ fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function { } fn build_enum(cx: &DocContext<'_>, did: DefId) -> clean::Enum { - let predicates = cx.tcx.predicates_of(did); + let predicates = cx.tcx.explicit_predicates_of(did); clean::Enum { generics: (cx.tcx.generics_of(did), &predicates).clean(cx), @@ -238,7 +238,7 @@ fn build_enum(cx: &DocContext<'_>, did: DefId) -> clean::Enum { } fn build_struct(cx: &DocContext<'_>, did: DefId) -> clean::Struct { - let predicates = cx.tcx.predicates_of(did); + let predicates = cx.tcx.explicit_predicates_of(did); let variant = cx.tcx.adt_def(did).non_enum_variant(); clean::Struct { @@ -254,7 +254,7 @@ fn build_struct(cx: &DocContext<'_>, did: DefId) -> clean::Struct { } fn build_union(cx: &DocContext<'_>, did: DefId) -> clean::Union { - let predicates = cx.tcx.predicates_of(did); + let predicates = cx.tcx.explicit_predicates_of(did); let variant = cx.tcx.adt_def(did).non_enum_variant(); clean::Union { @@ -266,7 +266,7 @@ fn build_union(cx: &DocContext<'_>, did: DefId) -> clean::Union { } fn build_type_alias(cx: &DocContext<'_>, did: DefId) -> clean::Typedef { - let predicates = cx.tcx.predicates_of(did); + let predicates = cx.tcx.explicit_predicates_of(did); clean::Typedef { type_: cx.tcx.type_of(did).clean(cx), @@ -325,7 +325,7 @@ pub fn build_impl(cx: &DocContext<'_>, did: DefId, ret: &mut Vec) { } } - let predicates = tcx.predicates_of(did); + let predicates = tcx.explicit_predicates_of(did); let (trait_items, generics) = if let Some(hir_id) = tcx.hir().as_local_hir_id(did) { match tcx.hir().expect_item_by_hir_id(hir_id).node { hir::ItemKind::Impl(.., ref gen, _, _, ref item_ids) => { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 27ffe4583df25..e994c661fdceb 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2288,7 +2288,7 @@ impl<'tcx> Clean for ty::AssociatedItem { } ty::AssociatedKind::Method => { let generics = (cx.tcx.generics_of(self.def_id), - &cx.tcx.predicates_of(self.def_id)).clean(cx); + &cx.tcx.explicit_predicates_of(self.def_id)).clean(cx); let sig = cx.tcx.fn_sig(self.def_id); let mut decl = (self.def_id, sig).clean(cx); @@ -2361,7 +2361,7 @@ impl<'tcx> Clean for ty::AssociatedItem { // are actually located on the trait/impl itself, so we need to load // all of the generics from there and then look for bounds that are // applied to this associated type in question. - let predicates = cx.tcx.predicates_of(did); + let predicates = cx.tcx.explicit_predicates_of(did); let generics = (cx.tcx.generics_of(did), &predicates).clean(cx); let mut bounds = generics.where_predicates.iter().filter_map(|pred| { let (name, self_type, trait_, bounds) = match *pred { @@ -3069,7 +3069,7 @@ impl<'tcx> Clean for Ty<'tcx> { ty::Opaque(def_id, substs) => { // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the projections associated with the def_id. - let predicates_of = cx.tcx.predicates_of(def_id); + let predicates_of = cx.tcx.explicit_predicates_of(def_id); let substs = cx.tcx.lift(&substs).expect("Opaque lift failed"); let bounds = predicates_of.instantiate(cx.tcx, substs); let mut regions = vec![]; diff --git a/src/libstd/sys/sgx/alloc.rs b/src/libstd/sys/sgx/alloc.rs index 98eb8397436bf..b385d567dd8c4 100644 --- a/src/libstd/sys/sgx/alloc.rs +++ b/src/libstd/sys/sgx/alloc.rs @@ -1,4 +1,4 @@ -use crate::alloc::{GlobalAlloc, Layout, System}; +use crate::alloc::{self, GlobalAlloc, Layout, System}; use super::waitqueue::SpinMutex; @@ -30,3 +30,17 @@ unsafe impl GlobalAlloc for System { DLMALLOC.lock().realloc(ptr, layout.size(), layout.align(), new_size) } } + +// The following functions are needed by libunwind. These symbols are named +// in pre-link args for the target specification, so keep that in sync. +#[cfg(not(test))] +#[no_mangle] +pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 { + alloc::alloc(Layout::from_size_align_unchecked(size, align)) +} + +#[cfg(not(test))] +#[no_mangle] +pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) { + alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align)) +} diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs index b0679f65f0d68..a99a534f41e3c 100644 --- a/src/libstd/sys/sgx/mod.rs +++ b/src/libstd/sys/sgx/mod.rs @@ -130,6 +130,15 @@ pub unsafe fn abort_internal() -> ! { abi::usercalls::exit(true) } +// This function is needed by the panic runtime. The symbol is named in +// pre-link args for the target specification, so keep that in sync. +#[cfg(not(test))] +#[no_mangle] +// NB. used by both libunwind and libpanic_abort +pub unsafe extern "C" fn __rust_abort() { + abort_internal(); +} + pub fn hashmap_random_keys() -> (u64, u64) { fn rdrand64() -> u64 { unsafe { diff --git a/src/libstd/sys/sgx/rwlock.rs b/src/libstd/sys/sgx/rwlock.rs index 09b5ffb199676..30c47e44eef8e 100644 --- a/src/libstd/sys/sgx/rwlock.rs +++ b/src/libstd/sys/sgx/rwlock.rs @@ -1,10 +1,4 @@ -#[cfg(not(test))] -use crate::alloc::{self, Layout}; use crate::num::NonZeroUsize; -#[cfg(not(test))] -use crate::slice; -#[cfg(not(test))] -use crate::str; use super::waitqueue::{ try_lock_or_false, NotifiedTcs, SpinMutex, SpinMutexGuard, WaitQueue, WaitVariable, @@ -165,10 +159,11 @@ impl RWLock { pub unsafe fn destroy(&self) {} } +// The following functions are needed by libunwind. These symbols are named +// in pre-link args for the target specification, so keep that in sync. #[cfg(not(test))] const EINVAL: i32 = 22; -// used by libunwind port #[cfg(not(test))] #[no_mangle] pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RWLock) -> i32 { @@ -198,39 +193,6 @@ pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 { return 0; } -// the following functions are also used by the libunwind port. They're -// included here to make sure parallel codegen and LTO don't mess things up. -#[cfg(not(test))] -#[no_mangle] -pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) { - if s < 0 { - return; - } - let buf = slice::from_raw_parts(m as *const u8, s as _); - if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) { - eprint!("{}", s); - } -} - -#[cfg(not(test))] -#[no_mangle] -// NB. used by both libunwind and libpanic_abort -pub unsafe extern "C" fn __rust_abort() { - crate::sys::abort_internal(); -} - -#[cfg(not(test))] -#[no_mangle] -pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 { - alloc::alloc(Layout::from_size_align_unchecked(size, align)) -} - -#[cfg(not(test))] -#[no_mangle] -pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) { - alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align)) -} - #[cfg(test)] mod tests { use super::*; diff --git a/src/libstd/sys/sgx/stdio.rs b/src/libstd/sys/sgx/stdio.rs index f2c6892bfb7fd..a575401f5f60d 100644 --- a/src/libstd/sys/sgx/stdio.rs +++ b/src/libstd/sys/sgx/stdio.rs @@ -2,6 +2,10 @@ use fortanix_sgx_abi as abi; use crate::io; use crate::sys::fd::FileDesc; +#[cfg(not(test))] +use crate::slice; +#[cfg(not(test))] +use crate::str; pub struct Stdin(()); pub struct Stdout(()); @@ -62,3 +66,17 @@ pub fn is_ebadf(err: &io::Error) -> bool { pub fn panic_output() -> Option { super::abi::panic::SgxPanicOutput::new() } + +// This function is needed by libunwind. The symbol is named in pre-link args +// for the target specification, so keep that in sync. +#[cfg(not(test))] +#[no_mangle] +pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) { + if s < 0 { + return; + } + let buf = slice::from_raw_parts(m as *const u8, s as _); + if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) { + eprint!("{}", s); + } +} diff --git a/src/libstd/sys/wasi/fs.rs b/src/libstd/sys/wasi/fs.rs index 7b1c2bd79cc16..589593299d609 100644 --- a/src/libstd/sys/wasi/fs.rs +++ b/src/libstd/sys/wasi/fs.rs @@ -1,5 +1,4 @@ -use crate::collections::HashMap; -use crate::ffi::{OsStr, OsString}; +use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; use crate::io::{self, IoVec, IoVecMut, SeekFrom}; use crate::iter; @@ -7,11 +6,10 @@ use crate::mem::{self, ManuallyDrop}; use crate::os::wasi::ffi::{OsStrExt, OsStringExt}; use crate::path::{Path, PathBuf}; use crate::ptr; -use crate::sync::atomic::{AtomicPtr, Ordering::SeqCst}; use crate::sync::Arc; use crate::sys::fd::{DirCookie, WasiFd}; use crate::sys::time::SystemTime; -use crate::sys::{cvt_wasi, unsupported}; +use crate::sys::unsupported; use crate::sys_common::FromInner; pub use crate::sys_common::fs::copy; @@ -230,7 +228,11 @@ impl DirEntry { } pub fn metadata(&self) -> io::Result { - metadata_at(&self.inner.dir.fd, 0, OsStr::from_bytes(&self.name).as_ref()) + metadata_at( + &self.inner.dir.fd, + 0, + OsStr::from_bytes(&self.name).as_ref(), + ) } pub fn file_type(&self) -> io::Result { @@ -377,8 +379,8 @@ impl OpenOptions { impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { - let (dir, file) = open_parent(path)?; - open_at(&dir, file, opts) + let (dir, file) = open_parent(path, libc::__WASI_RIGHT_PATH_OPEN)?; + open_at(&dir, &file, opts) } pub fn open_at(&self, path: &Path, opts: &OpenOptions) -> io::Result { @@ -475,7 +477,7 @@ impl DirBuilder { } pub fn mkdir(&self, p: &Path) -> io::Result<()> { - let (dir, file) = open_parent(p)?; + let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_CREATE_DIRECTORY)?; dir.create_directory(file.as_os_str().as_bytes()) } } @@ -506,13 +508,13 @@ pub fn readdir(p: &Path) -> io::Result { } pub fn unlink(p: &Path) -> io::Result<()> { - let (dir, file) = open_parent(p)?; + let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_UNLINK_FILE)?; dir.unlink_file(file.as_os_str().as_bytes()) } pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - let (old, old_file) = open_parent(old)?; - let (new, new_file) = open_parent(new)?; + let (old, old_file) = open_parent(old, libc::__WASI_RIGHT_PATH_RENAME_SOURCE)?; + let (new, new_file) = open_parent(new, libc::__WASI_RIGHT_PATH_RENAME_TARGET)?; old.rename( old_file.as_os_str().as_bytes(), &new, @@ -527,13 +529,13 @@ pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { } pub fn rmdir(p: &Path) -> io::Result<()> { - let (dir, file) = open_parent(p)?; + let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_REMOVE_DIRECTORY)?; dir.remove_directory(file.as_os_str().as_bytes()) } pub fn readlink(p: &Path) -> io::Result { - let (dir, file) = open_parent(p)?; - read_link(&dir, file) + let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_READLINK)?; + read_link(&dir, &file) } fn read_link(fd: &WasiFd, file: &Path) -> io::Result { @@ -568,13 +570,13 @@ fn read_link(fd: &WasiFd, file: &Path) -> io::Result { } pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { - let (dst, dst_file) = open_parent(dst)?; + let (dst, dst_file) = open_parent(dst, libc::__WASI_RIGHT_PATH_SYMLINK)?; dst.symlink(src.as_os_str().as_bytes(), dst_file.as_os_str().as_bytes()) } pub fn link(src: &Path, dst: &Path) -> io::Result<()> { - let (src, src_file) = open_parent(src)?; - let (dst, dst_file) = open_parent(dst)?; + let (src, src_file) = open_parent(src, libc::__WASI_RIGHT_PATH_LINK_SOURCE)?; + let (dst, dst_file) = open_parent(dst, libc::__WASI_RIGHT_PATH_LINK_TARGET)?; src.link( libc::__WASI_LOOKUP_SYMLINK_FOLLOW, src_file.as_os_str().as_bytes(), @@ -584,13 +586,13 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> { } pub fn stat(p: &Path) -> io::Result { - let (dir, file) = open_parent(p)?; - metadata_at(&dir, libc::__WASI_LOOKUP_SYMLINK_FOLLOW, file) + let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_FILESTAT_GET)?; + metadata_at(&dir, libc::__WASI_LOOKUP_SYMLINK_FOLLOW, &file) } pub fn lstat(p: &Path) -> io::Result { - let (dir, file) = open_parent(p)?; - metadata_at(&dir, 0, file) + let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_FILESTAT_GET)?; + metadata_at(&dir, 0, &file) } fn metadata_at( @@ -621,72 +623,69 @@ fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result { Ok(File { fd }) } -// FIXME: we shouldn't implement this. It'd be much better to share this between -// libc (the wasi-sysroot) and Rust as the logic here is likely far more tricky -// than what we're executing below. For now this is a stopgap to enable this -// module, but we should add an official API in upstream wasi-libc which looks -// like this. -// -// In the meantime this is highly unlikely to be correct. It allows some basic -// testing but is not at all robust. -fn open_parent(p: &Path) -> io::Result<(&'static WasiFd, &Path)> { - let map = preopened_map(); - for ancestor in p.ancestors() { - if let Some(fd) = map.get(ancestor) { - let tail = p.strip_prefix(ancestor).unwrap(); - let tail = if tail == Path::new("") { - ".".as_ref() - } else { - tail - }; - return Ok((fd, tail)) - } - } - let msg = format!("failed to find a preopened file descriptor to open {:?}", p); - return Err(io::Error::new(io::ErrorKind::Other, msg)); - - type Preopened = HashMap>; - fn preopened_map() -> &'static Preopened { - static PTR: AtomicPtr = AtomicPtr::new(ptr::null_mut()); - unsafe { - let ptr = PTR.load(SeqCst); - if !ptr.is_null() { - return &*ptr; - } - - let mut map = Box::new(HashMap::new()); - for fd in 3.. { - let mut buf = mem::zeroed(); - if cvt_wasi(libc::__wasi_fd_prestat_get(fd, &mut buf)).is_err() { - break; - } - if buf.pr_type != libc::__WASI_PREOPENTYPE_DIR { - continue; - } - let len = buf.u.dir.pr_name_len; - let mut v = vec![0u8; len]; - let res = cvt_wasi(libc::__wasi_fd_prestat_dir_name( - fd, - v.as_mut_ptr() as *mut i8, - v.len(), - )); - if res.is_err() { - continue; - } - let path = PathBuf::from(OsString::from_vec(v)); - map.insert(path, ManuallyDrop::new(WasiFd::from_raw(fd))); - } - let ptr = Box::into_raw(map); - match PTR.compare_exchange(ptr::null_mut(), ptr, SeqCst, SeqCst) { - Ok(_) => &*ptr, - - // If we lost the race for initialization clean up the map we - // made and just use the one that's already there - Err(other) => { - drop(Box::from_raw(ptr)); - &*other - } - } +/// Attempts to open a bare path `p`. +/// +/// WASI has no fundamental capability to do this. All syscalls and operations +/// are relative to already-open file descriptors. The C library, however, +/// manages a map of preopened file descriptors to their path, and then the C +/// library provides an API to look at this. In other words, when you want to +/// open a path `p`, you have to find a previously opened file descriptor in a +/// global table and then see if `p` is relative to that file descriptor. +/// +/// This function, if successful, will return two items: +/// +/// * The first is a `ManuallyDrop`. This represents a preopened file +/// descriptor which we don't have ownership of, but we can use. You shouldn't +/// actually drop the `fd`. +/// +/// * The second is a path that should be a part of `p` and represents a +/// relative traversal from the file descriptor specified to the desired +/// location `p`. +/// +/// If successful you can use the returned file descriptor to perform +/// file-descriptor-relative operations on the path returned as well. The +/// `rights` argument indicates what operations are desired on the returned file +/// descriptor, and if successful the returned file descriptor should have the +/// appropriate rights for performing `rights` actions. +/// +/// Note that this can fail if `p` doesn't look like it can be opened relative +/// to any preopened file descriptor. +fn open_parent( + p: &Path, + rights: libc::__wasi_rights_t, +) -> io::Result<(ManuallyDrop, PathBuf)> { + let p = CString::new(p.as_os_str().as_bytes())?; + unsafe { + let mut ret = ptr::null(); + let fd = __wasilibc_find_relpath(p.as_ptr(), rights, 0, &mut ret); + if fd == -1 { + let msg = format!( + "failed to find a preopened file descriptor \ + through which {:?} could be opened", + p + ); + return Err(io::Error::new(io::ErrorKind::Other, msg)); } + let path = Path::new(OsStr::from_bytes(CStr::from_ptr(ret).to_bytes())); + + // FIXME: right now `path` is a pointer into `p`, the `CString` above. + // When we return `p` is deallocated and we can't use it, so we need to + // currently separately allocate `path`. If this becomes an issue though + // we should probably turn this into a closure-taking interface or take + // `&CString` and then pass off `&Path` tied to the same lifetime. + let path = path.to_path_buf(); + + return Ok((ManuallyDrop::new(WasiFd::from_raw(fd as u32)), path)); + } + + // FIXME(rust-lang/libc#1314) use the `libc` crate for this when the API + // there is published + extern "C" { + pub fn __wasilibc_find_relpath( + path: *const libc::c_char, + rights_base: libc::__wasi_rights_t, + rights_inheriting: libc::__wasi_rights_t, + relative_path: *mut *const libc::c_char, + ) -> libc::c_int; } } diff --git a/src/test/run-make-fulldeps/lto-dylib-dep/Makefile b/src/test/run-make-fulldeps/lto-dylib-dep/Makefile new file mode 100644 index 0000000000000..ab8ee6c2ef7e1 --- /dev/null +++ b/src/test/run-make-fulldeps/lto-dylib-dep/Makefile @@ -0,0 +1,10 @@ +-include ../tools.mk + +# Test that we don't run into an assertion when using a Rust dylib dependency +# while compiling with full LTO. +# See https://github.com/rust-lang/rust/issues/59137 + +all: + $(RUSTC) a_dylib.rs --crate-type=dylib -C prefer-dynamic + $(RUSTC) main.rs -C lto + $(call RUN,main) diff --git a/src/test/run-make-fulldeps/lto-dylib-dep/a_dylib.rs b/src/test/run-make-fulldeps/lto-dylib-dep/a_dylib.rs new file mode 100644 index 0000000000000..c5a35296f89ed --- /dev/null +++ b/src/test/run-make-fulldeps/lto-dylib-dep/a_dylib.rs @@ -0,0 +1,4 @@ + +pub fn foo() { + println!("bar"); +} diff --git a/src/test/run-make-fulldeps/lto-dylib-dep/main.rs b/src/test/run-make-fulldeps/lto-dylib-dep/main.rs new file mode 100644 index 0000000000000..af0955e7f3520 --- /dev/null +++ b/src/test/run-make-fulldeps/lto-dylib-dep/main.rs @@ -0,0 +1,6 @@ + +extern crate a_dylib; + +fn main() { + a_dylib::foo(); +} diff --git a/src/test/rustdoc/useless_lifetime_bound.rs b/src/test/rustdoc/useless_lifetime_bound.rs new file mode 100644 index 0000000000000..f530d8a654f01 --- /dev/null +++ b/src/test/rustdoc/useless_lifetime_bound.rs @@ -0,0 +1,13 @@ +use std::marker::PhantomData; + +// @has useless_lifetime_bound/struct.Scope.html +// @!has - '//*[@class="rust struct"]' "'env: 'env" +pub struct Scope<'env> { + _marker: PhantomData<&'env mut &'env ()>, +} + +// @has useless_lifetime_bound/struct.Scope.html +// @!has - '//*[@class="rust struct"]' "T: 'a + 'a" +pub struct SomeStruct<'a, T: 'a> { + _marker: PhantomData<&'a T>, +}