From: Steve Klabnik Date: Tue, 20 Oct 2015 13:43:48 +0000 (-0400) Subject: Rollup merge of #29176 - huonw:shared-tracking, r=Gankro X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=e058318b2c5352994ca8bcd6dd39e99e6ec20bdb;hp=94e9a073b0edb3633b2adbcfff1dabf2da44334e;p=rust.git Rollup merge of #29176 - huonw:shared-tracking, r=Gankro --- diff --git a/mk/cfg/mips-unknown-linux-gnu.mk b/mk/cfg/mips-unknown-linux-gnu.mk index ba5f6d0e756..65b08774d49 100644 --- a/mk/cfg/mips-unknown-linux-gnu.mk +++ b/mk/cfg/mips-unknown-linux-gnu.mk @@ -7,8 +7,8 @@ CFG_LIB_NAME_mips-unknown-linux-gnu=lib$(1).so CFG_STATIC_LIB_NAME_mips-unknown-linux-gnu=lib$(1).a CFG_LIB_GLOB_mips-unknown-linux-gnu=lib$(1)-*.so CFG_LIB_DSYM_GLOB_mips-unknown-linux-gnu=lib$(1)-*.dylib.dSYM -CFG_JEMALLOC_CFLAGS_mips-unknown-linux-gnu := -mips32r2 -msoft-float -mabi=32 -mno-compact-eh $(CFLAGS) -CFG_GCCISH_CFLAGS_mips-unknown-linux-gnu := -Wall -g -fPIC -mips32r2 -msoft-float -mabi=32 -mno-compact-eh $(CFLAGS) +CFG_JEMALLOC_CFLAGS_mips-unknown-linux-gnu := -mips32r2 -msoft-float -mabi=32 $(CFLAGS) +CFG_GCCISH_CFLAGS_mips-unknown-linux-gnu := -Wall -g -fPIC -mips32r2 -msoft-float -mabi=32 $(CFLAGS) CFG_GCCISH_CXXFLAGS_mips-unknown-linux-gnu := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_mips-unknown-linux-gnu := -shared -fPIC -g -mips32r2 -msoft-float -mabi=32 CFG_GCCISH_DEF_FLAG_mips-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list= @@ -20,5 +20,5 @@ CFG_UNIXY_mips-unknown-linux-gnu := 1 CFG_LDPATH_mips-unknown-linux-gnu := CFG_RUN_mips-unknown-linux-gnu= CFG_RUN_TARG_mips-unknown-linux-gnu= -RUSTC_FLAGS_mips-unknown-linux-gnu := -C target-cpu=mips32r2 -C target-feature="+mips32r2,+o32" -C soft-float +RUSTC_FLAGS_mips-unknown-linux-gnu := -C target-cpu=mips32r2 -C target-feature="+mips32r2" -C soft-float CFG_GNU_TRIPLE_mips-unknown-linux-gnu := mips-unknown-linux-gnu diff --git a/mk/cfg/mipsel-unknown-linux-gnu.mk b/mk/cfg/mipsel-unknown-linux-gnu.mk index 539038c7434..4dadfc275d3 100644 --- a/mk/cfg/mipsel-unknown-linux-gnu.mk +++ b/mk/cfg/mipsel-unknown-linux-gnu.mk @@ -1,8 +1,8 @@ # mipsel-unknown-linux-gnu configuration -CC_mipsel-unknown-linux-gnu=mipsel-unknown-linux-gnu-gcc -CXX_mipsel-unknown-linux-gnu=mipsel-unknown-linux-gnu-g++ -CPP_mipsel-unknown-linux-gnu=mipsel-unknown-linux-gnu-gcc -AR_mipsel-unknown-linux-gnu=mipsel-unknown-linux-gnu-ar +CC_mipsel-unknown-linux-gnu=mipsel-linux-gnu-gcc +CXX_mipsel-unknown-linux-gnu=mipsel-linux-gnu-g++ +CPP_mipsel-unknown-linux-gnu=mipsel-linux-gnu-gcc +AR_mipsel-unknown-linux-gnu=mipsel-linux-gnu-ar CFG_LIB_NAME_mipsel-unknown-linux-gnu=lib$(1).so CFG_STATIC_LIB_NAME_mipsel-unknown-linux-gnu=lib$(1).a CFG_LIB_GLOB_mipsel-unknown-linux-gnu=lib$(1)-*.so @@ -20,5 +20,5 @@ CFG_UNIXY_mipsel-unknown-linux-gnu := 1 CFG_LDPATH_mipsel-unknown-linux-gnu := CFG_RUN_mipsel-unknown-linux-gnu= CFG_RUN_TARG_mipsel-unknown-linux-gnu= -RUSTC_FLAGS_mipsel-unknown-linux-gnu := -C target-cpu=mips32 -C target-feature="+mips32,+o32" +RUSTC_FLAGS_mipsel-unknown-linux-gnu := -C target-cpu=mips32 -C target-feature="+mips32" CFG_GNU_TRIPLE_mipsel-unknown-linux-gnu := mipsel-unknown-linux-gnu diff --git a/mk/dist.mk b/mk/dist.mk index 125141c1830..eb94760e248 100644 --- a/mk/dist.mk +++ b/mk/dist.mk @@ -21,6 +21,7 @@ # * dist-docs - Stage docs for upload PKG_NAME := $(CFG_PACKAGE_NAME) +STD_PKG_NAME := rust-std-$(CFG_PACKAGE_VERS) DOC_PKG_NAME := rust-docs-$(CFG_PACKAGE_VERS) MINGW_PKG_NAME := rust-mingw-$(CFG_PACKAGE_VERS) @@ -112,19 +113,25 @@ distcheck-tar-src: dist-tar-src # Unix binary installer tarballs ###################################################################### -define DEF_INSTALLER +define DEF_START_INSTALLER +dist-install-dir-$(1)-%: PREPARE_DIR_CMD=$(DEFAULT_PREPARE_DIR_CMD) +dist-install-dir-$(1)-%: PREPARE_BIN_CMD=$(DEFAULT_PREPARE_BIN_CMD) +dist-install-dir-$(1)-%: PREPARE_LIB_CMD=$(DEFAULT_PREPARE_LIB_CMD) +dist-install-dir-$(1)-%: PREPARE_MAN_CMD=$(DEFAULT_PREPARE_MAN_CMD) +dist-install-dir-$(1)-%: PREPARE_CLEAN=true $$(eval $$(call DEF_PREPARE,dir-$(1))) +endef + +$(foreach target,$(CFG_TARGET),\ + $(eval $(call DEF_START_INSTALLER,$(target)))) -dist-install-dir-$(1): PREPARE_HOST=$(1) -dist-install-dir-$(1): PREPARE_TARGETS=$(2) -dist-install-dir-$(1): PREPARE_DEST_DIR=tmp/dist/$$(PKG_NAME)-$(1)-image -dist-install-dir-$(1): PREPARE_DIR_CMD=$(DEFAULT_PREPARE_DIR_CMD) -dist-install-dir-$(1): PREPARE_BIN_CMD=$(DEFAULT_PREPARE_BIN_CMD) -dist-install-dir-$(1): PREPARE_LIB_CMD=$(DEFAULT_PREPARE_LIB_CMD) -dist-install-dir-$(1): PREPARE_MAN_CMD=$(DEFAULT_PREPARE_MAN_CMD) -dist-install-dir-$(1): PREPARE_CLEAN=true -dist-install-dir-$(1): prepare-base-dir-$(1) docs +define DEF_INSTALLER + +dist-install-dir-$(1)-host: PREPARE_HOST=$(1) +dist-install-dir-$(1)-host: PREPARE_TARGETS=$(2) +dist-install-dir-$(1)-host: PREPARE_DEST_DIR=tmp/dist/$$(PKG_NAME)-$(1)-image +dist-install-dir-$(1)-host: prepare-base-dir-$(1)-host docs $$(Q)mkdir -p $$(PREPARE_DEST_DIR)/share/doc/rust $$(Q)$$(PREPARE_MAN_CMD) $$(S)COPYRIGHT $$(PREPARE_DEST_DIR)/share/doc/rust $$(Q)$$(PREPARE_MAN_CMD) $$(S)LICENSE-APACHE $$(PREPARE_DEST_DIR)/share/doc/rust @@ -141,14 +148,27 @@ prepare-overlay-$(1): # This tiny morsel of metadata is used by rust-packaging $$(Q)echo "$(CFG_VERSION)" > tmp/dist/$$(PKG_NAME)-$(1)-overlay/version -dist/$$(PKG_NAME)-$(1).tar.gz: dist-install-dir-$(1) prepare-overlay-$(1) +dist/$$(PKG_NAME)-$(1).tar.gz: dist-install-dir-$(1)-host prepare-overlay-$(1) @$(call E, build: $$@) -# Copy essential gcc components into installer -ifdef CFG_WINDOWSY_$(1) -ifeq ($$(findstring gnu,$(1)),gnu) - $$(Q)rm -Rf tmp/dist/win-rust-gcc-$(1) - $$(Q)$$(CFG_PYTHON) $$(S)src/etc/make-win-dist.py tmp/dist/$$(PKG_NAME)-$(1)-image tmp/dist/win-rust-gcc-$(1) $(1) - $$(Q)cp -r $$(S)src/etc/third-party tmp/dist/$$(PKG_NAME)-$(1)-image/share/doc/ +# On a 32-bit MinGW target we've got a few runtime DLL dependencies that we need +# to include. THe first argument to `make-win-dist` is where to put these DLLs +# (the image we're creating) and the second argument is a junk directory to +# ignore all the other MinGW stuff the script creates. +ifeq ($(2),i686-pc-windows-gnu) + $$(Q)rm -Rf tmp/dist/win-rust-gcc-$(2) + $$(Q)$$(CFG_PYTHON) $$(S)src/etc/make-win-dist.py \ + tmp/dist/$$(STD_PKG_NAME)-$(2)-image \ + tmp/dist/win-rust-gcc-$(2) $(2) +endif +# On 32-bit MinGW we're always including a DLL which needs some extra licenses +# to distribute. On 64-bit MinGW we don't actually distribute anything requiring +# us to distribute a license but it's likely that the install will *also* +# include the rust-mingw package down below, which also need licenses, so to be +# safe we just inlude it here in all MinGW packages. +ifdef CFG_WINDOWSY_$(2) +ifeq ($$(findstring $(2),gnu),gnu) + $$(Q)cp -r $$(S)src/etc/third-party \ + tmp/dist/$$(STD_PKG_NAME)-$(2)-image/share/doc/ endif endif $$(Q)$$(S)src/rust-installer/gen-installer.sh \ @@ -183,11 +203,16 @@ dist/$$(DOC_PKG_NAME)-$(1).tar.gz: dist-doc-install-dir-$(1) --bulk-dirs=share/doc/rust/html $$(Q)rm -R tmp/dist/$$(DOC_PKG_NAME)-$(1)-image +# Creates the rust-mingw package, and the first argument to make-win-dist is a +# "temporary directory" which is just thrown away (this contains the runtime +# DLLs included in the rustc package above) and the second argument is where to +# place all the MinGW components (which is what we want). dist-mingw-install-dir-$(1): $$(Q)mkdir -p tmp/dist/rust-mingw-tmp-$(1)-image $$(Q)rm -Rf tmp/dist/$$(MINGW_PKG_NAME)-$(1)-image $$(Q)$$(CFG_PYTHON) $$(S)src/etc/make-win-dist.py \ - tmp/dist/rust-mingw-tmp-$(1)-image tmp/dist/$$(MINGW_PKG_NAME)-$(1)-image $(1) + tmp/dist/rust-mingw-tmp-$(1)-image \ + tmp/dist/$$(MINGW_PKG_NAME)-$(1)-image $(1) dist/$$(MINGW_PKG_NAME)-$(1).tar.gz: dist-mingw-install-dir-$(1) @$(call E, build: $$@) @@ -205,15 +230,34 @@ dist/$$(MINGW_PKG_NAME)-$(1).tar.gz: dist-mingw-install-dir-$(1) endef -ifneq ($(CFG_ENABLE_DIST_HOST_ONLY),) -$(foreach host,$(CFG_HOST),\ - $(eval $(call DEF_INSTALLER,$(host),$(host)))) -else -$(foreach host,$(CFG_HOST),\ - $(eval $(call DEF_INSTALLER,$(host),$(CFG_TARGET)))) -endif +# $(1) - host +# $(2) - target +define DEF_INSTALLER_TARGETS + +dist-install-dir-$(2)-target: PREPARE_HOST=$(1) +dist-install-dir-$(2)-target: PREPARE_TARGETS=$(2) +dist-install-dir-$(2)-target: PREPARE_DEST_DIR=tmp/dist/$$(STD_PKG_NAME)-$(2)-image +dist-install-dir-$(2)-target: prepare-base-dir-$(2)-target -dist-install-dirs: $(foreach host,$(CFG_HOST),dist-install-dir-$(host)) +dist/$$(STD_PKG_NAME)-$(2).tar.gz: dist-install-dir-$(2)-target + @$$(call E, build: $$@) + $$(Q)$$(S)src/rust-installer/gen-installer.sh \ + --product-name=Rust \ + --rel-manifest-dir=rustlib \ + --success-message=std-is-standing-at-the-ready. \ + --image-dir=tmp/dist/$$(STD_PKG_NAME)-$(2)-image \ + --work-dir=tmp/dist \ + --output-dir=dist \ + --package-name=$$(STD_PKG_NAME)-$(2) \ + --component-name=rust-std-$(2) \ + --legacy-manifest-dirs=rustlib,cargo + $$(Q)rm -R tmp/dist/$$(STD_PKG_NAME)-$(2)-image +endef + +$(foreach host,$(CFG_HOST),\ + $(eval $(call DEF_INSTALLER,$(host)))) +$(foreach target,$(CFG_TARGET),\ + $(eval $(call DEF_INSTALLER_TARGETS,$(CFG_BUILD),$(target)))) ifdef CFG_WINDOWSY_$(CFG_BUILD) define BUILD_MINGW_TARBALL @@ -230,7 +274,9 @@ ifeq ($(CFG_DISABLE_DOCS),) MAYBE_DOC_TARBALLS=$(foreach host,$(CFG_HOST),dist/$(DOC_PKG_NAME)-$(host).tar.gz) endif -dist-tar-bins: $(foreach host,$(CFG_HOST),dist/$(PKG_NAME)-$(host).tar.gz) \ +dist-tar-bins: \ + $(foreach host,$(CFG_HOST),dist/$(PKG_NAME)-$(host).tar.gz) \ + $(foreach target,$(CFG_TARGET),dist/$(STD_PKG_NAME)-$(target).tar.gz) \ $(MAYBE_DOC_TARBALLS) $(MAYBE_MINGW_TARBALLS) # Just try to run the compiler for the build host diff --git a/mk/install.mk b/mk/install.mk index cabc97a1e49..8b8170220c9 100644 --- a/mk/install.mk +++ b/mk/install.mk @@ -8,6 +8,12 @@ # option. This file may not be copied, modified, or distributed # except according to those terms. +RUN_INSALLER = cd tmp/empty_dir && \ + sh ../../tmp/dist/$(1)/install.sh \ + --prefix="$(DESTDIR)$(CFG_PREFIX)" \ + --libdir="$(DESTDIR)$(CFG_LIBDIR)" \ + --mandir="$(DESTDIR)$(CFG_MANDIR)" + install: ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER))) # Build the dist as the original user @@ -16,9 +22,11 @@ else $(Q)$(MAKE) prepare_install endif ifeq ($(CFG_DISABLE_DOCS),) - $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(DOC_PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" + $(Q)$(call RUN_INSALLER,$(DOC_PKG_NAME)-$(CFG_BUILD)) --disable-ldconfig endif - $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" + $(Q)$(foreach target,$(CFG_TARGET),\ + ($(call RUN_INSALLER,$(STD_PKG_NAME)-$(target)) --disable-ldconfig);) + $(Q)$(call RUN_INSALLER,$(PKG_NAME)-$(CFG_BUILD)) # Remove tmp files because it's a decent amount of disk space $(Q)rm -R tmp/dist @@ -32,9 +40,11 @@ else $(Q)$(MAKE) prepare_uninstall endif ifeq ($(CFG_DISABLE_DOCS),) - $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(DOC_PKG_NAME)-$(CFG_BUILD)/install.sh --uninstall --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" + $(Q)$(call RUN_INSALLER,$(DOC_PKG_NAME)-$(CFG_BUILD)) --uninstall endif - $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --uninstall --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" + $(Q)$(call RUN_INSALLER,$(PKG_NAME)-$(CFG_BUILD)) --uninstall + $(Q)$(foreach target,$(CFG_TARGET),\ + ($(call RUN_INSALLER,$(STD_PKG_NAME)-$(target)) --uninstall);) # Remove tmp files because it's a decent amount of disk space $(Q)rm -R tmp/dist diff --git a/mk/prepare.mk b/mk/prepare.mk index fe619cc7cae..e263a6d2e4d 100644 --- a/mk/prepare.mk +++ b/mk/prepare.mk @@ -185,16 +185,16 @@ INSTALL_DEBUGGER_SCRIPT_COMMANDS=$(if $(findstring windows,$(1)),\ define DEF_PREPARE -prepare-base-$(1): PREPARE_SOURCE_DIR=$$(PREPARE_HOST)/stage$$(PREPARE_STAGE) -prepare-base-$(1): PREPARE_SOURCE_BIN_DIR=$$(PREPARE_SOURCE_DIR)/bin -prepare-base-$(1): PREPARE_SOURCE_LIB_DIR=$$(PREPARE_SOURCE_DIR)/$$(CFG_LIBDIR_RELATIVE) -prepare-base-$(1): PREPARE_SOURCE_MAN_DIR=$$(S)/man -prepare-base-$(1): PREPARE_DEST_BIN_DIR=$$(PREPARE_DEST_DIR)/bin -prepare-base-$(1): PREPARE_DEST_LIB_DIR=$$(PREPARE_DEST_DIR)/$$(CFG_LIBDIR_RELATIVE) -prepare-base-$(1): PREPARE_DEST_MAN_DIR=$$(PREPARE_DEST_DIR)/share/man/man1 -prepare-base-$(1): prepare-everything-$(1) +prepare-base-$(1)-%: PREPARE_SOURCE_DIR=$$(PREPARE_HOST)/stage$$(PREPARE_STAGE) +prepare-base-$(1)-%: PREPARE_SOURCE_BIN_DIR=$$(PREPARE_SOURCE_DIR)/bin +prepare-base-$(1)-%: PREPARE_SOURCE_LIB_DIR=$$(PREPARE_SOURCE_DIR)/$$(CFG_LIBDIR_RELATIVE) +prepare-base-$(1)-%: PREPARE_SOURCE_MAN_DIR=$$(S)/man +prepare-base-$(1)-%: PREPARE_DEST_BIN_DIR=$$(PREPARE_DEST_DIR)/bin +prepare-base-$(1)-%: PREPARE_DEST_LIB_DIR=$$(PREPARE_DEST_DIR)/$$(CFG_LIBDIR_RELATIVE) +prepare-base-$(1)-%: PREPARE_DEST_MAN_DIR=$$(PREPARE_DEST_DIR)/share/man/man1 -prepare-everything-$(1): prepare-host-$(1) prepare-targets-$(1) prepare-debugger-scripts-$(1) +prepare-base-$(1)-target: prepare-target-$(1) +prepare-base-$(1)-host: prepare-host-$(1) prepare-debugger-scripts-$(1) prepare-host-$(1): prepare-host-tools-$(1) @@ -222,7 +222,7 @@ $$(foreach lib,$$(CRATES), \ $$(foreach host,$$(CFG_HOST), \ $$(eval $$(call DEF_PREPARE_HOST_LIB,$$(lib),$$(PREPARE_STAGE),$$(host),$(1))))) -prepare-targets-$(1): \ +prepare-target-$(1): \ $$(foreach host,$$(CFG_HOST), \ $$(foreach target,$$(CFG_TARGET), \ prepare-target-$$(target)-host-$$(host)-$$(PREPARE_STAGE)-$(1))) diff --git a/src/doc/nomicon/dropck.md b/src/doc/nomicon/dropck.md index 95bcdc02ba0..ad7c65032c7 100644 --- a/src/doc/nomicon/dropck.md +++ b/src/doc/nomicon/dropck.md @@ -220,6 +220,7 @@ checking the implicit assertion that no potentially expired data It is sometimes obvious that no such access can occur, like the case above. However, when dealing with a generic type parameter, such access can occur indirectly. Examples of such indirect access are: + * invoking a callback, * via a trait method call. diff --git a/src/doc/nomicon/leaking.md b/src/doc/nomicon/leaking.md index 1f72a4c1724..a5d5742a4c6 100644 --- a/src/doc/nomicon/leaking.md +++ b/src/doc/nomicon/leaking.md @@ -135,7 +135,7 @@ impl Rc { fn new(data: T) -> Self { unsafe { // Wouldn't it be nice if heap::allocate worked like this? - let ptr = heap::allocate>(); + let ptr = heap::allocate::>(); ptr::write(ptr, RcBox { data: data, ref_count: 1, diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index d438c27a96f..4cba1083fd9 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -32,6 +32,8 @@ use alloc::raw_vec::RawVec; +use super::range::RangeArgument; + const INITIAL_CAPACITY: usize = 7; // 2^3 - 1 const MINIMUM_CAPACITY: usize = 1; // 2 - 1 const MAXIMUM_ZST_CAPACITY: usize = 1 << (usize::BITS - 1); // Largest possible power of two @@ -168,6 +170,117 @@ unsafe fn copy_nonoverlapping(&self, dst: usize, src: usize, len: usize) { len); } + /// Copies a potentially wrapping block of memory len long from src to dest. + /// (abs(dst - src) + len) must be no larger than cap() (There must be at + /// most one continuous overlapping region between src and dest). + unsafe fn wrap_copy(&self, dst: usize, src: usize, len: usize) { + debug_assert!( + (if src <= dst { dst - src } else { src - dst }) + len <= self.cap(), + "dst={} src={} len={} cap={}", dst, src, len, self.cap()); + + if src == dst || len == 0 { return } + + let dst_after_src = self.wrap_sub(dst, src) < len; + + let src_pre_wrap_len = self.cap() - src; + let dst_pre_wrap_len = self.cap() - dst; + let src_wraps = src_pre_wrap_len < len; + let dst_wraps = dst_pre_wrap_len < len; + + match (dst_after_src, src_wraps, dst_wraps) { + (_, false, false) => { + // src doesn't wrap, dst doesn't wrap + // + // S . . . + // 1 [_ _ A A B B C C _] + // 2 [_ _ A A A A B B _] + // D . . . + // + self.copy(dst, src, len); + } + (false, false, true) => { + // dst before src, src doesn't wrap, dst wraps + // + // S . . . + // 1 [A A B B _ _ _ C C] + // 2 [A A B B _ _ _ A A] + // 3 [B B B B _ _ _ A A] + // . . D . + // + self.copy(dst, src, dst_pre_wrap_len); + self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len); + } + (true, false, true) => { + // src before dst, src doesn't wrap, dst wraps + // + // S . . . + // 1 [C C _ _ _ A A B B] + // 2 [B B _ _ _ A A B B] + // 3 [B B _ _ _ A A A A] + // . . D . + // + self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len); + self.copy(dst, src, dst_pre_wrap_len); + } + (false, true, false) => { + // dst before src, src wraps, dst doesn't wrap + // + // . . S . + // 1 [C C _ _ _ A A B B] + // 2 [C C _ _ _ B B B B] + // 3 [C C _ _ _ B B C C] + // D . . . + // + self.copy(dst, src, src_pre_wrap_len); + self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len); + } + (true, true, false) => { + // src before dst, src wraps, dst doesn't wrap + // + // . . S . + // 1 [A A B B _ _ _ C C] + // 2 [A A A A _ _ _ C C] + // 3 [C C A A _ _ _ C C] + // D . . . + // + self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len); + self.copy(dst, src, src_pre_wrap_len); + } + (false, true, true) => { + // dst before src, src wraps, dst wraps + // + // . . . S . + // 1 [A B C D _ E F G H] + // 2 [A B C D _ E G H H] + // 3 [A B C D _ E G H A] + // 4 [B C C D _ E G H A] + // . . D . . + // + debug_assert!(dst_pre_wrap_len > src_pre_wrap_len); + let delta = dst_pre_wrap_len - src_pre_wrap_len; + self.copy(dst, src, src_pre_wrap_len); + self.copy(dst + src_pre_wrap_len, 0, delta); + self.copy(0, delta, len - dst_pre_wrap_len); + } + (true, true, true) => { + // src before dst, src wraps, dst wraps + // + // . . S . . + // 1 [A B C D _ E F G H] + // 2 [A A B D _ E F G H] + // 3 [H A B D _ E F G H] + // 4 [H A B D _ E F F G] + // . . . D . + // + debug_assert!(src_pre_wrap_len > dst_pre_wrap_len); + let delta = src_pre_wrap_len - dst_pre_wrap_len; + self.copy(delta, 0, len - src_pre_wrap_len); + self.copy(0, self.cap() - delta, delta); + self.copy(dst, src, dst_pre_wrap_len); + } + } + } + /// Frobs the head and tail sections around to handle the fact that we /// just reallocated. Unsafe because it trusts old_cap. #[inline] @@ -613,8 +726,18 @@ pub fn len(&self) -> usize { count(self.tail, self.head, self.cap()) } #[stable(feature = "rust1", since = "1.0.0")] pub fn is_empty(&self) -> bool { self.len() == 0 } - /// Creates a draining iterator that clears the `VecDeque` and iterates over - /// the removed items from start to end. + /// Create a draining iterator that removes the specified range in the + /// `VecDeque` and yields the removed items from start to end. The element + /// range is removed even if the iterator is not consumed until the end. + /// + /// Note: It is unspecified how many elements are removed from the deque, + /// if the `Drain` value is not dropped, but the borrow it holds expires + /// (eg. due to mem::forget). + /// + /// # Panics + /// + /// Panics if the starting point is greater than the end point or if + /// the end point is greater than the length of the vector. /// /// # Examples /// @@ -623,18 +746,66 @@ pub fn is_empty(&self) -> bool { self.len() == 0 } /// /// use std::collections::VecDeque; /// + /// // draining using `..` clears the whole deque. /// let mut v = VecDeque::new(); /// v.push_back(1); - /// assert_eq!(v.drain().next(), Some(1)); + /// assert_eq!(v.drain(..).next(), Some(1)); /// assert!(v.is_empty()); /// ``` #[inline] #[unstable(feature = "drain", reason = "matches collection reform specification, waiting for dust to settle", issue = "27711")] - pub fn drain(&mut self) -> Drain { + pub fn drain(&mut self, range: R) -> Drain where R: RangeArgument { + // Memory safety + // + // When the Drain is first created, the source deque is shortened to + // make sure no uninitialized or moved-from elements are accessible at + // all if the Drain's destructor never gets to run. + // + // Drain will ptr::read out the values to remove. + // When finished, the remaining data will be copied back to cover the hole, + // and the head/tail values will be restored correctly. + // + let len = self.len(); + let start = *range.start().unwrap_or(&0); + let end = *range.end().unwrap_or(&len); + assert!(start <= end, "drain lower bound was too large"); + assert!(end <= len, "drain upper bound was too large"); + + // The deque's elements are parted into three segments: + // * self.tail -> drain_tail + // * drain_tail -> drain_head + // * drain_head -> self.head + // + // T = self.tail; H = self.head; t = drain_tail; h = drain_head + // + // We store drain_tail as self.head, and drain_head and self.head as + // after_tail and after_head respectively on the Drain. This also + // truncates the effective array such that if the Drain is leaked, we + // have forgotten about the potentially moved values after the start of + // the drain. + // + // T t h H + // [. . . o o x x o o . . .] + // + let drain_tail = self.wrap_add(self.tail, start); + let drain_head = self.wrap_add(self.tail, end); + let head = self.head; + + // "forget" about the values after the start of the drain until after + // the drain is complete and the Drain destructor is run. + self.head = drain_tail; + Drain { - inner: self, + deque: self as *mut _, + after_tail: drain_head, + after_head: head, + iter: Iter { + tail: drain_tail, + head: drain_head, + ring: unsafe { self.buffer_as_mut_slice() }, + }, } } @@ -653,7 +824,7 @@ pub fn drain(&mut self) -> Drain { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn clear(&mut self) { - self.drain(); + self.drain(..); } /// Provides a reference to the front element, or `None` if the sequence is @@ -1393,7 +1564,7 @@ pub fn split_off(&mut self, at: usize) -> Self { #[stable(feature = "append", since = "1.4.0")] pub fn append(&mut self, other: &mut Self) { // naive impl - self.extend(other.drain()); + self.extend(other.drain(..)); } /// Retains only the elements specified by the predicate. @@ -1627,15 +1798,59 @@ impl ExactSizeIterator for IntoIter {} reason = "matches collection reform specification, waiting for dust to settle", issue = "27711")] pub struct Drain<'a, T: 'a> { - inner: &'a mut VecDeque, + after_tail: usize, + after_head: usize, + iter: Iter<'a, T>, + deque: *mut VecDeque, } +unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {} +unsafe impl<'a, T: Send> Send for Drain<'a, T> {} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: 'a> Drop for Drain<'a, T> { fn drop(&mut self) { for _ in self.by_ref() {} - self.inner.head = 0; - self.inner.tail = 0; + + let source_deque = unsafe { &mut *self.deque }; + + // T = source_deque_tail; H = source_deque_head; t = drain_tail; h = drain_head + // + // T t h H + // [. . . o o x x o o . . .] + // + let orig_tail = source_deque.tail; + let drain_tail = source_deque.head; + let drain_head = self.after_tail; + let orig_head = self.after_head; + + let tail_len = count(orig_tail, drain_tail, source_deque.cap()); + let head_len = count(drain_head, orig_head, source_deque.cap()); + + // Restore the original head value + source_deque.head = orig_head; + + match (tail_len, head_len) { + (0, 0) => { + source_deque.head = 0; + source_deque.tail = 0; + } + (0, _) => { + source_deque.tail = drain_head; + } + (_, 0) => { + source_deque.head = drain_tail; + } + _ => unsafe { + if tail_len <= head_len { + source_deque.tail = source_deque.wrap_sub(drain_head, tail_len); + source_deque.wrap_copy(source_deque.tail, orig_tail, tail_len); + } else { + source_deque.head = source_deque.wrap_add(drain_tail, head_len); + source_deque.wrap_copy(drain_tail, drain_head, head_len); + } + } + } } } @@ -1645,13 +1860,16 @@ impl<'a, T: 'a> Iterator for Drain<'a, T> { #[inline] fn next(&mut self) -> Option { - self.inner.pop_front() + self.iter.next().map(|elt| + unsafe { + ptr::read(elt) + } + ) } #[inline] fn size_hint(&self) -> (usize, Option) { - let len = self.inner.len(); - (len, Some(len)) + self.iter.size_hint() } } @@ -1659,7 +1877,11 @@ fn size_hint(&self) -> (usize, Option) { impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { #[inline] fn next_back(&mut self) -> Option { - self.inner.pop_back() + self.iter.next_back().map(|elt| + unsafe { + ptr::read(elt) + } + ) } } @@ -1962,6 +2184,44 @@ fn test_remove() { } } + #[test] + fn test_drain() { + let mut tester: VecDeque = VecDeque::with_capacity(7); + + let cap = tester.capacity(); + for len in 0..cap + 1 { + for tail in 0..cap + 1 { + for drain_start in 0..len + 1 { + for drain_end in drain_start..len + 1 { + tester.tail = tail; + tester.head = tail; + for i in 0..len { + tester.push_back(i); + } + + // Check that we drain the correct values + let drained: VecDeque<_> = + tester.drain(drain_start..drain_end).collect(); + let drained_expected: VecDeque<_> = + (drain_start..drain_end).collect(); + assert_eq!(drained, drained_expected); + + // We shouldn't have changed the capacity or made the + // head or tail out of bounds + assert_eq!(tester.capacity(), cap); + assert!(tester.tail < tester.cap()); + assert!(tester.head < tester.cap()); + + // We should see the correct values in the VecDeque + let expected: VecDeque<_> = + (0..drain_start).chain(drain_end..len).collect(); + assert_eq!(expected, tester); + } + } + } + } + } + #[test] fn test_shrink_to_fit() { // This test checks that every single combination of head and tail position, diff --git a/src/libcollectionstest/vec_deque.rs b/src/libcollectionstest/vec_deque.rs index 1931e372aeb..5f587789bd8 100644 --- a/src/libcollectionstest/vec_deque.rs +++ b/src/libcollectionstest/vec_deque.rs @@ -475,7 +475,7 @@ fn test_drain() { let mut d: VecDeque = VecDeque::new(); { - let mut iter = d.drain(); + let mut iter = d.drain(..); assert_eq!(iter.size_hint(), (0, Some(0))); assert_eq!(iter.next(), None); @@ -492,7 +492,7 @@ fn test_drain() { d.push_back(i); } - assert_eq!(d.drain().collect::>(), [0, 1, 2, 3, 4]); + assert_eq!(d.drain(..).collect::>(), [0, 1, 2, 3, 4]); assert!(d.is_empty()); } @@ -506,7 +506,7 @@ fn test_drain() { d.push_front(i); } - assert_eq!(d.drain().collect::>(), [8,7,6,0,1,2,3,4]); + assert_eq!(d.drain(..).collect::>(), [8,7,6,0,1,2,3,4]); assert!(d.is_empty()); } @@ -521,7 +521,7 @@ fn test_drain() { } { - let mut it = d.drain(); + let mut it = d.drain(..); assert_eq!(it.size_hint(), (8, Some(8))); assert_eq!(it.next(), Some(8)); assert_eq!(it.size_hint(), (7, Some(7))); diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index f9480b4349d..27d8af2e8a8 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -36,6 +36,17 @@ impl !Send for *const T { } impl !Send for *mut T { } /// Types with a constant size known at compile-time. +/// +/// All type parameters which can be bounded have an implicit bound of `Sized`. The special syntax +/// `?Sized` can be used to remove this bound if it is not appropriate. +/// +/// ``` +/// struct Foo(T); +/// struct Bar(T); +/// +/// // struct FooUse(Foo<[i32]>); // error: Sized is not implemented for [i32] +/// struct BarUse(Bar<[i32]>); // OK +/// ``` #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sized"] #[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"] diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 0669f545a83..1da7a1502d9 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -2162,4 +2162,10 @@ fn dir_entry_methods() { } } } + + #[test] + fn read_dir_not_found() { + let res = fs::read_dir("/path/that/does/not/exist"); + assert_eq!(res.err().unwrap().kind(), ErrorKind::NotFound); + } } diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 6e3c5eaf217..9d03022bb84 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -625,8 +625,8 @@ fn exit_reported_right() { drop(p.wait()); } - #[cfg(unix)] #[cfg(all(unix, not(target_os="android")))] + #[test] fn signal_reported_right() { use os::unix::process::ExitStatusExt; diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index bac5b47eb1a..a9eb4db2f53 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -83,6 +83,8 @@ pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15; pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd; +pub const ERROR_PATH_NOT_FOUND: libc::c_int = 3; + #[repr(C)] #[cfg(target_arch = "x86")] pub struct WSADATA { diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 85f5d4e5884..4df3c561ab1 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -51,6 +51,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { libc::ERROR_ALREADY_EXISTS => ErrorKind::AlreadyExists, libc::ERROR_BROKEN_PIPE => ErrorKind::BrokenPipe, libc::ERROR_FILE_NOT_FOUND => ErrorKind::NotFound, + c::ERROR_PATH_NOT_FOUND => ErrorKind::NotFound, libc::ERROR_NO_DATA => ErrorKind::BrokenPipe, libc::ERROR_OPERATION_ABORTED => ErrorKind::TimedOut, diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 2a5c4993112..11bf6ec24ce 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -417,7 +417,7 @@ pub fn expand(&self, let mut attrs = newitem.attrs.clone(); attrs.extend(item.attrs.iter().filter(|a| { match &a.name()[..] { - "allow" | "warn" | "deny" | "forbid" => true, + "allow" | "warn" | "deny" | "forbid" | "stable" | "unstable" => true, _ => false, } }).cloned()); diff --git a/src/test/run-pass/sync-send-iterators-in-libcollections.rs b/src/test/run-pass/sync-send-iterators-in-libcollections.rs index 8160fe56fd0..7fa592105c0 100644 --- a/src/test/run-pass/sync-send-iterators-in-libcollections.rs +++ b/src/test/run-pass/sync-send-iterators-in-libcollections.rs @@ -93,7 +93,8 @@ fn from_usize(v: usize) -> Foo { } all_sync_send!(EnumSet::::new(), iter); - all_sync_send!(VecDeque::::new(), iter, iter_mut, drain, into_iter); + all_sync_send!(VecDeque::::new(), iter, iter_mut, into_iter); + is_sync_send!(VecDeque::::new(), drain(..)); all_sync_send!(Vec::::new(), into_iter); is_sync_send!(Vec::::new(), drain(..));