Merge branch 'master' into 35123-map3
This commit is contained in:
commit
20c10913ff
757 changed files with 23893 additions and 20370 deletions
|
|
@ -15,9 +15,9 @@ before_install:
|
|||
script:
|
||||
- docker run -v `pwd`:/build rust
|
||||
sh -c "
|
||||
./configure --llvm-root=/usr/lib/llvm-3.7 &&
|
||||
./configure --enable-rustbuild --llvm-root=/usr/lib/llvm-3.7 &&
|
||||
make tidy &&
|
||||
make check-notidy -j4
|
||||
make check -j4
|
||||
"
|
||||
|
||||
# Real testing happens on http://buildbot.rust-lang.org/
|
||||
|
|
|
|||
|
|
@ -151,6 +151,10 @@ Some common make targets are:
|
|||
command above as we only build the stage1 compiler, not the entire thing).
|
||||
You can also leave off the `-rpass` to run all stage1 test types.
|
||||
- `make check-stage1-coretest` - Run stage1 tests in `libcore`.
|
||||
- `make tidy` - Check that the source code is in compliance with Rust's style
|
||||
guidelines. There is no official document describing Rust's full guidelines
|
||||
as of yet, but basic rules like 4 spaces for indentation and no more than 99
|
||||
characters in a single line should be kept in mind when writing code.
|
||||
|
||||
## Pull Requests
|
||||
|
||||
|
|
@ -177,6 +181,15 @@ you’re adding something to the standard library, try
|
|||
|
||||
This will not rebuild the compiler, but will run the tests.
|
||||
|
||||
Please make sure your pull request is in compliance with Rust's style
|
||||
guidelines by running
|
||||
|
||||
$ make tidy
|
||||
|
||||
Make this check before every pull request (and every new commit in a pull
|
||||
request) ; you can add [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks)
|
||||
before every push to make sure you never forget to make this check.
|
||||
|
||||
All pull requests are reviewed by another person. We have a bot,
|
||||
@rust-highfive, that will automatically assign a random person to review your
|
||||
request.
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ fetch snapshots, and an OS that can execute the available snapshot binaries.
|
|||
|
||||
Snapshot binaries are currently built and tested on several platforms:
|
||||
|
||||
| Platform \ Architecture | x86 | x86_64 |
|
||||
| Platform / Architecture | x86 | x86_64 |
|
||||
|--------------------------------|-----|--------|
|
||||
| Windows (7, 8, Server 2008 R2) | ✓ | ✓ |
|
||||
| Linux (2.6.18 or later) | ✓ | ✓ |
|
||||
|
|
|
|||
26
configure
vendored
26
configure
vendored
|
|
@ -360,6 +360,13 @@ abs_path() {
|
|||
(unset CDPATH && cd "$_path" > /dev/null && pwd)
|
||||
}
|
||||
|
||||
HELP=0
|
||||
for arg; do
|
||||
case "$arg" in
|
||||
--help) HELP=1;;
|
||||
esac
|
||||
done
|
||||
|
||||
msg "looking for configure programs"
|
||||
need_cmd cmp
|
||||
need_cmd mkdir
|
||||
|
|
@ -517,6 +524,10 @@ case $CFG_CPUTYPE in
|
|||
CFG_CPUTYPE=powerpc64le
|
||||
;;
|
||||
|
||||
s390x)
|
||||
CFG_CPUTYPE=s390x
|
||||
;;
|
||||
|
||||
x86_64 | x86-64 | x64 | amd64)
|
||||
CFG_CPUTYPE=x86_64
|
||||
;;
|
||||
|
|
@ -566,11 +577,8 @@ esac
|
|||
|
||||
|
||||
OPTIONS=""
|
||||
HELP=0
|
||||
if [ "$1" = "--help" ]
|
||||
if [ "$HELP" -eq 1 ]
|
||||
then
|
||||
HELP=1
|
||||
shift
|
||||
echo
|
||||
echo "Usage: $CFG_SELF [options]"
|
||||
echo
|
||||
|
|
@ -609,7 +617,6 @@ opt dist-host-only 0 "only install bins for the host architecture"
|
|||
opt inject-std-version 1 "inject the current compiler version of libstd into programs"
|
||||
opt llvm-version-check 1 "check if the LLVM version is supported, build anyway"
|
||||
opt rustbuild 0 "use the rust and cargo based build system"
|
||||
opt orbit 1 "get MIR where it belongs - everywhere; most importantly, in orbit"
|
||||
opt codegen-tests 1 "run the src/test/codegen tests"
|
||||
opt option-checking 1 "complain about unrecognized options in this configure script"
|
||||
opt ninja 0 "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)"
|
||||
|
|
@ -630,6 +637,7 @@ valopt datadir "${CFG_PREFIX}/share" "install data"
|
|||
valopt infodir "${CFG_PREFIX}/share/info" "install additional info"
|
||||
valopt llvm-root "" "set LLVM root"
|
||||
valopt python "" "set path to python"
|
||||
valopt nodejs "" "set path to nodejs"
|
||||
valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located"
|
||||
valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple"
|
||||
valopt android-cross-path "" "Android NDK standalone path (deprecated)"
|
||||
|
|
@ -668,6 +676,7 @@ valopt_nosave local-rust-root "/usr/local" "set prefix for local rust binary"
|
|||
valopt_nosave host "${CFG_BUILD}" "GNUs ./configure syntax LLVM host triples"
|
||||
valopt_nosave target "${CFG_HOST}" "GNUs ./configure syntax LLVM target triples"
|
||||
valopt_nosave mandir "${CFG_PREFIX}/share/man" "install man pages in PATH"
|
||||
valopt_nosave docdir "${CFG_PREFIX}/share/doc/rust" "install man pages in PATH"
|
||||
|
||||
# On Windows this determines root of the subtree for target libraries.
|
||||
# Host runtime libs always go to 'bin'.
|
||||
|
|
@ -745,6 +754,9 @@ if [ $(echo $python_version | grep -c '^Python 2\.7') -ne 1 ]; then
|
|||
err "Found $python_version, but Python 2.7 is required"
|
||||
fi
|
||||
|
||||
# Checking for node, but not required
|
||||
probe CFG_NODEJS nodejs node
|
||||
|
||||
# If we have no git directory then we are probably a tarball distribution
|
||||
# and shouldn't attempt to load submodules
|
||||
if [ ! -e ${CFG_SRC_DIR}.git ]
|
||||
|
|
@ -897,7 +909,7 @@ then
|
|||
fi
|
||||
|
||||
CMD="${CFG_LOCAL_RUST_ROOT}/bin/rustc${BIN_SUF}"
|
||||
LRV=`$CMD --version`
|
||||
LRV=`LD_LIBRARY_PATH=${CFG_LOCAL_RUST_ROOT}/lib $CMD --version`
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
step_msg "failure while running $CMD --version"
|
||||
|
|
@ -1113,6 +1125,7 @@ putvar CFG_STDCPP_NAME
|
|||
# a little post-processing of various config values
|
||||
CFG_PREFIX=${CFG_PREFIX%/}
|
||||
CFG_MANDIR=${CFG_MANDIR%/}
|
||||
CFG_DOCDIR=${CFG_DOCDIR%/}
|
||||
CFG_HOST="$(echo $CFG_HOST | tr ',' ' ')"
|
||||
CFG_TARGET="$(echo $CFG_TARGET | tr ',' ' ')"
|
||||
CFG_SUPPORTED_TARGET=""
|
||||
|
|
@ -1794,6 +1807,7 @@ putvar CFG_ARMV7_LINUX_ANDROIDEABI_NDK
|
|||
putvar CFG_I686_LINUX_ANDROID_NDK
|
||||
putvar CFG_NACL_CROSS_PATH
|
||||
putvar CFG_MANDIR
|
||||
putvar CFG_DOCDIR
|
||||
putvar CFG_USING_LIBCPP
|
||||
|
||||
# Avoid spurious warnings from clang by feeding it original source on
|
||||
|
|
|
|||
1
mk/cfg/mips64-unknown-linux-gnuabi64.mk
Normal file
1
mk/cfg/mips64-unknown-linux-gnuabi64.mk
Normal file
|
|
@ -0,0 +1 @@
|
|||
# rustbuild-only target
|
||||
1
mk/cfg/mips64el-unknown-linux-gnuabi64.mk
Normal file
1
mk/cfg/mips64el-unknown-linux-gnuabi64.mk
Normal file
|
|
@ -0,0 +1 @@
|
|||
# rustbuild-only target
|
||||
|
|
@ -1 +1,24 @@
|
|||
# rustbuild-only target
|
||||
# s390x-unknown-linux-gnu configuration
|
||||
CROSS_PREFIX_s390x-unknown-linux-gnu=s390x-linux-gnu-
|
||||
CC_s390x-unknown-linux-gnu=$(CC)
|
||||
CXX_s390x-unknown-linux-gnu=$(CXX)
|
||||
CPP_s390x-unknown-linux-gnu=$(CPP)
|
||||
AR_s390x-unknown-linux-gnu=$(AR)
|
||||
CFG_LIB_NAME_s390x-unknown-linux-gnu=lib$(1).so
|
||||
CFG_STATIC_LIB_NAME_s390x-unknown-linux-gnu=lib$(1).a
|
||||
CFG_LIB_GLOB_s390x-unknown-linux-gnu=lib$(1)-*.so
|
||||
CFG_LIB_DSYM_GLOB_s390x-unknown-linux-gnu=lib$(1)-*.dylib.dSYM
|
||||
CFG_CFLAGS_s390x-unknown-linux-gnu := -m64 $(CFLAGS)
|
||||
CFG_GCCISH_CFLAGS_s390x-unknown-linux-gnu := -g -fPIC -m64 $(CFLAGS)
|
||||
CFG_GCCISH_CXXFLAGS_s390x-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_s390x-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m64
|
||||
CFG_GCCISH_DEF_FLAG_s390x-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_LLC_FLAGS_s390x-unknown-linux-gnu :=
|
||||
CFG_INSTALL_NAME_s390x-unknown-linux-gnu =
|
||||
CFG_EXE_SUFFIX_s390x-unknown-linux-gnu =
|
||||
CFG_WINDOWSY_s390x-unknown-linux-gnu :=
|
||||
CFG_UNIXY_s390x-unknown-linux-gnu := 1
|
||||
CFG_LDPATH_s390x-unknown-linux-gnu :=
|
||||
CFG_RUN_s390x-unknown-linux-gnu=$(2)
|
||||
CFG_RUN_TARG_s390x-unknown-linux-gnu=$(call CFG_RUN_s390x-unknown-linux-gnu,,$(2))
|
||||
CFG_GNU_TRIPLE_s390x-unknown-linux-gnu := s390x-unknown-linux-gnu
|
||||
|
|
|
|||
|
|
@ -102,7 +102,6 @@ define CLEAN_TARGET_STAGE_N
|
|||
clean$(1)_T_$(2)_H_$(3): \
|
||||
$$(foreach crate,$$(CRATES),clean$(1)_T_$(2)_H_$(3)-lib-$$(crate)) \
|
||||
$$(foreach tool,$$(TOOLS) $$(DEBUGGER_BIN_SCRIPTS_ALL),clean$(1)_T_$(2)_H_$(3)-tool-$$(tool))
|
||||
$$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/libcompiler-rt.a
|
||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/librun_pass_stage* # For unix
|
||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/run_pass_stage* # For windows
|
||||
|
||||
|
|
|
|||
25
mk/crates.mk
25
mk/crates.mk
|
|
@ -51,7 +51,7 @@
|
|||
|
||||
TARGET_CRATES := libc std term \
|
||||
getopts collections test rand \
|
||||
core alloc \
|
||||
compiler_builtins core alloc \
|
||||
rustc_unicode rustc_bitflags \
|
||||
alloc_system alloc_jemalloc \
|
||||
panic_abort panic_unwind unwind
|
||||
|
|
@ -59,12 +59,13 @@ RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_
|
|||
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
|
||||
rustc_data_structures rustc_platform_intrinsics rustc_errors \
|
||||
rustc_plugin rustc_metadata rustc_passes rustc_save_analysis \
|
||||
rustc_const_eval rustc_const_math rustc_incremental
|
||||
rustc_const_eval rustc_const_math rustc_incremental rustc_macro
|
||||
HOST_CRATES := syntax syntax_ext proc_macro syntax_pos $(RUSTC_CRATES) rustdoc fmt_macros \
|
||||
flate arena graphviz rbml log serialize
|
||||
flate arena graphviz log serialize
|
||||
TOOLS := compiletest rustdoc rustc rustbook error_index_generator
|
||||
|
||||
DEPS_core :=
|
||||
DEPS_compiler_builtins := core
|
||||
DEPS_alloc := core libc alloc_system
|
||||
DEPS_alloc_system := core libc
|
||||
DEPS_alloc_jemalloc := core libc native:jemalloc
|
||||
|
|
@ -77,12 +78,14 @@ DEPS_panic_abort := libc alloc
|
|||
DEPS_panic_unwind := libc alloc unwind
|
||||
DEPS_unwind := libc
|
||||
|
||||
RUSTFLAGS_compiler_builtins := -lstatic=compiler-rt
|
||||
|
||||
# FIXME(stage0): change this to just `RUSTFLAGS_panic_abort := ...`
|
||||
RUSTFLAGS1_panic_abort := -C panic=abort
|
||||
RUSTFLAGS2_panic_abort := -C panic=abort
|
||||
RUSTFLAGS3_panic_abort := -C panic=abort
|
||||
|
||||
DEPS_std := core libc rand alloc collections rustc_unicode \
|
||||
DEPS_std := core libc rand alloc collections compiler_builtins rustc_unicode \
|
||||
native:backtrace \
|
||||
alloc_system panic_abort panic_unwind unwind
|
||||
DEPS_arena := std
|
||||
|
|
@ -93,13 +96,12 @@ DEPS_getopts := std
|
|||
DEPS_graphviz := std
|
||||
DEPS_log := std
|
||||
DEPS_num := std
|
||||
DEPS_rbml := std log serialize
|
||||
DEPS_serialize := std log
|
||||
DEPS_term := std
|
||||
DEPS_test := std getopts term native:rust_test_helpers
|
||||
|
||||
DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode rustc_errors syntax_pos
|
||||
DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros
|
||||
DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros rustc_macro
|
||||
DEPS_proc_macro := syntax syntax_pos rustc_plugin log
|
||||
DEPS_syntax_pos := serialize
|
||||
|
||||
|
|
@ -107,7 +109,7 @@ DEPS_rustc_const_math := std syntax log serialize
|
|||
DEPS_rustc_const_eval := rustc_const_math rustc syntax log serialize \
|
||||
rustc_back graphviz syntax_pos
|
||||
|
||||
DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml \
|
||||
DEPS_rustc := syntax fmt_macros flate arena serialize getopts \
|
||||
log graphviz rustc_llvm rustc_back rustc_data_structures\
|
||||
rustc_const_math syntax_pos rustc_errors
|
||||
DEPS_rustc_back := std syntax flate log libc
|
||||
|
|
@ -118,11 +120,13 @@ DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_bo
|
|||
rustc_trans rustc_privacy rustc_lint rustc_plugin \
|
||||
rustc_metadata syntax_ext proc_macro \
|
||||
rustc_passes rustc_save_analysis rustc_const_eval \
|
||||
rustc_incremental syntax_pos rustc_errors
|
||||
rustc_incremental syntax_pos rustc_errors rustc_macro
|
||||
DEPS_rustc_errors := log libc serialize syntax_pos
|
||||
DEPS_rustc_lint := rustc log syntax syntax_pos rustc_const_eval
|
||||
DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
|
||||
DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rbml rustc_const_math
|
||||
DEPS_rustc_macro := std syntax
|
||||
DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rustc_const_math \
|
||||
rustc_macro syntax_ext
|
||||
DEPS_rustc_passes := syntax syntax_pos rustc core rustc_const_eval rustc_errors
|
||||
DEPS_rustc_mir := rustc syntax syntax_pos rustc_const_math rustc_const_eval rustc_bitflags
|
||||
DEPS_rustc_resolve := arena rustc log syntax syntax_pos rustc_errors
|
||||
|
|
@ -132,7 +136,7 @@ DEPS_rustc_privacy := rustc log syntax syntax_pos
|
|||
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
|
||||
log syntax serialize rustc_llvm rustc_platform_intrinsics \
|
||||
rustc_const_math rustc_const_eval rustc_incremental rustc_errors syntax_pos
|
||||
DEPS_rustc_incremental := rbml rustc syntax_pos serialize rustc_data_structures
|
||||
DEPS_rustc_incremental := rustc syntax_pos serialize rustc_data_structures
|
||||
DEPS_rustc_save_analysis := rustc log syntax syntax_pos serialize
|
||||
DEPS_rustc_typeck := rustc syntax syntax_pos rustc_platform_intrinsics rustc_const_math \
|
||||
rustc_const_eval rustc_errors
|
||||
|
|
@ -151,6 +155,7 @@ TOOL_SOURCE_rustc := $(S)src/driver/driver.rs
|
|||
TOOL_SOURCE_rustbook := $(S)src/tools/rustbook/main.rs
|
||||
TOOL_SOURCE_error_index_generator := $(S)src/tools/error_index_generator/main.rs
|
||||
|
||||
ONLY_RLIB_compiler_builtins := 1
|
||||
ONLY_RLIB_core := 1
|
||||
ONLY_RLIB_libc := 1
|
||||
ONLY_RLIB_alloc := 1
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ tmp/dist/$$(SRC_PKG_NAME)-image: $(PKG_FILES)
|
|||
@$(call E, making src image)
|
||||
$(Q)rm -Rf tmp/dist/$(SRC_PKG_NAME)-image
|
||||
$(Q)mkdir -p tmp/dist/$(SRC_PKG_NAME)-image/lib/rustlib/src/rust
|
||||
$(Q)echo "$(CFG_VERSION)" > tmp/dist/$(SRC_PKG_NAME)-image/lib/rustlib/src/rust/version
|
||||
$(Q)tar \
|
||||
-C $(S) \
|
||||
-f - \
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ RUN_INSTALLER = cd tmp/empty_dir && \
|
|||
sh ../../tmp/dist/$(1)/install.sh \
|
||||
--prefix="$(DESTDIR)$(CFG_PREFIX)" \
|
||||
--libdir="$(DESTDIR)$(CFG_LIBDIR)" \
|
||||
--mandir="$(DESTDIR)$(CFG_MANDIR)"
|
||||
--mandir="$(DESTDIR)$(CFG_MANDIR)" \
|
||||
--docdir="$(DESTDIR)$(CFG_DOCDIR)"
|
||||
|
||||
install:
|
||||
ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER)))
|
||||
|
|
|
|||
|
|
@ -348,6 +348,7 @@ LLVM_AS_$(1)=$$(CFG_LLVM_INST_DIR_$(1))/bin/llvm-as$$(X_$(1))
|
|||
LLC_$(1)=$$(CFG_LLVM_INST_DIR_$(1))/bin/llc$$(X_$(1))
|
||||
|
||||
LLVM_ALL_COMPONENTS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --components)
|
||||
LLVM_VERSION_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --version)
|
||||
|
||||
endef
|
||||
|
||||
|
|
@ -454,7 +455,10 @@ endif
|
|||
TSREQ$(1)_T_$(2)_H_$(3) = \
|
||||
$$(HSREQ$(1)_H_$(3)) \
|
||||
$$(foreach obj,$$(REQUIRED_OBJECTS_$(2)),\
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj))
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj)) \
|
||||
$$(TLIB0_T_$(2)_H_$(3))/$$(call CFG_STATIC_LIB_NAME_$(2),compiler-rt)
|
||||
# ^ This copies `libcompiler-rt.a` to the stage0 sysroot
|
||||
# ^ TODO(stage0) update this to not copy `libcompiler-rt.a` to stage0
|
||||
|
||||
# Prerequisites for a working stageN compiler and libraries, for a specific
|
||||
# target
|
||||
|
|
@ -629,7 +633,8 @@ ALL_TARGET_RULES = $(foreach target,$(CFG_TARGET), \
|
|||
$(foreach host,$(CFG_HOST), \
|
||||
all-target-$(target)-host-$(host)))
|
||||
|
||||
all: $(ALL_TARGET_RULES) $(GENERATED) docs
|
||||
all-no-docs: $(ALL_TARGET_RULES) $(GENERATED)
|
||||
all: all-no-docs docs
|
||||
|
||||
######################################################################
|
||||
# Build system documentation
|
||||
|
|
|
|||
|
|
@ -102,8 +102,6 @@ include $(wildcard $(CFG_SRC_DIR)mk/cfg/*.mk)
|
|||
define ADD_INSTALLED_OBJECTS
|
||||
INSTALLED_OBJECTS_$(1) += $$(CFG_INSTALLED_OBJECTS_$(1))
|
||||
REQUIRED_OBJECTS_$(1) += $$(CFG_THIRD_PARTY_OBJECTS_$(1))
|
||||
INSTALLED_OBJECTS_$(1) += $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt)
|
||||
REQUIRED_OBJECTS_$(1) += $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt)
|
||||
endef
|
||||
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
|
|
|
|||
338
mk/rt.mk
338
mk/rt.mk
|
|
@ -37,6 +37,16 @@
|
|||
################################################################################
|
||||
NATIVE_LIBS := hoedown miniz rust_test_helpers
|
||||
|
||||
# A macro to add a generic implementation of intrinsics iff a arch optimized implementation is not
|
||||
# already in the list.
|
||||
# $(1) is the target
|
||||
# $(2) is the intrinsic
|
||||
define ADD_INTRINSIC
|
||||
ifeq ($$(findstring X,$$(foreach intrinsic,$$(COMPRT_OBJS_$(1)),$$(if $$(findstring $(2),$$(intrinsic)),X,))),)
|
||||
COMPRT_OBJS_$(1) += $(2)
|
||||
endif
|
||||
endef
|
||||
|
||||
# $(1) is the target triple
|
||||
define NATIVE_LIBRARIES
|
||||
|
||||
|
|
@ -230,167 +240,15 @@ COMPRT_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt)
|
|||
COMPRT_LIB_$(1) := $$(RT_OUTPUT_DIR_$(1))/$$(COMPRT_NAME_$(1))
|
||||
COMPRT_BUILD_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/compiler-rt
|
||||
|
||||
# GENERIC_SOURCES in CMakeLists.txt
|
||||
COMPRT_OBJS_$(1) := \
|
||||
absvdi2.o \
|
||||
absvsi2.o \
|
||||
adddf3.o \
|
||||
addsf3.o \
|
||||
addvdi3.o \
|
||||
addvsi3.o \
|
||||
apple_versioning.o \
|
||||
ashldi3.o \
|
||||
ashrdi3.o \
|
||||
clear_cache.o \
|
||||
clzdi2.o \
|
||||
clzsi2.o \
|
||||
cmpdi2.o \
|
||||
comparedf2.o \
|
||||
comparesf2.o \
|
||||
ctzdi2.o \
|
||||
ctzsi2.o \
|
||||
divdc3.o \
|
||||
divdf3.o \
|
||||
divdi3.o \
|
||||
divmoddi4.o \
|
||||
divmodsi4.o \
|
||||
divsc3.o \
|
||||
divsf3.o \
|
||||
divsi3.o \
|
||||
divxc3.o \
|
||||
extendsfdf2.o \
|
||||
extendhfsf2.o \
|
||||
ffsdi2.o \
|
||||
fixdfdi.o \
|
||||
fixdfsi.o \
|
||||
fixsfdi.o \
|
||||
fixsfsi.o \
|
||||
fixunsdfdi.o \
|
||||
fixunsdfsi.o \
|
||||
fixunssfdi.o \
|
||||
fixunssfsi.o \
|
||||
fixunsxfdi.o \
|
||||
fixunsxfsi.o \
|
||||
fixxfdi.o \
|
||||
floatdidf.o \
|
||||
floatdisf.o \
|
||||
floatdixf.o \
|
||||
floatsidf.o \
|
||||
floatsisf.o \
|
||||
floatundidf.o \
|
||||
floatundisf.o \
|
||||
floatundixf.o \
|
||||
floatunsidf.o \
|
||||
floatunsisf.o \
|
||||
int_util.o \
|
||||
lshrdi3.o \
|
||||
moddi3.o \
|
||||
modsi3.o \
|
||||
muldc3.o \
|
||||
muldf3.o \
|
||||
muldi3.o \
|
||||
mulodi4.o \
|
||||
mulosi4.o \
|
||||
muloti4.o \
|
||||
mulsc3.o \
|
||||
mulsf3.o \
|
||||
mulvdi3.o \
|
||||
mulvsi3.o \
|
||||
mulxc3.o \
|
||||
negdf2.o \
|
||||
negdi2.o \
|
||||
negsf2.o \
|
||||
negvdi2.o \
|
||||
negvsi2.o \
|
||||
paritydi2.o \
|
||||
paritysi2.o \
|
||||
popcountdi2.o \
|
||||
popcountsi2.o \
|
||||
powidf2.o \
|
||||
powisf2.o \
|
||||
powixf2.o \
|
||||
subdf3.o \
|
||||
subsf3.o \
|
||||
subvdi3.o \
|
||||
subvsi3.o \
|
||||
truncdfhf2.o \
|
||||
truncdfsf2.o \
|
||||
truncsfhf2.o \
|
||||
ucmpdi2.o \
|
||||
udivdi3.o \
|
||||
udivmoddi4.o \
|
||||
udivmodsi4.o \
|
||||
udivsi3.o \
|
||||
umoddi3.o \
|
||||
umodsi3.o
|
||||
# We must avoid compiling both a generic implementation (e.g. `floatdidf.c) and an arch optimized
|
||||
# implementation (e.g. `x86_64/floatdidf.S) of the same symbol (e.g. `floatdidf) because that causes
|
||||
# linker errors. To avoid that, we first add all the arch optimized implementations and then add the
|
||||
# generic implementations if and only if its arch optimized version is not already in the list. This
|
||||
# last part is handled by the ADD_INTRINSIC macro.
|
||||
|
||||
ifeq ($$(findstring ios,$(1)),)
|
||||
COMPRT_OBJS_$(1) += \
|
||||
absvti2.o \
|
||||
addtf3.o \
|
||||
addvti3.o \
|
||||
ashlti3.o \
|
||||
ashrti3.o \
|
||||
clzti2.o \
|
||||
cmpti2.o \
|
||||
ctzti2.o \
|
||||
divtf3.o \
|
||||
divti3.o \
|
||||
ffsti2.o \
|
||||
fixdfti.o \
|
||||
fixsfti.o \
|
||||
fixunsdfti.o \
|
||||
fixunssfti.o \
|
||||
fixunsxfti.o \
|
||||
fixxfti.o \
|
||||
floattidf.o \
|
||||
floattisf.o \
|
||||
floattixf.o \
|
||||
floatuntidf.o \
|
||||
floatuntisf.o \
|
||||
floatuntixf.o \
|
||||
lshrti3.o \
|
||||
modti3.o \
|
||||
multf3.o \
|
||||
multi3.o \
|
||||
mulvti3.o \
|
||||
negti2.o \
|
||||
negvti2.o \
|
||||
parityti2.o \
|
||||
popcountti2.o \
|
||||
powitf2.o \
|
||||
subtf3.o \
|
||||
subvti3.o \
|
||||
trampoline_setup.o \
|
||||
ucmpti2.o \
|
||||
udivmodti4.o \
|
||||
udivti3.o \
|
||||
umodti3.o
|
||||
endif
|
||||
|
||||
ifeq ($$(findstring apple,$(1)),apple)
|
||||
COMPRT_OBJS_$(1) += \
|
||||
atomic_flag_clear.o \
|
||||
atomic_flag_clear_explicit.o \
|
||||
atomic_flag_test_and_set.o \
|
||||
atomic_flag_test_and_set_explicit.o \
|
||||
atomic_signal_fence.o \
|
||||
atomic_thread_fence.o
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($$(findstring windows,$(1)),)
|
||||
COMPRT_OBJS_$(1) += emutls.o
|
||||
endif
|
||||
COMPRT_OBJS_$(1) :=
|
||||
|
||||
ifeq ($$(findstring msvc,$(1)),)
|
||||
|
||||
ifeq ($$(findstring freebsd,$(1)),)
|
||||
COMPRT_OBJS_$(1) += gcc_personality_v0.o
|
||||
endif
|
||||
|
||||
COMPRT_OBJS_$(1) += emutls.o
|
||||
|
||||
ifeq ($$(findstring x86_64,$(1)),x86_64)
|
||||
COMPRT_OBJS_$(1) += \
|
||||
x86_64/chkstk.o \
|
||||
|
|
@ -540,9 +398,166 @@ COMPRT_OBJS_$(1) += \
|
|||
arm/unordsf2vfp.o
|
||||
endif
|
||||
|
||||
$(foreach intrinsic,absvdi2.o \
|
||||
absvsi2.o \
|
||||
adddf3.o \
|
||||
addsf3.o \
|
||||
addvdi3.o \
|
||||
addvsi3.o \
|
||||
apple_versioning.o \
|
||||
ashldi3.o \
|
||||
ashrdi3.o \
|
||||
clear_cache.o \
|
||||
clzdi2.o \
|
||||
clzsi2.o \
|
||||
cmpdi2.o \
|
||||
comparedf2.o \
|
||||
comparesf2.o \
|
||||
ctzdi2.o \
|
||||
ctzsi2.o \
|
||||
divdc3.o \
|
||||
divdf3.o \
|
||||
divdi3.o \
|
||||
divmoddi4.o \
|
||||
divmodsi4.o \
|
||||
divsc3.o \
|
||||
divsf3.o \
|
||||
divsi3.o \
|
||||
divxc3.o \
|
||||
extendsfdf2.o \
|
||||
extendhfsf2.o \
|
||||
ffsdi2.o \
|
||||
fixdfdi.o \
|
||||
fixdfsi.o \
|
||||
fixsfdi.o \
|
||||
fixsfsi.o \
|
||||
fixunsdfdi.o \
|
||||
fixunsdfsi.o \
|
||||
fixunssfdi.o \
|
||||
fixunssfsi.o \
|
||||
fixunsxfdi.o \
|
||||
fixunsxfsi.o \
|
||||
fixxfdi.o \
|
||||
floatdidf.o \
|
||||
floatdisf.o \
|
||||
floatdixf.o \
|
||||
floatsidf.o \
|
||||
floatsisf.o \
|
||||
floatundidf.o \
|
||||
floatundisf.o \
|
||||
floatundixf.o \
|
||||
floatunsidf.o \
|
||||
floatunsisf.o \
|
||||
int_util.o \
|
||||
lshrdi3.o \
|
||||
moddi3.o \
|
||||
modsi3.o \
|
||||
muldc3.o \
|
||||
muldf3.o \
|
||||
muldi3.o \
|
||||
mulodi4.o \
|
||||
mulosi4.o \
|
||||
muloti4.o \
|
||||
mulsc3.o \
|
||||
mulsf3.o \
|
||||
mulvdi3.o \
|
||||
mulvsi3.o \
|
||||
mulxc3.o \
|
||||
negdf2.o \
|
||||
negdi2.o \
|
||||
negsf2.o \
|
||||
negvdi2.o \
|
||||
negvsi2.o \
|
||||
paritydi2.o \
|
||||
paritysi2.o \
|
||||
popcountdi2.o \
|
||||
popcountsi2.o \
|
||||
powidf2.o \
|
||||
powisf2.o \
|
||||
powixf2.o \
|
||||
subdf3.o \
|
||||
subsf3.o \
|
||||
subvdi3.o \
|
||||
subvsi3.o \
|
||||
truncdfhf2.o \
|
||||
truncdfsf2.o \
|
||||
truncsfhf2.o \
|
||||
ucmpdi2.o \
|
||||
udivdi3.o \
|
||||
udivmoddi4.o \
|
||||
udivmodsi4.o \
|
||||
udivsi3.o \
|
||||
umoddi3.o \
|
||||
umodsi3.o,
|
||||
$(call ADD_INTRINSIC,$(1),$(intrinsic)))
|
||||
|
||||
ifeq ($$(findstring ios,$(1)),)
|
||||
$(foreach intrinsic,absvti2.o \
|
||||
addtf3.o \
|
||||
addvti3.o \
|
||||
ashlti3.o \
|
||||
ashrti3.o \
|
||||
clzti2.o \
|
||||
cmpti2.o \
|
||||
ctzti2.o \
|
||||
divtf3.o \
|
||||
divti3.o \
|
||||
ffsti2.o \
|
||||
fixdfti.o \
|
||||
fixsfti.o \
|
||||
fixunsdfti.o \
|
||||
fixunssfti.o \
|
||||
fixunsxfti.o \
|
||||
fixxfti.o \
|
||||
floattidf.o \
|
||||
floattisf.o \
|
||||
floattixf.o \
|
||||
floatuntidf.o \
|
||||
floatuntisf.o \
|
||||
floatuntixf.o \
|
||||
lshrti3.o \
|
||||
modti3.o \
|
||||
multf3.o \
|
||||
multi3.o \
|
||||
mulvti3.o \
|
||||
negti2.o \
|
||||
negvti2.o \
|
||||
parityti2.o \
|
||||
popcountti2.o \
|
||||
powitf2.o \
|
||||
subtf3.o \
|
||||
subvti3.o \
|
||||
trampoline_setup.o \
|
||||
ucmpti2.o \
|
||||
udivmodti4.o \
|
||||
udivti3.o \
|
||||
umodti3.o,
|
||||
$(call ADD_INTRINSIC,$(1),$(intrinsic)))
|
||||
endif
|
||||
|
||||
ifeq ($$(findstring apple,$(1)),apple)
|
||||
$(foreach intrinsic,atomic_flag_clear.o \
|
||||
atomic_flag_clear_explicit.o \
|
||||
atomic_flag_test_and_set.o \
|
||||
atomic_flag_test_and_set_explicit.o \
|
||||
atomic_signal_fence.o \
|
||||
atomic_thread_fence.o,
|
||||
$(call ADD_INTRINSIC,$(1),$(intrinsic)))
|
||||
endif
|
||||
|
||||
ifeq ($$(findstring windows,$(1)),)
|
||||
$(call ADD_INTRINSIC,$(1),emutls.o)
|
||||
endif
|
||||
|
||||
ifeq ($$(findstring msvc,$(1)),)
|
||||
|
||||
ifeq ($$(findstring freebsd,$(1)),)
|
||||
$(call ADD_INTRINSIC,$(1),gcc_personality_v0.o)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($$(findstring aarch64,$(1)),aarch64)
|
||||
COMPRT_OBJS_$(1) += \
|
||||
comparetf2.o \
|
||||
$(foreach intrinsic,comparetf2.o \
|
||||
extenddftf2.o \
|
||||
extendsftf2.o \
|
||||
fixtfdi.o \
|
||||
|
|
@ -557,7 +572,8 @@ COMPRT_OBJS_$(1) += \
|
|||
floatunsitf.o \
|
||||
multc3.o \
|
||||
trunctfdf2.o \
|
||||
trunctfsf2.o
|
||||
trunctfsf2.o,
|
||||
$(call ADD_INTRINSIC,$(1),$(intrinsic)))
|
||||
endif
|
||||
|
||||
ifeq ($$(findstring msvc,$(1)),msvc)
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ TEST_TARGET_CRATES = $(filter-out core rustc_unicode alloc_system libc \
|
|||
panic_abort,$(TARGET_CRATES)) \
|
||||
collectionstest coretest
|
||||
TEST_DOC_CRATES = $(DOC_CRATES) arena flate fmt_macros getopts graphviz \
|
||||
log rand rbml serialize syntax term test
|
||||
log rand serialize syntax term test
|
||||
TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve \
|
||||
rustc_trans rustc_lint,\
|
||||
$(HOST_CRATES))
|
||||
|
|
@ -649,6 +649,7 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) = \
|
|||
--lldb-python $$(CFG_LLDB_PYTHON) \
|
||||
--gdb-version="$(CFG_GDB_VERSION)" \
|
||||
--lldb-version="$(CFG_LLDB_VERSION)" \
|
||||
--llvm-version="$$(LLVM_VERSION_$(3))" \
|
||||
--android-cross-path=$(CFG_ARM_LINUX_ANDROIDEABI_NDK) \
|
||||
--adb-path=$(CFG_ADB) \
|
||||
--adb-test-dir=$(CFG_ADB_TEST_DIR) \
|
||||
|
|
|
|||
|
|
@ -269,6 +269,7 @@ class RustBuild:
|
|||
sys.exit(ret)
|
||||
|
||||
def build_triple(self):
|
||||
default_encoding = sys.getdefaultencoding()
|
||||
config = self.get_toml('build')
|
||||
if config:
|
||||
return config
|
||||
|
|
@ -276,8 +277,8 @@ class RustBuild:
|
|||
if config:
|
||||
return config
|
||||
try:
|
||||
ostype = subprocess.check_output(['uname', '-s']).strip()
|
||||
cputype = subprocess.check_output(['uname', '-m']).strip()
|
||||
ostype = subprocess.check_output(['uname', '-s']).strip().decode(default_encoding)
|
||||
cputype = subprocess.check_output(['uname', '-m']).strip().decode(default_encoding)
|
||||
except (subprocess.CalledProcessError, WindowsError):
|
||||
if sys.platform == 'win32':
|
||||
return 'x86_64-pc-windows-msvc'
|
||||
|
|
@ -289,7 +290,8 @@ class RustBuild:
|
|||
# Darwin's `uname -s` lies and always returns i386. We have to use
|
||||
# sysctl instead.
|
||||
if ostype == 'Darwin' and cputype == 'i686':
|
||||
sysctl = subprocess.check_output(['sysctl', 'hw.optional.x86_64'])
|
||||
args = ['sysctl', 'hw.optional.x86_64']
|
||||
sysctl = subprocess.check_output(args).decode(default_encoding)
|
||||
if ': 1' in sysctl:
|
||||
cputype = 'x86_64'
|
||||
|
||||
|
|
|
|||
|
|
@ -148,6 +148,9 @@ pub fn compiletest(build: &Build,
|
|||
if let Some(ref dir) = build.lldb_python_dir {
|
||||
cmd.arg("--lldb-python-dir").arg(dir);
|
||||
}
|
||||
let llvm_config = build.llvm_config(target);
|
||||
let llvm_version = output(Command::new(&llvm_config).arg("--version"));
|
||||
cmd.arg("--llvm-version").arg(llvm_version);
|
||||
|
||||
cmd.args(&build.flags.args);
|
||||
|
||||
|
|
@ -158,7 +161,6 @@ pub fn compiletest(build: &Build,
|
|||
// Only pass correct values for these flags for the `run-make` suite as it
|
||||
// requires that a C++ compiler was configured which isn't always the case.
|
||||
if suite == "run-make" {
|
||||
let llvm_config = build.llvm_config(target);
|
||||
let llvm_components = output(Command::new(&llvm_config).arg("--components"));
|
||||
let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags"));
|
||||
cmd.arg("--cc").arg(build.cc(target))
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ pub fn clean(build: &Build) {
|
|||
|
||||
let out = build.out.join(host);
|
||||
|
||||
rm_rf(build, &out.join("compiler-rt"));
|
||||
rm_rf(build, &out.join("doc"));
|
||||
|
||||
for stage in 0..4 {
|
||||
|
|
|
|||
|
|
@ -16,12 +16,14 @@
|
|||
//! compiler. This module is also responsible for assembling the sysroot as it
|
||||
//! goes along from the output of the previous stage.
|
||||
|
||||
use std::cmp;
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::fs::{self, File};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
use build_helper::output;
|
||||
use filetime::FileTime;
|
||||
|
||||
use util::{exe, staticlib, libdir, mtime, is_dylib, copy};
|
||||
use {Build, Compiler, Mode};
|
||||
|
|
@ -35,13 +37,23 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
|||
println!("Building stage{} std artifacts ({} -> {})", compiler.stage,
|
||||
compiler.host, target);
|
||||
|
||||
// Move compiler-rt into place as it'll be required by the compiler when
|
||||
// building the standard library to link the dylib of libstd
|
||||
let libdir = build.sysroot_libdir(compiler, target);
|
||||
let _ = fs::remove_dir_all(&libdir);
|
||||
t!(fs::create_dir_all(&libdir));
|
||||
copy(&build.compiler_rt_built.borrow()[target],
|
||||
&libdir.join(staticlib("compiler-rt", target)));
|
||||
// FIXME(stage0) remove this `if` after the next snapshot
|
||||
// The stage0 compiler still passes the `-lcompiler-rt` flag to the linker but now `bootstrap`
|
||||
// never builds a `libcopmiler-rt.a`! We'll fill the hole by simply copying stage0's
|
||||
// `libcompiler-rt.a` to where the stage1's one is expected (though we could as well just use
|
||||
// an empty `.a` archive). Note that the symbols of that stage0 `libcompiler-rt.a` won't make
|
||||
// it to the final binary because now `libcore.rlib` also contains the symbols that
|
||||
// `libcompiler-rt.a` provides. Since that rlib appears first in the linker arguments, its
|
||||
// symbols are used instead of `libcompiler-rt.a`'s.
|
||||
if compiler.stage == 0 {
|
||||
let rtlib = &staticlib("compiler-rt", target);
|
||||
let src = build.rustc.parent().unwrap().parent().unwrap().join("lib").join("rustlib")
|
||||
.join(target).join("lib").join(rtlib);
|
||||
copy(&src, &libdir.join(rtlib));
|
||||
}
|
||||
|
||||
// Some platforms have startup objects that may be required to produce the
|
||||
// libstd dynamic library, for example.
|
||||
|
|
@ -59,13 +71,14 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
|||
cargo.env("JEMALLOC_OVERRIDE", jemalloc);
|
||||
}
|
||||
}
|
||||
if let Some(ref p) = build.config.musl_root {
|
||||
if target.contains("musl") {
|
||||
if target.contains("musl") {
|
||||
if let Some(p) = build.musl_root(target) {
|
||||
cargo.env("MUSL_ROOT", p);
|
||||
}
|
||||
}
|
||||
|
||||
build.run(&mut cargo);
|
||||
update_mtime(&libstd_stamp(build, compiler, target));
|
||||
std_link(build, target, compiler, compiler.host);
|
||||
}
|
||||
|
||||
|
|
@ -83,26 +96,24 @@ pub fn std_link(build: &Build,
|
|||
|
||||
// If we're linking one compiler host's output into another, then we weren't
|
||||
// called from the `std` method above. In that case we clean out what's
|
||||
// already there and then also link compiler-rt into place.
|
||||
// already there.
|
||||
if host != compiler.host {
|
||||
let _ = fs::remove_dir_all(&libdir);
|
||||
t!(fs::create_dir_all(&libdir));
|
||||
copy(&build.compiler_rt_built.borrow()[target],
|
||||
&libdir.join(staticlib("compiler-rt", target)));
|
||||
}
|
||||
add_to_sysroot(&out_dir, &libdir);
|
||||
|
||||
if target.contains("musl") && !target.contains("mips") {
|
||||
copy_third_party_objects(build, target, &libdir);
|
||||
copy_musl_third_party_objects(build, &libdir);
|
||||
}
|
||||
}
|
||||
|
||||
/// Copies the crt(1,i,n).o startup objects
|
||||
///
|
||||
/// Only required for musl targets that statically link to libc
|
||||
fn copy_third_party_objects(build: &Build, target: &str, into: &Path) {
|
||||
fn copy_musl_third_party_objects(build: &Build, into: &Path) {
|
||||
for &obj in &["crt1.o", "crti.o", "crtn.o"] {
|
||||
copy(&compiler_file(build.cc(target), obj), &into.join(obj));
|
||||
copy(&build.config.musl_root.as_ref().unwrap().join("lib").join(obj), &into.join(obj));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -117,14 +128,16 @@ fn build_startup_objects(build: &Build, target: &str, into: &Path) {
|
|||
return
|
||||
}
|
||||
let compiler = Compiler::new(0, &build.config.build);
|
||||
let compiler = build.compiler_path(&compiler);
|
||||
let compiler_path = build.compiler_path(&compiler);
|
||||
|
||||
for file in t!(fs::read_dir(build.src.join("src/rtstartup"))) {
|
||||
let file = t!(file);
|
||||
build.run(Command::new(&compiler)
|
||||
.arg("--emit=obj")
|
||||
.arg("--out-dir").arg(into)
|
||||
.arg(file.path()));
|
||||
let mut cmd = Command::new(&compiler_path);
|
||||
build.add_bootstrap_key(&compiler, &mut cmd);
|
||||
build.run(cmd.arg("--target").arg(target)
|
||||
.arg("--emit=obj")
|
||||
.arg("--out-dir").arg(into)
|
||||
.arg(file.path()));
|
||||
}
|
||||
|
||||
for obj in ["crt2.o", "dllcrt2.o"].iter() {
|
||||
|
|
@ -141,11 +154,12 @@ pub fn test<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
|||
println!("Building stage{} test artifacts ({} -> {})", compiler.stage,
|
||||
compiler.host, target);
|
||||
let out_dir = build.cargo_out(compiler, Mode::Libtest, target);
|
||||
build.clear_if_dirty(&out_dir, &libstd_shim(build, compiler, target));
|
||||
build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target));
|
||||
let mut cargo = build.cargo(compiler, Mode::Libtest, target, "build");
|
||||
cargo.arg("--manifest-path")
|
||||
.arg(build.src.join("src/rustc/test_shim/Cargo.toml"));
|
||||
build.run(&mut cargo);
|
||||
update_mtime(&libtest_stamp(build, compiler, target));
|
||||
test_link(build, target, compiler, compiler.host);
|
||||
}
|
||||
|
||||
|
|
@ -173,7 +187,7 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
|||
compiler.stage, compiler.host, target);
|
||||
|
||||
let out_dir = build.cargo_out(compiler, Mode::Librustc, target);
|
||||
build.clear_if_dirty(&out_dir, &libtest_shim(build, compiler, target));
|
||||
build.clear_if_dirty(&out_dir, &libtest_stamp(build, compiler, target));
|
||||
|
||||
let mut cargo = build.cargo(compiler, Mode::Librustc, target, "build");
|
||||
cargo.arg("--features").arg(build.rustc_features())
|
||||
|
|
@ -203,6 +217,10 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
|||
cargo.env("LLVM_RUSTLLVM", "1");
|
||||
}
|
||||
cargo.env("LLVM_CONFIG", build.llvm_config(target));
|
||||
let target_config = build.config.target_config.get(target);
|
||||
if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
|
||||
cargo.env("CFG_LLVM_ROOT", s);
|
||||
}
|
||||
if build.config.llvm_static_stdcpp {
|
||||
cargo.env("LLVM_STATIC_STDCPP",
|
||||
compiler_file(build.cxx(target), "libstdc++.a"));
|
||||
|
|
@ -234,14 +252,14 @@ pub fn rustc_link(build: &Build,
|
|||
|
||||
/// Cargo's output path for the standard library in a given stage, compiled
|
||||
/// by a particular compiler for the specified target.
|
||||
fn libstd_shim(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
|
||||
build.cargo_out(compiler, Mode::Libstd, target).join("libstd_shim.rlib")
|
||||
fn libstd_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
|
||||
build.cargo_out(compiler, Mode::Libstd, target).join(".libstd.stamp")
|
||||
}
|
||||
|
||||
/// Cargo's output path for libtest in a given stage, compiled by a particular
|
||||
/// compiler for the specified target.
|
||||
fn libtest_shim(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
|
||||
build.cargo_out(compiler, Mode::Libtest, target).join("libtest_shim.rlib")
|
||||
fn libtest_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
|
||||
build.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp")
|
||||
}
|
||||
|
||||
fn compiler_file(compiler: &Path, file: &str) -> PathBuf {
|
||||
|
|
@ -354,10 +372,35 @@ pub fn tool(build: &Build, stage: u32, host: &str, tool: &str) {
|
|||
// Maybe when libstd is compiled it should clear out the rustc of the
|
||||
// corresponding stage?
|
||||
// let out_dir = build.cargo_out(stage, &host, Mode::Librustc, target);
|
||||
// build.clear_if_dirty(&out_dir, &libstd_shim(build, stage, &host, target));
|
||||
// build.clear_if_dirty(&out_dir, &libstd_stamp(build, stage, &host, target));
|
||||
|
||||
let mut cargo = build.cargo(&compiler, Mode::Tool, host, "build");
|
||||
cargo.arg("--manifest-path")
|
||||
.arg(build.src.join(format!("src/tools/{}/Cargo.toml", tool)));
|
||||
build.run(&mut cargo);
|
||||
}
|
||||
|
||||
/// Updates the mtime of a stamp file if necessary, only changing it if it's
|
||||
/// older than some other file in the same directory.
|
||||
///
|
||||
/// We don't know what file Cargo is going to output (because there's a hash in
|
||||
/// the file name) but we know where it's going to put it. We use this helper to
|
||||
/// detect changes to that output file by looking at the modification time for
|
||||
/// all files in a directory and updating the stamp if any are newer.
|
||||
fn update_mtime(path: &Path) {
|
||||
let mut max = None;
|
||||
if let Ok(entries) = path.parent().unwrap().read_dir() {
|
||||
for entry in entries.map(|e| t!(e)) {
|
||||
if t!(entry.file_type()).is_file() {
|
||||
let meta = t!(entry.metadata());
|
||||
let time = FileTime::from_last_modification_time(&meta);
|
||||
max = cmp::max(max, Some(time));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !max.is_none() && max <= Some(mtime(path)) {
|
||||
return
|
||||
}
|
||||
t!(File::create(path));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,9 +76,11 @@ pub struct Config {
|
|||
|
||||
// misc
|
||||
pub channel: String,
|
||||
// Fallback musl-root for all targets
|
||||
pub musl_root: Option<PathBuf>,
|
||||
pub prefix: Option<String>,
|
||||
pub codegen_tests: bool,
|
||||
pub nodejs: Option<PathBuf>,
|
||||
}
|
||||
|
||||
/// Per-target configuration stored in the global configuration structure.
|
||||
|
|
@ -89,6 +91,7 @@ pub struct Target {
|
|||
pub cc: Option<PathBuf>,
|
||||
pub cxx: Option<PathBuf>,
|
||||
pub ndk: Option<PathBuf>,
|
||||
pub musl_root: Option<PathBuf>,
|
||||
}
|
||||
|
||||
/// Structure of the `config.toml` file that configuration is read from.
|
||||
|
|
@ -144,6 +147,7 @@ struct Rust {
|
|||
rpath: Option<bool>,
|
||||
optimize_tests: Option<bool>,
|
||||
debuginfo_tests: Option<bool>,
|
||||
codegen_tests: Option<bool>,
|
||||
}
|
||||
|
||||
/// TOML representation of how each build target is configured.
|
||||
|
|
@ -232,6 +236,7 @@ impl Config {
|
|||
set(&mut config.rust_optimize, rust.optimize);
|
||||
set(&mut config.rust_optimize_tests, rust.optimize_tests);
|
||||
set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests);
|
||||
set(&mut config.codegen_tests, rust.codegen_tests);
|
||||
set(&mut config.rust_rpath, rust.rpath);
|
||||
set(&mut config.debug_jemalloc, rust.debug_jemalloc);
|
||||
set(&mut config.use_jemalloc, rust.use_jemalloc);
|
||||
|
|
@ -391,6 +396,9 @@ impl Config {
|
|||
self.rustc = Some(PathBuf::from(value).join("bin/rustc"));
|
||||
self.cargo = Some(PathBuf::from(value).join("bin/cargo"));
|
||||
}
|
||||
"CFG_NODEJS" if value.len() > 0 => {
|
||||
self.nodejs = Some(PathBuf::from(value));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
# Sample TOML configuration file for building Rust.
|
||||
#
|
||||
# To configure rustbuild, copy this file to the directory from which you will be
|
||||
# running the build, and name it config.toml.
|
||||
#
|
||||
# All options are commented out by default in this file, and they're commented
|
||||
# out with their default values. The build system by default looks for
|
||||
# `config.toml` in the current directory of a build for build configuration, but
|
||||
|
|
@ -115,10 +118,6 @@
|
|||
# nightly features
|
||||
#channel = "dev"
|
||||
|
||||
# The root location of the MUSL installation directory. The library directory
|
||||
# will also need to contain libunwind.a for an unwinding implementation.
|
||||
#musl-root = "..."
|
||||
|
||||
# By default the `rustc` executable is built with `-Wl,-rpath` flags on Unix
|
||||
# platforms to ensure that the compiler is usable by default from the build
|
||||
# directory (as it links to a number of dynamic libraries). This may not be
|
||||
|
|
@ -130,6 +129,10 @@
|
|||
#optimize-tests = true
|
||||
#debuginfo-tests = true
|
||||
|
||||
# Flag indicating whether codegen tests will be run or not. If you get an error
|
||||
# saying that the FileCheck executable is missing, you may want to disable this.
|
||||
#codegen-tests = true
|
||||
|
||||
# =============================================================================
|
||||
# Options for specific targets
|
||||
#
|
||||
|
|
@ -160,3 +163,9 @@
|
|||
# the NDK for the target lives. This is used to find the C compiler to link and
|
||||
# build native code.
|
||||
#android-ndk = "/path/to/ndk"
|
||||
|
||||
# The root location of the MUSL installation directory. The library directory
|
||||
# will also need to contain libunwind.a for an unwinding implementation. Note
|
||||
# that this option only makes sense for MUSL targets that produce statically
|
||||
# linked binaries
|
||||
#musl-root = "..."
|
||||
|
|
|
|||
|
|
@ -388,6 +388,9 @@ pub fn rust_src(build: &Build) {
|
|||
// Rename directory, so that root folder of tarball has the correct name
|
||||
t!(fs::rename(&dst_src, &plain_dst_src));
|
||||
|
||||
// Create the version file
|
||||
write_file(&plain_dst_src.join("version"), build.version.as_bytes());
|
||||
|
||||
// Create plain source tarball
|
||||
let mut cmd = Command::new("tar");
|
||||
cmd.arg("-czf").arg(sanitize_sh(&distdir(build).join(&format!("{}.tar.gz", plain_name))))
|
||||
|
|
@ -431,3 +434,8 @@ fn sanitize_sh(path: &Path) -> String {
|
|||
Some(format!("/{}/{}", drive, &s[drive.len_utf8() + 2..]))
|
||||
}
|
||||
}
|
||||
|
||||
fn write_file(path: &Path, data: &[u8]) {
|
||||
let mut vf = t!(fs::File::create(path));
|
||||
t!(vf.write_all(data));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ extern crate rustc_serialize;
|
|||
extern crate toml;
|
||||
extern crate regex;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::fs::{self, File};
|
||||
|
|
@ -46,7 +45,7 @@ use util::{exe, mtime, libdir, add_lib_path};
|
|||
/// * The error itself
|
||||
///
|
||||
/// This is currently used judiciously throughout the build system rather than
|
||||
/// using a `Result` with `try!`, but this may change on day...
|
||||
/// using a `Result` with `try!`, but this may change one day...
|
||||
macro_rules! t {
|
||||
($e:expr) => (match $e {
|
||||
Ok(e) => e,
|
||||
|
|
@ -131,7 +130,6 @@ pub struct Build {
|
|||
// Runtime state filled in later on
|
||||
cc: HashMap<String, (gcc::Tool, Option<PathBuf>)>,
|
||||
cxx: HashMap<String, gcc::Tool>,
|
||||
compiler_rt_built: RefCell<HashMap<String, PathBuf>>,
|
||||
}
|
||||
|
||||
/// The various "modes" of invoking Cargo.
|
||||
|
|
@ -198,7 +196,6 @@ impl Build {
|
|||
package_vers: String::new(),
|
||||
cc: HashMap::new(),
|
||||
cxx: HashMap::new(),
|
||||
compiler_rt_built: RefCell::new(HashMap::new()),
|
||||
gdb_version: None,
|
||||
lldb_version: None,
|
||||
lldb_python_dir: None,
|
||||
|
|
@ -252,9 +249,6 @@ impl Build {
|
|||
Llvm { _dummy } => {
|
||||
native::llvm(self, target.target);
|
||||
}
|
||||
CompilerRt { _dummy } => {
|
||||
native::compiler_rt(self, target.target);
|
||||
}
|
||||
TestHelpers { _dummy } => {
|
||||
native::test_helpers(self, target.target);
|
||||
}
|
||||
|
|
@ -585,6 +579,8 @@ impl Build {
|
|||
if mtime(&stamp) < mtime(input) {
|
||||
self.verbose(&format!("Dirty - {}", dir.display()));
|
||||
let _ = fs::remove_dir_all(dir);
|
||||
} else if stamp.exists() {
|
||||
return
|
||||
}
|
||||
t!(fs::create_dir_all(dir));
|
||||
t!(File::create(stamp));
|
||||
|
|
@ -839,11 +835,6 @@ impl Build {
|
|||
}
|
||||
}
|
||||
|
||||
/// Root output directory for compiler-rt compiled for `target`
|
||||
fn compiler_rt_out(&self, target: &str) -> PathBuf {
|
||||
self.out.join(target).join("compiler-rt")
|
||||
}
|
||||
|
||||
/// Root output directory for rust_test_helpers library compiled for
|
||||
/// `target`
|
||||
fn test_helpers_out(&self, target: &str) -> PathBuf {
|
||||
|
|
@ -977,6 +968,13 @@ impl Build {
|
|||
}
|
||||
return base
|
||||
}
|
||||
|
||||
/// Returns the "musl root" for this `target`, if defined
|
||||
fn musl_root(&self, target: &str) -> Option<&Path> {
|
||||
self.config.target_config[target].musl_root.as_ref()
|
||||
.or(self.config.musl_root.as_ref())
|
||||
.map(|p| &**p)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Compiler<'a> {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ use cmake;
|
|||
use gcc;
|
||||
|
||||
use Build;
|
||||
use util::{staticlib, up_to_date};
|
||||
use util::up_to_date;
|
||||
|
||||
/// Compile LLVM for `target`.
|
||||
pub fn llvm(build: &Build, target: &str) {
|
||||
|
|
@ -131,401 +131,6 @@ fn check_llvm_version(build: &Build, llvm_config: &Path) {
|
|||
panic!("\n\nbad LLVM version: {}, need >=3.5\n\n", version)
|
||||
}
|
||||
|
||||
/// Compiles the `compiler-rt` library, or at least the builtins part of it.
|
||||
///
|
||||
/// Note that while compiler-rt has a build system associated with it, we
|
||||
/// specifically don't use it here. The compiler-rt build system, written in
|
||||
/// CMake, is actually *very* difficult to work with in terms of getting it to
|
||||
/// compile on all the relevant platforms we want it to compile on. In the end
|
||||
/// it became so much pain to work with local patches, work around the oddities
|
||||
/// of the build system, etc, that we're just building everything by hand now.
|
||||
///
|
||||
/// In general compiler-rt is just a bunch of intrinsics that are in practice
|
||||
/// *very* stable. We just need to make sure that all the relevant functions and
|
||||
/// such are compiled somewhere and placed in an object file somewhere.
|
||||
/// Eventually, these should all be written in Rust!
|
||||
///
|
||||
/// So below you'll find a listing of every single file in the compiler-rt repo
|
||||
/// that we're compiling. We just reach in and compile with the `gcc` crate
|
||||
/// which should have all the relevant flags and such already configured.
|
||||
///
|
||||
/// The risk here is that if we update compiler-rt we may need to compile some
|
||||
/// new intrinsics, but to be honest we surely don't use all of the intrinsics
|
||||
/// listed below today so the likelihood of us actually needing a new intrinsic
|
||||
/// is quite low. The failure case is also just that someone reports a link
|
||||
/// error (if any) and then we just add it to the list. Overall, that cost is
|
||||
/// far far less than working with compiler-rt's build system over time.
|
||||
pub fn compiler_rt(build: &Build, target: &str) {
|
||||
let build_dir = build.compiler_rt_out(target);
|
||||
let output = build_dir.join(staticlib("compiler-rt", target));
|
||||
build.compiler_rt_built.borrow_mut().insert(target.to_string(),
|
||||
output.clone());
|
||||
t!(fs::create_dir_all(&build_dir));
|
||||
|
||||
let mut cfg = gcc::Config::new();
|
||||
cfg.cargo_metadata(false)
|
||||
.out_dir(&build_dir)
|
||||
.target(target)
|
||||
.host(&build.config.build)
|
||||
.opt_level(2)
|
||||
.debug(false);
|
||||
|
||||
if target.contains("msvc") {
|
||||
// Don't pull in extra libraries on MSVC
|
||||
cfg.flag("/Zl");
|
||||
|
||||
// Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP
|
||||
cfg.define("__func__", Some("__FUNCTION__"));
|
||||
} else {
|
||||
// Turn off various features of gcc and such, mostly copying
|
||||
// compiler-rt's build system already
|
||||
cfg.flag("-fno-builtin");
|
||||
cfg.flag("-fvisibility=hidden");
|
||||
cfg.flag("-fomit-frame-pointer");
|
||||
cfg.flag("-ffreestanding");
|
||||
}
|
||||
|
||||
let mut sources = vec![
|
||||
"absvdi2.c",
|
||||
"absvsi2.c",
|
||||
"adddf3.c",
|
||||
"addsf3.c",
|
||||
"addvdi3.c",
|
||||
"addvsi3.c",
|
||||
"apple_versioning.c",
|
||||
"ashldi3.c",
|
||||
"ashrdi3.c",
|
||||
"clear_cache.c",
|
||||
"clzdi2.c",
|
||||
"clzsi2.c",
|
||||
"cmpdi2.c",
|
||||
"comparedf2.c",
|
||||
"comparesf2.c",
|
||||
"ctzdi2.c",
|
||||
"ctzsi2.c",
|
||||
"divdc3.c",
|
||||
"divdf3.c",
|
||||
"divdi3.c",
|
||||
"divmoddi4.c",
|
||||
"divmodsi4.c",
|
||||
"divsc3.c",
|
||||
"divsf3.c",
|
||||
"divsi3.c",
|
||||
"divxc3.c",
|
||||
"extendsfdf2.c",
|
||||
"extendhfsf2.c",
|
||||
"ffsdi2.c",
|
||||
"fixdfdi.c",
|
||||
"fixdfsi.c",
|
||||
"fixsfdi.c",
|
||||
"fixsfsi.c",
|
||||
"fixunsdfdi.c",
|
||||
"fixunsdfsi.c",
|
||||
"fixunssfdi.c",
|
||||
"fixunssfsi.c",
|
||||
"fixunsxfdi.c",
|
||||
"fixunsxfsi.c",
|
||||
"fixxfdi.c",
|
||||
"floatdidf.c",
|
||||
"floatdisf.c",
|
||||
"floatdixf.c",
|
||||
"floatsidf.c",
|
||||
"floatsisf.c",
|
||||
"floatundidf.c",
|
||||
"floatundisf.c",
|
||||
"floatundixf.c",
|
||||
"floatunsidf.c",
|
||||
"floatunsisf.c",
|
||||
"int_util.c",
|
||||
"lshrdi3.c",
|
||||
"moddi3.c",
|
||||
"modsi3.c",
|
||||
"muldc3.c",
|
||||
"muldf3.c",
|
||||
"muldi3.c",
|
||||
"mulodi4.c",
|
||||
"mulosi4.c",
|
||||
"muloti4.c",
|
||||
"mulsc3.c",
|
||||
"mulsf3.c",
|
||||
"mulvdi3.c",
|
||||
"mulvsi3.c",
|
||||
"mulxc3.c",
|
||||
"negdf2.c",
|
||||
"negdi2.c",
|
||||
"negsf2.c",
|
||||
"negvdi2.c",
|
||||
"negvsi2.c",
|
||||
"paritydi2.c",
|
||||
"paritysi2.c",
|
||||
"popcountdi2.c",
|
||||
"popcountsi2.c",
|
||||
"powidf2.c",
|
||||
"powisf2.c",
|
||||
"powixf2.c",
|
||||
"subdf3.c",
|
||||
"subsf3.c",
|
||||
"subvdi3.c",
|
||||
"subvsi3.c",
|
||||
"truncdfhf2.c",
|
||||
"truncdfsf2.c",
|
||||
"truncsfhf2.c",
|
||||
"ucmpdi2.c",
|
||||
"udivdi3.c",
|
||||
"udivmoddi4.c",
|
||||
"udivmodsi4.c",
|
||||
"udivsi3.c",
|
||||
"umoddi3.c",
|
||||
"umodsi3.c",
|
||||
];
|
||||
|
||||
if !target.contains("ios") {
|
||||
sources.extend(vec![
|
||||
"absvti2.c",
|
||||
"addtf3.c",
|
||||
"addvti3.c",
|
||||
"ashlti3.c",
|
||||
"ashrti3.c",
|
||||
"clzti2.c",
|
||||
"cmpti2.c",
|
||||
"ctzti2.c",
|
||||
"divtf3.c",
|
||||
"divti3.c",
|
||||
"ffsti2.c",
|
||||
"fixdfti.c",
|
||||
"fixsfti.c",
|
||||
"fixunsdfti.c",
|
||||
"fixunssfti.c",
|
||||
"fixunsxfti.c",
|
||||
"fixxfti.c",
|
||||
"floattidf.c",
|
||||
"floattisf.c",
|
||||
"floattixf.c",
|
||||
"floatuntidf.c",
|
||||
"floatuntisf.c",
|
||||
"floatuntixf.c",
|
||||
"lshrti3.c",
|
||||
"modti3.c",
|
||||
"multf3.c",
|
||||
"multi3.c",
|
||||
"mulvti3.c",
|
||||
"negti2.c",
|
||||
"negvti2.c",
|
||||
"parityti2.c",
|
||||
"popcountti2.c",
|
||||
"powitf2.c",
|
||||
"subtf3.c",
|
||||
"subvti3.c",
|
||||
"trampoline_setup.c",
|
||||
"ucmpti2.c",
|
||||
"udivmodti4.c",
|
||||
"udivti3.c",
|
||||
"umodti3.c",
|
||||
]);
|
||||
}
|
||||
|
||||
if target.contains("apple") {
|
||||
sources.extend(vec![
|
||||
"atomic_flag_clear.c",
|
||||
"atomic_flag_clear_explicit.c",
|
||||
"atomic_flag_test_and_set.c",
|
||||
"atomic_flag_test_and_set_explicit.c",
|
||||
"atomic_signal_fence.c",
|
||||
"atomic_thread_fence.c",
|
||||
]);
|
||||
}
|
||||
|
||||
if !target.contains("windows") {
|
||||
sources.push("emutls.c");
|
||||
}
|
||||
|
||||
if target.contains("msvc") {
|
||||
if target.contains("x86_64") {
|
||||
sources.extend(vec![
|
||||
"x86_64/floatdidf.c",
|
||||
"x86_64/floatdisf.c",
|
||||
"x86_64/floatdixf.c",
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
if !target.contains("freebsd") {
|
||||
sources.push("gcc_personality_v0.c");
|
||||
}
|
||||
|
||||
if target.contains("x86_64") {
|
||||
sources.extend(vec![
|
||||
"x86_64/chkstk.S",
|
||||
"x86_64/chkstk2.S",
|
||||
"x86_64/floatdidf.c",
|
||||
"x86_64/floatdisf.c",
|
||||
"x86_64/floatdixf.c",
|
||||
"x86_64/floatundidf.S",
|
||||
"x86_64/floatundisf.S",
|
||||
"x86_64/floatundixf.S",
|
||||
]);
|
||||
}
|
||||
|
||||
if target.contains("i386") ||
|
||||
target.contains("i586") ||
|
||||
target.contains("i686") {
|
||||
sources.extend(vec![
|
||||
"i386/ashldi3.S",
|
||||
"i386/ashrdi3.S",
|
||||
"i386/chkstk.S",
|
||||
"i386/chkstk2.S",
|
||||
"i386/divdi3.S",
|
||||
"i386/floatdidf.S",
|
||||
"i386/floatdisf.S",
|
||||
"i386/floatdixf.S",
|
||||
"i386/floatundidf.S",
|
||||
"i386/floatundisf.S",
|
||||
"i386/floatundixf.S",
|
||||
"i386/lshrdi3.S",
|
||||
"i386/moddi3.S",
|
||||
"i386/muldi3.S",
|
||||
"i386/udivdi3.S",
|
||||
"i386/umoddi3.S",
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if target.contains("arm") && !target.contains("ios") {
|
||||
sources.extend(vec![
|
||||
"arm/aeabi_cdcmp.S",
|
||||
"arm/aeabi_cdcmpeq_check_nan.c",
|
||||
"arm/aeabi_cfcmp.S",
|
||||
"arm/aeabi_cfcmpeq_check_nan.c",
|
||||
"arm/aeabi_dcmp.S",
|
||||
"arm/aeabi_div0.c",
|
||||
"arm/aeabi_drsub.c",
|
||||
"arm/aeabi_fcmp.S",
|
||||
"arm/aeabi_frsub.c",
|
||||
"arm/aeabi_idivmod.S",
|
||||
"arm/aeabi_ldivmod.S",
|
||||
"arm/aeabi_memcmp.S",
|
||||
"arm/aeabi_memcpy.S",
|
||||
"arm/aeabi_memmove.S",
|
||||
"arm/aeabi_memset.S",
|
||||
"arm/aeabi_uidivmod.S",
|
||||
"arm/aeabi_uldivmod.S",
|
||||
"arm/bswapdi2.S",
|
||||
"arm/bswapsi2.S",
|
||||
"arm/clzdi2.S",
|
||||
"arm/clzsi2.S",
|
||||
"arm/comparesf2.S",
|
||||
"arm/divmodsi4.S",
|
||||
"arm/divsi3.S",
|
||||
"arm/modsi3.S",
|
||||
"arm/switch16.S",
|
||||
"arm/switch32.S",
|
||||
"arm/switch8.S",
|
||||
"arm/switchu8.S",
|
||||
"arm/sync_synchronize.S",
|
||||
"arm/udivmodsi4.S",
|
||||
"arm/udivsi3.S",
|
||||
"arm/umodsi3.S",
|
||||
]);
|
||||
}
|
||||
|
||||
if target.contains("armv7") {
|
||||
sources.extend(vec![
|
||||
"arm/sync_fetch_and_add_4.S",
|
||||
"arm/sync_fetch_and_add_8.S",
|
||||
"arm/sync_fetch_and_and_4.S",
|
||||
"arm/sync_fetch_and_and_8.S",
|
||||
"arm/sync_fetch_and_max_4.S",
|
||||
"arm/sync_fetch_and_max_8.S",
|
||||
"arm/sync_fetch_and_min_4.S",
|
||||
"arm/sync_fetch_and_min_8.S",
|
||||
"arm/sync_fetch_and_nand_4.S",
|
||||
"arm/sync_fetch_and_nand_8.S",
|
||||
"arm/sync_fetch_and_or_4.S",
|
||||
"arm/sync_fetch_and_or_8.S",
|
||||
"arm/sync_fetch_and_sub_4.S",
|
||||
"arm/sync_fetch_and_sub_8.S",
|
||||
"arm/sync_fetch_and_umax_4.S",
|
||||
"arm/sync_fetch_and_umax_8.S",
|
||||
"arm/sync_fetch_and_umin_4.S",
|
||||
"arm/sync_fetch_and_umin_8.S",
|
||||
"arm/sync_fetch_and_xor_4.S",
|
||||
"arm/sync_fetch_and_xor_8.S",
|
||||
]);
|
||||
}
|
||||
|
||||
if target.contains("eabihf") {
|
||||
sources.extend(vec![
|
||||
"arm/adddf3vfp.S",
|
||||
"arm/addsf3vfp.S",
|
||||
"arm/divdf3vfp.S",
|
||||
"arm/divsf3vfp.S",
|
||||
"arm/eqdf2vfp.S",
|
||||
"arm/eqsf2vfp.S",
|
||||
"arm/extendsfdf2vfp.S",
|
||||
"arm/fixdfsivfp.S",
|
||||
"arm/fixsfsivfp.S",
|
||||
"arm/fixunsdfsivfp.S",
|
||||
"arm/fixunssfsivfp.S",
|
||||
"arm/floatsidfvfp.S",
|
||||
"arm/floatsisfvfp.S",
|
||||
"arm/floatunssidfvfp.S",
|
||||
"arm/floatunssisfvfp.S",
|
||||
"arm/gedf2vfp.S",
|
||||
"arm/gesf2vfp.S",
|
||||
"arm/gtdf2vfp.S",
|
||||
"arm/gtsf2vfp.S",
|
||||
"arm/ledf2vfp.S",
|
||||
"arm/lesf2vfp.S",
|
||||
"arm/ltdf2vfp.S",
|
||||
"arm/ltsf2vfp.S",
|
||||
"arm/muldf3vfp.S",
|
||||
"arm/mulsf3vfp.S",
|
||||
"arm/negdf2vfp.S",
|
||||
"arm/negsf2vfp.S",
|
||||
"arm/nedf2vfp.S",
|
||||
"arm/nesf2vfp.S",
|
||||
"arm/restore_vfp_d8_d15_regs.S",
|
||||
"arm/save_vfp_d8_d15_regs.S",
|
||||
"arm/subdf3vfp.S",
|
||||
"arm/subsf3vfp.S",
|
||||
"arm/truncdfsf2vfp.S",
|
||||
"arm/unorddf2vfp.S",
|
||||
"arm/unordsf2vfp.S",
|
||||
]);
|
||||
}
|
||||
|
||||
if target.contains("aarch64") {
|
||||
sources.extend(vec![
|
||||
"comparetf2.c",
|
||||
"extenddftf2.c",
|
||||
"extendsftf2.c",
|
||||
"fixtfdi.c",
|
||||
"fixtfsi.c",
|
||||
"fixtfti.c",
|
||||
"fixunstfdi.c",
|
||||
"fixunstfsi.c",
|
||||
"fixunstfti.c",
|
||||
"floatditf.c",
|
||||
"floatsitf.c",
|
||||
"floatunditf.c",
|
||||
"floatunsitf.c",
|
||||
"multc3.c",
|
||||
"trunctfdf2.c",
|
||||
"trunctfsf2.c",
|
||||
]);
|
||||
}
|
||||
|
||||
let mut out_of_date = false;
|
||||
for src in sources {
|
||||
let src = build.src.join("src/compiler-rt/lib/builtins").join(src);
|
||||
out_of_date = out_of_date || !up_to_date(&src, &output);
|
||||
cfg.file(src);
|
||||
}
|
||||
if !out_of_date {
|
||||
return
|
||||
}
|
||||
cfg.compile("libcompiler-rt.a");
|
||||
}
|
||||
|
||||
/// Compiles the `rust_test_helpers.c` library which we used in various
|
||||
/// `run-pass` test suites for ABI testing.
|
||||
pub fn test_helpers(build: &Build, target: &str) {
|
||||
|
|
|
|||
|
|
@ -75,6 +75,12 @@ pub fn check(build: &mut Build) {
|
|||
|
||||
need_cmd("python".as_ref());
|
||||
|
||||
// If a manual nodejs was added to the config,
|
||||
// of if a nodejs install is detected through config, use it.
|
||||
if let Some(ref s) = build.config.nodejs {
|
||||
need_cmd(s.as_ref());
|
||||
}
|
||||
|
||||
// We're gonna build some custom C code here and there, host triples
|
||||
// also build some C++ shims for LLVM so we need a C++ compiler.
|
||||
for target in build.config.target.iter() {
|
||||
|
|
@ -111,8 +117,8 @@ pub fn check(build: &mut Build) {
|
|||
|
||||
// Make sure musl-root is valid if specified
|
||||
if target.contains("musl") && !target.contains("mips") {
|
||||
match build.config.musl_root {
|
||||
Some(ref root) => {
|
||||
match build.musl_root(target) {
|
||||
Some(root) => {
|
||||
if fs::metadata(root.join("lib/libc.a")).is_err() {
|
||||
panic!("couldn't find libc.a in musl dir: {}",
|
||||
root.join("lib").display());
|
||||
|
|
@ -123,8 +129,9 @@ pub fn check(build: &mut Build) {
|
|||
}
|
||||
}
|
||||
None => {
|
||||
panic!("when targeting MUSL the build.musl-root option \
|
||||
must be specified in config.toml")
|
||||
panic!("when targeting MUSL either the build.musl-root \
|
||||
option or the target.$TARGET.musl-root one must \
|
||||
be specified in config.toml")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,6 @@ macro_rules! targets {
|
|||
// There aren't really any parameters to this, but empty structs
|
||||
// with braces are unstable so we just pick something that works.
|
||||
(llvm, Llvm { _dummy: () }),
|
||||
(compiler_rt, CompilerRt { _dummy: () }),
|
||||
(test_helpers, TestHelpers { _dummy: () }),
|
||||
(debugger_scripts, DebuggerScripts { stage: u32 }),
|
||||
|
||||
|
|
@ -334,8 +333,7 @@ impl<'a> Step<'a> {
|
|||
vec![self.libstd(compiler)]
|
||||
}
|
||||
Source::Libstd { compiler } => {
|
||||
vec![self.compiler_rt(()),
|
||||
self.rustc(compiler.stage).target(compiler.host)]
|
||||
vec![self.rustc(compiler.stage).target(compiler.host)]
|
||||
}
|
||||
Source::LibrustcLink { compiler, host } => {
|
||||
vec![self.librustc(compiler),
|
||||
|
|
@ -348,7 +346,6 @@ impl<'a> Step<'a> {
|
|||
vec![self.libstd(compiler),
|
||||
self.target(host).rustc(compiler.stage)]
|
||||
}
|
||||
Source::CompilerRt { _dummy } => Vec::new(),
|
||||
Source::Llvm { _dummy } => Vec::new(),
|
||||
Source::TestHelpers { _dummy } => Vec::new(),
|
||||
Source::DebuggerScripts { stage: _ } => Vec::new(),
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ use filetime::FileTime;
|
|||
|
||||
/// Returns the `name` as the filename of a static library for `target`.
|
||||
pub fn staticlib(name: &str, target: &str) -> String {
|
||||
if target.contains("windows-msvc") {
|
||||
if target.contains("windows") {
|
||||
format!("{}.lib", name)
|
||||
} else {
|
||||
format!("lib{}.a", name)
|
||||
|
|
|
|||
|
|
@ -471,7 +471,7 @@ extern {
|
|||
|
||||
fn main() {
|
||||
println!("You have readline version {} installed.",
|
||||
rl_readline_version as i32);
|
||||
unsafe { rl_readline_version as i32 });
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -539,6 +539,7 @@ This is currently hidden behind the `abi_vectorcall` gate and is subject to chan
|
|||
* `system`
|
||||
* `C`
|
||||
* `win64`
|
||||
* `sysv64`
|
||||
|
||||
Most of the abis in this list are self-explanatory, but the `system` abi may
|
||||
seem a little odd. This constraint selects whatever the appropriate ABI is for
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ binary downloads][install-page].
|
|||
|
||||
Oh, we should also mention the officially supported platforms:
|
||||
|
||||
* Windows (7, 8, Server 2008 R2)
|
||||
* Windows (7+)
|
||||
* Linux (2.6.18 or later, various distributions), x86 and x86-64
|
||||
* OSX 10.7 (Lion) or greater, x86 and x86-64
|
||||
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ the thing `y` points at. You’ll notice that `x` had to be marked `mut` as well
|
|||
If it wasn’t, we couldn’t take a mutable borrow to an immutable value.
|
||||
|
||||
You'll also notice we added an asterisk (`*`) in front of `y`, making it `*y`,
|
||||
this is because `y` is a `&mut` reference. You'll need to use astrisks to
|
||||
this is because `y` is a `&mut` reference. You'll need to use asterisks to
|
||||
access the contents of a reference as well.
|
||||
|
||||
Otherwise, `&mut` references are like references. There _is_ a large
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ won’t have its methods:
|
|||
[write]: ../std/io/trait.Write.html
|
||||
|
||||
```rust,ignore
|
||||
let mut f = std::fs::File::open("foo.txt").expect("Couldn’t open foo.txt");
|
||||
let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt");
|
||||
let buf = b"whatever"; // byte string literal. buf: &[u8; 8]
|
||||
let result = f.write(buf);
|
||||
# result.unwrap(); // ignore the error
|
||||
|
|
@ -291,10 +291,10 @@ let result = f.write(buf);
|
|||
|
||||
We need to `use` the `Write` trait first:
|
||||
|
||||
```rust,ignore
|
||||
```rust,no_run
|
||||
use std::io::Write;
|
||||
|
||||
let mut f = std::fs::File::open("foo.txt").expect("Couldn’t open foo.txt");
|
||||
let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt");
|
||||
let buf = b"whatever";
|
||||
let result = f.write(buf);
|
||||
# result.unwrap(); // ignore the error
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ let mut data = vec![1, 2, 3];
|
|||
let x = &data[0];
|
||||
|
||||
// OH NO! `push` causes the backing storage of `data` to be reallocated.
|
||||
// Dangling pointer! User after free! Alas!
|
||||
// Dangling pointer! Use after free! Alas!
|
||||
// (this does not compile in Rust)
|
||||
data.push(4);
|
||||
|
||||
|
|
|
|||
|
|
@ -26,10 +26,6 @@ can therefore be trusted. You can use `unsafe` on a trait implementation
|
|||
to declare that the implementation of that trait has adhered to whatever
|
||||
contracts the trait's documentation requires.
|
||||
|
||||
There is also the `#[unsafe_no_drop_flag]` attribute, which exists for
|
||||
historic reasons and is being phased out. See the section on [drop flags]
|
||||
for details.
|
||||
|
||||
The standard library has a number of unsafe functions, including:
|
||||
|
||||
* `slice::get_unchecked`, which performs unchecked indexing, allowing
|
||||
|
|
|
|||
|
|
@ -1677,6 +1677,7 @@ There are also some platform-specific ABI strings:
|
|||
* `extern "cdecl"` -- The default for x86\_32 C code.
|
||||
* `extern "stdcall"` -- The default for the Win32 API on x86\_32.
|
||||
* `extern "win64"` -- The default for C code on x86\_64 Windows.
|
||||
* `extern "sysv64"` -- The default for C code on non-Windows x86\_64.
|
||||
* `extern "aapcs"` -- The default for ARM.
|
||||
* `extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's
|
||||
`__fastcall` and GCC and clang's `__attribute__((fastcall))`
|
||||
|
|
@ -2058,10 +2059,6 @@ macro scope.
|
|||
outside of its dynamic extent), and thus this attribute has the word
|
||||
"unsafe" in its name. To use this, the
|
||||
`unsafe_destructor_blind_to_params` feature gate must be enabled.
|
||||
- `unsafe_no_drop_flag` - on structs, remove the flag that prevents
|
||||
destructors from being run twice. Destructors might be run multiple times on
|
||||
the same object with this attribute. To use this, the `unsafe_no_drop_flag` feature
|
||||
gate must be enabled.
|
||||
- `doc` - Doc comments such as `/// foo` are equivalent to `#[doc = "foo"]`.
|
||||
- `rustc_on_unimplemented` - Write a custom note to be shown along with the error
|
||||
when the trait is found to be unimplemented on a type.
|
||||
|
|
@ -2070,6 +2067,9 @@ macro scope.
|
|||
trait of the same name. `{Self}` will be replaced with the type that is supposed
|
||||
to implement the trait but doesn't. To use this, the `on_unimplemented` feature gate
|
||||
must be enabled.
|
||||
- `must_use` - on structs and enums, will warn if a value of this type isn't used or
|
||||
assigned to a variable. You may also include an optional message by using
|
||||
`#[must_use = "message"]` which will be given alongside the warning.
|
||||
|
||||
### Conditional compilation
|
||||
|
||||
|
|
@ -2441,6 +2441,9 @@ The currently implemented features of the reference compiler are:
|
|||
into a Rust program. This capability, especially the signature for the
|
||||
annotated function, is subject to change.
|
||||
|
||||
* `static_in_const` - Enables lifetime elision with a `'static` default for
|
||||
`const` and `static` item declarations.
|
||||
|
||||
* `thread_local` - The usage of the `#[thread_local]` attribute is experimental
|
||||
and should be seen as unstable. This attribute is used to
|
||||
declare a `static` as being unique per-thread leveraging
|
||||
|
|
@ -2454,12 +2457,6 @@ The currently implemented features of the reference compiler are:
|
|||
* `unboxed_closures` - Rust's new closure design, which is currently a work in
|
||||
progress feature with many known bugs.
|
||||
|
||||
* `unsafe_no_drop_flag` - Allows use of the `#[unsafe_no_drop_flag]` attribute,
|
||||
which removes hidden flag added to a type that
|
||||
implements the `Drop` trait. The design for the
|
||||
`Drop` flag is subject to change, and this feature
|
||||
may be removed in the future.
|
||||
|
||||
* `unmarked_api` - Allows use of items within a `#![staged_api]` crate
|
||||
which have not been marked with a stability marker.
|
||||
Such items should not be allowed by the compiler to exist,
|
||||
|
|
@ -2485,6 +2482,9 @@ The currently implemented features of the reference compiler are:
|
|||
|
||||
* - `dotdot_in_tuple_patterns` - Allows `..` in tuple (struct) patterns.
|
||||
|
||||
* - `abi_sysv64` - Allows the usage of the system V AMD64 calling convention
|
||||
(e.g. `extern "sysv64" func fn_();`)
|
||||
|
||||
If a feature is promoted to a language feature, then all existing programs will
|
||||
start to receive compilation warnings about `#![feature]` directives which enabled
|
||||
the new feature (because the directive is no longer necessary). However, if a
|
||||
|
|
|
|||
|
|
@ -331,6 +331,33 @@ impl<T: ?Sized> Arc<T> {
|
|||
deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[unstable(feature = "ptr_eq",
|
||||
reason = "newly added",
|
||||
issue = "36497")]
|
||||
/// Return whether two `Arc` references point to the same value
|
||||
/// (not just values that compare equal).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(ptr_eq)]
|
||||
///
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let five = Arc::new(5);
|
||||
/// let same_five = five.clone();
|
||||
/// let other_five = Arc::new(5);
|
||||
///
|
||||
/// assert!(Arc::ptr_eq(&five, &same_five));
|
||||
/// assert!(!Arc::ptr_eq(&five, &other_five));
|
||||
/// ```
|
||||
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
|
||||
let this_ptr: *const ArcInner<T> = *this.ptr;
|
||||
let other_ptr: *const ArcInner<T> = *other.ptr;
|
||||
this_ptr == other_ptr
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -718,6 +745,7 @@ impl<T: ?Sized> Clone for Weak<T> {
|
|||
|
||||
#[stable(feature = "downgraded_weak", since = "1.10.0")]
|
||||
impl<T> Default for Weak<T> {
|
||||
/// Constructs a new `Weak<T>` without an accompanying instance of T.
|
||||
fn default() -> Weak<T> {
|
||||
Weak::new()
|
||||
}
|
||||
|
|
@ -923,6 +951,7 @@ impl<T: ?Sized> fmt::Pointer for Arc<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Default> Default for Arc<T> {
|
||||
/// Creates a new `Arc<T>`, with the `Default` value for T.
|
||||
fn default() -> Arc<T> {
|
||||
Arc::new(Default::default())
|
||||
}
|
||||
|
|
@ -1198,6 +1227,16 @@ mod tests {
|
|||
let foo: Weak<usize> = Weak::new();
|
||||
assert!(foo.upgrade().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ptr_eq() {
|
||||
let five = Arc::new(5);
|
||||
let same_five = five.clone();
|
||||
let other_five = Arc::new(5);
|
||||
|
||||
assert!(Arc::ptr_eq(&five, &same_five));
|
||||
assert!(!Arc::ptr_eq(&five, &other_five));
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -290,6 +290,7 @@ impl<T: ?Sized> Box<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Default> Default for Box<T> {
|
||||
/// Creates a `Box<T>`, with the `Default` value for T.
|
||||
fn default() -> Box<T> {
|
||||
box Default::default()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -376,6 +376,33 @@ impl<T: ?Sized> Rc<T> {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[unstable(feature = "ptr_eq",
|
||||
reason = "newly added",
|
||||
issue = "36497")]
|
||||
/// Return whether two `Rc` references point to the same value
|
||||
/// (not just values that compare equal).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(ptr_eq)]
|
||||
///
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5);
|
||||
/// let same_five = five.clone();
|
||||
/// let other_five = Rc::new(5);
|
||||
///
|
||||
/// assert!(Rc::ptr_eq(&five, &same_five));
|
||||
/// assert!(!Rc::ptr_eq(&five, &other_five));
|
||||
/// ```
|
||||
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
|
||||
let this_ptr: *const RcBox<T> = *this.ptr;
|
||||
let other_ptr: *const RcBox<T> = *other.ptr;
|
||||
this_ptr == other_ptr
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> Rc<T> {
|
||||
|
|
@ -870,6 +897,7 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for Weak<T> {
|
|||
|
||||
#[stable(feature = "downgraded_weak", since = "1.10.0")]
|
||||
impl<T> Default for Weak<T> {
|
||||
/// Creates a new `Weak<T>`.
|
||||
fn default() -> Weak<T> {
|
||||
Weak::new()
|
||||
}
|
||||
|
|
@ -1173,6 +1201,16 @@ mod tests {
|
|||
let foo: Weak<usize> = Weak::new();
|
||||
assert!(foo.upgrade().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ptr_eq() {
|
||||
let five = Rc::new(5);
|
||||
let same_five = five.clone();
|
||||
let other_five = Rc::new(5);
|
||||
|
||||
assert!(Rc::ptr_eq(&five, &same_five));
|
||||
assert!(!Rc::ptr_eq(&five, &other_five));
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -77,7 +77,9 @@ const MIN_ALIGN: usize = 8;
|
|||
#[cfg(all(any(target_arch = "x86",
|
||||
target_arch = "x86_64",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "powerpc64")))]
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "mips64",
|
||||
target_arch = "s390x")))]
|
||||
const MIN_ALIGN: usize = 16;
|
||||
|
||||
// MALLOCX_ALIGN(a) macro
|
||||
|
|
|
|||
|
|
@ -32,7 +32,9 @@
|
|||
target_arch = "asmjs")))]
|
||||
const MIN_ALIGN: usize = 8;
|
||||
#[cfg(all(any(target_arch = "x86_64",
|
||||
target_arch = "aarch64")))]
|
||||
target_arch = "aarch64",
|
||||
target_arch = "mips64",
|
||||
target_arch = "s390x")))]
|
||||
const MIN_ALIGN: usize = 16;
|
||||
|
||||
#[no_mangle]
|
||||
|
|
|
|||
|
|
@ -15,9 +15,8 @@
|
|||
//! of individual objects while the arena itself is still alive. The benefit
|
||||
//! of an arena is very fast allocation; just a pointer bump.
|
||||
//!
|
||||
//! This crate has two arenas implemented: `TypedArena`, which is a simpler
|
||||
//! arena but can only hold objects of a single type, and `Arena`, which is a
|
||||
//! more complex, slower arena which can hold objects of any type.
|
||||
//! This crate implements `TypedArena`, a simple arena that can only hold
|
||||
//! objects of a single type.
|
||||
|
||||
#![crate_name = "arena"]
|
||||
#![unstable(feature = "rustc_private", issue = "27812")]
|
||||
|
|
@ -51,8 +50,11 @@ use std::ptr;
|
|||
use alloc::heap;
|
||||
use alloc::raw_vec::RawVec;
|
||||
|
||||
/// A faster arena that can hold objects of only one type.
|
||||
/// An arena that can hold objects of only one type.
|
||||
pub struct TypedArena<T> {
|
||||
/// The capacity of the first chunk (once it is allocated).
|
||||
first_chunk_capacity: usize,
|
||||
|
||||
/// A pointer to the next object to be allocated.
|
||||
ptr: Cell<*mut T>,
|
||||
|
||||
|
|
@ -60,7 +62,7 @@ pub struct TypedArena<T> {
|
|||
/// reached, a new chunk is allocated.
|
||||
end: Cell<*mut T>,
|
||||
|
||||
/// A vector arena segments.
|
||||
/// A vector of arena chunks.
|
||||
chunks: RefCell<Vec<TypedArenaChunk<T>>>,
|
||||
|
||||
/// Marker indicating that dropping the arena causes its owned
|
||||
|
|
@ -69,7 +71,7 @@ pub struct TypedArena<T> {
|
|||
}
|
||||
|
||||
struct TypedArenaChunk<T> {
|
||||
/// Pointer to the next arena segment.
|
||||
/// The raw storage for the arena chunk.
|
||||
storage: RawVec<T>,
|
||||
}
|
||||
|
||||
|
|
@ -117,7 +119,7 @@ impl<T> TypedArenaChunk<T> {
|
|||
const PAGE: usize = 4096;
|
||||
|
||||
impl<T> TypedArena<T> {
|
||||
/// Creates a new `TypedArena` with preallocated space for many objects.
|
||||
/// Creates a new `TypedArena`.
|
||||
#[inline]
|
||||
pub fn new() -> TypedArena<T> {
|
||||
// Reserve at least one page.
|
||||
|
|
@ -125,18 +127,18 @@ impl<T> TypedArena<T> {
|
|||
TypedArena::with_capacity(PAGE / elem_size)
|
||||
}
|
||||
|
||||
/// Creates a new `TypedArena` with preallocated space for the given number of
|
||||
/// objects.
|
||||
/// Creates a new `TypedArena`. Each chunk used within the arena will have
|
||||
/// space for at least the given number of objects.
|
||||
#[inline]
|
||||
pub fn with_capacity(capacity: usize) -> TypedArena<T> {
|
||||
unsafe {
|
||||
let chunk = TypedArenaChunk::<T>::new(cmp::max(1, capacity));
|
||||
TypedArena {
|
||||
ptr: Cell::new(chunk.start()),
|
||||
end: Cell::new(chunk.end()),
|
||||
chunks: RefCell::new(vec![chunk]),
|
||||
_own: PhantomData,
|
||||
}
|
||||
TypedArena {
|
||||
first_chunk_capacity: cmp::max(1, capacity),
|
||||
// We set both `ptr` and `end` to 0 so that the first call to
|
||||
// alloc() will trigger a grow().
|
||||
ptr: Cell::new(0 as *mut T),
|
||||
end: Cell::new(0 as *mut T),
|
||||
chunks: RefCell::new(vec![]),
|
||||
_own: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -171,16 +173,22 @@ impl<T> TypedArena<T> {
|
|||
fn grow(&self) {
|
||||
unsafe {
|
||||
let mut chunks = self.chunks.borrow_mut();
|
||||
let prev_capacity = chunks.last().unwrap().storage.cap();
|
||||
let new_capacity = prev_capacity.checked_mul(2).unwrap();
|
||||
if chunks.last_mut().unwrap().storage.double_in_place() {
|
||||
self.end.set(chunks.last().unwrap().end());
|
||||
let (chunk, new_capacity);
|
||||
if let Some(last_chunk) = chunks.last_mut() {
|
||||
if last_chunk.storage.double_in_place() {
|
||||
self.end.set(last_chunk.end());
|
||||
return;
|
||||
} else {
|
||||
let prev_capacity = last_chunk.storage.cap();
|
||||
new_capacity = prev_capacity.checked_mul(2).unwrap();
|
||||
}
|
||||
} else {
|
||||
let chunk = TypedArenaChunk::<T>::new(new_capacity);
|
||||
self.ptr.set(chunk.start());
|
||||
self.end.set(chunk.end());
|
||||
chunks.push(chunk);
|
||||
new_capacity = self.first_chunk_capacity;
|
||||
}
|
||||
chunk = TypedArenaChunk::<T>::new(new_capacity);
|
||||
self.ptr.set(chunk.start());
|
||||
self.end.set(chunk.end());
|
||||
chunks.push(chunk);
|
||||
}
|
||||
}
|
||||
/// Clears the arena. Deallocates all but the longest chunk which may be reused.
|
||||
|
|
@ -188,12 +196,14 @@ impl<T> TypedArena<T> {
|
|||
unsafe {
|
||||
// Clear the last chunk, which is partially filled.
|
||||
let mut chunks_borrow = self.chunks.borrow_mut();
|
||||
let last_idx = chunks_borrow.len() - 1;
|
||||
self.clear_last_chunk(&mut chunks_borrow[last_idx]);
|
||||
// If `T` is ZST, code below has no effect.
|
||||
for mut chunk in chunks_borrow.drain(..last_idx) {
|
||||
let cap = chunk.storage.cap();
|
||||
chunk.destroy(cap);
|
||||
if let Some(mut last_chunk) = chunks_borrow.pop() {
|
||||
self.clear_last_chunk(&mut last_chunk);
|
||||
// If `T` is ZST, code below has no effect.
|
||||
for mut chunk in chunks_borrow.drain(..) {
|
||||
let cap = chunk.storage.cap();
|
||||
chunk.destroy(cap);
|
||||
}
|
||||
chunks_borrow.push(last_chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -230,13 +240,14 @@ impl<T> Drop for TypedArena<T> {
|
|||
unsafe {
|
||||
// Determine how much was filled.
|
||||
let mut chunks_borrow = self.chunks.borrow_mut();
|
||||
let mut last_chunk = chunks_borrow.pop().unwrap();
|
||||
// Drop the contents of the last chunk.
|
||||
self.clear_last_chunk(&mut last_chunk);
|
||||
// The last chunk will be dropped. Destroy all other chunks.
|
||||
for chunk in chunks_borrow.iter_mut() {
|
||||
let cap = chunk.storage.cap();
|
||||
chunk.destroy(cap);
|
||||
if let Some(mut last_chunk) = chunks_borrow.pop() {
|
||||
// Drop the contents of the last chunk.
|
||||
self.clear_last_chunk(&mut last_chunk);
|
||||
// The last chunk will be dropped. Destroy all other chunks.
|
||||
for chunk in chunks_borrow.iter_mut() {
|
||||
let cap = chunk.storage.cap();
|
||||
chunk.destroy(cap);
|
||||
}
|
||||
}
|
||||
// RawVec handles deallocation of `last_chunk` and `self.chunks`.
|
||||
}
|
||||
|
|
@ -260,6 +271,12 @@ mod tests {
|
|||
z: i32,
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_unused() {
|
||||
let arena: TypedArena<Point> = TypedArena::new();
|
||||
assert!(arena.chunks.borrow().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arena_alloc_nested() {
|
||||
struct Inner {
|
||||
|
|
|
|||
|
|
@ -263,6 +263,7 @@ impl<T: Clone> Clone for BinaryHeap<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Ord> Default for BinaryHeap<T> {
|
||||
/// Creates an empty `BinaryHeap<T>`.
|
||||
#[inline]
|
||||
fn default() -> BinaryHeap<T> {
|
||||
BinaryHeap::new()
|
||||
|
|
@ -884,58 +885,61 @@ struct Hole<'a, T: 'a> {
|
|||
|
||||
impl<'a, T> Hole<'a, T> {
|
||||
/// Create a new Hole at index `pos`.
|
||||
fn new(data: &'a mut [T], pos: usize) -> Self {
|
||||
unsafe {
|
||||
let elt = ptr::read(&data[pos]);
|
||||
Hole {
|
||||
data: data,
|
||||
elt: Some(elt),
|
||||
pos: pos,
|
||||
}
|
||||
///
|
||||
/// Unsafe because pos must be within the data slice.
|
||||
#[inline]
|
||||
unsafe fn new(data: &'a mut [T], pos: usize) -> Self {
|
||||
debug_assert!(pos < data.len());
|
||||
let elt = ptr::read(&data[pos]);
|
||||
Hole {
|
||||
data: data,
|
||||
elt: Some(elt),
|
||||
pos: pos,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[inline]
|
||||
fn pos(&self) -> usize {
|
||||
self.pos
|
||||
}
|
||||
|
||||
/// Return a reference to the element removed
|
||||
#[inline(always)]
|
||||
#[inline]
|
||||
fn element(&self) -> &T {
|
||||
self.elt.as_ref().unwrap()
|
||||
}
|
||||
|
||||
/// Return a reference to the element at `index`.
|
||||
///
|
||||
/// Panics if the index is out of bounds.
|
||||
///
|
||||
/// Unsafe because index must not equal pos.
|
||||
#[inline(always)]
|
||||
/// Unsafe because index must be within the data slice and not equal to pos.
|
||||
#[inline]
|
||||
unsafe fn get(&self, index: usize) -> &T {
|
||||
debug_assert!(index != self.pos);
|
||||
&self.data[index]
|
||||
debug_assert!(index < self.data.len());
|
||||
self.data.get_unchecked(index)
|
||||
}
|
||||
|
||||
/// Move hole to new location
|
||||
///
|
||||
/// Unsafe because index must not equal pos.
|
||||
#[inline(always)]
|
||||
/// Unsafe because index must be within the data slice and not equal to pos.
|
||||
#[inline]
|
||||
unsafe fn move_to(&mut self, index: usize) {
|
||||
debug_assert!(index != self.pos);
|
||||
let index_ptr: *const _ = &self.data[index];
|
||||
let hole_ptr = &mut self.data[self.pos];
|
||||
debug_assert!(index < self.data.len());
|
||||
let index_ptr: *const _ = self.data.get_unchecked(index);
|
||||
let hole_ptr = self.data.get_unchecked_mut(self.pos);
|
||||
ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1);
|
||||
self.pos = index;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for Hole<'a, T> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
// fill the hole again
|
||||
unsafe {
|
||||
let pos = self.pos;
|
||||
ptr::write(&mut self.data[pos], self.elt.take().unwrap());
|
||||
ptr::write(self.data.get_unchecked_mut(pos), self.elt.take().unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -249,6 +249,7 @@ impl<'a, B: ?Sized> Default for Cow<'a, B>
|
|||
where B: ToOwned,
|
||||
<B as ToOwned>::Owned: Default
|
||||
{
|
||||
/// Creates an owned Cow<'a, B> with the default value for the contained owned value.
|
||||
fn default() -> Cow<'a, B> {
|
||||
Owned(<B as ToOwned>::Owned::default())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,8 +56,12 @@ use self::Entry::*;
|
|||
/// however, performance is excellent.
|
||||
///
|
||||
/// It is a logic error for a key to be modified in such a way that the key's ordering relative to
|
||||
/// any other key, as determined by the `Ord` trait, changes while it is in the map. This is
|
||||
/// normally only possible through `Cell`, `RefCell`, global state, I/O, or unsafe code.
|
||||
/// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is
|
||||
/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
|
||||
///
|
||||
/// [`Ord`]: ../../std/cmp/trait.Ord.html
|
||||
/// [`Cell`]: ../../std/cell/struct.Cell.html
|
||||
/// [`RefCell`]: ../../std/cell/struct.RefCell.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -1663,6 +1667,7 @@ impl<K: Hash, V: Hash> Hash for BTreeMap<K, V> {
|
|||
}
|
||||
|
||||
impl<K: Ord, V> Default for BTreeMap<K, V> {
|
||||
/// Creates an empty `BTreeMap<K, V>`.
|
||||
fn default() -> BTreeMap<K, V> {
|
||||
BTreeMap::new()
|
||||
}
|
||||
|
|
@ -2020,7 +2025,7 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> {
|
|||
self.key
|
||||
}
|
||||
|
||||
/// Sets the value of the entry with the VacantEntry's key,
|
||||
/// Sets the value of the entry with the `VacantEntry`'s key,
|
||||
/// and returns a mutable reference to it.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
@ -2192,7 +2197,7 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
|
|||
self.handle.into_kv_mut().1
|
||||
}
|
||||
|
||||
/// Sets the value of the entry with the OccupiedEntry's key,
|
||||
/// Sets the value of the entry with the `OccupiedEntry`'s key,
|
||||
/// and returns the entry's old value.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
|
|||
|
|
@ -674,6 +674,7 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BTreeSet<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Ord> Default for BTreeSet<T> {
|
||||
/// Makes an empty `BTreeSet<T>` with a reasonable choice of B.
|
||||
fn default() -> BTreeSet<T> {
|
||||
BTreeSet::new()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ impl<T> LinkedList<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Default for LinkedList<T> {
|
||||
/// Creates an empty `LinkedList<T>`.
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
|
|
|
|||
|
|
@ -1594,6 +1594,49 @@ impl str {
|
|||
result
|
||||
}
|
||||
|
||||
/// Replaces first N matches of a pattern with another string.
|
||||
///
|
||||
/// `replacen` creates a new [`String`], and copies the data from this string slice into it.
|
||||
/// While doing so, it attempts to find matches of a pattern. If it finds any, it
|
||||
/// replaces them with the replacement string slice at most `N` times.
|
||||
///
|
||||
/// [`String`]: string/struct.String.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(str_replacen)]
|
||||
/// let s = "foo foo 123 foo";
|
||||
/// assert_eq!("new new 123 foo", s.replacen("foo", "new", 2));
|
||||
/// assert_eq!("faa fao 123 foo", s.replacen('o', "a", 3));
|
||||
/// assert_eq!("foo foo new23 foo", s.replacen(char::is_numeric, "new", 1));
|
||||
/// ```
|
||||
///
|
||||
/// When the pattern doesn't match:
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(str_replacen)]
|
||||
/// let s = "this is old";
|
||||
/// assert_eq!(s, s.replacen("cookie monster", "little lamb", 10));
|
||||
/// ```
|
||||
#[unstable(feature = "str_replacen",
|
||||
issue = "36436",
|
||||
reason = "only need to replace first N matches")]
|
||||
pub fn replacen<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) -> String {
|
||||
// Hope to reduce the times of re-allocation
|
||||
let mut result = String::with_capacity(32);
|
||||
let mut last_end = 0;
|
||||
for (start, part) in self.match_indices(pat).take(count) {
|
||||
result.push_str(unsafe { self.slice_unchecked(last_end, start) });
|
||||
result.push_str(to);
|
||||
last_end = start + part.len();
|
||||
}
|
||||
result.push_str(unsafe { self.slice_unchecked(last_end, self.len()) });
|
||||
result
|
||||
}
|
||||
|
||||
/// Returns the lowercase equivalent of this string slice, as a new [`String`].
|
||||
///
|
||||
/// 'Lowercase' is defined according to the terms of the Unicode Derived Core Property
|
||||
|
|
|
|||
|
|
@ -1567,6 +1567,7 @@ impl_eq! { Cow<'a, str>, String }
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Default for String {
|
||||
/// Creates an empty `String`.
|
||||
#[inline]
|
||||
fn default() -> String {
|
||||
String::new()
|
||||
|
|
|
|||
|
|
@ -1046,21 +1046,27 @@ impl<T: Clone> Vec<T> {
|
|||
self.reserve(n);
|
||||
|
||||
unsafe {
|
||||
let len = self.len();
|
||||
let mut ptr = self.as_mut_ptr().offset(len as isize);
|
||||
let mut ptr = self.as_mut_ptr().offset(self.len() as isize);
|
||||
// Use SetLenOnDrop to work around bug where compiler
|
||||
// may not realize the store through `ptr` trough self.set_len()
|
||||
// don't alias.
|
||||
let mut local_len = SetLenOnDrop::new(&mut self.len);
|
||||
|
||||
// Write all elements except the last one
|
||||
for i in 1..n {
|
||||
for _ in 1..n {
|
||||
ptr::write(ptr, value.clone());
|
||||
ptr = ptr.offset(1);
|
||||
// Increment the length in every step in case clone() panics
|
||||
self.set_len(len + i);
|
||||
local_len.increment_len(1);
|
||||
}
|
||||
|
||||
if n > 0 {
|
||||
// We can write the last element directly without cloning needlessly
|
||||
ptr::write(ptr, value);
|
||||
self.set_len(len + n);
|
||||
local_len.increment_len(1);
|
||||
}
|
||||
|
||||
// len set by scope guard
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1085,20 +1091,56 @@ impl<T: Clone> Vec<T> {
|
|||
pub fn extend_from_slice(&mut self, other: &[T]) {
|
||||
self.reserve(other.len());
|
||||
|
||||
for i in 0..other.len() {
|
||||
// Unsafe code so this can be optimised to a memcpy (or something
|
||||
// similarly fast) when T is Copy. LLVM is easily confused, so any
|
||||
// extra operations during the loop can prevent this optimisation.
|
||||
unsafe {
|
||||
let len = self.len();
|
||||
let ptr = self.get_unchecked_mut(len) as *mut T;
|
||||
// Use SetLenOnDrop to work around bug where compiler
|
||||
// may not realize the store through `ptr` trough self.set_len()
|
||||
// don't alias.
|
||||
let mut local_len = SetLenOnDrop::new(&mut self.len);
|
||||
|
||||
// Unsafe code so this can be optimised to a memcpy (or something
|
||||
// similarly fast) when T is Copy. LLVM is easily confused, so any
|
||||
// extra operations during the loop can prevent this optimisation.
|
||||
unsafe {
|
||||
ptr::write(self.get_unchecked_mut(len), other.get_unchecked(i).clone());
|
||||
self.set_len(len + 1);
|
||||
for i in 0..other.len() {
|
||||
ptr::write(ptr.offset(i as isize), other.get_unchecked(i).clone());
|
||||
local_len.increment_len(1);
|
||||
}
|
||||
|
||||
// len set by scope guard
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the length of the vec when the `SetLenOnDrop` value goes out of scope.
|
||||
//
|
||||
// The idea is: The length field in SetLenOnDrop is a local variable
|
||||
// that the optimizer will see does not alias with any stores through the Vec's data
|
||||
// pointer. This is a workaround for alias analysis issue #32155
|
||||
struct SetLenOnDrop<'a> {
|
||||
len: &'a mut usize,
|
||||
local_len: usize,
|
||||
}
|
||||
|
||||
impl<'a> SetLenOnDrop<'a> {
|
||||
#[inline]
|
||||
fn new(len: &'a mut usize) -> Self {
|
||||
SetLenOnDrop { local_len: *len, len: len }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn increment_len(&mut self, increment: usize) {
|
||||
self.local_len += increment;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for SetLenOnDrop<'a> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
*self.len = self.local_len;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq> Vec<T> {
|
||||
/// Removes consecutive repeated elements in the vector.
|
||||
///
|
||||
|
|
@ -1610,6 +1652,7 @@ impl<T> Drop for Vec<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Default for Vec<T> {
|
||||
/// Creates an empty `Vec<T>`.
|
||||
fn default() -> Vec<T> {
|
||||
Vec::new()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ impl<T> Drop for VecDeque<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Default for VecDeque<T> {
|
||||
/// Creates an empty `VecDeque<T>`.
|
||||
#[inline]
|
||||
fn default() -> VecDeque<T> {
|
||||
VecDeque::new()
|
||||
|
|
|
|||
|
|
@ -39,30 +39,8 @@ fn test_hash() {
|
|||
assert!(::hash(&x) == ::hash(&y));
|
||||
}
|
||||
|
||||
struct Counter<'a, 'b> {
|
||||
i: &'a mut usize,
|
||||
expected: &'b [i32],
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c> FnMut<(&'c i32,)> for Counter<'a, 'b> {
|
||||
extern "rust-call" fn call_mut(&mut self, (&x,): (&'c i32,)) -> bool {
|
||||
assert_eq!(x, self.expected[*self.i]);
|
||||
*self.i += 1;
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c> FnOnce<(&'c i32,)> for Counter<'a, 'b> {
|
||||
type Output = bool;
|
||||
|
||||
extern "rust-call" fn call_once(mut self, args: (&'c i32,)) -> bool {
|
||||
self.call_mut(args)
|
||||
}
|
||||
}
|
||||
|
||||
fn check<F>(a: &[i32], b: &[i32], expected: &[i32], f: F) where
|
||||
// FIXME Replace Counter with `Box<FnMut(_) -> _>`
|
||||
F: FnOnce(&BTreeSet<i32>, &BTreeSet<i32>, Counter) -> bool,
|
||||
F: FnOnce(&BTreeSet<i32>, &BTreeSet<i32>, &mut FnMut(&i32) -> bool) -> bool,
|
||||
{
|
||||
let mut set_a = BTreeSet::new();
|
||||
let mut set_b = BTreeSet::new();
|
||||
|
|
@ -71,7 +49,11 @@ fn check<F>(a: &[i32], b: &[i32], expected: &[i32], f: F) where
|
|||
for y in b { assert!(set_b.insert(*y)) }
|
||||
|
||||
let mut i = 0;
|
||||
f(&set_a, &set_b, Counter { i: &mut i, expected: expected });
|
||||
f(&set_a, &set_b, &mut |&x| {
|
||||
assert_eq!(x, expected[i]);
|
||||
i += 1;
|
||||
true
|
||||
});
|
||||
assert_eq!(i, expected.len());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@
|
|||
#![feature(collections)]
|
||||
#![feature(collections_bound)]
|
||||
#![feature(const_fn)]
|
||||
#![feature(fn_traits)]
|
||||
#![feature(enumset)]
|
||||
#![feature(pattern)]
|
||||
#![feature(rand)]
|
||||
#![feature(step_by)]
|
||||
#![feature(str_escape)]
|
||||
#![feature(str_replacen)]
|
||||
#![feature(test)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(unicode)]
|
||||
|
|
|
|||
|
|
@ -218,6 +218,20 @@ fn test_is_empty() {
|
|||
assert!(!"a".is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_replacen() {
|
||||
assert_eq!("".replacen('a', "b", 5), "");
|
||||
assert_eq!("acaaa".replacen("a", "b", 3), "bcbba");
|
||||
assert_eq!("aaaa".replacen("a", "b", 0), "aaaa");
|
||||
|
||||
let test = "test";
|
||||
assert_eq!(" test test ".replacen(test, "toast", 3), " toast toast ");
|
||||
assert_eq!(" test test ".replacen(test, "toast", 0), " test test ");
|
||||
assert_eq!(" test test ".replacen(test, "", 5), " ");
|
||||
|
||||
assert_eq!("qwer123zxc789".replacen(char::is_numeric, "", 3), "qwerzxc789");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_replace() {
|
||||
let a = "a";
|
||||
|
|
|
|||
15
src/libcompiler_builtins/Cargo.toml
Normal file
15
src/libcompiler_builtins/Cargo.toml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
authors = ["The Rust Project Developers"]
|
||||
build = "build.rs"
|
||||
name = "compiler_builtins"
|
||||
version = "0.0.0"
|
||||
|
||||
[lib]
|
||||
name = "compiler_builtins"
|
||||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
core = { path = "../libcore" }
|
||||
|
||||
[build-dependencies]
|
||||
gcc = "0.3.27"
|
||||
404
src/libcompiler_builtins/build.rs
Normal file
404
src/libcompiler_builtins/build.rs
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Compiles the `compiler-rt` library, or at least the builtins part of it.
|
||||
//!
|
||||
//! Note that while compiler-rt has a build system associated with it, we
|
||||
//! specifically don't use it here. The compiler-rt build system, written in
|
||||
//! CMake, is actually *very* difficult to work with in terms of getting it to
|
||||
//! compile on all the relevant platforms we want it to compile on. In the end
|
||||
//! it became so much pain to work with local patches, work around the oddities
|
||||
//! of the build system, etc, that we're just building everything by hand now.
|
||||
//!
|
||||
//! In general compiler-rt is just a bunch of intrinsics that are in practice
|
||||
//! *very* stable. We just need to make sure that all the relevant functions and
|
||||
//! such are compiled somewhere and placed in an object file somewhere.
|
||||
//! Eventually, these should all be written in Rust!
|
||||
//!
|
||||
//! So below you'll find a listing of every single file in the compiler-rt repo
|
||||
//! that we're compiling. We just reach in and compile with the `gcc` crate
|
||||
//! which should have all the relevant flags and such already configured.
|
||||
//!
|
||||
//! The risk here is that if we update compiler-rt we may need to compile some
|
||||
//! new intrinsics, but to be honest we surely don't use all of the intrinsics
|
||||
//! listed below today so the likelihood of us actually needing a new intrinsic
|
||||
//! is quite low. The failure case is also just that someone reports a link
|
||||
//! error (if any) and then we just add it to the list. Overall, that cost is
|
||||
//! far far less than working with compiler-rt's build system over time.
|
||||
|
||||
extern crate gcc;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
|
||||
struct Sources {
|
||||
// SYMBOL -> PATH TO SOURCE
|
||||
map: BTreeMap<&'static str, &'static str>,
|
||||
}
|
||||
|
||||
impl Sources {
|
||||
fn new() -> Sources {
|
||||
Sources { map: BTreeMap::new() }
|
||||
}
|
||||
|
||||
fn extend(&mut self, sources: &[&'static str]) {
|
||||
// NOTE Some intrinsics have both a generic implementation (e.g.
|
||||
// `floatdidf.c`) and an arch optimized implementation
|
||||
// (`x86_64/floatdidf.c`). In those cases, we keep the arch optimized
|
||||
// implementation and discard the generic implementation. If we don't
|
||||
// and keep both implementations, the linker will yell at us about
|
||||
// duplicate symbols!
|
||||
for &src in sources {
|
||||
let symbol = Path::new(src).file_stem().unwrap().to_str().unwrap();
|
||||
if src.contains("/") {
|
||||
// Arch-optimized implementation (preferred)
|
||||
self.map.insert(symbol, src);
|
||||
} else {
|
||||
// Generic implementation
|
||||
if !self.map.contains_key(symbol) {
|
||||
self.map.insert(symbol, src);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
let cfg = &mut gcc::Config::new();
|
||||
|
||||
if target.contains("msvc") {
|
||||
// Don't pull in extra libraries on MSVC
|
||||
cfg.flag("/Zl");
|
||||
|
||||
// Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP
|
||||
cfg.define("__func__", Some("__FUNCTION__"));
|
||||
} else {
|
||||
// Turn off various features of gcc and such, mostly copying
|
||||
// compiler-rt's build system already
|
||||
cfg.flag("-fno-builtin");
|
||||
cfg.flag("-fvisibility=hidden");
|
||||
cfg.flag("-fomit-frame-pointer");
|
||||
cfg.flag("-ffreestanding");
|
||||
}
|
||||
|
||||
let mut sources = Sources::new();
|
||||
sources.extend(&["absvdi2.c",
|
||||
"absvsi2.c",
|
||||
"adddf3.c",
|
||||
"addsf3.c",
|
||||
"addvdi3.c",
|
||||
"addvsi3.c",
|
||||
"apple_versioning.c",
|
||||
"ashldi3.c",
|
||||
"ashrdi3.c",
|
||||
"clear_cache.c",
|
||||
"clzdi2.c",
|
||||
"clzsi2.c",
|
||||
"cmpdi2.c",
|
||||
"comparedf2.c",
|
||||
"comparesf2.c",
|
||||
"ctzdi2.c",
|
||||
"ctzsi2.c",
|
||||
"divdc3.c",
|
||||
"divdf3.c",
|
||||
"divdi3.c",
|
||||
"divmoddi4.c",
|
||||
"divmodsi4.c",
|
||||
"divsc3.c",
|
||||
"divsf3.c",
|
||||
"divsi3.c",
|
||||
"divxc3.c",
|
||||
"extendsfdf2.c",
|
||||
"extendhfsf2.c",
|
||||
"ffsdi2.c",
|
||||
"fixdfdi.c",
|
||||
"fixdfsi.c",
|
||||
"fixsfdi.c",
|
||||
"fixsfsi.c",
|
||||
"fixunsdfdi.c",
|
||||
"fixunsdfsi.c",
|
||||
"fixunssfdi.c",
|
||||
"fixunssfsi.c",
|
||||
"fixunsxfdi.c",
|
||||
"fixunsxfsi.c",
|
||||
"fixxfdi.c",
|
||||
"floatdidf.c",
|
||||
"floatdisf.c",
|
||||
"floatdixf.c",
|
||||
"floatsidf.c",
|
||||
"floatsisf.c",
|
||||
"floatundidf.c",
|
||||
"floatundisf.c",
|
||||
"floatundixf.c",
|
||||
"floatunsidf.c",
|
||||
"floatunsisf.c",
|
||||
"int_util.c",
|
||||
"lshrdi3.c",
|
||||
"moddi3.c",
|
||||
"modsi3.c",
|
||||
"muldc3.c",
|
||||
"muldf3.c",
|
||||
"muldi3.c",
|
||||
"mulodi4.c",
|
||||
"mulosi4.c",
|
||||
"muloti4.c",
|
||||
"mulsc3.c",
|
||||
"mulsf3.c",
|
||||
"mulvdi3.c",
|
||||
"mulvsi3.c",
|
||||
"mulxc3.c",
|
||||
"negdf2.c",
|
||||
"negdi2.c",
|
||||
"negsf2.c",
|
||||
"negvdi2.c",
|
||||
"negvsi2.c",
|
||||
"paritydi2.c",
|
||||
"paritysi2.c",
|
||||
"popcountdi2.c",
|
||||
"popcountsi2.c",
|
||||
"powidf2.c",
|
||||
"powisf2.c",
|
||||
"powixf2.c",
|
||||
"subdf3.c",
|
||||
"subsf3.c",
|
||||
"subvdi3.c",
|
||||
"subvsi3.c",
|
||||
"truncdfhf2.c",
|
||||
"truncdfsf2.c",
|
||||
"truncsfhf2.c",
|
||||
"ucmpdi2.c",
|
||||
"udivdi3.c",
|
||||
"udivmoddi4.c",
|
||||
"udivmodsi4.c",
|
||||
"udivsi3.c",
|
||||
"umoddi3.c",
|
||||
"umodsi3.c"]);
|
||||
|
||||
if !target.contains("ios") {
|
||||
sources.extend(&["absvti2.c",
|
||||
"addtf3.c",
|
||||
"addvti3.c",
|
||||
"ashlti3.c",
|
||||
"ashrti3.c",
|
||||
"clzti2.c",
|
||||
"cmpti2.c",
|
||||
"ctzti2.c",
|
||||
"divtf3.c",
|
||||
"divti3.c",
|
||||
"ffsti2.c",
|
||||
"fixdfti.c",
|
||||
"fixsfti.c",
|
||||
"fixunsdfti.c",
|
||||
"fixunssfti.c",
|
||||
"fixunsxfti.c",
|
||||
"fixxfti.c",
|
||||
"floattidf.c",
|
||||
"floattisf.c",
|
||||
"floattixf.c",
|
||||
"floatuntidf.c",
|
||||
"floatuntisf.c",
|
||||
"floatuntixf.c",
|
||||
"lshrti3.c",
|
||||
"modti3.c",
|
||||
"multf3.c",
|
||||
"multi3.c",
|
||||
"mulvti3.c",
|
||||
"negti2.c",
|
||||
"negvti2.c",
|
||||
"parityti2.c",
|
||||
"popcountti2.c",
|
||||
"powitf2.c",
|
||||
"subtf3.c",
|
||||
"subvti3.c",
|
||||
"trampoline_setup.c",
|
||||
"ucmpti2.c",
|
||||
"udivmodti4.c",
|
||||
"udivti3.c",
|
||||
"umodti3.c"]);
|
||||
}
|
||||
|
||||
if target.contains("apple") {
|
||||
sources.extend(&["atomic_flag_clear.c",
|
||||
"atomic_flag_clear_explicit.c",
|
||||
"atomic_flag_test_and_set.c",
|
||||
"atomic_flag_test_and_set_explicit.c",
|
||||
"atomic_signal_fence.c",
|
||||
"atomic_thread_fence.c"]);
|
||||
}
|
||||
|
||||
if !target.contains("windows") {
|
||||
sources.extend(&["emutls.c"]);
|
||||
}
|
||||
|
||||
if target.contains("msvc") {
|
||||
if target.contains("x86_64") {
|
||||
sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]);
|
||||
}
|
||||
} else {
|
||||
if !target.contains("freebsd") {
|
||||
sources.extend(&["gcc_personality_v0.c"]);
|
||||
}
|
||||
|
||||
if target.contains("x86_64") {
|
||||
sources.extend(&["x86_64/chkstk.S",
|
||||
"x86_64/chkstk2.S",
|
||||
"x86_64/floatdidf.c",
|
||||
"x86_64/floatdisf.c",
|
||||
"x86_64/floatdixf.c",
|
||||
"x86_64/floatundidf.S",
|
||||
"x86_64/floatundisf.S",
|
||||
"x86_64/floatundixf.S"]);
|
||||
}
|
||||
|
||||
if target.contains("i386") || target.contains("i586") || target.contains("i686") {
|
||||
sources.extend(&["i386/ashldi3.S",
|
||||
"i386/ashrdi3.S",
|
||||
"i386/chkstk.S",
|
||||
"i386/chkstk2.S",
|
||||
"i386/divdi3.S",
|
||||
"i386/floatdidf.S",
|
||||
"i386/floatdisf.S",
|
||||
"i386/floatdixf.S",
|
||||
"i386/floatundidf.S",
|
||||
"i386/floatundisf.S",
|
||||
"i386/floatundixf.S",
|
||||
"i386/lshrdi3.S",
|
||||
"i386/moddi3.S",
|
||||
"i386/muldi3.S",
|
||||
"i386/udivdi3.S",
|
||||
"i386/umoddi3.S"]);
|
||||
}
|
||||
}
|
||||
|
||||
if target.contains("arm") && !target.contains("ios") {
|
||||
sources.extend(&["arm/aeabi_cdcmp.S",
|
||||
"arm/aeabi_cdcmpeq_check_nan.c",
|
||||
"arm/aeabi_cfcmp.S",
|
||||
"arm/aeabi_cfcmpeq_check_nan.c",
|
||||
"arm/aeabi_dcmp.S",
|
||||
"arm/aeabi_div0.c",
|
||||
"arm/aeabi_drsub.c",
|
||||
"arm/aeabi_fcmp.S",
|
||||
"arm/aeabi_frsub.c",
|
||||
"arm/aeabi_idivmod.S",
|
||||
"arm/aeabi_ldivmod.S",
|
||||
"arm/aeabi_memcmp.S",
|
||||
"arm/aeabi_memcpy.S",
|
||||
"arm/aeabi_memmove.S",
|
||||
"arm/aeabi_memset.S",
|
||||
"arm/aeabi_uidivmod.S",
|
||||
"arm/aeabi_uldivmod.S",
|
||||
"arm/bswapdi2.S",
|
||||
"arm/bswapsi2.S",
|
||||
"arm/clzdi2.S",
|
||||
"arm/clzsi2.S",
|
||||
"arm/comparesf2.S",
|
||||
"arm/divmodsi4.S",
|
||||
"arm/divsi3.S",
|
||||
"arm/modsi3.S",
|
||||
"arm/switch16.S",
|
||||
"arm/switch32.S",
|
||||
"arm/switch8.S",
|
||||
"arm/switchu8.S",
|
||||
"arm/sync_synchronize.S",
|
||||
"arm/udivmodsi4.S",
|
||||
"arm/udivsi3.S",
|
||||
"arm/umodsi3.S"]);
|
||||
}
|
||||
|
||||
if target.contains("armv7") {
|
||||
sources.extend(&["arm/sync_fetch_and_add_4.S",
|
||||
"arm/sync_fetch_and_add_8.S",
|
||||
"arm/sync_fetch_and_and_4.S",
|
||||
"arm/sync_fetch_and_and_8.S",
|
||||
"arm/sync_fetch_and_max_4.S",
|
||||
"arm/sync_fetch_and_max_8.S",
|
||||
"arm/sync_fetch_and_min_4.S",
|
||||
"arm/sync_fetch_and_min_8.S",
|
||||
"arm/sync_fetch_and_nand_4.S",
|
||||
"arm/sync_fetch_and_nand_8.S",
|
||||
"arm/sync_fetch_and_or_4.S",
|
||||
"arm/sync_fetch_and_or_8.S",
|
||||
"arm/sync_fetch_and_sub_4.S",
|
||||
"arm/sync_fetch_and_sub_8.S",
|
||||
"arm/sync_fetch_and_umax_4.S",
|
||||
"arm/sync_fetch_and_umax_8.S",
|
||||
"arm/sync_fetch_and_umin_4.S",
|
||||
"arm/sync_fetch_and_umin_8.S",
|
||||
"arm/sync_fetch_and_xor_4.S",
|
||||
"arm/sync_fetch_and_xor_8.S"]);
|
||||
}
|
||||
|
||||
if target.contains("eabihf") {
|
||||
sources.extend(&["arm/adddf3vfp.S",
|
||||
"arm/addsf3vfp.S",
|
||||
"arm/divdf3vfp.S",
|
||||
"arm/divsf3vfp.S",
|
||||
"arm/eqdf2vfp.S",
|
||||
"arm/eqsf2vfp.S",
|
||||
"arm/extendsfdf2vfp.S",
|
||||
"arm/fixdfsivfp.S",
|
||||
"arm/fixsfsivfp.S",
|
||||
"arm/fixunsdfsivfp.S",
|
||||
"arm/fixunssfsivfp.S",
|
||||
"arm/floatsidfvfp.S",
|
||||
"arm/floatsisfvfp.S",
|
||||
"arm/floatunssidfvfp.S",
|
||||
"arm/floatunssisfvfp.S",
|
||||
"arm/gedf2vfp.S",
|
||||
"arm/gesf2vfp.S",
|
||||
"arm/gtdf2vfp.S",
|
||||
"arm/gtsf2vfp.S",
|
||||
"arm/ledf2vfp.S",
|
||||
"arm/lesf2vfp.S",
|
||||
"arm/ltdf2vfp.S",
|
||||
"arm/ltsf2vfp.S",
|
||||
"arm/muldf3vfp.S",
|
||||
"arm/mulsf3vfp.S",
|
||||
"arm/negdf2vfp.S",
|
||||
"arm/negsf2vfp.S",
|
||||
"arm/nedf2vfp.S",
|
||||
"arm/nesf2vfp.S",
|
||||
"arm/restore_vfp_d8_d15_regs.S",
|
||||
"arm/save_vfp_d8_d15_regs.S",
|
||||
"arm/subdf3vfp.S",
|
||||
"arm/subsf3vfp.S",
|
||||
"arm/truncdfsf2vfp.S",
|
||||
"arm/unorddf2vfp.S",
|
||||
"arm/unordsf2vfp.S"]);
|
||||
}
|
||||
|
||||
if target.contains("aarch64") {
|
||||
sources.extend(&["comparetf2.c",
|
||||
"extenddftf2.c",
|
||||
"extendsftf2.c",
|
||||
"fixtfdi.c",
|
||||
"fixtfsi.c",
|
||||
"fixtfti.c",
|
||||
"fixunstfdi.c",
|
||||
"fixunstfsi.c",
|
||||
"fixunstfti.c",
|
||||
"floatditf.c",
|
||||
"floatsitf.c",
|
||||
"floatunditf.c",
|
||||
"floatunsitf.c",
|
||||
"multc3.c",
|
||||
"trunctfdf2.c",
|
||||
"trunctfsf2.c"]);
|
||||
}
|
||||
|
||||
for src in sources.map.values() {
|
||||
cfg.file(Path::new("../compiler-rt/lib/builtins").join(src));
|
||||
}
|
||||
|
||||
cfg.compile("libcompiler-rt.a");
|
||||
}
|
||||
19
src/libcompiler_builtins/lib.rs
Normal file
19
src/libcompiler_builtins/lib.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![cfg_attr(not(stage0), feature(compiler_builtins))]
|
||||
#![no_std]
|
||||
#![cfg_attr(not(stage0), compiler_builtins)]
|
||||
#![unstable(feature = "compiler_builtins_lib",
|
||||
reason = "internal implementation detail of rustc right now",
|
||||
issue = "0")]
|
||||
#![crate_name = "compiler_builtins"]
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(staged_api)]
|
||||
|
|
@ -317,6 +317,7 @@ impl<T:Copy> Clone for Cell<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T:Default + Copy> Default for Cell<T> {
|
||||
/// Creates a `Cell<T>`, with the `Default` value for T.
|
||||
#[inline]
|
||||
fn default() -> Cell<T> {
|
||||
Cell::new(Default::default())
|
||||
|
|
@ -758,6 +759,7 @@ impl<T: Clone> Clone for RefCell<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T:Default> Default for RefCell<T> {
|
||||
/// Creates a `RefCell<T>`, with the `Default` value for T.
|
||||
#[inline]
|
||||
fn default() -> RefCell<T> {
|
||||
RefCell::new(Default::default())
|
||||
|
|
@ -1139,6 +1141,7 @@ impl<T: ?Sized> UnsafeCell<T> {
|
|||
|
||||
#[stable(feature = "unsafe_cell_default", since = "1.9.0")]
|
||||
impl<T: Default> Default for UnsafeCell<T> {
|
||||
/// Creates an `UnsafeCell`, with the `Default` value for T.
|
||||
fn default() -> UnsafeCell<T> {
|
||||
UnsafeCell::new(Default::default())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,10 +14,14 @@
|
|||
//! assign them or pass them as arguments, the receiver will get a copy,
|
||||
//! leaving the original value in place. These types do not require
|
||||
//! allocation to copy and do not have finalizers (i.e. they do not
|
||||
//! contain owned boxes or implement `Drop`), so the compiler considers
|
||||
//! contain owned boxes or implement [`Drop`]), so the compiler considers
|
||||
//! them cheap and safe to copy. For other types copies must be made
|
||||
//! explicitly, by convention implementing the `Clone` trait and calling
|
||||
//! the `clone` method.
|
||||
//! explicitly, by convention implementing the [`Clone`] trait and calling
|
||||
//! the [`clone`][clone] method.
|
||||
//!
|
||||
//! [`Clone`]: trait.Clone.html
|
||||
//! [clone]: trait.Clone.html#tymethod.clone
|
||||
//! [`Drop`]: ../../std/ops/trait.Drop.html
|
||||
//!
|
||||
//! Basic usage example:
|
||||
//!
|
||||
|
|
@ -46,22 +50,22 @@
|
|||
|
||||
/// A common trait for the ability to explicitly duplicate an object.
|
||||
///
|
||||
/// Differs from `Copy` in that `Copy` is implicit and extremely inexpensive, while
|
||||
/// Differs from [`Copy`] in that [`Copy`] is implicit and extremely inexpensive, while
|
||||
/// `Clone` is always explicit and may or may not be expensive. In order to enforce
|
||||
/// these characteristics, Rust does not allow you to reimplement `Copy`, but you
|
||||
/// these characteristics, Rust does not allow you to reimplement [`Copy`], but you
|
||||
/// may reimplement `Clone` and run arbitrary code.
|
||||
///
|
||||
/// Since `Clone` is more general than `Copy`, you can automatically make anything
|
||||
/// `Copy` be `Clone` as well.
|
||||
/// Since `Clone` is more general than [`Copy`], you can automatically make anything
|
||||
/// [`Copy`] be `Clone` as well.
|
||||
///
|
||||
/// ## Derivable
|
||||
///
|
||||
/// This trait can be used with `#[derive]` if all fields are `Clone`. The `derive`d
|
||||
/// implementation of `clone()` calls `clone()` on each field.
|
||||
/// implementation of [`clone()`] calls [`clone()`] on each field.
|
||||
///
|
||||
/// ## How can I implement `Clone`?
|
||||
///
|
||||
/// Types that are `Copy` should have a trivial implementation of `Clone`. More formally:
|
||||
/// Types that are [`Copy`] should have a trivial implementation of `Clone`. More formally:
|
||||
/// if `T: Copy`, `x: T`, and `y: &T`, then `let x = y.clone();` is equivalent to `let x = *y;`.
|
||||
/// Manual implementations should be careful to uphold this invariant; however, unsafe code
|
||||
/// must not rely on it to ensure memory safety.
|
||||
|
|
@ -70,6 +74,9 @@
|
|||
/// library only implements `Clone` up until arrays of size 32. In this case, the implementation of
|
||||
/// `Clone` cannot be `derive`d, but can be implemented as:
|
||||
///
|
||||
/// [`Copy`]: ../../std/marker/trait.Copy.html
|
||||
/// [`clone()`]: trait.Clone.html#tymethod.clone
|
||||
///
|
||||
/// ```
|
||||
/// #[derive(Copy)]
|
||||
/// struct Stats {
|
||||
|
|
@ -106,10 +113,23 @@ pub trait Clone : Sized {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME(aburka): this method is used solely by #[derive] to
|
||||
// assert that every component of a type implements Clone.
|
||||
// FIXME(aburka): these structs are used solely by #[derive] to
|
||||
// assert that every component of a type implements Clone or Copy.
|
||||
//
|
||||
// This should never be called by user code.
|
||||
// These structs should never appear in user code.
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[unstable(feature = "derive_clone_copy",
|
||||
reason = "deriving hack, should not be public",
|
||||
issue = "0")]
|
||||
pub struct AssertParamIsClone<T: Clone + ?Sized> { _field: ::marker::PhantomData<T> }
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[unstable(feature = "derive_clone_copy",
|
||||
reason = "deriving hack, should not be public",
|
||||
issue = "0")]
|
||||
pub struct AssertParamIsCopy<T: Copy + ?Sized> { _field: ::marker::PhantomData<T> }
|
||||
#[cfg(stage0)]
|
||||
#[doc(hidden)]
|
||||
#[inline(always)]
|
||||
#[unstable(feature = "derive_clone_copy",
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ pub trait PartialEq<Rhs: ?Sized = Self> {
|
|||
/// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has
|
||||
/// no extra methods, it is only informing the compiler that this is an
|
||||
/// equivalence relation rather than a partial equivalence relation. Note that
|
||||
/// the `derive` strategy requires all fields are `PartialEq`, which isn't
|
||||
/// the `derive` strategy requires all fields are `Eq`, which isn't
|
||||
/// always desired.
|
||||
///
|
||||
/// ## How can I implement `Eq`?
|
||||
|
|
@ -165,6 +165,17 @@ pub trait Eq: PartialEq<Self> {
|
|||
fn assert_receiver_is_total_eq(&self) {}
|
||||
}
|
||||
|
||||
// FIXME: this struct is used solely by #[derive] to
|
||||
// assert that every component of a type implements Eq.
|
||||
//
|
||||
// This struct should never appear in user code.
|
||||
#[doc(hidden)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[unstable(feature = "derive_eq",
|
||||
reason = "deriving hack, should not be public",
|
||||
issue = "0")]
|
||||
pub struct AssertParamIsEq<T: Eq + ?Sized> { _field: ::marker::PhantomData<T> }
|
||||
|
||||
/// An `Ordering` is the result of a comparison between two values.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
|
|||
|
|
@ -92,6 +92,22 @@ pub trait AsRef<T: ?Sized> {
|
|||
/// [`Option<T>`]: ../../std/option/enum.Option.html
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// [`Box<T>`] implements `AsMut<T>`:
|
||||
///
|
||||
/// [`Box<T>`]: ../../std/boxed/struct.Box.html
|
||||
///
|
||||
/// ```
|
||||
/// fn add_one<T: AsMut<u64>>(num: &mut T) {
|
||||
/// *num.as_mut() += 1;
|
||||
/// }
|
||||
///
|
||||
/// let mut boxed_num = Box::new(0);
|
||||
/// add_one(&mut boxed_num);
|
||||
/// assert_eq!(*boxed_num, 1);
|
||||
/// ```
|
||||
///
|
||||
/// # Generic Impls
|
||||
///
|
||||
/// - `AsMut` auto-dereferences if the inner type is a reference or a mutable
|
||||
|
|
|
|||
|
|
@ -272,10 +272,14 @@ impl<'a> Arguments<'a> {
|
|||
/// safely be done so, so no constructors are given and the fields are private
|
||||
/// to prevent modification.
|
||||
///
|
||||
/// The `format_args!` macro will safely create an instance of this structure
|
||||
/// The [`format_args!`] macro will safely create an instance of this structure
|
||||
/// and pass it to a function or closure, passed as the first argument. The
|
||||
/// macro validates the format string at compile-time so usage of the `write`
|
||||
/// and `format` functions can be safely performed.
|
||||
/// macro validates the format string at compile-time so usage of the [`write`]
|
||||
/// and [`format`] functions can be safely performed.
|
||||
///
|
||||
/// [`format_args!`]: ../../std/macro.format_args.html
|
||||
/// [`format`]: ../../std/fmt/fn.format.html
|
||||
/// [`write`]: ../../std/fmt/fn.write.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Arguments<'a> {
|
||||
|
|
|
|||
|
|
@ -333,6 +333,7 @@ impl<S: Sip> Clone for Hasher<S> {
|
|||
}
|
||||
|
||||
impl<S: Sip> Default for Hasher<S> {
|
||||
/// Creates a `Hasher<S>` with the two initial keys set to 0.
|
||||
#[inline]
|
||||
fn default() -> Hasher<S> {
|
||||
Hasher::new_with_keys(0, 0)
|
||||
|
|
|
|||
|
|
@ -194,6 +194,20 @@ extern "rust-intrinsic" {
|
|||
/// own, or if it does not enable any significant optimizations.
|
||||
pub fn assume(b: bool);
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
/// Hints to the compiler that branch condition is likely to be true.
|
||||
/// Returns the value passed to it.
|
||||
///
|
||||
/// Any use other than with `if` statements will probably not have an effect.
|
||||
pub fn likely(b: bool) -> bool;
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
/// Hints to the compiler that branch condition is likely to be false.
|
||||
/// Returns the value passed to it.
|
||||
///
|
||||
/// Any use other than with `if` statements will probably not have an effect.
|
||||
pub fn unlikely(b: bool) -> bool;
|
||||
|
||||
/// Executes a breakpoint trap, for inspection by a debugger.
|
||||
pub fn breakpoint();
|
||||
|
||||
|
|
@ -262,22 +276,25 @@ extern "rust-intrinsic" {
|
|||
/// Moves a value out of scope without running drop glue.
|
||||
pub fn forget<T>(_: T) -> ();
|
||||
|
||||
/// Reinterprets the bits of a value of one type as another type; both types
|
||||
/// must have the same size. Neither the original, nor the result, may be an
|
||||
/// [invalid value] (../../nomicon/meet-safe-and-unsafe.html).
|
||||
/// Reinterprets the bits of a value of one type as another type.
|
||||
///
|
||||
/// Both types must have the same size. Neither the original, nor the result,
|
||||
/// may be an [invalid value](../../nomicon/meet-safe-and-unsafe.html).
|
||||
///
|
||||
/// `transmute` is semantically equivalent to a bitwise move of one type
|
||||
/// into another. It copies the bits from the destination type into the
|
||||
/// source type, then forgets the original. It's equivalent to C's `memcpy`
|
||||
/// under the hood, just like `transmute_copy`.
|
||||
/// into another. It copies the bits from the source value into the
|
||||
/// destination value, then forgets the original. It's equivalent to C's
|
||||
/// `memcpy` under the hood, just like `transmute_copy`.
|
||||
///
|
||||
/// `transmute` is incredibly unsafe. There are a vast number of ways to
|
||||
/// cause undefined behavior with this function. `transmute` should be
|
||||
/// `transmute` is **incredibly** unsafe. There are a vast number of ways to
|
||||
/// cause [undefined behavior][ub] with this function. `transmute` should be
|
||||
/// the absolute last resort.
|
||||
///
|
||||
/// The [nomicon](../../nomicon/transmutes.html) has additional
|
||||
/// documentation.
|
||||
///
|
||||
/// [ub]: ../../reference.html#behavior-considered-undefined
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// There are a few things that `transmute` is really useful for.
|
||||
|
|
@ -292,7 +309,8 @@ extern "rust-intrinsic" {
|
|||
/// assert_eq!(bitpattern, 0x3F800000);
|
||||
/// ```
|
||||
///
|
||||
/// Turning a pointer into a function pointer:
|
||||
/// Turning a pointer into a function pointer. This is *not* portable to
|
||||
/// machines where function pointers and data pointers have different sizes.
|
||||
///
|
||||
/// ```
|
||||
/// fn foo() -> i32 {
|
||||
|
|
@ -305,8 +323,8 @@ extern "rust-intrinsic" {
|
|||
/// assert_eq!(function(), 0);
|
||||
/// ```
|
||||
///
|
||||
/// Extending a lifetime, or shortening an invariant lifetime; this is
|
||||
/// advanced, very unsafe rust:
|
||||
/// Extending a lifetime, or shortening an invariant lifetime. This is
|
||||
/// advanced, very unsafe Rust!
|
||||
///
|
||||
/// ```
|
||||
/// struct R<'a>(&'a i32);
|
||||
|
|
@ -322,11 +340,9 @@ extern "rust-intrinsic" {
|
|||
///
|
||||
/// # Alternatives
|
||||
///
|
||||
/// However, many uses of `transmute` can be achieved through other means.
|
||||
/// `transmute` can transform any type into any other, with just the caveat
|
||||
/// that they're the same size, and often interesting results occur. Below
|
||||
/// are common applications of `transmute` which can be replaced with safe
|
||||
/// applications of `as`:
|
||||
/// Don't despair: many uses of `transmute` can be achieved through other means.
|
||||
/// Below are common applications of `transmute` which can be replaced with safer
|
||||
/// constructs.
|
||||
///
|
||||
/// Turning a pointer into a `usize`:
|
||||
///
|
||||
|
|
@ -335,6 +351,7 @@ extern "rust-intrinsic" {
|
|||
/// let ptr_num_transmute = unsafe {
|
||||
/// std::mem::transmute::<&i32, usize>(ptr)
|
||||
/// };
|
||||
///
|
||||
/// // Use an `as` cast instead
|
||||
/// let ptr_num_cast = ptr as *const i32 as usize;
|
||||
/// ```
|
||||
|
|
@ -346,6 +363,7 @@ extern "rust-intrinsic" {
|
|||
/// let ref_transmuted = unsafe {
|
||||
/// std::mem::transmute::<*mut i32, &mut i32>(ptr)
|
||||
/// };
|
||||
///
|
||||
/// // Use a reborrow instead
|
||||
/// let ref_casted = unsafe { &mut *ptr };
|
||||
/// ```
|
||||
|
|
@ -357,6 +375,7 @@ extern "rust-intrinsic" {
|
|||
/// let val_transmuted = unsafe {
|
||||
/// std::mem::transmute::<&mut i32, &mut u32>(ptr)
|
||||
/// };
|
||||
///
|
||||
/// // Now, put together `as` and reborrowing - note the chaining of `as`
|
||||
/// // `as` is not transitive
|
||||
/// let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) };
|
||||
|
|
@ -368,9 +387,11 @@ extern "rust-intrinsic" {
|
|||
/// // this is not a good way to do this.
|
||||
/// let slice = unsafe { std::mem::transmute::<&str, &[u8]>("Rust") };
|
||||
/// assert_eq!(slice, &[82, 117, 115, 116]);
|
||||
///
|
||||
/// // You could use `str::as_bytes`
|
||||
/// let slice = "Rust".as_bytes();
|
||||
/// assert_eq!(slice, &[82, 117, 115, 116]);
|
||||
///
|
||||
/// // Or, just use a byte string, if you have control over the string
|
||||
/// // literal
|
||||
/// assert_eq!(b"Rust", &[82, 117, 115, 116]);
|
||||
|
|
@ -381,18 +402,21 @@ extern "rust-intrinsic" {
|
|||
/// ```
|
||||
/// let store = [0, 1, 2, 3];
|
||||
/// let mut v_orig = store.iter().collect::<Vec<&i32>>();
|
||||
///
|
||||
/// // Using transmute: this is Undefined Behavior, and a bad idea.
|
||||
/// // However, it is no-copy.
|
||||
/// let v_transmuted = unsafe {
|
||||
/// std::mem::transmute::<Vec<&i32>, Vec<Option<&i32>>>(
|
||||
/// v_orig.clone())
|
||||
/// };
|
||||
///
|
||||
/// // This is the suggested, safe way.
|
||||
/// // It does copy the entire Vector, though, into a new array.
|
||||
/// // It does copy the entire vector, though, into a new array.
|
||||
/// let v_collected = v_orig.clone()
|
||||
/// .into_iter()
|
||||
/// .map(|r| Some(r))
|
||||
/// .collect::<Vec<Option<&i32>>>();
|
||||
///
|
||||
/// // The no-copy, unsafe way, still using transmute, but not UB.
|
||||
/// // This is equivalent to the original, but safer, and reuses the
|
||||
/// // same Vec internals. Therefore the new inner type must have the
|
||||
|
|
@ -412,6 +436,7 @@ extern "rust-intrinsic" {
|
|||
///
|
||||
/// ```
|
||||
/// use std::{slice, mem};
|
||||
///
|
||||
/// // There are multiple ways to do this; and there are multiple problems
|
||||
/// // with the following, transmute, way.
|
||||
/// fn split_at_mut_transmute<T>(slice: &mut [T], mid: usize)
|
||||
|
|
@ -426,6 +451,7 @@ extern "rust-intrinsic" {
|
|||
/// (&mut slice[0..mid], &mut slice2[mid..len])
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // This gets rid of the typesafety problems; `&mut *` will *only* give
|
||||
/// // you an `&mut T` from an `&mut T` or `*mut T`.
|
||||
/// fn split_at_mut_casts<T>(slice: &mut [T], mid: usize)
|
||||
|
|
@ -439,6 +465,7 @@ extern "rust-intrinsic" {
|
|||
/// (&mut slice[0..mid], &mut slice2[mid..len])
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // This is how the standard library does it. This is the best method, if
|
||||
/// // you need to do something like this
|
||||
/// fn split_at_stdlib<T>(slice: &mut [T], mid: usize)
|
||||
|
|
|
|||
|
|
@ -1657,6 +1657,32 @@ pub trait Iterator {
|
|||
.map(|(_, x)| x)
|
||||
}
|
||||
|
||||
/// Returns the element that gives the maximum value with respect to the
|
||||
/// specified comparison function.
|
||||
///
|
||||
/// Returns the rightmost element if the comparison determines two elements
|
||||
/// to be equally maximum.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iter_max_by)]
|
||||
/// let a = [-3_i32, 0, 1, 5, -10];
|
||||
/// assert_eq!(*a.iter().max_by(|x, y| x.cmp(y)).unwrap(), 5);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "iter_max_by", issue="36105")]
|
||||
fn max_by<F>(self, mut compare: F) -> Option<Self::Item>
|
||||
where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering,
|
||||
{
|
||||
select_fold1(self,
|
||||
|_| (),
|
||||
// switch to y even if it is only equal, to preserve
|
||||
// stability.
|
||||
|_, x, _, y| Ordering::Greater != compare(x, y))
|
||||
.map(|(_, x)| x)
|
||||
}
|
||||
|
||||
/// Returns the element that gives the minimum value from the
|
||||
/// specified function.
|
||||
///
|
||||
|
|
@ -1681,6 +1707,33 @@ pub trait Iterator {
|
|||
.map(|(_, x)| x)
|
||||
}
|
||||
|
||||
/// Returns the element that gives the minimum value with respect to the
|
||||
/// specified comparison function.
|
||||
///
|
||||
/// Returns the latest element if the comparison determines two elements
|
||||
/// to be equally minimum.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iter_min_by)]
|
||||
/// let a = [-3_i32, 0, 1, 5, -10];
|
||||
/// assert_eq!(*a.iter().min_by(|x, y| x.cmp(y)).unwrap(), -10);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "iter_min_by", issue="36105")]
|
||||
fn min_by<F>(self, mut compare: F) -> Option<Self::Item>
|
||||
where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering,
|
||||
{
|
||||
select_fold1(self,
|
||||
|_| (),
|
||||
// switch to y even if it is strictly smaller, to
|
||||
// preserve stability.
|
||||
|_, x, _, y| Ordering::Greater == compare(x, y))
|
||||
.map(|(_, x)| x)
|
||||
}
|
||||
|
||||
|
||||
/// Reverses an iterator's direction.
|
||||
///
|
||||
/// Usually, iterators iterate from left to right. After using `rev()`,
|
||||
|
|
@ -1814,7 +1867,8 @@ pub trait Iterator {
|
|||
/// # Panics
|
||||
///
|
||||
/// When calling `sum` and a primitive integer type is being returned, this
|
||||
/// method will panic if the computation overflows.
|
||||
/// method will panic if the computation overflows and debug assertions are
|
||||
/// enabled.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -1841,7 +1895,8 @@ pub trait Iterator {
|
|||
/// # Panics
|
||||
///
|
||||
/// When calling `product` and a primitive integer type is being returned,
|
||||
/// this method will panic if the computation overflows.
|
||||
/// method will panic if the computation overflows and debug assertions are
|
||||
/// enabled.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
|||
|
|
@ -643,7 +643,9 @@ impl<A, B> FusedIterator for Chain<A, B>
|
|||
pub struct Zip<A, B> {
|
||||
a: A,
|
||||
b: B,
|
||||
spec: <(A, B) as ZipImplData>::Data,
|
||||
// index and len are only used by the specialized version of zip
|
||||
index: usize,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -685,17 +687,6 @@ trait ZipImpl<A, B> {
|
|||
B: DoubleEndedIterator + ExactSizeIterator;
|
||||
}
|
||||
|
||||
// Zip specialization data members
|
||||
#[doc(hidden)]
|
||||
trait ZipImplData {
|
||||
type Data: 'static + Clone + Default + fmt::Debug;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<T> ZipImplData for T {
|
||||
default type Data = ();
|
||||
}
|
||||
|
||||
// General Zip impl
|
||||
#[doc(hidden)]
|
||||
impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
||||
|
|
@ -706,7 +697,8 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
|||
Zip {
|
||||
a: a,
|
||||
b: b,
|
||||
spec: Default::default(), // unused
|
||||
index: 0, // unused
|
||||
len: 0, // unused
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -759,20 +751,6 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
|||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Default, Debug, Clone)]
|
||||
struct ZipImplFields {
|
||||
index: usize,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<A, B> ZipImplData for (A, B)
|
||||
where A: TrustedRandomAccess, B: TrustedRandomAccess
|
||||
{
|
||||
type Data = ZipImplFields;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
||||
where A: TrustedRandomAccess, B: TrustedRandomAccess
|
||||
|
|
@ -782,18 +760,16 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
|||
Zip {
|
||||
a: a,
|
||||
b: b,
|
||||
spec: ZipImplFields {
|
||||
index: 0,
|
||||
len: len,
|
||||
}
|
||||
index: 0,
|
||||
len: len,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<(A::Item, B::Item)> {
|
||||
if self.spec.index < self.spec.len {
|
||||
let i = self.spec.index;
|
||||
self.spec.index += 1;
|
||||
if self.index < self.len {
|
||||
let i = self.index;
|
||||
self.index += 1;
|
||||
unsafe {
|
||||
Some((self.a.get_unchecked(i), self.b.get_unchecked(i)))
|
||||
}
|
||||
|
|
@ -804,7 +780,7 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
|||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.spec.len - self.spec.index;
|
||||
let len = self.len - self.index;
|
||||
(len, Some(len))
|
||||
}
|
||||
|
||||
|
|
@ -813,9 +789,9 @@ impl<A, B> ZipImpl<A, B> for Zip<A, B>
|
|||
where A: DoubleEndedIterator + ExactSizeIterator,
|
||||
B: DoubleEndedIterator + ExactSizeIterator
|
||||
{
|
||||
if self.spec.index < self.spec.len {
|
||||
self.spec.len -= 1;
|
||||
let i = self.spec.len;
|
||||
if self.index < self.len {
|
||||
self.len -= 1;
|
||||
let i = self.len;
|
||||
unsafe {
|
||||
Some((self.a.get_unchecked(i), self.b.get_unchecked(i)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
use ops::{Mul, Add};
|
||||
|
||||
/// Conversion from an `Iterator`.
|
||||
///
|
||||
|
|
@ -581,41 +582,34 @@ pub trait Product<A = Self>: Sized {
|
|||
fn product<I: Iterator<Item=A>>(iter: I) -> Self;
|
||||
}
|
||||
|
||||
// NB: explicitly use Add and Mul here to inherit overflow checks
|
||||
macro_rules! integer_sum_product {
|
||||
($($a:ident)*) => ($(
|
||||
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
|
||||
impl Sum for $a {
|
||||
fn sum<I: Iterator<Item=$a>>(iter: I) -> $a {
|
||||
iter.fold(0, |a, b| {
|
||||
a.checked_add(b).expect("overflow in sum")
|
||||
})
|
||||
iter.fold(0, Add::add)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
|
||||
impl Product for $a {
|
||||
fn product<I: Iterator<Item=$a>>(iter: I) -> $a {
|
||||
iter.fold(1, |a, b| {
|
||||
a.checked_mul(b).expect("overflow in product")
|
||||
})
|
||||
iter.fold(1, Mul::mul)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
|
||||
impl<'a> Sum<&'a $a> for $a {
|
||||
fn sum<I: Iterator<Item=&'a $a>>(iter: I) -> $a {
|
||||
iter.fold(0, |a, b| {
|
||||
a.checked_add(*b).expect("overflow in sum")
|
||||
})
|
||||
iter.cloned().fold(0, Add::add)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
|
||||
impl<'a> Product<&'a $a> for $a {
|
||||
fn product<I: Iterator<Item=&'a $a>>(iter: I) -> $a {
|
||||
iter.fold(1, |a, b| {
|
||||
a.checked_mul(*b).expect("overflow in product")
|
||||
})
|
||||
iter.cloned().fold(1, Mul::mul)
|
||||
}
|
||||
}
|
||||
)*)
|
||||
|
|
|
|||
|
|
@ -119,6 +119,44 @@ macro_rules! assert_eq {
|
|||
});
|
||||
}
|
||||
|
||||
/// Asserts that two expressions are not equal to each other.
|
||||
///
|
||||
/// On panic, this macro will print the values of the expressions with their
|
||||
/// debug representations.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let a = 3;
|
||||
/// let b = 2;
|
||||
/// assert_ne!(a, b);
|
||||
/// ```
|
||||
#[macro_export]
|
||||
#[stable(feature = "assert_ne", since = "1.12.0")]
|
||||
macro_rules! assert_ne {
|
||||
($left:expr , $right:expr) => ({
|
||||
match (&$left, &$right) {
|
||||
(left_val, right_val) => {
|
||||
if *left_val == *right_val {
|
||||
panic!("assertion failed: `(left != right)` \
|
||||
(left: `{:?}`, right: `{:?}`)", left_val, right_val)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
($left:expr , $right:expr, $($arg:tt)*) => ({
|
||||
match (&($left), &($right)) {
|
||||
(left_val, right_val) => {
|
||||
if *left_val == *right_val {
|
||||
panic!("assertion failed: `(left != right)` \
|
||||
(left: `{:?}`, right: `{:?}`): {}", left_val, right_val,
|
||||
format_args!($($arg)*))
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Ensure that a boolean expression is `true` at runtime.
|
||||
///
|
||||
/// This will invoke the `panic!` macro if the provided expression cannot be
|
||||
|
|
@ -189,10 +227,44 @@ macro_rules! debug_assert_eq {
|
|||
($($arg:tt)*) => (if cfg!(debug_assertions) { assert_eq!($($arg)*); })
|
||||
}
|
||||
|
||||
/// Helper macro for unwrapping `Result` values while returning early with an
|
||||
/// error if the value of the expression is `Err`. Can only be used in
|
||||
/// functions that return `Result` because of the early return of `Err` that
|
||||
/// it provides.
|
||||
/// Asserts that two expressions are not equal to each other.
|
||||
///
|
||||
/// On panic, this macro will print the values of the expressions with their
|
||||
/// debug representations.
|
||||
///
|
||||
/// Unlike `assert_ne!`, `debug_assert_ne!` statements are only enabled in non
|
||||
/// optimized builds by default. An optimized build will omit all
|
||||
/// `debug_assert_ne!` statements unless `-C debug-assertions` is passed to the
|
||||
/// compiler. This makes `debug_assert_ne!` useful for checks that are too
|
||||
/// expensive to be present in a release build but may be helpful during
|
||||
/// development.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let a = 3;
|
||||
/// let b = 2;
|
||||
/// debug_assert_ne!(a, b);
|
||||
/// ```
|
||||
#[macro_export]
|
||||
#[stable(feature = "assert_ne", since = "1.12.0")]
|
||||
macro_rules! debug_assert_ne {
|
||||
($($arg:tt)*) => (if cfg!(debug_assertions) { assert_ne!($($arg)*); })
|
||||
}
|
||||
|
||||
/// Helper macro for reducing boilerplate code for matching `Result` together
|
||||
/// with converting downstream errors.
|
||||
///
|
||||
/// `try!` matches the given `Result`. In case of the `Ok` variant, the
|
||||
/// expression has the value of the wrapped value.
|
||||
///
|
||||
/// In case of the `Err` variant, it retrieves the inner error. `try!` then
|
||||
/// performs conversion using `From`. This provides automatic conversion
|
||||
/// between specialized errors and more general ones. The resulting
|
||||
/// error is then immediately returned.
|
||||
///
|
||||
/// Because of the early return, `try!` can only be used in functions that
|
||||
/// return `Result`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -201,18 +273,28 @@ macro_rules! debug_assert_eq {
|
|||
/// use std::fs::File;
|
||||
/// use std::io::prelude::*;
|
||||
///
|
||||
/// fn write_to_file_using_try() -> Result<(), io::Error> {
|
||||
/// enum MyError {
|
||||
/// FileWriteError
|
||||
/// }
|
||||
///
|
||||
/// impl From<io::Error> for MyError {
|
||||
/// fn from(e: io::Error) -> MyError {
|
||||
/// MyError::FileWriteError
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn write_to_file_using_try() -> Result<(), MyError> {
|
||||
/// let mut file = try!(File::create("my_best_friends.txt"));
|
||||
/// try!(file.write_all(b"This is a list of my best friends."));
|
||||
/// println!("I wrote to the file");
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// // This is equivalent to:
|
||||
/// fn write_to_file_using_match() -> Result<(), io::Error> {
|
||||
/// fn write_to_file_using_match() -> Result<(), MyError> {
|
||||
/// let mut file = try!(File::create("my_best_friends.txt"));
|
||||
/// match file.write_all(b"This is a list of my best friends.") {
|
||||
/// Ok(v) => v,
|
||||
/// Err(e) => return Err(e),
|
||||
/// Err(e) => return Err(From::from(e)),
|
||||
/// }
|
||||
/// println!("I wrote to the file");
|
||||
/// Ok(())
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Primitive traits and marker types representing basic 'kinds' of types.
|
||||
//! Primitive traits and types representing basic properties of types.
|
||||
//!
|
||||
//! Rust types can be classified in various useful ways according to
|
||||
//! intrinsic properties of the type. These classifications, often called
|
||||
//! 'kinds', are represented as traits.
|
||||
//! their intrinsic properties. These classifications are represented
|
||||
//! as traits.
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
|
|
@ -22,7 +22,21 @@ use hash::Hasher;
|
|||
|
||||
/// Types that can be transferred across thread boundaries.
|
||||
///
|
||||
/// This trait is automatically derived when the compiler determines it's appropriate.
|
||||
/// This trait is automatically implemented when the compiler determines it's
|
||||
/// appropriate.
|
||||
///
|
||||
/// An example of a non-`Send` type is the reference-counting pointer
|
||||
/// [`rc::Rc`][rc]. If two threads attempt to clone `Rc`s that point to the same
|
||||
/// reference-counted value, they might try to update the reference count at the
|
||||
/// same time, which is [undefined behavior][ub] because `Rc` doesn't use atomic
|
||||
/// operations. Its cousin [`sync::Arc`][arc] does use atomic operations (incurring
|
||||
/// some overhead) and thus is `Send`.
|
||||
///
|
||||
/// See [the Nomicon](../../nomicon/send-and-sync.html) for more details.
|
||||
///
|
||||
/// [rc]: ../../std/rc/struct.Rc.html
|
||||
/// [arc]: ../../std/sync/struct.Arc.html
|
||||
/// [ub]: ../../reference.html#behavior-considered-undefined
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[lang = "send"]
|
||||
#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
|
||||
|
|
@ -38,10 +52,10 @@ impl<T: ?Sized> !Send for *const T { }
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> !Send for *mut T { }
|
||||
|
||||
/// Types with a constant size known at compile-time.
|
||||
/// 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.
|
||||
/// All type parameters have an implicit bound of `Sized`. The special syntax
|
||||
/// `?Sized` can be used to remove this bound if it's not appropriate.
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(dead_code)]
|
||||
|
|
@ -51,6 +65,26 @@ impl<T: ?Sized> !Send for *mut T { }
|
|||
/// // struct FooUse(Foo<[i32]>); // error: Sized is not implemented for [i32]
|
||||
/// struct BarUse(Bar<[i32]>); // OK
|
||||
/// ```
|
||||
///
|
||||
/// The one exception is the implicit `Self` type of a trait, which does not
|
||||
/// get an implicit `Sized` bound. This is because a `Sized` bound prevents
|
||||
/// the trait from being used to form a [trait object]:
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(unused_variables)]
|
||||
/// trait Foo { }
|
||||
/// trait Bar: Sized { }
|
||||
///
|
||||
/// struct Impl;
|
||||
/// impl Foo for Impl { }
|
||||
/// impl Bar for Impl { }
|
||||
///
|
||||
/// let x: &Foo = &Impl; // OK
|
||||
/// // let y: &Bar = &Impl; // error: the trait `Bar` cannot
|
||||
/// // be made into an object
|
||||
/// ```
|
||||
///
|
||||
/// [trait object]: ../../book/trait-objects.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[lang = "sized"]
|
||||
#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"]
|
||||
|
|
@ -59,14 +93,27 @@ pub trait Sized {
|
|||
// Empty.
|
||||
}
|
||||
|
||||
/// Types that can be "unsized" to a dynamically sized type.
|
||||
/// Types that can be "unsized" to a dynamically-sized type.
|
||||
///
|
||||
/// For example, the sized array type `[i8; 2]` implements `Unsize<[i8]>` and
|
||||
/// `Unsize<fmt::Debug>`.
|
||||
///
|
||||
/// All implementations of `Unsize` are provided automatically by the compiler.
|
||||
///
|
||||
/// `Unsize` is used along with [`ops::CoerceUnsized`][coerceunsized] to allow
|
||||
/// "user-defined" containers such as [`rc::Rc`][rc] to contain dynamically-sized
|
||||
/// types. See the [DST coercion RFC][RFC982] for more details.
|
||||
///
|
||||
/// [coerceunsized]: ../ops/trait.CoerceUnsized.html
|
||||
/// [rc]: ../../std/rc/struct.Rc.html
|
||||
/// [RFC982]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md
|
||||
#[unstable(feature = "unsize", issue = "27732")]
|
||||
#[lang="unsize"]
|
||||
pub trait Unsize<T: ?Sized> {
|
||||
// Empty.
|
||||
}
|
||||
|
||||
/// Types that can be copied by simply copying bits (i.e. `memcpy`).
|
||||
/// Types whose values can be duplicated simply by copying bits.
|
||||
///
|
||||
/// By default, variable bindings have 'move semantics.' In other
|
||||
/// words:
|
||||
|
|
@ -87,7 +134,8 @@ pub trait Unsize<T: ?Sized> {
|
|||
/// However, if a type implements `Copy`, it instead has 'copy semantics':
|
||||
///
|
||||
/// ```
|
||||
/// // we can just derive a `Copy` implementation
|
||||
/// // We can derive a `Copy` implementation. `Clone` is also required, as it's
|
||||
/// // a supertrait of `Copy`.
|
||||
/// #[derive(Debug, Copy, Clone)]
|
||||
/// struct Foo;
|
||||
///
|
||||
|
|
@ -100,13 +148,59 @@ pub trait Unsize<T: ?Sized> {
|
|||
/// println!("{:?}", x); // A-OK!
|
||||
/// ```
|
||||
///
|
||||
/// It's important to note that in these two examples, the only difference is if you are allowed to
|
||||
/// access `x` after the assignment: a move is also a bitwise copy under the hood.
|
||||
/// It's important to note that in these two examples, the only difference is whether you
|
||||
/// are allowed to access `x` after the assignment. Under the hood, both a copy and a move
|
||||
/// can result in bits being copied in memory, although this is sometimes optimized away.
|
||||
///
|
||||
/// ## How can I implement `Copy`?
|
||||
///
|
||||
/// There are two ways to implement `Copy` on your type. The simplest is to use `derive`:
|
||||
///
|
||||
/// ```
|
||||
/// #[derive(Copy, Clone)]
|
||||
/// struct MyStruct;
|
||||
/// ```
|
||||
///
|
||||
/// You can also implement `Copy` and `Clone` manually:
|
||||
///
|
||||
/// ```
|
||||
/// struct MyStruct;
|
||||
///
|
||||
/// impl Copy for MyStruct { }
|
||||
///
|
||||
/// impl Clone for MyStruct {
|
||||
/// fn clone(&self) -> MyStruct {
|
||||
/// *self
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// There is a small difference between the two: the `derive` strategy will also place a `Copy`
|
||||
/// bound on type parameters, which isn't always desired.
|
||||
///
|
||||
/// ## What's the difference between `Copy` and `Clone`?
|
||||
///
|
||||
/// Copies happen implicitly, for example as part of an assignment `y = x`. The behavior of
|
||||
/// `Copy` is not overloadable; it is always a simple bit-wise copy.
|
||||
///
|
||||
/// Cloning is an explicit action, `x.clone()`. The implementation of [`Clone`][clone] can
|
||||
/// provide any type-specific behavior necessary to duplicate values safely. For example,
|
||||
/// the implementation of `Clone` for [`String`][string] needs to copy the pointed-to string
|
||||
/// buffer in the heap. A simple bitwise copy of `String` values would merely copy the
|
||||
/// pointer, leading to a double free down the line. For this reason, `String` is `Clone`
|
||||
/// but not `Copy`.
|
||||
///
|
||||
/// `Clone` is a supertrait of `Copy`, so everything which is `Copy` must also implement
|
||||
/// `Clone`. If a type is `Copy` then its `Clone` implementation need only return `*self`
|
||||
/// (see the example above).
|
||||
///
|
||||
/// [clone]: ../clone/trait.Clone.html
|
||||
/// [string]: ../../std/string/struct.String.html
|
||||
///
|
||||
/// ## When can my type be `Copy`?
|
||||
///
|
||||
/// A type can implement `Copy` if all of its components implement `Copy`. For example, this
|
||||
/// `struct` can be `Copy`:
|
||||
/// struct can be `Copy`:
|
||||
///
|
||||
/// ```
|
||||
/// # #[allow(dead_code)]
|
||||
|
|
@ -116,7 +210,8 @@ pub trait Unsize<T: ?Sized> {
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// A `struct` can be `Copy`, and `i32` is `Copy`, so therefore, `Point` is eligible to be `Copy`.
|
||||
/// A struct can be `Copy`, and `i32` is `Copy`, therefore `Point` is eligible to be `Copy`.
|
||||
/// By contrast, consider
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(dead_code)]
|
||||
|
|
@ -126,107 +221,114 @@ pub trait Unsize<T: ?Sized> {
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The `PointList` `struct` cannot implement `Copy`, because `Vec<T>` is not `Copy`. If we
|
||||
/// The struct `PointList` cannot implement `Copy`, because [`Vec<T>`] is not `Copy`. If we
|
||||
/// attempt to derive a `Copy` implementation, we'll get an error:
|
||||
///
|
||||
/// ```text
|
||||
/// the trait `Copy` may not be implemented for this type; field `points` does not implement `Copy`
|
||||
/// ```
|
||||
///
|
||||
/// ## When can my type _not_ be `Copy`?
|
||||
/// ## When *can't* my type be `Copy`?
|
||||
///
|
||||
/// Some types can't be copied safely. For example, copying `&mut T` would create an aliased
|
||||
/// mutable reference, and copying `String` would result in two attempts to free the same buffer.
|
||||
/// mutable reference. Copying [`String`] would duplicate responsibility for managing the `String`'s
|
||||
/// buffer, leading to a double free.
|
||||
///
|
||||
/// Generalizing the latter case, any type implementing `Drop` can't be `Copy`, because it's
|
||||
/// managing some resource besides its own `size_of::<T>()` bytes.
|
||||
/// Generalizing the latter case, any type implementing [`Drop`] can't be `Copy`, because it's
|
||||
/// managing some resource besides its own [`size_of::<T>()`] bytes.
|
||||
///
|
||||
/// ## What if I derive `Copy` on a type that can't?
|
||||
/// If you try to implement `Copy` on a struct or enum containing non-`Copy` data, you will get a
|
||||
/// compile-time error. Specifically, with structs you'll get [E0204] and with enums you'll get
|
||||
/// [E0205].
|
||||
///
|
||||
/// If you try to derive `Copy` on a struct or enum, you will get a compile-time error.
|
||||
/// Specifically, with structs you'll get [E0204](https://doc.rust-lang.org/error-index.html#E0204)
|
||||
/// and with enums you'll get [E0205](https://doc.rust-lang.org/error-index.html#E0205).
|
||||
/// [E0204]: https://doc.rust-lang.org/error-index.html#E0204
|
||||
/// [E0205]: https://doc.rust-lang.org/error-index.html#E0205
|
||||
///
|
||||
/// ## When should my type be `Copy`?
|
||||
/// ## When *should* my type be `Copy`?
|
||||
///
|
||||
/// Generally speaking, if your type _can_ implement `Copy`, it should. There's one important thing
|
||||
/// to consider though: if you think your type may _not_ be able to implement `Copy` in the future,
|
||||
/// then it might be prudent to not implement `Copy`. This is because removing `Copy` is a breaking
|
||||
/// change: that second example would fail to compile if we made `Foo` non-`Copy`.
|
||||
/// Generally speaking, if your type _can_ implement `Copy`, it should. Keep in mind, though,
|
||||
/// that implementing `Copy` is part of the public API of your type. If the type might become
|
||||
/// non-`Copy` in the future, it could be prudent to omit the `Copy` implementation now, to
|
||||
/// avoid a breaking API change.
|
||||
///
|
||||
/// ## Derivable
|
||||
///
|
||||
/// This trait can be used with `#[derive]` if all of its components implement `Copy` and the type
|
||||
/// implements `Clone`. The implementation will copy the bytes of each field using `memcpy`.
|
||||
///
|
||||
/// ## How can I implement `Copy`?
|
||||
///
|
||||
/// There are two ways to implement `Copy` on your type:
|
||||
///
|
||||
/// ```
|
||||
/// #[derive(Copy, Clone)]
|
||||
/// struct MyStruct;
|
||||
/// ```
|
||||
///
|
||||
/// and
|
||||
///
|
||||
/// ```
|
||||
/// struct MyStruct;
|
||||
/// impl Copy for MyStruct {}
|
||||
/// impl Clone for MyStruct { fn clone(&self) -> MyStruct { *self } }
|
||||
/// ```
|
||||
///
|
||||
/// There is a small difference between the two: the `derive` strategy will also place a `Copy`
|
||||
/// bound on type parameters, which isn't always desired.
|
||||
/// [`Vec<T>`]: ../../std/vec/struct.Vec.html
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`Drop`]: ../../std/ops/trait.Drop.html
|
||||
/// [`size_of::<T>()`]: ../../std/mem/fn.size_of.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[lang = "copy"]
|
||||
pub trait Copy : Clone {
|
||||
// Empty.
|
||||
}
|
||||
|
||||
/// Types that can be safely shared between threads when aliased.
|
||||
/// Types for which it is safe to share references between threads.
|
||||
///
|
||||
/// This trait is automatically implemented when the compiler determines
|
||||
/// it's appropriate.
|
||||
///
|
||||
/// The precise definition is: a type `T` is `Sync` if `&T` is
|
||||
/// thread-safe. In other words, there is no possibility of data races
|
||||
/// when passing `&T` references between threads.
|
||||
/// [`Send`][send]. In other words, if there is no possibility of
|
||||
/// [undefined behavior][ub] (including data races) when passing
|
||||
/// `&T` references between threads.
|
||||
///
|
||||
/// As one would expect, primitive types like `u8` and `f64` are all
|
||||
/// `Sync`, and so are simple aggregate types containing them (like
|
||||
/// tuples, structs and enums). More instances of basic `Sync` types
|
||||
/// include "immutable" types like `&T` and those with simple
|
||||
/// inherited mutability, such as `Box<T>`, `Vec<T>` and most other
|
||||
/// collection types. (Generic parameters need to be `Sync` for their
|
||||
/// container to be `Sync`.)
|
||||
/// As one would expect, primitive types like [`u8`][u8] and [`f64`][f64]
|
||||
/// are all `Sync`, and so are simple aggregate types containing them,
|
||||
/// like tuples, structs and enums. More examples of basic `Sync`
|
||||
/// types include "immutable" types like `&T`, and those with simple
|
||||
/// inherited mutability, such as [`Box<T>`][box], [`Vec<T>`][vec] and
|
||||
/// most other collection types. (Generic parameters need to be `Sync`
|
||||
/// for their container to be `Sync`.)
|
||||
///
|
||||
/// A somewhat surprising consequence of the definition is `&mut T` is
|
||||
/// `Sync` (if `T` is `Sync`) even though it seems that it might
|
||||
/// provide unsynchronized mutation. The trick is a mutable reference
|
||||
/// stored in an aliasable reference (that is, `& &mut T`) becomes
|
||||
/// read-only, as if it were a `& &T`, hence there is no risk of a data
|
||||
/// race.
|
||||
/// A somewhat surprising consequence of the definition is that `&mut T`
|
||||
/// is `Sync` (if `T` is `Sync`) even though it seems like that might
|
||||
/// provide unsynchronized mutation. The trick is that a mutable
|
||||
/// reference behind a shared reference (that is, `& &mut T`)
|
||||
/// becomes read-only, as if it were a `& &T`. Hence there is no risk
|
||||
/// of a data race.
|
||||
///
|
||||
/// Types that are not `Sync` are those that have "interior
|
||||
/// mutability" in a non-thread-safe way, such as `Cell` and `RefCell`
|
||||
/// in `std::cell`. These types allow for mutation of their contents
|
||||
/// even when in an immutable, aliasable slot, e.g. the contents of
|
||||
/// `&Cell<T>` can be `.set`, and do not ensure data races are
|
||||
/// impossible, hence they cannot be `Sync`. A higher level example
|
||||
/// of a non-`Sync` type is the reference counted pointer
|
||||
/// `std::rc::Rc`, because any reference `&Rc<T>` can clone a new
|
||||
/// reference, which modifies the reference counts in a non-atomic
|
||||
/// way.
|
||||
/// mutability" in a non-thread-safe form, such as [`cell::Cell`][cell]
|
||||
/// and [`cell::RefCell`][refcell]. These types allow for mutation of
|
||||
/// their contents even through an immutable, shared reference. For
|
||||
/// example the `set` method on `Cell<T>` takes `&self`, so it requires
|
||||
/// only a shared reference `&Cell<T>`. The method performs no
|
||||
/// synchronization, thus `Cell` cannot be `Sync`.
|
||||
///
|
||||
/// Another example of a non-`Sync` type is the reference-counting
|
||||
/// pointer [`rc::Rc`][rc]. Given any reference `&Rc<T>`, you can clone
|
||||
/// a new `Rc<T>`, modifying the reference counts in a non-atomic way.
|
||||
///
|
||||
/// For cases when one does need thread-safe interior mutability,
|
||||
/// types like the atomics in `std::sync` and `Mutex` & `RWLock` in
|
||||
/// the `sync` crate do ensure that any mutation cannot cause data
|
||||
/// races. Hence these types are `Sync`.
|
||||
/// Rust provides [atomic data types], as well as explicit locking via
|
||||
/// [`sync::Mutex`][mutex] and [`sync::RWLock`][rwlock]. These types
|
||||
/// ensure that any mutation cannot cause data races, hence the types
|
||||
/// are `Sync`. Likewise, [`sync::Arc`][arc] provides a thread-safe
|
||||
/// analogue of `Rc`.
|
||||
///
|
||||
/// Any types with interior mutability must also use the `std::cell::UnsafeCell`
|
||||
/// wrapper around the value(s) which can be mutated when behind a `&`
|
||||
/// reference; not doing this is undefined behavior (for example,
|
||||
/// `transmute`-ing from `&T` to `&mut T` is invalid).
|
||||
/// Any types with interior mutability must also use the
|
||||
/// [`cell::UnsafeCell`][unsafecell] wrapper around the value(s) which
|
||||
/// can be mutated through a shared reference. Failing to doing this is
|
||||
/// [undefined behavior][ub]. For example, [`transmute`][transmute]-ing
|
||||
/// from `&T` to `&mut T` is invalid.
|
||||
///
|
||||
/// This trait is automatically derived when the compiler determines it's appropriate.
|
||||
/// See [the Nomicon](../../nomicon/send-and-sync.html) for more
|
||||
/// details about `Sync`.
|
||||
///
|
||||
/// [send]: trait.Send.html
|
||||
/// [u8]: ../../std/primitive.u8.html
|
||||
/// [f64]: ../../std/primitive.f64.html
|
||||
/// [box]: ../../std/boxed/struct.Box.html
|
||||
/// [vec]: ../../std/vec/struct.Vec.html
|
||||
/// [cell]: ../cell/struct.Cell.html
|
||||
/// [refcell]: ../cell/struct.RefCell.html
|
||||
/// [rc]: ../../std/rc/struct.Rc.html
|
||||
/// [arc]: ../../std/sync/struct.Arc.html
|
||||
/// [atomic data types]: ../sync/atomic/index.html
|
||||
/// [mutex]: ../../std/sync/struct.Mutex.html
|
||||
/// [rwlock]: ../../std/sync/struct.RwLock.html
|
||||
/// [unsafecell]: ../cell/struct.UnsafeCell.html
|
||||
/// [ub]: ../../reference.html#behavior-considered-undefined
|
||||
/// [transmute]: ../../std/mem/fn.transmute.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[lang = "sync"]
|
||||
#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"]
|
||||
|
|
@ -295,29 +397,30 @@ macro_rules! impls{
|
|||
)
|
||||
}
|
||||
|
||||
/// `PhantomData<T>` allows you to describe that a type acts as if it stores a value of type `T`,
|
||||
/// even though it does not. This allows you to inform the compiler about certain safety properties
|
||||
/// of your code.
|
||||
/// Zero-sized type used to mark things that "act like" they own a `T`.
|
||||
///
|
||||
/// For a more in-depth explanation of how to use `PhantomData<T>`, please see [the Nomicon].
|
||||
/// Adding a `PhantomData<T>` field to your type tells the compiler that your
|
||||
/// type acts as though it stores a value of type `T`, even though it doesn't
|
||||
/// really. This information is used when computing certain safety properties.
|
||||
///
|
||||
/// [the Nomicon]: ../../nomicon/phantom-data.html
|
||||
/// For a more in-depth explanation of how to use `PhantomData<T>`, please see
|
||||
/// [the Nomicon](../../nomicon/phantom-data.html).
|
||||
///
|
||||
/// # A ghastly note 👻👻👻
|
||||
///
|
||||
/// Though they both have scary names, `PhantomData<T>` and 'phantom types' are related, but not
|
||||
/// identical. Phantom types are a more general concept that don't require `PhantomData<T>` to
|
||||
/// implement, but `PhantomData<T>` is the most common way to implement them in a correct manner.
|
||||
/// Though they both have scary names, `PhantomData` and 'phantom types' are
|
||||
/// related, but not identical. A phantom type parameter is simply a type
|
||||
/// parameter which is never used. In Rust, this often causes the compiler to
|
||||
/// complain, and the solution is to add a "dummy" use by way of `PhantomData`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ## Unused lifetime parameter
|
||||
/// ## Unused lifetime parameters
|
||||
///
|
||||
/// Perhaps the most common time that `PhantomData` is required is
|
||||
/// with a struct that has an unused lifetime parameter, typically as
|
||||
/// part of some unsafe code. For example, here is a struct `Slice`
|
||||
/// that has two pointers of type `*const T`, presumably pointing into
|
||||
/// an array somewhere:
|
||||
/// Perhaps the most common use case for `PhantomData` is a struct that has an
|
||||
/// unused lifetime parameter, typically as part of some unsafe code. For
|
||||
/// example, here is a struct `Slice` that has two pointers of type `*const T`,
|
||||
/// presumably pointing into an array somewhere:
|
||||
///
|
||||
/// ```ignore
|
||||
/// struct Slice<'a, T> {
|
||||
|
|
@ -331,7 +434,7 @@ macro_rules! impls{
|
|||
/// intent is not expressed in the code, since there are no uses of
|
||||
/// the lifetime `'a` and hence it is not clear what data it applies
|
||||
/// to. We can correct this by telling the compiler to act *as if* the
|
||||
/// `Slice` struct contained a borrowed reference `&'a T`:
|
||||
/// `Slice` struct contained a reference `&'a T`:
|
||||
///
|
||||
/// ```
|
||||
/// use std::marker::PhantomData;
|
||||
|
|
@ -340,29 +443,53 @@ macro_rules! impls{
|
|||
/// struct Slice<'a, T: 'a> {
|
||||
/// start: *const T,
|
||||
/// end: *const T,
|
||||
/// phantom: PhantomData<&'a T>
|
||||
/// phantom: PhantomData<&'a T>,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This also in turn requires that we annotate `T:'a`, indicating
|
||||
/// that `T` is a type that can be borrowed for the lifetime `'a`.
|
||||
/// This also in turn requires the annotation `T: 'a`, indicating
|
||||
/// that any references in `T` are valid over the lifetime `'a`.
|
||||
///
|
||||
/// ## Unused type parameters
|
||||
///
|
||||
/// It sometimes happens that there are unused type parameters that
|
||||
/// indicate what type of data a struct is "tied" to, even though that
|
||||
/// data is not actually found in the struct itself. Here is an
|
||||
/// example where this arises when handling external resources over a
|
||||
/// foreign function interface. `PhantomData<T>` can prevent
|
||||
/// mismatches by enforcing types in the method implementations:
|
||||
/// When initializing a `Slice` you simply provide the value
|
||||
/// `PhantomData` for the field `phantom`:
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(dead_code)]
|
||||
/// # trait ResType { fn foo(&self); }
|
||||
/// # use std::marker::PhantomData;
|
||||
/// # struct Slice<'a, T: 'a> {
|
||||
/// # start: *const T,
|
||||
/// # end: *const T,
|
||||
/// # phantom: PhantomData<&'a T>,
|
||||
/// # }
|
||||
/// fn borrow_vec<'a, T>(vec: &'a Vec<T>) -> Slice<'a, T> {
|
||||
/// let ptr = vec.as_ptr();
|
||||
/// Slice {
|
||||
/// start: ptr,
|
||||
/// end: unsafe { ptr.offset(vec.len() as isize) },
|
||||
/// phantom: PhantomData,
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Unused type parameters
|
||||
///
|
||||
/// It sometimes happens that you have unused type parameters which
|
||||
/// indicate what type of data a struct is "tied" to, even though that
|
||||
/// data is not actually found in the struct itself. Here is an
|
||||
/// example where this arises with [FFI]. The foreign interface uses
|
||||
/// handles of type `*mut ()` to refer to Rust values of different
|
||||
/// types. We track the Rust type using a phantom type parameter on
|
||||
/// the struct `ExternalResource` which wraps a handle.
|
||||
///
|
||||
/// [FFI]: ../../book/ffi.html
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(dead_code)]
|
||||
/// # trait ResType { }
|
||||
/// # struct ParamType;
|
||||
/// # mod foreign_lib {
|
||||
/// # pub fn new(_: usize) -> *mut () { 42 as *mut () }
|
||||
/// # pub fn do_stuff(_: *mut (), _: usize) {}
|
||||
/// # pub fn new(_: usize) -> *mut () { 42 as *mut () }
|
||||
/// # pub fn do_stuff(_: *mut (), _: usize) {}
|
||||
/// # }
|
||||
/// # fn convert_params(_: ParamType) -> usize { 42 }
|
||||
/// use std::marker::PhantomData;
|
||||
|
|
@ -389,21 +516,20 @@ macro_rules! impls{
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Indicating ownership
|
||||
/// ## Ownership and the drop check
|
||||
///
|
||||
/// Adding a field of type `PhantomData<T>` also indicates that your
|
||||
/// struct owns data of type `T`. This in turn implies that when your
|
||||
/// struct is dropped, it may in turn drop one or more instances of
|
||||
/// the type `T`, though that may not be apparent from the other
|
||||
/// structure of the type itself. This is commonly necessary if the
|
||||
/// structure is using a raw pointer like `*mut T` whose referent
|
||||
/// may be dropped when the type is dropped, as a `*mut T` is
|
||||
/// otherwise not treated as owned.
|
||||
/// Adding a field of type `PhantomData<T>` indicates that your
|
||||
/// type owns data of type `T`. This in turn implies that when your
|
||||
/// type is dropped, it may drop one or more instances of the type
|
||||
/// `T`. This has bearing on the Rust compiler's [drop check]
|
||||
/// analysis.
|
||||
///
|
||||
/// If your struct does not in fact *own* the data of type `T`, it is
|
||||
/// better to use a reference type, like `PhantomData<&'a T>`
|
||||
/// (ideally) or `PhantomData<*const T>` (if no lifetime applies), so
|
||||
/// as not to indicate ownership.
|
||||
///
|
||||
/// [drop check]: ../../nomicon/dropck.html
|
||||
#[lang = "phantom_data"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct PhantomData<T:?Sized>;
|
||||
|
|
@ -419,10 +545,13 @@ mod impls {
|
|||
|
||||
/// Types that can be reflected over.
|
||||
///
|
||||
/// This trait is implemented for all types. Its purpose is to ensure
|
||||
/// that when you write a generic function that will employ
|
||||
/// reflection, that must be reflected (no pun intended) in the
|
||||
/// generic bounds of that function. Here is an example:
|
||||
/// By "reflection" we mean use of the [`Any`][any] trait, or related
|
||||
/// machinery such as [`TypeId`][typeid].
|
||||
///
|
||||
/// `Reflect` is implemented for all types. Its purpose is to ensure
|
||||
/// that when you write a generic function that will employ reflection,
|
||||
/// that must be reflected (no pun intended) in the generic bounds of
|
||||
/// that function.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(reflect_marker)]
|
||||
|
|
@ -436,21 +565,24 @@ mod impls {
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Without the declaration `T: Reflect`, `foo` would not type check
|
||||
/// (note: as a matter of style, it would be preferable to write
|
||||
/// `T: Any`, because `T: Any` implies `T: Reflect` and `T: 'static`, but
|
||||
/// we use `Reflect` here to show how it works). The `Reflect` bound
|
||||
/// thus serves to alert `foo`'s caller to the fact that `foo` may
|
||||
/// behave differently depending on whether `T = u32` or not. In
|
||||
/// particular, thanks to the `Reflect` bound, callers know that a
|
||||
/// function declared like `fn bar<T>(...)` will always act in
|
||||
/// precisely the same way no matter what type `T` is supplied,
|
||||
/// because there are no bounds declared on `T`. (The ability for a
|
||||
/// caller to reason about what a function may do based solely on what
|
||||
/// generic bounds are declared is often called the ["parametricity
|
||||
/// property"][1].)
|
||||
/// Without the bound `T: Reflect`, `foo` would not typecheck. (As
|
||||
/// a matter of style, it would be preferable to write `T: Any`,
|
||||
/// because `T: Any` implies `T: Reflect` and `T: 'static`, but we
|
||||
/// use `Reflect` here for illustrative purposes.)
|
||||
///
|
||||
/// [1]: http://en.wikipedia.org/wiki/Parametricity
|
||||
/// The `Reflect` bound serves to alert `foo`'s caller to the
|
||||
/// fact that `foo` may behave differently depending on whether
|
||||
/// `T` is `u32` or not. The ability for a caller to reason about what
|
||||
/// a function may do based solely on what generic bounds are declared
|
||||
/// is often called the "[parametricity property][param]". Despite the
|
||||
/// use of `Reflect`, Rust lacks true parametricity because a generic
|
||||
/// function can, at the very least, call [`mem::size_of`][size_of]
|
||||
/// without employing any trait bounds whatsoever.
|
||||
///
|
||||
/// [any]: ../any/trait.Any.html
|
||||
/// [typeid]: ../any/struct.TypeId.html
|
||||
/// [param]: http://en.wikipedia.org/wiki/Parametricity
|
||||
/// [size_of]: ../mem/fn.size_of.html
|
||||
#[rustc_reflect_like]
|
||||
#[unstable(feature = "reflect_marker",
|
||||
reason = "requires RFC and more experience",
|
||||
|
|
|
|||
|
|
@ -21,54 +21,39 @@ use ptr;
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use intrinsics::transmute;
|
||||
|
||||
/// Leaks a value into the void, consuming ownership and never running its
|
||||
/// destructor.
|
||||
/// Leaks a value: takes ownership and "forgets" about the value **without running
|
||||
/// its destructor**.
|
||||
///
|
||||
/// This function will take ownership of its argument, but is distinct from the
|
||||
/// `mem::drop` function in that it **does not run the destructor**, leaking the
|
||||
/// value and any resources that it owns.
|
||||
/// Any resources the value manages, such as heap memory or a file handle, will linger
|
||||
/// forever in an unreachable state.
|
||||
///
|
||||
/// There's only a few reasons to use this function. They mainly come
|
||||
/// up in unsafe code or FFI code.
|
||||
///
|
||||
/// * You have an uninitialized value, perhaps for performance reasons, and
|
||||
/// need to prevent the destructor from running on it.
|
||||
/// * You have two copies of a value (like when writing something like
|
||||
/// [`mem::swap`][swap]), but need the destructor to only run once to
|
||||
/// prevent a double `free`.
|
||||
/// * Transferring resources across [FFI][ffi] boundaries.
|
||||
///
|
||||
/// [swap]: fn.swap.html
|
||||
/// [ffi]: ../../book/ffi.html
|
||||
/// If you want to dispose of a value properly, running its destructor, see
|
||||
/// [`mem::drop`][drop].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is not marked as `unsafe` as Rust does not guarantee that the
|
||||
/// `Drop` implementation for a value will always run. Note, however, that
|
||||
/// leaking resources such as memory or I/O objects is likely not desired, so
|
||||
/// this function is only recommended for specialized use cases.
|
||||
/// `forget` is not marked as `unsafe`, because Rust's safety guarantees
|
||||
/// do not include a guarantee that destructors will always run. For example,
|
||||
/// a program can create a reference cycle using [`Rc`][rc], or call
|
||||
/// [`process:exit`][exit] to exit without running destructors. Thus, allowing
|
||||
/// `mem::forget` from safe code does not fundamentally change Rust's safety
|
||||
/// guarantees.
|
||||
///
|
||||
/// The safety of this function implies that when writing `unsafe` code
|
||||
/// yourself care must be taken when leveraging a destructor that is required to
|
||||
/// run to preserve memory safety. There are known situations where the
|
||||
/// destructor may not run (such as if ownership of the object with the
|
||||
/// destructor is returned) which must be taken into account.
|
||||
/// That said, leaking resources such as memory or I/O objects is usually undesirable,
|
||||
/// so `forget` is only recommended for specialized use cases like those shown below.
|
||||
///
|
||||
/// # Other forms of Leakage
|
||||
/// Because forgetting a value is allowed, any `unsafe` code you write must
|
||||
/// allow for this possibility. You cannot return a value and expect that the
|
||||
/// caller will necessarily run the value's destructor.
|
||||
///
|
||||
/// It's important to point out that this function is not the only method by
|
||||
/// which a value can be leaked in safe Rust code. Other known sources of
|
||||
/// leakage are:
|
||||
/// [rc]: ../../std/rc/struct.Rc.html
|
||||
/// [exit]: ../../std/process/fn.exit.html
|
||||
///
|
||||
/// * `Rc` and `Arc` cycles
|
||||
/// * `mpsc::{Sender, Receiver}` cycles (they use `Arc` internally)
|
||||
/// * Panicking destructors are likely to leak local resources
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// Leak some heap memory by never deallocating it:
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// use std::mem;
|
||||
///
|
||||
/// let heap_memory = Box::new(3);
|
||||
|
|
@ -77,7 +62,7 @@ pub use intrinsics::transmute;
|
|||
///
|
||||
/// Leak an I/O object, never closing the file:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// ```no_run
|
||||
/// use std::mem;
|
||||
/// use std::fs::File;
|
||||
///
|
||||
|
|
@ -85,9 +70,43 @@ pub use intrinsics::transmute;
|
|||
/// mem::forget(file);
|
||||
/// ```
|
||||
///
|
||||
/// The `mem::swap` function uses `mem::forget` to good effect:
|
||||
/// The practical use cases for `forget` are rather specialized and mainly come
|
||||
/// up in unsafe or FFI code.
|
||||
///
|
||||
/// ```rust
|
||||
/// ## Use case 1
|
||||
///
|
||||
/// You have created an uninitialized value using [`mem::uninitialized`][uninit].
|
||||
/// You must either initialize or `forget` it on every computation path before
|
||||
/// Rust drops it automatically, like at the end of a scope or after a panic.
|
||||
/// Running the destructor on an uninitialized value would be [undefined behavior][ub].
|
||||
///
|
||||
/// ```
|
||||
/// use std::mem;
|
||||
/// use std::ptr;
|
||||
///
|
||||
/// # let some_condition = false;
|
||||
/// unsafe {
|
||||
/// let mut uninit_vec: Vec<u32> = mem::uninitialized();
|
||||
///
|
||||
/// if some_condition {
|
||||
/// // Initialize the variable.
|
||||
/// ptr::write(&mut uninit_vec, Vec::new());
|
||||
/// } else {
|
||||
/// // Forget the uninitialized value so its destructor doesn't run.
|
||||
/// mem::forget(uninit_vec);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Use case 2
|
||||
///
|
||||
/// You have duplicated the bytes making up a value, without doing a proper
|
||||
/// [`Clone`][clone]. You need the value's destructor to run only once,
|
||||
/// because a double `free` is undefined behavior.
|
||||
///
|
||||
/// An example is the definition of [`mem::swap`][swap] in this module:
|
||||
///
|
||||
/// ```
|
||||
/// use std::mem;
|
||||
/// use std::ptr;
|
||||
///
|
||||
|
|
@ -109,6 +128,41 @@ pub use intrinsics::transmute;
|
|||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Use case 3
|
||||
///
|
||||
/// You are transferring ownership across a [FFI] boundary to code written in
|
||||
/// another language. You need to `forget` the value on the Rust side because Rust
|
||||
/// code is no longer responsible for it.
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::mem;
|
||||
///
|
||||
/// extern "C" {
|
||||
/// fn my_c_function(x: *const u32);
|
||||
/// }
|
||||
///
|
||||
/// let x: Box<u32> = Box::new(3);
|
||||
///
|
||||
/// // Transfer ownership into C code.
|
||||
/// unsafe {
|
||||
/// my_c_function(&*x);
|
||||
/// }
|
||||
/// mem::forget(x);
|
||||
/// ```
|
||||
///
|
||||
/// In this case, C code must call back into Rust to free the object. Calling C's `free`
|
||||
/// function on a [`Box`][box] is *not* safe! Also, `Box` provides an [`into_raw`][into_raw]
|
||||
/// method which is the preferred way to do this in practice.
|
||||
///
|
||||
/// [drop]: fn.drop.html
|
||||
/// [uninit]: fn.uninitialized.html
|
||||
/// [clone]: ../clone/trait.Clone.html
|
||||
/// [swap]: fn.swap.html
|
||||
/// [FFI]: ../../book/ffi.html
|
||||
/// [box]: ../../std/boxed/struct.Box.html
|
||||
/// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw
|
||||
/// [ub]: ../../reference.html#behavior-considered-undefined
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn forget<T>(t: T) {
|
||||
|
|
@ -133,7 +187,14 @@ pub fn size_of<T>() -> usize {
|
|||
unsafe { intrinsics::size_of::<T>() }
|
||||
}
|
||||
|
||||
/// Returns the size of the given value in bytes.
|
||||
/// Returns the size of the pointed-to value in bytes.
|
||||
///
|
||||
/// This is usually the same as `size_of::<T>()`. However, when `T` *has* no
|
||||
/// statically known size, e.g. a slice [`[T]`][slice] or a [trait object],
|
||||
/// then `size_of_val` can be used to get the dynamically-known size.
|
||||
///
|
||||
/// [slice]: ../../std/primitive.slice.html
|
||||
/// [trait object]: ../../book/trait-objects.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -141,6 +202,10 @@ pub fn size_of<T>() -> usize {
|
|||
/// use std::mem;
|
||||
///
|
||||
/// assert_eq!(4, mem::size_of_val(&5i32));
|
||||
///
|
||||
/// let x: [u8; 13] = [0; 13];
|
||||
/// let y: &[u8] = &x;
|
||||
/// assert_eq!(13, mem::size_of_val(y));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -148,10 +213,14 @@ pub fn size_of_val<T: ?Sized>(val: &T) -> usize {
|
|||
unsafe { intrinsics::size_of_val(val) }
|
||||
}
|
||||
|
||||
/// Returns the ABI-required minimum alignment of a type
|
||||
/// Returns the [ABI]-required minimum alignment of a type.
|
||||
///
|
||||
/// Every valid address of a value of the type `T` must be a multiple of this number.
|
||||
///
|
||||
/// This is the alignment used for struct fields. It may be smaller than the preferred alignment.
|
||||
///
|
||||
/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -167,7 +236,11 @@ pub fn min_align_of<T>() -> usize {
|
|||
unsafe { intrinsics::min_align_of::<T>() }
|
||||
}
|
||||
|
||||
/// Returns the ABI-required minimum alignment of the type of the value that `val` points to
|
||||
/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to.
|
||||
///
|
||||
/// Every valid address of a value of the type `T` must be a multiple of this number.
|
||||
///
|
||||
/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -184,10 +257,14 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
|
|||
unsafe { intrinsics::min_align_of_val(val) }
|
||||
}
|
||||
|
||||
/// Returns the alignment in memory for a type.
|
||||
/// Returns the [ABI]-required minimum alignment of a type.
|
||||
///
|
||||
/// Every valid address of a value of the type `T` must be a multiple of this number.
|
||||
///
|
||||
/// This is the alignment used for struct fields. It may be smaller than the preferred alignment.
|
||||
///
|
||||
/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -201,7 +278,11 @@ pub fn align_of<T>() -> usize {
|
|||
unsafe { intrinsics::min_align_of::<T>() }
|
||||
}
|
||||
|
||||
/// Returns the ABI-required minimum alignment of the type of the value that `val` points to
|
||||
/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to.
|
||||
///
|
||||
/// Every valid address of a value of the type `T` must be a multiple of this number.
|
||||
///
|
||||
/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -216,16 +297,23 @@ pub fn align_of_val<T: ?Sized>(val: &T) -> usize {
|
|||
unsafe { intrinsics::min_align_of_val(val) }
|
||||
}
|
||||
|
||||
/// Creates a value initialized to zero.
|
||||
/// Creates a value whose bytes are all zero.
|
||||
///
|
||||
/// This function is similar to allocating space for a local variable and zeroing it out (an unsafe
|
||||
/// operation).
|
||||
/// This has the same effect as allocating space with
|
||||
/// [`mem::uninitialized`][uninit] and then zeroing it out. It is useful for
|
||||
/// [FFI] sometimes, but should generally be avoided.
|
||||
///
|
||||
/// Care must be taken when using this function, if the type `T` has a destructor and the value
|
||||
/// falls out of scope (due to unwinding or returning) before being initialized, then the
|
||||
/// destructor will run on zeroed data, likely leading to crashes.
|
||||
/// There is no guarantee that an all-zero byte-pattern represents a valid value of
|
||||
/// some type `T`. If `T` has a destructor and the value is destroyed (due to
|
||||
/// a panic or the end of a scope) before being initialized, then the destructor
|
||||
/// will run on zeroed data, likely leading to [undefined behavior][ub].
|
||||
///
|
||||
/// This is useful for FFI functions sometimes, but should generally be avoided.
|
||||
/// See also the documentation for [`mem::uninitialized`][uninit], which has
|
||||
/// many of the same caveats.
|
||||
///
|
||||
/// [uninit]: fn.uninitialized.html
|
||||
/// [FFI]: ../../book/ffi.html
|
||||
/// [ub]: ../../reference.html#behavior-considered-undefined
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -233,6 +321,7 @@ pub fn align_of_val<T: ?Sized>(val: &T) -> usize {
|
|||
/// use std::mem;
|
||||
///
|
||||
/// let x: i32 = unsafe { mem::zeroed() };
|
||||
/// assert_eq!(0, x);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -241,32 +330,38 @@ pub unsafe fn zeroed<T>() -> T {
|
|||
}
|
||||
|
||||
/// Bypasses Rust's normal memory-initialization checks by pretending to
|
||||
/// produce a value of type T, while doing nothing at all.
|
||||
/// produce a value of type `T`, while doing nothing at all.
|
||||
///
|
||||
/// **This is incredibly dangerous, and should not be done lightly. Deeply
|
||||
/// consider initializing your memory with a default value instead.**
|
||||
///
|
||||
/// This is useful for FFI functions and initializing arrays sometimes,
|
||||
/// This is useful for [FFI] functions and initializing arrays sometimes,
|
||||
/// but should generally be avoided.
|
||||
///
|
||||
/// # Undefined Behavior
|
||||
/// [FFI]: ../../book/ffi.html
|
||||
///
|
||||
/// It is Undefined Behavior to read uninitialized memory. Even just an
|
||||
/// # Undefined behavior
|
||||
///
|
||||
/// It is [undefined behavior][ub] to read uninitialized memory, even just an
|
||||
/// uninitialized boolean. For instance, if you branch on the value of such
|
||||
/// a boolean your program may take one, both, or neither of the branches.
|
||||
/// a boolean, your program may take one, both, or neither of the branches.
|
||||
///
|
||||
/// Note that this often also includes *writing* to the uninitialized value.
|
||||
/// Rust believes the value is initialized, and will therefore try to Drop
|
||||
/// the uninitialized value and its fields if you try to overwrite the memory
|
||||
/// in a normal manner. The only way to safely initialize an arbitrary
|
||||
/// uninitialized value is with one of the `ptr` functions: `write`, `copy`, or
|
||||
/// `copy_nonoverlapping`. This isn't necessary if `T` is a primitive
|
||||
/// or otherwise only contains types that don't implement Drop.
|
||||
/// Writing to the uninitialized value is similarly dangerous. Rust believes the
|
||||
/// value is initialized, and will therefore try to [`Drop`][drop] the uninitialized
|
||||
/// value and its fields if you try to overwrite it in a normal manner. The only way
|
||||
/// to safely initialize an uninitialized value is with [`ptr::write`][write],
|
||||
/// [`ptr::copy`][copy], or [`ptr::copy_nonoverlapping`][copy_no].
|
||||
///
|
||||
/// If this value *does* need some kind of Drop, it must be initialized before
|
||||
/// If the value does implement `Drop`, it must be initialized before
|
||||
/// it goes out of scope (and therefore would be dropped). Note that this
|
||||
/// includes a `panic` occurring and unwinding the stack suddenly.
|
||||
///
|
||||
/// [ub]: ../../reference.html#behavior-considered-undefined
|
||||
/// [write]: ../ptr/fn.write.html
|
||||
/// [copy]: ../intrinsics/fn.copy.html
|
||||
/// [copy_no]: ../intrinsics/fn.copy_nonoverlapping.html
|
||||
/// [drop]: ../ops/trait.Drop.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Here's how to safely initialize an array of `Vec`s.
|
||||
|
|
@ -309,8 +404,8 @@ pub unsafe fn zeroed<T>() -> T {
|
|||
/// println!("{:?}", &data[0]);
|
||||
/// ```
|
||||
///
|
||||
/// This example emphasizes exactly how delicate and dangerous doing this is.
|
||||
/// Note that the `vec!` macro *does* let you initialize every element with a
|
||||
/// This example emphasizes exactly how delicate and dangerous using `mem::uninitialized`
|
||||
/// can be. Note that the `vec!` macro *does* let you initialize every element with a
|
||||
/// value that is only `Clone`, so the following is semantically equivalent and
|
||||
/// vastly less dangerous, as long as you can live with an extra heap
|
||||
/// allocation:
|
||||
|
|
@ -325,21 +420,20 @@ pub unsafe fn uninitialized<T>() -> T {
|
|||
intrinsics::uninit()
|
||||
}
|
||||
|
||||
/// Swap the values at two mutable locations of the same type, without deinitializing or copying
|
||||
/// either one.
|
||||
/// Swaps the values at two mutable locations, without deinitializing either one.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::mem;
|
||||
///
|
||||
/// let x = &mut 5;
|
||||
/// let y = &mut 42;
|
||||
/// let mut x = 5;
|
||||
/// let mut y = 42;
|
||||
///
|
||||
/// mem::swap(x, y);
|
||||
/// mem::swap(&mut x, &mut y);
|
||||
///
|
||||
/// assert_eq!(42, *x);
|
||||
/// assert_eq!(5, *y);
|
||||
/// assert_eq!(42, x);
|
||||
/// assert_eq!(5, y);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -361,10 +455,7 @@ pub fn swap<T>(x: &mut T, y: &mut T) {
|
|||
}
|
||||
|
||||
/// Replaces the value at a mutable location with a new one, returning the old value, without
|
||||
/// deinitializing or copying either one.
|
||||
///
|
||||
/// This is primarily used for transferring and swapping ownership of a value in a mutable
|
||||
/// location.
|
||||
/// deinitializing either one.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -373,15 +464,17 @@ pub fn swap<T>(x: &mut T, y: &mut T) {
|
|||
/// ```
|
||||
/// use std::mem;
|
||||
///
|
||||
/// let mut v: Vec<i32> = Vec::new();
|
||||
/// let mut v: Vec<i32> = vec![1, 2];
|
||||
///
|
||||
/// mem::replace(&mut v, Vec::new());
|
||||
/// let old_v = mem::replace(&mut v, vec![3, 4, 5]);
|
||||
/// assert_eq!(2, old_v.len());
|
||||
/// assert_eq!(3, v.len());
|
||||
/// ```
|
||||
///
|
||||
/// This function allows consumption of one field of a struct by replacing it with another value.
|
||||
/// The normal approach doesn't always work:
|
||||
/// `replace` allows consumption of a struct field by replacing it with another value.
|
||||
/// Without `replace` you can run into issues like these:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// ```ignore
|
||||
/// struct Buffer<T> { buf: Vec<T> }
|
||||
///
|
||||
/// impl<T> Buffer<T> {
|
||||
|
|
@ -401,6 +494,7 @@ pub fn swap<T>(x: &mut T, y: &mut T) {
|
|||
/// ```
|
||||
/// # #![allow(dead_code)]
|
||||
/// use std::mem;
|
||||
///
|
||||
/// # struct Buffer<T> { buf: Vec<T> }
|
||||
/// impl<T> Buffer<T> {
|
||||
/// fn get_and_reset(&mut self) -> Vec<T> {
|
||||
|
|
@ -417,14 +511,25 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T {
|
|||
|
||||
/// Disposes of a value.
|
||||
///
|
||||
/// While this does call the argument's implementation of `Drop`, it will not
|
||||
/// release any borrows, as borrows are based on lexical scope.
|
||||
/// While this does call the argument's implementation of [`Drop`][drop],
|
||||
/// it will not release any borrows, as borrows are based on lexical scope.
|
||||
///
|
||||
/// This effectively does nothing for
|
||||
/// [types which implement `Copy`](../../book/ownership.html#copy-types),
|
||||
/// e.g. integers. Such values are copied and _then_ moved into the function,
|
||||
/// so the value persists after this function call.
|
||||
///
|
||||
/// This function is not magic; it is literally defined as
|
||||
///
|
||||
/// ```
|
||||
/// pub fn drop<T>(_x: T) { }
|
||||
/// ```
|
||||
///
|
||||
/// Because `_x` is moved into the function, it is automatically dropped before
|
||||
/// the function returns.
|
||||
///
|
||||
/// [drop]: ../ops/trait.Drop.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
|
|
@ -461,8 +566,8 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T {
|
|||
/// v.push(4); // no problems
|
||||
/// ```
|
||||
///
|
||||
/// Since `RefCell` enforces the borrow rules at runtime, `drop()` can
|
||||
/// seemingly release a borrow of one:
|
||||
/// Since `RefCell` enforces the borrow rules at runtime, `drop` can
|
||||
/// release a `RefCell` borrow:
|
||||
///
|
||||
/// ```
|
||||
/// use std::cell::RefCell;
|
||||
|
|
@ -478,7 +583,7 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T {
|
|||
/// println!("{}", *borrow);
|
||||
/// ```
|
||||
///
|
||||
/// Integers and other types implementing `Copy` are unaffected by `drop()`
|
||||
/// Integers and other types implementing `Copy` are unaffected by `drop`.
|
||||
///
|
||||
/// ```
|
||||
/// #[derive(Copy, Clone)]
|
||||
|
|
@ -496,19 +601,22 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn drop<T>(_x: T) { }
|
||||
|
||||
/// Interprets `src` as `&U`, and then reads `src` without moving the contained
|
||||
/// value.
|
||||
/// Interprets `src` as having type `&U`, and then reads `src` without moving
|
||||
/// the contained value.
|
||||
///
|
||||
/// This function will unsafely assume the pointer `src` is valid for
|
||||
/// `sizeof(U)` bytes by transmuting `&T` to `&U` and then reading the `&U`. It
|
||||
/// will also unsafely create a copy of the contained value instead of moving
|
||||
/// out of `src`.
|
||||
/// [`size_of::<U>()`][size_of] bytes by transmuting `&T` to `&U` and then reading
|
||||
/// the `&U`. It will also unsafely create a copy of the contained value instead of
|
||||
/// moving out of `src`.
|
||||
///
|
||||
/// It is not a compile-time error if `T` and `U` have different sizes, but it
|
||||
/// is highly encouraged to only invoke this function where `T` and `U` have the
|
||||
/// same size. This function triggers undefined behavior if `U` is larger than
|
||||
/// same size. This function triggers [undefined behavior][ub] if `U` is larger than
|
||||
/// `T`.
|
||||
///
|
||||
/// [ub]: ../../reference.html#behavior-considered-undefined
|
||||
/// [size_of]: fn.size_of.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
|
|||
|
|
@ -474,9 +474,9 @@ macro_rules! define_bignum {
|
|||
let sz = if self.size < 1 {1} else {self.size};
|
||||
let digitlen = mem::size_of::<$ty>() * 2;
|
||||
|
||||
try!(write!(f, "{:#x}", self.base[sz-1]));
|
||||
write!(f, "{:#x}", self.base[sz-1])?;
|
||||
for &v in self.base[..sz-1].iter().rev() {
|
||||
try!(write!(f, "_{:01$x}", v, digitlen));
|
||||
write!(f, "_{:01$x}", v, digitlen)?;
|
||||
}
|
||||
::result::Result::Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2211,25 +2211,21 @@ macro_rules! uint_impl {
|
|||
let mut base = self;
|
||||
let mut acc = 1;
|
||||
|
||||
let mut prev_base = self;
|
||||
let mut base_oflo = false;
|
||||
while exp > 0 {
|
||||
while exp > 1 {
|
||||
if (exp & 1) == 1 {
|
||||
if base_oflo {
|
||||
// ensure overflow occurs in the same manner it
|
||||
// would have otherwise (i.e. signal any exception
|
||||
// it would have otherwise).
|
||||
acc = acc * (prev_base * prev_base);
|
||||
} else {
|
||||
acc = acc * base;
|
||||
}
|
||||
acc = acc * base;
|
||||
}
|
||||
prev_base = base;
|
||||
let (new_base, new_base_oflo) = base.overflowing_mul(base);
|
||||
base = new_base;
|
||||
base_oflo = new_base_oflo;
|
||||
exp /= 2;
|
||||
base = base * base;
|
||||
}
|
||||
|
||||
// Deal with the final bit of the exponent separately, since
|
||||
// squaring the base afterwards is not necessary and may cause a
|
||||
// needless overflow.
|
||||
if exp == 1 {
|
||||
acc = acc * base;
|
||||
}
|
||||
|
||||
acc
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -282,6 +282,12 @@ macro_rules! forward_ref_binop {
|
|||
/// Point { x: 3, y: 3 });
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Note that `RHS = Self` by default, but this is not mandatory. For example,
|
||||
/// [std::time::SystemTime] implements `Add<Duration>`, which permits
|
||||
/// operations of the form `SystemTime = SystemTime + Duration`.
|
||||
///
|
||||
/// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html
|
||||
#[lang = "add"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Add<RHS=Self> {
|
||||
|
|
@ -349,6 +355,12 @@ add_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 }
|
|||
/// Point { x: 1, y: 0 });
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Note that `RHS = Self` by default, but this is not mandatory. For example,
|
||||
/// [std::time::SystemTime] implements `Sub<Duration>`, which permits
|
||||
/// operations of the form `SystemTime = SystemTime - Duration`.
|
||||
///
|
||||
/// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html
|
||||
#[lang = "sub"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Sub<RHS=Self> {
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
//! Optional values.
|
||||
//!
|
||||
//! Type `Option` represents an optional value: every `Option`
|
||||
//! is either `Some` and contains a value, or `None`, and
|
||||
//! does not. `Option` types are very common in Rust code, as
|
||||
//! Type [`Option`] represents an optional value: every [`Option`]
|
||||
//! is either [`Some`] and contains a value, or [`None`], and
|
||||
//! does not. [`Option`] types are very common in Rust code, as
|
||||
//! they have a number of uses:
|
||||
//!
|
||||
//! * Initial values
|
||||
|
|
@ -26,8 +26,8 @@
|
|||
//! * Nullable pointers
|
||||
//! * Swapping things out of difficult situations
|
||||
//!
|
||||
//! Options are commonly paired with pattern matching to query the presence
|
||||
//! of a value and take action, always accounting for the `None` case.
|
||||
//! [`Option`]s are commonly paired with pattern matching to query the presence
|
||||
//! of a value and take action, always accounting for the [`None`] case.
|
||||
//!
|
||||
//! ```
|
||||
//! fn divide(numerator: f64, denominator: f64) -> Option<f64> {
|
||||
|
|
@ -57,13 +57,13 @@
|
|||
//!
|
||||
//! Rust's pointer types must always point to a valid location; there are
|
||||
//! no "null" pointers. Instead, Rust has *optional* pointers, like
|
||||
//! the optional owned box, `Option<Box<T>>`.
|
||||
//! the optional owned box, [`Option`]`<`[`Box<T>`]`>`.
|
||||
//!
|
||||
//! The following example uses `Option` to create an optional box of
|
||||
//! `i32`. Notice that in order to use the inner `i32` value first the
|
||||
//! The following example uses [`Option`] to create an optional box of
|
||||
//! [`i32`]. Notice that in order to use the inner [`i32`] value first the
|
||||
//! `check_optional` function needs to use pattern matching to
|
||||
//! determine whether the box has a value (i.e. it is `Some(...)`) or
|
||||
//! not (`None`).
|
||||
//! determine whether the box has a value (i.e. it is [`Some(...)`][`Some`]) or
|
||||
//! not ([`None`]).
|
||||
//!
|
||||
//! ```
|
||||
//! let optional: Option<Box<i32>> = None;
|
||||
|
|
@ -80,14 +80,14 @@
|
|||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! This usage of `Option` to create safe nullable pointers is so
|
||||
//! This usage of [`Option`] to create safe nullable pointers is so
|
||||
//! common that Rust does special optimizations to make the
|
||||
//! representation of `Option<Box<T>>` a single pointer. Optional pointers
|
||||
//! representation of [`Option`]`<`[`Box<T>`]`>` a single pointer. Optional pointers
|
||||
//! in Rust are stored as efficiently as any other pointer type.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Basic pattern matching on `Option`:
|
||||
//! Basic pattern matching on [`Option`]:
|
||||
//!
|
||||
//! ```
|
||||
//! let msg = Some("howdy");
|
||||
|
|
@ -101,7 +101,7 @@
|
|||
//! let unwrapped_msg = msg.unwrap_or("default message");
|
||||
//! ```
|
||||
//!
|
||||
//! Initialize a result to `None` before a loop:
|
||||
//! Initialize a result to [`None`] before a loop:
|
||||
//!
|
||||
//! ```
|
||||
//! enum Kingdom { Plant(u32, &'static str), Animal(u32, &'static str) }
|
||||
|
|
@ -136,6 +136,12 @@
|
|||
//! None => println!("there are no animals :("),
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! [`Option`]: enum.Option.html
|
||||
//! [`Some`]: enum.Option.html#variant.Some
|
||||
//! [`None`]: enum.Option.html#variant.None
|
||||
//! [`Box<T>`]: ../../std/boxed/struct.Box.html
|
||||
//! [`i32`]: ../../std/primitive.i32.html
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
|
|
@ -156,7 +162,7 @@ pub enum Option<T> {
|
|||
None,
|
||||
/// Some value `T`
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
Some(#[stable(feature = "rust1", since = "1.0.0")] T)
|
||||
Some(#[stable(feature = "rust1", since = "1.0.0")] T),
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -168,7 +174,7 @@ impl<T> Option<T> {
|
|||
// Querying the contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns `true` if the option is a `Some` value
|
||||
/// Returns `true` if the option is a `Some` value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -188,7 +194,7 @@ impl<T> Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the option is a `None` value
|
||||
/// Returns `true` if the option is a `None` value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -209,15 +215,17 @@ impl<T> Option<T> {
|
|||
// Adapter for working with references
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Converts from `Option<T>` to `Option<&T>`
|
||||
/// Converts from `Option<T>` to `Option<&T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Convert an `Option<String>` into an `Option<usize>`, preserving the original.
|
||||
/// The `map` method takes the `self` argument by value, consuming the original,
|
||||
/// The [`map`] method takes the `self` argument by value, consuming the original,
|
||||
/// so this technique uses `as_ref` to first take an `Option` to a reference
|
||||
/// to the value inside the original.
|
||||
///
|
||||
/// [`map`]: enum.Option.html#method.map
|
||||
///
|
||||
/// ```
|
||||
/// let num_as_str: Option<String> = Some("10".to_string());
|
||||
/// // First, cast `Option<String>` to `Option<&String>` with `as_ref`,
|
||||
|
|
@ -234,7 +242,7 @@ impl<T> Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts from `Option<T>` to `Option<&mut T>`
|
||||
/// Converts from `Option<T>` to `Option<&mut T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -357,7 +365,7 @@ impl<T> Option<T> {
|
|||
// Transforming contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Maps an `Option<T>` to `Option<U>` by applying a function to a contained value
|
||||
/// Maps an `Option<T>` to `Option<U>` by applying a function to a contained value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -423,8 +431,12 @@ impl<T> Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Transforms the `Option<T>` into a `Result<T, E>`, mapping `Some(v)` to
|
||||
/// `Ok(v)` and `None` to `Err(err)`.
|
||||
/// Transforms the `Option<T>` into a [`Result<T, E>`], mapping `Some(v)` to
|
||||
/// [`Ok(v)`] and `None` to [`Err(err)`][Err].
|
||||
///
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [Err]: ../../std/result/enum.Result.html#variant.Err
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -444,8 +456,12 @@ impl<T> Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Transforms the `Option<T>` into a `Result<T, E>`, mapping `Some(v)` to
|
||||
/// `Ok(v)` and `None` to `Err(err())`.
|
||||
/// Transforms the `Option<T>` into a [`Result<T, E>`], mapping `Some(v)` to
|
||||
/// [`Ok(v)`] and `None` to [`Err(err())`][Err].
|
||||
///
|
||||
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
|
||||
/// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
|
||||
/// [Err]: ../../std/result/enum.Result.html#variant.Err
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -698,6 +714,7 @@ fn expect_failed(msg: &str) -> ! {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Default for Option<T> {
|
||||
/// Returns None.
|
||||
#[inline]
|
||||
fn default() -> Option<T> { None }
|
||||
}
|
||||
|
|
@ -789,7 +806,9 @@ impl<A> DoubleEndedIterator for Item<A> {
|
|||
impl<A> ExactSizeIterator for Item<A> {}
|
||||
impl<A> FusedIterator for Item<A> {}
|
||||
|
||||
/// An iterator over a reference of the contained item in an Option.
|
||||
/// An iterator over a reference of the contained item in an [`Option`].
|
||||
///
|
||||
/// [`Option`]: enum.Option.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[derive(Debug)]
|
||||
pub struct Iter<'a, A: 'a> { inner: Item<&'a A> }
|
||||
|
|
@ -823,7 +842,9 @@ impl<'a, A> Clone for Iter<'a, A> {
|
|||
}
|
||||
}
|
||||
|
||||
/// An iterator over a mutable reference of the contained item in an Option.
|
||||
/// An iterator over a mutable reference of the contained item in an [`Option`].
|
||||
///
|
||||
/// [`Option`]: enum.Option.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[derive(Debug)]
|
||||
pub struct IterMut<'a, A: 'a> { inner: Item<&'a mut A> }
|
||||
|
|
@ -850,7 +871,9 @@ impl<'a, A> ExactSizeIterator for IterMut<'a, A> {}
|
|||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl<'a, A> FusedIterator for IterMut<'a, A> {}
|
||||
|
||||
/// An iterator over the item contained inside an Option.
|
||||
/// An iterator over the item contained inside an [`Option`].
|
||||
///
|
||||
/// [`Option`]: enum.Option.html
|
||||
#[derive(Clone, Debug)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct IntoIter<A> { inner: Item<A> }
|
||||
|
|
|
|||
|
|
@ -479,6 +479,40 @@ impl<T: ?Sized> PartialEq for *mut T {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Eq for *mut T {}
|
||||
|
||||
/// Compare raw pointers for equality.
|
||||
///
|
||||
/// This is the same as using the `==` operator, but less generic:
|
||||
/// the arguments have to be `*const T` raw pointers,
|
||||
/// not anything that implements `PartialEq`.
|
||||
///
|
||||
/// This can be used to compare `&T` references (which coerce to `*const T` implicitly)
|
||||
/// by their address rather than comparing the values they point to
|
||||
/// (which is what the `PartialEq for &T` implementation does).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(ptr_eq)]
|
||||
/// use std::ptr;
|
||||
///
|
||||
/// let five = 5;
|
||||
/// let other_five = 5;
|
||||
/// let five_ref = &five;
|
||||
/// let same_five_ref = &five;
|
||||
/// let other_five_ref = &other_five;
|
||||
///
|
||||
/// assert!(five_ref == same_five_ref);
|
||||
/// assert!(five_ref == other_five_ref);
|
||||
///
|
||||
/// assert!(ptr::eq(five_ref, same_five_ref));
|
||||
/// assert!(!ptr::eq(five_ref, other_five_ref));
|
||||
/// ```
|
||||
#[unstable(feature = "ptr_eq", reason = "newly added", issue = "36497")]
|
||||
#[inline]
|
||||
pub fn eq<T: ?Sized>(a: *const T, b: *const T) -> bool {
|
||||
a == b
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Clone for *const T {
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
//! Error handling with the `Result` type.
|
||||
//!
|
||||
//! `Result<T, E>` is the type used for returning and propagating
|
||||
//! errors. It is an enum with the variants, `Ok(T)`, representing
|
||||
//! success and containing a value, and `Err(E)`, representing error
|
||||
//! [`Result<T, E>`][`Result`] is the type used for returning and propagating
|
||||
//! errors. It is an enum with the variants, [`Ok(T)`], representing
|
||||
//! success and containing a value, and [`Err(E)`], representing error
|
||||
//! and containing an error value.
|
||||
//!
|
||||
//! ```
|
||||
|
|
@ -23,11 +23,11 @@
|
|||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Functions return `Result` whenever errors are expected and
|
||||
//! recoverable. In the `std` crate `Result` is most prominently used
|
||||
//! Functions return [`Result`] whenever errors are expected and
|
||||
//! recoverable. In the `std` crate, [`Result`] is most prominently used
|
||||
//! for [I/O](../../std/io/index.html).
|
||||
//!
|
||||
//! A simple function returning `Result` might be
|
||||
//! A simple function returning [`Result`] might be
|
||||
//! defined and used like so:
|
||||
//!
|
||||
//! ```
|
||||
|
|
@ -50,8 +50,8 @@
|
|||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Pattern matching on `Result`s is clear and straightforward for
|
||||
//! simple cases, but `Result` comes with some convenience methods
|
||||
//! Pattern matching on [`Result`]s is clear and straightforward for
|
||||
//! simple cases, but [`Result`] comes with some convenience methods
|
||||
//! that make working with it more succinct.
|
||||
//!
|
||||
//! ```
|
||||
|
|
@ -80,14 +80,14 @@
|
|||
//!
|
||||
//! A common problem with using return values to indicate errors is
|
||||
//! that it is easy to ignore the return value, thus failing to handle
|
||||
//! the error. Result is annotated with the #[must_use] attribute,
|
||||
//! the error. [`Result`] is annotated with the `#[must_use]` attribute,
|
||||
//! which will cause the compiler to issue a warning when a Result
|
||||
//! value is ignored. This makes `Result` especially useful with
|
||||
//! value is ignored. This makes [`Result`] especially useful with
|
||||
//! functions that may encounter errors but don't otherwise return a
|
||||
//! useful value.
|
||||
//!
|
||||
//! Consider the `write_all` method defined for I/O types
|
||||
//! by the [`Write`](../../std/io/trait.Write.html) trait:
|
||||
//! Consider the [`write_all`] method defined for I/O types
|
||||
//! by the [`Write`] trait:
|
||||
//!
|
||||
//! ```
|
||||
//! use std::io;
|
||||
|
|
@ -97,8 +97,8 @@
|
|||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! *Note: The actual definition of `Write` uses `io::Result`, which
|
||||
//! is just a synonym for `Result<T, io::Error>`.*
|
||||
//! *Note: The actual definition of [`Write`] uses [`io::Result`], which
|
||||
//! is just a synonym for [`Result`]`<T, `[`io::Error`]`>`.*
|
||||
//!
|
||||
//! This method doesn't produce a value, but the write may
|
||||
//! fail. It's crucial to handle the error case, and *not* write
|
||||
|
|
@ -119,7 +119,7 @@
|
|||
//! warning (by default, controlled by the `unused_must_use` lint).
|
||||
//!
|
||||
//! You might instead, if you don't want to handle the error, simply
|
||||
//! assert success with `expect`. This will panic if the
|
||||
//! assert success with [`expect`]. This will panic if the
|
||||
//! write fails, providing a marginally useful message indicating why:
|
||||
//!
|
||||
//! ```{.no_run}
|
||||
|
|
@ -139,7 +139,7 @@
|
|||
//! assert!(file.write_all(b"important message").is_ok());
|
||||
//! ```
|
||||
//!
|
||||
//! Or propagate the error up the call stack with `try!`:
|
||||
//! Or propagate the error up the call stack with [`try!`]:
|
||||
//!
|
||||
//! ```
|
||||
//! # use std::fs::File;
|
||||
|
|
@ -156,7 +156,7 @@
|
|||
//! # The `try!` macro
|
||||
//!
|
||||
//! When writing code that calls many functions that return the
|
||||
//! `Result` type, the error handling can be tedious. The `try!`
|
||||
//! [`Result`] type, the error handling can be tedious. The [`try!`]
|
||||
//! macro hides some of the boilerplate of propagating errors up the
|
||||
//! call stack.
|
||||
//!
|
||||
|
|
@ -219,9 +219,9 @@
|
|||
//!
|
||||
//! *It's much nicer!*
|
||||
//!
|
||||
//! Wrapping an expression in `try!` will result in the unwrapped
|
||||
//! success (`Ok`) value, unless the result is `Err`, in which case
|
||||
//! `Err` is returned early from the enclosing function. Its simple definition
|
||||
//! Wrapping an expression in [`try!`] will result in the unwrapped
|
||||
//! success ([`Ok`]) value, unless the result is [`Err`], in which case
|
||||
//! [`Err`] is returned early from the enclosing function. Its simple definition
|
||||
//! makes it clear:
|
||||
//!
|
||||
//! ```
|
||||
|
|
@ -230,9 +230,21 @@
|
|||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! `try!` is imported by the prelude and is available everywhere, but it can only
|
||||
//! be used in functions that return `Result` because of the early return of
|
||||
//! `Err` that it provides.
|
||||
//! [`try!`] is imported by the prelude and is available everywhere, but it can only
|
||||
//! be used in functions that return [`Result`] because of the early return of
|
||||
//! [`Err`] that it provides.
|
||||
//!
|
||||
//! [`expect`]: enum.Result.html#method.expect
|
||||
//! [`Write`]: ../../std/io/trait.Write.html
|
||||
//! [`write_all`]: ../../std/io/trait.Write.html#method.write_all
|
||||
//! [`io::Result`]: ../../std/io/type.Result.html
|
||||
//! [`try!`]: ../../std/macro.try.html
|
||||
//! [`Result`]: enum.Result.html
|
||||
//! [`Ok(T)`]: enum.Result.html#variant.Ok
|
||||
//! [`Err(E)`]: enum.Result.html#variant.Err
|
||||
//! [`io::Error`]: ../../std/io/struct.Error.html
|
||||
//! [`Ok`]: enum.Result.html#variant.Ok
|
||||
//! [`Err`]: enum.Result.html#variant.Err
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
|
|
@ -264,7 +276,7 @@ impl<T, E> Result<T, E> {
|
|||
// Querying the contained values
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns true if the result is `Ok`
|
||||
/// Returns true if the result is `Ok`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -286,7 +298,7 @@ impl<T, E> Result<T, E> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns true if the result is `Err`
|
||||
/// Returns true if the result is `Err`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -309,11 +321,13 @@ impl<T, E> Result<T, E> {
|
|||
// Adapter for each variant
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Converts from `Result<T, E>` to `Option<T>`
|
||||
/// Converts from `Result<T, E>` to [`Option<T>`].
|
||||
///
|
||||
/// Converts `self` into an `Option<T>`, consuming `self`,
|
||||
/// Converts `self` into an [`Option<T>`], consuming `self`,
|
||||
/// and discarding the error, if any.
|
||||
///
|
||||
/// [`Option<T>`]: ../../std/option/enum.Option.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
|
|
@ -334,11 +348,13 @@ impl<T, E> Result<T, E> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts from `Result<T, E>` to `Option<E>`
|
||||
/// Converts from `Result<T, E>` to [`Option<E>`].
|
||||
///
|
||||
/// Converts `self` into an `Option<E>`, consuming `self`,
|
||||
/// Converts `self` into an [`Option<E>`], consuming `self`,
|
||||
/// and discarding the success value, if any.
|
||||
///
|
||||
/// [`Option<E>`]: ../../std/option/enum.Option.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
|
|
@ -363,7 +379,7 @@ impl<T, E> Result<T, E> {
|
|||
// Adapter for working with references
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Converts from `Result<T, E>` to `Result<&T, &E>`
|
||||
/// Converts from `Result<T, E>` to `Result<&T, &E>`.
|
||||
///
|
||||
/// Produces a new `Result`, containing a reference
|
||||
/// into the original, leaving the original in place.
|
||||
|
|
@ -388,7 +404,7 @@ impl<T, E> Result<T, E> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts from `Result<T, E>` to `Result<&mut T, &mut E>`
|
||||
/// Converts from `Result<T, E>` to `Result<&mut T, &mut E>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -563,7 +579,7 @@ impl<T, E> Result<T, E> {
|
|||
|
||||
/// Calls `op` if the result is `Ok`, otherwise returns the `Err` value of `self`.
|
||||
///
|
||||
/// This function can be used for control flow based on result values.
|
||||
/// This function can be used for control flow based on `Result` values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -646,7 +662,7 @@ impl<T, E> Result<T, E> {
|
|||
}
|
||||
|
||||
/// Unwraps a result, yielding the content of an `Ok`.
|
||||
/// Else it returns `optb`.
|
||||
/// Else, it returns `optb`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -837,7 +853,10 @@ impl<'a, T, E> IntoIterator for &'a mut Result<T, E> {
|
|||
// The Result Iterators
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// An iterator over a reference to the `Ok` variant of a `Result`.
|
||||
/// An iterator over a reference to the [`Ok`] variant of a [`Result`].
|
||||
///
|
||||
/// [`Ok`]: enum.Result.html#variant.Ok
|
||||
/// [`Result`]: enum.Result.html
|
||||
#[derive(Debug)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Iter<'a, T: 'a> { inner: Option<&'a T> }
|
||||
|
|
@ -872,7 +891,10 @@ impl<'a, T> Clone for Iter<'a, T> {
|
|||
fn clone(&self) -> Iter<'a, T> { Iter { inner: self.inner } }
|
||||
}
|
||||
|
||||
/// An iterator over a mutable reference to the `Ok` variant of a `Result`.
|
||||
/// An iterator over a mutable reference to the [`Ok`] variant of a [`Result`].
|
||||
///
|
||||
/// [`Ok`]: enum.Result.html#variant.Ok
|
||||
/// [`Result`]: enum.Result.html
|
||||
#[derive(Debug)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct IterMut<'a, T: 'a> { inner: Option<&'a mut T> }
|
||||
|
|
@ -902,7 +924,14 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> {}
|
|||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl<'a, T> FusedIterator for IterMut<'a, T> {}
|
||||
|
||||
/// An iterator over the value in a `Ok` variant of a `Result`.
|
||||
/// An iterator over the value in a [`Ok`] variant of a [`Result`]. This struct is
|
||||
/// created by the [`into_iter`] method on [`Result`][`Result`] (provided by
|
||||
/// the [`IntoIterator`] trait).
|
||||
///
|
||||
/// [`Ok`]: enum.Result.html#variant.Ok
|
||||
/// [`Result`]: enum.Result.html
|
||||
/// [`into_iter`]: ../iter/trait.IntoIterator.html#tymethod.into_iter
|
||||
/// [`IntoIterator`]: ../iter/trait.IntoIterator.html
|
||||
#[derive(Debug)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct IntoIter<T> { inner: Option<T> }
|
||||
|
|
|
|||
|
|
@ -520,8 +520,8 @@ impl<T> ops::Index<usize> for [T] {
|
|||
type Output = T;
|
||||
|
||||
fn index(&self, index: usize) -> &T {
|
||||
assert!(index < self.len());
|
||||
unsafe { self.get_unchecked(index) }
|
||||
// NB built-in indexing
|
||||
&(*self)[index]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -530,8 +530,8 @@ impl<T> ops::Index<usize> for [T] {
|
|||
impl<T> ops::IndexMut<usize> for [T] {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: usize) -> &mut T {
|
||||
assert!(index < self.len());
|
||||
unsafe { self.get_unchecked_mut(index) }
|
||||
// NB built-in indexing
|
||||
&mut (*self)[index]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -755,11 +755,13 @@ impl<T> ops::IndexMut<ops::RangeToInclusive<usize>> for [T] {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> Default for &'a [T] {
|
||||
/// Creates an empty slice.
|
||||
fn default() -> &'a [T] { &[] }
|
||||
}
|
||||
|
||||
#[stable(feature = "mut_slice_default", since = "1.5.0")]
|
||||
impl<'a, T> Default for &'a mut [T] {
|
||||
/// Creates a mutable empty slice.
|
||||
fn default() -> &'a mut [T] { &mut [] }
|
||||
}
|
||||
|
||||
|
|
@ -1821,7 +1823,8 @@ impl<T: PartialOrd> PartialOrd for [T] {
|
|||
// intermediate trait for specialization of slice's PartialEq
|
||||
trait SlicePartialEq<B> {
|
||||
fn equal(&self, other: &[B]) -> bool;
|
||||
fn not_equal(&self, other: &[B]) -> bool;
|
||||
|
||||
fn not_equal(&self, other: &[B]) -> bool { !self.equal(other) }
|
||||
}
|
||||
|
||||
// Generic slice equality
|
||||
|
|
@ -1841,20 +1844,6 @@ impl<A, B> SlicePartialEq<B> for [A]
|
|||
|
||||
true
|
||||
}
|
||||
|
||||
default fn not_equal(&self, other: &[B]) -> bool {
|
||||
if self.len() != other.len() {
|
||||
return true;
|
||||
}
|
||||
|
||||
for i in 0..self.len() {
|
||||
if self[i].ne(&other[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// Use memcmp for bytewise equality when the types allow
|
||||
|
|
@ -1874,10 +1863,6 @@ impl<A> SlicePartialEq<A> for [A]
|
|||
other.as_ptr() as *const u8, size) == 0
|
||||
}
|
||||
}
|
||||
|
||||
fn not_equal(&self, other: &[A]) -> bool {
|
||||
!self.equal(other)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
|
|
|
|||
|
|
@ -1987,5 +1987,6 @@ impl AsRef<[u8]> for str {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a> Default for &'a str {
|
||||
/// Creates an empty str
|
||||
fn default() -> &'a str { "" }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ pub struct AtomicBool {
|
|||
#[cfg(target_has_atomic = "8")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Default for AtomicBool {
|
||||
/// Creates an `AtomicBool` initialised as false.
|
||||
fn default() -> Self {
|
||||
Self::new(false)
|
||||
}
|
||||
|
|
@ -117,6 +118,7 @@ pub struct AtomicPtr<T> {
|
|||
#[cfg(target_has_atomic = "ptr")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Default for AtomicPtr<T> {
|
||||
/// Creates a null `AtomicPtr<T>`.
|
||||
fn default() -> AtomicPtr<T> {
|
||||
AtomicPtr::new(::ptr::null_mut())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -664,12 +664,24 @@ fn test_max_by_key() {
|
|||
assert_eq!(*xs.iter().max_by_key(|x| x.abs()).unwrap(), -10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_max_by() {
|
||||
let xs: &[isize] = &[-3, 0, 1, 5, -10];
|
||||
assert_eq!(*xs.iter().max_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), -10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_min_by_key() {
|
||||
let xs: &[isize] = &[-3, 0, 1, 5, -10];
|
||||
assert_eq!(*xs.iter().min_by_key(|x| x.abs()).unwrap(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_min_by() {
|
||||
let xs: &[isize] = &[-3, 0, 1, 5, -10];
|
||||
assert_eq!(*xs.iter().min_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_by_ref() {
|
||||
let mut xs = 0..10;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@
|
|||
#![feature(try_from)]
|
||||
#![feature(unicode)]
|
||||
#![feature(unique)]
|
||||
#![feature(iter_max_by)]
|
||||
#![feature(iter_min_by)]
|
||||
|
||||
extern crate core;
|
||||
extern crate test;
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ impl OptGroup {
|
|||
}],
|
||||
}
|
||||
}
|
||||
(_, _) => panic!("something is wrong with the long-form opt"),
|
||||
_ => panic!("something is wrong with the long-form opt"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 5066b7dcab7e700844b0e2ba71b8af9dc627a59b
|
||||
Subproject commit d4f6a19c55a03e3f9f6fb7377911b37ed807eb6c
|
||||
|
|
@ -124,12 +124,15 @@ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX
|
|||
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
|
||||
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1
|
||||
|
||||
#[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
|
||||
#[cfg(any(target_arch = "mips", target_arch = "mipsel", target_arch = "mips64"))]
|
||||
const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1
|
||||
|
||||
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||
const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4
|
||||
|
||||
#[cfg(target_arch = "s390x")]
|
||||
const UNWIND_DATA_REG: (i32, i32) = (6, 7); // R6, R7
|
||||
|
||||
// The following code is based on GCC's C and C++ personality routines. For reference, see:
|
||||
// https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc
|
||||
// https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
|
||||
|
|
|
|||
|
|
@ -232,13 +232,13 @@ extern "C" {
|
|||
// Again, I'm not entirely sure what this is describing, it just seems to work.
|
||||
#[cfg_attr(not(test), lang = "msvc_try_filter")]
|
||||
static mut TYPE_DESCRIPTOR1: _TypeDescriptor = _TypeDescriptor {
|
||||
pVFTable: &TYPE_INFO_VTABLE as *const _ as *const _,
|
||||
pVFTable: unsafe { &TYPE_INFO_VTABLE } as *const _ as *const _,
|
||||
spare: 0 as *mut _,
|
||||
name: imp::NAME1,
|
||||
};
|
||||
|
||||
static mut TYPE_DESCRIPTOR2: _TypeDescriptor = _TypeDescriptor {
|
||||
pVFTable: &TYPE_INFO_VTABLE as *const _ as *const _,
|
||||
pVFTable: unsafe { &TYPE_INFO_VTABLE } as *const _ as *const _,
|
||||
spare: 0 as *mut _,
|
||||
name: imp::NAME2,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault {
|
|||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Default for ReseedWithDefault {
|
||||
/// Creates an instance of `ReseedWithDefault`.
|
||||
fn default() -> ReseedWithDefault {
|
||||
ReseedWithDefault
|
||||
}
|
||||
|
|
@ -137,6 +138,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
impl Default for Counter {
|
||||
/// Constructs a `Counter` with initial value zero.
|
||||
fn default() -> Counter {
|
||||
Counter { i: 0 }
|
||||
}
|
||||
|
|
|
|||
1609
src/librbml/lib.rs
1609
src/librbml/lib.rs
File diff suppressed because it is too large
Load diff
|
|
@ -14,7 +14,6 @@ flate = { path = "../libflate" }
|
|||
fmt_macros = { path = "../libfmt_macros" }
|
||||
graphviz = { path = "../libgraphviz" }
|
||||
log = { path = "../liblog" }
|
||||
rbml = { path = "../librbml" }
|
||||
rustc_back = { path = "../librustc_back" }
|
||||
rustc_bitflags = { path = "../librustc_bitflags" }
|
||||
rustc_const_math = { path = "../librustc_const_math" }
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
|||
|
||||
fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex {
|
||||
match pat.node {
|
||||
PatKind::Binding(_, _, None) |
|
||||
PatKind::Binding(.., None) |
|
||||
PatKind::Path(..) |
|
||||
PatKind::Lit(..) |
|
||||
PatKind::Range(..) |
|
||||
|
|
@ -109,7 +109,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
|||
|
||||
PatKind::Box(ref subpat) |
|
||||
PatKind::Ref(ref subpat, _) |
|
||||
PatKind::Binding(_, _, Some(ref subpat)) => {
|
||||
PatKind::Binding(.., Some(ref subpat)) => {
|
||||
let subpat_exit = self.pat(&subpat, pred);
|
||||
self.add_ast_node(pat.id, &[subpat_exit])
|
||||
}
|
||||
|
|
@ -306,7 +306,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
|||
self.call(expr, pred, &func, args.iter().map(|e| &**e))
|
||||
}
|
||||
|
||||
hir::ExprMethodCall(_, _, ref args) => {
|
||||
hir::ExprMethodCall(.., ref args) => {
|
||||
self.call(expr, pred, &args[0], args[1..].iter().map(|e| &**e))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -341,6 +341,8 @@ path is found (as demonstrated above).
|
|||
|
||||
### Debugging the dependency graph
|
||||
|
||||
#### Dumping the graph
|
||||
|
||||
The compiler is also capable of dumping the dependency graph for your
|
||||
debugging pleasure. To do so, pass the `-Z dump-dep-graph` flag. The
|
||||
graph will be dumped to `dep_graph.{txt,dot}` in the current
|
||||
|
|
@ -392,6 +394,35 @@ This will dump out all the nodes that lead from `Hir(foo)` to
|
|||
`TypeckItemBody(bar)`, from which you can (hopefully) see the source
|
||||
of the erroneous edge.
|
||||
|
||||
#### Tracking down incorrect edges
|
||||
|
||||
Sometimes, after you dump the dependency graph, you will find some
|
||||
path that should not exist, but you will not be quite sure how it came
|
||||
to be. **When the compiler is built with debug assertions,** it can
|
||||
help you track that down. Simply set the `RUST_FORBID_DEP_GRAPH_EDGE`
|
||||
environment variable to a filter. Every edge created in the dep-graph
|
||||
will be tested against that filter -- if it matches, a `bug!` is
|
||||
reported, so you can easily see the backtrace (`RUST_BACKTRACE=1`).
|
||||
|
||||
The syntax for these filters is the same as described in the previous
|
||||
section. However, note that this filter is applied to every **edge**
|
||||
and doesn't handle longer paths in the graph, unlike the previous
|
||||
section.
|
||||
|
||||
Example:
|
||||
|
||||
You find that there is a path from the `Hir` of `foo` to the type
|
||||
check of `bar` and you don't think there should be. You dump the
|
||||
dep-graph as described in the previous section and open `dep-graph.txt`
|
||||
to see something like:
|
||||
|
||||
Hir(foo) -> Collect(bar)
|
||||
Collect(bar) -> TypeckItemBody(bar)
|
||||
|
||||
That first edge looks suspicious to you. So you set
|
||||
`RUST_FORBID_DEP_GRAPH_EDGE` to `Hir&foo -> Collect&bar`, re-run, and
|
||||
then observe the backtrace. Voila, bug fixed!
|
||||
|
||||
### Inlining of HIR nodes
|
||||
|
||||
For the time being, at least, we still sometimes "inline" HIR nodes
|
||||
|
|
|
|||
|
|
@ -66,4 +66,11 @@ impl EdgeFilter {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test<D: Clone + Debug>(&self,
|
||||
source: &DepNode<D>,
|
||||
target: &DepNode<D>)
|
||||
-> bool {
|
||||
self.source.test(source) && self.target.test(target)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,18 +103,13 @@ pub enum DepNode<D: Clone + Debug> {
|
|||
// table in the tcx (or elsewhere) maps to one of these
|
||||
// nodes. Often we map multiple tables to the same node if there
|
||||
// is no point in distinguishing them (e.g., both the type and
|
||||
// predicates for an item wind up in `ItemSignature`). Other
|
||||
// times, such as `ImplItems` vs `TraitItemDefIds`, tables which
|
||||
// might be mergable are kept distinct because the sets of def-ids
|
||||
// to which they apply are disjoint, and hence we might as well
|
||||
// have distinct labels for easier debugging.
|
||||
// predicates for an item wind up in `ItemSignature`).
|
||||
ImplOrTraitItems(D),
|
||||
ItemSignature(D),
|
||||
FieldTy(D),
|
||||
SizedConstraint(D),
|
||||
TraitItemDefIds(D),
|
||||
ImplOrTraitItemDefIds(D),
|
||||
InherentImpls(D),
|
||||
ImplItems(D),
|
||||
|
||||
// The set of impls for a given trait. Ultimately, it would be
|
||||
// nice to get more fine-grained here (e.g., to include a
|
||||
|
|
@ -132,7 +127,7 @@ pub enum DepNode<D: Clone + Debug> {
|
|||
// which would yield an overly conservative dep-graph.
|
||||
TraitItems(D),
|
||||
ReprHints(D),
|
||||
TraitSelect(D, Vec<D>),
|
||||
TraitSelect(Vec<D>),
|
||||
}
|
||||
|
||||
impl<D: Clone + Debug> DepNode<D> {
|
||||
|
|
@ -162,9 +157,8 @@ impl<D: Clone + Debug> DepNode<D> {
|
|||
ImplOrTraitItems,
|
||||
ItemSignature,
|
||||
FieldTy,
|
||||
TraitItemDefIds,
|
||||
ImplOrTraitItemDefIds,
|
||||
InherentImpls,
|
||||
ImplItems,
|
||||
TraitImpls,
|
||||
ReprHints,
|
||||
}
|
||||
|
|
@ -231,16 +225,14 @@ impl<D: Clone + Debug> DepNode<D> {
|
|||
ItemSignature(ref d) => op(d).map(ItemSignature),
|
||||
FieldTy(ref d) => op(d).map(FieldTy),
|
||||
SizedConstraint(ref d) => op(d).map(SizedConstraint),
|
||||
TraitItemDefIds(ref d) => op(d).map(TraitItemDefIds),
|
||||
ImplOrTraitItemDefIds(ref d) => op(d).map(ImplOrTraitItemDefIds),
|
||||
InherentImpls(ref d) => op(d).map(InherentImpls),
|
||||
ImplItems(ref d) => op(d).map(ImplItems),
|
||||
TraitImpls(ref d) => op(d).map(TraitImpls),
|
||||
TraitItems(ref d) => op(d).map(TraitItems),
|
||||
ReprHints(ref d) => op(d).map(ReprHints),
|
||||
TraitSelect(ref d, ref type_ds) => {
|
||||
let d = try_opt!(op(d));
|
||||
TraitSelect(ref type_ds) => {
|
||||
let type_ds = try_opt!(type_ds.iter().map(|d| op(d)).collect());
|
||||
Some(TraitSelect(d, type_ds))
|
||||
Some(TraitSelect(type_ds))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,6 +80,17 @@ impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
|
|||
pub fn keys(&self) -> Vec<M::Key> {
|
||||
self.map.keys().cloned().collect()
|
||||
}
|
||||
|
||||
/// Append `elem` to the vector stored for `k`, creating a new vector if needed.
|
||||
/// This is considered a write to `k`.
|
||||
pub fn push<E: Clone>(&mut self, k: M::Key, elem: E)
|
||||
where M: DepTrackingMapConfig<Value=Vec<E>>
|
||||
{
|
||||
self.write(&k);
|
||||
self.map.entry(k)
|
||||
.or_insert(Vec::new())
|
||||
.push(elem);
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ impl DepGraph {
|
|||
data: Rc::new(DepGraphData {
|
||||
thread: DepGraphThreadData::new(enabled),
|
||||
previous_work_products: RefCell::new(FnvHashMap()),
|
||||
work_products: RefCell::new(FnvHashMap())
|
||||
work_products: RefCell::new(FnvHashMap()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ mod edges;
|
|||
mod graph;
|
||||
mod query;
|
||||
mod raii;
|
||||
mod shadow;
|
||||
mod thread;
|
||||
mod visit;
|
||||
|
||||
|
|
|
|||
|
|
@ -47,3 +47,4 @@ impl<'graph> Drop for IgnoreTask<'graph> {
|
|||
self.data.enqueue(DepMessage::PopIgnore);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
145
src/librustc/dep_graph/shadow.rs
Normal file
145
src/librustc/dep_graph/shadow.rs
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! The "Shadow Graph" is maintained on the main thread and which
|
||||
//! tracks each message relating to the dep-graph and applies some
|
||||
//! sanity checks as they go by. If an error results, it means you get
|
||||
//! a nice stack-trace telling you precisely what caused the error.
|
||||
//!
|
||||
//! NOTE: This is a debugging facility which can potentially have non-trivial
|
||||
//! runtime impact. Therefore, it is largely compiled out if
|
||||
//! debug-assertions are not enabled.
|
||||
//!
|
||||
//! The basic sanity check, enabled if you have debug assertions
|
||||
//! enabled, is that there is always a task (or ignore) on the stack
|
||||
//! when you do read/write, and that the tasks are pushed/popped
|
||||
//! according to a proper stack discipline.
|
||||
//!
|
||||
//! Optionally, if you specify RUST_FORBID_DEP_GRAPH_EDGE, you can
|
||||
//! specify an edge filter to be applied to each edge as it is
|
||||
//! created. See `./README.md` for details.
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use std::cell::{BorrowState, RefCell};
|
||||
use std::env;
|
||||
|
||||
use super::DepNode;
|
||||
use super::thread::DepMessage;
|
||||
use super::debug::EdgeFilter;
|
||||
|
||||
pub struct ShadowGraph {
|
||||
// if you push None onto the stack, that corresponds to an Ignore
|
||||
stack: RefCell<Vec<Option<DepNode<DefId>>>>,
|
||||
forbidden_edge: Option<EdgeFilter>,
|
||||
}
|
||||
|
||||
const ENABLED: bool = cfg!(debug_assertions);
|
||||
|
||||
impl ShadowGraph {
|
||||
pub fn new() -> Self {
|
||||
let forbidden_edge = if !ENABLED {
|
||||
None
|
||||
} else {
|
||||
match env::var("RUST_FORBID_DEP_GRAPH_EDGE") {
|
||||
Ok(s) => {
|
||||
match EdgeFilter::new(&s) {
|
||||
Ok(f) => Some(f),
|
||||
Err(err) => bug!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err),
|
||||
}
|
||||
}
|
||||
Err(_) => None,
|
||||
}
|
||||
};
|
||||
|
||||
ShadowGraph {
|
||||
stack: RefCell::new(vec![]),
|
||||
forbidden_edge: forbidden_edge,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enqueue(&self, message: &DepMessage) {
|
||||
if ENABLED {
|
||||
match self.stack.borrow_state() {
|
||||
BorrowState::Unused => {}
|
||||
_ => {
|
||||
// When we apply edge filters, that invokes the
|
||||
// Debug trait on DefIds, which in turn reads from
|
||||
// various bits of state and creates reads! Ignore
|
||||
// those recursive reads.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let mut stack = self.stack.borrow_mut();
|
||||
match *message {
|
||||
DepMessage::Read(ref n) => self.check_edge(Some(Some(n)), top(&stack)),
|
||||
DepMessage::Write(ref n) => self.check_edge(top(&stack), Some(Some(n))),
|
||||
DepMessage::PushTask(ref n) => stack.push(Some(n.clone())),
|
||||
DepMessage::PushIgnore => stack.push(None),
|
||||
DepMessage::PopTask(ref n) => {
|
||||
match stack.pop() {
|
||||
Some(Some(m)) => {
|
||||
if *n != m {
|
||||
bug!("stack mismatch: found {:?} expected {:?}", m, n)
|
||||
}
|
||||
}
|
||||
Some(None) => bug!("stack mismatch: found Ignore expected {:?}", n),
|
||||
None => bug!("stack mismatch: found empty stack, expected {:?}", n),
|
||||
}
|
||||
}
|
||||
DepMessage::PopIgnore => {
|
||||
match stack.pop() {
|
||||
Some(Some(m)) => bug!("stack mismatch: found {:?} expected ignore", m),
|
||||
Some(None) => (),
|
||||
None => bug!("stack mismatch: found empty stack, expected ignore"),
|
||||
}
|
||||
}
|
||||
DepMessage::Query => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_edge(&self,
|
||||
source: Option<Option<&DepNode<DefId>>>,
|
||||
target: Option<Option<&DepNode<DefId>>>) {
|
||||
assert!(ENABLED);
|
||||
match (source, target) {
|
||||
// cannot happen, one side is always Some(Some(_))
|
||||
(None, None) => unreachable!(),
|
||||
|
||||
// nothing on top of the stack
|
||||
(None, Some(n)) | (Some(n), None) => bug!("read/write of {:?} but no current task", n),
|
||||
|
||||
// this corresponds to an Ignore being top of the stack
|
||||
(Some(None), _) | (_, Some(None)) => (),
|
||||
|
||||
// a task is on top of the stack
|
||||
(Some(Some(source)), Some(Some(target))) => {
|
||||
if let Some(ref forbidden_edge) = self.forbidden_edge {
|
||||
if forbidden_edge.test(source, target) {
|
||||
bug!("forbidden edge {:?} -> {:?} created", source, target)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do a little juggling: we get back a reference to an option at the
|
||||
// top of the stack, convert it to an optional reference.
|
||||
fn top<'s>(stack: &'s Vec<Option<DepNode<DefId>>>) -> Option<Option<&'s DepNode<DefId>>> {
|
||||
stack.last()
|
||||
.map(|n: &'s Option<DepNode<DefId>>| -> Option<&'s DepNode<DefId>> {
|
||||
// (*)
|
||||
// (*) type annotation just there to clarify what would
|
||||
// otherwise be some *really* obscure code
|
||||
n.as_ref()
|
||||
})
|
||||
}
|
||||
|
|
@ -20,13 +20,13 @@
|
|||
|
||||
use hir::def_id::DefId;
|
||||
use rustc_data_structures::veccell::VecCell;
|
||||
use std::cell::Cell;
|
||||
use std::sync::mpsc::{self, Sender, Receiver};
|
||||
use std::thread;
|
||||
|
||||
use super::DepGraphQuery;
|
||||
use super::DepNode;
|
||||
use super::edges::DepGraphEdges;
|
||||
use super::shadow::ShadowGraph;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DepMessage {
|
||||
|
|
@ -42,12 +42,16 @@ pub enum DepMessage {
|
|||
pub struct DepGraphThreadData {
|
||||
enabled: bool,
|
||||
|
||||
// Local counter that just tracks how many tasks are pushed onto the
|
||||
// stack, so that we still get an error in the case where one is
|
||||
// missing. If dep-graph construction is enabled, we'd get the same
|
||||
// error when processing tasks later on, but that's annoying because
|
||||
// it lacks precision about the source of the error.
|
||||
tasks_pushed: Cell<usize>,
|
||||
// The "shadow graph" is a debugging aid. We give it each message
|
||||
// in real time as it arrives and it checks for various errors
|
||||
// (for example, a read/write when there is no current task; it
|
||||
// can also apply user-defined filters; see `shadow` module for
|
||||
// details). This only occurs if debug-assertions are enabled.
|
||||
//
|
||||
// Note that in some cases the same errors will occur when the
|
||||
// data is processed off the main thread, but that's annoying
|
||||
// because it lacks precision about the source of the error.
|
||||
shadow_graph: ShadowGraph,
|
||||
|
||||
// current buffer, where we accumulate messages
|
||||
messages: VecCell<DepMessage>,
|
||||
|
|
@ -76,7 +80,7 @@ impl DepGraphThreadData {
|
|||
|
||||
DepGraphThreadData {
|
||||
enabled: enabled,
|
||||
tasks_pushed: Cell::new(0),
|
||||
shadow_graph: ShadowGraph::new(),
|
||||
messages: VecCell::with_capacity(INITIAL_CAPACITY),
|
||||
swap_in: rx2,
|
||||
swap_out: tx1,
|
||||
|
|
@ -118,21 +122,7 @@ impl DepGraphThreadData {
|
|||
/// the buffer is full, this may swap.)
|
||||
#[inline]
|
||||
pub fn enqueue(&self, message: DepMessage) {
|
||||
// Regardless of whether dep graph construction is enabled, we
|
||||
// still want to check that we always have a valid task on the
|
||||
// stack when a read/write/etc event occurs.
|
||||
match message {
|
||||
DepMessage::Read(_) | DepMessage::Write(_) =>
|
||||
if self.tasks_pushed.get() == 0 {
|
||||
self.invalid_message("read/write but no current task")
|
||||
},
|
||||
DepMessage::PushTask(_) | DepMessage::PushIgnore =>
|
||||
self.tasks_pushed.set(self.tasks_pushed.get() + 1),
|
||||
DepMessage::PopTask(_) | DepMessage::PopIgnore =>
|
||||
self.tasks_pushed.set(self.tasks_pushed.get() - 1),
|
||||
DepMessage::Query =>
|
||||
(),
|
||||
}
|
||||
self.shadow_graph.enqueue(&message);
|
||||
|
||||
if self.enabled {
|
||||
self.enqueue_enabled(message);
|
||||
|
|
@ -147,11 +137,6 @@ impl DepGraphThreadData {
|
|||
self.swap();
|
||||
}
|
||||
}
|
||||
|
||||
// Outline this too.
|
||||
fn invalid_message(&self, string: &str) {
|
||||
bug!("{}; see src/librustc/dep_graph/README.md for more information", string)
|
||||
}
|
||||
}
|
||||
|
||||
/// Definition of the depgraph thread.
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use syntax::visit::Visitor;
|
|||
enum Target {
|
||||
Fn,
|
||||
Struct,
|
||||
Union,
|
||||
Enum,
|
||||
Other,
|
||||
}
|
||||
|
|
@ -27,6 +28,7 @@ impl Target {
|
|||
match item.node {
|
||||
ast::ItemKind::Fn(..) => Target::Fn,
|
||||
ast::ItemKind::Struct(..) => Target::Struct,
|
||||
ast::ItemKind::Union(..) => Target::Union,
|
||||
ast::ItemKind::Enum(..) => Target::Enum,
|
||||
_ => Target::Other,
|
||||
}
|
||||
|
|
@ -40,7 +42,9 @@ struct CheckAttrVisitor<'a> {
|
|||
impl<'a> CheckAttrVisitor<'a> {
|
||||
fn check_inline(&self, attr: &ast::Attribute, target: Target) {
|
||||
if target != Target::Fn {
|
||||
span_err!(self.sess, attr.span, E0518, "attribute should be applied to function");
|
||||
struct_span_err!(self.sess, attr.span, E0518, "attribute should be applied to function")
|
||||
.span_label(attr.span, &format!("requires a function"))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -54,16 +58,20 @@ impl<'a> CheckAttrVisitor<'a> {
|
|||
|
||||
let mut conflicting_reprs = 0;
|
||||
for word in words {
|
||||
|
||||
let name = match word.name() {
|
||||
Some(word) => word,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let message = match &*name {
|
||||
let (message, label) = match &*name {
|
||||
"C" => {
|
||||
conflicting_reprs += 1;
|
||||
if target != Target::Struct && target != Target::Enum {
|
||||
"attribute should be applied to struct or enum"
|
||||
if target != Target::Struct &&
|
||||
target != Target::Union &&
|
||||
target != Target::Enum {
|
||||
("attribute should be applied to struct, enum or union",
|
||||
"a struct, enum or union")
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
|
|
@ -71,8 +79,10 @@ impl<'a> CheckAttrVisitor<'a> {
|
|||
"packed" => {
|
||||
// Do not increment conflicting_reprs here, because "packed"
|
||||
// can be used to modify another repr hint
|
||||
if target != Target::Struct {
|
||||
"attribute should be applied to struct"
|
||||
if target != Target::Struct &&
|
||||
target != Target::Union {
|
||||
("attribute should be applied to struct or union",
|
||||
"a struct or union")
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
|
|
@ -80,7 +90,8 @@ impl<'a> CheckAttrVisitor<'a> {
|
|||
"simd" => {
|
||||
conflicting_reprs += 1;
|
||||
if target != Target::Struct {
|
||||
"attribute should be applied to struct"
|
||||
("attribute should be applied to struct",
|
||||
"a struct")
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
|
|
@ -90,15 +101,17 @@ impl<'a> CheckAttrVisitor<'a> {
|
|||
"isize" | "usize" => {
|
||||
conflicting_reprs += 1;
|
||||
if target != Target::Enum {
|
||||
"attribute should be applied to enum"
|
||||
("attribute should be applied to enum",
|
||||
"an enum")
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
span_err!(self.sess, attr.span, E0517, "{}", message);
|
||||
struct_span_err!(self.sess, attr.span, E0517, "{}", message)
|
||||
.span_label(attr.span, &format!("requires {}", label))
|
||||
.emit();
|
||||
}
|
||||
if conflicting_reprs > 1 {
|
||||
span_warn!(self.sess, attr.span, E0566,
|
||||
|
|
|
|||
|
|
@ -16,23 +16,20 @@ use hir;
|
|||
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub enum Def {
|
||||
Fn(DefId),
|
||||
SelfTy(Option<DefId> /* trait */, Option<ast::NodeId> /* impl */),
|
||||
SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),
|
||||
Mod(DefId),
|
||||
ForeignMod(DefId),
|
||||
Static(DefId, bool /* is_mutbl */),
|
||||
Const(DefId),
|
||||
AssociatedConst(DefId),
|
||||
Local(DefId, // def id of variable
|
||||
ast::NodeId), // node id of variable
|
||||
Variant(DefId /* enum */, DefId /* variant */),
|
||||
Local(DefId),
|
||||
Variant(DefId),
|
||||
Enum(DefId),
|
||||
TyAlias(DefId),
|
||||
AssociatedTy(DefId /* trait */, DefId),
|
||||
AssociatedTy(DefId),
|
||||
Trait(DefId),
|
||||
PrimTy(hir::PrimTy),
|
||||
TyParam(DefId),
|
||||
Upvar(DefId, // def id of closed over local
|
||||
ast::NodeId, // node id of closed over local
|
||||
usize, // index in the freevars list of the closure
|
||||
ast::NodeId), // expr node that creates the closure
|
||||
|
||||
|
|
@ -41,6 +38,7 @@ pub enum Def {
|
|||
// If Def::Struct lives in value namespace (e.g. tuple struct, unit struct expressions)
|
||||
// it denotes a constructor and its DefId refers to NodeId of the struct's constructor.
|
||||
Struct(DefId),
|
||||
Union(DefId),
|
||||
Label(ast::NodeId),
|
||||
Method(DefId),
|
||||
Err,
|
||||
|
|
@ -93,37 +91,20 @@ pub type DefMap = NodeMap<PathResolution>;
|
|||
// within.
|
||||
pub type ExportMap = NodeMap<Vec<Export>>;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
|
||||
pub struct Export {
|
||||
pub name: ast::Name, // The name of the target.
|
||||
pub def_id: DefId, // The definition of the target.
|
||||
}
|
||||
|
||||
impl Def {
|
||||
pub fn var_id(&self) -> ast::NodeId {
|
||||
match *self {
|
||||
Def::Local(_, id) |
|
||||
Def::Upvar(_, id, _, _) => {
|
||||
id
|
||||
}
|
||||
|
||||
Def::Fn(..) | Def::Mod(..) | Def::ForeignMod(..) | Def::Static(..) |
|
||||
Def::Variant(..) | Def::Enum(..) | Def::TyAlias(..) | Def::AssociatedTy(..) |
|
||||
Def::TyParam(..) | Def::Struct(..) | Def::Trait(..) |
|
||||
Def::Method(..) | Def::Const(..) | Def::AssociatedConst(..) |
|
||||
Def::PrimTy(..) | Def::Label(..) | Def::SelfTy(..) | Def::Err => {
|
||||
bug!("attempted .var_id() on invalid {:?}", self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn def_id(&self) -> DefId {
|
||||
match *self {
|
||||
Def::Fn(id) | Def::Mod(id) | Def::ForeignMod(id) | Def::Static(id, _) |
|
||||
Def::Variant(_, id) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(_, id) |
|
||||
Def::TyParam(id) | Def::Struct(id) | Def::Trait(id) |
|
||||
Def::Fn(id) | Def::Mod(id) | Def::Static(id, _) |
|
||||
Def::Variant(id) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(id) |
|
||||
Def::TyParam(id) | Def::Struct(id) | Def::Union(id) | Def::Trait(id) |
|
||||
Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) |
|
||||
Def::Local(id, _) | Def::Upvar(id, _, _, _) => {
|
||||
Def::Local(id) | Def::Upvar(id, ..) => {
|
||||
id
|
||||
}
|
||||
|
||||
|
|
@ -140,13 +121,13 @@ impl Def {
|
|||
match *self {
|
||||
Def::Fn(..) => "function",
|
||||
Def::Mod(..) => "module",
|
||||
Def::ForeignMod(..) => "foreign module",
|
||||
Def::Static(..) => "static",
|
||||
Def::Variant(..) => "variant",
|
||||
Def::Enum(..) => "enum",
|
||||
Def::TyAlias(..) => "type",
|
||||
Def::AssociatedTy(..) => "associated type",
|
||||
Def::Struct(..) => "struct",
|
||||
Def::Union(..) => "union",
|
||||
Def::Trait(..) => "trait",
|
||||
Def::Method(..) => "method",
|
||||
Def::Const(..) => "constant",
|
||||
|
|
|
|||
|
|
@ -8,12 +8,69 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use middle::cstore::LOCAL_CRATE;
|
||||
use ty;
|
||||
use syntax::ast::CrateNum;
|
||||
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use serialize::{self, Encoder, Decoder};
|
||||
|
||||
use std::fmt;
|
||||
use std::u32;
|
||||
|
||||
#[derive(Clone, Copy, Eq, Ord, PartialOrd, PartialEq, Hash, Debug)]
|
||||
pub struct CrateNum(u32);
|
||||
|
||||
impl Idx for CrateNum {
|
||||
fn new(value: usize) -> Self {
|
||||
assert!(value < (u32::MAX) as usize);
|
||||
CrateNum(value as u32)
|
||||
}
|
||||
|
||||
fn index(self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
/// Item definitions in the currently-compiled crate would have the CrateNum
|
||||
/// LOCAL_CRATE in their DefId.
|
||||
pub const LOCAL_CRATE: CrateNum = CrateNum(0);
|
||||
|
||||
impl CrateNum {
|
||||
pub fn new(x: usize) -> CrateNum {
|
||||
assert!(x < (u32::MAX as usize));
|
||||
CrateNum(x as u32)
|
||||
}
|
||||
|
||||
pub fn from_u32(x: u32) -> CrateNum {
|
||||
CrateNum(x)
|
||||
}
|
||||
|
||||
pub fn as_usize(&self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
|
||||
pub fn as_u32(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CrateNum {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl serialize::UseSpecializedEncodable for CrateNum {
|
||||
fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
s.emit_u32(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl serialize::UseSpecializedDecodable for CrateNum {
|
||||
fn default_decode<D: Decoder>(d: &mut D) -> Result<CrateNum, D::Error> {
|
||||
d.read_u32().map(CrateNum)
|
||||
}
|
||||
}
|
||||
|
||||
/// A DefIndex is an index into the hir-map for a crate, identifying a
|
||||
/// particular definition. It should really be considered an interned
|
||||
/// shorthand for a particular DefPath.
|
||||
|
|
@ -46,8 +103,7 @@ pub const CRATE_DEF_INDEX: DefIndex = DefIndex(0);
|
|||
|
||||
/// A DefId identifies a particular *definition*, by combining a crate
|
||||
/// index and a def index.
|
||||
#[derive(Clone, Eq, Ord, PartialOrd, PartialEq, RustcEncodable,
|
||||
RustcDecodable, Hash, Copy)]
|
||||
#[derive(Clone, Eq, Ord, PartialOrd, PartialEq, RustcEncodable, RustcDecodable, Hash, Copy)]
|
||||
pub struct DefId {
|
||||
pub krate: CrateNum,
|
||||
pub index: DefIndex,
|
||||
|
|
@ -58,19 +114,14 @@ impl fmt::Debug for DefId {
|
|||
write!(f, "DefId {{ krate: {:?}, node: {:?}",
|
||||
self.krate, self.index)?;
|
||||
|
||||
// Unfortunately, there seems to be no way to attempt to print
|
||||
// a path for a def-id, so I'll just make a best effort for now
|
||||
// and otherwise fallback to just printing the crate/node pair
|
||||
if self.is_local() { // (1)
|
||||
// (1) side-step fact that not all external things have paths at
|
||||
// the moment, such as type parameters
|
||||
ty::tls::with_opt(|opt_tcx| {
|
||||
if let Some(tcx) = opt_tcx {
|
||||
write!(f, " => {}", tcx.item_path_str(*self))?;
|
||||
ty::tls::with_opt(|opt_tcx| {
|
||||
if let Some(tcx) = opt_tcx {
|
||||
if let Some(def_path) = tcx.opt_def_path(*self) {
|
||||
write!(f, " => {}", def_path.to_string(tcx))?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
write!(f, " }}")
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue